БИЛИМ БУЛАГЫ

MediaWiki

Common.js — различия между версиями

(Содержимое страницы заменено на «/* Размещённый здесь код JavaScript будет загружаться пользователям при обра…»)
Строка 1: Строка 1:
 
/* Размещённый здесь код JavaScript будет загружаться пользователям при обращении к каждой странице */
 
/* Размещённый здесь код JavaScript будет загружаться пользователям при обращении к каждой странице */
/***************************************************
 
* 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(/&nbsp;/, " ").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(
 
/(&nbsp; | &nbsp;)/, " "
 
).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; | &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(/&nbsp;/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
 
/&nbsp;/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(
 
/&amp;/g, "&"
 
).replace(
 
/&nbsp;/g, " "
 
).replace(/ /g, "_");
 
 
gefunden[1] = tr.cells[1].innerHTML.replace(
 
/<\/?[^>]+>/g, ""
 
).replace(
 
/&amp;/g, "&"
 
).replace(/&nbsp;/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(
 
/&amp;/g, "&"
 
).replace(
 
/&nbsp;/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(
 
/&amp;/g, "&"
 
).replace(
 
/&nbsp;/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"
 
})
 
);
 
 
 
// 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();
 

Версия 04:51, 28 сентября 2017

/* Размещённый здесь код JavaScript будет загружаться пользователям при обращении к каждой странице */