PDA

View Full Version : [JS] Document.getElements



icio
March 11th, 2007, 11:54 AM
I've been meaning to do something like this for a while - it's always a pain in JS to have to write multiple loops for finding elements to meet certain criteria (for example, an group of elements inheriting some specific classes that are below an element of a specific tag below a specific element).

Most of you now will be thinking about prototype's `$` function which allows you to specify the sort of tags you want in the form you would for CSS. I have stolen this idea and written it up without anything else added to it. All this does is return an array of elements based on the CSS-based string you provide.

For example, you can simply use `document.getElements("a")` to return an array of all A elements, similar to `document.getElementsByTagName("a")` but say then, you want only the ones from that array that inherit a specific class. You can use my function like this: `document.getElements("a.class")` whereas using `document.getElementsByTagName` would then require a for loop after the call to filter the elements.

So lets say you want to select all of the anchor elements inheriting the class "linkage" that are contained within a span element in your main #content element:

document.getElements("#content span a.linkage");will return all of the elements that meet these criteria.

Update:
I have not added a new parameter to the function: `s`. S can reference an element that all of the returned elements must by a child of on some level. This is useful for where you have a reference to an element in javascript, but there is no distinguishable link in the html.

So, for example, lets say you have several <a> elements throughout your HTML and several list <li> elements. Now lets say that you're only interested in <li> elements that meet a certain requirement and you have managed to select one and have a variable `li` which references it. You can select the <a> elements withni this 'ambiguous' <li> as follows:

var a_li = document.getElements("a", li);
Which would be similar to `var a_li = li.getElementsByTagName("a");` except you have the option of expanding this to look for class names and sub-elements.
(end of update)

Update:
I was experiencing a bug in Internet Explorer where my usage of a variable named `class` within an object was causing runtime errors. I've renamed it to solve the problem. I also, at some stage, appear to have renamed the `s` parameter to `elem`. It's still pretty self-explanatory, though.
(end of update)

Anyway, here's the code:

/**
* Get arrays matching a CSS-Style search query
* @param string e The CSS search query
* @param element elem A specific element to search within (defaults to document.body)
* @return array The found elements matching the query
*/
document.getElements = function(e, elem) {
if (!e || !e.length || e.length == 0)
return [];
var store = [elem||document.body];
var store_t = [];
e = e.split(" ");
for (var i=0; i<e.length; i++) {
var r = {
id: "",
tag: "*",
clas:[]
};
var c, s, t=e[i];
while (t.length > 0) {
s = t.search(/.[#\.]/) + 1 || t.length;
c = t.substr(0, s);

if (c.substr(0, 1) == "#") r.id = c.substr(1);
else if (c.substr(0, 1) == ".") r.clas.push(c.substr(1));
else r.tag = c;

t = t.substr(s);
}
while (store.length > 0) {
var curr = [], temp = store.shift().getElementsByTagName(r.tag);
for (var j=0; j<temp.length; j++) {
curr.push(temp[j]);
}
while (curr.length > 0) {
var ok = true, ce = curr.shift();
if (r.id && ce.id!=r.id) ok = false;
for (j=0; j<r.clas.length; j++) {
if ((" "+ce.className+" ").indexOf(" "+r.clas[j]+" ") == -1) {
ok = false;
break;
}
}
if (ok) store_t.push(ce);
}
}
store = store_t;
store_t = [];
}
return store;
};

If you find any bugs, let me know (Not that i'll necessarily do anything about it, lol).
Hope this helps :thumb:

Icy Penguin
March 11th, 2007, 06:03 PM
Works like a dream for me. Thank you!

Esherido
March 11th, 2007, 06:15 PM
Nice function icio. :thumb2:

icio
March 12th, 2007, 09:08 PM
Glad it worked for you Penguin. And thanks, Esherido.

The thing I like about it is that it actually returns an Array type object of HTML elements instead of a HTMLCollection type object of HTML elements, meaning you can pop, push, shift and unshift as you would with any normal array (seeing as though it is one..)

somnamblst
March 17th, 2007, 09:08 AM
icio

this thread caught my attention because I am an arthead who recently figured out how to make scriptaculous.js do what I wanted.

Do you have an example of something you created with this?

icio
April 13th, 2007, 07:50 AM
somnamblst: it's uses are many. It's not really something that you can use for something by itself, it is supposed to be implemented into other things.

somnamblst
April 13th, 2007, 02:17 PM
Thanks icio. I am not a mathhead so I do struggle with things like scriptaculous & jquery Thickbox. I tried implementing all 3 workaround scripts that claim to force jquery to not disrupt prototype but it just introduces errors and the scriptaculous blind effect doesn't work.

http://docs.jquery.com/Using_jQuery_with_Other_Libraries

hybrid101
April 14th, 2007, 03:28 AM
another great code example icio, nice library you made on my laptop so far;)