Benutzer:V.R.S./catscan.js

aus Wikipedia, der freien Enzyklopädie

Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Strg+F5
// Catscan-Skript für de.wikipedia.org

// Noch längst nicht fertig. Siehe auch [[Benutzer:V.R.S./V.R.Skin#catscan.js]]

// Todo: redundante queries wegoptimieren (per jobqueue?), 'einfaches Schneiden' per API

// http://de.wikipedia.org/w/api.php?action=query&list=categorymembers&cmtitle=Kategorie:Mann&cmdir=asc&cmlimit=500&cmprop=title|sortkey&format=jsonfm
// http://de.wikipedia.org/w/api.php?action=query&titles=Kategorie:Mann&prop=categoryinfo
// http://de.wikipedia.org/w/api.php?action=query&generator=categorymembers&gcmtitle=Kategorie:Mann&gcmprop=title&prop=categories&format=xml

// man verzeihe mir die Benutzung von schicken neuen JS-Features, die wahrscheinlich nie
// im IE auftauchen werden. Liegt an einer Überdosis MDC (http://developer.mozilla.org/).
var Set = {
	// Mengenoperationen (mops)
	// Grundansatz bei allen:
	// 1. Arrays vereinigen und sortieren, sodass gleiche (doppelte) Einträge aufeinander folgen
	// 2. durchloopen, benachbarte Elemente vergleichen und je nach Funktion diese oder jene entfernen
	// geben sortierte Arrays zurück
	intersect : function (cat1, cat2){ // s : schneiden (0(M)0)
		var cat3 = cat1.concat(cat2).sort();
		for (var i = cat3.length -1; i > 0; i--){
			if (cat1[i] !== cat3[i-1]){
				cat3.splice(i--, 1); // nicht doppelt vorhanden, nicht in der Schnittmenge
			}
		}
		return cat3;
	},
	unite : function (cat1, cat2) { // u : vereinigen (M(M)M)
		var cat3 = cat1.concat(cat2).sort();
		for (var i = cat3.length -1; i > 0; i--){
			if (cat3[i] === cat3[i-1]){
				cat3.splice(i, 1); // durch Vereinigung entstandene Doppelungen entfernen
			}
		}
		return cat3;
	},
	substract : function(cat1, cat2){ // d : Differenz (M(0)0)
		var cat3 = cat1.concat(Set.intersect(cat1, cat2)).sort(); // Einträge in [cat2 s cat1] doppeln
		for (var i = cat3.length -1; i > 0; i--){
			if (cat3[i] === cat3[i-1]){
				cat3.splice(--i, 2); // doppelte Einträge raus
			}
		}
		return cat3;
	},
	anti_intrsct : function(cat1, cat2){ // e : symmetrische Differenz (M(0)M)
		var cat3 = cat1.concat(cat2).sort();
		for (var i = cat3.length -1; i > 0; i--){
			if (cat3[i] === cat3[i-1]){
				cat3.splice(--i, 2); // doppelte Einträge raus
			}
		}
		return cat3;
	},
	// nicht direkt eine Mengenoperation
	unique : function(cat1){ // Mehrfacheinträge aus einem Array entfernen
		cat2 = cat1.sort();
		for (var i = cat2.length -1; i > 0;){
			if (cat2[i] === cat1[i-1]){
				cat2.splice(i, 1);
			} else {
				i--; // nix mehr redundant, weitersuchen
			}
		}
		return cat2;
	}
}
// <TODO> AUFRÄUMEN </TODO>
var cs = {
	// eigentliches Catscanscript
	// Ideen: optimieren von mehrfachen queries, Syntaxhighlighting
	conf : {
	// <TODO>
		ids : {
			Target: ,
			CsForm: ,
			Logfield : ,
			Legend :
		},
	// </TODO>
		// für die Verwendung mittels cs.conf.shortcut[kürzel]
		shortcut : { // neue Kürzel können einfach hinzugefügt werden, sollten aber keine Kategoriennamen sein
			s : Set.intersect, // schneide
			v : Set.unite, // vereinige
			d : Set.substract, // subtrahiere
			e : Set.anti_intrsct // symmetrische Differenz
		},
	},
	values : { // Zwischenspeicher für:
		catinfo : {}, // Katinformationen
		cats : {}, // geladene Kategorien
	},
	display : { // Anzeige
		csForm : function(){
	// <TODO>
			// Inputfeld anzeigen, auf Kategorienseite oder allgemein?
			// Inputknopf erzeugen
			// Katleerknopf
			// Feld für Status
			
			// per E4X?
	// </TODO>
		},
		results : function (Articles){
			// Artikelliste in Linkliste umwandeln und auf dem Bildschirm ausgeben
			var artList = document.createElement('ul');
			while(Articles[0]){
				artList.appendChild(
					// E4X: <li><a href={wgServer + '/wiki/' + Articles[0]}>{Articles.shift()}</a></li>
					document.createElement('li').appendChild(
						document.createElement('a')
							.setAttribute('href', wgServer + '/wiki/' + Articles[0])
							.appendChild(document.createTextNode(Articles.shift()))
					)
				);
			}
			// anzeigen <TODO/>
		}
	},
	advanced : {
		init : function (query) {// <TODO> an Ladefunktion anpassen
			// Funktionen geben bei Misserfolg false und eine Fehlermeldung aus
			// den input in upn (umgekehrt polnische Notation) umwandeln
			if (query = cs.anvanced.toUpn(query)){
				// validieren, bei Erfolg wird eine Liste der Kategorien zurückgegeben
				var catlist = cs.anvanced.validate(query);
			}
			if (query && catlist){
				cs.loadCats(
					Set.unique(catlist), // evtl. redundante Elemente entfernen
					function(){ // Kats laden und Ergebnis ausrechnen, wenn sie geladen sind
						cs.display.results( // nimmt ein Ergebnisarray von cs.anvanced.execute und zeigt es als Artikelliste an
							cs.anvanced.execute(query)
						)
					}
				)
			}
		},
		toUpn : function (query) { // [Baum v Notation] in upn umwandeln
		// vorvalidieren und vorbereiten
			// input vorhanden?
			if (!query) return false;
			// überflüssige Leerzeichen entfernen
			query = query.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' ').replace('[ ','[').replace(' ]',']');
			// 3 Argumente bräuchte man schon
			if (query.match(' ').length <= 1){
				cs.misc.println('zu wenige Argumente oder Leerzeichen; abgebrochen.');
				return false;
			}
			// böse Zeichen checken:
			if (query.test(/[.,|&{}]/)){
				cs.misc.println('In dem Ausdruck sind ungültige Zeichen enthalten; abgebrochen.');
				return false;
			}
			// Klammernzahl checken
			var difference = query.match(/\[/).length - query.match(/\]/).length;
			if (!difference) { // unterschiedlich viele Klammern?
				cs.misc.println('Es sind ' + math.abs(difference) + (difference > 0 ? 'öffnende ([)' : 'schließende (])') + ' eckige Klammern zu viel enthalten; abgebrochen.');
				return false;
			}
			// fürs Parsen noch Klammern an die Enden
			query = query.replace(/^/, '[').replace(/$/, ']');
		// umwandeln
			function subStrToUpn (subStr){ // eins v zwei u drei → eins zwei v drei u
				subStr = subStr.split(' ');
				for (var i = subStr.length - 1; i > 1; i -= 2){
					[subStr[i], subStr[i-1]] = [subStr[i-1], subStr[i]]; // i-tes und i-1-tes Element vertauschen, JS 1.7
				}
				// da nach Leerzeichen gesplittet wird wird der Output ab nun als zusammenhängender Text betrachtet
				return subStr.join('|');
			}
			while (
				query !== ( // sobald === gilt, ist nichts mehr zu ersetzen
					query = query.replace(
						/\[[^\[\]]\]/g,
						subStrToUpn
					)
				)
			) {/*nix machen, die Bedingung erledigt die Arbeit*/}
			return query.split('|');
		},
		validate : function (query){ // validiert query, gibt eine Liste der zu ladenden Kategorien zurück
		// nachvalidieren und zu ladende Kats ermitteln
			var catlist = []; // wird später an cs.loadCats verfüttert
			var opcounter = 0;
			for (var j = 0; j < query.length; j++){
				if (opcounter === (
					opcounter += query[j] in cs.conf.shortcut // opcounter um eins erhöhen, wenn query[i] eine mop ist
					)){
					catlist.push(query[j]); // sonst Name zur Katliste hinzufügen
				}
				if (catlist.length <= opcounter){ // stimmt dies an einer Stelle, ist query nicht mehr von execute ausführbar
					cs.misc.println('Zu viele Mengenoperationen; abgebrochen.'); // query[j] in der Fehlermeldung angeben?
					return false;
				}
			}
			if (catlist.length > opcounter + 1){ // Es sollte genau 1 Kat mehr als Anweisungen sein, sonst gehts nicht auf
				cs.misc.println('Zu viele Kategorien; abgebrochen.');
				return false;
			}
			return catlist;
		},
		execute : function (upnQuery){ // führt einen upn-Ausdruck aus
			while(upnQuery.length > 1){ // sobald length == 1 ist, ist nur noch das Array mit der Schnittmenge enthalten
				if (upnQuery[1] in cs.conf.shortcut) { // gilt nur, wenn bereits nach rechts rotiert wurde
					upnQuery.unshift(upn.Query.pop()); // eins nach links rotieren
				}
				while (!(upnQuery[2] in cs.conf.shortcut)){ // Zeichen für mop suchen
					upnQuery.push(upnQuery.shift()); // eins nach rechts rotieren
				}
				upnQuery[0] = cs.conf.shortcut[upnQuery[2]]( // das vormalige upnQuery[2] wird durch das Ergebnis ersetzt
					// Wenn String, dann Katname, wenn Array, dann direkt verfüttern
					typeof upnQuery[0] === 'String' ? cs.values.cats[upnQuery.shift()] : upnQuery.shift(),
					typeof upnQuery[0] === 'String' ? cs.values.cats[upnQuery.shift()] : upnQuery.shift()
				);
			}
			return upnQuery[0];
		}
	},
	simple : {// <TODO> an Ladefunktion anpassen
		init : function (cat1, mop, cat2){
			if (mop in cs.conf.shortcut){ // ist die mop definiert?
				if (cat1 === cat2){ // gleiche Kategorien sollte man nicht schneiden
					cs.misc.println('<a href="http://icanhascheezburger.com/2008/09/01/funny-pictures-catscan/">You can has easter Egg!</a>');
				} else {
				// <TODO/>cs.loadCats([cat1, cat2], function(){
					cs.display.results(
						cs.conf.shortcut[mop](cat1, cat2)
					);
				}
			} else {
				cs.misc.println('ungültige Mengenoperation ' + mop + '; abgebrochen.');
			}
		}
	},
	get : { // Ladefunktionen
	// Kats laden und speichern
		CatInfo : function (cat) {
	// <TODO>
		// http://de.wikipedia.org/w/api.php?action=query&titles=Kategorie:Mann&prop=categoryinfo
	// </TODO>
			return catsizes;
		},
		Cat : function (cat) {
	// <TODO>
			// alert(i); alert(j);
			// Lade Kategorie:cat... 78% fertig (1500/1923 Einträge)
		//http://de.wikipedia.org/w/api.php?action=query&list=categorymembers&cmtitle=Kategorie:Mann&cmdir=asc&cmlimit=500&cmprop=title&format=jsonfm
			// fertig laden, als Array in cs.values.cats[catname] schreiben
			// laden abbrechen, indem contFunc geändert wird
	// </TODO>
			return true; // success
		},
		Cats : function (catlist, whendone){
			catlist = Set.unique(catlist); // -Redundanzen
	// <TODO>
			// Katinfo laden
			// Lade Kategorieninfo... fertig. 
			while(catlist[0]){
				cs.loadCat(catlist.shift[0])
			}
			// return false bei Misserfolg
		}
	// </TODO>
	}, // Katfunktionen
	misc : {
		println : function (msg, spanId){ // Konsole
			if (!spanId){ // normales loggen
				document.getElementById(cs.ids.Logfield).innerHTML += msg + '<br />\n';
			} else { // mit id für spätere Verwendung
				document.getElementById(cs.ids.Logfield).innerHTML += '<span id="' + id + '">' + msg + '</span><br />\n';
			}
		},
		// Aufräumfunktion für den Aufräumknopf
		cleanup : function (){
			cs.values.cats = {};
		}
	}
}