gruss Felix, hallo interessierte,
Du suchst nach einer Art "getElementsByClassName()"
ich habe Dir meine Funktion herausgesucht. Hier ist sie:
// getElementsByClassName : function (className, element) {
var getElementsByClassName = function (className, element) {
//wird spaeter benoetigt:
var nodeObj, nodeClassName, regXTrim = (/^\s+|\s+$/g), regXShrink = (/\s+/g);
> //element = element ? element : document; // das ist keine hinreichend genaue pruefung - besser:
element = ((element && ((typeof element.getElementsByTagName == "function") || (typeof element.getElementsByTagName == "object"))) ? (element) : (document.documentElement || document.getElementsByTagName("html")[0]));
//auf korrektes [className] attribut wird gar nicht geprueft - kann man z.b. so bewerkstelligen:
//*undefinierte* [className] ausdruecke, resultieren in einer *wildcard*-suche:
className = ((className) ? (String(className).replace(regXTrim, "").replace(regXShrink, " ")) : ("*"));
> //var muster = new RegExp("(^|\\s)" + className + "(\\s|$)");
//die naechste zeile beruecksichtigt den gerade erwaehnten *wildcard* modus:
var muster = new RegExp(((className == "*") ? ("^.+$") : ("(?:^|\\s)" + className + "(?:$|\\s)")), "");
> //var alles = element.getElementsByTagName("*");
> //var gefunden = new Array();
> //var i;
//zusammenfassen:
var i, len, gefunden = [], alles = element.getElementsByTagName("*");
> //for (i = 0; i < alles.length; i++) {
for (i=0, len=alles.length; i<len; ++i) {
> //if (alles[i] && alles[i].className && alles[i].className != "") {
//---------------------------------------------------------^^ genauer:
//if (alles[i] && alles[i].className && alles[i].className !== "") { besser noch:
nodeObj = alles[i];
nodeClassName = nodeObj.className;
//normalisiert alle *white spaces*, um jegliche inkonsistenzen/manipulationen auszuschliessen:
nodeClassName = (((typeof nodeClassName != "undefined") && !((typeof nodeClassName == "object") && !nodeClassName)) ? (String(nodeClassName).replace(regXTrim, "").replace(regXShrink, " ")) : (""));
> //if (alles[i].className.match(muster)) // für Fälle wie class="xyz abc"
if (muster.test(nodeClassName)) {
> //gefunden[gefunden.length] = alles[i];
gefunden[gefunden.length] = nodeObj;
> }
> }
>
> return gefunden;
> };
~~~
oder auch kuerzer unter zuhilfenahme des generischen [[Array]]-iterators [filter]:
~~~javascript
var getElementsByClassName = (function (className, nodeObj) {
var nodeClassName, regXClassName, regXTrim = (/^\s+|\s+$/g), regXShrink = (/\s+/g);
nodeObj = ((nodeObj && ((typeof nodeObj.getElementsByTagName == "function") || (typeof nodeObj.getElementsByTagName == "object"))) ? (nodeObj) : (document.documentElement || document.getElementsByTagName("html")[0]));
className = ((className) ? (String(className).replace(regXTrim, "").replace(regXShrink, " ")) : ("*"));
var regXClassName = new RegExp(((className == "*") ? ("^.+$") : ("(?:^|\\s)" + className + "(?:$|\\s)")), "");
return Array.filter(nodeObj.getElementsByTagName("*"), (function (elm/*, idx, arr*/) {
nodeClassName = elm.className;
nodeClassName = (((typeof nodeClassName != "undefined") && !((typeof nodeClassName == "object") && !nodeClassName)) ? (String(nodeClassName).replace(regXTrim, "").replace(regXShrink, " ")) : (""));
return regXClassName.test(nodeClassName);
}));
});
~~~
aber selbst die korrigierte bzw. die iterierende loesung sucht multiple
klassennamen immer noch in einem \*strict\*-modus - d.h.: die reihenfolge
der einzelnen schluesselwoerter innerhalb eines solchen mutiplen namens
wird durch den jetzigen suchausdruck streng beruecksichtigt - die durch
die css-spezifikation erlaubten abweichungen in der reihenfolge sowie
auslassungen sind hier ausschlusskriterien und lassen die funktion nicht
getreu dieser spezifikation arbeiten.
sowohl suchausdruck als auch zu vergleichende [className]-elementattribute
verlangen mehr aufmerksamkeit. um den regulaeren ausdruck fuer die suche
fit zu machen, bietet es sich an, eine subroutine zu schreiben. benoetigt
wird eine von reduntanten eintraegen bereinigte liste, aller im multiplen
klassennamen vorkommender schluesselwoerter. darauf laesst sich dann ein
simpler algorithmus stricken, der den anspruchsvolleren suchausdruck generiert:
~~~javascript
//[http://www.pseliger.de/jsExtendedApi/jsApi.Array.normalize.js] - [http://www.pseliger.de/jsExtendedApi/jsApi.Array.normalize.dev.js]
Array.prototype.normalize = (function() {var arr=this,i=0,k=0;while(i<arr.length){k=i+1;while(k<arr.length){if(arr[i]===arr[k]){arr=arr.slice(0,k).concat(arr.slice(k+1,arr.length));--k;}++k;}++i;}for(i=0;i<arr.length;++i){this[i]=arr[i];}this.length=arr.length;});
var regXSplit = (/\s+/);
var getRegExpSearchTerm = (function (str) {
if (regXSplit.test(str)) {
var arr = str.split(regXSplit).sort();
arr.normalize();
str = arr.shift();
arr.forEach(function (elm/*, idx, arr*/) {
str += ("\\s(?:" + elm + "|(?:[^\\s]+\\s)+" + elm + ")");
});
}
return str;
});
var className = "confused happy ashamed joyful joyful ashamed";
var regXClassName = new RegExp(((className == "*") ? ("^.+$") : ("(?:^|\\s)" + getRegExpSearchTerm(className) + "(?:$|\\s)")), "");
alert(regXClassName);
~~~
die werte aller [className]-elementattribute muessen ebenfalls
sortiert, normalisiert und in einen stringwert zuruckgefuehrt
werden, sobald es sich bei einem solchen attributwert um eine
multiple klasse handelt.
dannach darf endlich verglichen werden - fertig.
obige erklaerungen in code gegossen - ich bitte um tests und rueckmeldungen:
~~~javascript
var getElementsByClassName = (function (className, nodeObj) {
var nodeClassName, regXClassName, regXTrim = (/^\s+|\s+$/g), regXShrink = (/\s+/g), regXSplit = (/\s+/);
var getRegExpSearchTerm = (function (str) {
if (regXSplit.test(str)) {
var arr = str.split(regXSplit).sort();
arr.normalize();
str = arr.shift();
arr.forEach(function (elm/*, idx, arr*/) {
str += ("\\s(?:" + elm + "|(?:[^\\s]+\\s)+" + elm + ")");
});
}
return str;
});
nodeObj = ((nodeObj && ((typeof nodeObj.getElementsByTagName == "function") || (typeof nodeObj.getElementsByTagName == "object"))) ? (nodeObj) : (document.documentElement || document.getElementsByTagName("html")[0]));
className = ((className) ? (String(className).replace(regXTrim, "").replace(regXShrink, " ")) : ("*"));
var regXClassName = new RegExp(((className == "*") ? ("^.+$") : ("(?:^|\\s)" + getRegExpSearchTerm(className) + "(?:$|\\s)")), "");
return Array.filter(nodeObj.getElementsByTagName("*"), (function (elm/*, idx, arr*/) {
nodeClassName = elm.className;
nodeClassName = (((typeof nodeClassName != "undefined") && !((typeof nodeClassName == "object") && !nodeClassName)) ? (String(nodeClassName).replace(regXTrim, "").replace(regXShrink, " ")) : (""));
if (regXSplit.test(nodeClassName)) {
nodeClassName = nodeClassName.split(regXSplit).sort();
nodeClassName.normalize();
nodeClassName = nodeClassName.join(" ");
}
return regXClassName.test(nodeClassName);
}));
});
~~~
so long - peterS. - pseliger@gmx.net
--
»Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - [Douglas Crockford](http://javascript.crockford.com/)
[ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:\]](http://www.peter.in-berlin.de/projekte/selfcode/?code=ie%3A%28+fl%3A%29+br%3A%3E+va%3A%28+ls%3A%26+fo%3A%29+rl%3A%29+n3%3B%7D+n4%3A%7D+ss%3A%7D+de%3A%B5+js%3A%7D+mo%3A%3F+zu%3A%5D)