Hallo,
Der Code ist die Umsetzung. Die interessiert erst einmal nicht. Was ist das Konzept? Was ist das Ziel? Was sind die Vorteile? Wie verhält sich das zu gegenwärtigen Umsetzungen?
Du setzt (soweit ich das verstanden habe) Pseudoklassen mit public/private/protected-Sichtbarkeiten um. Okay. Warum? Weil es Gang und Gäbe ist? Weil es JavaScript fehlt? Weil das deiner Meinung nach »richtiges« OOP ist? Was heißt das alles? Wozu braucht man das? OOP umfasst verschiedene Paradigmen für verschiedene Zwecke. Klassen und effektive Sichtbarkeiten gehören nicht zwangsläufig dazu.
Vielleicht fängst du besser mit einem Prosatext über das Konzept an. So sagt das niemandem etwas.
Ich finde es ja am Beispiel immer am deutlichsten. Ich habe im Rahmen der Schul-Ag mal versucht, mit Javascript (xmtHTTP) und JSON eine Tabelle vom Server zu laden und diese mit "bearbeiten"-Buttons zu versehen. Ich habe vier Objekte:
1. DomCreator
2. InOutHandler
3. AjaxObjekt
4. ActionController
Ich finde, dass es schon jetzt nicht mehr ganz so übersichtlich ist, und dabei sind die "bearbeiten"-button-Funktionen noch nicht mal ausgeschrieben. (Immerhin ist der Code Jslint-konform (;-)).
An Sicherheit oder private Variablen denke ich zur Zeit garnicht, weiß auch nicht, wo ich die wirklich brauchen würde, außer eben, dass man den globalen Scope nicht mit eigenen Vars überschreibt. Dazu nutze ich dann "my" als Präfix für meine Objekte. Ob ich das ganze in eine selbstauführende Funktion packen sollte, weiß ich nicht. Vielleicht mag sich ja mal jemand den Code anschauen?
// Mozilla, Opera, Safari sowie Internet Explorer (ab v7)
var myDOMCreator = {
"buildElementWithTextOrNode" : function (elemName, textOrNode) {
var node, elem = document.createElement(elemName);
if (typeof textOrNode === "string") {
node = document.createTextNode(textOrNode);
} else if (typeof textOrNode === "object") {
node = textOrNode;
}
elem.appendChild(node);
return elem;
},
// third parameter optional (if set "header" creates headerline using "<th>" instead of
// "</td>" and the keys instead of values for the contents (column-names)
"buildRow" : function (rowAsObject, firstCol, headerOrRow, callback) {
var i, controlElement, cellElement, rowElem, cellValue;
cellElement = headerOrRow === "header" ? "th" : "td";
rowElem = document.createElement("tr");
rowElem.id = headerOrRow === "header" ? "header" : "nr" + firstCol;
// row number in first column
rowElem.appendChild(this.buildElementWithTextOrNode(cellElement, firstCol));
for (i in rowAsObject) {
if (rowAsObject.hasOwnProperty(i)) {
cellValue = headerOrRow === "header" ? i : rowAsObject[i];
rowElem.appendChild(this.buildElementWithTextOrNode(cellElement, cellValue));
}
}
if (headerOrRow === "header") {
controlElement = "bearbeiten";
} else {
controlElement = this.buildElementWithTextOrNode("button", "bearbeiten");
controlElement.onclick = function () {
callback(this);
};
}
rowElem.appendChild(this.buildElementWithTextOrNode(cellElement, controlElement));
return rowElem;
},
"tabelize" : function (table, callback) {
var i, nextRow, tableElem;
tableElem = document.createElement("table");
// header Row
tableElem.appendChild(this.buildRow(table[0], "rowNr", "header"));
// data
for (i in table) {
if (table.hasOwnProperty(i)) {
nextRow = this.buildRow(table[i], i, "row", callback);
tableElem.appendChild(nextRow);
}
}
return tableElem;
}
};
var myInOut = {
"actionController" : "",
"buttons" : document.getElementById("getselect").getElementsByTagName("button"),
"setup" : function (actionController) {
this.actionController = actionController;
this.setupListeners();
},
"setupListeners" : function () {
var i;
for (i = 0; i < this.buttons.length; i += 1) {
this.buttons[i].onclick = this.actionController.getTable;
}
},
"divs" : {
"data" : document.getElementById("data"),
"response" : document.getElementById("response")
},
"reset" : function (whichDiv) {
this.divs[whichDiv].innerHTML = new Date() + "<br>";
},
"addHTML" : function (string, whichDiv) {
this.divs[whichDiv].innerHTML += string + "</br>";
},
"addDOMTable" : function (table) {
this.divs.data.appendChild(myDOMCreator.tabelize(table, this.actionController.bearbeiten));
},
"setupUpdateRow" : function (button) {
var cellElement, updateButton;
cellElement = button.parentNode;
updateButton = myDOMCreator.buildElementWithTextOrNode("button", "update");
updateButton.onclick = function () {
//this ist der button
myInOut.actionController.update(this);
};
cellElement.replaceChild(updateButton, button);
}
};
var myAjax = {
"xmlhttp" : new XMLHttpRequest(),
"get" : function (getUrl, callback) {
this.xmlhttp.open('GET', getUrl, true);
this.xmlhttp.onreadystatechange = callback;
this.xmlhttp.send(null);
}
};
var myActionController = {
"type" : "", // json oder html momentan
"getTable" : function () {
var getType, getUrl;
getType = this.innerHTML;
myActionController.type = getType;
myInOut.reset("data");
myInOut.reset("response");
getUrl = 'http://html-ag.wvs-berlin.de/JSON/json_objekt_test.php?' + getType;
myAjax.get(getUrl, myActionController.onreadystatechange);
},
"onreadystatechange" : function () {
// this bleibt das xmlhttpobjekt
myInOut.addHTML("readyState = " + this.readyState, "response");
if (this.readyState === 4 && this.status === 200) {
if (myActionController.type === "json") {
myInOut.addHTML("<h2>json</h2>", "data");
var table = JSON.parse(this.responseText);
myInOut.addDOMTable(table);
} else if (myActionController.type === "html") {
myInOut.addHTML("<h2>html</h2>", "data");
myInOut.addHTML(this.responseText, "data");
}
}
},
"bearbeiten" : function (button) {
// just forwarding for the sake of "dont overrule the action controller"
myInOut.setupUpdateRow(button);
},
"update" : function (button) {
/*global alert */
alert("noch nicht fertig: " + button);
}
};
myInOut.setup(myActionController);
Das ganze ist zu bewundern unter http://html-ag.wvs-berlin.de/JSON/json_tests_6.js.html, bzw. die Serverantworten auf den xmlHttpRequest sind JSON oder html.
Es war Teil des Ansatzes, mal den Unterschied zu demonstieren, wie es ist, den Server das html liefern zu lassen und das nur in den output einzubauen mit innerHTML oder sich die Tabelle als JSON-Objekt zu holen und das Einbauen Javascript zu überlassen. Hier geht es nicht(!) um Browser, bei denen Javascript ausgeschaltet sein könnte (;-).
Vielleicht aber kann man an dem Beispiel ja mal erklären, ob und wenn ja was daran OOP ist und was da fehlt oder unelegant ist (mal unabhängig davon, das YUI oder jquery diese Funktionen zu Teilen bereit stellen). Es geht eben vielmehr ums prinzipielle Verständnis anhand eines Beispiels (weiß nicht, ob das jetzt Thread-Injection ist und ich lieber einen eigenen aufmachen sollte).
Gruß
jobo