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 = {};
}
}
}