Quiz.js
Версия от 04:11, 28 сентября 2017; Admine2 (обсуждение | вклад) (Новая страница: «/*************************************************** * JavaScript-Framework für interaktive Lernaufgaben **************************************************** * *…»)
Версия от 04:11, 28 сентября 2017; Admine2 (обсуждение | вклад) (Новая страница: «/*************************************************** * JavaScript-Framework für interaktive Lernaufgaben **************************************************** * *…»)
/***************************************************
* JavaScript-Framework für interaktive Lernaufgaben
****************************************************
*
* V 2.6 (2017/03/11)
*
* 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)
*/
window.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
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)
lastCoords : {
// wird später mit den Mauskoordinaten überschrieben werden
left : 0,
top : 0
},
codeTabelle : codeTabelle = {
A : new Array(
'\u0041', // a
'\u0061', // A
'\u00c0', // À
'\u00c1', // Á
'\u00c2', // Â
'\u00c3', // Ã
'\u00c5', // Å
'\u00e0', // à
'\u00e1', // á
'\u00e2', // â
'\u00e3', // ã
'\u00e5' // å
),
AE : new Array(
'\u00c4', // Ä
'\u00c6', // Æ
'\u00e4', // ä
'\u00e6' // æ
),
B : new Array(
'\u0042', // B
'\u0062' // b
),
C : new Array(
'\u0043', // C
'\u0063', // c
'\u00c7', // Ç
'\u00e7' // ç
),
D : new Array(
'\u0044', // D
'\u0064' // d
),
E : new Array(
'\u0045', // E
'\u0065', // e
'\u00c8', // È
'\u00c9', // É
'\u00ca', // Ê
'\u00cb', // Ë
'\u00e8', // è
'\u00e9', // é
'\u00ea', // ê
'\u00eb' // ë
),
F : new Array(
'\u0046', // F
'\u0066' // f
),
G : new Array(
'\u0047', // G
'\u0067' // g
),
H : new Array(
'\u0048', // H
'\u0068' // h
),
I : new Array(
'\u0049', // I
'\u0069', // i
'\u00cc', // Ì
'\u00cd', // Í
'\u00ce', // Î
'\u00cf', // Ï
'\u00ec', // ì
'\u00ed', // í
'\u00ee', // î
'\u00ef' // ï
),
J : new Array(
'\u004a', // J
'\u006a' // j
),
K : new Array(
'\u004b', // K
'\u006b' // k
),
L : new Array(
'\u004c', // L
'\u006c' // l
),
M : new Array(
'\u004d', // M
'\u006d' // m
),
N : new Array(
'\u004e', // N
'\u006e', // n
'\u00d1', // Ñ
'\u00f1' // ñ
),
O : new Array(
'\u004f', // O
'\u006f', // o
'\u00d2', // Ò
'\u00d3', // Ó
'\u00d4', // Ô
'\u00d5', // Õ
'\u00f2', // ò
'\u00f3', // ó
'\u00f4', // ô
'\u00f5' // õ
),
OE : new Array(
'\u00d6', // Ö
'\u00f6' // ö
),
P : new Array(
'\u0050', // P
'\u0070' // p
),
Q : new Array(
'\u0051', // Q
'\u0071' // q
),
R : new Array(
'\u0052', // R
'\u0072' // r
),
S : new Array(
'\u0053', // S
'\u0073' // s
),
SS : new Array(
'\u00df' // ß
),
T : new Array(
'\u0054', // T
'\u0074' // t
),
U : new Array(
'\u0055', // U
'\u0075', // u
'\u00d9', // Ù
'\u00da', // Ú
'\u00db', // Û
'\u00f9', // ù
'\u00fa', // ú
'\u00fb' // û
),
UE : new Array(
'\u00dc', // Ü
'\u00fc' // ü
),
V : new Array(
'\u0056', // V
'\u0076' // v
),
W : new Array(
'\u0057', // W
'\u0077' // w
),
X : new Array(
'\u0058', // X
'\u0078' // x
),
Y : new Array(
'\u0059', // Y
'\u0079', // y
'\u00dd', // Ý
'\u00fd' // ý
),
Z : new Array(
'\u005a', // Z
'\u007a' // z
)
},
meldungen : {
// deutsche Meldungen (Voreinstellung)
de : {
pruefen : 'pr\u00fcfen!',
lob1 : 'Ausgezeichnet!',
lob2 : 'Gut gemacht!',
lob3 : 'Das war nicht schlecht!',
ergebnis1 : 'Die Aufgabe wurde gleich beim ersten Versuch erfolgreich gel\u00f6st!',
ergebnis2 : 'Die Aufgabe wurde nach nur zwei Versuchen erfolgreich gel\u00f6st!',
ergebnis3 : 'Die Aufgabe wurde nach %n Versuchen erfolgreich gel\u00f6st!',
// memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
alleGefunden : 'Alle Sets gefunden!',
erneut : 'Wie w\u00e4r\'s mit einer neuen Runde?',
// Multiple-Choice-Quiz
ergebnisProzent : 'Die Antworten sind zu %n% richtig.',
// Kreuzworträtsel
senkrecht : 'Senkrecht',
waagrecht : 'Waagrecht',
eintragen : 'eintragen',
eingabehinweis : 'Benutzen Sie zur Eingabe die Tastatur. Eventuell m\u00fcssen sie zuerst ein Eingabefeld durch Anklicken aktivieren.',
// Buchstabenraten-Quiz
eingabehinweis_buchstabenraten : 'Benutzen Sie die Tastatur zur Eingabe! Eventuell m\u00fcssen Sie erst in das Quiz klicken, um es zu aktivieren.',
quizStarten : 'Quiz starten.',
gerateneBuchstaben : 'Bereits geratene Buchstaben',
erkannteWoerter : 'Erkannte W\u00f6rter',
quizEnde : 'Quiz ist zuende.'
},
// englische Meldungen
en : {
pruefen : 'check it!',
lob1 : 'Brilliant!',
lob2 : 'Well done!',
lob3 : 'That was nice!',
ergebnis1 : 'You solved everything on your first try!',
ergebnis2 : 'You solved everything with only two tries!',
ergebnis3 : 'You solved everything after trying %n times!',
// memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
alleGefunden : 'You\'ve found all sets!',
erneut : 'How about another round?',
// Multiple-Choice-Quiz
ergebnisProzent : 'The answers are %n% correct.',
// Kreuzworträtsel
senkrecht : 'Vertical',
waagrecht : 'Horizontal',
eintragen : 'fill in',
eingabehinweis : 'Use the keyboard to enter letters. You may need to first activate a box by clicking it.',
// Buchstabenraten-Quiz
eingabehinweis_buchstabenraten : 'Use the keyboard to enter letters. You may need to first click somewhere into this quiz in oder to activate it.',
quizStarten : 'Start quiz.',
gerateneBuchstaben : 'Already Guessed Characters',
erkannteWoerter : 'Found Words',
quizEnde : 'Quiz is over.'
},
// spanische Meldungen; mit dankenswerter Unterstützung von Frau Ulrike Weinmann
es : {
pruefen : '\u00a1Chequear!',
lob1 : '\u00a1Muy bien hecho!',
lob2 : '\u00a1Bien hecho!',
lob3 : '\u00a1Correcto!',
ergebnis1 : '\u00a1Resolviste el ejercicio al primer intento!',
ergebnis2 : '\u00a1Resolviste el ejercicio al segundo intento!',
ergebnis3 : 'Intentaste resolver el ejercicio %n veces y \u00a1lo lograste!',
// memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
alleGefunden : '\u00a1Encontraste todos los juegos!',
erneut : '\u00bfOtra vez?',
// Multiple-Choice-Quiz
ergebnisProzent : 'Porcentaje de respuestas correctas: %n%.',
// Kreuzworträtsel
senkrecht : 'Vertical',
waagrecht : 'Horizontal',
eintragen : 'llenar',
eingabehinweis : 'Usa el teclado para entrar letras. Quiz\u00e1s tienes que hacer clic en una caja primero para activ\u00e1rla.',
// Buchstabenraten-Quiz
eingabehinweis_buchstabenraten : 'Usa el teclado para entrar letras. Quiz\u00e1s tienes que hacer clic en el quiz primero para activ\u00e1rla.',
quizStarten : 'Empezar quiz.',
gerateneBuchstaben : 'Letras ya probadas',
erkannteWoerter : 'Palabras encontradas',
quizEnde : 'Fin de juego'
},
// französische Meldungen; mit dankenswerter Unterstützung von Herrn Otto Ebert
fr : {
pruefen : 'verifier!',
lob1 : 'Excellent! Super!',
lob2 : 'Bien fait!',
lob3 : 'Ce n\'\u00e9tait pas mal',
ergebnis1 : 'Ton essai \u00e9tait tout de suite un succ\u00e8s.',
ergebnis2 : 'Tu as r\u00e9soulu le devoir apr\u00e8s deux tentatives seulement!',
ergebnis3 : 'Tu as r\u00e9soulu le devoir apr\u00e8s %n tentatives.',
// memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
alleGefunden : 'Tu as trouv\u00e9 tous les "sets".',
erneut : 'Alors tu veux recommencer?',
// Multiple-Choice-Quiz
ergebnisProzent : 'Les r\u00e9ponses sont %n% correctes.',
// Kreuzworträtsel
senkrecht : 'V\u00e9rtical',
waagrecht : 'Horizontal',
eintragen : 'inscrire',
eingabehinweis : 'Utilisez le clavier pour inscrire des lettres. Vous devez probablement d\'abord activer une bo\u00eete en le claquant.',
// Buchstabenraten-Quiz
eingabehinweis_buchstabenraten : 'Utilisez le clavier pour inscrire des lettres. Vous devez probablement d\'abord activer le quiz en le claquant.',
quizStarten : 'Commencer le quiz.',
gerateneBuchstaben : 'Lettres d\u00e9j\u00e0 essay\u00e9es',
erkannteWoerter : 'Mots trouv\u00e9s',
quizEnde : 'Quiz est finis.'
},
// lateinische Meldungen; mit dankenswerter Unterstützung von Herrn Ralf Altgeld und Frau Ulrike Weinmann
la : {
pruefen : 'probare',
lob1 : 'optime!',
lob2 : 'bene!',
lob3 : 'Id non male fecisti.',
ergebnis1 : 'Pensum statim in primo conatu feliciter absolutum est!',
ergebnis2 : 'Pensum cam post duos conatus feliciter absolutum est.',
ergebnis3 : 'Pensum cam post %n conatus feliciter absolutum est.',
// memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
alleGefunden : 'Omnes partes repperisti.',
erneut : 'Ludum novum vis?',
// Multiple-Choice-Quiz
ergebnisProzent : '%n% centesimae responsorum rectae sunt.',
// Kreuzworträtsel
senkrecht : 'perpendiculariter',
waagrecht : 'directe',
eintragen : 'complere',
eingabehinweis : 'Utere clavibus ad verba scribenda. Fortasse tibi capsa eligenda est.',
// Buchstabenraten-Quiz
eingabehinweis_buchstabenraten : 'Utere clavibus ad verba scribenda. Fortasse tibi aenigma eligendum est.',
quizStarten : 'Incipere aenigma.',
gerateneBuchstaben : 'Litterae iam temptatae',
erkannteWoerter : 'Verba iam reperta',
quizEnde : 'Factum est.'
},
// italienische Meldungen; mit dankenswerter Unterstützung von Herrn Ihor Bilaniuk
it : {
pruefen : 'controllare!',
lob1 : 'Ottimo!',
lob2 : 'Benissimo!',
lob3 : 'Bene!',
ergebnis1 : 'Il compito \u00e8 stato risolto al primo passo!',
ergebnis2 : 'Il compito \u00e8 stato risolto dopo la seconda prova!',
ergebnis3 : 'Il compito \u00e8 stato risolto dopo %n prove.',
// memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
alleGefunden : 'Tutti i sets sono stati risolti!',
erneut : 'Ancora una volta?',
// Multiple-Choice-Quiz
ergebnisProzent : 'Le tue risposte sono il %n per cento giuste.',
// Kreuzworträtsel
senkrecht : 'Verticale',
waagrecht : 'Orizontale',
eintragen : 'inserire',
eingabehinweis : 'Utilizzi la tastiera per entrare nelle lettere. Potete avere bisogno di in primo luogo di attivare una scatola scattandola.',
// Buchstabenraten-Quiz
eingabehinweis_buchstabenraten : 'Utilizzi la tastiera per entrare nelle lettere. Potete avere bisogno di in primo luogo di scattarti in qualche luogo in questo quiz per attivarlo.',
quizStarten : 'Inizi il quiz.',
gerateneBuchstaben : 'Lettere gi\u00e0 indovinate',
erkannteWoerter : 'Parole trovate ',
quizEnde : 'Il quiz \u00e8 sopra .'
},
// polnische Meldungen von Pitr Wójs www.merula.pl
pl : {
pruefen : 'Sprawdź!',
lob1 : 'Celująco!',
lob2 : 'Bardzo dobrze!',
lob3 : 'Nieźle!',
ergebnis1 : 'Zadanie rozwiązałaś/łeś poprawnie za pierwszym razem!',
ergebnis2 : 'Zadanie rozwiązałaś/łeś poprawnie za drugim razem!',
ergebnis3 : 'Zadanie zostało rozwiązane poprawnie po %n próbach !',
// memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
alleGefunden : 'Znalazłaś/łeś wszystkie pary!',
erneut : 'Co powiesz na drugą rundę? Spróbuj jeszcze raz!',
// Multiple-Choice-Quiz
ergebnisProzent : 'Odpowiedzi są poprawne w %n procentach.',
// Kreuzworträtsel
senkrecht : 'Pionowo',
waagrecht : 'Poziomo',
eintragen : 'Wpisz',
eingabehinweis : 'Aby wpisać rozwiązanie użyj klawiatury. Kliknij pole, aby wprowadzić text!',
// Buchstabenraten-Quiz
eingabehinweis_buchstabenraten : 'Aby wpisać rozwiązanie użyj klawiatury. Kliknij pole, aby wprowadzić text!',
quizStarten : 'Start quizu.',
gerateneBuchstaben : 'Odgadnięte litery',
erkannteWoerter : 'Rozpoznane słówka',
quizEnde : 'Koniec quizu.'
}
},
// 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
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 <p>
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;
document.addEventListener("DOMContentLoaded", function () { q.initQuizze(); });
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);
}
});
/* 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.whileMove(e);
}
document.addEventListener("touchstart",function(e){q.touchStart(e)});
document.addEventListener("touchmove",function(e){q.whileMove(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);
}
}
// 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;
};
}
},
removeAllListeners : function(t) {
// Eventhandler entfernen
t.element.removeEventListener("mousedown", this.startDrag);
t.element.removeEventListener("mouseup", this.stopDrag);
// touch devices
t.element.removeEventListener("touchstart", this.startDrag);
t.element.removeEventListener("touchend", this.stopDrag);
t.element.removeEventListener("touchcancel", this.stopDrag);
},
addAllListeners : function(t) {
// Eventhandler für bewegliche Felder einrichten
t.element.addEventListener("mousedown", this.startDrag);
t.element.addEventListener("mouseup", this.stopDrag);
// touch devices
t.element.addEventListener("touchstart", this.startDrag);
t.element.addEventListener("touchend", this.stopDrag);
t.element.addEventListener("touchcancel", this.stopDrag);
},
/*
=================
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 <th>!), in denen die Werte stehen. */
zuordnungsQuiz : function (div) {
var q = this,
i, tabelle;
var quiz = {
// Objekt-Gestalt eines Zuordnungs-Quizzes
name : "Quiz-x", // Platzhalter - hier steht später etwas anderes.
typ : "Zuordnungs-Quiz",
spielModus : "paarweise", // entweder paarweise oder gruppenweise Zuordnungen
loesungsClass : "loesungs-paar",
element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet
daten : new Array(), // Hier stehen später Wertegruppen (in Arrays).
felder : new Array(), // Hier stehen später Referenzen auf SPAN-Elemente
pool : q.domCreate({
tagName : "p",
className : q.poolClass
}),
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 Drag&Drop-Aktionen des Benutzers
dragNDropAuswerten : function (element, ziel) {
var t = this,
vorgaenger, test;
// Element einpflanzen
element.parentNode.removeChild(element);
ziel.appendChild(element);
test = q.domSelect("."+q.draggableClass, ziel);
// bei paarweise: War bereits ein Element hier eingefügt? -> Zurück in den Pool damit!
if (t.spielModus == "paarweise" && test.length > 1) {
vorgaenger = ziel.removeChild(test[0]);
t.pool.appendChild(vorgaenger);
}
// Auswertungsbutton entfernen, falls vorhanden
if (t.auswertungsButton.parentNode) {
t.auswertungsButton.parentNode.removeChild(t.auswertungsButton);
}
// letztes Element verwendet -> Auswertungs-Button anbieten
if (q.domSelect("."+q.draggableClass, t.pool).length < 1) {
t.pool.appendChild(t.auswertungsButton);
}
},
// Funktion zum Auswerten der Zuordnungen
auswerten : function () {
var t = this,
loesungen = q.domSelect("."+t.loesungsClass, t.element),
test;
// Anzahl Lösungsversuche um eins erhöhen
t.versuche++;
// Zuordnungen einzeln überprüfen
q.each(loesungen, function (l) {
var gruppe = l.getElementsByTagName("span"),
test = new RegExp(
"^" + gruppe[0].id.substring(0, gruppe[0].id.lastIndexOf("_"))
);
// Stimmen die IDs bis auf ihre letzte Zahl überein?
q.each(gruppe, function (g) {
if (g && !g.id.match(test)) {
// Nein! Element zurück in den Pool!
t.pool.appendChild(g);
}
});
});
// Auswertungsbutton entfernen, falls vorhanden
if (t.auswertungsButton.parentNode) {
t.auswertungsButton.parentNode.removeChild(t.auswertungsButton);
}
// Sind keine Felder mehr im Pool? -> Quiz erfolgreich gelöst!
if (q.domSelect("span", t.pool).length < 1) {
q.removeAllListeners(t);
t.solved = true;
t.element.className += " "+q.fertigClass;
t.pool.parentNode.removeChild(t.pool);
// Bewegungscursor entfernen
loesungen = q.domSelect("."+q.draggableClass, t.element);
test = new RegExp(" ?" + q.draggableClass);
q.each(loesungen, function (l) {
l.className = l.className.replace(test, "");
l.style.cursor = "";
});
// Erfolgsmeldung ausgeben
t.element.appendChild(q.domCreate({
tagName : "p",
className : q.bewertungsClass,
text : q.meldungen[t.sprache]["lob" + (t.versuche > 2 ? 3 : t.versuche)]
+ " "
+ q.meldungen[t.sprache][
"ergebnis" + (t.versuche > 2 ? 3 : t.versuche)
].replace(/%n/i, t.versuche)
}));
}
},
// Funktion zum Mischen und Austeilen der Wörter
init : function () {
var t = this,
loesung, feld, i, j, gruppe, benutzte, zufall, gemischte;
// Spracheinstellungen auf deutsch zurück korrigieren, falls entsprechende Sprachdaten fehlen
if (!q.meldungen[t.sprache]) {
t.sprache = "de";
}
/* Jeder Wert aus den Werten der 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 der Wertegruppe, der er entstammt
und anschließend die laufende Nummer innerhalb der Wertegruppe. Dadurch kann später die Zuordnung ausgewertet werden,
da die ID bis auf die letzte Nummer übereinstimmen muss, wenn die Zuordnung stimmen soll. */
t.element.appendChild(t.pool); // ins Dokument einfügen
// Wertegruppen durchgehen, Felder erzeugen
for (i = 0; i < t.daten.length; i++) {
// Jedes Datum besteht aus einem Array, das mindestens zwei Felder besitzt.
if (t.daten[i].length > 2) {
t.spielModus = "gruppenweise";
}
for (j = 0; j < t.daten[i].length; j++) {
t.felder.push(q.domCreate({
tagName : "span",
id : t.name + "_" + i + "_" + j,
className : q.feldClass,
innerHTML : t.daten[i][j]
}));
}
}
// Felder mischen und verteilen!
benutzte = new Array(); // Hier werden bereits benutzte Gruppen markiert
gemischte = new Array(); // Felder einer Gruppe die in den Pool sollen, hier eintragen
for (j = 0; j < t.daten.length; j++) {
// Lösungs-Absatz erzeugen
loesung = q.domCreate({
tagName: "p",
className : t.loesungsClass
});
// Gruppe auswählen
gruppe = true; // Wertegruppe schon verwendet?
while (gruppe) {
zufall = Math.floor(Math.random() * t.daten.length);
gruppe = benutzte[zufall]; // prüfen auf "bereits verwendet"
}
benutzte[zufall] = true; // Gruppe jetzt als verwendet eintragen.
/*
Je nach Spiel-Modus ("paarweise" oder "gruppenweise") darf die inhaltliche Vorbelegung des
Lösungsabsatzes nicht zufällig belegt werden. Bei paarweisen Zuordnungen ist immer "logisch",
welches Feld aus dem Pool dem bereits im Lösungsabsatz stehenden zugeordnet werden muss. Bei
gruppenweisen Zuordnungen muss dort aber eine Art Oberbegriff stehen, der dann der ersten
Tabellenzelle der Vorgaben entspricht!
*/
feld = 0; // erstes Feld einer Gruppe
if (t.spielModus == "paarweise") {
// Feld im Lösungsabsatz zufällig auswählen.
feld = Math.floor(Math.random() * 2);
}
/* Feld aus der Liste der erstellten Felder ermitteln und in Lösungsabsatz schreiben.
Restliche Felder der Gruppe in den Pool schreiben. */
for (i = 0; i < t.felder.length; i++) {
if (t.felder[i].id.match(new RegExp(t.name + "_" + zufall + "_"))) {
// Feld aus dieser Gruppe ermittelt!
if (t.felder[i].id.match(new RegExp(t.name + "_" + zufall + "_" + feld))) {
// Feld in den Lösungsabsatz eintragen
t.felder[i].style.cursor = "";
loesung.appendChild(t.felder[i]);
t.pool.parentNode.insertBefore(loesung, t.pool);
} else {
// Feld zu den gemischten einordnen
gemischte.push(t.felder[i]);
}
}
}
}
// zuzuordnende Felder vermischt ausgeben
gemischte.shuffle();
q.each(gemischte, function (f) {
t.pool.appendChild(f);
f.className += " "+q.draggableClass;
f.style.cursor = "move";
});
// ID für das umgebende DIV-Element vergeben
t.element.id = t.name;
q.addAllListeners(t);
// 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?
tabelle = q.domSelect("table", div);
if (tabelle.length < 1) {
return false;
}
// Daten sind also vorhanden? -> Auswerten
q.each(tabelle[0].getElementsByTagName("tr"), function (tr) {
var gefunden = new Array(); // Eine Wertegruppe anlegen
// Tabellenzeilen nach Daten durchforsten
q.each(tr.getElementsByTagName("td"), function (td) {
// Tabellenzellen nach Daten durchforsten
var k = false; // normalisierter Zelleninhalt
if (td.innerHTML && td.innerHTML != "") {
k = td.innerHTML.replace(/ /, " ").quizTrim();
}
if (k && k != "") {
gefunden.push(k);
}
});
// Falls Wertegruppe mindestens ein Wertepaar enthält, dieses den Daten hinzufügen.
if (gefunden.length > 1) {
quiz.daten.push(gefunden);
}
});
// Keine brauchbare Daten? -> Verwerfen!
if (quiz.daten.length < 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 Lückentext-Quiz. Dazu braucht sie ein Elternelement mit dem
CSS-Klassen-Präfix "lueckentext", z.B. "lueckentext-quiz", wenn "-quiz" das Suffix der Quiz.triggerClass ist.
Die mit <strong>, <em>, <b> oder <i> ausgezeichneten Textstellen werden durch Drag&Drop-Felder ersetzt. Sollten
Lösungshinweise in Klammern stehen, so werden die Textstellen durch Eingabefelder ersetzt. */
lueckentextQuiz : function (div) {
var q = this,
ids = 0,
i, daten;
var quiz = {
// Objekt-Gestalt eines Lückentext-Quizzes
name : "Quiz-x", // Platzhalter - hier steht später etwas anderes.
typ : "Lückentext-Quiz",
loesungsClass : "luecke", // Für die manuellen Texteingaben kommt noch "_i" hinzu!
lueckenPlatzhalter : "", // Leerzeichen als Platzhalter für Lücken
element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet
felder : new Array(), // Hier stehen später Referenzen auf SPAN-Elemente
pool : q.domCreate({
tagName : "p",
className: q.poolClass
}),
inputs : new Array(), // Hier stehen später Referenzen auf die Text-Eingabefelder und ihre Lösungen
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 Drag&Drop-Aktionen des Benutzers
dragNDropAuswerten : function (element, ziel) {
var t = this,
vorgaenger, test, ok, i;
if (element && ziel) {
// Element bewegen
test = new RegExp(t.loesungsClass, "");
// Zuerst überflüssige Leerzeichen im Ziel-Element entfernen?
if (ziel.className.match(test)
&& q.domSelect("."+q.draggableClass, ziel).length < 1
) {
ziel.innerHTML = ""; // Leerzeichen in einer Lücke zuvor entfernen
}
// Bewegliches Element einpflanzen
vorgaenger = element.parentNode;
ziel.appendChild(element);
// Entleertes Element mit Leerzeichen auffüllen?
if (vorgaenger.className.match(test)
&& q.domSelect("."+q.draggableClass, vorgaenger).length < 1
) {
// Leerzeichen in einer Lücke als Platzhalter einfügen
vorgaenger.innerHTML = t.lueckenPlatzhalter;
}
// War bereits ein Element hier eingefügt? -> Zurück in den Pool damit!
test = q.domSelect("."+q.draggableClass, ziel);
if (test.length > 1) {
t.pool.appendChild(test[0]);
}
}
// Auswertungsbutton entfernen, falls vorhanden
if (t.auswertungsButton.parentNode) {
t.auswertungsButton.parentNode.removeChild(t.auswertungsButton);
}
// Auswertungs-Button anbieten?
if (q.domSelect("."+q.draggableClass, t.pool).length < 1) {
// letztes Element verwendet -> Alle Eingabefelder ausgefüllt?
ok = true; // Wir gehen jetzt einmal davon aus...
q.each(t.element.getElementsByTagName("input"), function (i) {
if (i.value == "") {
ok = false; // Aha, ein Eingabefeld war leer!
}
});
if (ok) {
t.pool.appendChild(t.auswertungsButton);
}
}
},
// Funktion zum Auswerten der Lösungen
auswerten : function () {
var t = this,
loesungen = new Array(),
ok;
// Anzahl Lösungsversuche um eins erhöhen
t.versuche++;
// Drag&Drop-Felder überprüfen
loesungen = q.domSelect("."+t.loesungsClass, t.element);
if (loesungen.length > 0) {
// Es gibt Drag&Drop-Felder zu überprüfen...
q.each(loesungen, function (l) {
var test = new RegExp("^" + l.id.replace(/^([^_]+_\d+)\w+.*$/, "$1"), ""),
element = q.domSelect("."+q.draggableClass, l)[0];
if (!element.id.match(test)) {
// Falsche Zuordnung! Zurück in den Pool damit!
t.pool.appendChild(element);
l.innerHTML = t.lueckenPlatzhalter;
}
});
}
// Eingabefelder überprüfen
loesungen = q.domSelect("."+t.loesungsClass + "_i", t.element);
ok = true; // Wir gehen einmal davon aus, dass alles richtig ist...
q.each(loesungen, function (l) {
q.each(t.inputs, function (i) {
var element = q.domSelect("#"+l.id + "i")[0],
richtig, test;
if (element.id == q.domSelect("input", i.element)[0].id) {
// Inhalt prüfen
test = i.loesung.split("|");
element.value = element.value.quizTrim();
q.each(test, function (t) {
if (element.value == t.quizTrim()) {
richtig = true;
}
});
if (!richtig) {
ok = false; // Falsche Eingabe!
element.value = "";
}
}
});
});
// Auswertungsbutton entfernen
t.auswertungsButton.parentNode.removeChild(t.auswertungsButton);
// Sind alle Eingaben richtig und keine Felder mehr im Pool? -> Quiz erfolgreich gelöst!
if (ok && q.domSelect("span", t.pool).length < 1) {
// Eventhandler entfernen
t.element.onmousedown = null;
t.element.onmousemove = null;
t.element.onmouseup = null;
t.solved = true;
t.element.className += " "+q.fertigClass;
t.pool.parentNode.removeChild(t.pool);
// Elementen die Beweglichkeit nehmen
loesungen = q.domSelect("."+q.draggableClass, t.element);
test = new RegExp(" ?" + q.draggableClass, "");
q.each(loesungen, function (l) {
l.className = l.className.replace(test);
l.style.cursor = "";
});
// Eingabefelder durch gelöste Felder ersetzen
loesungen = q.domSelect("."+t.loesungsClass + "_i", t.element);
q.each(loesungen, function (l) {
l.parentNode.insertBefore(q.domCreate({
tagName : "span",
className : t.loesungsClass,
text : q.domSelect("#"+l.id+"i")[0].value
}), l);
l.parentNode.removeChild(l);
});
// Erfolgsmeldung ausgeben
t.element.appendChild(q.domCreate({
tagName : "p",
className : q.bewertungsClass,
text : q.meldungen[t.sprache]["lob" + (t.versuche > 2 ? 3 : t.versuche)]
+ " "
+ q.meldungen[t.sprache][
"ergebnis" + (t.versuche > 2 ? 3 : t.versuche)
].replace(/%n/i, t.versuche)
}));
}
},
// Funktion zum Erstellen der Lücken, Mischen und Austeilen der beweglichen Wörter, bzw Umwandeln der Wörter zu Engabefeldern
init : function () {
var t = this,
input, felder, benutzte, zufall, luecke, test, i;
// Spracheinstellungen auf deutsch zurück korrigieren, falls entsprechende Sprachdaten fehlen
if (!q.meldungen[t.sprache]) {
t.sprache = "de";
}
/* Jeder markierte Textabschnitt (zum Markieren dienen die Elemente <i>, <b>, <em> und <strong>) wird zu entweder
einem beweglichen SPAN-Element ("Feld"), oder (wenn eine öffnende Klammer für Hilfsangaben enthalten sind)
einem Input-Feld. Das markierende Element (also das <i>, <b> etc.) wird ersetzt durch ein <span>-Element mit der
CSS_Klasse, die in quiz.loesungsClass definiert wurde.
Beispiel1: <p>Eine Henne legt ein <i>Ei</i>.</p>
wird zu
<p>Eine Henne legt ein <span class="luecke" id="......"> nbsp; nbsp; nbsp; </span>.</p>
->"Ei" wird zu <span id="quiz0_xb" class="beweglich">Ei</span> und landet im Pool.
Beispiel2: <p>Eine Henne <b>legt (legen)</b> ein Ei.</p>
wird zu
<p>Eine Henne <span class="luecke"><input type="text" id="......" /></span> (legen) ein Ei.</p>
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;
q.addAllListeners(t);
// 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) {
// <li>-Element ermitteln, um es später einzufärben
var li = i.parentNode;
while (!li.tagName || !li.tagName.match(/^li$/i)) {
li = li.parentNode;
}
// Checkbox unveränderlich machen
i.disabled = "disabled";
if (i.id.match(/_f$/)) {
// Aha, eine Falschantwort...
if (i.checked) {
// ... wurde fälschlicherweise angewählt!
li.className = "falsch";
ok--;
}
} else {
// Aha, eine richtige Antwort...
li.className = "richtig";
anzahl++; // Anzahl der möglichen richtigen Antworten erhöhen
if (i.checked) {
// ...wurde korrekt angewählt
ok++;
}
}
});
// keine negative Wertung für eine Antwort
ok = ok < 0 ? 0 : ok;
richtigkeit += ok; // richtige Treffer merken
});
richtigkeit = (anzahl > 0) ?
Math.floor(richtigkeit / anzahl * 1000) / 10 // auf eine Zehntelstelle genau
: 0;
// Auswertung ins Dokument schreiben
t.element.appendChild(q.domCreate({
tagName : "p",
className : q.bewertungsClass,
text : q.meldungen[t.sprache].ergebnisProzent.replace(/%n/i, richtigkeit)
}));
t.solved = true;
t.element.className += " " + q.fertigClass;
// Auswertungs-Button entfernen
test = q.domSelect(".auswertungs-button", t.element);
if (test.length > 0) {
t.element.removeChild(test[0]);
}
},
// Funktion zum Anzeigen der Fragen und der vermischten möglichen Antworten
init : function () {
var t = this,
frage, antworten, i, j, html, ID;
// Spracheinstellungen auf deutsch zurück korrigieren, falls entsprechende Sprachdaten fehlen
if (!q.meldungen[t.sprache]) {
t.sprache = "de";
}
/* Jede Antwort wird zu einem Listen-Element innerhalb einer geordneten Liste.
Die Liste erhält die CSS-Klasse quiz.loesungsClass.
Die Listenelemente erhalten eine ID, die sich nur am letzten Buchstaben unterscheidet.
Die ID einer Falschantwort erhält zusätzlich ein "_f". */
for (i = 0; i < t.fragen.length; i++) {
// Frage in das Dokument schreiben
frage = q.domCreate({
tagName: "p"
});
frage.innerHTML = t.fragen[i].frage;
t.element.insertBefore(frage, t.fragen[i].original);
// Antworten zusammenstellen und vermischt ausgeben
antworten = q.domCreate({
tagName : "ol",
className : t.loesungsClass
});
html = "";
t.fragen[i].antworten.shuffle();
for (j = 0; j < this.fragen[i].antworten.length; j++) {
ID = this.name + "_" + i + String.fromCharCode(j + 97);
if (this.fragen[i].antworten[j].match(/^\!/))
ID += "_f"; // Falschantwort markieren
html += '<li><input type="checkbox" id="' + ID + '">'
+ '<label for="' + ID + '"> '
+ t.fragen[i].antworten[j].replace(/^\!/, "")
+ "</label></li>";
}
antworten.innerHTML += html;
t.element.insertBefore(frage, t.fragen[i].original);
t.element.insertBefore(antworten, t.fragen[i].original);
t.element.removeChild(t.fragen[i].original);
}
// Auswertungsbutton anzeigen
t.element.appendChild(q.domCreate({
tagName : "p",
className : "auswertungs-button",
text : q.meldungen[t.sprache].pruefen,
onclick : function () { t.auswerten(); }
}));
// ID für das umgebende DIV-Element vergeben
t.element.id = t.name;
}
}
// 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?
fragen = q.domSelect("p", div);
if (fragen.length < 1) {
// Keine Textabsätze für Quiz-Daten gefunden! -> abbrechen
return false;
}
// Daten sind also vorhanden? -> Auswerten
q.each(fragen, function (f) {
// Textabsatz durchforsten
var test = f.innerHTML.replace(/[\t\r\n]/g, " "),
daten = {
frage : "",
antworten : new Array(),
original : null // Referenz auf den originalen Textabsatz, um ihn später zu entfernen
};
// Zeilenumbrüche und überflüssige Leerzeichen entfernen
test = test.replace(/(<br>|<br\/>|<br \/>|&bnsp;| )*$/ig, "");
while (test.match(/\)$/)) {
daten.antworten.push(test.replace(/^.*\(([^\(\)]*)\)$/, "$1"));
// extrahierte Antwort aus dem String entfernen
test = test.replace(/^(.*)\([^\(\)]*\)$/, "$1");
test = test.quizTrim();
}
// Passende Fragen im aktuellen Textabsatz gefunden?
if (daten.antworten.length > 0) {
// Ja! Frage mit dazu ...
daten.frage = test;
daten.original = f; // Referenz zum ursprünglichen Textabsatz
// ... und Daten ins Quiz übertragen
quiz.fragen.push(daten);
}
});
// Keine brauchbare Daten? -> Verwerfen!
i = 0;
q.each(quiz.fragen, 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 Schüttel-Quiz. Dazu braucht sie ein Elternelement mit dem
CSS-Klassen-Präfix "schuettel", z.B. "schuettel-quiz", wenn "-quiz" das Suffix der Quiz.triggerClass ist.
Die mit <strong>, <em>, <b> oder <i> ausgezeichneten Textstellen werden durch Drag&Drop-Felder ersetzt. Sollten
Lösungshinweise in Klammern stehen, so werden die Textstellen durch Eingabefelder ersetzt. */
schuettelQuiz : function (div) {
var q = this,
i, j, test, inhalt, daten;
var quiz = {
// Objekt-Gestalt eines Schüttel-Quizzes
name : "Quiz-x", // Platzhalter - hier steht später etwas anderes.
typ : "Schüttel-Quiz",
loesungsClass : "luecke",
element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet
felder : new Array(), // Hier stehen später Referenzen auf die Text-Eingabefelder und ihre Lösungen
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 (klick) {
var t = this,
loesungen, ok;
if (klick) {
// Auswertungs-Button wurde geklickt! Auswerten!
ok = true; // Mal davon ausgehen, dass alles richtig ist...
// Anzahl Lösungsversuche um eins erhöhen
t.versuche++;
q.each(q.domSelect("."+t.loesungsClass, t.element), function(f) {
var eingabe = q.domSelect("input", f),
nummer;
// bereits als richtig ausgewertete Felder enthalten kein Input-Element mehr!
if (eingabe.length > 0) {
nummer = eingabe[0].id.replace(/^.*_(\d+)$/, "$1");
if (eingabe[0].value.toLowerCase() == t.felder[nummer].loesung.toLowerCase()) {
// Eingabefeld wurde richtig ausgefüllt!
f.innerHTML = t.felder[nummer].loesung;
} else {
// Eingabefeld wurde falsch ausgefüllt! -> leeren
eingabe[0].value = "";
ok = false;
}
}
});
if (ok) {
// Quiz wurde korrekt gelöst! -> Erfolgsmeldung ausgeben
t.element.appendChild(q.domCreate({
tagName : "p",
className : q.bewertungsClass,
text : q.meldungen[t.sprache]["lob" + (t.versuche > 2 ? 3 : t.versuche)]
+ " "
+ q.meldungen[t.sprache][
"ergebnis" + (t.versuche > 2 ? 3 : t.versuche)
].replace(/%n/i, t.versuche)
}));
t.solved = true;
t.element.className += " " + q.fertigClass;
}
}
// Auswertungsbutton entfernen, falls vorhanden
if (t.auswertungsButton.parentNode) {
t.auswertungsButton.parentNode.removeChild(t.auswertungsButton);
}
// Eingabefelder überprüfen
loesungen = q.domSelect("input", t.element);
ok = loesungen.length > 0; // Mal davon ausgehen, dass alle ausgefüllt sind... wenn es welche gibt!
q.each(loesungen, function(l) {
if (l.value == "") {
ok = false; // Feld war leer!
}
});
// Sind alle Eingabefelder ausgefüllt?
if (ok) {
// Ja. -> Button ins Dokument schreiben
t.element.appendChild(t.auswertungsButton);
}
},
// Funktion zum Umwandeln der Wörter zu Engabefeldern
init : function () {
var t = this,
luecke;
// Spracheinstellungen auf deutsch zurück korrigieren, falls entsprechende Sprachdaten fehlen
if (!q.meldungen[t.sprache]) {
t.sprache = "de";
}
/* Jeder markierte Textabschnitt (zum Markieren dienen die Elemente <i>, <b>, <em> und <strong>) wird durch ein
SPAN-Element, in welchem sich ein Input-Element mit einer Lösucngsvorgabe in Klammern befindet, ersetzt.
Es erhält die CSS_Klasse, die in quiz.loesungsClass definiert wurde.
Beispiel: <p>Eine <i>Henne</i> legt ein.</p>
wird zu
<p>Eine <span class="luecke"><input id="......" /> (eeHnn)</span> legt ein Ei.</p>
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: <String>,
quizItem: {
wort: <String>,
x: <Number>,
y: <Number>,
hilfe: <String>,
richtung: "waagrecht|senkrecht",
name: <String>
},
form: <HTMLFormObject>
} */
var t = this,
test = true,
i, p, button, zelle, alleZellen, forms;
if (werte.wort && werte.quizItem) {
// Es wurde ein Button geklickt... Eintragen!
p = {
wort : werte.quizItem.wort,
x : werte.quizItem.x,
y : werte.quizItem.y,
richtung : werte.quizItem.richtung
};
alleZellen = t.findeZellen(p);
for (i = 0; i < alleZellen.length; i ++) {
if (werte.wort.length > i) {
// Buchstabe in die Zelle eintragen
zelle = q.domSelect("."+t.loesungsClass2, alleZellen[i]); // span-Element für Buchstaben finden
if (zelle.length > 0) {
zelle[0].firstChild.nodeValue = werte.wort.substr(
i, 1
).replace(
/ /, String.fromCharCode(160)
);
}
}
}
// Eingabeformular(e) entfernen/aktualisieren
werte.form.parentNode.removeChild(werte.form);
forms = q.domSelect("form", t.eingabe);
if (forms.length > 0) {
// weitere Eingabe(n) möglich -> Formular(e) neu aufbauen
p = new Array();
q.each(forms, function (f) {
p.push({
wort : f.quizDaten.wort,
x : f.quizDaten.x,
y : f.quizDaten.y,
hilfe : f.quizDaten.hilfe,
richtung : f.quizDaten.richtung
});
});
// Formulare neu erstellen lassen
return t.eintragen(p);
} else {
// keine weiteren Eingaben mehr zu tätigen -> weg damit oder Auswertungsbutton anzeigen?
q.each(q.domSelect("."+t.loesungsClass2, t.tabelle), function (a) {
if (!a.lastChild.nodeValue
|| a.lastChild.nodeValue == ""
|| a.lastChild.nodeValue == String.fromCharCode(160)
) {
test = false;
}
});
if (test) {
// Alles ausgefüllt! -> Auswertungs-Button anzeigen!
q.each(q.domSelect("p", t.eingabe), function (a) {
a.style.display = "none";
});
t.eingabe.insertBefore(t.auswertungsButton, t.eingabe.lastChild);
} else {
// weg damit!
t.eingabe.style.display = "none";
}
}
return false;
}
// Auswertungsbutton geklickt?
if (werte == "auswertungs-button") {
// Auswerten!
t.versuche++;
test = true;
q.each(q.domSelect("."+t.loesungsClass2, t.tabelle), function (a) {
if (a.firstChild.nodeValue != a.parentNode.id.replace(
/^.*(\w)$/, "$1"
).replace(
/_/g, " "
)) {
// Falsche Eingabe! -> Löschen
a.firstChild.nodeValue = String.fromCharCode(160);
test = false;
}
});
if (test) {
// Alles richtig!
t.eingabe.parentNode.insertBefore(
q.domCreate({
tagName : "p",
className : q.bewertungsClass,
text: q.meldungen[t.sprache]["lob" + (t.versuche > 2 ? 3 : t.versuche)]
+ " "
+ q.meldungen[t.sprache][
"ergebnis" + (t.versuche > 2 ? 3 : t.versuche)
].replace(/%n/i, t.versuche)
}),
t.eingabe
);
// Auswertungs-Button und alle Eventhandler entfernen
t.eingabe.parentNode.removeChild(t.eingabe);
t.element.onmousedown = null;
t.element.onmouseup = null;
t.solved = true;
t.element.className += " " + q.fertigClass;
} else {
// zurück zum Ausfüllen
q.each(q.domSelect("p", t.eingabe), function (a) {
a.style.display = "";
});
t.eingabe.style.display = "none";
}
}
return false;
},
// Funktion zum Eintragen von Kreuzwort-Wörtern
eintragen : function (werte) {
/* "werte" hat folgende Struktur: Array[
{
wort: <String>,
x: <Number>,
y: <Number>,
hilfe: <String>,
richtung: "waagrecht|senkrecht"
} // eventuell ein weiteres Objekt:
,{
wort: <String>,
x: <Number>,
y: <Number>,
hilfe: <String>,
richtung: "waagrecht|senkrecht"
}
] */
var t = this,
i, p, w, test, text, eingabefeld, zellen;
// Auswertungsbutton entfernen falls vorhanden
if (t.auswertungsButton.parentNode == t.eingabe) {
t.eingabe.removeChild(t.auswertungsButton);
}
while (q.domSelect("form", t.eingabe).length > 0) {
t.eingabe.removeChild(q.domSelect("form", t.eingabe)[0]);
}
// Formular erstellen - für jeden Suchbegriff eines
q.each(werte, function (wert) {
wert.name = t.name;
eingabefeld = q.domCreate({
tagName : "form",
quizDaten : wert,
onsubmit : function () {
var werte = {
wort : "",
quizItem : this.quizDaten,
form: this
};
q.each(
q.domSelect("span", q.domSelect(".eingabezeile", this)[0]),
function (s) {
werte.wort += s.innerHTML.replace(/ /g, " ").quizTrim();
}
);
return t.auswerten(werte);
}
});
t.eingabe.appendChild(eingabefeld);
// Textabsatz mit Lösungshinweis erstellen
p = q.domCreate({
tagName: "p",
// die eigentliche Lösungshilfe
text : wert.hilfe.replace(/^\d+ */, "")
});
// Die Richtung (mehrsprachig!) in einem extra <span>-Element
p.insertBefore(
q.domCreate({
tagName : "span",
className : "richtung",
text: q.meldungen[t.sprache][wert.richtung] + ":"
}),
p.firstChild
);
// Nummer auch in einem extra <span>-Element
p.insertBefore(
q.domCreate({
tagName : "span",
className : "nummer",
text: wert.hilfe.replace(/^(\d+).*$/, "$1")
}),
p.firstChild
);
eingabefeld.appendChild(p);
// korrespondierende Zellen ermitteln, um bereits Eingetragenes mit anzubieten
zellen = t.findeZellen({
wort : wert.wort,
x : wert.x,
y : wert.y,
richtung : wert.richtung
});
// Textabsatz als Eingabezeile erstellen, in welchem die Eingaben in <span>-Elementen stehen
p = q.domCreate({
tagName : "p",
className : "eingabezeile"
});
eingabefeld.appendChild(p);
// <span>-Elemente erstellen
for (w = 0; w < wert.wort.length; w++) {
// bereits vorhandenen Zelleninhalt vorbereiten
test = zellen[w].innerHTML.replace(
// HTML-Tags entfernen
/<\/?[^>]+>/g, ""
).replace(
// Leerzeichen
/ /g, " "
).replace(
// nur letztes Zeichen nehmen (es könnte ja auch eine Eingabeziffer darin stehen)
/.*(.)$/, "$1"
).quizTrim();
// Zelleninhalt voreintragen
p.appendChild(q.domCreate({
tagName : "span",
text : (test.length > 0 ? test : String.fromCharCode(160)),
// dem versteckten Textinput den Focus geben
onmouseup : function () {
q.each(q.domSelect("span", this.parentNode), function (s) {
s.className = "";
});
this.className = "aktiv";
q.domSelect(".texteingabefeld", this.parentNode)[0].focus();
}
}));
}
// Submit-Button braucht keinen Eventhandler, da das Formular onsubmit geprüft wird.
p.appendChild(q.domCreate({
tagName : "input",
type : "submit",
value : q.meldungen[t.sprache].eintragen
}));
// Das versteckte Textinputfeld, das nach jedem Tastendruck ausgelesen wird.
p.appendChild(q.domCreate({
tagName : "input",
type : "text",
className : "texteingabefeld",
// Eventhandler für jeden Tastenanschlag
onkeyup : function (e) {
return t.tasteAuswerten({
obj: this,
e: e
});
},
// Eventhandler für das Verlieren des Focus
onblur : function () {
q.each(q.domSelect("span", this.parentNode), function(s) {
s.className = "";
});
}
}));
// Erstes Eingabefeld aktiv setzen und den Fokus auf das versteckte Eingabefeld legen:
window.setTimeout(function () {
t.eingabefeldAktivieren({
eingabezeile: q.domSelect(".eingabezeile", t.eingabe)[0],
feldnummer: 0, // null für erstes Feld
});
}, 300);
});
t.eingabe.style.display = "block";
return false;
},
// Eingabefeld aktivieren
eingabefeldAktivieren : function (werte) {
/* "werte " hat folgende Struktur: {
eingabezeile: <HTMLParagraphElement>,
feldnummer: <Number> (Wert beginnend bei 0!)
} */
var spans = q.domSelect("span", werte.eingabezeile);
q.each(spans, function (s) {
s.className = "";
});
if (werte.feldnummer < spans.length) {
spans[werte.feldnummer].className = "aktiv";
}
q.domSelect(".texteingabefeld", werte.eingabezeile)[0].focus();
},
tasteAuswerten : function (werte) {
// "werte" hat folgende Struktur; { obj: <input>-Element, e: event}
var t = this,
spans = q.domSelect("span", werte.obj.parentNode),
gefunden = false,
i, j, z;
werte.e = werte.e || window.event;
// aktuelles aktives Eingabefeld ermitteln
for (i = 0; i < spans.length; i++) {
if (spans[i].className == "aktiv") {
gefunden = i;
}
}
switch (werte.e.keyCode) {
case 35: // End (Ende)
// letztes Feld!
t.eingabefeldAktivieren({
eingabezeile: werte.obj.parentNode,
feldnummer: spans.length -1
});
break;
case 36: // Home (Pos1)
// erstes Feld!
t.eingabefeldAktivieren({
eingabezeile: werte.obj.parentNode,
feldnummer: 0
});
break;
case 37: // Cursor left
case 8: // Backspace
// ein Feld zurück!
if (gefunden !== false) {
gefunden = gefunden > 0 ? gefunden -1 : 0;
} else {
// letztes Feld anwählen, da gerade keines aktiv war
gefunden = spans.length -1;
/* eventuell eingegebene Zeichen im <input>-Element entfernen,
da diese sonst jetzt automatisch eingetragen werden! */
werte.obj.value = "";
}
// bei Backspace Feld leeren!
if (werte.e.keyCode == 8) {
spans[gefunden].innerHTML = String.fromCharCode(160);
}
t.eingabefeldAktivieren({
eingabezeile: werte.obj.parentNode,
feldnummer: gefunden
});
break;
case 39: // Cursor right
// ein Feld vor!
if (gefunden !== false) {
gefunden = gefunden < spans.length -2 ? gefunden +1 : spans.length -1;
t.eingabefeldAktivieren({
eingabezeile: werte.obj.parentNode,
feldnummer: gefunden
});
}
break;
}
if (werte.obj.value.length > 0) {
z = q.wandleZeichen(werte.obj.value.substr(0, 1));
// bisherige Eingaben wieder löschen, da immer nur erster Buchstabe genommen wird
werte.obj.value = "";
if (z.length > 0) {
j = false;
for (i = 0; i < spans.length; i++) {
if (spans[i].className && spans[i].className == "aktiv") {
j = i;
}
}
// eventuell sollen mehrere Zeichen eingetragen werden (z.B. bei Ligaturen oder Umlauten)
for (i = 0; i < z.length; i++) {
if (spans[j + i]) {
spans[j + i].innerHTML = z.substr(i, 1);
}
}
t.eingabefeldAktivieren({
eingabezeile : spans[0].parentNode,
feldnummer : j + i
});
}
}
},
/* Funktion zum Ermitteln aller HTML-Elemente (td), in die ein Lösungswort
geschrieben werden muss */
findeZellen : function (werte) {
/* "werte" hat folgende Struktur: {
wort: <String>,
x: <Number>,
y: <Number>,
richtung: "waagrecht|senkrecht"
} */
var t = this,
zellen = new Array(),
zelle, x, y, i;
for (i = 0; i < werte.wort.length; i++) {
zelle = werte.richtung == "waagrecht" ?
q.domSelect("tr", t.tabelle)[werte.y] :
q.domSelect("tr", t.tabelle)[werte.y + i];
if (zelle) {
zelle = werte.richtung == "waagrecht" ?
q.domSelect("td", zelle)[werte.x + i] :
q.domSelect("td", zelle)[werte.x];
}
if (zelle) {
zellen.push(zelle);
}
}
return zellen;
},
// Funktion zum Errichten der Tabelle des Kreuzwort-Quiz und zum Einrichten der Eventhandler
init : function () {
var t = this,
kreuzwortGitter, tr, td, a, x, y;
// Spracheinstellungen auf deutsch zurück korrigieren, falls entsprechende Sprachdaten fehlen
if (!q.meldungen[t.sprache]) {
t.sprache = "de";
}
/* Wörtergitter erzeugen, sodass nach Möglichkeit keine alleinstehenden Wörter
im Gitter enthalten sind */
kreuzwortGitter = q.erstelleWoerterGitter(
t.daten,
true, // true für "alle verbunden"
false // false für "keine diagonalen Wörter"
);
// Daten und Gitter abspeichern
t.daten = kreuzwortGitter.woerter;
t.grid = kreuzwortGitter.gitter;
// Tabelle befüllen
for (y = 0; y < t.grid.length; y++) {
tr = t.tabelle.insertRow(
t.tabelle.rows.length <= 0 ? 0 : t.tabelle.rows.length
);
for (x = 0; x < this.grid[0].length; x++) {
td = q.domCreate({
tagName : "td",
id : t.name + "_" + x + "_" + y
});
if (t.grid[y][x]) {
td.id += "_" + t.grid[y][x];
td.className = t.loesungsClass;
}
// Zelleninhalt
if (t.grid[y][x]) {
td.appendChild(q.domCreate({
tagName : "span",
className : t.loesungsClass2,
text : String.fromCharCode(160)
}));
} else {
td.innerHTML = String.fromCharCode(160);
}
// Zelle in Zeile einhängen
tr.appendChild(td);
}
}
// Einfügemarken und Eventhandler einrichten
a = 1;
q.each(t.daten, function (d) {
var nummer = a, // Nummer der aktuellen Einfügemarke merken
marke;
x = d.x;
y = d.y;
if (td = t.tabelle.rows[y] && t.tabelle.rows[y].cells[x]) {
// bereits eine Einfügemarke vorhanden?
td.style.cursor = "pointer";
if (!td.nummer) {
// Nein! -> Einfügemarke erstellen
marke = q.domCreate({
tagName : "span",
className : "einfuegemarke",
text : nummer
});
td.insertBefore(marke, td.firstChild);
td.nummer = nummer;
a++; // Ziffer der Einfügemarke erhöhen
} else {
// Nummer der vorhandenen Einfügemarke merken
nummer = td.nummer;
}
// Lösungshilfe mit Nummer der Einfügemarke versehen
d.hilfe = nummer + " " + d.hilfe;
// Eventhandler einrichten / erweitern
td.daten = td.daten || new Array();
td.daten.push(d); // auszuwertende Daten für Eingabedialog hinzufügen
if (typeof(td.onclick) != "function") {
td.onclick = function () {
t.eintragen(this.daten);
};
}
}
});
// Eingabebereich erstellen
t.eingabe.className = "eingabe " + q.draggableClass;
// Header des Eingabebereichs
t.eingabe.appendChild(q.domCreate({
tagName : "div",
className : "eingabe-header"
}));
// "schließen"-Schaltfläche
t.eingabe.lastChild.appendChild(q.domCreate({
tagName : "span",
className : "schliessen-button",
onclick : function () {
this.parentNode.parentNode.style.display = "";
}
}));
t.eingabe.lastChild.lastChild.style.cursor = "pointer";
// Textabsatz für einen Eingabehinweis erstellen, der ein verdecktes <span>-Element enthält
t.eingabe.appendChild(q.domCreate({
tagName : "p",
className : "eingabehinweis",
// Anzeigen des verdeckten <span>-Elementes bei Hover (für IE notwendig)
onmouseover : function () {
this.childNodes[0].style.display = "block";
},
// Verbergen des verdeckten <span>-Elementes beim Verlassen
onmouseout : function () {
this.childNodes[0].style.display = "";
}
}));
// Eingabehinweis
t.eingabe.lastChild.appendChild(q.domCreate({
tagName : "span",
text : q.meldungen[t.sprache].eingabehinweis
}));
t.tabelle.parentNode.insertBefore(t.eingabe, t.tabelle.nextSibling);
// Eingabefeld durch Eventhandler für bewegliche Felder zu einem Fensterimitat machen
t.element.onmousedown = q.startDrag;
t.element.onmouseup = q.stopDrag;
// Auswertungsbutton erstellen
t.auswertungsButton = q.domCreate({
tagName : "p",
className : "auswertungs-button",
text : q.meldungen[t.sprache].pruefen,
onclick : function () { t.auswerten("auswertungs-button"); }
});
// ID für das umgebende DIV-Element vergeben
t.element.id = t.name;
// Für die Druckausgabe eine Liste der Lösungshilfen ausgeben
t.element.appendChild(q.domCreate({
tagName : "div",
className : "uebersicht"
}));
// Listen ausgeben
q.each(["senkrecht", "waagrecht"], function (r) {
// Liste erzeugen
var dl = q.domCreate({ tagName : "dl" });
dl.appendChild(q.domCreate({
tagName : "dt",
text : q.meldungen[t.sprache][r]
}));
// passende Lösungshilfen ausfiltern
q.each(t.daten, function (d) {
if (d.richtung == r) {
dl.appendChild(q.domCreate({
tagName : "dd",
text : d.hilfe.replace(/^\d+(.*)/, "$1")
}));
dl.lastChild.appendChild(q.domCreate({
tagName : "span",
text : d.hilfe.replace(/^(\d+).*/, "$1")
}));
}
});
t.element.lastChild.appendChild(dl);
});
}
};
// 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) {
return false;
}
// Daten sind also vorhanden? -> Tabellenzeilen nach Daten durchforsten
q.each(tabelle[0].rows, function (tr) {
var gefunden = new Array();
if (tr.cells.length > 1) {
// "Müll" entfernen
gefunden[0] = tr.cells[0].innerHTML.replace(
/<\/?[^>]+>/g, ""
).replace(
/&/g, "&"
).replace(
/ /g, " "
).replace(/ /g, "_");
gefunden[1] = tr.cells[1].innerHTML.replace(
/<\/?[^>]+>/g, ""
).replace(
/&/g, "&"
).replace(/ /g, " ");
// Lösungswort in reine Großbuchstaben umwandeln
gefunden[0] = q.wandleZeichen(gefunden[0]).toUpperCase();
if (gefunden[0] != "" && gefunden[1] != "") {
quiz.daten.push({
wort : gefunden[0].quizTrim(),
x : -1,
y : -1,
hilfe : gefunden[1].quizTrim()
});
}
}
});
// Keine brauchbare Daten? -> Verwerfen!
if (quiz.daten.length < 1) {
return false;
}
// originale Tabelle durch leere Tabelle ersetzen
quiz.tabelle = document.createElement("table");
quiz.tabelle.className = "gitter";
tabelle[0].parentNode.insertBefore(quiz.tabelle, tabelle[0].nextSibling);
tabelle[0].parentNode.removeChild(tabelle[0]);
// Quiz in die Liste aufnehmen und initialisieren
q.alleQuizze[quiz.name] = quiz;
quiz.element.quiz = quiz;
quiz.init();
return true;
},
erstelleWoerterGitter : function (woerter, alleVerbunden, diagonaleWoerter, keineFreienZwischenRaeume) {
/* übergebene Parameter
@woerter:
Ein Array mit Wort-Objekten. Ein Wort-Objekt hat mindestens diese Struktur:
wort = {
wort : (String),
hilfe : (String), // nur bei Aufruf aus dem Kreuzworträtsel-Quiz heraus
wortOriginal : (String) // nur bei Aufruf aus dem Suchsel-Quiz heraus
}
Nach dieser Funktion kann ein Wort-Objekt dann auch so aussehen
wort = {
wort : (String),
x : (Integer),
y : (Integer),
richtung : (String), "waagrecht|senkrecht"
hilfe : (String), // nur bei Aufruf aus dem Kreuzworträtsel-Quiz heraus
wortOriginal : (String) // nur bei Aufruf aus dem Suchsel-Quiz heraus
}
@alleVerbunden (true|false):
Wenn true, werden bis zu 10 Versuche unternommen, ein Gitter zu erstellen,
bei dem alle Begriffe miteinander verbunden sind.
@diagonaleWoerter (true|false):
Wenn true, werden Wörter auch diagonal eingepasst. Dabei ist die
Leserichtung immer von links nach rechts, egal ob das Wort von links
oben nach rechts unten, oder von links unten nach rechts oben verläuft.
*/
var q = this;
var fertige = new Array(); // Array mit fertigen Gittern
var makel = 1, maxVersuche = alleVerbunden ? 10 : 1;
var richtungen = diagonaleWoerter ?
["waagrecht", "senkrecht", "diagonal-loru", "diagonal-luro"]
:
["waagrecht", "senkrecht"];
var grid, abgelegte, erfolglose, test, zufall, i, wort, a,
eingepasst, x, y, nummer, p, button, input, buchstaben, b, d, moeglicheRichtungen, r;
// Gitter erzeugen, falls das nicht ohne Makel gelingt, bis zu 10x
while (makel > 0 && fertige.length < maxVersuche) {
makel = 0; // zuerst davon ausgehen, dass ein perfektes Gitter entstehen wird
abgelegte = new Array(); // es wurde noch nichts abgelegt
erfolglose = new Array(); // es gibt noch keine erfolglos eingepassten Wörter
// Grid aufbauen
test = 0;
q.each(woerter, function (w) {
test += w.wort.length; // Anzahl Buchstaben insgesamt
});
grid = new Array(test);
for (i = 0; i < test; i++) {
grid[i] = new Array(test);
}
// Wörter in zufälliger Reihenfolge ins Gitter einpassen - wenn es gelingt
while (abgelegte.length < woerter.length) {
test = true; // neue Zufallszahl erzwingen
while (test) {
zufall = Math.floor(Math.random() * woerter.length);
test = false; // annehmen, dass die Zufallszahl noch nicht benutzt wurde
// Wort bereits abgelegt?
q.each(abgelegte, function (a) {
if (a.wort == woerter[zufall].wort) {
test = true;
}
});
if (erfolglose.length > 0) {
// bereits erfolglos probierte Wörter ausschließen
q.each(erfolglose, function (e) {
if (woerter[zufall] == e) {
test = true;
}
});
}
}
// Jetzt haben wir ein Wort zum Einpassen in das Gitter
wort = woerter[zufall];
wort.x = -1;
wort.y = -1;
// geeignete Stelle finden, um es einzupassen
if (abgelegte.length > 0) {
// weiteres Wort einfügen -> bereits eingesetzte Wörter der Reihe nach durchgehen
for (a = 0; a < abgelegte.length; a++) {
// schon eine passende Stelle zum Einpassen ermittelt?
if (wort.x >= 0 && wort.y >= 0)
break; // Ja! -> abbrechen!
// zufälligen Buchstaben des Wortes nehmen und nach Übereinstimmungen mit eingepasstem Wort suchen
buchstaben = new Array(); // benutzte Buchstaben leeren
for (b = 0; b < wort.wort.length; b++) {
// schon eine passende Stelle zum Einpassen ermittelt?
if (wort.x >= 0 && wort.y >= 0)
break; // Ja! -> abbrechen!
test = true; // neue Zufallszahl erzwingen
while (test) {
zufall = Math.floor(Math.random() * wort.wort.length);
test = buchstaben[zufall];
}
buchstaben[zufall] = true; // Buchstaben als benutzt markieren
// Buchstabe in beiden Wörtern vorhanden?
if (abgelegte[a].wort.indexOf(wort.wort.substr(zufall, 1)) >= 0) {
// Ja! -> jeden Buchstaben des bereits eingepassten Wortes durchgehen
for (eingepasst = 0; eingepasst < abgelegte[a].wort.length; eingepasst++) {
// Wort bereits erfolgreich eingepasst?
if (wort.x >= 0 && wort.y >= 0)
break; // Ja! -> abbrechen
if (abgelegte[a].wort.substr(eingepasst, 1) == wort.wort.substr(zufall, 1)) {
// übereinstimmender Buchstabe ermittelt! -> Wort testweise ins Gitter einpassen
test = true; // davon ausgehen, dass das Wort passt...
// Position des Buchstabens im Gitter ermitteln
if (abgelegte[a].richtung == "waagrecht") {
x = abgelegte[a].x + eingepasst;
y = abgelegte[a].y;
}
if (abgelegte[a].richtung == "senkrecht") {
x = abgelegte[a].x;
y = abgelegte[a].y + eingepasst;
}
if (abgelegte[a].richtung == "diagonal-loru") {
x = abgelegte[a].x + eingepasst;
y = abgelegte[a].y + eingepasst;
}
if (abgelegte[a].richtung == "diagonal-luro") {
x = abgelegte[a].x + eingepasst;
y = abgelegte[a].y - eingepasst;
}
// mögliche Richtungen für neu einzupassendes Wort ermitteln
moeglicheRichtungen = [];
for (i = 0; i < richtungen.length; i++) {
if (richtungen[i] != abgelegte[a].richtung) {
moeglicheRichtungen.push(richtungen[i]);
}
}
moeglicheRichtungen.shuffle();
while (moeglicheRichtungen.length) {
// Richtung des einzupassenden Wortes festlegen
wort.richtung = moeglicheRichtungen.pop();
// im Gitter die Startposition des einzupassenden Wortes ermitteln
if (wort.richtung == "senkrecht") {
y = y - zufall; // "zufall" ist der Abstand des entsprechenden Buchstabens zum Wortbeginn
}
if (wort.richtung == "waagrecht") {
x = x - zufall;
}
if (wort.richtung == "diagonal-loru") {
x = x - zufall;
y = y - zufall;
}
if (wort.richtung == "diagonal-luro") {
x = x - zufall;
y = y + zufall;
}
// zu belegende Felder im Gitter prüfen
for (i = 0; i < wort.wort.length; i++) {
if (wort.richtung == "waagrecht") {
if (grid[y][x + i] && grid[y][x + i] != wort.wort.substr(i, 1)) {
test = false;
}
// nebenan frei? (Kosmetik)
if (!keineFreienZwischenRaeume) {
/* alle bereits abgelegten Wörter daraufhin prüfen, ob sie im
Bereich des Wortes parallel in einer Nachbarzeile verlaufen */
q.each(abgelegte, function (a) {
if (a.richtung == "waagrecht"
&& (a.y + 1 == y
|| a.y -1 == y)
) {
if (// Nachbarwort länger?
(a.x <= x &&
a.wort.x + a.wort.length >= x + wort.wort.length)
||
// Nachbarwort überlappt Anfang
(a.x <= x
&& a.x + a.wort.length >= x)
||
// Nachbarwort beginnt mitten im Wort
(a.x > x
&& a.x <= x + wort.wort.length)
) {
test = false; // ja -> verwerfen
}
}
// beginnt ein senkrechtes Wort direkt unterhalb?
if (a.richtung == "senkrecht" && a.y - 1 == y) {
if (a.x >= x && a.x <= x + wort.wort.length) {
test = false; // ja -> verwerfen
}
}
});
}
}
if (wort.richtung == "senkrecht") {
if (grid[y + i][x] && grid[y + i][x] != wort.wort.substr(i, 1)) {
test = false;
}
// nebenan frei? (Kosmetik)
if (!keineFreienZwischenRaeume) {
/* alle bereits abgelegten Wörter daraufhin prüfen, ob sie im
Bereich des Wortes parallel in einer Nachbarspalte verlaufen */
q.each(abgelegte, function (a) {
if (a.richtung == "senkrecht"
&& (a.x == x + 1
|| a.x == x - 1)
) {
if (// Nachbarwort länger?
(a.y <= y &&
a.wort.y + a.wort.length >= y + wort.wort.length)
||
// Nachbarwort überlappt Anfang
(a.y <= y
&& a.y + a.wort.length >= y)
||
// Nachbarwort beginnt mitten im Wort
(a.y > y
&& a.y <= y + wort.wort.length)
) {
test = false; // leider nein
}
}
// verläuft ein waagrechtes Wort direkt nebenan?
if (a.richtung == "waagrecht" &&
(a.x == x + 1 || a.x == x - wort.wort.length - 1)
) {
if (a.y >= y && a.y <= y + wort.wort.length) {
test = false; // ja -> verwerfen
}
}
});
}
}
if (wort.richtung == "diagonal-loru") {
if (grid[y + i][x + i] && grid[y + i][x + i] != wort.wort.substr(i, 1)) {
test = false;
}
}
if (wort.richtung == "diagonal-luro") {
if (grid[y - i][x + i] && grid[y - i][x + i] != wort.wort.substr(i, 1)) {
test = false;
}
}
}
// Ist vor und nach dem Wort noch Platz? (Kosmetik)
if (wort.richtung == "waagrecht") {
if (grid[y][x - 1] || grid[y][x + wort.wort.length])
test = false;
}
if (wort.richtung == "senkrecht") {
if (grid[y - 1][x] || grid[y + wort.wort.length][x])
test = false;
}
if (wort.richtung == "diagonal-loru") {
if (grid[y - 1][x - 1] || grid[y + wort.wort.length][x + wort.wort.length])
test = false;
}
if (wort.richtung == "diagonal-luro") {
if (grid[y + 1][x - 1] || grid[y - wort.wort.length][x + wort.wort.length])
test = false;
}
if (test) {
// hat gepasst! -> Wort übernehmen lassen!
wort.x = x;
wort.y = y;
erfolglose = new Array(); // erfolglos eingepasste Wörter wieder versuchen
break; // weitere Tests abbrechen
}
}
if (test)
break; // weitere Tests abbrechen
}
}
}
}
}
if (wort.x < 0 && wort.y < 0) {
// hat nicht gepasst! -> merken
erfolglose.push(wort);
if (erfolglose.length == (woerter.length - abgelegte.length)) {
// anscheinend gibt es für die restlichen Wörter überhaupt keine geeignete Stelle... -> ein freies Plätzchen für aktuelles Wort finden! -> oben (0), links(1), unten(2) oder rechts(3)
makel ++;
zufall = Math.floor(Math.random() * 4);
if (zufall & 1 == 1) {
// links / rechts
y = Math.floor(grid.length / 2) - Math.floor(wort.wort.length / 2);
x = (zufall & 2) == 2 ? 0 : grid[0].length; // Wert muss unter- bzw. überboten werden, daher ist er zu klein/groß
} else {
// oben / unten
x = Math.floor(grid[0].length / 2);
y = (zufall & 2) == 2 ? 0 : grid.length;
}
wort.richtung = (zufall & 1) == 0 ? "waagrecht" : "senkrecht";
// Koordinaten der abgelegten Wörter durchgehen, um freie Stelle zu ermitteln
q.each(abgelegte, function (a) {
if ((zufall & 1) == 1) {
// links / rechts einschränken
if ((zufall & 2) == 0 && a.x < x)
x = a.x;
if ((zufall & 2) == 2) {
test = a.x;
if (a.richtung == "waagrecht")
test += a.wort.length;
if (test > x)
x = test;
}
} else {
// oben / unten einschränken
if ((zufall & 2) == 0 && a.y < y)
y = a.y;
if ((zufall & 2) == 2) {
test = a.y;
if (a.richtung == "senkrecht")
test += a.wort.length;
if (test > y)
y = test;
}
}
});
// geeignete Position zum Einpassen gefunden!
wort.x = (zufall & 2) == 0 ? x - 2 : x + 2;
wort.y = (zufall & 2) == 0 ? y - 2 : y + 2;
erfolglose = [];
}
}
} else {
// es ist das erste Wort -> direkt (senkrecht) einpassen
wort.x = Math.floor(grid[0].length / 2);
wort.y = Math.floor(grid.length / 2) - Math.floor(wort.wort.length / 2);
wort.richtung = "senkrecht";
}
// abspeichern wenn Wort erfolgreich eingepasst werden konnte
if (wort && wort.x >= 0 && wort.y >= 0) {
abgelegte.push(wort);
// Buchstaben in das Gitter eintragen
for (i = 0; i < wort.wort.length; i++) {
if (wort.richtung == "waagrecht") {
grid[wort.y][wort.x + i] = wort.wort.substr(i, 1);
}
if (wort.richtung == "senkrecht") {
grid[wort.y + i][wort.x] = wort.wort.substr(i, 1);
}
if (wort.richtung == "diagonal-loru") {
grid[wort.y + i][wort.x + i] = wort.wort.substr(i, 1);
}
if (wort.richtung == "diagonal-luro") {
grid[wort.y - i][wort.x + i] = wort.wort.substr(i, 1);
}
}
}
}
// fertig erstelltes und bestücktes Gitter abspeichern
fertige.push({
gitter : grid,
daten : abgelegte,
makel : makel
});
}
// eventuell wurden nun mehrere Gitter erstellt
if (makel > 0) {
// anscheinend wurde kein perfektes Gitter erstellt -> das beste aus den maximal zehn erstellten aussuchen
test = false;
q.each(fertige, function (f) {
if (!test || f.makel < test.makel)
test = f;
});
// bester Versuch wurde ermittelt -> nehmen
grid = test.gitter;
abgelegte = test.daten;
}
// ausgewähltes Gitter beschneiden
a = {
x : {
min : grid[0].length,
max : 0
},
y : {
min : grid.length,
max : 0
}
};
for (y = 0; y < grid.length; y++) {
for (x = 0; x < grid[0].length; x++) {
// Zelle befüllt? -> Koordinaten benutzen!
if (grid[y][x]) {
// min-Werte bei Bedarf verkleinern!
a.x.min = (a.x.min > x) ? x : a.x.min;
a.y.min = (a.y.min > y) ? y : a.y.min;
// max-Werte bei Bedarf erhöhen
a.x.max = (a.x.max < x) ? x : a.x.max;
a.y.max = (a.y.max < y) ? y : a.y.max;
}
}
}
// min/max-Maße ermittelt -> Gitterinhalt in beschnittenes Gitter übertragen
test = new Array(a.y.max - a.y.min + 1);
for (y = 0; y < (a.y.max - a.y.min + 1); y++) { // zeilenweise
test[y] = new Array(a.x.max - a.x.min + 1);
for (x = 0; x < (a.x.max - a.x.min + 1); x++) { // spaltenweise
if (grid[y + a.y.min][x + a.x.min])
test[y][x] = grid[y + a.y.min][x + a.x.min]; // Inhalt übertragen
}
}
grid = test; // altes Gitter durch neues ersetzen
// eingetragene Koordinaten der Wörter korrigieren
for (i = 0; i < abgelegte.length; i++) {
abgelegte[i].x = abgelegte[i].x - a.x.min;
abgelegte[i].y = abgelegte[i].y - a.y.min;
}
return { gitter : grid, woerter : abgelegte };
},
/* Diese Funktion erzeugt ein Suchsel-Quiz. Dazu braucht sie ein Elternelement mit dem
CSS-Klassen-Präfix "suchsel", z.B. "suchsel-quiz", wenn "-quiz" das Suffix der Quiz.triggerClass ist.
Die Daten für das Quiz müssen in einer einspaltigen Tabelle stehen.
*/
suchselQuiz : function (div) {
var q = this,
i, tabelle;
var quiz = {
// Objekt-Gestalt eines Suchsel-Quizzes
name : "Quiz-x", // Platzhalter - hier steht später etwas anderes.
typ : "Suchsel-Quiz",
element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet
tabelle : null, // Referenz auf das HTML-Element, in dem das Suchsel angezeigt wird
daten : new Array(), // Hier stehen später Objekte, die die Quiz-Daten enthalten.
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
loesungsliste : null, // Referenz auf ein <ol>-Objekt, in dem bereits gefundene Wörter angezeigt werden
markierungStart : null, // Referenz auf das erste markierte <td>-Element
markierungEnde : null, // Referenz auf das letzte markierte <td>-Element
// Funktion zum Auswerten der Lösungen
auswerten : function () {
var t = this,
el = q.domSelect(".markiert", t.tabelle),
betroffene = [],
felder = [];
if (el.length > 1) {
t.versuche++;
// Koordinaten der markierten Felder ermitteln
q.each(el, function (f) {
felder.push({
buchstabe : f.innerHTML,
x : f.id.replace(/^quiz\d+_(\d+)_.*/i, "$1"),
y : f.id.replace(/.*_(\d+)$/i, "$1")
});
});
// Jedes Lösungswort prüfen, ob sein Anfangsbuchstabe markiert wurde
q.each(t.daten, function (d) {
q.each(felder, function (f) {
if (d.x == f.x && d.y == f.y) {
// Lösungswort merken
betroffene.push(d);
}
});
});
// Jedes betroffene Lösungswort prüfen, ob es vollständig markiert wurde
q.each(betroffene, function (b) {
var erfolg;
// stimmt die Anzahl markierter Felder exakt?
if (b.wort.length == felder.length) {
// prüfen, ob alle markierten Felder auch die richtigen Felder sind
erfolg = b; // mal davon ausgehen, dass alles passt
q.each(felder, function (f) {
if (b.richtung == "senkrecht") {
// x-Werte immer identisch!
if (f.x != b.x || f.y < b.y
|| f.y > b.y + b.wort.length -1
) {
erfolg = false;
}
}
if (b.richtung == "waagrecht") {
// y-Werte immer identisch
if (f.y != b.y || f.x < b.x
|| f.x > b.x + b.wort.length -1
) {
erfolg = false;
}
}
if (b.richtung == "diagonal-loru") {
if (f.x - f.y != b.x - b.y
|| f.x < b.x
|| f.x > b.x + b.wort.length -1
|| f.y < b.y
|| f.y > b.y + b.wort.length -1
) {
erfolg = false;
}
}
if (b.richtung == "diagonal-luro") {
if (Math.abs(f.x) + Math.abs(f.y) != b.x + b.y
|| f.x < b.x
|| f.x > b.x + b.wort.length -1
|| f.y > b.y
|| f.y < b.y - b.wort.length -1
) {
erfolg = false;
}
}
});
if (erfolg) {
// "erfolg" enthält das Datenobjekt der Lösung
q.each(el, function(f) {
// Markierungen dauerhaft machen
f.className = f.className.replace(/ markiert/, "") + " aufgedeckt";
});
// Fund in die Liste eintragen
erfolg.eingetragen = false;
el = q.domSelect("li", t.loesungsliste);
q.each(el, function (li) {
// Wort bereits gefunden worden?
if (li.innerHTML == erfolg.wortOriginal) {
erfolg.eingetragen = true;
}
if (!erfolg.eingetragen &&
(!li.className || li.className != "ausgefuellt")
) {
li.innerHTML = erfolg.wortOriginal;
li.className = "ausgefuellt";
erfolg.eingetragen = true;
if (q.domSelect(
".ausgefuellt", t.loesungsliste
).length == el.length
) {
// letztes Wort wurde gefunden!
t.beenden();
}
}
});
}
}
});
}
return false;
},
// entferne alle Markierungen
alleMarkierungenEntfernen : function (mitHover) {
var t = this;
q.each(q.domSelect(".markiert", t.tabelle), function (f) {
f.className = f.className.replace(/(^| )markiert/, "");
});
if (mitHover) {
q.each(q.domSelect(".hover", t.tabelle), function (f) {
f.className = f.className.replace(/(^| )hover/, "");
});
}
},
// Felder markieren, die die gegenwärtige Auswahl darstellen
auswahlMarkieren : function () {
var t = this,
richtung = "",
el, ende, start, steigung, x, y;
/* In welche Richtung geht die Markierung denn?
-> Zeilenweise die Tabelle durchlaufen,
um X- und Y-Koordinaten der Markierungsenden zu ermitteln */
for (y = 0; y < t.tabelle.rows.length; y++) {
for (x = 0; x < t.tabelle.rows[y].cells.length; x++) {
if (t.tabelle.rows[y].cells[x] == t.markierungStart) {
start = { x : x, y : y };
}
if (t.tabelle.rows[y].cells[x] == t.markierungEnde) {
ende = { x : x, y : y };
}
}
}
// Fehler passiert? -> beenden
if (!start || !ende) {
return false;
}
// Steigung bestimmen, in der die Markierung erfolgen soll
if ((ende.y - start.y) === 0) {
// Division by Zero!
steigung = 2; // hier genügt ein Wert > 1.5
} else {
// Quotient ist "legal"
steigung = (ende.x - start.x) / (ende.y - start.y);
}
// Richtung aus der Steigung und der Koordinaten bestimmen
if (Math.abs(steigung) >= 0.5 && Math.abs(steigung) <= 1.5) {
// diagonal
richtung = steigung > 0 ? "nw-so" : "no-sw";
} else {
// waagrecht/senkrecht
richtung = Math.abs(steigung) > 1 ? "w-o" : "n-s";
}
// alle zu markierenden Felder ermitteln und markieren
x = start.x;
y = start.y;
el = t.tabelle.rows[y].cells[x];
while (el) {
el.className = el.className.replace(/(^| )markiert/, "") + " markiert";
// "richtung" enthält nun einen String (n-s|w-o|nw-so|no-sw)
switch (richtung) {
case "n-s":
// nur y-Wert weiterzählen
if (start.y > ende.y && y > ende.y) {
y--;
}
if (start.y < ende.y && y < ende.y) {
y++;
}
break;
case "w-o":
// nur x-Wert weiterzählen
if (start.x > ende.x && x > ende.x) {
x--;
}
if (start.x < ende.x && x < ende.x) {
x++;
}
break;
case "nw-so":
if (start.x > ende.x && x > ende.x
&&
start.y > ende.y && y > ende.y
) {
x--;
y--;
}
if (start.x < ende.x && x < ende.x
&&
start.y < ende.y && y < ende.y
) {
x++;
y++;
}
break;
case "no-sw":
if (start.x > ende.x && x > ende.x
&&
start.y < ende.y && y < ende.y
) {
x--;
y++;
}
if (start.x < ende.x && x < ende.x
&&
start.y > ende.y && y > ende.y
) {
x++;
y--;
}
break;
}
// aufhören, wenn kein neues Feld zu markieren ist
el = (el != t.tabelle.rows[y].cells[x]) ?
t.tabelle.rows[y].cells[x] : false;
}
},
// Quiz wurde erfolgreich gelöst -> Meldung ausgeben
beenden : function () {
var t = this;
t.element.appendChild(q.domCreate({
tagName : "p",
className : q.bewertungsClass,
text : q.meldungen[t.sprache]["lob" + (t.versuche > 2 ? 3 : t.versuche)]
+ " "
+ q.meldungen[t.sprache][
"ergebnis" + (t.versuche > 2 ? 3 : t.versuche)
].replace(/%n/i, t.versuche)
}));
// Auswertungs-Button und alle Eventhandler entfernen
t.tabelle.onmousedown = null;
t.tabelle.onmousemove = null;
t.tabelle.onmouseover = null;
t.tabelle.onmouseup = null;
t.solved = true;
t.element.className += " "+q.fertigClass;
},
// Funktion zum Errichten der Tabelle des Suchsel-Quiz und zum Einrichten der Eventhandler
init : function () {
var t = this,
kreuzwortGitter, platzhalter, tr, x, y;
// Spracheinstellungen auf deutsch zurück korrigieren, falls entsprechende Sprachdaten fehlen
if (!q.meldungen[t.sprache]) {
t.sprache = "de";
}
// Gitter erzeugen
kreuzwortGitter = q.erstelleWoerterGitter(
t.daten,
true, // true für "alle Wörter verbunden"
true // true für "diagonale Wörter möglich"
);
// Daten und Gitter abspeichern
t.daten = kreuzwortGitter.woerter;
t.grid = kreuzwortGitter.gitter;
// Lösungsliste befüllen
platzhalter = 0;
q.each(t.daten, function (d) {
if (platzhalter < d.wortOriginal.length) {
platzhalter = d.wortOriginal.length;
}
});
platzhalter = new Array(platzhalter +3).join("_");
q.each(t.daten, function (d) {
t.loesungsliste.appendChild(q.domCreate({
tagName : "li",
text : platzhalter
}));
});
// Tabelle befüllen
for (y = 0; y < t.grid.length; y++) {
tr = t.tabelle.insertRow(
t.tabelle.rows.length <= 0 ? 0 : t.tabelle.rows.length
);
for (x = 0; x < t.grid[0].length; x++) {
// Zelleninhalt vorbereiten
tr.appendChild(q.domCreate({
tagName : "td",
id : t.name + "_" + x + "_" + y,
text : t.grid[y][x] ?
t.grid[y][x] : String.fromCharCode(
65 + Math.floor(Math.random() * 26)
).toUpperCase()
}));
}
}
// ID für das umgebende DIV-Element vergeben
t.element.id = t.name;
// Markierungsmechanismus einrichten
t.tabelle.onmousedown = function (e) {
var el = q.eventElement(e);
if (el.tagName && el.tagName.match(/^td$/i)) {
el.className = el.className.replace(/(^| )hover/, "") + " markiert";
// Beginn der Markierung merken
t.markierungStart = el;
// Markiermodus einschalten
t.markiermodus = true;
// Markierungseffekt im IE unterbinden
q.antiMarkierungsModusFuerIE(true);
// Markierungseffekt in W3C-konformen Browsern unterbinden
if (window.getSelection) {
window.getSelection().removeAllRanges();
}
}
e.preventDefault();
return true;
};
t.tabelle.addEventListener("touchstart",t.tabelle.onmousedown);
t.tabelle.onmouseover = function (e) {
var el = q.eventElement(e);
if (el.tagName && el.tagName.match(/^td$/i) && t.markiermodus) {
t.markierungEnde = el;
// bestehende Markierungen entfernen
t.alleMarkierungenEntfernen();
// neue Markierungen setzen
t.auswahlMarkieren();
}
e.preventDefault();
return true;
};
t.tabelle.onmousemove = function (e) {
var el = q.eventElement(e);
if (!t.markiermodus) {
t.alleMarkierungenEntfernen(true); // mit Hover
// setze hover-Markierung für aktuelles Element
if (el.tagName && el.tagName.match(/^td$/i)) {
el.className += " hover";
}
} else {
// Markierungseffekt in W3C-konformen Browsern unterbinden
if (window.getSelection) {
window.getSelection().removeAllRanges();
}
}
return true;
};
t.tabelle.addEventListener("touchmove",t.tabelle.onmouseover);
t.tabelle.addEventListener("touchmove",t.tabelle.onmousemove);
t.element.onmouseup = function (e) {
// markierte Felder auswerten
t.auswerten();
// alle Markierungen entfernen
t.alleMarkierungenEntfernen();
// Beende Markiermodus
t.markiermodus = false;
// Markierungseffekt im IE wieder erlauben
q.antiMarkierungsModusFuerIE();
return true;
};
t.element.addEventListener("touchend",t.element.onmouseup);
t.element.addEventListener("touchcancel",t.element.onmouseup);
t.tabelle.onmouseout = function (e) {
if (!t.markiermodus) {
// entferne alle Markierungen (samt hover)
t.alleMarkierungenEntfernen(true);
}
};
}
};
// 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) {
return false;
}
// Daten sind also vorhanden? -> Auswerten
q.each(tabelle[0].rows, function (tr) {
var gefunden;
if (tr.cells.length > 0) {
// "Müll" entfernen
gefunden = tr.cells[0].innerHTML.replace(
/<\/?[^>]+>/g, ""
).replace(
/&/g, "&"
).replace(
/ /g, " "
).replace(
/ /g, "_"
).quizTrim();
if (gefunden != "") {
quiz.daten.push({
// Lösungswort in reine Großbuchstaben umwandeln
wort : q.wandleZeichen(gefunden).toUpperCase(),
wortOriginal : gefunden,
x : -1,
y : -1
});
}
}
});
// Keine brauchbare Daten? -> Verwerfen!
if (quiz.daten.length < 1) {
return false;
}
// originale Tabelle durch leere Tabelle ersetzen
quiz.tabelle = q.domCreate({
tagName : "table",
className : "gitter"
});
tabelle[0].parentNode.insertBefore(quiz.tabelle, tabelle[0].nextSibling);
tabelle[0].parentNode.removeChild(tabelle[0]);
// Liste mit gefundenen Lösungen erstellen
quiz.loesungsliste = q.domCreate({
tagName : "ol",
className : "liste"
});
div.appendChild(quiz.loesungsliste);
// Quiz in die Liste aufnehmen und initialisieren
q.alleQuizze[quiz.name] = quiz;
quiz.element.quiz = quiz;
quiz.init();
return true;
},
/* Diese Funktion erzeugt ein Quiz, das man auch als Hangman-Quiz kennt. Es müssen die Buchstaben
eines Wortes geraten werden, um zu einer Lösung zu geraten. Zu viele Fehlversuche führen zum Verlieren
des Spiels. */
buchstabenratenQuiz : function (div) {
var q = this,
i, tabelle, test, daten, gefunden;
var quiz = {
// Objekt-Gestalt eines Suchsel-Quizzes
name : "Quiz-x", // Platzhalter - hier steht später etwas anderes.
typ : "Buchstabenraten-Quiz",
element : div, // Referenz auf das DIV-Element, in welchem sich das Quiz befindet
feld : null, // Referenz auf das HTML-Element, in dem das eigentliche Spiel angezeigt wird
daten : new Array(), // Hier stehen später Objekte, die die Quiz-Daten enthalten.
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
erkannteWoerter : new Array(), // speichert die bereits erratenen Wörter
gestartet : false, // Steuert, ob Tastatureingaben überhaupt ausgewertet werden
bilder : new Array(
/* Hier stehen die Bilddateien für die verschiedenen Stadien der Grafik, die das drohende
Spielende darstellt. Dabei gilt die erste Grafik als Spielende und die letzte Grafik als Spielstart. */
"blume00.gif",
"blume01.gif",
"blume02.gif",
"blume03.gif",
"blume04.gif",
"blume05.gif",
"blume06.gif",
"blume07.gif",
"blume08.gif",
"blume09.gif",
"blume10.gif"
),
// Funktion zum Auswerten der Lösungen
auswerten : function (keyCode) {
var t = this,
c = q.wandleZeichen(String.fromCharCode(keyCode)),
schonGeraten, treffer, ul, li;
if (c) {
ul = q.domSelect(".geratene-buchstaben ul", t.element)[0]; // Element muss vorhanden sein
// testen, ob dieser Buchstabe bereits geraten worden war
q.each(ul.childNodes, function (li) {
if (li.firstChild.data == c) {
schonGeraten = true;
}
});
if(schonGeraten)
return;
// noch nicht geraten worden? -> auf Treffer testen
if (!schonGeraten) {
li = q.domCreate({
tagName : "li",
text : c
});
ul.appendChild(li);
// Ist der Buchstabe im Lösungswort enthalten?
ul = q.domSelect(".ratewort ", t.element)[0]; // Element ist garantiert vorhanden
q.each(ul.childNodes, function (l) {
if (l.buchstabe == c) {
treffer = true;
l.className = "erraten";
l.firstChild.data = l.buchstabe;
li.className = "treffer";
}
});
}
// Ergebnis?
if (!treffer) {
t.versuche++;
// Statusbild aktualisieren
q.domSelect(".statusbild img", t.feld)[0].src = q.baseURL
+ "/images/"
+ t.bilder[t.bilder.length - 1 - t.versuche];
// Spiel zu Ende?
if (t.versuche == t.bilder.length - 1) {
t.beenden();
}
} else {
// Wort komplett erkannt?
q.each(ul.childNodes, function (li) {
// ul ist #ratewort! Prüfen ob alle Felder einen Buchstaben enthalten
if (li.firstChild.data == String.fromCharCode(160)) {
treffer = false; // nicht alle Buchstaben sind schon erkannt
}
})
if (treffer) {
// nächstes Wort erraten lassen
t.erkannteWoerter.push(t.daten[t.erkannteWoerter.length]);
if (t.versuche > 0) {
t.versuche--;
}
window.setTimeout(
function () {
t.wortAbfragen();
},
2000
);
}
}
}
},
// Funktion zum starten des Quiz-Vorgangs
wortAbfragen : function () {
var t = this,
platzhalter, i;
// "Spielfeld" aufbauen
while (t.feld.firstChild) {
t.feld.removeChild(t.feld.firstChild);
}
var input = document.createElement("input");
t.feld.appendChild(input);
input.style.width=0;
input.style.height=0;
input.style.opacity=0;
input.focus();
t.feld.addEventListener("click",function(){input.focus()});
input.addEventListener("keyup",function(e){
if (q.aktivesQuiz === t && !t.solved && t.gestartet) {
var str=this.value;
t.auswerten(str.charCodeAt(str.length - 1));
this.value="";
}
});
if (t.erkannteWoerter.length < t.daten.length) {
// Statusbild einfügen
t.feld.appendChild(q.domCreate({
tagName : "p",
className : "statusbild"
}));
t.feld.lastChild.appendChild(q.domCreate({
tagName : "img",
src : q.baseURL + "images/" + t.bilder[t.bilder.length - 1 - t.versuche]
}));
// Eingabehinweis
t.feld.appendChild(q.domCreate({
tagName : "p",
className : "eingabehinweis",
// Anzeigen des verdeckten <span>-Elementes bei Hover (für IE notwendig)
onmouseover : function () {
this.childNodes[0].style.display = "block";
},
// Verbergen des verdeckten <span>-Elementes beim Verlassen
onmouseout : function () {
this.childNodes[0].style.display = "";
}
}));
t.feld.lastChild.appendChild(q.domCreate({
tagName : "span",
text : q.meldungen[t.sprache].eingabehinweis_buchstabenraten
}));
// Leerfelder für das zu erratende Wort aufbauen
t.feld.appendChild(q.domCreate({
tagName : "ul",
className : "ratewort",
wort : t.daten[t.erkannteWoerter.length].wort
}));
q.each(t.daten[t.erkannteWoerter.length].wort.split(""), function (c) {
t.feld.lastChild.appendChild(q.domCreate({
tagName : "li",
text: String.fromCharCode(160),
buchstabe : q.wandleZeichen(c)
}));
});
}
// Liste bereits gefundener Wörter erstellen
platzhalter = 0;
q.each(t.daten, function (d) {
if (platzhalter < d.wort.length) {
platzhalter = d.wort.length;
}
});
platzhalter = new Array(platzhalter +3).join("_");
t.feld.appendChild(q.domCreate({
tagName : "div",
className : "erkannte-woerter"
}));
t.feld.lastChild.appendChild(q.domCreate({
tagName : "p",
text: q.meldungen[t.sprache].erkannteWoerter
}));
t.feld.lastChild.appendChild(q.domCreate({
tagName : "ol"
}));
for (i = 0; i < t.daten.length; i++) {
t.feld.lastChild.lastChild.appendChild(q.domCreate({
tagName : "li",
className : t.erkannteWoerter[i] ? "erkannt" : "",
text : t.erkannteWoerter[i] ?
t.erkannteWoerter[i].wortOriginal : platzhalter
}));
}
if (t.erkannteWoerter.length < t.daten.length) {
// Liste bereits geratener Buchstaben erstellen
t.feld.appendChild(q.domCreate({
tagName : "div",
className : "geratene-buchstaben"
}));
t.feld.lastChild.appendChild(q.domCreate({
tagName : "p",
text: q.meldungen[t.sprache].gerateneBuchstaben
}));
t.feld.lastChild.appendChild(q.domCreate({
tagName : "ul"
}));
// Tastatureingabe einschalten
t.gestartet = true;
} else {
// Quiz schon zu ende gespielt?
t.beenden();
}
},
// Meldung zu Spielende ausgeben + Neustart-Button
beenden : function () {
var t = this;
// erneutes Spiel anbieten
t.feld.appendChild(t.startLink);
t.startLink.firstChild.data = q.meldungen[t.sprache].erneut;
t.solved = true;
t.element.className += " "+q.fertigClass;
},
// Quiz initialisieren
init : function () {
var t = this;
// ID für das umgebende DIV-Element vergeben
t.element.id = t.name;
// Start-Link erzeugen
t.startLink = q.domCreate({
tagName : "p",
className : "start-link",
text : q.meldungen[t.sprache].quizStarten,
onclick : function () {
t.solved = false;
t.element.className = t.element.className.replace(
new RegExp(" ?" + q.fertigClass), ""
);
t.daten.shuffle();
t.versuche = 0;
t.erkannteWoerter = new Array();
t.wortAbfragen();
}
});
t.feld.appendChild(t.startLink);
}
};
// 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) {
return false;
}
// Daten sind also vorhanden? -> Auswerten
q.each(tabelle[0].rows, function (tr) {
var gefunden;
if (tr.cells.length > 0) {
// "Müll" entfernen
gefunden = tr.cells[0].innerHTML.replace(
/<\/?[^>]+>/g, ""
).replace(
/&/g, "&"
).replace(
/ /g, " "
).replace(
/ /g, "_"
).quizTrim();
if (gefunden != "") {
quiz.daten.push({
// Lösungswort in reine Großbuchstaben umwandeln
wort : q.wandleZeichen(gefunden).toUpperCase(),
wortOriginal : gefunden,
x : -1,
y : -1
});
}
}
});
// Keine brauchbare Daten? -> Verwerfen!
if (quiz.daten.length < 1) {
return false;
}
// originale Tabelle entfernen
tabelle[0].parentNode.removeChild(tabelle[0]);
// "Spielfeld" erstellen und ins Dokument schreiben
quiz.feld = q.domCreate({ tagName : "div" });
quiz.element.appendChild(quiz.feld);
// Quiz in die Liste aufnehmen und initialisieren
q.alleQuizze[quiz.name] = quiz;
quiz.element.quiz = quiz;
quiz.init();
return true;
},
/*
==================
weitere Funktionen
==================
*/
// Zeichen in eintragbare Buchstaben umwandeln: "s" ist ein String
wandleZeichen : function (s) {
var q = this,
r = "",
z, i, j;
for (i = 0; i < s.length; i++) {
if (s[i] == String.fromCharCode(160) || s[i] == String.fromCharCode(32)) {
r += String.fromCharCode(160);
} else {
for (z in q.codeTabelle) {
if (z.match(/^[A-Z][A-Z]?$/)) {
for (j = 0; j < q.codeTabelle[z].length; j++) {
if (s.substr(i, 1) == q.codeTabelle[z][j]) {
r += z;
}
}
}
}
}
}
return r;
},
initQuizze : function () {
var q = this;
// deutsche Sprachausgabe als Default
if (!q.meldungen) {
q.meldungen = {};
}
if (!q.meldungen.de) {
// Voreinstellungen für Mehrsprachigkeit
q.meldungen.de = {
pruefen : 'prüfen!',
lob1 : 'Ausgezeichnet!',
lob2 : 'Gut gemacht!',
lob3 : 'Das war nicht schlecht!',
ergebnis1 : 'Die Aufgabe wurde gleich beim ersten Versuch erfolgreich gelöst!',
ergebnis2 : 'Die Aufgabe wurde nach nur zwei Versuchen erfolgreich gelöst!',
ergebnis3 : 'Die Aufgabe wurde nach %n Versuchen erfolgreich gelöst!',
alleGefunden : 'Alle Sets gefunden!', // memo-quiz - Es können auch Triplets, Quartette und mehr gefunden werden müssen
erneut : 'Wie wär\'s mit einer neuen Runde?',
ergebnisProzent : 'Die Antworten sind zu %n% richtig.', // Multiple-Choice-Quiz
senkrecht : 'Senkrecht', // Kreuzworträtsel
waagrecht : 'Waagrecht',
eingabehinweis : 'Klicken Sie auf ein gr\u00fcnes Feld, um einen Buchstaben einzugeben!',
eingabehinweis_buchstabenraten : 'Benutzen Sie die Tastatur zur Eingabe! Eventuell m\u00fcssen Sie erst in das Quiz klicken, um es zu aktivieren.'
};
}
// prüfen, ob Code-Tabelle für UTF-8-Normalisierung und Mehrsprachenunterstützung geladen wurden
if (!q.codeTabelle || !q.meldungen.en || !q.domSelect) {
window.setTimeout(q.initQuizze, 100);
return false;
}
// Initialisierung der Quizze
var quizBereiche = new Array(),
muster = new RegExp(q.triggerClass),
i, j, a, gefunden, typ, ok, css;
// Alle DIVs daraufhin überprüfen, ob sie eine CSS-Klasse haben, die auf ein Quiz schließen lässt
q.each(q.domSelect("div"), function (d) {
if (d.className && d.className.match(muster)) {
quizBereiche.push(d);
}
});
// Alle Quiz-Bereiche gefunden -> Initialisieren
if (quizBereiche.length > 0) {
q.each(quizBereiche, function (d) {
var typ = d.className.replace(/([^ ,]+)-quiz/, "$1"),
gefunden, ok; // Initialisierung ok?
if (typeof(q[typ + "Quiz"]) == "function") {
ok = q[typ + "Quiz"](d); // entsprechende Quiz-Funktion zum Erstellen aufrufen
}
// Initialisierung OK? -> Warnungen entfernen
if (ok) {
q.each(q.domSelect(".js-hinweis", d), function (j) {
j.parentNode.removeChild(j);
});
}
});
}
// Wenn mindestens ein Quiz initialisiert wurde, dann Seite "bestücken".
if (q.alleQuizze.quiz0) {
// CSS für Quizbereiche einbinden
q.domSelect("head")[0].appendChild(
q.domCreate({
tagName : "link",
rel : "stylesheet",
type : "text/css",
media : "screen, projection",
href : q.baseURL + "css/quiz.css"
})
);
// Print-CSS für Quizbereiche einbinden
q.domSelect("head")[0].appendChild(
q.domCreate({
tagName : "link",
rel : "stylesheet",
type : "text/css",
media : "print",
href : q.baseURL + "css/quiz-print.css"
})
);
// IE-spezifische Stylesheets einbinden
/*@cc_on
@if (@_jscript_version == 5.6)
// zusätzliches Stylesheet für IE6 einbinden
q.domSelect("head")[0].appendChild(
q.domCreate({
tagName : "link",
rel : "stylesheet",
type : "text/css",
media : "screen, projection",
href : q.baseURL + "css/quiz-ie6.css"
})
);
@end
@if (@_jscript_version == 5.7)
// zusätzliches Stylesheet für IE7 einbinden
q.domSelect("head")[0].appendChild(
q.domCreate({
tagName : "link",
rel : "stylesheet",
type : "text/css",
media : "screen, projection",
href : q.baseURL + "css/quiz-ie7.css"
})
);
@end
@*/
// Links innerhalb eines Quizzes solange deaktivieren, bis es gelöst ist:
q.each(q.alleQuizze, function (a) {
if (a.felder) {
q.each(a.felder, function (f) {
gefunden = [];
if (f.getElementsByTagName) {
gefunden = f.getElementsByTagName("a");
}
if (f.element && f.element.getElementsByTagName) {
gefunden = f.element.getElementsByTagName("a");
}
q.each(gefunden, function (g) {
g.quiz = a;
g.oldOnClick = g.onclick;
g.onclick = q.linkOnClick; // neue onclick-Funktion, die Klicks blocken kann
});
});
}
// onclick-EventHandler für jedes <div> eines Quizzes setzen
if (typeof a.element.onclick == "function") {
a.element.oldOnClick = a.element.onclick;
}
a.element.onclick = function (e) {
q.aktivesQuiz = this.quiz;
if (typeof this.oldOnClick == "function") {
this.oldOnClick(e);
}
return true;
};
});
}
},
// neue onclick-Funktion für Links
linkOnClick : function (e) {
if (this.quiz.typ == "Multiple Choice - Quiz"
|| this.quiz.typ == "Buchstabenraten-Quiz"
|| this.quiz.solved
) {
if (typeof this.oldOnClick == "function") {
this.oldOnClick(e);
}
return true;
}
return false;
},
/* Funktionen für Drag&Drop-Mechanismus */
eventElement : function (e) {
// ermittle aktuelles Element unter dem Mauszeiger
e = e || window.event;
if (e.touches) {
var changedTouch = e.touches[0];
return document.elementFromPoint(changedTouch.clientX, changedTouch.clientY);
}
return e.target || e.srcElement; // W3C DOM <-> IE
},
auswahl : function (element, ziel) {
if (!Quiz.baseURL)
Quiz.init();
if (ziel) {
// Drag&Drop hat stattgefunden!
Quiz.aktivesQuiz.dragNDropAuswerten(element, ziel);
}
// User-Eingabe war "nur ein Klick"...
return false;
},
startDrag : function (e) {
var q = Quiz,
muster = new RegExp("(^|\\s)" + q.draggableClass + "(\\s|$)"),
test;
q.dragElm = q.eventElement(e);
test = q.dragElm;
/* Nur bei Klick auf ein entsprechend ausgezeichnetes Element
(oder eines seiner Nachfahren-Elemente) Drag&Drop-Verhalten zeigen! */
while (test != document.body
&& (!test.className
|| !test.className.match(muster)
)) {
test = test.parentNode;
}
if (test != document.body && test.className.match(muster)) {
q.dragElm = test;
q.dragMode = true;
q.dragElm.className = q.dragElm.className.replace(
new RegExp(q.draggedClass, "g"),
""
).trim();
q.dragElm.className += " " + q.draggedClass;
e.preventDefault();
// aktives Quiz eintragen
q.aktivesQuiz = q.alleQuizze[q.dragElm.id.replace(/_.+/, "")];
}
return !q.dragMode;
},
touchStart : function (e) {
var left = e.touches[0].clientX;
var top = e.touches[0].clientY;
Quiz.lastCoords.left = left;
Quiz.lastCoords.top = top;
},
whileMove : function (e) {
var q = Quiz;
var left = e.clientX;
var top = e.clientY;
if(e.touches) {
left = e.touches[0].clientX;
top = e.touches[0].clientY;
}
dx = q.lastCoords.left - left;
dy = q.lastCoords.top - top;
// Mauskoordinaten speichern
q.lastCoords.left = left;
q.lastCoords.top = top;
// falls gerade kein Element gezogen wird, hier beenden
if (!q.dragElm || !q.dragMode) {
return true;
}
// zu ziehendes Element bewegen
q.dragElm.style.visibility='';
q.dragElm.style.position='relative';
q.dragged = true;
e.preventDefault();
// Abstand zu den letzten Mauskoordinaten berechnen
var lastLeft=0;
var lastTop=0;
if(q.dragElm.style.left) {
lastLeft = parseFloat(q.dragElm.style.left);
lastTop = parseFloat(q.dragElm.style.top);
}
q.dragElm.style.left = lastLeft - dx + "px";
q.dragElm.style.top = lastTop - dy + "px";
q.highlightTarget();
return true;
},
highlightTarget : function () {
var q = Quiz;
var rectDrag=q.dragElm.getBoundingClientRect();
var elements=q.aktivesQuiz.element.getElementsByClassName(q.aktivesQuiz.loesungsClass);
q.highlightElm=null;
q.each(elements,function(element){
var rect=element.getBoundingClientRect();
element.className = element.className.replace(q.highlightClass,"").trim();
if(rect.top<q.lastCoords.top &&
rect.left<q.lastCoords.left &&
rect.bottom>q.lastCoords.top &&
rect.right>q.lastCoords.left){
element.className += " "+q.highlightClass;
q.highlightElm=element;
}
});
},
stopDrag : function (e) {
var q = Quiz,
returnVal;
if (!q.dragElm || !q.dragElm.className) {
return false;
}
// Anti-Markier-Effekt in IE beenden
q.antiMarkierungsModusFuerIE();
if (q.dragged) {
// eventuelle aktive Eingabefelder deaktivieren - aber nur wenn Drag&Drop stattgefunden hat!
q.each(q.domSelect("input"), function (i) {
try { i.blur(); }
catch (e) { }
try { i.onblur(); }
catch (e) { }
});
}
// bewegtes Element wieder eingliedern
q.dragElm.className = q.dragElm.className.replace(
new RegExp(q.draggedClass, "g"),
""
).trim();
// Sichtbarkeit wurde nur verändert, wenn das Element wirklich gezogen wurde...
if (q.dragged) {
q.dragElm.style.visibility = q.dragElmOldVisibility;
q.dragElmOldVisibility = "";
}
// Position (nur!) bei Feldern wieder zurückstellen
if (q.dragElm.className.match(new RegExp("(^|\\s)" + q.feldClass + "(\\s|$)"))
&& q.dragged
) {
q.dragElm.style.top = "";
q.dragElm.style.left = "";
}
// Rückgabewert bereitstellen
returnVal = q.dragged ?
// für Drag&Drop
q.auswahl(q.dragElm, q.highlightElm) :
// für einen simplen Klick (zweiter Parameter false!)
q.auswahl(q.dragElm, false);
// Variablen wieder löschen
q.dragElm = null;
q.dragged = false;
q.dragMode = false;
// gehighlightetes Element wieder abstellen
if (q.highlightElm) {
q.highlightElm.className = q.highlightElm.className.replace(
new RegExp(" ?" + q.highlightClass), ""
);
q.highlightElm = null;
}
return returnVal;
},
einBlender : function (e) {
var q = Quiz;
if (q.dragElm) {
q.dragElm.style.visibility = q.dragElmOldVisibility;
}
return true;
},
antiMarkierungsModusFuerIE : function (schalter) {
var q = this;
if (schalter) {
// Anti-Markierungs-Effekt für IE einschalten
q.oldDocOnSelectStart = document.onselectstart;
q.oldDocOnDragStart = document.ondragstart;
document.onselectstart = function () { return false;};
document.ondragstart = function () { return false;};
} else {
// Anti-Markier-Effekt für IE beenden
if (q.oldDocOnSelectStart
|| typeof(document.onselectstart) == "function"
) {
document.onselectstart = q.oldDocOnSelectStart;
}
if (q.oldDocOnDragStart
|| typeof(document.ondragstart) == "function"
) {
document.ondragstart = q.oldDocOnDragStart;
}
}
}
};
/*!
* Sizzle CSS Selector Engine
* Copyright 2011, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
* More information: http://sizzlejs.com/
*/
(function(){
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
expando = "sizcache" + (Math.random() + '').replace('.', ''),
done = 0,
toString = Object.prototype.toString,
hasDuplicate = false,
baseHasDuplicate = true,
rBackslash = /\\/g,
rReturn = /\r\n/g,
rNonWord = /\W/;
// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
// Thus far that includes Google Chrome.
[0, 0].sort(function() {
baseHasDuplicate = false;
return 0;
});
var Sizzle = function( selector, context, results, seed ) {
results = results || [];
context = context || document;
var origContext = context;
if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
return [];
}
if ( !selector || typeof selector !== "string" ) {
return results;
}
var m, set, checkSet, extra, ret, cur, pop, i,
prune = true,
contextXML = Sizzle.isXML( context ),
parts = [],
soFar = selector;
// Reset the position of the chunker regexp (start from head)
do {
chunker.exec( "" );
m = chunker.exec( soFar );
if ( m ) {
soFar = m[3];
parts.push( m[1] );
if ( m[2] ) {
extra = m[3];
break;
}
}
} while ( m );
if ( parts.length > 1 && origPOS.exec( selector ) ) {
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
set = posProcess( parts[0] + parts[1], context, seed );
} else {
set = Expr.relative[ parts[0] ] ?
[ context ] :
Sizzle( parts.shift(), context );
while ( parts.length ) {
selector = parts.shift();
if ( Expr.relative[ selector ] ) {
selector += parts.shift();
}
set = posProcess( selector, set, seed );
}
}
} else {
// Take a shortcut and set the context if the root selector is an ID
// (but not if it'll be faster if the inner selector is an ID)
if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
ret = Sizzle.find( parts.shift(), context, contextXML );
context = ret.expr ?
Sizzle.filter( ret.expr, ret.set )[0] :
ret.set[0];
}
if ( context ) {
ret = seed ?
{ expr: parts.pop(), set: makeArray(seed) } :
Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
set = ret.expr ?
Sizzle.filter( ret.expr, ret.set ) :
ret.set;
if ( parts.length > 0 ) {
checkSet = makeArray( set );
} else {
prune = false;
}
while ( parts.length ) {
cur = parts.pop();
pop = cur;
if ( !Expr.relative[ cur ] ) {
cur = "";
} else {
pop = parts.pop();
}
if ( pop == null ) {
pop = context;
}
Expr.relative[ cur ]( checkSet, pop, contextXML );
}
} else {
checkSet = parts = [];
}
}
if ( !checkSet ) {
checkSet = set;
}
if ( !checkSet ) {
Sizzle.error( cur || selector );
}
if ( toString.call(checkSet) === "[object Array]" ) {
if ( !prune ) {
results.push.apply( results, checkSet );
} else if ( context && context.nodeType === 1 ) {
for ( i = 0; checkSet[i] != null; i++ ) {
if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
results.push( set[i] );
}
}
} else {
for ( i = 0; checkSet[i] != null; i++ ) {
if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
results.push( set[i] );
}
}
}
} else {
makeArray( checkSet, results );
}
if ( extra ) {
Sizzle( extra, origContext, results, seed );
Sizzle.uniqueSort( results );
}
return results;
};
Sizzle.uniqueSort = function( results ) {
if ( sortOrder ) {
hasDuplicate = baseHasDuplicate;
results.sort( sortOrder );
if ( hasDuplicate ) {
for ( var i = 1; i < results.length; i++ ) {
if ( results[i] === results[ i - 1 ] ) {
results.splice( i--, 1 );
}
}
}
}
return results;
};
Sizzle.matches = function( expr, set ) {
return Sizzle( expr, null, null, set );
};
Sizzle.matchesSelector = function( node, expr ) {
return Sizzle( expr, null, null, [node] ).length > 0;
};
Sizzle.find = function( expr, context, isXML ) {
var set, i, len, match, type, left;
if ( !expr ) {
return [];
}
for ( i = 0, len = Expr.order.length; i < len; i++ ) {
type = Expr.order[i];
if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
left = match[1];
match.splice( 1, 1 );
if ( left.substr( left.length - 1 ) !== "\\" ) {
match[1] = (match[1] || "").replace( rBackslash, "" );
set = Expr.find[ type ]( match, context, isXML );
if ( set != null ) {
expr = expr.replace( Expr.match[ type ], "" );
break;
}
}
}
}
if ( !set ) {
set = typeof context.getElementsByTagName !== "undefined" ?
context.getElementsByTagName( "*" ) :
[];
}
return { set: set, expr: expr };
};
Sizzle.filter = function( expr, set, inplace, not ) {
var match, anyFound,
type, found, item, filter, left,
i, pass,
old = expr,
result = [],
curLoop = set,
isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
while ( expr && set.length ) {
for ( type in Expr.filter ) {
if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
filter = Expr.filter[ type ];
left = match[1];
anyFound = false;
match.splice(1,1);
if ( left.substr( left.length - 1 ) === "\\" ) {
continue;
}
if ( curLoop === result ) {
result = [];
}
if ( Expr.preFilter[ type ] ) {
match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
if ( !match ) {
anyFound = found = true;
} else if ( match === true ) {
continue;
}
}
if ( match ) {
for ( i = 0; (item = curLoop[i]) != null; i++ ) {
if ( item ) {
found = filter( item, match, i, curLoop );
pass = not ^ found;
if ( inplace && found != null ) {
if ( pass ) {
anyFound = true;
} else {
curLoop[i] = false;
}
} else if ( pass ) {
result.push( item );
anyFound = true;
}
}
}
}
if ( found !== undefined ) {
if ( !inplace ) {
curLoop = result;
}
expr = expr.replace( Expr.match[ type ], "" );
if ( !anyFound ) {
return [];
}
break;
}
}
}
// Improper expression
if ( expr === old ) {
if ( anyFound == null ) {
Sizzle.error( expr );
} else {
break;
}
}
old = expr;
}
return curLoop;
};
Sizzle.error = function( msg ) {
throw new Error( "Syntax error, unrecognized expression: " + msg );
};
/**
* Utility function for retreiving the text value of an array of DOM nodes
* @param {Array|Element} elem
*/
var getText = Sizzle.getText = function( elem ) {
var i, node,
nodeType = elem.nodeType,
ret = "";
if ( nodeType ) {
if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
// Use textContent || innerText for elements
if ( typeof elem.textContent === 'string' ) {
return elem.textContent;
} else if ( typeof elem.innerText === 'string' ) {
// Replace IE's carriage returns
return elem.innerText.replace( rReturn, '' );
} else {
// Traverse it's children
for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
ret += getText( elem );
}
}
} else if ( nodeType === 3 || nodeType === 4 ) {
return elem.nodeValue;
}
} else {
// If no nodeType, this is expected to be an array
for ( i = 0; (node = elem[i]); i++ ) {
// Do not traverse comment nodes
if ( node.nodeType !== 8 ) {
ret += getText( node );
}
}
}
return ret;
};
var Expr = Sizzle.selectors = {
order: [ "ID", "NAME", "TAG" ],
match: {
ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
},
leftMatch: {},
attrMap: {
"class": "className",
"for": "htmlFor"
},
attrHandle: {
href: function( elem ) {
return elem.getAttribute( "href" );
},
type: function( elem ) {
return elem.getAttribute( "type" );
}
},
relative: {
"+": function(checkSet, part){
var isPartStr = typeof part === "string",
isTag = isPartStr && !rNonWord.test( part ),
isPartStrNotTag = isPartStr && !isTag;
if ( isTag ) {
part = part.toLowerCase();
}
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
if ( (elem = checkSet[i]) ) {
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
elem || false :
elem === part;
}
}
if ( isPartStrNotTag ) {
Sizzle.filter( part, checkSet, true );
}
},
">": function( checkSet, part ) {
var elem,
isPartStr = typeof part === "string",
i = 0,
l = checkSet.length;
if ( isPartStr && !rNonWord.test( part ) ) {
part = part.toLowerCase();
for ( ; i < l; i++ ) {
elem = checkSet[i];
if ( elem ) {
var parent = elem.parentNode;
checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
}
}
} else {
for ( ; i < l; i++ ) {
elem = checkSet[i];
if ( elem ) {
checkSet[i] = isPartStr ?
elem.parentNode :
elem.parentNode === part;
}
}
if ( isPartStr ) {
Sizzle.filter( part, checkSet, true );
}
}
},
"": function(checkSet, part, isXML){
var nodeCheck,
doneName = done++,
checkFn = dirCheck;
if ( typeof part === "string" && !rNonWord.test( part ) ) {
part = part.toLowerCase();
nodeCheck = part;
checkFn = dirNodeCheck;
}
checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
},
"~": function( checkSet, part, isXML ) {
var nodeCheck,
doneName = done++,
checkFn = dirCheck;
if ( typeof part === "string" && !rNonWord.test( part ) ) {
part = part.toLowerCase();
nodeCheck = part;
checkFn = dirNodeCheck;
}
checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
}
},
find: {
ID: function( match, context, isXML ) {
if ( typeof context.getElementById !== "undefined" && !isXML ) {
var m = context.getElementById(match[1]);
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
return m && m.parentNode ? [m] : [];
}
},
NAME: function( match, context ) {
if ( typeof context.getElementsByName !== "undefined" ) {
var ret = [],
results = context.getElementsByName( match[1] );
for ( var i = 0, l = results.length; i < l; i++ ) {
if ( results[i].getAttribute("name") === match[1] ) {
ret.push( results[i] );
}
}
return ret.length === 0 ? null : ret;
}
},
TAG: function( match, context ) {
if ( typeof context.getElementsByTagName !== "undefined" ) {
return context.getElementsByTagName( match[1] );
}
}
},
preFilter: {
CLASS: function( match, curLoop, inplace, result, not, isXML ) {
match = " " + match[1].replace( rBackslash, "" ) + " ";
if ( isXML ) {
return match;
}
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
if ( elem ) {
if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
if ( !inplace ) {
result.push( elem );
}
} else if ( inplace ) {
curLoop[i] = false;
}
}
}
return false;
},
ID: function( match ) {
return match[1].replace( rBackslash, "" );
},
TAG: function( match, curLoop ) {
return match[1].replace( rBackslash, "" ).toLowerCase();
},
CHILD: function( match ) {
if ( match[1] === "nth" ) {
if ( !match[2] ) {
Sizzle.error( match[0] );
}
match[2] = match[2].replace(/^\+|\s*/g, '');
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
// calculate the numbers (first)n+(last) including if they are negative
match[2] = (test[1] + (test[2] || 1)) - 0;
match[3] = test[3] - 0;
}
else if ( match[2] ) {
Sizzle.error( match[0] );
}
// TODO: Move to normal caching system
match[0] = done++;
return match;
},
ATTR: function( match, curLoop, inplace, result, not, isXML ) {
var name = match[1] = match[1].replace( rBackslash, "" );
if ( !isXML && Expr.attrMap[name] ) {
match[1] = Expr.attrMap[name];
}
// Handle if an un-quoted value was used
match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
if ( match[2] === "~=" ) {
match[4] = " " + match[4] + " ";
}
return match;
},
PSEUDO: function( match, curLoop, inplace, result, not ) {
if ( match[1] === "not" ) {
// If we're dealing with a complex expression, or a simple one
if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
match[3] = Sizzle(match[3], null, null, curLoop);
} else {
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
if ( !inplace ) {
result.push.apply( result, ret );
}
return false;
}
} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
return true;
}
return match;
},
POS: function( match ) {
match.unshift( true );
return match;
}
},
filters: {
enabled: function( elem ) {
return elem.disabled === false && elem.type !== "hidden";
},
disabled: function( elem ) {
return elem.disabled === true;
},
checked: function( elem ) {
return elem.checked === true;
},
selected: function( elem ) {
// Accessing this property makes selected-by-default
// options in Safari work properly
if ( elem.parentNode ) {
elem.parentNode.selectedIndex;
}
return elem.selected === true;
},
parent: function( elem ) {
return !!elem.firstChild;
},
empty: function( elem ) {
return !elem.firstChild;
},
has: function( elem, i, match ) {
return !!Sizzle( match[3], elem ).length;
},
header: function( elem ) {
return (/h\d/i).test( elem.nodeName );
},
text: function( elem ) {
var attr = elem.getAttribute( "type" ), type = elem.type;
// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
// use getAttribute instead to test this case
return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
},
radio: function( elem ) {
return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
},
checkbox: function( elem ) {
return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
},
file: function( elem ) {
return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
},
password: function( elem ) {
return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
},
submit: function( elem ) {
var name = elem.nodeName.toLowerCase();
return (name === "input" || name === "button") && "submit" === elem.type;
},
image: function( elem ) {
return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
},
reset: function( elem ) {
var name = elem.nodeName.toLowerCase();
return (name === "input" || name === "button") && "reset" === elem.type;
},
button: function( elem ) {
var name = elem.nodeName.toLowerCase();
return name === "input" && "button" === elem.type || name === "button";
},
input: function( elem ) {
return (/input|select|textarea|button/i).test( elem.nodeName );
},
focus: function( elem ) {
return elem === elem.ownerDocument.activeElement;
}
},
setFilters: {
first: function( elem, i ) {
return i === 0;
},
last: function( elem, i, match, array ) {
return i === array.length - 1;
},
even: function( elem, i ) {
return i % 2 === 0;
},
odd: function( elem, i ) {
return i % 2 === 1;
},
lt: function( elem, i, match ) {
return i < match[3] - 0;
},
gt: function( elem, i, match ) {
return i > match[3] - 0;
},
nth: function( elem, i, match ) {
return match[3] - 0 === i;
},
eq: function( elem, i, match ) {
return match[3] - 0 === i;
}
},
filter: {
PSEUDO: function( elem, match, i, array ) {
var name = match[1],
filter = Expr.filters[ name ];
if ( filter ) {
return filter( elem, i, match, array );
} else if ( name === "contains" ) {
return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
} else if ( name === "not" ) {
var not = match[3];
for ( var j = 0, l = not.length; j < l; j++ ) {
if ( not[j] === elem ) {
return false;
}
}
return true;
} else {
Sizzle.error( name );
}
},
CHILD: function( elem, match ) {
var first, last,
doneName, parent, cache,
count, diff,
type = match[1],
node = elem;
switch ( type ) {
case "only":
case "first":
while ( (node = node.previousSibling) ) {
if ( node.nodeType === 1 ) {
return false;
}
}
if ( type === "first" ) {
return true;
}
node = elem;
/* falls through */
case "last":
while ( (node = node.nextSibling) ) {
if ( node.nodeType === 1 ) {
return false;
}
}
return true;
case "nth":
first = match[2];
last = match[3];
if ( first === 1 && last === 0 ) {
return true;
}
doneName = match[0];
parent = elem.parentNode;
if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
count = 0;
for ( node = parent.firstChild; node; node = node.nextSibling ) {
if ( node.nodeType === 1 ) {
node.nodeIndex = ++count;
}
}
parent[ expando ] = doneName;
}
diff = elem.nodeIndex - last;
if ( first === 0 ) {
return diff === 0;
} else {
return ( diff % first === 0 && diff / first >= 0 );
}
}
},
ID: function( elem, match ) {
return elem.nodeType === 1 && elem.getAttribute("id") === match;
},
TAG: function( elem, match ) {
return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
},
CLASS: function( elem, match ) {
return (" " + (elem.className || elem.getAttribute("class")) + " ")
.indexOf( match ) > -1;
},
ATTR: function( elem, match ) {
var name = match[1],
result = Sizzle.attr ?
Sizzle.attr( elem, name ) :
Expr.attrHandle[ name ] ?
Expr.attrHandle[ name ]( elem ) :
elem[ name ] != null ?
elem[ name ] :
elem.getAttribute( name ),
value = result + "",
type = match[2],
check = match[4];
return result == null ?
type === "!=" :
!type && Sizzle.attr ?
result != null :
type === "=" ?
value === check :
type === "*=" ?
value.indexOf(check) >= 0 :
type === "~=" ?
(" " + value + " ").indexOf(check) >= 0 :
!check ?
value && result !== false :
type === "!=" ?
value !== check :
type === "^=" ?
value.indexOf(check) === 0 :
type === "$=" ?
value.substr(value.length - check.length) === check :
type === "|=" ?
value === check || value.substr(0, check.length + 1) === check + "-" :
false;
},
POS: function( elem, match, i, array ) {
var name = match[2],
filter = Expr.setFilters[ name ];
if ( filter ) {
return filter( elem, i, match, array );
}
}
}
};
var origPOS = Expr.match.POS,
fescape = function(all, num){
return "\\" + (num - 0 + 1);
};
for ( var type in Expr.match ) {
Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
}
// Expose origPOS
// "global" as in regardless of relation to brackets/parens
Expr.match.globalPOS = origPOS;
var makeArray = function( array, results ) {
array = Array.prototype.slice.call( array, 0 );
if ( results ) {
results.push.apply( results, array );
return results;
}
return array;
};
// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
// Also verifies that the returned array holds DOM nodes
// (which is not the case in the Blackberry browser)
try {
Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
// Provide a fallback method if it does not work
} catch( e ) {
makeArray = function( array, results ) {
var i = 0,
ret = results || [];
if ( toString.call(array) === "[object Array]" ) {
Array.prototype.push.apply( ret, array );
} else {
if ( typeof array.length === "number" ) {
for ( var l = array.length; i < l; i++ ) {
ret.push( array[i] );
}
} else {
for ( ; array[i]; i++ ) {
ret.push( array[i] );
}
}
}
return ret;
};
}
var sortOrder, siblingCheck;
if ( document.documentElement.compareDocumentPosition ) {
sortOrder = function( a, b ) {
if ( a === b ) {
hasDuplicate = true;
return 0;
}
if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
return a.compareDocumentPosition ? -1 : 1;
}
return a.compareDocumentPosition(b) & 4 ? -1 : 1;
};
} else {
sortOrder = function( a, b ) {
// The nodes are identical, we can exit early
if ( a === b ) {
hasDuplicate = true;
return 0;
// Fallback to using sourceIndex (in IE) if it's available on both nodes
} else if ( a.sourceIndex && b.sourceIndex ) {
return a.sourceIndex - b.sourceIndex;
}
var al, bl,
ap = [],
bp = [],
aup = a.parentNode,
bup = b.parentNode,
cur = aup;
// If the nodes are siblings (or identical) we can do a quick check
if ( aup === bup ) {
return siblingCheck( a, b );
// If no parents were found then the nodes are disconnected
} else if ( !aup ) {
return -1;
} else if ( !bup ) {
return 1;
}
// Otherwise they're somewhere else in the tree so we need
// to build up a full list of the parentNodes for comparison
while ( cur ) {
ap.unshift( cur );
cur = cur.parentNode;
}
cur = bup;
while ( cur ) {
bp.unshift( cur );
cur = cur.parentNode;
}
al = ap.length;
bl = bp.length;
// Start walking down the tree looking for a discrepancy
for ( var i = 0; i < al && i < bl; i++ ) {
if ( ap[i] !== bp[i] ) {
return siblingCheck( ap[i], bp[i] );
}
}
// We ended someplace up the tree so do a sibling check
return i === al ?
siblingCheck( a, bp[i], -1 ) :
siblingCheck( ap[i], b, 1 );
};
siblingCheck = function( a, b, ret ) {
if ( a === b ) {
return ret;
}
var cur = a.nextSibling;
while ( cur ) {
if ( cur === b ) {
return -1;
}
cur = cur.nextSibling;
}
return 1;
};
}
// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
// We're going to inject a fake input element with a specified name
var form = document.createElement("div"),
id = "script" + (new Date()).getTime(),
root = document.documentElement;
form.innerHTML = "";
// Inject it into the root element, check its status, and remove it quickly
root.insertBefore( form, root.firstChild );
// The workaround has to do additional checks after a getElementById
// Which slows things down for other browsers (hence the branching)
if ( document.getElementById( id ) ) {
Expr.find.ID = function( match, context, isXML ) {
if ( typeof context.getElementById !== "undefined" && !isXML ) {
var m = context.getElementById(match[1]);
return m ?
m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
[m] :
undefined :
[];
}
};
Expr.filter.ID = function( elem, match ) {
var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
return elem.nodeType === 1 && node && node.nodeValue === match;
};
}
root.removeChild( form );
// release memory in IE
root = form = null;
})();
(function(){
// Check to see if the browser returns only elements
// when doing getElementsByTagName("*")
// Create a fake element
var div = document.createElement("div");
div.appendChild( document.createComment("") );
// Make sure no comments are found
if ( div.getElementsByTagName("*").length > 0 ) {
Expr.find.TAG = function( match, context ) {
var results = context.getElementsByTagName( match[1] );
// Filter out possible comments
if ( match[1] === "*" ) {
var tmp = [];
for ( var i = 0; results[i]; i++ ) {
if ( results[i].nodeType === 1 ) {
tmp.push( results[i] );
}
}
results = tmp;
}
return results;
};
}
// Check to see if an attribute returns normalized href attributes
div.innerHTML = "";
if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
div.firstChild.getAttribute("href") !== "#" ) {
Expr.attrHandle.href = function( elem ) {
return elem.getAttribute( "href", 2 );
};
}
// release memory in IE
div = null;
})();
if ( document.querySelectorAll ) {
(function(){
var oldSizzle = Sizzle,
div = document.createElement("div"),
id = "__sizzle__";
div.innerHTML = "<p class='TEST'></p>";
// Safari can't handle uppercase or unicode characters when
// in quirks mode.
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
return;
}
Sizzle = function( query, context, extra, seed ) {
context = context || document;
// Only use querySelectorAll on non-XML documents
// (ID selectors don't work in non-HTML documents)
if ( !seed && !Sizzle.isXML(context) ) {
// See if we find a selector to speed up
var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
// Speed-up: Sizzle("TAG")
if ( match[1] ) {
return makeArray( context.getElementsByTagName( query ), extra );
// Speed-up: Sizzle(".CLASS")
} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
return makeArray( context.getElementsByClassName( match[2] ), extra );
}
}
if ( context.nodeType === 9 ) {
// Speed-up: Sizzle("body")
// The body element only exists once, optimize finding it
if ( query === "body" && context.body ) {
return makeArray( [ context.body ], extra );
// Speed-up: Sizzle("#ID")
} else if ( match && match[3] ) {
var elem = context.getElementById( match[3] );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id === match[3] ) {
return makeArray( [ elem ], extra );
}
} else {
return makeArray( [], extra );
}
}
try {
return makeArray( context.querySelectorAll(query), extra );
} catch(qsaError) {}
// qSA works strangely on Element-rooted queries
// We can work around this by specifying an extra ID on the root
// and working up from there (Thanks to Andrew Dupont for the technique)
// IE 8 doesn't work on object elements
} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
var oldContext = context,
old = context.getAttribute( "id" ),
nid = old || id,
hasParent = context.parentNode,
relativeHierarchySelector = /^\s*[+~]/.test( query );
if ( !old ) {
context.setAttribute( "id", nid );
} else {
nid = nid.replace( /'/g, "\\$&" );
}
if ( relativeHierarchySelector && hasParent ) {
context = context.parentNode;
}
try {
if ( !relativeHierarchySelector || hasParent ) {
return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
}
} catch(pseudoError) {
} finally {
if ( !old ) {
oldContext.removeAttribute( "id" );
}
}
}
}
return oldSizzle(query, context, extra, seed);
};
for ( var prop in oldSizzle ) {
Sizzle[ prop ] = oldSizzle[ prop ];
}
// release memory in IE
div = null;
})();
}
(function(){
var html = document.documentElement,
matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
if ( matches ) {
// Check to see if it's possible to do matchesSelector
// on a disconnected node (IE 9 fails this)
var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
pseudoWorks = false;
try {
// This should fail with an exception
// Gecko does not error, returns false instead
matches.call( document.documentElement, "[test!='']:sizzle" );
} catch( pseudoError ) {
pseudoWorks = true;
}
Sizzle.matchesSelector = function( node, expr ) {
// Make sure that attribute selectors are quoted
expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
if ( !Sizzle.isXML( node ) ) {
try {
if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
var ret = matches.call( node, expr );
// IE 9's matchesSelector returns false on disconnected nodes
if ( ret || !disconnectedMatch ||
// As well, disconnected nodes are said to be in a document
// fragment in IE 9, so check for that
node.document && node.document.nodeType !== 11 ) {
return ret;
}
}
} catch(e) {}
}
return Sizzle(expr, null, null, [node]).length > 0;
};
}
})();
(function(){
var div = document.createElement("div");
div.innerHTML = "<div class='test e'></div><div class='test'></div>";
// Opera can't find a second classname (in 9.6)
// Also, make sure that getElementsByClassName actually exists
if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
return;
}
// Safari caches class attributes, doesn't catch changes (in 3.2)
div.lastChild.className = "e";
if ( div.getElementsByClassName("e").length === 1 ) {
return;
}
Expr.order.splice(1, 0, "CLASS");
Expr.find.CLASS = function( match, context, isXML ) {
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
return context.getElementsByClassName(match[1]);
}
};
// release memory in IE
div = null;
})();
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
var match = false;
elem = elem[dir];
while ( elem ) {
if ( elem[ expando ] === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 && !isXML ){
elem[ expando ] = doneName;
elem.sizset = i;
}
if ( elem.nodeName.toLowerCase() === cur ) {
match = elem;
break;
}
elem = elem[dir];
}
checkSet[i] = match;
}
}
}
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
var match = false;
elem = elem[dir];
while ( elem ) {
if ( elem[ expando ] === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 ) {
if ( !isXML ) {
elem[ expando ] = doneName;
elem.sizset = i;
}
if ( typeof cur !== "string" ) {
if ( elem === cur ) {
match = true;
break;
}
} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
match = elem;
break;
}
}
elem = elem[dir];
}
checkSet[i] = match;
}
}
}
if ( document.documentElement.contains ) {
Sizzle.contains = function( a, b ) {
return a !== b && (a.contains ? a.contains(b) : true);
};
} else if ( document.documentElement.compareDocumentPosition ) {
Sizzle.contains = function( a, b ) {
return !!(a.compareDocumentPosition(b) & 16);
};
} else {
Sizzle.contains = function() {
return false;
};
}
Sizzle.isXML = function( elem ) {
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
var posProcess = function( selector, context, seed ) {
var match,
tmpSet = [],
later = "",
root = context.nodeType ? [context] : context;
// Position selectors must be done after the filter
// And so must :not(positional) so we move all PSEUDOs to the end
while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
later += match[0];
selector = selector.replace( Expr.match.PSEUDO, "" );
}
selector = Expr.relative[selector] ? selector + "*" : selector;
for ( var i = 0, l = root.length; i < l; i++ ) {
Sizzle( selector, root[i], tmpSet, seed );
}
return Sizzle.filter( later, tmpSet );
};
// EXPOSE
if (!window.Quiz)
window.Quiz = new Object();
window.Quiz.domSelect = Sizzle;
})();
// initialisieren
Quiz.init();