MediaWiki:Skin/Projekt:Adventure2/lib.js: Unterschied zwischen den Versionen

aus Kamelopedia, der wüsten Enzyklopädie
Zur Navigation springen Zur Suche springen
sollte es so gehen, wäre das wohl besser
Keine Bearbeitungszusammenfassung
 
(91 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
// A2lib
// A2lib


a2 = {};
if (window.a2 === undefined)
window.a2 = {};
a2.events = {};
a2.events = {};
a2.virtuals = {};
a2.errorCount = 0;
a2.EVENT_CHAIN_MAX_LENGTH = 20;
a2.eventChain = [];
a2.clearEventChain = function clearEventChain () {
    a2.eventChain = [];
};


a2.clearScope = function clearScope(sc) {
a2.clearScope = function clearScope(sc) {
     delete a2.events[sc];
     delete a2.events[sc];
    delete a2.virtuals[sc];
};
};


a2.registerEventHandler = function registerEventHandler(e) {
a2.registerEventHandler = function registerEventHandler(e) {
     var sc = (e.scope[0] == "page") ? ":page:" : e.scope[1];
     var sc = e.scope;


     if (!a2.events[sc])
     if (!a2.events[sc])
Zeile 19: Zeile 30:
             a2.events[sc][tr] = [];
             a2.events[sc][tr] = [];
      
      
         a2.events[sc][tr].push(function(){
         a2.events[sc][tr].push(function(real){
             a2.log("run", e.name);
             a2.log("run", e.name);
             if (e.condition())
             var cond = e.condition();
                 e.action();
            a2.debugEventInstance(e.scope, e.name, cond);
            if (cond)
                 e.action(real);
         });
         });
     }
     }
};
};


if (window.console && window.console.log)
a2.log = function () {return;};
     a2.log = window.console.log;
if (window.console && window.console.log && window.console.log.apply)
else
     a2.log = function() { console.log.apply(window.console, arguments) };
     a2.log = function () {return;};
 
 
a2.virtualTriggerMap = {
    add: [1],
    remove: [1],
    activate: [1],
    apply: [1,0],
    combine: [1,1],
    enter: [1],
    leave: [1]
}
 
a2.xJoin = function xJoin (z){
    function _xj(arr, vals){
        var ret = [];
        for (var i=0; i<arr.length; i++)
            for (var j=0; j<vals.length; j++)
                ret.push(arr[i].concat(vals[j]));
        return ret;
    }
    var n = [[]];
    for (var i=0; i<z.length; i++)
        n = _xj(n,z[i]);
    return n;
}
 
a2.createVirtualTriggers = function createVirtualTriggers (tr) {
    var b = tr[0];
    return a2.xJoin($.map(tr, function (val, i) {
        if (i>0 && a2.virtualTriggerMap[b] && a2.virtualTriggerMap[b][i-1] && a2.virtuals[val])
            return [[val].concat(a2.virtuals[val])];
        else
            return [[val]];
    }));
}
 
a2.fireEvent = function fireEvent(ev) {
     var triggers = a2.createVirtualTriggers(ev);
    for (var i=0; i<triggers.length; i++)
        a2._fireEvent(triggers[i], ev);
}
 
