Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 3 123 LastLast
Results 1 to 15 of 35
  1. #1
    Kor
    Kor is offline
    Red Devil Mod Kor's Avatar
    Join Date
    Apr 2003
    Location
    Bucharest, ROMANIA
    Posts
    8,478
    Thanks
    58
    Thanked 379 Times in 375 Posts

    document.getElementsByClassName()

    FF3, Chrome and Opera 9+ have already implemented this method : document.getElementsByClassName() as javascript native, but for a crossbrowser approach, you may use this workaround:
    Code:
    <script type="text/javascript">
    onload=function(){
    if(!document.getElementsByClassName){
    document.getElementsByClassName=function(cn){
    var allT=document.getElementsByTagName('*'), allCN=[], i=0, a;
    	while(a=allT[i++]){
    	a.className==cn?allCN[allCN.length]=a:null;
    	}
    return allCN
    }
    }
    }
    </script>
    KOR
    Offshore programming
    -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

  2. The Following 2 Users Say Thank You to Kor For This Useful Post:

    abduraooft (12-22-2008), oesxyl (12-22-2008)

  • #2
    Senior Coder rangana's Avatar
    Join Date
    Feb 2008
    Location
    Cebu City, Philippines
    Posts
    1,752
    Thanks
    65
    Thanked 372 Times in 365 Posts
    Hi Kor,

    It would fail on multiple class names like:
    Code:
    <span class="class1 class2">Dummy</span>
    ...how about:
    Code:
    onload=function(){
    if(!document.getElementsByClassName){
    document.getElementsByClassName=function(cn){
    var rx=new RegExp('\\b'+cn+'\\b');
    var allT=document.getElementsByTagName('*'), allCN=[], i=0, a;
    	while(a=allT[i++]){
    	rx.test(a.className)?allCN[allCN.length]=a:null;
    	}
    return allCN
    }
    }
    }
    Learn how to javascript at 02geek

    The more you learn, the more you'll realize there's much more to learn
    Ray.ph

  • The Following 3 Users Say Thank You to rangana For This Useful Post:

    abduraooft (12-24-2008), Kor (12-22-2008), oesxyl (12-22-2008)

  • #3
    Kor
    Kor is offline
    Red Devil Mod Kor's Avatar
    Join Date
    Apr 2003
    Location
    Bucharest, ROMANIA
    Posts
    8,478
    Thanks
    58
    Thanked 379 Times in 375 Posts
    Yes, good ideea.
    KOR
    Offshore programming
    -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

  • #4
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,444
    Thanks
    11
    Thanked 598 Times in 578 Posts

    with performance optimizations

    i liked rangana's take on kor's slim code.
    i've seen many versions of this floating around, and this one is pretty good.

    i had some time on my hands, so i thought i could tweak it a bit.
    i think that since native code performs about 100X faster than js replacements, we should tweak native replacements as much as possible.

    The direct string compare is much faster than a regexp, but as we see from kor's code, limited to single class attribs.

    Second best to a direct compare, indexOf performs 3-50X faster than a comparable regExp.
    This is of limited use however, because it could match partial substring:
    ex: searching for "sample" would match "sampleBold".

    what we want is the speed of string methods, and the precision of a regexp.



    the solution: have the matching code to only work as hard as needed:

    Code:
    if (!document.getElementsByClassName) {
      	document.getElementsByClassName = function (cn) {
    		var rx = new RegExp("\\b" + cn + "\\b"), allT = document.getElementsByTagName("*"), allCN = [], i = 0, a;
    			while (a = allT[i++]) {
    			  if (a.className && a.className.indexOf(cn) + 1) {
    				if(a.className===cn){ allCN[allCN.length] = a; continue;   }
    				rx.test(a.className) ? (allCN[allCN.length] = a) : 0;
    			  }
    			}
    		return allCN;
    	}
    }
    this performs about 10 - 50% (avg ~20) faster than rangana's version, and it finds the same things.


    after checking for any className at all,
    it uses the medium speed indexOf to determine if it's worth further examination.

    if there is some kind of match, a super fast direct compare is tried.
    failing the direct compare, sub-matches are eliminated by rangana's regexp.



    perhaps someone else can tweak it even further?
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • The Following 2 Users Say Thank You to rnd me For This Useful Post:

    Kor (12-22-2008), oesxyl (12-22-2008)

  • #5
    Kor
    Kor is offline
    Red Devil Mod Kor's Avatar
    Join Date
    Apr 2003
    Location
    Bucharest, ROMANIA
    Posts
    8,478
    Thanks
    58
    Thanked 379 Times in 375 Posts
    Pretty good development, good job also rnd me
    KOR
    Offshore programming
    -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

  • #6
    Master Coder
    Join Date
    Dec 2007
    Posts
    6,682
    Thanks
    436
    Thanked 890 Times in 879 Posts
    Quote Originally Posted by rnd me View Post
    Code:
    if (!document.getElementsByClassName) {
      	document.getElementsByClassName = function (cn) {
    		var rx = new RegExp("\\b" + cn + "\\b"), allT = document.getElementsByTagName("*"), allCN = [], i = 0, a;
    			while (a = allT[i++]) {
    			  if (a.className && a.className.indexOf(cn) + 1) {
    				if(a.className===cn){ allCN[allCN.length] = a; continue;   }
    				rx.test(a.className) ? (allCN[allCN.length] = a) : 0;
    			  }
    			}
    		return allCN;
    	}
    }
    would be any problem of speed and portability with this?
    Code:
    ...
    if(a.className && a.className.split(' ').indexOf(cn) > -1){
    ...
    best regards

  • #7
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,444
    Thanks
    11
    Thanked 598 Times in 578 Posts
    Quote Originally Posted by oesxyl View Post
    would be any problem of speed and portability with this?
    yes.
    Array.indexOf is not supported in ie or any browser without 1.6 array methods...

    while it could be added in with 1.5 code, that robs peter to pay paul, and i suspect it would be slower in the end.
    Last edited by rnd me; 12-22-2008 at 11:12 PM.
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • Users who have thanked rnd me for this post:

    oesxyl (12-22-2008)

  • #8
    Master Coder
    Join Date
    Dec 2007
    Posts
    6,682
    Thanks
    436
    Thanked 890 Times in 879 Posts
    Quote Originally Posted by rnd me View Post
    yes.
    Array.indexOf is not supported in ie or any browser without 1.6 array methods...

    while it could be added in with 1.5 code, that robs peter to pay paul, and i suspect it would be slower in the end.
    good to know, . that means Opera, Safari and IE?

    http://aptana.com/reference/html/api/Array.html

    best regards

  • #9
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,444
    Thanks
    11
    Thanked 598 Times in 578 Posts
    Quote Originally Posted by oesxyl View Post
    good to know, . that means Opera, Safari and IE?
    best regards
    basically anything besides firefox, which already supports document.getElementsByClassName()...

    good link btw...
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #10
    Master Coder
    Join Date
    Dec 2007
    Posts
    6,682
    Thanks
    436
    Thanked 890 Times in 879 Posts
    Quote Originally Posted by rnd me View Post
    basically anything besides firefox, which already supports document.getElementsByClassName()...

    good link btw...
    yes, is good,

    I discover also problems with split in safari,

    best regards

  • #11
    Senior Coder rangana's Avatar
    Join Date
    Feb 2008
    Location
    Cebu City, Philippines
    Posts
    1,752
    Thanks
    65
    Thanked 372 Times in 365 Posts
    Okay, now I understand. You are filtering the element for a match (single class name), otherwise (for multiple classname), it'll go to the RegEx.

    Saves resources indeed.

    Edit:
    rnd me, I'm confused, on why go all the hassle of those if's statement.

    Why not just:
    Code:
    if (!document.getElementsByClassName)
    {
    document.getElementsByClassName = function (cn)
    	{
    	var rx = new RegExp("\\b" + cn + "\\b"), allT = document.getElementsByTagName("*"), allCN = [], i = 0, a;
    	while (a = allT[i++])
    		if (rx.test(a.className))
    			allCN.push(a);
    	return allCN;
    	}
    }
    Last edited by rangana; 12-23-2008 at 02:41 AM.
    Learn how to javascript at 02geek

    The more you learn, the more you'll realize there's much more to learn
    Ray.ph

  • #12
    Senior Coder
    Join Date
    Oct 2008
    Location
    Long Beach
    Posts
    1,196
    Thanks
    36
    Thanked 164 Times in 164 Posts
    He's saying that
    Code:
    if (rx.test(a.className))
    is significantly slower than
    Code:
    if (cn===a.className)
    So he's avoiding RegExp.test() for elements with a single class name.

    EDIT: I missed your edit Ignore my post.
    Last edited by itsallkizza; 12-23-2008 at 03:15 AM.
    Feel free to e-mail me if I forget to respond ;)
    ohsosexybrit@gmail.com

  • #13
    Kor
    Kor is offline
    Red Devil Mod Kor's Avatar
    Join Date
    Apr 2003
    Location
    Bucharest, ROMANIA
    Posts
    8,478
    Thanks
    58
    Thanked 379 Times in 375 Posts
    Quote Originally Posted by rnd me View Post
    basically anything besides firefox, which already supports document.getElementsByClassName()...

    good link btw...
    Basically all the new browsers' versions, except, of course, IE support now the native getElementsByClassName() method. At least Opera 9+ and Chrome do so.
    KOR
    Offshore programming
    -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

  • #14
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,444
    Thanks
    11
    Thanked 598 Times in 578 Posts
    lots of discussion calls for further explanation.

    i throw in a little general performance tuning strategy to provide a context for what's going on here, and why it matters.

    loops are slow.
    thus, less work at each iteration equals faster execution.
    simple and true.

    also, functions that will be commonly used should be as fast as possible. you'll have plenty of opportunity to slow things down later on...


    a common task like harvesting tags should be as quick and compatible with existing native interfaces.



    consider the four possible outcomes of matching a className to an element:
    (in order of likelihood)

    1. the tag has no className
    2. the tag has a className, but the search term is not contained in the element's className
    3. the tag has a className, and the search term is equal to the element's className
    4. the tag has a className, and the search term is contained in the element's className ( it's one of many classes represented in the attribute)


    we provide the code inside the loop four opportunities to avoid the regexp and bail out early.
    these opportunities coincide with the four possible outcomes.


    line by line walkthrough:
    Code:
    while (a = allT[i++]) {
    continue advancing to the next one in our stack of all tags, and assign it to "a".

    Code:
      if (a.className && a.className.indexOf(cn) + 1) {
    this one is critical. most tags do not have classes. the first part of the if statement "if a.className" means that any element without a class will fail, and goto the end of the if block, and thus the end of the loop. right away, most tags fail. bailing early lets us avoid a slow string (.indexOf) or regexp (.test) method execution on something with no class at all.

    the second part of the if statement (a.className.indexOf(cn) + 1) performs a similar role, acting as a gate keeper to the slow regexp. if no match if found, indexOf will return -1. adding 1 to that = 0, turning a no-match evaluation into a "falsey" value, and failing the if statement.


    if we got to this point we know the element has a class, and that the search term at least partially matches the element's class.


    Code:
    if(a.className===cn){ allCN[allCN.length] = a; continue;   }
    most of the time there will only be one class used, and a direct compare is super fast.
    therefore, it is fastest to try to get away with a direct compare.
    if it works, which it usually will since most class attributes mean one class, we add the result to the array of matches, and continue the loop from the top.
    this skips over the regexp if the fast direct match is successful.


    if the direct match fails we know that one of two things is true:
    1. we found a match substring, like "tree" in "subtree" for instance.
    2. we found the proper class among more than one classes represented in one class attribute, typically in a space-separated list.

    this line:
    Code:
    rx.test(a.className) ? (allCN[allCN.length] = a) : 0;
    runs the regexp that can determine precisely the difference between a substring and a "one of many" match.
    if it's "one of many", it adds the element to the array of matches and proceed with the next loop iteration.

    -------

    in general, there is a point of diminishing returns using ifs to avoid work.
    you could get to the point that the filtering is more intensive than the workload to be avoided.
    in this case, the regexp is sufficiently slow to provide ample time to trade in exchange for a couple of if statements.

    in other situations, that's not the case, and it pays to runs a few tests and find the proper balance.
    Last edited by rnd me; 12-23-2008 at 06:05 AM.
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #15
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,444
    Thanks
    11
    Thanked 598 Times in 578 Posts
    Quote Originally Posted by Kor View Post
    Basically all the new browsers' versions, except, of course, IE support now the native getElementsByClassName() method. At least Opera 9+ and Chrome do so.
    i was referring to Array.indexOf, not getElementsByClassName, but it's probably the same either way. i know chrome has Array.indexOf...
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%


  •  
    Page 1 of 3 123 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •