/* ####################################################################################
Verfügbare Funktionen und Variablen:
---------------------------------------------------------------------------------------
[A] $.ajaxSetup()		=>	globale jQuery-Settings
[A]	sfHover				=>	SUCKERFISH Horizontales Dropdown-Menü (Main-Nav)
[A]	sfHoverLang			=>	SUCKERFISH Horizontales Dropdown-Menü (Language-Nav)

	f_
	f_IsValidEmail		=>	gültige eMail-Adresse?
	f_LoadContent()		=>	Ajax-Content-Loader für Controls
	npf_trim()			=>	TRIM-Funktion für Strings
	
	$.URLEncode			=>	Plugin zum Encoden von Strings für URLs
	$.URLDecode			=>	Plugin zum Decoden von Strings für URLs
	jquery.slideshow	=>	v1.3 - Slider für reine Bilder
	jquery.timer		=>	v0.1
	jquery.boxy			=>	v0.1.4 - PopUp-Overlay im Facebook-Style
	jquery.tipsy		=>	Tooltip im Facebook-Style
	jquery.accordian	=>	Accordion für die Top-Events auf der HOME.ASP
	jquery.inputHint	=>	Hinweistexte innerhalb von INPUT-Feldern
	jquery.autogrow		=>	sich selbst vergrößernde Eingabefelder wie bei Facebook
	jquery.jeditable	=>	In-Place-Editing von HTML-Elementen wie bei Facebook
	jquery.mousewheel	=>	Bedienung des jcarousellite per Mausrad
	jquery.jcarousellite=>	v1.0.1. 
	jquery.s3slider		=>	v1.0 - Slider für Content-Teaser

	flower_bubble		=>	v0.4 "Ajax-Loading"-Indicator (verwendet in f_loadContent())
---------------------------------------------------------------------------------------
[A] = wird automatisch beim Laden ausgeführt !
#################################################################################### */
$.ajaxSetup ({
	// Global disable caching of AJAX responses */    
	cache: false
});
//Diese Var verhindert eine Tastatur-Navigation (galleries) wenn die Textbox den Focus hat:
var gPreventKeyControl = false;

/* ------------------------------------------------------------------------------------
SUCKERFISH Horizontales Dropdown-Menü
Wird für das ausklappende CSS-Menü der Site benötigt und global instanziert
---------------------------------------------------------------------------------------
Quelle:
http://www.htmldog.com/articles/suckerfish/dropdowns/
Modifikation für IE-Bug:
http://css-class.com/articles/explorer/sticky/
------------------------------------------------------------------------------------ */
sfHover = function() {
	var sfEls = document.getElementById("mainnav").getElementsByTagName("LI");
	for (var i=0; i<sfEls.length; i++) {         
		sfEls[i].onmouseover=function() { this.className+=" sfhover"; }
		sfEls[i].onmouseout=function() { this.className=this.className.replace(new RegExp(" sfhover\\b"), ""); }
	} 
} 
if (window.attachEvent) { window.attachEvent("onload", sfHover); } 

sfHoverLang = function() {
// to do: Für LANGUAGES wieder aktivieren:
//	var sfEls = document.getElementById("mainnav_lang").getElementsByTagName("LI");
//	for (var i=0; i<sfEls.length; i++) {         
//		sfEls[i].onmouseover=function() { this.className+=" sfhover"; }
//		sfEls[i].onmouseout=function() { this.className=this.className.replace(new RegExp(" sfhover\\b"), ""); }
//	} 
} 
if (window.attachEvent) { window.attachEvent("onload", sfHoverLang); }

/* http://plugins.jquery.com/project/URLEncode */

$.extend({
URLEncode:function(c){var o='';var x=0;c=c.toString();var r=/(^[a-zA-Z0-9_.]*)/;
  while(x<c.length){var m=r.exec(c.substr(x));
    if(m!=null && m.length>1 && m[1]!=''){o+=m[1];x+=m[1].length;
    }else{if(c[x]==' ')o+='+';else{var d=c.charCodeAt(x);var h=d.toString(16);
    o+='%'+(h.length<2?'0':'')+h.toUpperCase();}x++;}}return o;},
URLDecode:function(s){var o=s;var binVal,t;var r=/(%[^%]{2})/;
  while((m=r.exec(o))!=null && m.length>1 && m[1]!=''){b=parseInt(m[1].substr(1),16);
  t=String.fromCharCode(b);o=o.replace(m[1],t);}return o;}
});

/* --------------------------------------------------------------
nightpaper-Messaging
-------------------------------------------------------------- */
var mLastOpenendMessageBoxy;

function npf_Message_Show(pMessageID, pType, pBoxTitle) {
	/* Anzeigen einer einzelnen Message */
	try { npf_Message_Cancel(mLastOpenendMessageBoxy); } catch(e) {}
	mMessageDialog = new Boxy.load('/message.asp?'+pType+'='+pMessageID, {
		title: pBoxTitle, closeText:'[x]', draggable:true, show:true, modal:false, 
		afterShow: function() {
			mLastOpenendMessageBoxy = this;
			if ($('#message_'+pMessageID).html() != '') { $('#message_'+pMessageID).html(''); }
			npf_Insert_DeleteLink(pMessageID);
		}
	});
}

function npf_Message_Send(pRecipID, pRecipName, pLang, pBoxTitle) {
	/* Verschicken einer Message */
	mMessageDialog = new Boxy.load('/message.asp', {
		title:pBoxTitle, closeText:'[x]', draggable:true, show:true, modal:false,
		afterShow: function() {
			mLastOpenendMessageBoxy = this;
			$('#recipient_id').val(pRecipID);
			$('#recipient').val(pRecipName);
			$('#recipient').attr('disabled', true);
		}
	});
}
function npf_Message_Reply(pOpener, pRecipID, pRecipName, pLang, pSubject, pMessage) {
	/* Antworten auf eine erhaltene Message */
	mMessageDialog = new Boxy.load('/message.asp', {
		title:'Nachricht an einen User senden', closeText:'[x]', draggable:true, show:true, modal:false,
		afterShow: function() {
			mLastOpenendMessageBoxy = this;
			$('#recipient_id').val(pRecipID);
			$('#recipient').val(pRecipName);
			$('#recipient').attr('disabled', true);
			$('#subject').val(pSubject);
			$('#messagetext').val(pMessage);
			npf_setSelectionRange(document.getElementById('messagetext'), 0, 0);
		}
	});
	npf_Message_Cancel(pOpener);
}
function npf_Message_Submit(box) {
	var hasError = false;
	var mSubject = $('#subject').val();
	if(mSubject.length > 100)		{ $('#subject').addClass('missing'); $('#subject-label span').text('max.100 Zeichen'); hasError = true; }
	if(npf_trim(mSubject) == '')	{ $('#subject').addClass('missing'); $('#subject-label span').text('Eingabe erforderlich'); hasError = true; }
	if(!hasError)					{ $('#subject').removeClass('missing'); $('#subject-label span').text(''); }
	var mMessage = $('#messagetext').val();
	if(mMessage.length > 2000)		{ $('#messagetext').addClass('missing'); $('#messagetext-label span').text('max.2000 Zeichen'); hasError = true; }
	if(npf_trim(mMessage) == '')	{ $('#messagetext').addClass('missing'); $('#messagetext-label span').text('Eingabe erforderlich'); hasError = true; }
	if(!hasError)					{ $('#messagetext').removeClass('missing'); $('#messagetext-label span').text(''); }
	if(!hasError) {
		$('#recipient').removeAttr('disabled');
		var formVal = $('#messageform').serialize();
		$('#message').html('<img id="message_ajaxloader" src="/_css/img/ajax-loader.gif" alt="">');
		$.post('message.asp', formVal, function(data) {$('#message').html(data);} );
	}
}
function npf_Message_Cancel(box) { box.hide(); box.unload(); return false; }

function f_IsValidEmail(pEmail) {
	var a = false;
	var res = false;
	if(typeof(RegExp) == 'function') {
		var b = new RegExp('abc');
		if(b.test('abc') == true) {a = true;}
	}
	if (a == true) {
		reg = /^\w[\w|\.|\-]+@\w[\w|\.|\-]+\.[a-zA-Z]{2,4}$/;
		res = (reg.test(pEmail));
	} else {
		res = (pEmail.search('@') >= 1 && pEmail.lastIndexOf('.') > pEmail.search('@') && pEmail.lastIndexOf('.') >= pEmail.length-5)
	}

	return(res);	
}

function npf_setSelectionRange(input, selectionStart, selectionEnd) { 
	input.focus();
  if (input.setSelectionRange) { 
    input.setSelectionRange(selectionStart, selectionEnd); 
  } 
  else if (input.createTextRange) { 
    var range = input.createTextRange(); 
    range.collapse(true); 
    range.moveEnd('character', selectionEnd); 
    range.moveStart('character', selectionStart); 
    range.select(); 
  } 
}

function f_LoadContent(pElement, pAjaxControl, pAjaxParams, pLoadingIndicator, pLangID, pSessionID) {
	/* ------------------------------------------------------------------------------------
	AJAX-Content-Loader
	Lädt in das gewünschte DOM-Element per AJAX via "/ajax.asp" Control-Inhalte nach.
	Die "/ajax.asp" liefert HTML-Quelltext.
	---------------------------------------------------------------------------------------
	Parameter:
		pElement		=>	DOM-Element, in welches das Result geschrieben wird
		pAjaxControl	=>	Name für das gewünschte ASP-Control. Wird an die "/ajax.asp" im 
							Get-Parameter "c" weitergereicht. Die Auswertung des Parameters 
							erfolgt in der "/ajax.asp"!
		pAjaxParams		=>	Parameter für das ASP-Control. Wird an die "/ajax.asp" im Get-
							Parameter "p" weitergereicht. Wenn mehr benannte Parameter 
							übergeben werden müssen, dann ist hier der entsprechende Query-
							String zusammengesetzt zu übergeben.
							Bspw.: [p] = "wert1&key2=wert2&key3=wert3"
							(to do: NOCH NICHT GETESTET ob jquery die "&" escaped!!!)
		pLoadingInd.	=>	TRUE / FALSE > Soll das Ziel-DOM-Element mit einem Ajax-Load-Anzeiger
							disabled werden?
		pLangID			=>	Inhalt von "gLanguageID"
		pSesionID		=>	Inhalt von "gSessionID"
	---------------------------------------------------------------------------------------
	01.10.2009	OA	Erstellung
	------------------------------------------------------------------------------------ */
	if (pLoadingIndicator==true) {
		var flobu ;
		$(function(){
			flobu = new flower_bubble ({
				base_obj: $( pElement ),
				base_dir: '/_css/img',
				background: { css: 'white', opacity: 0.78 },
				bubble: { image: 'bubble.png', width: 130, height: 98 },
				flower: { image: 'flower.gif', width: 32, height: 32 },
				block_mode: 'base_obj'
			}) ;
		}) ;
		flobu.enable() ;
	}
	// *Synchrones* Laden des Contents:
	mURL = "/ajax.asp?c=" + pAjaxControl + "&p=" + pAjaxParams + "&r=" + Math.round(Math.random()*10000000) + "&lang=" + pLangID + "&us=" + pSessionID;
	if (pLoadingIndicator==false) {
		$(pElement).load(mURL);
	} else {
		$(pElement).load(mURL, '', function(){flobu.disable();});
	}
	//Alternative, *asynchrone* Methode zum Laden des Contents inkl. Error-Handler:
/* 
	$.ajax({
		type: 'GET',
		cache: false,
		url: '/ajax.asp',
		data: 'c=' + pAjaxControl + '&p=' + pAjaxParams + '&r=' + Math.round(Math.random()*10000000) + '&lang=' + pLangID + '&us=' + pSessionID, 
		error: function() { window.alert('ERROR!'); },
		success: function(data) { $(pElement).html(data); }
	});
*/
}

function npf_trim(pString) {
	/* ------------------------------------------------------------------------------------
	TRIM für einen String
	---------------------------------------------------------------------------------------
	Parameter:
		pString		=>	zu trimmender String
	Rückgabe:
		STRING
	---------------------------------------------------------------------------------------
	22.10.2009	OA	Erstellung
	------------------------------------------------------------------------------------ */
	// Erst führende, dann Abschließende Whitespaces entfernen
	// und das Ergebnis dieser Operationen zurückliefern
	return pString.replace (/^\s+/, '').replace (/\s+$/, '');
}

jQuery.fn.slideshow = function(options) {
/* ------------------------------------------------------------------
 * jQuery Slideshow Plugin v1.3
 * Author: Matt Oakes
 * URL: http://www.matto1990.com/jquery/slideshow/
 *
 * Modifications by Meinhard Benn (http://benn.org/):
 *  - fadetime setting
------------------------------------------------------------------ */
	var settings = {
		fadetime: 'slow',
		timeout: '2000',
		type: 'sequence',
		pauselink: null,
		playcallback: null,
		pausecallback: null
	};
	if (options) {
		jQuery.extend(settings, options);
	}
	var	pauseState = 0,
		current = 1,
		last = 0,
		timer = '';
	var change = function () {
		if ( pauseState == 0 ) {
			for (var i = 0; i < slides.length; i++) {
				jQuery(slides[i]).css('display', 'none');
			}
			jQuery(slides[last]).css('display', 'block').css('zIndex', '0');
			jQuery(slides[current]).css('zIndex', '1').fadeIn(settings.fadetime);
			
			if ( settings.type == 'sequence' ) {
				if ( ( current + 1 ) < slides.length ) {
					current = current + 1;
					last = current - 1;
				}
				else {
					current = 0;
					last = slides.length - 1;
				}
			}
			else if ( settings.type == 'random' ) {
				last = current;
				while (	current == last ) {
					current = Math.floor ( Math.random ( ) * ( slides.length ) );
				}
			}
			else {
				alert('type must either be \'sequence\' or \'random\'');
			}
			timer = setTimeout(change, settings.timeout);
		}
	};
	var pause = function() {
		if ( pauseState == 0 ) {
			pauseState = 1;
			clearTimeout(timer);
			if ( settings.playcallback != null ) {
				settings.pausecallback(jQuery('#' + settings.pauselink));
			}
		}
		else {
			pauseState = 0;
			change();
			if ( settings.playcallback != null ) {
				settings.playcallback(jQuery('#' + settings.pauselink));
			}
		}
		return false;
	};
	this.css('position', 'relative');
	var slides = this.find('img').get();
	jQuery.each(slides, function(i){
		jQuery(slides[i]).css('zIndex', slides.length - i).css('position', 'absolute').css('top', '0').css('left', '0');
	});
	if ( settings.type == 'sequence' ) {
		timer = setTimeout(change, settings.timeout);
	}
	else if ( settings.type == 'random' ) {
		do {
			current = Math.floor ( Math.random ( ) * ( slides.length ) );
		} while ( current == 0 );
		timer = setTimeout(change, settings.timeout);
	}
	else {
		alert('type must either be \'sequence\' or \'random\'');
	}
	
	if ( settings.pauselink != null ) {
		jQuery('#' + settings.pauselink).click(pause);
	}
	
	return this;
};

/*
 *
 *	jQuery Timer plugin v0.1
 *		Matt Schmidt [http://www.mattptr.net]
 *
 *	Licensed under the BSD License:
 *		http://mattptr.net/license/license.txt
 *
 */
 
 jQuery.timer = function (interval, callback)
 {
 /**
  *
  * timer() provides a cleaner way to handle intervals  
  *
  *	@usage
  * $.timer(interval, callback);
  *
  *
  * @example
  * $.timer(1000, function (timer) {
  * 	alert("hello");
  * 	timer.stop();
  * });
  * @desc Show an alert box after 1 second and stop
  * 
  * @example
  * var second = false;
  *	$.timer(1000, function (timer) {
  *		if (!second) {
  *			alert('First time!');
  *			second = true;
  *			timer.reset(3000);
  *		}
  *		else {
  *			alert('Second time');
  *			timer.stop();
  *		}
  *	});
  * @desc Show an alert box after 1 second and show another after 3 seconds
  *
  * 
  */

	var interval = interval || 100;

	if (!callback)
		return false;
	
	_timer = function (interval, callback) {
		this.stop = function () {
			clearInterval(self.id);
		};
		
		this.internalCallback = function () {
			callback(self);
		};
		
		this.reset = function (val) {
			if (self.id)
				clearInterval(self.id);
			
			var val = val || 100;
			this.id = setInterval(this.internalCallback, val);
		};
		
		this.interval = interval;
		this.id = setInterval(this.internalCallback, this.interval);
		
		var self = this;
	};
	
	return new _timer(interval, callback);
 };

jQuery.fn.boxy = function(options) {
	/* ------------------------------------------------------------------------------------
	 * Boxy 0.1.4 - Facebook-style dialog, with frills
	 *
	 * (c) 2008 Jason Frame
	 * Licensed under the MIT License (LICENSE)
	
	 * jQuery plugin
	 *
	 * Options:
	 *   message: confirmation message for form submit hook (default: "Please confirm:")
	 * 
	 * Any other options - e.g. 'clone' - will be passed onto the boxy constructor (or
	 * Boxy.load for AJAX operations)
	
	http://onehackoranother.com/projects/jquery/boxy/
	------------------------------------------------------------------------------------ */
    options = options || {};
    return this.each(function() {      
        var node = this.nodeName.toLowerCase(), self = this;
        if (node == 'a') {
            jQuery(this).click(function() {
                var active = Boxy.linkedTo(this),
                    href = this.getAttribute('href'),
                    localOptions = jQuery.extend({actuator: this, title: this.title}, options);
                    
                if (active) {
                    active.show();
                } else if (href.indexOf('#') >= 0) {
                    var content = jQuery(href.substr(href.indexOf('#'))),
                        newContent = content.clone(true);
                    content.remove();
                    localOptions.unloadOnHide = false;
                    new Boxy(newContent, localOptions);
                } else { // fall back to AJAX; could do with a same-origin check
                    if (!localOptions.cache) localOptions.unloadOnHide = true;
                    Boxy.load(this.href, localOptions);
                }
                
                return false;
            });
        } else if (node == 'form') {
            jQuery(this).bind('submit.boxy', function() {
                Boxy.confirm(options.message || 'Please confirm:', function() {
                    jQuery(self).unbind('submit.boxy').submit();
                });
                return false;
            });
        }
    });
};

//
// Boxy Class
//

function Boxy(element, options) {
    this.boxy = jQuery(Boxy.WRAPPER);
    jQuery.data(this.boxy[0], 'boxy', this);
    this.visible = false;
    this.options = jQuery.extend({}, Boxy.DEFAULTS, options || {});
    if (this.options.modal) {
        this.options = jQuery.extend(this.options, {center: true, draggable: false});
    }
    // options.actuator == DOM element that opened this boxy
    // association will be automatically deleted when this boxy is remove()d
    if (this.options.actuator) {
        jQuery.data(this.options.actuator, 'active.boxy', this);
    }
    this.setContent(element || "<div></div>");
    this._setupTitleBar();
    this.boxy.css('display', 'none').appendTo(document.body);
    this.toTop();
    if (this.options.fixed) {
        if (jQuery.browser.msie && jQuery.browser.version < 7) {
            this.options.fixed = false; // IE6 doesn't support fixed positioning
        } else {
            this.boxy.addClass('fixed');
        }
    }
    if (this.options.center && Boxy._u(this.options.x, this.options.y)) {
        this.center();
    } else {
        this.moveTo(
            Boxy._u(this.options.x) ? this.options.x : Boxy.DEFAULT_X,
            Boxy._u(this.options.y) ? this.options.y : Boxy.DEFAULT_Y
        );
    }
    if (this.options.show) this.show();
};

Boxy.EF = function() {};

jQuery.extend(Boxy, {
    WRAPPER:    "<table cellspacing='0' cellpadding='0' border='0' class='boxy-wrapper'>" +
                "<tr><td class='top-left'></td><td class='top'></td><td class='top-right'></td></tr>" +
                "<tr><td class='left'></td><td class='boxy-inner'></td><td class='right'></td></tr>" +
                "<tr><td class='bottom-left'></td><td class='bottom'></td><td class='bottom-right'></td></tr>" +
                "</table>",
    DEFAULTS: {
        title:                  null,           // titlebar text. titlebar will not be visible if not set.
        closeable:              true,           // display close link in titlebar?
        draggable:              true,           // can this dialog be dragged?
        clone:                  false,          // clone content prior to insertion into dialog?
        actuator:               null,           // element which opened this dialog
        center:                 true,           // center dialog in viewport?
        show:                   true,           // show dialog immediately?
        modal:                  false,          // make dialog modal?
        fixed:                  true,           // use fixed positioning, if supported? absolute positioning used otherwise
        closeText:              '[close]',      // text to use for default close link
        unloadOnHide:           false,          // should this dialog be removed from the DOM after being hidden?
        clickToFront:           false,          // bring dialog to foreground on any click (not just titlebar)?
        behaviours:             Boxy.EF,        // function used to apply behaviours to all content embedded in dialog.
        afterDrop:              Boxy.EF,        // callback fired after dialog is dropped. executes in context of Boxy instance.
        afterShow:              Boxy.EF,        // callback fired after dialog becomes visible. executes in context of Boxy instance.
        afterHide:              Boxy.EF,        // callback fired after dialog is hidden. executed in context of Boxy instance.
        beforeUnload:           Boxy.EF         // callback fired after dialog is unloaded. executed in context of Boxy instance.
    },
    DEFAULT_X:          50,
    DEFAULT_Y:          50,
    zIndex:             1337,
    dragConfigured:     false, // only set up one drag handler for all boxys
    resizeConfigured:   false,
    dragging:           null,
    // load a URL and display in boxy
    // url - url to load
    // options keys (any not listed below are passed to boxy constructor)
    //   type: HTTP method, default: GET
    //   cache: cache retrieved content? default: false
    //   filter: jQuery selector used to filter remote content
    load: function(url, options) {
        options = options || {};
        var ajax = {
            url: url, type: 'GET', dataType: 'html', cache: false, success: function(html) {
                html = jQuery(html);
                if (options.filter) html = jQuery(options.filter, html);
                new Boxy(html, options);
            }
        };
        jQuery.each(['type', 'cache'], function() {
            if (this in options) {
                ajax[this] = options[this];
                delete options[this];
            }
        });
        jQuery.ajax(ajax);
    },
    // allows you to get a handle to the containing boxy instance of any element
    // e.g. <a href='#' onclick='alert(Boxy.get(this));'>inspect!</a>.
    // this returns the actual instance of the boxy 'class', not just a DOM element.
    // Boxy.get(this).hide() would be valid, for instance.
    get: function(ele) {
        var p = jQuery(ele).parents('.boxy-wrapper');
        return p.length ? jQuery.data(p[0], 'boxy') : null;
    },
    // returns the boxy instance which has been linked to a given element via the
    // 'actuator' constructor option.
    linkedTo: function(ele) {
        return jQuery.data(ele, 'active.boxy');
    },
    // displays an alert box with a given message, calling optional callback
    // after dismissal.
    alert: function(message, callback, options) {
        return Boxy.ask(message, ['OK'], callback, options);
    },
    // displays an alert box with a given message, calling after callback iff
    // user selects OK.
    confirm: function(message, after, options) {
        return Boxy.ask(message, ['OK', 'Cancel'], function(response) {
            if (response == 'OK') after();
        }, options);
    },
    // asks a question with multiple responses presented as buttons
    // selected item is returned to a callback method.
    // answers may be either an array or a hash. if it's an array, the
    // the callback will received the selected value. if it's a hash,
    // you'll get the corresponding key.
    ask: function(question, answers, callback, options) {
        options = jQuery.extend({modal: true, closeable: false},
                                options || {},
                                {show: true, unloadOnHide: true});
        var body = jQuery('<div></div>').append(jQuery('<div class="question"></div>').html(question));
        // ick
        var map = {}, answerStrings = [];
        if (answers instanceof Array) {
            for (var i = 0; i < answers.length; i++) {
                map[answers[i]] = answers[i];
                answerStrings.push(answers[i]);
            }
        } else {
            for (var k in answers) {
                map[answers[k]] = k;
                answerStrings.push(answers[k]);
            }
        }
        var buttons = jQuery('<form class="answers"></form>');
        buttons.html(jQuery.map(answerStrings, function(v) {
            return "<input type='button' value='" + v + "' />";
        }).join(' '));
        jQuery('input[type=button]', buttons).click(function() {
            var clicked = this;
            Boxy.get(this).hide(function() {
                if (callback) callback(map[clicked.value]);
            });
        });
        body.append(buttons);
        new Boxy(body, options);
    },
    // returns true if a modal boxy is visible, false otherwise
    isModalVisible: function() {
        return jQuery('.boxy-modal-blackout').length > 0;
    },
    _u: function() {
        for (var i = 0; i < arguments.length; i++)
            if (typeof arguments[i] != 'undefined') return false;
        return true;
    },
    _handleResize: function(evt) {
        var d = jQuery(document);
        jQuery('.boxy-modal-blackout').css('display', 'none').css({
            width: d.width(), height: d.height()
        }).css('display', 'block');
    },
    _handleDrag: function(evt) {
        var d;
        if (d = Boxy.dragging) {
            d[0].boxy.css({left: evt.pageX - d[1], top: evt.pageY - d[2]});
        }
    },
    _nextZ: function() {
        return Boxy.zIndex++;
    },
    _viewport: function() {
        var d = document.documentElement, b = document.body, w = window;
        return jQuery.extend(
            jQuery.browser.msie ?
                { left: b.scrollLeft || d.scrollLeft, top: b.scrollTop || d.scrollTop } :
                { left: w.pageXOffset, top: w.pageYOffset },
            !Boxy._u(w.innerWidth) ?
                { width: w.innerWidth, height: w.innerHeight } :
                (!Boxy._u(d) && !Boxy._u(d.clientWidth) && d.clientWidth != 0 ?
                    { width: d.clientWidth, height: d.clientHeight } :
                    { width: b.clientWidth, height: b.clientHeight }) );
    }
});

Boxy.prototype = {
    // Returns the size of this boxy instance without displaying it.
    // Do not use this method if boxy is already visible, use getSize() instead.
    estimateSize: function() {
        this.boxy.css({visibility: 'hidden', display: 'block'});
        var dims = this.getSize();
        this.boxy.css('display', 'none').css('visibility', 'visible');
        return dims;
    },
    // Returns the dimensions of the entire boxy dialog as [width,height]
    getSize: function() {
        return [this.boxy.width(), this.boxy.height()];
    },
    // Returns the dimensions of the content region as [width,height]
    getContentSize: function() {
        var c = this.getContent();
        return [c.width(), c.height()];
    },
    // Returns the position of this dialog as [x,y]
    getPosition: function() {
        var b = this.boxy[0];
        return [b.offsetLeft, b.offsetTop];
    },
    // Returns the center point of this dialog as [x,y]
    getCenter: function() {
        var p = this.getPosition();
        var s = this.getSize();
        return [Math.floor(p[0] + s[0] / 2), Math.floor(p[1] + s[1] / 2)];
    },
    // Returns a jQuery object wrapping the inner boxy region.
    // Not much reason to use this, you're probably more interested in getContent()
    getInner: function() {
        return jQuery('.boxy-inner', this.boxy);
    },
    // Returns a jQuery object wrapping the boxy content region.
    // This is the user-editable content area (i.e. excludes titlebar)
    getContent: function() {
        return jQuery('.boxy-content', this.boxy);
    },
    // Replace dialog content
    setContent: function(newContent) {
        newContent = jQuery(newContent).css({display: 'block'}).addClass('boxy-content');
        if (this.options.clone) newContent = newContent.clone(true);
        this.getContent().remove();
        this.getInner().append(newContent);
        this._setupDefaultBehaviours(newContent);
        this.options.behaviours.call(this, newContent);
        return this;
    },
    // Move this dialog to some position, funnily enough
    moveTo: function(x, y) {
        this.moveToX(x).moveToY(y);
        return this;
    },
    // Move this dialog (x-coord only)
    moveToX: function(x) {
        if (typeof x == 'number') this.boxy.css({left: x});
        else this.centerX();
        return this;
    },
    // Move this dialog (y-coord only)
    moveToY: function(y) {
        if (typeof y == 'number') this.boxy.css({top: y});
        else this.centerY();
        return this;
    },
    // Move this dialog so that it is centered at (x,y)
    centerAt: function(x, y) {
        var s = this[this.visible ? 'getSize' : 'estimateSize']();
        if (typeof x == 'number') this.moveToX(x - s[0] / 2);
        if (typeof y == 'number') this.moveToY(y - s[1] / 2);
        return this;
    },
    centerAtX: function(x) {
        return this.centerAt(x, null);
    },
    centerAtY: function(y) {
        return this.centerAt(null, y);
    },
    // Center this dialog in the viewport
    // axis is optional, can be 'x', 'y'.
    center: function(axis) {
        var v = Boxy._viewport();
        var o = this.options.fixed ? [0, 0] : [v.left, v.top];
        if (!axis || axis == 'x') this.centerAt(o[0] + v.width / 2, null);
        if (!axis || axis == 'y') this.centerAt(null, o[1] + v.height / 2);
        return this;
    },
    // Center this dialog in the viewport (x-coord only)
    centerX: function() {
        return this.center('x');
    },
    // Center this dialog in the viewport (y-coord only)
    centerY: function() {
        return this.center('y');
    },
    // Resize the content region to a specific size
    resize: function(width, height, after) {
        if (!this.visible) return;
        var bounds = this._getBoundsForResize(width, height);
        this.boxy.css({left: bounds[0], top: bounds[1]});
        this.getContent().css({width: bounds[2], height: bounds[3]});
        if (after) after(this);
        return this;
    },
    // Tween the content region to a specific size
    tween: function(width, height, after) {
        if (!this.visible) return;
        var bounds = this._getBoundsForResize(width, height);
        var self = this;
        this.boxy.stop().animate({left: bounds[0], top: bounds[1]});
        this.getContent().stop().animate({width: bounds[2], height: bounds[3]}, function() {
            if (after) after(self);
        });
        return this;
    },
    // Returns true if this dialog is visible, false otherwise
    isVisible: function() {
        return this.visible;    
    },
    // Make this boxy instance visible
    show: function() {
        if (this.visible) return;
        if (this.options.modal) {
            var self = this;
            if (!Boxy.resizeConfigured) {
                Boxy.resizeConfigured = true;
                jQuery(window).resize(function() { Boxy._handleResize(); });
            }
            this.modalBlackout = jQuery('<div class="boxy-modal-blackout"></div>')
                .css({zIndex: Boxy._nextZ(),
                      opacity: 0.7,
                      width: jQuery(document).width(),
                      height: jQuery(document).height()})
                .appendTo(document.body);
            this.toTop();
            if (this.options.closeable) {
                jQuery(document.body).bind('keypress.boxy', function(evt) {
                    var key = evt.which || evt.keyCode;
                    if (key == 27) {
                        self.hide();
                        jQuery(document.body).unbind('keypress.boxy');
                    }
                });
            }
        }
        this.boxy.stop().css({opacity: 1}).show();
        this.visible = true;
        this._fire('afterShow');
        return this;
    },
    // Hide this boxy instance
    hide: function(after) {
        if (!this.visible) return;
        var self = this;
        if (this.options.modal) {
            jQuery(document.body).unbind('keypress.boxy');
            this.modalBlackout.animate({opacity: 0}, function() {
                jQuery(this).remove();
            });
        }
        this.boxy.stop().animate({opacity: 0}, 300, function() {
            self.boxy.css({display: 'none'});
            self.visible = false;
            self._fire('afterHide');
            if (after) after(self);
            if (self.options.unloadOnHide) self.unload();
        });
        return this;
    },
    toggle: function() {
        this[this.visible ? 'hide' : 'show']();
        return this;
    },
    hideAndUnload: function(after) {
        this.options.unloadOnHide = true;
        this.hide(after);
        return this;
    },
    unload: function() {
        this._fire('beforeUnload');
        this.boxy.remove();
        if (this.options.actuator) {
            jQuery.data(this.options.actuator, 'active.boxy', false);
        }
    },
    // Move this dialog box above all other boxy instances
    toTop: function() {
        this.boxy.css({zIndex: Boxy._nextZ()});
        return this;
    },
    // Returns the title of this dialog
    getTitle: function() {
        return jQuery('> .title-bar h2', this.getInner()).html();
    },
    // Sets the title of this dialog
    setTitle: function(t) {
        jQuery('> .title-bar h2', this.getInner()).html(t);
        return this;
    },
    //
    // Don't touch these privates
    _getBoundsForResize: function(width, height) {
        var csize = this.getContentSize();
        var delta = [width - csize[0], height - csize[1]];
        var p = this.getPosition();
        return [Math.max(p[0] - delta[0] / 2, 0),
                Math.max(p[1] - delta[1] / 2, 0), width, height];
    },
    _setupTitleBar: function() {
        if (this.options.title) {
            var self = this;
            var tb = jQuery("<div class='title-bar'></div>").html("<h2>" + this.options.title + "</h2>");
            if (this.options.closeable) {
                tb.append(jQuery("<a href='#' class='close'></a>").html(this.options.closeText));
            }
            if (this.options.draggable) {
                tb[0].onselectstart = function() { return false; }
                tb[0].unselectable = 'on';
                tb[0].style.MozUserSelect = 'none';
                if (!Boxy.dragConfigured) {
                    jQuery(document).mousemove(Boxy._handleDrag);
                    Boxy.dragConfigured = true;
                }
                tb.mousedown(function(evt) {
                    self.toTop();
                    Boxy.dragging = [self, evt.pageX - self.boxy[0].offsetLeft, evt.pageY - self.boxy[0].offsetTop];
                    jQuery(this).addClass('dragging');
                }).mouseup(function() {
                    jQuery(this).removeClass('dragging');
                    Boxy.dragging = null;
                    self._fire('afterDrop');
                });
            }
            this.getInner().prepend(tb);
            this._setupDefaultBehaviours(tb);
        }
    },
    _setupDefaultBehaviours: function(root) {
        var self = this;
        if (this.options.clickToFront) {
            root.click(function() { self.toTop(); });
        }
        jQuery('.close', root).click(function() {
            self.hide();
            return false;
        }).mousedown(function(evt) { evt.stopPropagation(); });
    },
    _fire: function(event) {
        this.options[event].call(this);
    }
};


(function($) { $.fn.editable = function(target,options){
if('disable'==target){$(this).data('disabled.editable',true);return;}
if('enable'==target){$(this).data('disabled.editable',false);return;}
if('destroy'==target){$(this).unbind($(this).data('event.editable')).removeData('disabled.editable').removeData('event.editable');return;}
var settings=$.extend({},$.fn.editable.defaults,{target:target},options);var plugin=$.editable.types[settings.type].plugin||function(){};var submit=$.editable.types[settings.type].submit||function(){};var buttons=$.editable.types[settings.type].buttons||$.editable.types['defaults'].buttons;var content=$.editable.types[settings.type].content||$.editable.types['defaults'].content;var element=$.editable.types[settings.type].element||$.editable.types['defaults'].element;var reset=$.editable.types[settings.type].reset||$.editable.types['defaults'].reset;var callback=settings.callback||function(){};var onedit=settings.onedit||function(){};var onsubmit=settings.onsubmit||function(){};var onreset=settings.onreset||function(){};var onerror=settings.onerror||reset;if(settings.tooltip){$(this).attr('title',settings.tooltip);}
settings.autowidth='auto'==settings.width;settings.autoheight='auto'==settings.height;return this.each(function(){var self=this;var savedwidth=$(self).width();var savedheight=$(self).height();$(this).data('event.editable',settings.event);if(!$.trim($(this).html())){$(this).html(settings.placeholder);}
$(this).bind(settings.event,function(e){if(true===$(this).data('disabled.editable')){return;}
if(self.editing){return;}
if(false===onedit.apply(this,[settings,self])){return;}
e.preventDefault();e.stopPropagation();if(settings.tooltip){$(self).removeAttr('title');}
if(0==$(self).width()){settings.width=savedwidth;settings.height=savedheight;}else{if(settings.width!='none'){settings.width=settings.autowidth?$(self).width():settings.width;}
if(settings.height!='none'){settings.height=settings.autoheight?$(self).height():settings.height;}}
if($(this).html().toLowerCase().replace(/(;|")/g,'')==settings.placeholder.toLowerCase().replace(/(;|")/g,'')){$(this).html('');}
self.editing=true;self.revert=$(self).html();$(self).html('');var form=$('<form />');if(settings.cssclass){if('inherit'==settings.cssclass){form.attr('class',$(self).attr('class'));}else{form.attr('class',settings.cssclass);}}
if(settings.style){if('inherit'==settings.style){form.attr('style',$(self).attr('style'));form.css('display',$(self).css('display'));}else{form.attr('style',settings.style);}}
var input=element.apply(form,[settings,self]);var input_content;if(settings.loadurl){var t=setTimeout(function(){input.disabled=true;content.apply(form,[settings.loadtext,settings,self]);},100);var loaddata={};loaddata[settings.id]=self.id;if($.isFunction(settings.loaddata)){$.extend(loaddata,settings.loaddata.apply(self,[self.revert,settings]));}else{$.extend(loaddata,settings.loaddata);}
$.ajax({type:settings.loadtype,url:settings.loadurl,data:loaddata,async:false,success:function(result){window.clearTimeout(t);input_content=result;input.disabled=false;}});}else if(settings.data){input_content=settings.data;if($.isFunction(settings.data)){input_content=settings.data.apply(self,[self.revert,settings]);}}else{input_content=self.revert;}
content.apply(form,[input_content,settings,self]);input.attr('name',settings.name);buttons.apply(form,[settings,self]);$(self).append(form);plugin.apply(form,[settings,self]);$(':input:visible:enabled:first',form).focus();if(settings.select){input.select();}
input.keydown(function(e){if(e.keyCode==27){e.preventDefault();reset.apply(form,[settings,self]);}});var t;if('cancel'==settings.onblur){input.blur(function(e){t=setTimeout(function(){reset.apply(form,[settings,self]);},500);});}else if('submit'==settings.onblur){input.blur(function(e){t=setTimeout(function(){form.submit();},200);});}else if($.isFunction(settings.onblur)){input.blur(function(e){settings.onblur.apply(self,[input.val(),settings]);});}else{input.blur(function(e){});}
form.submit(function(e){if(t){clearTimeout(t);}
e.preventDefault();if(false!==onsubmit.apply(form,[settings,self])){if(false!==submit.apply(form,[settings,self])){if($.isFunction(settings.target)){var str=settings.target.apply(self,[input.val(),settings]);$(self).html(str);self.editing=false;callback.apply(self,[self.innerHTML,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}}else{var submitdata={};submitdata[settings.name]=input.val();submitdata[settings.id]=self.id;if($.isFunction(settings.submitdata)){$.extend(submitdata,settings.submitdata.apply(self,[self.revert,settings]));}else{$.extend(submitdata,settings.submitdata);}
if('PUT'==settings.method){submitdata['_method']='put';}
$(self).html(settings.indicator);var ajaxoptions={type:'POST',data:submitdata,dataType:'html',url:settings.target,success:function(result,status){if(ajaxoptions.dataType=='html'){$(self).html(result);}
self.editing=false;callback.apply(self,[result,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}},error:function(xhr,status,error){onerror.apply(form,[settings,self,xhr]);}};$.extend(ajaxoptions,settings.ajaxoptions);$.ajax(ajaxoptions);}}}
$(self).attr('title',settings.tooltip);return false;});});this.reset=function(form){if(this.editing){if(false!==onreset.apply(form,[settings,self])){$(self).html(self.revert);self.editing=false;if(!$.trim($(self).html())){$(self).html(settings.placeholder);}
if(settings.tooltip){$(self).attr('title',settings.tooltip);}}}};});};$.editable={types:{defaults:{element:function(settings,original){var input=$('<input type="hidden"></input>');$(this).append(input);return(input);},content:function(string,settings,original){$(':input:first',this).val(string);},reset:function(settings,original){original.reset(this);},buttons:function(settings,original){var form=this;if(settings.submit){if(settings.submit.match(/>$/)){var submit=$(settings.submit).click(function(){if(submit.attr("type")!="submit"){form.submit();}});}else{var submit=$('<button type="submit" />');submit.html(settings.submit);}
$(this).append(submit);}
if(settings.cancel){if(settings.cancel.match(/>$/)){var cancel=$(settings.cancel);}else{var cancel=$('<button type="cancel" />');cancel.html(settings.cancel);}
$(this).append(cancel);$(cancel).click(function(event){if($.isFunction($.editable.types[settings.type].reset)){var reset=$.editable.types[settings.type].reset;}else{var reset=$.editable.types['defaults'].reset;}
reset.apply(form,[settings,original]);return false;});}}},text:{element:function(settings,original){var input=$('<input />');if(settings.width!='none'){input.width(settings.width);}
if(settings.height!='none'){input.height(settings.height);}
/* [MOD by OA]: 2 x Textarea-Attibute hinzugefügt für Tastensteuerung in den Galleries: */
input.attr('autocomplete','off');$(this).append(input);return(input);}},textarea:{element:function(settings,original){var textarea=$('<textarea />');textarea.bind('focus',function(e){gPreventKeyControl=true;});textarea.bind('blur',function(e){gPreventKeyControl=false;});if(settings.rows){textarea.attr('rows',settings.rows);}else if(settings.height!="none"){textarea.height(settings.height);}
if(settings.cols){textarea.attr('cols',settings.cols);}else if(settings.width!="none"){textarea.width(settings.width);}
$(this).append(textarea);return(textarea);}},select:{element:function(settings,original){var select=$('<select />');$(this).append(select);return(select);},content:function(data,settings,original){if(String==data.constructor){eval('var json = '+data);}else{var json=data;}
for(var key in json){if(!json.hasOwnProperty(key)){continue;}
if('selected'==key){continue;}
var option=$('<option />').val(key).append(json[key]);$('select',this).append(option);}
$('select',this).children().each(function(){if($(this).val()==json['selected']||$(this).text()==$.trim(original.revert)){$(this).attr('selected','selected');}});}}},addInputType:function(name,input){$.editable.types[name]=input;}};$.fn.editable.defaults={name:'value',id:'id',type:'text',width:'auto',height:'auto',event:'click.editable',onblur:'cancel',loadtype:'GET',loadtext:'Loading...',placeholder:'&nbsp;',loaddata:{},submitdata:{},ajaxoptions:{}};
})(jQuery);

(function($) { $.fn.tipsy = function(opts) {
	/* ------------------------------------------------------------------------------------
	T I P S Y
	
	tipsy - Facebook-style tooltip plugin for jQuery
		(c) 2008 Jason Frame (jason@onehackoranother.com)
		Released under The MIT License.
	
	http://onehackoranother.com/projects/jquery/tipsy
	------------------------------------------------------------------------------------ */
        opts = $.extend({fade: false, gravity: 'n'}, opts || {});
        var tip = null, cancelHide = false;
        this.hover(function() {
            $.data(this, 'cancel.tipsy', true);
            var tip = $.data(this, 'active.tipsy');
            if (!tip) {
                tip = $('<div class="tipsy"><div class="tipsy-inner">' + $(this).attr('title') + '</div></div>');
                tip.css({position: 'absolute', zIndex: 100000});
                $(this).attr('title', '');
                $.data(this, 'active.tipsy', tip);
            }
            var pos = $.extend({}, $(this).offset(), {width: this.offsetWidth, height: this.offsetHeight});
            tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body);
            var actualWidth = tip[0].offsetWidth, actualHeight = tip[0].offsetHeight;
            switch (opts.gravity.charAt(0)) {
                case 'n':
                    tip.css({top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}).addClass('tipsy-north');
                    break;
                case 's':
                    tip.css({top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}).addClass('tipsy-south');
                    break;

                case 'e':
                    tip.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}).addClass('tipsy-east');
                    break;
                case 'w':
                    tip.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}).addClass('tipsy-west');
                    break;
            }
            if (opts.fade) {
                tip.css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: 1});
            } else {
                tip.css({visibility: 'visible'});
            }
        }, function() {
            $.data(this, 'cancel.tipsy', false);
            var self = this;
            setTimeout(function() {
                if ($.data(this, 'cancel.tipsy')) return;
                var tip = $.data(self, 'active.tipsy');
                if (opts.fade) {
                    tip.stop().fadeOut(function() { $(this).remove(); });
                } else {
                    tip.remove();
                }
            }, 100);
        });
    };
})(jQuery);

(function($) { $.fn.autogrow = function(options) {
    /*
     * Auto-growing textareas; technique ripped from Facebook
	 * http://onehackoranother.com/projects/jquery/jquery-grab-bag/
     */
        this.filter('textarea').each(function() {
            var $this       = $(this),
                minHeight   = $this.height(),
                lineHeight  = $this.css('lineHeight');
            var shadow = $('<div></div>').css({
                position:   'absolute',
                top:        -10000,
                left:       -10000,
                width:      $(this).width() - parseInt($this.css('paddingLeft')) - parseInt($this.css('paddingRight')),
                fontSize:   $this.css('fontSize'),
                fontFamily: $this.css('fontFamily'),
                lineHeight: $this.css('lineHeight'),
                resize:     'none'
            }).appendTo(document.body);
            var update = function() {
                var times = function(string, number) {
                    for (var i = 0, r = ''; i < number; i ++) r += string;
                    return r;
                };
                var val = this.value.replace(/</g, '&lt;')
                                    .replace(/>/g, '&gt;')
                                    .replace(/&/g, '&amp;')
                                    .replace(/\n$/, '<br/>&nbsp;')
                                    .replace(/\n/g, '<br/>')
                                    .replace(/ {2,}/g, function(space) { return times('&nbsp;', space.length -1) + ' ' });
                shadow.html(val);
                $(this).css('height', Math.max(shadow.height() + 20, minHeight));
            }
            $(this).change(update).keyup(update).keydown(update);
            update.apply(this);
        });
        return this;
    }
})(jQuery);

(function ($) { $.fn.inputHint = function(options) {
	/* ------------------------------------------------------------------------
	 * Initialise input hints on all matched inputs.
	 *
	 * Usage examples:
	 *
	 * Add hints to all inputs with the 'title' attribute set:
	 *   $('input[title],textarea[title]').inputHint();
     *
     * Add hints to all matched elements, grabbing the hint text from each element's
     * adjacent <kbd/> tag:
     *   $('input').inputHint({using: '+ kbd'});
	 *
	 * Options keys:
	 *  using: jQuery selector locating element containing hint text, relative to
	 *         the input currently being considered.
	 *  hintAttr - tag attribute containing hint text. Default: 'title'
	 *  hintClass - CSS class to apply to inputs with active hints. Default: 'hint'
	 ------------------------------------------------------------------------
	 * (c) 2008-9 Jason Frame
	 * Auxiliary element code based on work by pjesi (http://wtf.hax.is/)
	 * http://onehackoranother.com/projects/jquery/jquery-grab-bag/
	 ------------------------------------------------------------------------ */
		options = $.extend({hintClass: 'hint', hintAttr: 'title'}, options || {});
		function hintFor(element) {
			var h;
			if (options.using && (h = $(options.using, element)).length > 0) {
				return h.text();
			} else {
				return $(element).attr(options.hintAttr) || '';
			}
		}
		function showHint() {
			if ($(this).val() == '') {
				$(this).addClass(options.hintClass).val(hintFor(this));
			}
		}
		function removeHint() {
			if ($(this).hasClass(options.hintClass)) $(this).removeClass(options.hintClass).val('');
		}
		this.filter(function() { return !!hintFor(this); })
			.focus(removeHint).blur(showHint).blur();
        this.each(function() {
            var self = this;
            $(this).parents('form').submit(function() { removeHint.apply(self); });
        });
		return this.end(); // undo filter
	};
})(jQuery);