a2._fireEvent = function _fireEvent (ev, real) {
 
    if (a2.eventChain.length >= a2.EVENT_CHAIN_MAX_LENGTH) {
        a2.debugError("Abbruch: zu viele Folge-Ereignisse.");
        return;
    }
    var evstate = a2.stateEncode() + "|" + ev;
    if (a2.eventChain.indexOf(evstate) > -1) {
        a2.debugError("Abbruch: Ereignis-Rekursion.");
        return;  
    }
    a2.eventChain.push(evstate);
 
    if ( ev[0] == "enter" || ev[0] == "add" || ev[0] == "remove" )
        a2.updateHash()


a2.fireEvent = function fireEvent (event) {
    event = ev.join(".");
     a2.log("Fire", event);
     a2.log("Fire", event, real);
    a2.debugEvent(event);
     var e = a2.events;
     var e = a2.events;
     for(i in e)
     for(var i in e)
       try {
       try {
           for(j=0; j<e[i][event].length; j++){
           for(j=0; e[i][event] !== undefined && j<e[i][event].length; j++){
               a2.log("Event", i, event, j, e[i][event][j]);
               a2.log("Event", i, event, j, e[i][event][j]);
               e[i][event][j]();
               e[i][event][j](real);
           }
           }
       } catch (e) {
       } catch (e) {
Zeile 50: Zeile 120:
     var page = mw.config.get("wgPageName");
     var page = mw.config.get("wgPageName");
     return [script, page, p].join("/");
     return [script, page, p].join("/");
}
a2.updateHash = function updateHash() {
    var hash = "#" + a2.crypt(a2.stateEncode(), true);
    location.hash = hash;
    a2.latestHash = hash;
}
}


a2.loadPage = function loadPage(n){
a2.loadPage = function loadPage(n){
     a2.clearScope(":page:");
     if (isNaN(parseInt(n)) /* || a2.cpage == parseInt(n) */ )
    a2.fireEvent("leave."+a2.cpage);
        return;
     response = $.ajax({
 
 
     var response = $.ajax({
         url: a2.makeUrl(parseInt(n)+"?action=render"),
         url: a2.makeUrl(parseInt(n)+"?action=render"),
         async: false
         async: false
     });
     });
    if (response.status != 200) {
        a2.debugError("Fehler beim Laden von Seite "+n+": "+response.statusText);
        return;
    }
    a2.fireEvent(["leave",a2.cpage]);
    a2.clearScope(":page:");
   
   
     a2.cpage = n;
     a2.cpage = n;
     $content = $(response.responseText)
     a2.debugPage(n);
     $content.append('<scr'+'ipt type="text/javascript">setTimeout(function(){a2.fireEvent("enter."+a2.cpage);}, 100);</scr'+'ipt>');
    var $content = $(response.responseText)
     $content.append('<scr'+'ipt type="text/javascript">setTimeout(function(){a2.fireEvent(["enter",a2.cpage]); $("#a2loader").hide();}, 100);</scr'+'ipt>');
   
   
     $("#a2image").empty().append($content);
     $("#a2image").empty().append($content);
Zeile 68: Zeile 155:


     $("#a2image area").click(function (ev) {
     $("#a2image area").click(function (ev) {
         a2.fireEvent("click."+ev.target.hash.substr(1));
        a2.clearEventChain();
         a2.fireEvent(["click",ev.currentTarget.hash.substr(1)]);
        return false;
    });
 
    $(".overlay").css("cursor","pointer").click(function (ev) {
        a2.clearEventChain();
        a2.fireEvent(["click",ev.currentTarget.id.split("_")[1]]);
        return false;
    });
 
    $("#_l, #_r, #_u, #_d").click(function (ev) {
        a2.clearEventChain();
        a2.fireEvent(["click",ev.currentTarget.id]);
         return false;
         return false;
     });
     });
    $("#a2image area[href='#_L']").css('cursor','url("/images/4/41/Leftarrow.png") 0 15, w-resize');
    $("#a2image area[href='#_R']").css('cursor','url("/images/b/b9/Rightarrow.png") 30 15, e-resize');
    $("#a2image area[href='#_U']").css('cursor','url("/images/3/37/Uparrow.png") 15 0, n-resize');
    $("#a2image area[href='#_D']").css('cursor','url("/images/6/62/Downarrow.png") 15 30, s-resize');


     $("#a2image img").droppable({
     $("#a2image img").droppable({
Zeile 80: Zeile 176:
             var target = a2.ui.getDroparea($(this), ui);
             var target = a2.ui.getDroparea($(this), ui);
             a2.log("drop", target, event, ui);
             a2.log("drop", target, event, ui);
             if (target.length)
             for (var i=0; i<target.length; i++) {
                 a2.fireEvent("apply."+ui.draggable.data("item")+"."+target[0].hash.substr(1));
                a2.clearEventChain();
                 a2.fireEvent(["apply",ui.draggable.data("item"),target[i].hash.substr(1)]);
            }
         }
         }
     });
     });
  $(".overlay").droppable({
        drop: function (event, ui) {
            a2.clearEventChain();
            a2.fireEvent(["apply",ui.draggable.data("item"),this.id.split("_")[1]]);
    }
  });


};
};


