Zurück zum Artikel Javascript und Webstandards
In Kommentaren wird jeweils angegeben, von welchem Typ die das verwendete Objekte ist und von welchem ECMAScript-Kernobjekte bzw. DOM-Interface es abgeleitet ist. Der ECMAScript-Operator, um eine solche Instantiierung zu überprüfen, lautet instanceof. Deswegen notiere ich diese Verhältnisse nach dem Schema Eigene Variable instanceof Prototyp-Objekt.
window.document habe ich, pingelig wie ich bin, als Netscape-proprietär gekennzeichnet, auch wenn document eine Instanz von Document und HTMLDocument ist (in der DOM-Terminologie: document implementiert das Document-Interface). DOM Core und DOM HTML definieren dessen Eigenschaften und Methoden; diese sind dann auch als standardkonform gekennzeichnet, zum Beispiel document.getElementsByTagName. Das DOM definiert aber nicht, dass der Zugriff auf die Document-Instanz über window.document möglich ist. Dies ist für sich genommen eine auf Netscape-JavaScript beruhende Konvention.
/*
TableSort by frequency-decoder.com
Released under a creative commons nc-sa license (http://creativecommons.org/licenses/by-nc-sa/2.5/)
(...)
*/
// fdTableSort instanceof Object
var fdTableSort = {
// regExp_Currency instanceof RegExp
regExp_Currency : /^[£$€]/,
// regExp_Number instanceof RegExp
regExp_Number : /^(\-)?[0-9]+(\.[0-9]*)?$/,
// pos instanceof Number
pos : -1,
// cache instanceof Boolean
cache : false,
// cacheValues instanceof Object
cacheValues : {},
// uniqueHash instanceof Number
uniqueHash : 1,
// addEvent instanceof Function
addEvent : function (obj, type, fn) {
// obj instanceof HTMLElement bzw. irgendein Objekt, bei dem proprietäre Events passieren
// type instanceof String
// fn instanceof Function
if (obj.attachEvent) {
obj["e" + type + fn] = fn;
obj[type + fn] = function () { obj["e" + type + fn](window.event); };
obj.attachEvent("on" + type, obj[type + fn] );
} else {
obj.addEventListener(type, fn, false);
}
},
// stopEvent instanceof Function
stopEvent : function (e) {
// e instanceof Event bzw. proprietär
if (e == null) {
e = document.parentWindow.event;
}
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
/*@cc_on@*/
/*@if(@_win32)
e.cancelBubble = true;
e.returnValue = false;
/*@end@*/
return false;
},
// init instanceof Function
init : function () {
if (!document.getElementsByTagName) {
return;
}
// tables instanceof NodeList
var tables = document.getElementsByTagName('table');
// sortable instanceof Boolean bzw. HTMLTableCellElement
// headers instanceof NodeList
// thtext instanceof String
// columnNum instanceof Number
var sortable, headers, thtext, columnNum = 0;
// t instanceof Number
// tbl instanceof HTMLTableElement
for (var t = 0, tbl; tbl = tables[t]; t++) {
headers = tbl.getElementsByTagName('th');
sortable = false;
if (tbl.className.search(/sortable-onload-([0-9]+)/) != -1) {
columnNum = parseInt(tbl.className.match(/sortable-onload-([0-9]+)/)[1]) - 1;
}
// z instanceof Number
// th instanceof HTMLTableCellElement
for (var z = 0, th; th = headers[z]; z++) {
if (th.className.match('sortable')) {
if (tbl.className.match('sortable-onload') && z == columnNum) sortable = th;
thtext = fdTableSort.getInnerText(th);
while (th.firstChild) {
th.removeChild(th.firstChild);
}
// Create the link
// a instanceof HTMLAnchorElement
a = document.createElement("a");
a.href = "#";
a.onclick = th.onclick = fdTableSort.clickWrapper;
a.onkeypress = fdTableSort.keyWrapper;
a.appendChild(document.createTextNode(thtext));
a.title = "Sort on " + thtext;
th.appendChild(a);
th.appendChild(document.createElement('span'));
}
}
if (sortable) {
fdTableSort.initSort(sortable);
}
}
},
clickWrapper : function (e) {
// e instanceof MouseEvent bzw. proprietär
// Die Übergabe des Eventobjektes als Parameter an die Handlerfunktion ist nicht streng
// in DOM Events festgelegt, es ist eher eine Konvention aus Netscape-JavaScript;
// das Event-Objekt selbst ist ein Mix aus proprietären und standardisierten
// Eigenschaften und Methoden.
// targ instanceof HTMLElement bzw. HTMLTableCellElement
var targ;
if (!e) {
var e = window.event;
}
if (e.target) {
targ = e.target;
} else if (e.srcElement) {
targ = e.srcElement;
}
if (targ.nodeType == 3) {
targ = targ.parentNode;
}
while (targ.tagName.toLowerCase() != "th") {
targ = targ.parentNode;
}
targ.getElementsByTagName("a")[0].focus();
fdTableSort.initSort(targ);
return fdTableSort.stopEvent(e);
},
keyWrapper : function (e) {
// e instanceof KeyboardEvent bzw. proprietär
// targ instanceof HTMLElement bzw. HTMLTableCellElement
var targ;
if (!e) {
var e = window.event;
}
if (e.target) {
targ = e.target;
} else if (e.srcElement) {
targ = e.srcElement;
}
if (targ.nodeType == 3) {
targ = targ.parentNode;
}
while (targ.tagName.toLowerCase() != "th") {
targ = targ.parentNode;
}
// kc instanceof Number
var kc = e.keyCode != null ? e.keyCode : e.charCode;
// If an enter then initiate the sort
if (kc == 13) {
fdTableSort.initSort(targ);
return fdTableSort.stopEvent(e);
}
return true;
},
initSort : function (thNode) {
// thNode instanceof HTMLTableCellElement
// curr instanceof HTMLTableCellElement
var curr = thNode;
thNode.className = thNode.className + " sort-active";
document.getElementsByTagName('body')[0].style.cursor = "wait";
fdTableSort.pos = 0;
// Get the column position
while (curr.previousSibling) {
if (curr.previousSibling.nodeType != 3) fdTableSort.pos++;
curr = curr.previousSibling;
}
// Remove any old "reverse" class we might have previously added
// thCollection instanceof NodeList
var thCollection = curr.parentNode.getElementsByTagName('th');
// span instanceof NodeList bzw. HTMLElement
var span;
// i instanceof Number
// th instanceof HTMLTableCellElement
for (var i = 0, th; th = thCollection[i]; i++) {
if (i != fdTableSort.pos) {
th.className = th.className.replace('reverseSort','');
// Remove arrow
span = th.getElementsByTagName('span');
if (span.length > 0) {
span = span[span.length - 1];
if (span.firstChild) span.removeChild(span.firstChild);
span.appendChild(document.createTextNode("\u00a0\u00a0"));
}
}
}
// Get the table
// tableElem instanceof HTMLTableCellElement bzw. HTMLTableElement
var tableElem = thNode;
while (tableElem.tagName.toLowerCase() != 'table' && tableElem.parentNode) {
tableElem = tableElem.parentNode;
}
// Has a row color been defined in the table's className?
// style instanceof String
var style;
if (tableElem.className.search(/style-([\S]+)/) != -1) {
style = tableElem.className.match(/style-([\S]+)/)[1];
}
// Do we cache the results for this table?
fdTableSort.cache = tableElem.className.search(/cache-results/) != -1 ? true : false;
// Has the table a tbody ?
// N.B. By definition, tables can have multiple tbody tags
// this script assumes only one.
if (tableElem.getElementsByTagName('tbody')) {
tableElem = tableElem.getElementsByTagName('tbody')[0];
}
// trs instanceof NodeList
var trs = tableElem.getElementsByTagName('tr');
// trCollection instanceof Array
var trCollection = new Array();
// If the current tr has any th child elements then skip it..
// i instanceof Number
// tr instanceof HTMLTableRowElement
for (var i = 0, tr; tr = trs[i]; i++) {
if (tr.getElementsByTagName('th').length == 0) trCollection.push(tr);
}
// Try to get the column data type
// sortFunction instanceof Function
var sortFunction;
// txt instanceof String (später)
var txt = null;
// identical instanceof Boolean
var identical = true;
// firstTxt instanceof String
var firstTxt = "";
for (i = 0; i < trCollection.length; i++) {
cellTxt = fdTableSort.getInnerText(trCollection[i].getElementsByTagName('td')[fdTableSort.pos]);
if (i > 0 && txt != cellTxt) {
identical = false;
}
txt = cellTxt;
if (firstTxt == "") {
firstTxt = txt;
}
}
if (thNode.className.match('sortable-numeric')) {
sortFunction = fdTableSort.sortNumeric;
} else if (thNode.className.match('sortable-currency')) {
sortFunction = fdTableSort.sortCurrency;
} else if (thNode.className.match('sortable-date')) {
sortFunction = fdTableSort.sortDate;
} else if (thNode.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
sortFunction = window[thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1]];
} else if (fdTableSort.dateFormat(firstTxt) != 0) {
sortFunction = fdTableSort.sortDate;
} else if (firstTxt.match(fdTableSort.regExp_Number)) {
sortFunction = fdTableSort.sortNumeric;
} else if (firstTxt.match(fdTableSort.regExp_Currency)) {
sortFunction = fdTableSort.sortCurrency;
} else {
sortFunction = fdTableSort.sortCaseInsensitive;
}
// Call the JavaScript array.sort method, passing in our bespoke sort function
if (!identical) {
trCollection.sort(sortFunction);
}
// Do we need to reverse the sort?
// arrow instanceof String
var arrow;
if (thNode.className.match('reverseSort') && !identical) {
trCollection.reverse();
thNode.className = thNode.className.replace('reverseSort','');
arrow = " \u2191";
} else {
thNode.className = thNode.className.replace('reverseSort','');
thNode.className = thNode.className + ' reverseSort';
arrow = " \u2193";
}
span = thNode.getElementsByTagName('span');
if (span.length > 0) {
span = span[span.length - 1];
if (span.firstChild) {
span.removeChild(span.firstChild);
}
span.appendChild(document.createTextNode(arrow));
}
document.getElementsByTagName('body')[0].style.cursor = "auto";
thNode.className = thNode.className.replace("sort-active", "");
if (identical) {
return;
}
for (var i = 0, tr; tr = trCollection[i]; i++) {
if (style) {
tr.className = tr.className.replace(style,'');
tr.className = (i % 2 != 0) ? tr.className + " " + style : tr.className;
}
tableElem.appendChild(tr);
}
},
// getInnerText instanceof Function
getInnerText : function (el) {
// el instanceof HTMLElement
if (typeof el == "string" || typeof el == "undefined") {
return el;
}
if (el.innerText) {
return el.innerText;
}
// Added 27/03/2006 : Cache the text if the table has "cache-results" defined as a className
if (fdTableSort.cache && el.id && el.id in fdTableSort.cacheValues) {
return fdTableSort.cacheValues[el.id];
}
// txt instanceof String
// i instanceof Node
var txt = '', i;
for (i = el.firstChild; i; i = i.nextSibling) {
if (i.nodeType == 3) {
txt += i.nodeValue;
} else if (i.nodeType == 1) {
txt += fdTableSort.getInnerText(i);
}
}
if (fdTableSort.cache && el.tagName && el.tagName.toLowerCase() == 'td') {
if (!el.id) {
el.id = 'fd_uniqueid_' + fdTableSort.uniqueHash++;
}
fdTableSort.cacheValues[el.id] = txt;
}
return txt;
},
// dateFormat instanceof Function
dateFormat : function (dateIn) {
// dateIn instanceof String
// y instanceof String
// m instanceof String
// d instanceof String
// res instanceof Array
var y, m, d, res;
if (dateIn.match(/^(0[1-9]|1[012])([- \/.])(0[1-9]|[12][0-9]|3[01])([- \/.])(\d\d?\d\d)$/)) {
res = dateIn.match(/^(0[1-9]|1[012])([- \/.])(0[1-9]|[12][0-9]|3[01])([- \/.])(\d\d?\d\d)$/);
y = res[5];
m = res[1];
d = res[3];
} else if (dateIn.match(/^(0[1-9]|[12][0-9]|3[01])([- \/.])(0[1-9]|1[012])([- \/.])(\d\d?\d\d)$/)) {
res = dateIn.match(/^(0[1-9]|[12][0-9]|3[01])([- \/.])(0[1-9]|1[012])([- \/.])(\d\d?\d\d)$/);
y = res[5];
m = res[3];
d = res[1];
} else if (dateIn.match(/^(\d\d?\d\d)([- \/.])(0[1-9]|1[012])([- \/.])(0[1-9]|[12][0-9]|3[01])$/)) {
res = dateIn.match(/^(\d\d?\d\d)([- \/.])(0[1-9]|1[012])([- \/.])(0[1-9]|[12][0-9]|3[01])$/);
y = res[1];
m = res[3];
d = res[5];
} else {
return 0;
}
if (m.length == 1) {
m = "0" + m;}
}
if (d.length == 1) {
d = "0" + d;
}
if (y.length == 1) {
y = '0' + y;
}
if (y.length != 4) {
y = (parseInt(y) < 50) ? '20' + y : '19' + y;
}
return y + m + d;
},
// sortDate instanceof Function
sortDate : function (a, b) {
// a instanceof HTMLTableRowElement
// b instanceof HTMLTableRowElement
// aa instanceof String
var aa = fdTableSort.dateFormat(fdTableSort.getInnerText(a.getElementsByTagName('td')[fdTableSort.pos]));
// bb instanceof String
var bb = fdTableSort.dateFormat(fdTableSort.getInnerText(b.getElementsByTagName('td')[fdTableSort.pos]));
if (aa == 0 && bb != 0) {
return -1;
} else if (bb == 0 && aa != 0) {
return 1;
}
if (aa == bb) {
return 0;
}
if (aa < bb) {
return -1;
}
return 1;
},
// sortCurrency instanceof Function
sortCurrency : function (a, b) {
// a instanceof HTMLTableRowElement
// b instanceof HTMLTableRowElement
// aa instanceof String
var aa = fdTableSort.getInnerText(a.getElementsByTagName('td')[fdTableSort.pos]).replace(/[^0-9.]/g,'');
// bb instanceof String
var bb = fdTableSort.getInnerText(b.getElementsByTagName('td')[fdTableSort.pos]).replace(/[^0-9.]/g,'');
if ((isNaN(aa) || aa == "") && !isNaN(bb)) {
return -1;
} else if ((isNaN(bb) || bb == "") && !isNaN(aa)) {
return 1;
}
if (isNaN(aa) || aa == "") {
aa = 0;
}
if (isNaN(bb) || bb == "") {
bb = 0;
}
return parseFloat(aa) - parseFloat(bb);
},
// sortNumeric instanceof Function
sortNumeric : function (a, b) {
// a instanceof HTMLTableRowElement
// b instanceof HTMLTableRowElement
// aa instanceof Number
var aa = parseFloat(fdTableSort.getInnerText(a.getElementsByTagName('td')[fdTableSort.pos]));
// bb instanceof Number
var bb = parseFloat(fdTableSort.getInnerText(b.getElementsByTagName('td')[fdTableSort.pos]));
if ((isNaN(aa) || aa == "") && !isNaN(bb)) {
return -1;
} else if ((isNaN(bb) || bb == "") && !isNaN(aa)) {
return 1;
}
if (isNaN(aa) || aa == "") {
aa = 0;
}
if (isNaN(bb) || bb == "") {
bb = 0;
}
return aa-bb;
},
// sortNumeric instanceof Function
sortCaseInsensitive : function (a, b) {
// a instanceof HTMLTableRowElement
// b instanceof HTMLTableRowElement
// aa instanceof String
var aa = fdTableSort.getInnerText(a.getElementsByTagName('td')[fdTableSort.pos]).toLowerCase();
// bb instanceof String
var bb = fdTableSort.getInnerText(b.getElementsByTagName('td')[fdTableSort.pos]).toLowerCase();
if (aa == bb) {
return 0;
}
if (aa < bb) {
return -1;
}
return 1;
}
}
fdTableSort.addEvent(window, "load", fdTableSort.init);
Quelle: http://www.frequency-decoder.com/demo/table-sort/tablesort_v2.js. An der Funktionalität habe ich keine Änderungen vorgenommen, die Code-Formatierung habe ich vereinheitlicht und angepasst.
molily, molily@selfhtml.org, 2006-04-22