$.accordian = function(items, first, options) {
	/* ------------------------------------------------------------------------------------
	Accordian für die Top-Events auf der HOME.ASP
	
	Quelle:
	http://fmarcia.info/jquery/accordion.html
	------------------------------------------------------------------------------------ */
	var active = first;
	var running = 0;
	var titles = options && options.titles || '.title';
	var contents = options && options.contents || '.content';
	var onClick = options && options.onClick || function(){};
	var onShow = options && options.onShow || function(){};
	var onHide = options && options.onHide || function(){};
	var showSpeed = options && options.showSpeed || 'slow';
	var hideSpeed = options && options.hideSpeed || 'fast';
	$(items).not(active).children(contents).hide();
	$(items).not(active).each(onHide);
	$(active).each(onShow);
	$(items).children(titles).click(function(e){
		var p = $(contents, this.parentNode);
		$(this.parentNode).each(onClick);
		if (running || !p.is(":hidden")) return false;
		running = 2;
		$(active).children(contents).not(':hidden').slideUp(hideSpeed, function(){--running;});
		p.slideDown(showSpeed, function(){--running;});
		$(active).each(onHide);
		active = '#' + $(this.parentNode)[0].id;
		$(active).each(onShow);
		return false;
	});
};

var flower_bubble = function ( options ) {
	/* ------------------------------------------------------------------------------------
	 * jquery flower bubble
	 * blocks and tints the screen, draws a bubble and a flower inside of it
	 *
	 * @author Oktay Acikalin ( ok@ryotic.de )
	 * @version 0.4
	 * @license MIT / GPL v2
	 * @copyright Oktay Acikalin, 7 October, 2008
	 * @package jquery_flower_bubble
	------------------------------------------------------------------------------------ */
	// begin: define defaults
	this . defaults = {
		base_obj: null, // which (jquery-)object to block
		container_id: 'flower_bubble_container',
		fade_speed: 250,
		zindex: 2000,
		// full = start at base_obj.top and cover whole screen
		// base_obj = only block this specific object
		block_mode: 'full',
		// block_mode: 'base_obj',
		base_dir: 'images',
		background: { css: 'white', opacity: 0.5 },
		bubble: { image: 'bubble.png', width: 'auto', height: 'auto' },
		flower: { image: 'flower.gif', width: 'auto', height: 'auto' }
	} ;
	// end: define defaults
	// begin: add some timestamp to the id to make it quite unique
	var t = new Date () ;
	this . defaults . container_id += '_' + t . getTime () ;
	// end: add some timestamp to the id to make it quite unique
	// begin: define container vars
	this . base_obj ;
	this . container_id ;
	this . fade_speed ;
	this . zindex ;
	this . block_mode ;
	this . base_dir ;
	this . background ;
	this . bubble ;
	this . flower ;
	// end: define container vars
	// begin: setup container vars
	jQuery . extend ( this . defaults, options ) ;
	jQuery . extend ( this, this . defaults ) ;
	// end: setup container vars
	// begin: preload images
	var bubble_img = $( '<img src="' + this . base_dir + '/' + this . bubble . image + '">' ) ;
	var flower_img = $( '<img src="' + this . base_dir + '/' + this . flower . image + '">' ) ;
	if ( this . bubble . width == 'auto' || this . bubble . width == undefined )
		this . bubble . width = bubble_img . get ( 0 ) . width ;
	if ( this . bubble . height == 'auto' || this . bubble . height == undefined )
		this . bubble . height = bubble_img . get ( 0 ) . height ;
	if ( this . flower . width == 'auto' || this . flower . width == undefined )
		this . flower . width = flower_img . get ( 0 ) . width ;
	if ( this . flower . height == 'auto' || this . flower . height == undefined )
		this . flower . height = flower_img . get ( 0 ) . height ;
	// end: preload images
	this . flowers = 0 ; // unblock will only occur if no flowers are left
	// block ui and show flower
	this . enable = function ()
	{
		this . flowers++ ;
		if ( $( 'body > div#' + this . container_id ) . length != 0 ) return ;
		var pos = this . base_obj . offset () ;
		
		var container = $( '<div></div>' ) ;
		container . attr ( 'id', this . container_id ) ;
		container . css ({
			position: 'absolute',
			'z-index': this . zindex,
			top: pos . top,
			left: 0,
			width: '100%',
			overflow: 'hidden',
			height: Math . max ( $( window ) . height (), $( 'body' ) . height () ) - pos . top
		}) ;
		if ( this . block_mode == 'base_obj' )
		{
			container . css ({
				left: pos . left,
				width: this . base_obj . width (),
				height: this . base_obj . height ()
			}) ;
		}
		container . hide () ;
		
		var background = $( '<div></div>' ) ;
		background . css ({
			position: 'absolute',
			width: '100%',
			height: '100%',
			background: this . background . css,
			opacity: this . background . opacity
		}) ;
		container . append ( background ) ;
		
		var bubble = $( '<div></div>' ) ;
		bubble . css ({
			position: 'relative',
//			background: 'url("' + bubble_img . attr ( 'src' ) + '") no-repeat',
			width: this . bubble . width,
			height: this . bubble . height
		}) ;
		var flower = flower_img ;
		flower . css ({
			position: 'relative',
			left: this . bubble . width / 2 - this . flower . width / 2,
			top: this . bubble . height / 2 - this . flower . height / 2 - 2
		}) ;
		flower . mousedown ( function () { return false ; } ) ;
		bubble . append ( flower ) ;
		container . append ( bubble ) ;
		
		$( 'body' ) . append ( container ) ;
		
		bubble . css ( 'left', container . width () / 2 - this . bubble . width / 2 ) ;
		bubble . css ( 'top', container . height () / 2 - this . bubble . height / 2 ) ;
		
		if ( container . pngFix )
		  container . pngFix () ;
		
		container . mousedown ( function () { return false ; } ) ;
		container . fadeIn ( this . fade_speed ) ;
	}
	// unblock ui
	this . disable = function ()
	{
		if ( $( 'body > div#' + this . container_id ) . length == 0 ) return ;
		this . flowers = Math . max ( 0, this . flowers - 1 ) ;
		if ( this . flowers > 0 ) return ;
		
		$( 'body > div#' + this . container_id ) . fadeOut ( this . fade_speed, function () {
			$( this ) . remove () ;
		} ) ;
	}
}