a2.util = {
a2.util = {
     print: function (s) {  
     print: function (s, opts) {  
         $("#a2text").text(s);
         $("#a2text").text(s);
        // print options for the ask method
        if(opts) {
            var functionBuilder = function (target) {
                return function () {
                    a2.util.print("");
                    a2.fireEvent(["click", target]);
                };
            };
            var ul = $("<ul/>");
            for(var i=0; i<opts.length; i++) {
                var li = $("<li class='pseudolink'/>");
                li.click(functionBuilder(opts[i][0]));
                li.text(opts[i][1]);
                ul.append(li);
            }
            $("#a2text").append(ul);
        }
     },
     },
     goto: function (p) {
     goto: function (p) {
        // prevent side effects
        a2.timer.clear();
        // this was for old Widgets!
        //$("audio").each(function (a,b) { b.autoplay = false; b.pause(); });
        // stop background noises, keep music
        a2.audio.stop("background");
        // actually go to page
         a2.loadPage(p);
         a2.loadPage(p);
    },
    timeoutIsSet: function () {
        return ! isNaN(a2.timer.pt);
     }
     }
};
};
Zeile 100: Zeile 238:
a2.loadItem = function loadItem(n){
a2.loadItem = function loadItem(n){
     a2.log("load", n);
     a2.log("load", n);
    a2.clearScope(n);
 
     response = $.ajax({
     var response = $.ajax({
         url: a2.makeUrl("item/"+n+"?action=render"),
         url: a2.makeUrl("item/"+n+"?action=render"),
         async: false
         async: false
     });
     });
    if (response.status != 200) {
        a2.debugError("Fehler beim Laden von Item "+n+": "+response.statusText);
        return;
    }
    a2.clearScope(n);
     a2.items[n] = response.responseText;
     a2.items[n] = response.responseText;
     a2.log(a2.items);
     a2.log(a2.items);
     a2.renderItems();
     a2.renderItems();
    a2.fireEvent(["add",n]);
};
};


a2.renderItems = function renderItems(){
a2.renderItems = function renderItems(){
     $("#a2items").empty()
     $("#a2items, #a2pseudoitems").empty()
    a2.debugItems();
     for (var item in a2.items){
     for (var item in a2.items){
         $fl=$('<div style="float:left;" class="a2item" />');
         if (item[0] == "_") {
            // skip "virtual" status items
            $("#a2pseudoitems").append(a2.items[item]);
            continue;
        }
 
        var $flbox=$('<div class="a2itembox" />');
        var $fl=$('<div class="a2item" />');
        $flbox.append($fl);
         $fl.append(a2.items[item]);
         $fl.append(a2.items[item]);
         $("#a2items").append($fl);
         $("#a2items").append($flbox);
         $fl.draggable({
         $fl.draggable({
             // cursorAt: {top: -5, left: -5},
             // cursorAt: {top: -5, left: -5},
Zeile 128: Zeile 284:
         });
         });
         $fl.data("item",item);
         $fl.data("item",item);
         $fl.click(function () {a2.fireEvent("activate."+$(this).data("item"));});
         $fl.click(function () {
            a2.clearEventChain();
            a2.fireEvent(["activate",$(this).data("item")]);
        });
         $fl.droppable({
         $fl.droppable({
             drop: function (event, ui) {
             drop: function (event, ui) {
                 a2.fireEvent("combine."+ui.draggable.data("item")+"."+$(this).data("item"));
                a2.clearEventChain();
                 a2.fireEvent(["combine",ui.draggable.data("item"),$(this).data("item")]);
                 return false;
                 return false;
             }
             }
Zeile 145: Zeile 305:
     delete a2.items[i];  
     delete a2.items[i];  
     delete a2.events[i];
     delete a2.events[i];
    delete a2.virtuals[i];
     a2.renderItems();
     a2.renderItems();
    a2.fireEvent(["remove",i]);
};
};
a2.util.removeAll = function removeAll(v) {
    for (i in a2.virtuals)
        if( a2.virtuals[i].indexOf(v) > -1 ) {
            delete a2.items[i];
            delete a2.events[i];
            delete a2.virtuals[i];
            a2.fireEvent(["remove",i]);
    }
    a2.renderItems();
}
a2.util.hasVirtual = function hasVirtual (v) {
    for (i in a2.virtuals)
        if( a2.virtuals[i].indexOf(v) > -1 )
            return i;
    return false;
}


a2.ui = {};
a2.ui = {};
a2.ui.getAreaBox = function getAreaBox (area) {
a2.ui.getAreaBox = function getAreaBox (area) {
     $area = $(area);
     var $area = $(area);
     shape = $area.attr("shape");
     var shape = $area.attr("shape");
     p = $area.attr("coords");
     var p = $area.attr("coords");
     p = p.split(",")
     p = p.split(",")
     p = $.map(p, function(x){ return parseInt(x);});
     p = $.map(p, function(x){ return parseInt(x);});
Zeile 178: Zeile 358:


a2.ui.getDroparea = function getDroparea (img, ui) {
a2.ui.getDroparea = function getDroparea (img, ui) {
     $areas = $("area");
     var $areas = $("area");
     return $areas.filter(function () {
     return $areas.filter(function () {
         var b = a2.ui.getAreaBox(this);
         var b = a2.ui.getAreaBox(this);
Zeile 194: Zeile 374:
                 dy - s < ym && ym < dy + s);             
                 dy - s < ym && ym < dy + s);             
     });
     });
}
a2.stateEncode = function () {
    var s = String(a2.cpage);
    for (var i in a2.items)
        s+="|"+i;
    return s
}
a2.stateDecode = function (s) {
    a2.clearEventChain();
    var c = s.split("|");
    a2.items = {};
    a2.virtuals = {};
    a2.events = {}
    for (var j=1; j<c.length; j++) {
        a2.items[c[j]] = "<img src='/images/a/a6/A2loading.gif' alt='Loading …' />";
    }
    a2.renderItems();
    for (var j=1; j<c.length; j++)
        a2.loadItem(c[j]);
    a2.loadPage(parseInt(c[0]));
}
a2.crypt = function crypt (str, encode) {
    if (encode){
        var n = Math.floor((Math.random()*9))+1;
        out = String(n);
    } else {
        var n = - parseInt(str.substr(0,1));
        var out = "";
        str = str.substr(1);
    }
    var chain = "pwoTä7eGNVk1SAldv0mJ9zIöPE4x8rF|B6ybüjZDC5cqfRhOXsQY23iUngLWuMHatK";
    var mk = function(i){ return i % chain.length };
    for (var i=0; i<str.length; i++) {
        var c = str.substr(i,1);
        var ind = chain.indexOf(c);
        if (ind == -1)
            out += c;
        else
            out += chain.substr(mk(ind + n),1);
    }
    return out;
}
/* DEBUGGER */
a2.debugEvent = function debugEvent (ev) {
    if (!$("#a2dbgBottom").length)
        return;
    $("#a2dbgEventLog").append($("<li/>").text(ev).append("<ul/>"));
    $("#a2dbgBottom:visible").scrollTop($("#a2dbgBottom")[0].scrollHeight);
}
a2.debugEventInstance = function debugEventInstance (sc,n,cond) {
    if (!$("#a2dbgBottom").length)
        return;
    var classname = cond ? "a2fired" : "a2notfired";
    $("#a2dbgEventLog li ul").last().append($("<li/>").text(sc+"->"+n).addClass(classname));
    $("#a2dbgBottom:visible").scrollTop($("#a2dbgBottom")[0].scrollHeight);
}
a2.debugPage = function debugPage (p) {
  $("#a2dbgGoto").val(p);
}
a2.debugItems = function debugItems() {
  var s = [];
  for (i in a2.items)
      s.push(i);
  $("#a2dbgItems").val(s.join("\n"));
}
a2.debugError = function debugError(text) {
    if (!$("#a2dbgBottom").length)
        return;
    a2.errorCount ++;
    $("#a2errorCount").text(a2.errorCount);
    $("#a2dbgEventLog").append($("<li/>").text(text).addClass("a2error"));
    $("#a2dbgBottom:visible").scrollTop($("#a2dbgBottom")[0].scrollHeight);
}
// provide timer functions
a2.timer = {
    time: 0,
    pt: NaN,
    fn: null,
    set: function set(n, fn) {
   
        if (! isNaN(a2.timer.pt)) {
    // do not set timer if timer already active
            return;
        }
           
        a2.timer.time = n;
        a2.timer.fn = fn;
       
        a2.timer.pt = setInterval(function () {
            a2.timer.time--;
   
            if (a2.timer.time <= 0) {
                clearInterval(a2.timer.pt);
                a2.timer.pt = NaN;
                $("#_t").text("0:00").fadeOut('slow');
                fn();
                return;
            }
       
            var sec = a2.timer.time % 60;
       
            if (sec < 10)
                sec = "0" + sec;
            $("#_t").show().text(String(Math.floor(a2.timer.time / 60)) + ":" + sec );
        }, 1000);
    },
   
    clear: function clear() {
        if (! isNaN(a2.timer.pt)) {
            clearInterval(a2.timer.pt);
            a2.timer.pt = NaN;
            $("#_t").fadeOut();
        }
    }
};
// provide audio functions
a2.audio = {
    cache: {},
    current: [],
    fetch: function fetch(file) {
            var data = $.ajax({
            type: "GET",
            url: "/api.php",
            data: {
                action: "parse",
                format: "xml",
                text: "{{filepath:"+file+"}}"
            },
            async: false
        });
       
        var html = $(data.responseText).find("text").text();
        var url = $(html).find("a")[0].href;
        return url;
    },
    getaudio: function getaudio(file) {
        if (a2.audio.cache[file]) {
            return a2.audio.cache[file];
        } else {
            var url = a2.audio.fetch(file);
            a2.audio.cache[file] = url;
            return url;
        }
    },
    play: function play(channel, file) {
        var $player = $("#a2audio_channel_"+channel)[0];
        var audiofile = a2.audio.getaudio(file);
        if (audiofile != a2.audio.current[channel]) {       
            $player.pause();
            $player.src = a2.audio.getaudio(file);
            $player.load();
            $player.play();
            a2.audio.current[channel] = audiofile;
        }
    },
    stop: function stop(channel) {
        var $player = $("#a2audio_channel_"+channel)[0];
        $player.pause();
        a2.audio.current[channel] = null;
    }
}
}

Aktuelle Version vom 22. Juli 2015, 22:05 Uhr

// A2lib

if (window.a2 === undefined)
	window.a2 = {};
a2.events = {};
a2.virtuals = {};
a2.errorCount = 0;

a2.EVENT_CHAIN_MAX_LENGTH = 20;
a2.eventChain = [];

a2.clearEventChain = function clearEventChain () {
    a2.eventChain = [];
};

a2.clearScope = function clearScope(sc) {
    delete a2.events[sc];
    delete a2.virtuals[sc];
};

a2.registerEventHandler = function registerEventHandler(e) {
    var sc = e.scope;

    if (!a2.events[sc])
        a2.events[sc]={};

    for(var i=0; i<e.trigger.length; i++){
        var tr = e.trigger[i];
        if (!a2.events[sc][tr])
            a2.events[sc][tr] = [];
    
        a2.events[sc][tr].push(function(real){
            a2.log("run", e.name);
            var cond = e.condition();
            a2.debugEventInstance(e.scope, e.name, cond);
            if (cond)
                e.action(real);
        });
    }
};

a2.log = function () {return;};
if (window.console && window.console.log && window.console.log.apply)
    a2.log = function() { console.log.apply(window.console, arguments) };


a2.virtualTriggerMap = {
    add: [1],
    remove: [1],
    activate: [1],
    apply: [1,0],
    combine: [1,1],
    enter: [1],
    leave: [1]
}

a2.xJoin = function xJoin (z){
    function _xj(arr, vals){
        var ret = [];
        for (var i=0; i<arr.length; i++)
            for (var j=0; j<vals.length; j++)
                ret.push(arr[i].concat(vals[j]));
        return ret;
    }
    var n = [[]];
    for (var i=0; i<z.length; i++)
        n = _xj(n,z[i]);
    return n;
}

a2.createVirtualTriggers = function createVirtualTriggers (tr) {
    var b = tr[0];
    return a2.xJoin($.map(tr, function (val, i) {
        if (i>0 && a2.virtualTriggerMap[b] && a2.virtualTriggerMap[b][i-1] && a2.virtuals[val])
            return [[val].concat(a2.virtuals[val])];
        else
            return [[val]];
    }));
}

a2.fireEvent = function fireEvent(ev) {
    var triggers = a2.createVirtualTriggers(ev);
    for (var i=0; i<triggers.length; i++)
        a2._fireEvent(triggers[i], ev);
}

a2._fireEvent = function _fireEvent (ev, real) {

    if (a2.eventChain.length >= a2.EVENT_CHAIN_MAX_LENGTH) {
        a2.debugError("Abbruch: zu viele Folge-Ereignisse.");
        return; 
    } 
    var evstate = a2.stateEncode() + "|" + ev;
    if (a2.eventChain.indexOf(evstate) > -1) {
        a2.debugError("Abbruch: Ereignis-Rekursion.");
        return; 
    }
    a2.eventChain.push(evstate);

    if ( ev[0] == "enter" || ev[0] == "add" || ev[0] == "remove" )
        a2.updateHash()

    event = ev.join(".");
    a2.log("Fire", event, real);
    a2.debugEvent(event);
    var e = a2.events;
    for(var i in e)
       try {
           for(j=0; e[i][event] !== undefined && j<e[i][event].length; j++){
               a2.log("Event", i, event, j, e[i][event][j]);
               e[i][event][j](real);
           }
       } catch (e) {
           a2.log("Event Exception", e);
       }
};

a2.makeUrl = function makeUrl(p){
    var script = mw.config.get("wgScript");
    var page = mw.config.get("wgPageName");
    return [script, page, p].join("/");
}

a2.updateHash = function updateHash() {
    var hash = "#" + a2.crypt(a2.stateEncode(), true);
    location.hash = hash;
    a2.latestHash = hash;
}

a2.loadPage = function loadPage(n){
    if (isNaN(parseInt(n)) /* || a2.cpage == parseInt(n) */ )
        return;


    var response = $.ajax({
        url: a2.makeUrl(parseInt(n)+"?action=render"),
        async: false
    });

    if (response.status != 200) {
        a2.debugError("Fehler beim Laden von Seite "+n+": "+response.statusText);
        return;
    }

    a2.fireEvent(["leave",a2.cpage]);
    a2.clearScope(":page:");
 
    a2.cpage = n;
    a2.debugPage(n);
    var $content = $(response.responseText)
    $content.append('<scr'+'ipt type="text/javascript">setTimeout(function(){a2.fireEvent(["enter",a2.cpage]); $("#a2loader").hide();}, 100);</scr'+'ipt>');
 
    $("#a2image").empty().append($content);
    console.log($("#a2image a"));

    $("#a2image area").click(function (ev) {
        a2.clearEventChain();
        a2.fireEvent(["click",ev.currentTarget.hash.substr(1)]);
        return false;
    });

    $(".overlay").css("cursor","pointer").click(function (ev) {
        a2.clearEventChain();
        a2.fireEvent(["click",ev.currentTarget.id.split("_")[1]]);
        return false;
    });

    $("#_l, #_r, #_u, #_d").click(function (ev) {
        a2.clearEventChain();
        a2.fireEvent(["click",ev.currentTarget.id]);
        return false;
    });

    $("#a2image img").droppable({
        drop: function (event, ui) {
            var target = a2.ui.getDroparea($(this), ui);
            a2.log("drop", target, event, ui);
            for (var i=0; i<target.length; i++) {
                a2.clearEventChain();
                a2.fireEvent(["apply",ui.draggable.data("item"),target[i].hash.substr(1)]);
            }
        }
    });

   $(".overlay").droppable({
        drop: function (event, ui) {
            a2.clearEventChain();
            a2.fireEvent(["apply",ui.draggable.data("item"),this.id.split("_")[1]]);
    }
  });

};

a2.util = {
    print: function (s, opts) { 
        $("#a2text").text(s);

        // print options for the ask method
        if(opts) {
            var functionBuilder = function (target) {
                return function () {
                    a2.util.print("");
                    a2.fireEvent(["click", target]);
                };
            };

            var ul = $("<ul/>");
            for(var i=0; i<opts.length; i++) {
                var li = $("<li class='pseudolink'/>");
                li.click(functionBuilder(opts[i][0]));
                li.text(opts[i][1]);
                ul.append(li);
            }
            $("#a2text").append(ul);
        }
    },
    goto: function (p) {

        // prevent side effects
        a2.timer.clear();

        // this was for old Widgets!
        //$("audio").each(function (a,b) { b.autoplay = false; b.pause(); });

        // stop background noises, keep music
        a2.audio.stop("background");

        // actually go to page
        a2.loadPage(p);
    },
    timeoutIsSet: function () {
        return ! isNaN(a2.timer.pt);
    }
};


a2.items = {};
a2.loadItem = function loadItem(n){
    a2.log("load", n);

    var response = $.ajax({
        url: a2.makeUrl("item/"+n+"?action=render"),
        async: false
    });

    if (response.status != 200) {
        a2.debugError("Fehler beim Laden von Item "+n+": "+response.statusText);
        return;
    }

    a2.clearScope(n);

    a2.items[n] = response.responseText;
    a2.log(a2.items);
    a2.renderItems();
    a2.fireEvent(["add",n]);
};

a2.renderItems = function renderItems(){
    $("#a2items, #a2pseudoitems").empty()
    a2.debugItems();
    for (var item in a2.items){
        if (item[0] == "_") {
            // skip "virtual" status items
            $("#a2pseudoitems").append(a2.items[item]);
            continue;
        }

        var $flbox=$('<div class="a2itembox" />');
        var $fl=$('<div class="a2item" />');
        $flbox.append($fl);
        $fl.append(a2.items[item]);
        $("#a2items").append($flbox);
        $fl.draggable({
            // cursorAt: {top: -5, left: -5},
            revert: true,
            zIndex: 10000,
            start: function(event, ui) {
                ui.helper.bind("click.prevent", function(event) { event.preventDefault(); });
            },
            stop: function(event, ui) {
                setTimeout(function(){ui.helper.unbind("click.prevent");}, 300);
            }
        });
        $fl.data("item",item);
        $fl.click(function () {
            a2.clearEventChain();
            a2.fireEvent(["activate",$(this).data("item")]);
        });
        $fl.droppable({
            drop: function (event, ui) {
                a2.clearEventChain();
                a2.fireEvent(["combine",ui.draggable.data("item"),$(this).data("item")]);
                return false;
            }
        });
        a2.log($("#a2items"))
    }
}

a2.util.add = function add (i) {
    a2.loadItem(i);
};
a2.util.remove = function remove(i) {
    delete a2.items[i]; 
    delete a2.events[i];
    delete a2.virtuals[i];
    a2.renderItems();
    a2.fireEvent(["remove",i]);
};

a2.util.removeAll = function removeAll(v) {
    for (i in a2.virtuals)
        if( a2.virtuals[i].indexOf(v) > -1 ) {
            delete a2.items[i]; 
            delete a2.events[i];
            delete a2.virtuals[i];
            a2.fireEvent(["remove",i]);
    }
    a2.renderItems();
}

a2.util.hasVirtual = function hasVirtual (v) {
    for (i in a2.virtuals)
        if( a2.virtuals[i].indexOf(v) > -1 )
            return i;
    return false;
}

a2.ui = {};
a2.ui.getAreaBox = function getAreaBox (area) {
    var $area = $(area);
    var shape = $area.attr("shape");
    var p = $area.attr("coords");
    p = p.split(",")
    p = $.map(p, function(x){ return parseInt(x);});

    if (shape == "circle"){
        var x1 = p[0] - p[2];
        var y1 = p[1] - p[2];
        var x2 = p[0] + p[2];
        var y2 = p[1] + p[2];
    } else {
        var x1 = Infinity;
        var y1 = Infinity;
        var x2 = -Infinity;
        var y2 = -Infinity;
        for(var i=0; i<p.length; i=i+2){
            if (p[i] < x1) x1 = p[i];
            if (p[i+1] < y1) y1 = p[i+1];
            if (p[i] > x2) x2 = p[i];
            if (p[i+1] > y2) y2 = p[i+1];
        }
    }

    return {x1:x1, y1:y1, x2:x2, y2:y2};
};

a2.ui.getDroparea = function getDroparea (img, ui) {
    var $areas = $("area");
    return $areas.filter(function () {
        var b = a2.ui.getAreaBox(this);
        var s = 25; // half itemsize

        var xm = (b.x1 + b.x2) / 2;
        var ym = (b.y1 + b.y2) / 2;

        var dx = ui.offset.left - $(img).offset().left + s;
        var dy = ui.offset.top - $(img).offset().top + s;

        return (b.x1 < dx && dx < b.x2 &&
                b.y1 < dy && dy < b.y2) ||
               (dx - s < xm && xm < dx + s &&
                dy - s < ym && ym < dy + s);            
    });
}

a2.stateEncode = function () {
    var s = String(a2.cpage);
    for (var i in a2.items)
        s+="|"+i;
    return s
}

a2.stateDecode = function (s) {
    a2.clearEventChain();
    var c = s.split("|");
    a2.items = {};
    a2.virtuals = {};
    a2.events = {}
    for (var j=1; j<c.length; j++) {
        a2.items[c[j]] = "<img src='/images/a/a6/A2loading.gif' alt='Loading …' />";
    }
    a2.renderItems();
    for (var j=1; j<c.length; j++)
        a2.loadItem(c[j]);
    a2.loadPage(parseInt(c[0]));
}

a2.crypt = function crypt (str, encode) {
    if (encode){
        var n = Math.floor((Math.random()*9))+1;
        out = String(n);
    } else {
        var n = - parseInt(str.substr(0,1));
        var out = "";
        str = str.substr(1);
    }
    var chain = "pwoTä7eGNVk1SAldv0mJ9zIöPE4x8rF|B6ybüjZDC5cqfRhOXsQY23iUngLWuMHatK";
    var mk = function(i){ return i % chain.length };

    for (var i=0; i<str.length; i++) {
        var c = str.substr(i,1);
        var ind = chain.indexOf(c);
        if (ind == -1)
            out += c;
        else
            out += chain.substr(mk(ind + n),1);
    }
    return out;
}

/* DEBUGGER */

a2.debugEvent = function debugEvent (ev) {
    if (!$("#a2dbgBottom").length)
        return;

    $("#a2dbgEventLog").append($("<li/>").text(ev).append("<ul/>"));
    $("#a2dbgBottom:visible").scrollTop($("#a2dbgBottom")[0].scrollHeight);
}

a2.debugEventInstance = function debugEventInstance (sc,n,cond) {
    if (!$("#a2dbgBottom").length)
        return;

    var classname = cond ? "a2fired" : "a2notfired";
    $("#a2dbgEventLog li ul").last().append($("<li/>").text(sc+"->"+n).addClass(classname));
    $("#a2dbgBottom:visible").scrollTop($("#a2dbgBottom")[0].scrollHeight);
}

a2.debugPage = function debugPage (p) {
   $("#a2dbgGoto").val(p);
}

a2.debugItems = function debugItems() {
   var s = [];
   for (i in a2.items)
       s.push(i);
   $("#a2dbgItems").val(s.join("\n"));
}

a2.debugError = function debugError(text) {
    if (!$("#a2dbgBottom").length)
        return;

    a2.errorCount ++;
    $("#a2errorCount").text(a2.errorCount);
    $("#a2dbgEventLog").append($("<li/>").text(text).addClass("a2error"));
    $("#a2dbgBottom:visible").scrollTop($("#a2dbgBottom")[0].scrollHeight);
}

// provide timer functions
a2.timer = {
    time: 0,
    pt: NaN,
    fn: null,
    set: function set(n, fn) {
    
        if (! isNaN(a2.timer.pt)) {
	    // do not set timer if timer already active
            return;
        }
            
        a2.timer.time = n;
        a2.timer.fn = fn;
        
        a2.timer.pt = setInterval(function () {
            a2.timer.time--;
    
            if (a2.timer.time <= 0) {
                clearInterval(a2.timer.pt);
                a2.timer.pt = NaN;
                $("#_t").text("0:00").fadeOut('slow');
                fn();
                return;
            }
        
            var sec = a2.timer.time % 60;
        
            if (sec < 10)
                sec = "0" + sec;
            $("#_t").show().text(String(Math.floor(a2.timer.time / 60)) + ":" + sec );
        }, 1000);
    },
    
    clear: function clear() {
        if (! isNaN(a2.timer.pt)) {
            clearInterval(a2.timer.pt);
            a2.timer.pt = NaN;
            $("#_t").fadeOut();
        }
    }
};

// provide audio functions
a2.audio = {
    cache: {},
    current: [],

    fetch: function fetch(file) {
            var data = $.ajax({
            type: "GET",
            url: "/api.php",
            data: {
                action: "parse",
                format: "xml",
                text: "{{filepath:"+file+"}}"
            }, 
            async: false
        });
        
        var html = $(data.responseText).find("text").text();
        var url = $(html).find("a")[0].href;
        return url;
    },

    getaudio: function getaudio(file) {
        if (a2.audio.cache[file]) {
            return a2.audio.cache[file];
        } else {
            var url = a2.audio.fetch(file);
            a2.audio.cache[file] = url;
            return url;
        }
    },

    play: function play(channel, file) {
        var $player = $("#a2audio_channel_"+channel)[0];
        var audiofile = a2.audio.getaudio(file);

        if (audiofile != a2.audio.current[channel]) {        
            $player.pause();
            $player.src = a2.audio.getaudio(file);
            $player.load();
            $player.play();
            a2.audio.current[channel] = audiofile;
        }
    },

    stop: function stop(channel) {
        var $player = $("#a2audio_channel_"+channel)[0];
        $player.pause();
        a2.audio.current[channel] = null;
    }
}