The ultimate getElementsByClassName, anno 2008

Two and a half years ago, I released the first version of getElementsByClassName. With how web browsers has evolved since, I thought I’d release a real ultimate version, dated 2008. :-)

Native web browser support

Safari 3.1 has native getElmentsByClassName support, and upcoming Firefox 3 and Opera 9.5 will have it too. It only leaves out, you’ve guessed it, Internet Explorer.

The necessity of this script

Living in a world where Microsoft is halting every possible way the web could evolve, this means that you will need a custom script for this for years to come. Also, the native version returns just a nodelist, as opposed to an array, which may somewhat limit your options to work with it.

New features

When I rewrote the script (download new version), there were a number of factors I wanted to include to make it the best script available for this task:

  • Utilize native getElementsByClassName support if it’s available.
  • Utilize native XPath support if it’s available.
  • Support multiple class names in the same call, in any order specified.
  • Return an actual array to work with, instead of just the native nodelists.

The way it works is that it detects the available native support, and then re-uses that for consecutive calls. This will lead top optimal performance for the end user experience. Please take a look at the demo page, which consists of a hefty 130 kb raw HTML, to compare execution times between call types, web browsers and platforms.

The script

The script should support basically any web browser being used today, and also has support back till IE 5.5. This is how the script now looks like:

/*
	Developed by Robert Nyman, http://www.robertnyman.com
	Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/	
var getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};

How to call it and parameters

Parameters

className
One or several class names, separated by space. Multiple class names demands that each match have all of the classes specified. Mandatory.
tag
Specifies the tag name of the elements to match. Optional.
elm
Reference to a DOM element to look amongst its children for matches. Recommended for better performance in larger documents. Optional.

Call examples

To get all elements in the document with a “info-links” class.
getElementsByClassName("info-links");
To get all div elements within the element named “container”, with a “col” class.
getElementsByClassName("col", "div", document.getElementById("container"));
To get all elements within in the document with a “click-me” and a “sure-thang” class.
getElementsByClassName("click-me sure-thang");

Download the new getElementsByClassName

The new version is available for download right as we speak, so by all means, download it, take it for a spin, and experience selecting elements through their class names cross-browser, cross-platform without having to worry about any differences. :-)

Posted in Developing,JavaScript,Technology,Web browsers |

164 Comments

  • […] completely rewritten version of getElementsByClassName has been released, taking into account all new available web bowser features and possibilities, to […]

  • […] Update to a classic javascript function (anno 2005, if not earlier) in order to take advantage of the native getElementsByClassName function or XPATH (if available, with fallback mechanisms in place) Spread the word! […]

  • kimblim says:

    Nice.

    In your first example, shouldn't it just say "..get all elements.." instead of "..get all a elements..", though?

  • Milo says:

    Why not use the Selectors API when it's available (e.g in IE8)?

  • Robert Nyman says:

    kimblim,

    Absolutely right, thanks! Updated the post.

    Milo,

    I did consider that a while, but the day IE 8 finally gets out (and I'm fairly sure we're not talking this year), I'm convinced that they will include native <code>getElementsByClassName</code>; if for no other reason, due to popular demand.

    With DOMAssistant, we rely on the Selectors API in web browsers that support it, and have XPath and other fallbacks when either the web browser fails, or if it's a non-standard selector.

    With this function, though, it is targeted solely at getting elements by class, and using the Selector API seems a bit overkill.

    However, if IE 8 for no reason won't support <code>getElementsByClassName</code>, then naturally, using Selectors will be the solution here.

  • Tino Zijdel says:

    This looks a lot like the revision I made almost a year ago (getElementsByClassName re-re-re-visited) except that I did not add namespace support (never had the need for it) and don't support the usecase where you want to have elements that match more than 1 particular class (never had the need for that either and only once I had the need to do the opposite – selecting elements that match either of a list of classes – which the native gEBCN doesn't support).

    I think partly as a result mine might be a bit faster…

  • Robert Nyman says:

    Tino,

    Ah, it looks very similar. :-)

    I thought that namespace support and especially multiple classes would make it a bit more complete. With just one class, the performance hit shouldn't be too bad. As you can see in my simple test page, the overall times are definitely good, in my opinion.

    Thinking so alike, perhaps we should write something together one day. :-)

  • Tino Zijdel says:

    Robert: I'd might be interesting to exchange thoughts someday yeah, contact me anytime :)

    By the way, for my employer I use a version of gEBCN that supports regular expression syntax for className (it does fallback to the 'generic' method in that case, but that's fast enough in most cases). Downside is that you can't do branching for the definition of the function itself.

  • Robert Nyman says:

    Tino,

    Yeah, such specific tweaks are definitely options in certain environments. Personally, though, I think that when one starts to make it fairly complex, the CSS selector approach with different JavaScript libraries seems more suitable and more tested.

    Also, I do hope we get to talk and meet one day. We'll just have to see what the future holds. :-)

  • Tino Zijdel says:

    fwiw: [a-z]+ doesn't match tags like h[1-6]. Besides, the whole regexp matching in the loop seems useless when 'tag' isn't given or equals '*'

    In your ultimate fallback it might be worth to branch when classesToCheck.length == 1 and first check for equality on .className which saves a (more expensive) regexp call in most cases ;)

  • Looks very complete, Robert!

    I've used a combination of a custom <code>Array.contains()</code> method and <code>element.className.split (' ')</code> to look for classes.

    Something like:

    <code>element.className.split (' ').contains ('searchClass');</code>

    I haven't dabbled in Xpath and the Selectors API yet actually, but from all I hear about it, I think it's about time I start learning :)

  • Eric Meyer says:

    Sweet. Thanks, Robert! One thing I'm wondering and wasn't clear to me from reading the JS ('cause I'm a JS n00b): does this version support the several-class <code>getElementsByClassName(document, "div", ["col", "left"]);</code> pattern of the older script, or no? Though I guess if it does the new pattern would be <code>getElementsByClassName(["col", "left"], "div", document);</code>.

  • Robert Nyman says:

    Tino,

    Ah, thanks for spotting the heading thing. And yes, the superfluous check when a tag isn't sent in has been removed too.

    However, with the fallback for IE, a regular expression is still necessary, since even though just one class name is sent in, the element might contain multiple ones, so it's necessary for checking and comparing.

    I've issued a new release, 1.0.1, with the above fixes, and have also updated the post above.

    Harmen,

    Thanks! Yes, the Selectors API and XPath is definitely something to dig into. :-)

    Eric,

    Thank you!

    It is almost as you mention it, but as opposed from the old version (and in line with the web browser native implementation) it doesn't need any array anymore, just the desired class names separated by spaces. Like, with your code:

    <code>getElementsByClassName("col left", "div", document);</code>

    Also, they don't have to be specified in that order on the actual HTML element either, so it will always work as long as they're present at all.

  • Grant Palin says:

    Nicely done Robert. Way to push the envelope with current and upcoming browser support for the native version.

  • Robert Nyman says:

    Grant,

    Thank you! :-)

  • Eric Meyer says:

    Ah, okay. I guess I misunderstood how that syntax worked with the old plugin– I thought it was an OR, not an AND as in traditional CSS. So, cool. Thanks again! You rock, sir.

  • Robert Nyman says:

    Eric,

    Thanks a lot! :-)

    I've always been a great fan of your CSS work and it has made my coding skills grow considerably, so any way I can give something back, I'm just happy to help!

  • You could tidy up a bit by self invoking and return the supported function (rather when redeclaring and recalling the script). Alternatively you could of course just scrap the wrapping the if statement all together (as every function costs performance, stylistic preferences take a back seat on my javascript).

    For looping through NodeLists and arrays…

    <code>var i = 0;

    while (current = elements[i++]) {

    }</code>

    Is faster and IMO easy to read than…

    <code>for(var l=0, ll=elements.length; l<ll; l+=1) {

    current = elements[l];

    }</code>

    Also <code>array[array.length]="foo";</code> runs faster than <code>array.push("bar");</code> and would have the small plus of adding IE5 support to you script.

    Since your going all out to make the "ultimate" version you may want to add the uses of xml.selectNodes for when IE is working with XML.

  • Robert Nyman says:

    Aldrik,

    Thanks for the input.

    The cost if if checking and applying is only run the first time the function is called, and it has then learned for consecutive calls which way to do it is the best way for that certain web browser/environment.

    With looping, I'm very reluctant to add variable assigning to expression checking, and it is also something that goes against the advice of JSLint.

    About scrapping <code>push</code> for adding it to the length of the array, it's something I thought of, both for performance and IE 5.0 support, so thanks for pointing that out. It will be in the next release!

    Like the idea about <code>selectNodes</code>, and I never really even thought about support in XML documents.

    Also, I just have to say that the name ultimate, at least on my behalf, is mostly ironic, since I believe that no function or method can truly ever become ultimate for all needs and scenarios. :-)

  • I'm aware that the statement runs only once, it's just that it could be written a bit more elegantly.

    <code>var getElementsByClassName = function (className, tag, elm){

    if (document.getElementsByClassName) {

    getElementsByClassName = function (className, tag, elm) {

    //…

    }

    return getElementsByClassName(className, tag, elm);

    };</code>

    vs

    <code>var getElementsByClassName = function (){

    if (document.getElementsByClassName) {

    return function (className, tag, elm) {

    //…

    }

    }();</code>

    vs

    <code>var getElementsByClassName;

    if (document.getElementsByClassName) {

    getElementsByClassName = function (className, tag, elm) {

    //…

    }</code>

    As for the <code>++</code> (and <code>–</code>) that is one of the few things I disagree with Crockford about (the other is wether one should extend JavaScripts base <code>Object</code>). But if you wish to fellow blindly, you could of course do the slightly less efficient and elegant…

    <code>var i = -1;

    while (current = elements[(i+=1)]) {

    //…

    }</code>

  • […] The ultimate getElementsByClassName, anno 2008 – Robert Nyman updates the useful script to include support for the native functions in Safari 3.1 and the upcoming Firefox 3 and Opera 9.5. Very nice. […]

  • Robert Nyman says:

    Aldrik,

    Well, what's elegant is just in the eye of the beholder, right? :-)

    With Crockford and ++, I'm on the same page as you.

    And no, I'm not following blindly, I agree on some things while I disagree on others.

  • I'm not sure word-boundary is a good test for your regex, other than that it looks good.

    var elem = elem || document;

    So simple :)

  • Robert Nyman says:

    Anthony,

    Ah, but that's only for checking actual node/tag names, which can only contain regular characters. In the script checking for class names, it instead checks for spaces and start/end of string, since word boundaries isn't complete there.

    And thanks! :-)

  • […] The ultimate getElementsByClassName, anno 2008 […]

  • […] Nyman has posted an updated version of his ultimate getElementsByClassName. It takes advantage of the native getElementsByClassName support in Safari 3, Firefox 3 and Opera […]

  • micke says:

    I used this function in a project at work and it works great! Thanks Robert!

  • Marcy Sutton says:

    Are there any examples of this in use? I am trying to use it in conjunction with PHP to get/set classes and I'm having some trouble.

  • Thanks heaps Robert – this script was just what I needed for my Intranet project.

    I owe you a beer!

  • Nejoom says:

    Hi thanks for this.

    I found this one surfing the web, it is very efficient, you might be able to adapt it to your method signature.

    Regards:

    // @http://gathering.tweakers.net/forum/list_messages/1025018
    var getElementsByClassName = function (className)

    {

    var classes = className.split(" ");

    var r = [];

    for(var j=0; j -1)

    {

    s = [document.documentElement || document.body], i = 0;

    do

    {

    e = s[i];

    while (e)

    {

    if (e.nodeType == 1)

    {

    if (e.className && re.test(e.className)) r[l++] = e;

    s[i++] = e.firstChild;

    }

    e = e.nextSibling;

    }

    }

    while (i–);

    }

    else

    {

    s = document.getElementsByTagName('*'), i = s.length;

    while (i–)

    {

    e = s[i];

    if (e.className && re.test(e.className)) r[l++] = e;

    }

    }

    }

    return r.length;

    }

    // @http://gathering.tweakers.net/forum/list_messages/1025018

  • sanish joseph says:

    actually am using ie7 this code is not at all useful for me. somebody please help me. i just solved my problem by using getelementsbytag() method.

  • Anth says:

    Thanks a lot !!!!!!!!!!!

  • John Goodwin says:

    Hi Robert, thanks for sharing.

    I realise the people above are only trying to assist with improvements, but I think it can be quite demoralising when all you seem to receive is suggestions for improvement or criticism, rather than recognition for what you have succeeded in doing.

    So, on behalf of all those who have found this script useful, helpful or just interesting;

    Cheers!! :-)

    John.

  • […] The ultimate getElementsByClassName […]

  • […] if this is an old thread, could still be of use to someone The ultimate getElementsByClassName, anno 2008 – Robert’s talk – Web development and Internet … Your Favourite getElementsByClassName – Snook.ca __________________ http://www.benshu.ch // Evolving […]

  • Vijay Krishna Ramesh says:

    This seems strange, and I'm assuming I'm overlooking something simple, but anyhow – I can't get the call to work in an onclick in FF3:

    <code><a href="javascript:;" onclick="someMatches = getElementsByClassName('someClass'); alert(someMatches.length);">test</code>

    However, it does work if I do it in a window.onload (like in your demo page – http://www.robertnyman.com/test/getelementsbyclas…. I've figured out a way around this, by simply adding a caller function to the end of the script:

    <code>getElementsByClassNameCaller = function(className,tag,elm){

    return getElementsByClassName(className,tag,elm);

    }

    </code>

    I'm hoping/assuming that I'm just doing something wrong, and that this shouldn't be needed (in IE, the straight call works fine, it is only in FF3 that I've been running into it returning 0 items always) – but if not, is this missing just because you normally only use this function in a window.onload? Or am I overlooking something here?

  • red says:

    Robert,

    Just a note on your exasperation with some critical posters who seemed to be picking your work apart without thought of a little – nice job, kudos – praise in passing.

    You might think of it this way; if people didn't find it valuable and worthy, they wouldn't have come back with their 'my trick is better' stuff, it wouldn't have been worth the time. I know, it's a back-handed form of respect. Some add their two-cents because they do think they contribute an improvement. Some are just trying to say, "Oh yeah, I can do it better." N'importe. Either way, they've acknowledged the value and quality of your work. Translate that subtext into the praise it really is and bask in it – much better than feeling you're not being validated or appreciated.

    Ps. judging from your banner photo, you might like the work of Robert Newport at http://www.doctorobertsart.com/ Oh,& I hope you're enjoying the time with the kids during your parental leave. Suck it up while you can, it passes so quickly…. best, red.

  • Robert Nyman says:

    Marcy,

    You need to provide more info for me to be able to help you.

    Paul,

    Great! :-)

    Nejoom,

    Absolutely, if you want to.

    sanish,

    You need to provide more info for me to be able to help you.

    Anth,

    You’re welcome!

    John Goodwin, red,

    Thank you!
    I appreciate the compliments, and I do like people giving feedback and tips; I mean, after all, that’s how it becomes even better and other people will surely be able to find things I’ve missed.

    The way I see it, if the input is something I really have to change I’ll update the code. Otherwise, the code is released under such a license that anyone can change it to their liking. :-)

    And red, thanks for the picture tips!

    Vijay Krishna Ramesh,

    Can’t tell what the problem is, but in general, you should never use inline event handlers, and especially not the javascript: protocol. Please read more in AJAX, JavaScript and Accessibility
    .

  • Works great in FF3 – having issues in IE6.

    Getting an 'Object doesnt support this property or method' error on this line:

    <code>nodeName = (tag)? new RegExp("b" + tag + "b", "i") : null,</code>

    Any ideas on how I can circumvent this?

    Thanks,

    -=Patrick=-

  • Robert Nyman says:

    Patrick,

    First, that line should never be executed, since it checks for native support for <code>document.getElementsByClassName</code> in the web browser, which certainly doesn't exist in IE 6.

    I'm guessing that you have probably already extended the document in some way, and that that triggers the error. If I take the <code>getElementsByClassName</code> code here and try it out in a clean page in IE 6 and IE 7 I get no errors.

    Please try that as well and see if the problem persists.

  • Mazza says:

    Robert,

    First off, like the new site design! :) Secondly, so I am having an issue here with the getElementsByClassName with only IE7 (havn’t tested with IE6); IE7 reports (with debugging enabled) that “Microsoft JScript runtime error: Object doesn’t support this property or method” and highlights the var classes = className.split(" "), line that occurs in the last else statement. This baffles me cause I use getElementsByClassName in another function within the same script and it runs without any errors. Can this function only be used once per page/script?

  • Robert Nyman says:

    Mazza,

    Thanks!

    Hmm, sounds weird. Please post a link to an example, or e-mail me, and I’ll let you know if I see something weird.

  • Tom Oakes says:

    Thanks! This cut my script time from ~25 seconds to ~6.

  • Lori says:

    I love this function! Am I correct to conclude that if elem is specified, and tag isn’t we should pass “” or null for tag instead of the old “*”? I noticed that I was running into a invalid regExp error in FF3 with tag = “*” (nodeName = (tag)? new RegExp(“\\b” + tag + “\\b”, “i”) : null,) since tag was evaluating as true — sorry it wasn’t too clear to me in the current documentation since I was use to using “*” with your previous version.

    Thanks again for the function!

  • Robert Nyman says:

    Lori,

    I'm glad that you like it!

    Actually, it's a minor flaw which was recently brought to my notice. <code>"*"</code> won't work, like you say, just pass in <code>null</code> to be completely safe. Like this:

    <code>getElementsByClassName("desired-class", null, document.body);</code>

    I'll fix this in the next release.

  • Mazza says:

    Hey Robert,

    As a follow-up to my post and our email correspondence, I looked more into the issue and I found out the root of the problem is that I am using your code on MediaWiki 1.11… looks like the folks of MediaWiki integrated either an old version or a hacked version of your getElementsByClassName into their wikibits.js file

    Figured I would post this as a comment instead of email for anyone else that may think about adding this to their MediaWiki! :D

  • Robert Nyman says:

    Mazza,

    Interesting. Hopefully MediaWiki will update their code. If not, please alert them. :-)

  • The Turtle says:

    Robert: thanks for this. It saved us from a sticky problem brought on by confused user requirements…

    Turtle

  • Nightfalcon says:

    Hi Robert,

    i'm using your fabulous script but am getting the same error like Mazza on IE7 when calling it like this:

    <code>function hideall()

    {

    var boxnr = 0;

    submenuboxes = getElementsByClassName(document, 'navigator');</code>

    <code>while (submenuboxes[boxnr])

    {

    submenuboxes[boxnr].style.display = 'none';

    boxnr++;

    }

    }</code>

    I'm hiding all div-containers with the class 'navigator' via onfocus-eventhandling and then view the active submenu-divcontainer ([…] onfocus="hideall(); displayactivebox('id', 'block')"[…])

    This works on all browsers except IE7, you got any idea to help me through this problem?

    The submenus are neccessary, you know? ;-)

  • Robert Nyman says:

    Nightfalcon,

    You're specifying the parameters in the wrong order. The first one should be classname, the second tag name (optional) and the third parent element (optional). Like this:

    <code>getElementsByClassName('navigator', null, document);</code>

  • […] it natively, you will need a wrapper script. There are many such scripts; I myself am partial to Robert Nyman’s Ultimate GetElementsByClassName. It uses the native getElementsByClassName() method in modern browsers that support it, then falls […]

  • […] however, native support for that doesn’t exist in all web browsers, Therefore I recommend the getElementsByClassName function, which also supports some other nifty features not available in any native web browser […]

  • […] The Ultimate GetElementsByClassName — Déjà évoquée ici, cette superbe fonction qui sélectionne les éléments par leur classe CSS a été mise à jour récemment. […]

  • John L. Clark says:

    Robert,

    I wanted to take advantage of some Firefox 3 features in our client, including the native `getElementsByClassName`. All was well and good, until our testers discovered some critical problems with Firefox 3, so we needed to step back to Firefox 2 (unfortunately). I still needed the gEBCN functionality, though, but I quickly discovered your implementation, dropped it in place, and it worked without any problems. This saved me a lot of time and energy. Thanks!

  • Robert Nyman says:

    John,

    Great to hear, I’m glad it helped you!

  • […] access, however, native support for that doesn’t exist in all web browsers, Therefore I recommend the getElementsByClassName function, which also supports some other nifty features not available in any native web browser […]

  • Andrew says:

    Rob, Script works great but I have a question. I have the function in the head with a link to pass the classname variable, but the link has to be clicked twice. The second click displays hidden items and then afterwards it works by clicking once.

    function toggle_visibility(className) {

    var e = getElementsByClassName(className, "div", document);

    for (var i = 0, len = e.length; i < len; ++i) {

    if (e[i].style.display == 'none') {

    e[i].style.display = 'block';

    }

    else {

    e[i].style.display = 'none';

    }

    }

    }

    + more

  • Robert Nyman says:

    Andrew,

    Thanks.

    Your problem seems to rather stem from the fact that your element doesn't have the style applied that you think; i.e. an element can be hidden from an external style sheet, but that doesn't set its <code>style.display</code> property to "none".

    You can read more in Get the rendered style of an element.

    So, you can either go down that windy road, or just work with classNames all the way through, i.e. one for block display and one for none.

    Good luck!

  • Andrew says:

    Thanks for the response Robert. You are correct, I am using nested repeaters that set an external style to all elements after a set number and then the function shows or hides the rest of the list for the designated catagory.

    If I want to just use the classnames all the way through how do I designate one for block and one for none? or would it just be easier to set inline styles on the repeater items?

    Thanks again.

  • Robert Nyman says:

    Andrew,

    Basically, just have something like this in your CSS:

    <code>.display-block {

    display: block;

    }</code>

    <code>.display-none {

    display: none;

    }</code>

    and then apply it accordingly in your code.

  • […] klasy getElementsByClassName mo?esz skorzysta? zagl?daj?c na stron? Robert-a Nyman-a, natomiast pozosta?e […]

  • Tetsuoo says:

    hmm it won't work in IE7 :( No problem in Firefox or Opera

    I included the JS file that way :

    ..and started to write my scripts as usual

    function etc…

    Any idea where i'm wrong ?

  • Tetsuoo says:

    oops.

    So, that way : <script type="text/javascript" src="getElementsByClassName.js"></script>

    (btw that "preview comment" stuff is amazing, how you do that ? Ajax ?)

  • Robert Nyman says:

    Tetsuoo,

    With the above code in the post, the functionality should be working.

    The comment preview is not AJAX, just a script that detects your keyboard input and puts the content in a preview element. :-)

  • Tetsuoo says:

    Hey thanks for the quick answer :D

    Well i'm back to say it's still not working ^^;

    I put a sample here : http://tetsuoo1.free.fr/bouffe/sample.php

    I used getElementsByclass to be able to check/uncheck every checkboxes ( try the "all / none" toggle).

    There is other ways to do that but i already used getElementById for something else and… it look more logical with your method, as an ID is supposed to be unique.

    ok, so you can see in the source code :

    function checkAll()

    {

    c = document.getElementsByClassName('cbx');

    for (i = 0; i < c.length; i++) {

    c[i].checked = true;

    }

    }

    function uncheckAll()

    {

    c = document.getElementsByClassName('cbx');

    for (i = 0; i < c.length; i++) {

    c[i].checked = false;

    }

    }

    And the checkboxes look like this :

    <input type="checkbox" class="cbx" id="cbx80" name="cbx[]" value="80">

    It works nice in Firefox or Opera.

    IE 7 don't like it, it's not recognized (error : "this object can't use this property or method" )

  • Robert Nyman says:

    Tetsuoo,

    You should use <code>getElementsByClassName</code> only, not <code>document.getElementsByClassName</code>.

    Why it works in any other web browser but IE is that they have native support for a <code>getElementsByClassName</code> method. This code, however, is just a stand-alone function which should not be called as a method of the <code>document</code> object.

  • Tetsuoo says:

    ok, i tried :

    c = getElementsByClassName('cbx'); —-> not working

    then :

    c = getElementsByClassName(document,'input','cbx'); —-> WORKS !!

    phew.

    Thanks again for your support :)

    (now maybe i'll try on Safari…haha no i'm joking;))

  • Tetsuoo says:

    Hi Robert,

    I'll be a little off topic :D

    After the tiny struggle with your class/function, i wanted to come back one day and say Hey i found out how you made your html Preview trick !

    Well it was easier than expected, and it works !! (almost)

    No Ajax involved, you were right, i'm discovering only now how much powerful JS is (after years of lazyness HTML coding and little PHP – what a shame, yeah i know)

    I just did this, with a simple onKeyUp event :

    function previewText()

    {

    var txt = document.form0.AreaText.value;

    document.getElementById('preview').innerHTML = txt;

    document.getElementById('preview').style.color='#36F';

    }

    ..and that's all folks ! (cartoon ending)

    Almost. Maybe i'll just STEAL some of your regex for replacing the smileys and all, because i HATE regex. Really. Regex are just not for "normal" human beings.

    So, thanks for giving me ideas, even when you don't want to (hehe :D)

  • Robert Nyman says:

    Tetsuoo,

    Glad you got it to work!

    However, in terms of regular expressions and its different syntax, I would really recommend learning.

    I did a number of years ago, and no mater what technology I've worked with, knowing reg exps has been invaluable!

  • […] The ultimate getElementsByClassName, anno 2008 – Robert’s talk – Web development and Internet tren… (tags: http://www.robertnyman.com 2009 mes1 dia9 getElementsByClassName JavaScript function) […]

  • real.code says:

    function getElementsByClassName(className, node)

    {

    var children = null, returnArr = [], i;

    var regexp = new RegExp("(^|s)"+ className +"(s|$)", "g");

    if ( node == undefined ) node = document.body;

    else if ( typeof node != "object" ) return([]);

    else if ( regexp.test(node.className) )

    returnArr[returnArr.length] = node;

    children = node.childNodes;

    for (i = 0; i < children.length; i++)

    {

    returnArr = returnArr.concat(

    getElementsByClassName( className, children[i] )

    );

    }

    return(returnArr);

    }

  • birey says:

    Hey Robert,

    Never mind on my problems with IE7, I fixed them using the help you gave Tetsuoo. Again, thanks, for the great tool!

  • birey says:

    Hmm, just noticed that my original post didn't show up. To summarize, I wasn't getting the script working in ie7, but it was due to the same issue of using var foo = document.getElementsByClassName("bar") instead of using the stand alone var foo = getElementsByClassName("bar") call. (Same as Tetsuoo)

    -Ben

  • Robert Nyman says:

    real.code,

    You will get a much better performance by utilizing native support.

    birey,

    Oh, well, good to hear that it worked out at least! :-)

  • Brent says:

    great implementation, helped me easily bypass the annoying IE.

    thanks!

  • […] getElementsByClassName()??Firefox 3, Opera 9.5, Safari 3.1, Google Chrome?????????????????????IE???????????????getElementsByClassName()?????????????????????????????????????????????Robert Nyman?????????????????????????????????getElementsByClassName??????????????????????? […]

  • quique says:

    Huge thanks man!!

    You saved me a lot of work!

    Why Microsoft hates us all??

  • Robert Nyman says:

    Brent,

    You're welcome!

    quique,

    Glad it helped. And yes, it's a good question. :-)

  • Marney says:

    Hi Robert,

    This script is just what I was looking for, but i'm not sure I am implimenting it in the right way.

    I am calling your function in the following way:

    function changeFontOne () {

    var oDivNormal = getElementsByClassName('websiteNormal');

    oDivNormal.style.fontFamily = "Times New Roman, Times, serif";

    oDivNormal.style.fontSize = "11px";

    oDivNormal.style.fontStyle = "italic";

    }

    But it does not seam to be working.

    I just want to be able to change the style depending on specific class names. I had it working no problems using getElementById but it would be much more flexible and powerful if I could change the style based on class names.

    Any direction would be appricated.

    Marney

  • Robert Nyman says:

    Marney,

    It is because the function returns an array, not an element reference. It does that since it can be one or several matches. To alter the matching elements, loop through them and do what you want to do. In your case:

    function changeFontOne () {

    // Get a reference to all mathcing elements

    oDivNormalArray = getElementsByClassName("websiteNormal");

    // Loop through each of them and do what you want to do

    for (var i=0, il=oDivNormalArray.length, oDivNormal; i<il; i++) {

    oDivNormal = oDivNormalArray[i];

    oDivNormal.style.fontFamily = "Times New Roman, Times, serif";

    oDivNormal.style.fontSize = "11px";

    oDivNormal.style.fontStyle = "italic";

    }

    }

  • […] [upmod] [downmod] The ultimate getElementsByClassName, anno 2008 – Robert’s talk – Web development and Internet tren… (robertnyman.com) 0 points posted 6 months, 4 weeks ago by trshant tags 4mdelicious […]

  • […] developed a few different ways to get the elements they want, including custom functions – like Robert Nyman’s getElementsByClassname – which take advantage of local browser support, but you’re still forced to account for those […]

  • Lùcaz says:

    very cool!!

  • […] The Ultimate GetElementsByClassName — Déjà évoquée ici, cette superbe fonction qui sélectionne les éléments par leur classe CSS a été mise à jour récemment. […]

  • Daniel says:

    Using a 3rd parameter doesn't work in IE8:

    Error: "Object doesn't support this property or method"

    The exception to this is if the 3rd param is just document.

    var items = getElementsByClassName("extra-content-1", "span", this);

    where ^this^ is a DOM element (containing div), i've also tried passing in: document.getElementById(this.id) as the 3rd param; no difference.

    Works fine in safari, opera, ff…

  • Daniel says:

    nevermind, it was the method by which I procured the IE DOM element… a little bit of extra testing with element.getElementsByTagName() revealed this.

  • Robert Nyman says:

    Lùcaz,

    Thank you!

    Daniel,

    Glad it worked out for you!

  • sameer says:

    Hello Mr.Robert ,

    I am just a beginner to JS . I have created a table in which there are onmouse() event handlers . This works fine in FF but doesnot work in IE . On searching I came to know that we have use this custom script . Can u please explain me how to use it .

  • Pat says:

    Like Patrick (another Patrick) above, watch out for a conflict with JavaScript frameworks (i.e. web widgets in uncertain environments).

    For example, since the Prototype framework attaches getElementsByClassName to the core Object and returns an Array instead of the expected NodeList, Robert's function will cause IE and older browsers to error.

    To work around this conflict, you can check to make sure that the getElementsByClassName function, if it exists, is indeed native:

    <code>if (document.getElementsByClassName && Object.prototype.getElementsByClassName === document.getElementsByClassName)</code>

    Note that they have thankfully depreciated the function in Prototype.

  • Robert Nyman says:

    sameer,

    You probably call the function like this the:

    <code>document.getElementsByClassName</code>, which is incorrect.

    It should be called like this:

    <code>getElementsByClassName</code>

    Pat,

    Good point. It was really annoying that Prototype hooked into real objects with a method name that was about to be standardized. Gladly, though, they have now moved on.

  • […] hadn’t checked the statistics for some time for my getElementsByClassName code, so you can just guess my surprise when I saw it has passed one million […]

  • […] getElementsByClassName() ??Firefox 3, Opera 9.5, Safari 3.1, Google Chrome ?????????????????????IE ???????????????getElementsByClassName() ?????????????????????????????????????????????Robert Nyman ????????????????????????????????? getElementsByClassName ??????????????????????? […]

  • Fredrik says:

    Hi,
    I think there’s something wrong with the native fast path (first block)?.
    First, all other paths do a tag = tag || "*"; initially and also, if actually passing a ‘*’ as tag Firefox 3.5 complains about invalid regexp (“*\b”). Should it use empty string instead of ‘*’?

  • Robert Nyman says:

    Fredrik,

    Yes, some browsers could complain on that, and the recommended way is to send in an empty string, null or false.

  • Fredrik says:

    ok, thanks.
    Not sure if you rate this snippet as a library component? In that case if would be nice to automatically add the ‘*’->null conversion.

    Currently tag name is obviously optional, but personally I quite often need both tag- and class-name in various combinations. That pattern is present in MochiKit as getElementsByTagAndClassName() http://mochikit.com/doc/html/MochiKit/DOM.html#fn-getelementsbytagandclassname
    Difference with youe code (apart from speed :) ) is that is is symmetric with regards to tag or class being null/optional. (i.e it has an explicit getElementsByTagName path).
    Perhaps that would be a case worth exploring performance profiles for also?

    (yes, I guess I should rather use a proper selector engine..)

  • Robert Nyman says:

    Fredrik,

    It’s a valid question, but generally I see this as a fast stand-alone and consistent getElementsByClassName across web browsers.

    For more advanced usage I’d probably recommend a selector engine as well.

  • […] the their class names instead. Please read the creator’s page for proper usage instructions. Original Source – check for terms of […]

  • […] dans les navigateurs. Pour y remédier, je recommande l’utilisation de la fonction getElementsByClassName qui contient par ailleurs quelques fonctionnalités […]

  • Luis Pabon says:

    Having some trouble with this and IE8.

    The statement "if (document.getElementsByClassName) {" is true on IE8 but still, the function is not supported resulting on execution stopping sharp.

    Am I missing something?

  • Luis Pabon says:

    Ahhh, Pat @ September 10th, 2009 at 3:39 had the key, the fix suggested works like a charm (prototype conflict) :)

    Thanks !!!

  • Robert Nyman says:

    Luis,

    Glad it works for you!

  • […] les éléments qui partagent une ou plusieurs classes. C’est là qu’intervient The Ultimate GetElementsByClassName déjà évoqué dans Utillisez le DOM et Javascript comme un chef pour redéfinir le comportement […]

  • mighty_child says:

    i wanna change lastPostUser

    <span class="lastPostUser" …

    when i use

    document.getElementsByClassName("lastPostUser").className = "catLink";

    it didnt work.. why? help me

  • Robert Nyman says:

    mighty_child,

    You just call it with <code>getElementsByClassName("lastPostUser")</code>, NOT having the word <code>document</code> before it.

  • Pritush says:

    i am using this for tabs , and need a bit help

    here is the code i am using

    <code>

    tab1

    tab1 content

    Click Here to go tab2

    tab2

    tab2 contents

    <code>

    on clicking, "Click Here to go tab2" user can go to next tab,

    is it possible to make user go to another tab ( div id="2" )editing onclick="click(this);"

  • Robert Nyman says:

    Pritush,

    Yes, you could easily use <code>getElementsByClassName</code> to do something like that. Also, if you use a JavaScript library, e.g. jQuery, there are a number of already existing tab plugins.

  • Toan says:

    can you fix with IE ?

    thanks

  • Robert Nyman says:

    Toan,

    It works fine in IE. Please make sure to call it with getElementsByClassName, i.e. not preceded by document.

  • Zu says:

    Hi!

    I try to use this function in next way:

    I have div with class tab_13

    I type

    <code>getElementsByClassName("tab_13").className="lighted";</code>

    but class doesn't change..

    then when I type

    <code>alert (getElementsByClassName("tab_13"));</code>

    I get <cite>[object HTMLDivElement]</cite>

    It seems that I go wrong somewhere… But where? :)

    Thanks for the answers!

  • Robert Nyman says:

    Zu,

    The function returns an an array. If you get multiple elements back, you need to loop over them; if you just want to change the first, write <code>getElementsByClassName("tab_13")[0].className="lighted";</code>

  • pakha says:

    ??, ??? ? ?? ??????? ???????. ??? ?? ???????? ?????????. ???????, ??? ? ??????!

  • Thank you! your code here helped me a lot in getting a difficult project (at least for my novice level) done.

    for some reason, even in Firefox, document.get—- wasn't working, but your function made it work flawlessly.

  • Robert Nyman says:

    Amit,

    Glad it was of help to you!

  • Robert Nyman says:

    Hugo,

    Glad you like it!

  • Hugo Lim says:

    something really really useful to my project. thanks! it works beautifully!

  • I think 'thank you' will be little for this great job

    i love it

    for (i = 0; i <= 1000000000000000000; i++)

    {

    document.write("Thank You!");

    }

  • Robert Nyman says:

    Abdulrahman,

    Thank you! :-)

  • Javier says:

    Hi Robert

    I'm very new to javascript and your code helped me a lot in a little project of my own. It's awesome!

    One thing though, I can get it to work using

    getElementsByClassName("class")

    but what about when I want do something like:

    document.getElementById("tableContainer").getElementsByClassName("class")

    since I have "class" elements both inside and outside of the tableContainer div, but just want to get ahold of the ones inside.

    I appreciate your help

    keep it up man!

  • Robert Nyman says:

    Javier,

    Thanks!

    If you want to look within a certain element, you need to specify it as the third parameter, i.e:

    getElementsByClassName("class", "*", document.getElementById("tableContainer"));

    The * character could be replaced by a certain tag name; for instance, if you want all the div elements, just replace the * with div.

  • Javier says:

    works flawlessly!

    you're the man!

    thanx again!

  • Ed Cole says:

    Thanks for the code; it saved me a lot of trouble today (I forgot to check my code on Internet Explorer, which was a big, public, mistake).

    If I had written it, I would probably have organized it like this:

    var getElementsByClassName = function (className, tag, elm){

    var g;

    if (document.getElementsByClassName) {

    g = function (className, tag, elm) {

    ….

    }

    else if (document.evaluate) {

    g = function (className, tag, elm) {

    ….

    }

    else {

    g = function (className, tag, elm) {

    ….

    }

    }

    return g;

    }();

    That way, you only have to go through the browser-capability selection once, when the function is defined.

    But this code is excellent and very helpful. Thanks again!

    Ed.

  • Coral says:

    This is brilliant code, thank you so much for sharing it!

    I've been attempting to implement a very similar function to one that was posted earlier, and I've been trying to execute the loop you gave that commenter but I think I must be doing something wrong (maybe a syntax issue since I'm not very familiar with Javascript):

    <code>function changeTextStyle() {

    elementArray = document.getElementsByClassName("hasevents");

    for(var i=0, i=elementArray.length; eventsElement; i) {

    eventsElement = elementArray[i];

    eventsElement.style.fontFamily = "Times New Roman, Times, serif";

    }

    }</code>

  • Coral says:

    You can disregard/delete the last post, I got the loop to work. :)

    Now I'm having issues accessing "a" tags. I can access any other tag it seems but that one.

    <code>var elementArray;

    function changeTextStyle() {

    elementArray = document.getElementsByClassName("hasevents", "a");

    for (var i=0; i<elementArray.length; i++ ) {

    elementArray[i].style.color = colorvalue;

    }

    }

    #######

    <div class="hasevents">Hello</div>

    </code>

    It changes the color as long as the "a" tag has no "href" following it, but once I put the link in it doesn't change the link color. Any thoughts you could give I'd be grateful for.

  • Duke says:

    Hi,

    How would I use getElementsByClassName from an external js file.

    I have this block in another file:

    function toggle(class){

    var t = getElementsByClassName(class);

    if (t) {

    for (var i=0; i<t.length;i++) {

    t[i].style.visibility= (t[i].style.visibility=="visible" || t[i].style.visibility=="" )?'hidden':'visible';

    }

    }

    };

    … and it wouldnt work in IE 8..

  • Robert Nyman says:

    Coral,

    Don't call it as document.getElementsByClassName, call it without document.

    Duke,

    Check for JavaScript errors and make sure the file is included before you call the function.

  • […] The Ultimate GetElementsByClassName – Sélectionner les éléments par leur classe avec getElementsByClassName. […]

  • Travis Hall says:

    I think I managed to reproduce Mazza's problem, from way back in September 2008. I'd been trying to get this working in a website based on some old technology (rather be using jQuery or similar for this stuff, but the client has good reasons not to pay for such an extensive rewrite), and discovered that it was working fine in some browsers, but not IE7. Mazza's tools would appear to be reporting the wrong line to him, because what I found is that the error occurs on the line "var elements = elm.getElementsByClassName(className),", but only when the third parameter has been specified when calling getElementsByClassName.

    So it appears that IE7 (or at least some versions – I suspect that the jscript implementation may change between minor versions of IE7) only implements getElementsByClassName on the document, not on elements within the document.

    I looked closely at the code, and realised that "elm = elm || document;" appears in all three major code branches. I also put it in as the first statement within the getElementsByClassName function, and lo-and-behold, now we test for the existence of the member function on the object on which we intend to call it (instead of just testing to see if it is implemented on document and hoping that everything else follows suit).

    And that fixes the problem… in that specific case. There's still an issue, though, because that function is written to test the capabilities of the browser only the first time it is called, and after that it bypasses that step. This means my approach messes up if I call getElementsByClassName first with no third parameter, and then passing an element (other than document) as they third parameter.

    The only way I can see to deal with that is to let the function test the method it uses every time it is run. (I guess you could set it up so that it bypasses the check after the first time it falls through to the second or third search algorithm, but depending on how you use it the efficiency gains may well be wiped out by not using document.getElementsByClassName when you can.) So that's what I'm doing.

  • Robert Nyman says:

    Travis,

    Yes, I think you need to be pragmatic about it. Tweak the code in any way you want to to suit your needs and potential problems.

  • gio says:

    Great work, thank you very much!!!

  • I just wanted to say thank you for your very helpful function! I’ve created a form-validation framework in Javascript and I didn’t want to have it depend on another framework (like jQuery). Hence, I was looking for a fast function that would get me elements by class name. Your function helped me out a lot. I’ve made sure to leave your copyright information in my source code.

    You can check my project out here and the source here.

  • Robert Nyman says:

    gio,

    Thanks!

    Vivin,

    Glad it helped you out! And thanks for sharing your code!

  • knot says:

    doesn’t work for me. returns an empty string.

  • Maria says:

    I am having trouble implementing the script. All I want to do is find out if a div of class “test” exists on the page, and if it does, output text.

    I have the script loaded, but cannot write the function. Any help appreciated!

    Thanks,
    Maria

  • mihai says:

    any update for IE9, FF4 ?

  • Robert Nyman says:

    knot,

    Well, it’s been working for people for a few years, so you need to describe the problem and web browser if you have a case that’s not working.

    Maria,

    If you have included the script, all you need to do is call:

    getElementsByClassName(“test”);

    which will return an array of results.

    mihai,

    It works fine and utilizes the native document.getElementsByClassname support there.

  • […] where getElementsByClassName is supported, but failing that you can fall back to custom version of getElementsByClassName and knit them together so that native browser support takes precendence over the other one. […]

  • Alex says:

    Big thnx=)
    That`s helped me very much.

  • Robert Nyman says:

    Alex,

    Thanks, glad you liked it!

  • […] The Ultimate GetElementsByClassName – Sélectionner les éléments par leur classe avec getElementsByClassName. […]

  • Túbal says:

    First of all, thank you for this function Robert, it was really helpful!!

    Time has passed though and it can be improved that’s why I’ve refactored & improved your function. You can have a look at my version here: http://blog.margenn.com/post/13835045360/getelementsbyclassname

    Also, I’ve written some QUnit tests.

    Tell me what you think ;)

  • Robert Nyman says:

    Túbal,

    Interesting!
    I’ll look into it more properly as soon as I get the time, but it looks good from what I’ve seen so far!

  • nandavanan says:

    Dude!!!!

    Saving my ass big time!!

    Thanks a ton!

  • pdr-martin says:

    Awesome!!!!
    After desperately looking for a solution to this problem and some discouraging trying-and-error I found your script and it works perfertly!
    Thanks a lot!!!

  • Robert Nyman says:

    nandavanan, pdr-martin,

    Glad it was useful!

  • Yanone says:

    Hi,

    are you aware that in IE7/8 the function throws an error when the first object in a <p>paragraph is a <span>? Or is it just me? Why like this, do you know?

    This works (first child is a div, second a span):

    <p>
    Test 1
    <div class="chartwell bars">
    <span style="color:#123456;">10</span>
    <span style="color:#CCC;">85</span>
    <span class="red">20</span>
    <span style="color:#FFF;">=</span>
    </div>
    Test2
    <span class="chartwell bars" style="font-size:24pt;">
    <span style="color:#123456;">1000</span>
    <span>85</span>
    <span style="color:#654321;">20</span>
    <span>=</span>
    </span>
    </p>

    This doesn’t (both span):

    <p>
    Test 1
    <span class="chartwell bars">
    <span style="color:#123456;">10</span>
    <span style="color:#CCC;">85</span>
    <span class="red">20</span>
    <span style="color:#FFF;">=</span>
    </span>
    Test2
    <span class="chartwell bars" style="font-size:24pt;">
    <span style="color:#123456;">1000</span>
    <span>85</span>
    <span style="color:#654321;">20</span>
    <span>=</span>
    </span>
    </p>

    I’m trying to select them using
    var objects = getElementsByClassName(‘chartwell’);
    regardless of their tag type, which is what getElementsByClassName was born for, right?

    Thank you!!

  • Robert Nyman says:

    Yanone,

    I’m sorry, I have no idea why that is.

  • We’re getting an “Unexpected quantifier” in IE 9 when compatibility mode is turned off.

    if(document.getElementsByClassName) passes, and it blows up on:
    nodeNode = (tag) ? new RegExp(“\\b” + tag + “\\b”, “i”) : null
    …if a tag of “*” is passed along.

    It makes some sense – either new RegExp(“\\b*\\b”) or /\b*\b/ will blow up in the Watch in the IE 9 debugger. “Match any number of word breaks” might just be sending things into a tizzy. You can put parentheses around the word break items and it will stop complaining, but the regex will still be invalid for the purpose that it looks to be meant for.

    Since it looks like a plain * is expected in the “all” case for other branches of the function, my best guess would be that this might be a little more regex-friendly:

    nodeName = (tag) ? new RegExp(“\\b” + tag.replace(“*”, “.*”) + “\\b”, “i”) : null,

    It seems to work when I made this modification.

  • Robert Nyman says:

    Ritchie,

    Thanks for the feedback.
    I haven’t looked at this function in a long time, but what you say makes sense.

    Easiest solution, albeit not entirely correct, would be to send in null instead of “*” for the tag parameter.

    Alternatively, feel free to tweak the script you use with your suggested solution.

    Best regards,
    Robert

  • […] The Ultimate GetElementsByClassName – Sélectionner les éléments par leur classe avec getElementsByClassName. […]

  • DutchSpeed says:

    Thank you!

    Is there also a minified version available?

  • Robert Nyman says:

    DutchSpeed,

    No. Just use that function in your editor or in any of the online services supporting it.

  • Craig says:

    Robert, this function does not work as expected. I must alert developer not to use it before it gets fixed.

    After running some tests I found the function returns nothing in the following scenario:

    1. the web page contains multiple tables.
    2. all of the tables have class name = “classname1″
    3. some of the tables have another class name = “classname2″

    after running getElementsByClassName(“classname1″,”table”), the function returns nothing when IT SHOULD return all tables whose class list match “classname1″ (all the tables)

  • […] populate it’s contents. In my case, as there was no framework support, I used Robert’s Ultimate getElementsByClassName to get the element by […]

  • Consigliere says:

    Thanks a lot Robert Nyman….. That really really helped me….. :)

  • good practice Robert, thanks a lot :D

  • Al Reid says:

    Thank you so much for this script. I had an issue where my code would not function in IE10 if I had my web site redirection set to stealth (it wraps the pages and a frame). Of course Chrome and FireFox had no problems at all with this. This saved me countless hours of frustration.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>