/*************************************************** * JavaScript-Framework für interaktive Lernaufgaben **************************************************** * * V 2.5 (2012/03/18) * * Dieses Script wandelt Teile einer Website * in interaktive Quiz-Aufgaben um. Dazu orientiert * es sich an CSS-Klassen einzelner HTML-Elemente. * Dadurch können interaktive Aufgaben auf Websiten * in einem einfachen WYSIWYG-Editor erstellt * werden. Die Interaktion geschieht dann mittels * dieses nachgeladenen Javascripts. * * SOFTWARE LICENSE: LGPL * (C) 2007 Felix Riesterer * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Felix Riesterer (Felix.Riesterer@gmx.net) */ var Quiz = { triggerClass : "-quiz", /* Variable, in der das Suffix der CSS-Klasse steht, auf die das Script reagiert, um eine Übung als solche zu erkennen und umzuwandeln. Es gibt derzeit folgende Übungen, deren Klassennamen wie folgt lauten: * Zuordnungsspiel -> class="zuordnungs-quiz" * Lückentext-Aufgabe -> class="lueckentext-quiz" * Memo -> class="memo-quiz" * Multiple Choice - Quiz -> class="multiplechoice-quiz" * Schüttelrätsel -> class="schuettel-quiz" * Kreuzworträtsel -> class="kreuzwort-quiz" */ poolClass : "daten-pool", // CSS-Klasse für das Element, in welchem die zu ziehenden Felder liegen feldClass : "feld", // CSS-Klasse für Datenfelder fertigClass : "geloest", // CSS-Klasse für gelöstes Quiz bewertungsClass : "quiz-bewertung", // CSS-Klasse für den Textabsatz mit den Bewertungsergebnissen highlightClass : "anvisiert", // CSS-Klasse für das Ziel-Highlighting highlightElm : null, // hier steht später eine Referenz auf das HTML-Element, welches gerade als potenzielles Ziel anvisiert wird baseURL : false, // enthält später den Pfad zum Ordner dieses Scripts codeTabelle : false, // wird später durch ein nachgeladenes Script mit einem Objekt befüllt draggableClass : "quiz-beweglich", // CSS-Klasse, die ein Element für Drag&Drop freigibt, damit es beweglich wird. draggedClass : "quiz-gezogen", // CSS-Klasse, wenn ein Element gerade bewegt wird. dragMode : false, // entscheidet, ob ein Element bei onmousedown gezogen werden soll, oder nicht dragElm : null, // hier steht später eine Referenz auf das HTML-Element in dem der mousedown stattfand dragElmOldVisibility : "", // hier steht später der originale Wert des gezogenen Elements (wird für's Highlighten verändert) mouseLastCoords : { // wird später mit den Mauskoordinaten überschrieben werden left : 0, top : 0 }, // Anzahl mouseover-Events, nach denen das Drag-Element unsichtbar geschaltet wird (reduziert das Flimmern beim Draggen) visibilityCountDefault : 5, // Hier findet später der Countdown statt, um das Drag-Element nicht bei jedem mouseover-Event unsichtbar zu schalten visibilityCount : 0, // Platzhalter für Eventhandler oldWinOnLoad : "leer", oldDocOnMouseMove : "leer", oldDocOnMouseOver : "leer", oldDocOnMouseUp : "leer", oldDocOnKeyUp : "leer", // Alle Quizze auf einer Seite werden hier beim Initialisieren abgespeichert alleQuizze : new Object(), // Das gerade benutze Quiz aktivesQuiz : null, domCreate : function (params) { var el, p; /* "params" ist ein Objekt mit folgender Struktur: { tagName : "p", // z.B. für
text : "einfach ein Text" // als Kind-Textknoten des Elements ... // weitere (native) Eigenschaften (wie id, className etc.) } */ if (params.tagName && params.tagName.match(/[a-z]/)) { el = document.createElement(params.tagName); for (p in params) { if (p.match(/^text/i)) { el.appendChild(document.createTextNode(params[p])); } else { if (!p.match(/^tagname$/i)) { el[p] = params[p]; } } } } return el; }, domSelect : null, // Hier steht später eine Referenz auf die Sizzle-Engine each : function(o, cb, s) { // Die each-Methode wurde aus dem TinyMCE-Projekt (von Moxiecode.com) entnommen. var n, l; if (!o) return 0; s = s || o; if (o.length !== undefined) { // Indexed arrays, needed for Safari for (n=0, l = o.length; n < l; n++) { if (cb.call(s, o[n], n, o) === false) return 0; } } else { // Hashtables for (n in o) { if (o.hasOwnProperty(n)) { if (cb.call(s, o[n], n, o) === false) return 0; } } } return 1; }, init : function () { // baseURL herausfinden var q = this; q.each(document.getElementsByTagName("script"), function (s) { if (s.src && s.src.match(/\/quiz.js$/)) { q.baseURL = s.src.substr(0, s.src.lastIndexOf("/") + 1); } }); // Sizzle-Engine einbinden document.getElementsByTagName("head")[0].appendChild( q.domCreate({ tagName : "script", type : "text/javascript", src : Quiz.baseURL + "sizzle.js" }) ); // Mehrsprachigkeit einbinden document.getElementsByTagName("head")[0].appendChild( q.domCreate({ tagName : "script", type : "text/javascript", src : Quiz.baseURL + "multilingual.js" }) ); // UTF-8-Normalizer einbinden document.getElementsByTagName("head")[0].appendChild( q.domCreate({ tagName : "script", type : "text/javascript", src : Quiz.baseURL + "utf8-normalizer.js" }) ); /* Die Initialisierung könnte mehrfach benötigt werden, die folgenden Umleitungen dürfen aber nur einmal gemacht werden! */ if (q.oldDocOnMouseMove == "leer") { q.oldDocOnMouseMove = document.onmousemove; document.onmousemove = function (e) { if (typeof(q.oldDocOnMouseMove) == "function") { q.oldDocOnMouseMove(e); } q.whileDrag(e); } } // OnMouseOver-Handler nur einmal eintragen if (q.oldDocOnMouseOver == "leer") { q.oldDocOnMouseOver = document.onmouseover; document.onmouseover = function (e) { if (typeof(q.oldDocOnMouseOver) == "function") { q.oldDocOnMouseOver(e); } q.einBlender(e); } } // OnLoad-Handler nur einmal eintragen if (q.oldWinOnLoad == "leer") { q.oldWinOnLoad = window.onload; window.onload = function () { if (typeof(q.oldWinOnLoad) == "function") { q.oldWinOnLoad(); } q.initQuizze(); } } // OnMouseUp-Handler nur einmal eintragen if (q.oldDocOnMouseUp == "leer") { q.oldDocOnMouseUp = document.onmouseup; document.onmouseup = function (e) { if (typeof(q.oldDocOnMouseUp) == "function") { q.oldDocOnMouseUp(e); } q.each(q.alleQuizze, function (a) { if (a.element.onmouseup) { a.element.onmouseup(e); } }); } } // OnKeyUp-Handler nur einmal eintragen if (q.oldDocOnKeyUp == "leer") { q.oldDocOnKeyUp = document.onkeyup; document.onkeyup = function (e) { if (typeof(q.oldDocOnKeyUp) == "function") { q.oldDocOnKeyUp(e); } q.each(q.alleQuizze, function (a) { if (a.element.onkeyup) { a.element.onkeyup(e); } }); } } // Erweiterung für das native String-Objekt in JavaScript: trim()-Methode (wie in PHP verfügbar) if (typeof(new String().quizTrim) != "function") { String.prototype.quizTrim = function () { var l = new RegExp( "^[" + String.fromCharCode(32) + String.fromCharCode(160) + "\t\r\n]+", "g" ); var r = new RegExp( "[" + String.fromCharCode(32) + String.fromCharCode(160) + "\t\r\n]+$", "g" ); return this.replace(l, "").replace(r, ""); }; } // Erweiterung für das native Array-Objekt: contains()-Methode if (![].contains) { Array.prototype.contains = function (el, strict) { var i; for (i = 0; i < this.length; i++) { if (this[i] === el) { return true; } } return false; }; } // Erweiterung für das native Array-Objekt: shuffle()-Methode if (typeof(new Array().shuffle) != "function") { Array.prototype.shuffle = function () { var ar = [], zufall, i; while (this.length > 0) { zufall = Math.floor(Math.random() * this.length); ar.push(this[zufall]); this.splice(zufall, 1); // Element entfernen } for (i = 0; i < ar.length; i++) { this[i] = ar[i]; } return this; }; } }, /* ================= Quiz - Funktionen ================= */ /* Diese Funktion erzeugt ein Zuordnungs-Quiz. Dazu braucht sie eine Tabelle innerhalb eines Elternelements mit dem CSS-Klassen-Präfix "matching", z.B. "matching-quiz", wenn "-quiz" das Suffix der Quiz.triggerClass ist. Die Tabelle mit den Daten enthält Spalten (ohne
Eine Henne legt ein Ei.
wird zuEine Henne legt ein nbsp; nbsp; nbsp; .
->"Ei" wird zu Ei und landet im Pool. Beispiel2:Eine Henne legt (legen) ein Ei.
wird zuEine Henne (legen) ein Ei.
Die ID eines solchen Feldes enthält den Namen des Quizes, die laufende Nummer des Wertepaares, dem er entstammt und entweder ein "a" oder ein "b". Dadurch kann später die Zuordnung ausgewertet werden, da die ID bis auf den letzten Buchstaben übereinstimmen muss, wenn die Zuordnung stimmen soll. */ // Wenn es Drag&Drop-Felder gibt, dann wird ein Pool benötigt if (t.felder.length > 0 || t.inputs.length >0) { // Behälter für die beweglichen Teile ins Dokument einfügen t.element.appendChild(t.pool); // Felder vermischt im Pool ablegen und Lücken erzeugen t.felder.shuffle(); q.each(t.felder, function (f) { t.pool.appendChild(f.element); luecke = q.domCreate({ tagName: "span", text : t.lueckenPlatzhalter, id : f.element.id + "_" + t.loesungsClass, className : t.loesungsClass }); // Lücke ins Dokument schreiben f.original.parentNode.insertBefore(luecke, f.original); f.original.parentNode.removeChild(f.original); }); // Eventhandler für bewegliche Felder einrichten t.element.onmousedown = q.startDrag; t.element.onmouseover = q.highlight; t.element.onmouseup = q.stopDrag; q.each(q.domSelect("."+q.feldClass, t.pool), function (f) { f.className += " " + q.draggableClass; f.style.cursor = "move"; }); } // falls Eingabefelder vorhanden -> einbinden if (t.inputs.length > 0) { q.each(t.inputs, function (i) { if (typeof i != "function") { i.original.parentNode.insertBefore(i.element, i.original); i.original.parentNode.removeChild(i.original); } }) } // ID für das umgebende DIV-Element vergeben t.element.id = t.name; // Auswertungs-Button erzeugen t.auswertungsButton = q.domCreate({ tagName : "span", className : "auswertungs-button", text : q.meldungen[t.sprache].pruefen, onclick : function (e) { t.auswerten(); } }); } }; // Laufende Nummer ermitteln -> Quiz-Name wird "quiz" + laufende Nummer i = 0; q.each(q.alleQuizze, function () { i++; }); quiz.name = "quiz" + i; // Gibt es Quiz-Daten? daten = { bolds : q.domSelect("b", div), italics : q.domSelect("i", div), strongs : q.domSelect("strong", div), ems : q.domSelect("em", div) } // keine potentiellen Daten gefunden? -> abbrechen! if (daten.bolds.length < 1 && daten.italics.length < 1 && daten.strongs.length < 1 && daten.ems.length < 1 ) { return false; } // Daten sind also vorhanden? -> Auswerten q.each(daten, function (tagType) { q.each(tagType, function (d) { var test = d.innerHTML.replace(/<\/a>/i, "").replace(/]*>/i, ""); if (test.match(/\(/)) { // Eingabefeld! test = q.domCreate({ tagName : "span", className : quiz.loesungsClass + "_i", id : quiz.name + "_" + ids }); test.innerHTML += d.innerHTML.replace(/^[^(]*(\(.*) *$/, "$1").replace(/ ?\(\)$/, ""); test.insertBefore(q.domCreate({ tagName : "input", type : "text", id : test.id + "i", onkeyup : function (e) { quiz.dragNDropAuswerten(); } }), test.firstChild); quiz.inputs.push({ element : test, original : d, // Lösungsinhalt "säubern" loesung : d.innerHTML.replace( /[\t\r\n]/g, " " ).replace( /^([^(]+).*$/, "$1" ).replace( /( | )/, " " ).replace( / +/, " " ).quizTrim() }); ids++; // verwendete ID eintragen, damit keine doppelten IDs entstehen } else { // Drag&Drop-Feld! if (d.innerHTML != "") { // Feld ist nicht leer test = q.domCreate({ tagName : "span", className : q.feldClass }); test.innerHTML = d.innerHTML.replace(/^ *([^ ](.*[^ ])?) *$/, "$1"); /* Gibt es bereits Felder mit identischem Inhalt? Deren IDs müssen bis auf die Buchstaben am Ende übereinstimmen! */ q.each(quiz.felder, function (f) { if (typeof(f.element) != "undefined" && f.element.innerHTML == test.innerHTML ) { // ID übernehmen! test.id = f.element.id; } }); if (test.id == "") { test.id = quiz.name + "_" + ids + "a"; ids++; } else { // übernommene ID eines bereits existierenden Feldes ändern test.id = test.id.substr(0, test.id.length - 1) + String.fromCharCode(test.id.charCodeAt(test.id.length - 1)); } quiz.felder.push({ element : test, original : d }); } } }); }); // Keine brauchbare Daten? -> Verwerfen! i = 0; q.each(quiz.felder, function () { i++; }); q.each(quiz.inputs, function () { i++; }); if (i < 1) { return false; } // Quiz in die Liste aufnehmen und initialisieren q.alleQuizze[quiz.name] = quiz; quiz.element.quiz = quiz; quiz.init(); return true; }, /* Diese Funktion erzeugt ein memo-quiz. Dazu braucht sie eine Tabelle innerhalb eines Elternelementes mit dem CSS-Klassen-Präfix "memo", z.B. "memo-quiz", wenn "-quiz" das Suffix der Quiz.triggerClass ist. In der Tabelle stehen die Set-Daten: Die Anzahl an Spalten steht für die Anzahl der Felder pro Set, die Anzahl der Zeilen ist die Anzahl der Sets. */ memoQuiz : function (div) { var q = this, i, j, test, daten, tabelle; var quiz = { // Objekt-Gestalt eines memo-quizzes name : "Quiz-x", // Platzhalter - hier steht später etwas anderes. typ : "memo-quiz", inhaltsClass : "feld-inhalt", // CSS-Klasse für den Inhalt eines Feldes aktivClass : "aktiv", // CSS-Klasse für ein aktiviertes Feld fertigClass : "fertig", // CSS-Klasse für ein Feld, das aussortiert wurde element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet angeklickt : null, // Referenz auf das angeklickte Element innerhalb des DIVs felder : new Array(), // Hier stehen später Referenzen auf SPAN-Elemente. pool : q.domCreate({ tagName : "p", className : q.poolClass }), setGroesse : 2, // Anzahl der zu einem Set gehörenden Felder versuche : 0, // Speichert die Anzahl Versuche, die für die Lösung gebraucht wurden. sprache : (div.lang && div.lang != "") ? div.lang : "de", // deutsche Meldungen als Voreinstellung // Funktion zum Aufdecken eines Feldes (kommt über Eventhandler onclick) aufdecken : function (e) { var t = this; e = e || window.event; t.angeklickt = e.target || e.srcElement; // W3C DOM <-> IE // Nur bei Klick auf ein Feld (oder eines seiner Nachfahren-Elemente) reagieren! test = t.angeklickt; while (!test.className || !test.className.match(new RegExp("(^|\\s)" + q.feldClass + "(\\s|$)")) ) { test = test.parentNode; if (test == document.body) { return false; } } q.aktivesQuiz = t; t.angeklickt = test; // das angeklickte Feld abspeichern // Feld wurde angeklickt -> aufdecken? test = q.domSelect("."+t.aktivClass, t.element); if (test.length >= t.setGroesse) { // Nein, denn es sind schon alle Felder für ein Set aufgedeckt! return false; } else { // Das aktuelle Set ist noch nicht vollständig aufgedeckt... if (!t.angeklickt.className.match(new RegExp( "(^|\\s)" + t.aktivClass + "(\\s|$)", "" ))) { // OK, Feld wurde noch nicht aufgedeckt. -> aufdecken t.angeklickt.className += " " + t.aktivClass; // eventuelle Markierungen aufheben (stört bei Bildern) try { window.getSelection().collapse(t.angeklickt, 0); } catch (e) { }; try { document.selection.clear(); } catch (e) { }; if (q.domSelect("."+t.aktivClass, t.element).length >= t.setGroesse) { // Alle Felder für ein Feld wurden aufgedeckt! -> auswerten window.setTimeout(function () { t.auswerten(); }, 1500); } } } }, // Funktion zum Auswerten eines aufgedeckten Sets auswerten : function () { var t = this, i, ok, muster; // Anzahl Lösungsversuche um eins erhöhen t.versuche++; // aufgedeckte Felder ermitteln test = q.domSelect("."+t.aktivClass, t.element); // IDs der Felder vergleichen muster = new RegExp(test[0].id.replace(/^([^_]+_\d+).*$/, "$1"), ""); // ID des ersten Feldes ohne letzten Buchstaben ok = true; // Wir gehen von einer Übereinstimmung aus... q.each(test, function (i) { if (!i.id.match(muster)) { ok = false; } }); // IDs haben übereingestimmt? muster = new RegExp(" ?" + t.aktivClass, ""); q.each(test, function (i) { if (ok) { // Ja. -> aufgedekte Felder "entfernen" i.className = t.fertigClass; } else { // Nein! -> Felder wieder umdrehen! i.className = i.className.replace(muster, ""); } }); // Alle Felder abgeräumt? test = q.domSelect("."+Quiz.feldClass, this.element); if (test.length < 1) { // Gratulieren und nachfragen var nachfrage = q.meldungen[t.sprache]["lob" + (t.versuche > 2 ? 3 : t.versuche)] + " " + q.meldungen[t.sprache].alleGefunden + "\n" + q.meldungen[t.sprache]["ergebnis" + (t.versuche > 2 ? 3 : t.versuche)].replace(/%n/i, t.versuche) + "\n" + q.meldungen[t.sprache].erneut; if (confirm( q.meldungen[t.sprache]["lob" + (t.versuche > 2 ? 3 : t.versuche)] + " " + q.meldungen[t.sprache].alleGefunden + "\n" + q.meldungen[t.sprache][ "ergebnis" + (t.versuche > 2 ? 3 : t.versuche) ].replace(/%n/i, t.versuche) + "\n" + q.meldungen[t.sprache].erneut )) { test = q.domSelect("."+Quiz.poolClass, this.element); if (test.length > 0) test[0].parentNode.removeChild(test[0]); t.init(); // Quiz erneut starten } else { t.element.onmousedown = null; t.element.onmousemove = null; t.element.onmouseup = null; t.solved = true; t.element.className += " "+q.fertigClass; } } }, // Funktion zum Mischen und Austeilen der Wörter init : function () { var t = this, sets = new Array(), i, zufall; // Spracheinstellungen auf deutsch zurück korrigieren, falls entsprechende Sprachdaten fehlen if (!q.meldungen[t.sprache]) { t.sprache = "de"; } /* Jeder Wert aus den Set-Daten wird zu einem SPAN-Element ("Feld") und erhält eine ID. Die ID eines solchen Feldes enthält den Namen des Quizes, die laufende Nummer des Sets, dem das Feld entstammt und einen "laufenden Buchstaben". Dadurch kann später die Zuordnung ausgewertet werden, da die ID bis auf den letzten Buchstaben übereinstimmen muss, wenn die Zuordnung stimmen soll. */ t.element.appendChild(t.pool); // ins Dokument einfügen // Felder vermischt in den Pool schreiben t.felder.shuffle(); q.each(t.felder, function (f) { t.pool.appendChild(f.cloneNode(true)); }); // Elternelement vorbereiten t.element.onclick = function (e) { t.aufdecken(e); }; // Eventhandler vergeben t.element.id = t.name; // ID vergeben t.versuche = 0; // Anzahl Versuche zurücksetzen } } // Laufende Nummer ermitteln -> Quiz-Name wird "quiz" + laufende Nummer i = 0; q.each(q.alleQuizze, function () { i++; }); quiz.name = "quiz" + i; // Gibt es Quiz-Daten? tabelle = q.domSelect("table", div); if (tabelle.length < 1) { // Keine Tabelle für Quiz-Daten gefunden! -> abbrechen return false; } // Daten sind also vorhanden? -> Auswerten test = q.domSelect("tr", tabelle[0]); // Tabellenzeilen nach Daten durchforsten for (i = 0; i < test.length; i++) { daten = q.domSelect("td", test[i]); if (daten.length > 1) { quiz.setGroesse = daten.length; for (j = 0; j < daten.length; j++) { // Feld abspeichern quiz.felder.push(q.domCreate({ tagName : "span", className : q.feldClass, id : quiz.name + "_" + i + String.fromCharCode(j + 97) })); quiz.felder[quiz.felder.length -1].appendChild(q.domCreate({ tagName : "span", className : quiz.inhaltsClass })); quiz.felder[quiz.felder.length -1].lastChild.innerHTML = daten[j].innerHTML; } } } // Keine brauchbare Daten? -> Verwerfen! i = 0; q.each(quiz.felder, function() { i++; }); if (i < 1) { return false; } // Quiz in die Liste aufnehmen und initialisieren q.alleQuizze[quiz.name] = quiz; tabelle[0].parentNode.removeChild(tabelle[0]); quiz.element.quiz = quiz; quiz.init(); return true; }, /* Diese Funktion erzeugt ein Multiple Choice - Quiz. Dazu braucht sie Textabsätze innerhalb eines Elternelementes mit dem CSS-Klassen-Präfix "multiplechoice", z.B. "multiplechoice-quiz", wenn "-quiz" das Suffix der Quiz.triggerClass ist. In den Textabsätzen stehen die jeweiligen Quiz-Fragen, die Antworten stehen am Ende der Absätze in runden Klammern. Falsche Antworten haben innerhalb der Klammer gleich als erstes Zeichen ein Ausrufezeichen, richtige Antworten nicht. Textabsätze ohne Klammernpaar am Ende werden nicht als Quiz-Fragen interpretiert. */ multiplechoiceQuiz : function (div) { var q = this, fragen, i; var quiz = { // Objekt-Gestalt eines Multiple Choice - Quizzes name : "Quiz-x", // Platzhalter - hier steht später etwas anderes. typ : "Multiple Choice - Quiz", loesungsClass : "quiz-antworten", // CSS-Klasse für das Elternelement mit den Antworten element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet fragen : new Array(), // Hier stehen später die Fragen zusammen mit ihren Antworten sprache : (div.lang && div.lang != "") ? div.lang : "de", // deutsche Meldungen als Voreinstellung // Funktion zum Auswerten eines aufgedeckten Sets auswerten : function () { var t = this, anzahl, test, richtigkeit; // Antwort-Blöcke ermitteln richtigkeit = 0; // Anzahl der gezählten Treffer anzahl = 0; // Anzahl der möglichen richtigen Antworten q.each(q.domSelect("."+t.loesungsClass, t.element), function(a) { // Jeden Antwortblock einzeln durchgehen var ok = 0; // Anzahl Treffer abzüglich falscher Treffer q.each(q.domSelect("input", a), function(i) { //Eine Henne legt ein.
wird zuEine (eeHnn) legt ein Ei.
Die ID eines solchen Input-Elements korrespondiert mit der laufenden Nummer des Daten-Eintrages in "quiz.felder". */ for (i = 0; i < t.felder.length; i++) { // Lücke mit Eingabe-Element vorbereiten luecke = q.domCreate({ tagName : "span", className : t.loesungsClass, text : " (" + t.felder[i].loesung.toLowerCase().split("").shuffle().join("") + ")" }); luecke.insertBefore( q.domCreate({ tagName : "input", type : "text", name : t.name + "_" + i, id : t.name + "_" + i, onkeyup : function () { t.auswerten(); } }), luecke.firstChild ); t.felder[i].element = luecke; } // Alle im Dokument markierten Wörter in Eingabefelder umwandeln q.each(t.felder, function (f) { f.original.parentNode.insertBefore(f.element, f.original); f.original.parentNode.removeChild(f.original); }); // ID für das umgebende DIV-Element vergeben t.element.id = t.name; // Auswertungs-Button erzeugen t.auswertungsButton = q.domCreate({ tagName : "p", className : "auswertungs-button", text : q.meldungen[t.sprache].pruefen, onclick : function () { t.auswerten(1); } }); } }; // Laufende Nummer ermitteln -> Quiz-Name wird "quiz" + laufende Nummer i = 0; q.each(q.alleQuizze, function () { i++; }); quiz.name = "quiz" + i; // Gibt es Quiz-Daten? daten = { bolds : q.domSelect("b", div), italics : q.domSelect("i", div), strongs : q.domSelect("strong", div), ems : q.domSelect("em", div) } // keine potentiellen Daten gefunden? -> abbrechen! if (daten.bolds.length < 1 && daten.italics.length < 1 && daten.strongs.length < 1 && daten.ems.length < 1 ) { return false; } // Daten sind also vorhanden? -> Auswerten q.each(daten, function (d) { q.each(d, function (f) { // Lösungsinhalt "säubern" quiz.felder.push({ element : null, original : f, loesung : f.innerHTML.replace( /[\t\r\n]/g, " " ).replace( /^<\/?[^>]+>$/, "" ).replace( /(nbsp; | )/, " " ).replace( / +/, " " ).quizTrim() }); }); }); // Brauchbare Daten? i = 0; q.each(quiz.felder, function () { i++; }); if (i < 1) { return false; } // Quiz in die Liste aufnehmen und initialisieren q.alleQuizze[quiz.name] = quiz; quiz.element.quiz = quiz; quiz.init(); return true; }, /* Diese Funktion erzeugt ein Kreuzwort-Quiz. Dazu braucht sie ein Elternelement mit dem CSS-Klassen-Präfix "kreuzwort", z.B. "kreuzwort-quiz", wenn "-quiz" das Suffix der Quiz.triggerClass ist. Die Daten für das Quiz müssen in einer zweispaltigen Tabelle stehen: 1. Zelle enthält das Lösungswort, 2. Zelle enthält eine Lösungshilfe */ kreuzwortQuiz : function (div) { var q = this, i, tabelle; var quiz = { // Objekt-Gestalt eines Kreuzwort-Quizzes name : "Quiz-x", // Platzhalter - hier steht später etwas anderes. typ : "Kreuzwort-Quiz", loesungsClass : "feld", loesungsClass2 : "eingabe-feld", element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet eingabe : q.domCreate({ tagName : "div" }), // Eingabebereich tabelle : null, // Referenz auf das HTML-Element, in dem das Kreuzworträtsel angezeigt wird daten : new Array(), // Hier stehen später Objekte, die die Quiz-Daten enthalten. auswertungsButton : null, // Hier steht später das HTML-Element des Auswertungs-Buttons. versuche : 0, // Speichert die Anzahl Versuche, die für die Lösung gebraucht wurden. sprache : (div.lang && div.lang != "") ? div.lang : "de", // deutsche Meldungen als Voreinstellung // Funktion zum Auswerten der Lösungen auswerten : function (werte) { /* "werte" hat folgende Struktur: { wort: