// this is an alternative for livequery, which can be quite ressource consuming,
// escpecially with ie6 and when we're using many components and much dynamically loaded 
// content (ajax). livequery proxies calls to append, prepend, ... which is incompatible with
// other javascript libraries - that could become a problem with ruby on rails, for example, 
// because rails is using prototype
//
// you register a component for a selection like 
//	$(".popup-menu").alive($.fn.popupMenu);
// or
//	$(".popup-menu").alive(function() { $(this).popupMenu(); ... });
// if you inject dynamic (ajax) content like
// 	<div id="ajax-wrapper"><div class="popup-menu">..</div></div>
// from a script, just add one line to your content
//	$("#ajax-wrapper").alive();
//
// that's it. it's not as elegant as livequery, but its more compatible and much faster.
// I guess one extra line of code is worth it depending on your needs. For very small sites i would prefer
// livequery.

(function($) {
	$.fn.alive = function(fn) {
		if(fn) {
			var self = this;
			
			if($.fn.alive.lives == null)
				$.fn.alive.lives = [];

			$.fn.alive.lives.push(
				function(el) {
					var elements = $(el).find(self.selector).add($(el).filter(self.selector));

					if(elements.size() > 0)
						fn.apply(elements);
				}
			);

			fn.apply($(this.selector));
		} else {
			var self = this;

			if($.fn.alive.lives) {
				$.each(
					$.fn.alive.lives,
					function() {
						var fn = this;

						fn($(self));
					}
				);
			}
		}

		return this;
	}

	$(window).unload(
		function() {
			// fix ie memory leak

			$.fn.alive.lives = null;
		}
	);
})(jQuery);

// call it for an input field for example $("input").autocomplete([options]);

(function($) {
	$.fn.autocomplete = function(options) {
		var settings = $.extend({ timeout: 300, selector: null, trigger: null, min: 3, trim: true }, options);

		return this.each(
			function() {
				var self = this;

				var value = $(this).val();	

				var selection = null; // selection index in list (changed through keydown events)

				// a user clicks an item

				$(settings.selector + " li").live(
					"mousedown",
					function(e) {
						if(settings.trigger != null)
							e.preventDefault();

						select_index($.inArray(this, $(settings.selector).find("li")), true);
		
						if(settings.trigger != null) // trigger specified event to form
							$(self).closest("form").trigger(settings.trigger);
					}
				);

				// user moves over an item

				$(settings.selector + " li").live(
					"mouseover",
					function() {
						select_index($.inArray(this, $(settings.selector).find("li")), false);
					}
				);	

				// check whether list is empty or not

				var listIsEmpty = function() {
					return $(settings.selector).find("li").size() == 0;
				}

				var hideOrShowList = function() {
					if(listIsEmpty() || $(self).val().length < settings.min)
						$(settings.selector).empty().hide();
					else
						$(settings.selector).positionRelativeY(self).show();
				}

				// hide the element if user clicks anywhere

				$("body").click( 
					function(e) {
						$(settings.selector).empty();

						hideOrShowList();
					}
				);

				var update = function() {
					value = $(self).val();

					if(value.length >= settings.min) {
						$(self).startLoading({ xOffset: 5, xPosition: "right" });

						$.ajax({ 
							data: $.param($(self)), 
							type: "get",
							url: settings.url,
							error: function() {
								$(settings.selector).empty();
							},
							success: function(html) {
								$(settings.selector).html(html);

								selection = null; // reset selection to "no element selected"
							},
							complete: function() {
								$(self).stopLoading();
		
								hideOrShowList();
							}
						}); 
					}

					hideOrShowList();
				}

				// select specific item

				var select_index = function(index, set_value) {
					selection = index;

					$(settings.selector).find("li").removeClass("autocomplete-selected");

					$(settings.selector).find("li:eq(" + selection + ")").addClass("autocomplete-selected");

					if(!listIsEmpty() && set_value) {
						value = $(settings.selector).find("li:eq(" + selection + ") .autocomplete-value").text();

						if(settings.trim)
							value = $.trim(value);

						$(self).setObservedValue(value);

						$(self).val(value);
					}
				}

				// select an element from the list, jumping offset elements from current

				var select_offset = function(offset) {
					var index = selection;

					if(index == null)
						index = 0;
					else
						index += offset;

					index += $(settings.selector).find("li").size();
					index %= $(settings.selector).find("li").size();
		
					select_index(index, true);
				}

				$(self).keydown( // navigate through results
					function(e) {
						switch(e.keyCode){
							case 40: // down
								select_offset(1);
								break;
							case 38: // up
								select_offset(-1);
								break;
						}
					}
				);

				$(this).observeValue(update);
			}
		);
	}
})(jQuery);


(function($) {
	$.fn.autosubmit = function(options) {
		return this.each(
			function() {
				$(this).change(
					function() {
						$(this).closest("form").submit();
					}
				);
			}
		);
	}

	$.fn.autoonsubmit = function(options) {
		return this.each(
			function() {
				$(this).change(
					function() {
						$(this).closest("form").trigger("onsubmit");
					}
				);
			}
		);
	}


	$(document).ready(
		function() {
			$(".autosubmit").alive($.fn.autosubmit);
			$(".autoonsubmit").alive($.fn.autoonsubmit);
		}
	);
})(jQuery);


(function($) {
	$.fn.blink = function() {
		return $(this).each(
			function() {
				$(this).fadeTo(130, 0.2).fadeTo(130, 1);
			}
		);
	}
})(jQuery);


(function($) {
	$.fn.clearValue = function() {
		return this.each(
			function() {
				$(this).attr("data-value", $(this).val());

				$(this).click(
					function() {
						if($(this).attr("data-value") == $(this).val())
							$(this).val("");
					}
				);

				$(this).blur(
					function() {
						if($(this).val() == "")
							$(this).val($(this).attr("data-value"));
					}
				);
			}
		);
	}

	$(document).ready(
		function() {
			$(".clear-value").alive($.fn.clearValue);
		}
	);
})(jQuery);

/**
 * Cookie plugin
 *
 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

/**
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 *       used when the cookie was set.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Get the value of a cookie with the given name.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};
(function($) {
	$.defaultValue = function(value, default_value) {
		if(value == "" || value == null)
			return default_value;

		return value;
	}
})(jQuery);


(function($) {
	$.fn.delay = function( time, name ) {

	    return this.queue( ( name || "fx" ), function() {
		var self = this;
		setTimeout(function() { $(self).dequeue(); } , time );
	    } );

	};
})(jQuery);


(function($) {
	$.hideDescriptions = function() {
		$("#description").remove();
	}

	$.fn.description = function() {
		$(this).hover(
			function() {
				var self = this;

				if($("#description").size() == 0 || $("#description").get(0).trigger != this) {
					$.hideDescriptions();

					$("body").append("<div id='description'><p id='description-content'></p></div>");

					$("#description").mouseout(
						function(e) {
							if(!$.mouseIsOver(self, e))
								$.hideDescriptions();
						}
					);

					$("#description").get(0).trigger = this;

					$("#description").css("opacity", 0.75);

					var description = $(this).attr("data-description");

					$("#description-content").html(description);

					$("#description")
						.css("width", $(this).outerWidth())
						.positionWithin(this, { xPosition: "left", yPosition: "bottom" })
						.fadeIn("slow");
				}
			},
			function(e) {
				if(!$.mouseIsOver("#description", e))
					$.hideDescriptions();
			}
		);
	}

	$(document).ready(
		function() {
			$("[data-description]").alive($.fn.description);
		}
	);
})(jQuery);


(function($) {
	$.hideDialogs = function() {
		$(".dialog-container").hideDialog();
	}

	$.fn.hideDialog = function() {
		return this.each(
			function() {
				$(this.trigger).removeClass("dialog-visible");

				$(this).hide();
			}
		);
	}

	$.fn.showDialog = function() {
		$.hideDialogs();

		return this.each(
			function() {
				$(this.trigger).addClass("dialog-visible");

				$(this).positionRelativeY(this.trigger).fadeIn("fast");
			}
		);
	}

	$.fn.toggleDialog = function() {
		$(this).click(
			function(e) {
				e.preventDefault();

				var dialog = $("#" + $(this).attr("data-id"));

				if(dialog.get(0))
					dialog.get(0).trigger = this;

				if(dialog.is(":visible"))
					dialog.hideDialog();
				else
					dialog.showDialog();
			}
		);
	}

	$.fn.dialogContainer = function() {
		$(this).click(
			function(e) {
				if($(e.target).hasClass("hide-dialog"))
					$(this).hideDialog();
			}
		);

		$(this).submit(
			function(e) {
				if($(e.target).closest("form").hasClass("hide-dialog"))
					$(this).hideDialog();
			}
		);
	}

	$(document).ready(
		function() {
			$(".toggle-dialog").alive($.fn.toggleDialog);
			$(".dialog-container").alive($.fn.dialogContainer);

			$("body").click(
				function(e) {
					var dialog = $(e.target).closest(".dialog-container");
					var toggle_dialog = $(e.target).closest(".toggle-dialog");
					
					if(dialog.size() == 0 && toggle_dialog.size() == 0)
						$.hideDialogs();
				}
			);

			$(window).scroll(
				function() {
					$(".dialog-container").hideDialog();
				}
			);
		}
	);
})(jQuery);


(function($) {
	$(document).ready(
		function() {
			$(".disable-radio").click(
				function() {
					var self = this;

					$(".disable-radio").each(
						function() {
							if($(this).attr("name") == $(self).attr("name")) {
								$("." + $(this).attr("data-class")).attr("disabled", "true");
							}
						}
					);

					$("." + $(this).attr("data-class")).removeAttr("disabled");
				}
			);
		}
	);
})(jQuery);


(function($) {
	$.fadeBackground = function(options) {
		var settings = $.extend({ opacity: 0.5 }, options);

		$("#background").positionFullscreen().css("opacity", settings.opacity).show();
	}

	$.showBackground = function() {
		$("#background").hide();
	}

	$.getBackground = function() {
		return $("#background");
	}

	$(document).ready(
		function() {
			$("body").append("<div id='background'></div>");
		}
	);

	$(window).resize(
		function() {
			$("#background").positionFullscreen();
		}
	);
})(jQuery);


(function($) {
	$.fn.formOption = function(options) {
		var settings = $.extend({ hidden: null, trigger: null, value: "" }, options);
	
		$(this).click(
			function(e) {
				e.preventDefault();

				$("#" + settings.hidden).val(settings.value);

				if(settings.trigger && settings.trigger != "")
					$("#" + settings.hidden).closest("form").trigger(settings.trigger);
			}
		);
	}

	$(document).ready(
		function() {
			$(".form-option").alive(
				function() {
					this.each(
						function() {
							$(this).formOption({ hidden: $(this).attr("data-id"), trigger: $(this).attr("data-trigger"), value: $(this).attr("data-value") });
						}
					);
				}
			);
		}
	);
})(jQuery);


(function($) {
	$.fn.groupNotify = function(f) {
		this.each(
			function() {
				this.groupNotify = f;
			}
		);

		return $(this);
	}

	$.fn.groupSelectItem = function(id, value, text) {
		return this.each(
			function() {
				this.selectItem(id, value, text);
			}
		);
	}

	$.fn.groupUpdate = function() {
		this.each(
			function() {
				this.update();
			}
		);

		return $(this);
	}

	$.fn.groupSelect = function(values) {
		return this.each(
			function() {
				var selection = {};
				var keys = [];

				if(values.length == 0) // error: no values
					return;

				for(var key in values[0]) { // get array of keys that have attribute 'value' and attribute 'text'
					if(values[0][key].value && values[0][key].text)
						keys.push(key);
				}
				
				var self = this; // copy of this pointer
				
				this.groupNotify = function() {} // dummy

				// capture change event of select field and update all other select fields

				$(this).find("select").change(
					function() {
						selection[this.id] = { value: $(this).val(), text: $(this).find("option:selected").text() };

						var index = $.inArray(this.id, keys);

						for(var i = index + 1; i < keys.length; i++)
							selection[keys[i]] = null;

						self.update(this.id);
					}
				);

				// check if value corresponds to selection 

				var isValidValue = function(value, selection, k) {
					for(var index in keys) {
						var key = keys[index];

						if(key == k)
							return true;

						if(selection[key] != null && value[key].value != selection[key].value)
							return false;
					}

					return true;
				}

				this.selectItem = function(id, value, text) {
					selection[id] = { value: value, text: text };
				}

				this.update = function(except) {
					var sel = {};

					for(var key in selection) // copy the current selection 
						sel[key] = selection[key];

					for(var index in keys) {
						var key = keys[index];

						if(key != except) {
							$(self).find("#" + key).empty();

							var valid_values = [];
							var valid_hash = {};
								
							$.each(values,
								function() {
									if(isValidValue(this, sel, key)) { // valid value ?
										// add this value to the select field if it is not in hash already

										if(valid_hash[this[key].value] == null) {
											$("#" + key).append("<option value='" + this[key].value + "'>" + this[key].text + "</option>");

											valid_values.push(this);

											valid_hash[this[key].value] = this[key];
										}
									}
								}
							);

							// choose a random valid value for the temporary selection

							if(sel[key] == null && valid_values.length != 0)
								sel[key] = valid_values[0][key];
				
							// set selection (delayed cause of ie6 bug)

							$("#" + key + " option[value=" + sel[key].value + "]").timeout( 
								function() {
									$(this).attr("selected", "selected");
								}
							);
						}
					}

					for(var index in values) { // send the first value corresponding to sel to groupNotify
						var value = values[index];

						if(isValidValue(value, sel)) {
							self.groupNotify(value);
			
							break;
						}
					}
				}
			}
		);
	}
})(jQuery);


(function($) {
	$.showHint = function(html, options) {
		var settings = $.extend({ xOffset: 15, yOffset: 15, delay: 1000 }, options);

		$.hideHints();

		$("#hint").html(html);

		$("#hint")
			.positionLargestQuad(null, { xOffset: settings.xOffset, yOffset: settings.yOffset })
			.show()
			.delay(1000)
			.hide(1);
	}

	$.hideHints = function() {
		$("#hint").hide();
	}

	$.fn.hint = function() {
		$(this).click(
			function() {
				var hint = $(this).attr("data-hint");

				$.showHint(hint);
			}
		);
	}

	$(document).ready(
		function() {
			$("[data-hint]").alive($.fn.hint);

			$("body").append("<div id='hint'></div>");
		}
	);
})(jQuery);


(function($) {
	$.preloadImage = function(src) {
		if(src != null && src != "") {
			var tmp = new Image();

			tmp.src = src;

			return tmp;
		}
	}

	$.fn.cssBackgroundImage = function() {
		return $(this).css("background-image").replace(/^\s*url\s*\(\s*["']?|["']?\s*\)\s*$/ig, "");
	}

	$.fn.loadBackgroundImage = function() {
		$.preloadImage($(this).cssBackgroundImage());
	}
})(jQuery);


(function($) {
	$.fn.imagezoom = function() {
		return this.each(
			function() {
				var self = this;

				$(this).mouseover(
					function(e) {
						var content = $("<div id='imagezoom'><img src='" + $(this).attr("data-zoomimage") + "' /></div>");

						var image = content.find("img");

						$("body").append(content);

						content.positionOver(this).show();

						content.mouseout(
							function(e) {
								if(!$.mouseIsOver(content, e))
									content.hide().remove();
							}
						);

						content.find("img").mouseout(
							function() {
								content.hide().remove();
							}
						);

						var scrollTo = function(e) {
							var scroll_width = image.outerWidth() - content.outerWidth();
							var scroll_height = image.outerHeight() - content.outerHeight();

							var x_image = ((e.pageX - $(self).offset().left) / $(self).outerWidth()) * scroll_width;
							var y_image = ((e.pageY - $(self).offset().top) / $(self).outerHeight()) * scroll_height;

							content
								.scrollLeft(x_image)
								.scrollTop(y_image);
						}
	
						content.mouseover( // initial scrolling
							function(e) {
								scrollTo(e);
							}
						);

						content.find("img").mouseover(
							function(e) {
								scrollTo(e);
							}
						);

						content.find("img").mousemove( // continuous scrolling
							function(e) {
								scrollTo(e);
							}
						);
					}
				);
			}
		);
	}

	$(document).ready(
		function() {
			$("[data-zoomimage]").alive($.fn.imagezoom);
		}
	);
})(jQuery);


(function($) {
	$.fn.startLoading = function(options) {
		$(this).stopLoading();

		return this.each(
			function() {
				this.loading = $("<div class='loading'></div>");

				$("body").append(this.loading);

				$(this.loading).positionWithin(this, options).show();
			}
		);
	}

	$.fn.stopLoading = function() {
		 return this.each(
			function() {
				if(this.loading)
					$(this.loading).remove();
			}
		 );
	}
})(jQuery);


(function($) {
	$.mouseIsOver = function(elem, e) {
		var x = $.getMouseX();
		var y = $.getMouseY();

		if(e) {
			x = e.pageX;
			y = e.pageY;
		}

		return x >= $(elem).offset().left && x < $(elem).offset().left + $(elem).outerWidth() &&
			y >= $(elem).offset().top && y < $(elem).offset().top + $(elem).outerHeight();
	}

	$.getMouseX = function() {
		return $("body").getMouseX();
	}

	$.getMouseY = function() {
		return $("body").getMouseY();
	}

	$.fn.getMouseX = function() {
		var x = 0;

		this.each(
			function() { 
				x = this.mouse_x;
			}
		);
		
		return x;
	}

	$.fn.getMouseY = function() {
		var y = 0;

		this.each(
			function() {
				y = this.mouse_y;
			}
		);

		return y;
	}

	$.fn.observeMouse = function() {
		return this.each(
			function() {
				var self = this;

				self.mouse_x = 0;
				self.mouse_y = 0;

				$(this).mousemove(
					function(e) {
						self.mouse_x = e.pageX;
						self.mouse_y = e.pageY;
					}
				);

				$(this).click(
					function(e) {
						self.mouse_x = e.pageX;
						self.mouse_y = e.pageY;
					}
				);

				$(this).mousedown(
					function(e) {
						self.mouse_x = e.pageX;
						self.mouse_y = e.pageY;
					}
				);
			}
		);
	}

	$(document).ready(
		function() {
			$("body").observeMouse();
		}
	);
})(jQuery);


(function($) {
	$.fn.setObservedValue = function(value) {
		return this.each(
			function() {
				this.observed_value = value;
			}
		);
	}

	$.fn.observeValue = function(fn, options) {
		var settings = $.extend({ timeout: 300 }, options);
	
		return this.each(
			function() {
				var self = this;

				this.observed_value = $(this).val();

				var observe = function() {
					var new_value = $(self).val();

					if(self.observed_value != new_value) {
						self.observed_value = new_value;

						fn.apply(self);
					}

					setTimeout(observe, settings.timeout);
				}
		
				setTimeout(observe, settings.timeout);
			}
		);
	}
})(jQuery);


// popup-menu when user hovers over somehting containing class .popup-menu

(function($) {
	$.fn.showPopupMenu = function(options) {
		var settings = $.extend({ position: "none" }, options);

		return this.each(
			function() {
				$(this.trigger).addClass("popup-menu-visible");

				if(settings.position != "y")
					$(this).positionRelativeX(this.trigger, settings).show();
				else
					$(this).positionRelativeY(this.trigger, settings).show();
			}
		);
	}

	$.hidePopupMenus = function() {
		$(".popup-menu-container").hidePopupMenu();
	}

	$.fn.hidePopupMenu = function() {
		return this.each(
			function() {
				$(this.trigger).removeClass("popup-menu-visible");

				$(this).hide();
			}
		);
	}

	$.fn.popupMenu = function() {
		$(this).hover(
			function(e) {
				$.hidePopupMenus();

				var popup_menu = $("#" + $(this).attr("data-id"));

				if(popup_menu.get(0))
					popup_menu.get(0).trigger = this;

				popup_menu.showPopupMenu({ position: $(this).attr("data-position") });
			},
			function(e) {
				var popup_menu = $("#" + $(this).attr("data-id"));

				if(!$.mouseIsOver(popup_menu, e))
					popup_menu.hidePopupMenu();
			}
		);	

		return this.each(
			function() {
				var self = this;

				var popup_menu = $("#" + $(this).attr("data-id"));
	
				popup_menu.mouseleave(
					function(e) {
						if(!$.mouseIsOver(self, e))
							popup_menu.hidePopupMenu();
					}
				);

			}
		);
	}

	$(document).ready(
		function() {
			$(".popup-menu").alive($.fn.popupMenu);
		}
	);
})(jQuery);


// we add target="_popup" to open a popup window

(function($) {
	$.fn.popupWindow = function() {
		$(this).click(
			function(e) {
				e.preventDefault();

				var windowWidth = $.defaultValue($(this).attr("data-width"), 800);
				var windowHeight = $.defaultValue($(this).attr("data-height"), 600);
				var windowToolbar = $.defaultValue($(this).attr("data-toolbar"), "no");
				var windowLocation = $.defaultValue($(this).attr("data-location"), "yes");
				var windowStatus = $.defaultValue($(this).attr("data-status"), "yes");
				var windowMenubar = $.defaultValue($(this).attr("data-menubar"), "no");
				var windowScreenX = $.defaultValue($(this).attr("data-screen-x"), "100");
				var windowScreenY = $.defaultValue($(this).attr("data-screen-y"), "100");
				var windowScrollbars = $.defaultValue($(this).attr("data-scrollbars"), "yes");

				var popup = window.open(
					$(this).attr("href"), 
					$(this).attr("data-title"), 
					"width="+windowWidth+",height="+windowHeight+",toolbar="+windowToolbar+",location="+windowLocation+",status="+windowStatus+",menubar="+windowMenubar+",screenX="+windowScreenX+",screenY="+windowScreenY+",scrollbars="+windowScrollbars
				);

				if(popup)
					popup.focus();
			}
		);
	}

	$(document).ready(
		function() {
			$("[target=_popup]").alive($.fn.popupWindow);
		}
	);
})(jQuery);


// display a dialog in center of screen with dark background
// there'll always be only one popup visible at a time

(function($) {
	$.hidePopups = function() {
		$(".popup-container").hidePopup();
	}

	$.fn.removePopup = function() {
		$(this).remove();
	}

	$.fn.hidePopup = function() {
		$(this).removePopup();

		if($(this).size() > 0)
			$.showBackground();
	}

	$.fn.showPopup = function(options) {
		var settings = $.extend({ background_opacity: 0.5 }, options);

		if($(this).size() > 0)
			$.fadeBackground({ opacity: settings.background_opacity });

		var self = this;

		$.each( // hide other popups
			$(".popup-container"),
			function() {
				if($.inArray(this, $(self)) == -1)
					$(this).removePopup();
			}
		);

		$(this).positionCenter().show();
	}

	$.fn.popup = function() {
		$(this).find("img").load(
			function() {
				$(this).closest(".popup-container").positionCenter();
			}
		);

		$(this).find(".hide-popup:not(form)").click(
			function(e) {
				e.preventDefault();
			
				$(this).closest(".popup-container").hidePopup();

				$.showBackground();
			}
		);

		$(this).find("form").submit(
			function(e) {
				$(this).closest(".popup-container").hide(); // can't use hidePopup cause then it's removed and the form can't be sent

				$.showBackground();
			}
		);


		$(this).positionCenter();
	}

	$(document).ready(
		function() {
			$(".popup-container").alive($.fn.popup);

			$("body").click(
				function(e) {
					var popup_container = $(e.target).closest(".popup-container");

					if(popup_container.size() == 0) 
						$(".popup-container").hidePopup();
				}
			);

			$(window).keydown(
				function(e) {
					if(e.keyCode == 27) {
						if($(".popup-container").is(":visible"))
							$(".popup-container").hidePopup();
					}
				}
			);
		}
	);
})(jQuery);


(function($) {
	// position fullscreen (including scrollareas)

	$.fn.positionFullscreen = function() {
		return this.each(
			function() {
				$(this)
					.css("left", "0px")
					.css("top", "0px")
					.css("width", $(document).width())
					.css("height", $(document).height());
			}
		);
	}

	// position elements over other element

	$.fn.positionOver = function(selector) {
		return this.each(
			function() {
				var sel = $(selector);

				$(this)
					.css("left", sel.offset().left)
					.css("top", sel.offset().top)
					.css("width", sel.outerWidth())
					.css("height", sel.outerHeight());
			}
		);
	}

	$.fn.positionWithin = function(elem, options) {
		return this.each(
			function() {
				var settings = $.extend({ xOffset: 0, yOffset: 0, xPosition: "center", yPosition: "center" }, options);
				
				if(settings.xPosition == "left")
					$(this).css("left", $(elem).offset().left + settings.xOffset);
				else if(settings.xPosition == "right")	
					$(this).css("left", $(elem).offset().left + $(elem).outerWidth() - $(this).outerWidth() - settings.xOffset);
				else // center
					$(this).css("left", $(elem).offset().left + $(elem).outerWidth() / 2 - $(this).outerWidth() / 2);
	
				if(settings.yPosition == "top")
					$(this).css("top", $(elem).offset().top + settings.yOffset);
				else if(settings.yPosition == "bottom")	
					$(this).css("top", $(elem).offset().top + $(elem).outerHeight() - $(this).outerHeight() - settings.yOffset);
				else // center
					$(this).css("top", $(elem).offset().top + $(elem).outerHeight() / 2 - $(this).outerHeight() / 2);
			}
		);
	}

	// position at center of screen

	$.fn.positionCenter = function() {
		return this.each(
			function() {
				var leftPos = $(window).scrollLeft() + $(window).width() / 2 - $(this).outerWidth() / 2;
				var topPos = $(window).scrollTop() + $(window).height() / 2 - $(this).outerHeight() / 2;

				leftPos = Math.max(leftPos, $(window).scrollLeft());
				topPos = Math.max(topPos, $(window).scrollTop());

				$(this)
					.css("left", leftPos)
					.css("top", topPos);
			}
		);
	}

	$.fn.positionCenterIn = function(elem) {
		return this.each(
			function() {
				$(this)
					.css("left", $(elem).offset().left + $(elem).outerWidth() / 2 - $(this).outerWidth() / 2)
					.css("top", $(elem).offset().top + $(elem).outerHeight() / 2 - $(this).outerHeight() / 2);
			}
		);
	}

	$.fn.positionBottom = function() {
		return this.each(
			function() {
				$(this).css("top", $(window).height() + $(window).scrollTop() - $(this).outerHeight());
			}
		);
	}

	// position on/under an element
	// xOffset, yOffset

	$.fn.positionRelativeY = function(elem, options) {
		return this.each(
			function() {
				var settings = $.extend({ xOffset: 0, yOffset: 0, centered: false, force_y_position: "none" }, options);

				var x_rel = $(elem).offset().left + $(elem).outerWidth() / 2 - $(window).scrollLeft();
				var y_rel = $(elem).offset().top + $(elem).outerHeight() / 2 - $(window).scrollTop();

				var x_pos = 0;

				if(x_rel < $(window).width() / 2)
					x_pos = $(elem).offset().left + settings.xOffset;
				else 
					x_pos = $(elem).offset().left - $(this).outerWidth() + $(elem).outerWidth() - settings.xOffset;

				// be sure we dont move it out the screen, prefer moving it out to the right than to left
			
				if(x_pos + $(this).outerWidth() > $(window).scrollLeft() + $(window).width())
					x_pos = ($(window).scrollLeft() + $(window).width()) - $(this).outerWidth();

				if(x_pos < $(window).scrollLeft())
					x_pos = $(window).scrollLeft();

				if(settings.centered)
					$(this).css("left", $(elem).offset().left + $(elem).outerWidth() / 2 - $(this).outerWidth() / 2);
				else
					$(this).css("left", x_pos);

				if(y_rel < $(window).height() / 2 && settings.force_y_position != "top" || settings.force_y_position == "bottom")
					$(this).css("top", $(elem).offset().top + $(elem).outerHeight() + settings.yOffset);
				else
					$(this).css("top", $(elem).offset().top - $(this).outerHeight() - settings.yOffset);
			}
		);
	}

	// position beside an element (left or right from it)
	// xOffset, yOffset

	$.fn.positionRelativeX = function(elem, options) {
		return this.each( 
			function() {
				var settings = $.extend({ xOffset: 0, yOffset: 0, centered: false, force_x_position: "none" }, options);

				var x_rel = $(elem).offset().left + $(elem).outerWidth() / 2 - $(window).scrollLeft();
				var y_rel = $(elem).offset().top + $(elem).outerHeight() / 2 - $(window).scrollTop();

				if(x_rel < $(window).width() / 2 && settings.force_x_position != "left" || settings.force_x_position == "right")
					$(this).css("left", $(elem).offset().left + $(elem).outerWidth() + settings.xOffset);
				else
					$(this).css("left", $(elem).offset().left -$(this).outerWidth() - settings.xOffset);

				var y_pos = 0;

				if(y_rel < $(window).height() / 2)
					y_pos = $(elem).offset().top + settings.yOffset;
				else
					y_pos = $(elem).offset().top - $(this).outerHeight() + $(elem).outerHeight() - settings.yOffset;

				// be sure we dont move it out the screen, prefer moving it down than up

				if(y_pos + $(this).outerHeight() > $(window).scrollTop() + $(window).height())
					y_pos = ($(window).scrollTop() + $(window).height()) - $(this).outerHeight();

				if(y_pos < $(window).scrollTop())
					y_pos = $(window).scrollTop();

				if(settings.centered)
					$(this).css("top", $(elem).offset().top + $(elem).outerHeight() / 2 - $(this).outerHeight() / 2);
				else
					$(this).css("top", y_pos);
			}
		);
	}

	// position in largest quad relative to mouse
	// options include:
	//	xOffset: x-distance from mouse
	//	yOffset: y-distance from mouse

	$.fn.positionLargestQuad = function(e, options) {
		return this.each(
			function() {
				var x = 0;
				var y = 0;

				if(e == null) { // get mouse position from mouse observer if we don't have an event
					x = $("body").getMouseX();
					y = $("body").getMouseY();
				} else {
					x = e.pageX;
					y = e.pageY;
				}

				var settings = $.extend({ xOffset: 15, yOffset: 15 }, options);
				
				var x_rel = x - $(window).scrollLeft();
				var y_rel = y - $(window).scrollTop();

				if(x_rel < $(window).width() / 2)
					$(this).css("left", x + settings.xOffset);
				else
					$(this).css("left", x - $(this).outerWidth() - settings.xOffset);

				var y_pos = 0;

				if(y_rel < $(window).height() / 2)
					y_pos = y + settings.yOffset;
				else
					y_pos = y - $(this).outerHeight() - settings.yOffset;

				// be sure we dont move it out the screen

				if(y_pos < $(window).scrollTop())
					y_pos = $(window).scrollTop();
				else if(y_pos + $(this).outerHeight() > $(window).scrollTop() + $(window).height())
					y_pos = ($(window).scrollTop() + $(window).height()) - $(this).outerHeight();

				$(this).css("top", y_pos);
			}
		);
	}
})(jQuery);


// uses fade-background and inserts a div #preloading (where a 
// loading animation can be specified as background-image)

(function($) {
	$.startPreloading = function() {
		$.fadeBackground();

		$("#preloading").positionCenter().show();
	}

	$.stopPreloading = function() {
		$.showBackground();

		$("#preloading").hide();
	}

	$.fn.preloading = function() {
		$(this).click(
			function() {
				$.startPreloading();
			}
		);
	}

	$.fn.preloadingSubmit = function() {
		$(this).submit(
			function() {
				$.startPreloading();
			}
		);
	}

	$(document).ready(
		function() {
			$("body").append("<div id='preloading'></div>");

			// preload loading anim if we have one

			$("#preloading").loadBackgroundImage();

			$(".preloading").alive($.fn.preloading);
			$(".preloading-submit").alive($.fn.preloadingSubmit);
		}
	);
})(jQuery);


(function($) {
	var enabled = true;

	$.disablePreview = function() {
		enabled = false;
	}

	$.enablePreview = function() {
		enabled = true;
	}

	$.hidePreviews = function() {
		$("#preview").remove();
	}

	$.fn.hidePreview = function() {
		$(this).removeClass("preview-visible");

		$.hidePreviews();
	}

	$.fn.showPreview = function() {
		var self = this;

		var url = $(this).attr("data-url");

		$.hidePreviews();

		$(this).addClass("preview-visible");

		var max_timeout = 700;

		var t1 = (new Date()).getTime();
		
		$("body").append("<div id='preview'><img src='" + url + "' /></div>");

		$("#preview").find("img").load( // reposition when loading is finished
			function() {
				var t2 = (new Date()).getTime();

				var timeout = max_timeout - (t2 - t1);

				if(timeout < 0)
					timeout = 0;
									
				$("#preview").delay(timeout).positionRelativeX(self).fadeIn("fast");
			}
		);

		$("#preview").delay(max_timeout).positionRelativeX(this).fadeIn("fast");
	}

	$.fn.preview = function() {
		$(this).hover(
			function() {
				if(enabled)
					$(this).showPreview();
			},
			function() {
				$(this).hidePreview();
			}
		);
	}

	$(document).ready(
		function() {
			$(".preview").alive($.fn.preview);

			$("body").click(
				function() {	
					$.hidePreviews();
				}
			);
		}
	);
})(jQuery);


// try to serialize any jquery object like jquery.ui.sortable

(function($) {
	$.fn.serializeIDs = function() {
		var str = [];

		this.each(
			function() {
				var res = $(this).attr("id").match(/(.+)[-=_](.+)/);

				if(res)
					str.push(res[1] + "[]" + "=" + res[2])
			}
		);

		return str.join("&");
	}
})(jQuery);


(function($) {
	$(document).ready(
		function() {
			$(".set-focus").focus();
		}
	);
})(jQuery);


(function($) {
	$.fn.stopAutoplay = function() {
		return this.each(
			function() {	
				this.stopAutoplay();
			}
		);
	}

	$.fn.startAutoplay = function() {
		return this.each(
			function() {
				this.startAutoplay();
			}
		);
	}

	$.fn.slideshow = function(options) {
		var settings = $.extend({ elements: 4, timeout: 3000 }, options);

		return this.each(
			function() {
				// previews: how many previews to show in navi bar
				// period: how long content will stay until next content fades in

				var elements = $(this).find(".navi li").size();

				var current_page = 0;
				var current_element = 0;
				
				var playing = false;

				var self = this;

				$(this).find(".left a").click( // navi bar previous
					function(e) {
						e.preventDefault();
				
						current_page--;
	
						showPage();
	
						self.stopAutoplay();
					}
				);

				$(this).find(".right a").click( // navi bar next
					function(e) {
						e.preventDefault();
				
						current_page++;

						showPage();

						self.stopAutoplay();
					}
				);

				$.each(
					$(".navi li"),
					function(index) {
						$(this).click(
							function() {
								$(self).find(".content li:visible").hide();

								selectElement(index);

								self.stopAutoplay();
							}
						);
					}
				);

				// check which navi elements are neccessary on every change

				var showOrHideNaviElements = function() {
					if(current_page == 0)
						$(self).find(".left").hide();
					else
						$(self).find(".left").show();

					if(havePreview(current_page * settings.elements + settings.elements))
						$(self).find(".right").show();
					else
						$(self).find(".right").hide();
				}

				var havePreview = function(cur) { // do we have content at position: cur
					return cur < elements; 
				}

				var showPage = function(page) {
					$(self).find(".navi li").hide();

					for(var i = current_page * settings.elements; i < (current_page + 1) * settings.elements; i++) {
						if(havePreview(i))
							$(self).find(".navi li").eq(i).show();
					}

					showOrHideNaviElements();
				}

				var changePage = function() {
					var old_page = current_page;

					current_page = parseInt(current_element / settings.elements);

					if(old_page != current_page)
						showPage();
				}

				var selectElement = function(index) {
					current_element = index;

					$(self).find(".content li:visible").hide();

					$(self).find(".content li").eq(current_element).fadeIn("slow");

					$(self).find(".navi li").removeClass("slideshow-current");
					$(self).find(".navi li").eq(current_element).addClass("slideshow-current");
				}

				var autoplay = function() {
					if(playing) {
						selectElement(++current_element);

						changePage();
						
						setTimeout(autoplay, settings.timeout);
					}
				}
		
				this.startAutoplay = function() {
					playing = true;
					
					setTimeout(autoplay, settings.timeout);
				}

				this.stopAutoplay = function() {
					playing = false;
				}

				showPage(current_page);

				selectElement(0);
					
				$(this).find(".content li:first").show();
			}
		);
	}
})(jQuery);


(function($) {
	$.statusmessage = function(html) {
		$(".statusmessage").remove();

		var content = $("<div class='statusmessage'><p class='statusmessage-content'>" + html + "</p></div>");

		$("body").append(content);

		content.click(
			function() {
				$(this).remove();
			}
		);

		content
			.css("top", $(window).scrollTop())
			.css("left", $(window).scrollLeft())
			.delay(100)
			.slideDown("fast")
			.css("opacity", 0.95);

		content.find(".statusmessage-content").delay(500).blink().blink();

		content
			.delay(4000)
			.slideUp("fast", function() { $(this).remove(); });
	}
	
	$.fn.dataStatusmessage = function() {
		$(this).click(
			function() {
				$.statusmessage($(this).attr("data-statusmessage"));
			}
		);
	}

	$.hideStatusmessages = function() {
		$(".statusmessage").slideUp("fast", function() { $(this).remove(); });
	}

	$(document).ready(
		function() {
			$("[data-statusmessage]").alive($.fn.dataStatusmessage);

			$(window).scroll(
				function() {
					$(".statusmessage").remove();
				}
			);
		}
	);
})(jQuery);


(function($) {
	$.fn.switching = function() {
		$(this).hover(
			function() {
				var img = $(this).attr("data-src");
						
				$(this).attr("data-src", $(this).attr("src"));
		
				$(this).attr("src", img);
			},
			function() {
				var img = $(this).attr("data-src");
						
				$(this).attr("data-src", $(this).attr("src"));
		
				$(this).attr("src", img);
			}
		);

		return this.each(
			function() {
				$.preloadImage($(this).attr("data-src"));
			}
		);
	}

	$(document).ready(
		function() {
			$(".switch-src").alive($.fn.switching);
		}
	);
})(jQuery);


(function($) {
	$.fn.tab = function() {
		$(this).click(
			function(e) {
				e.preventDefault();

				$("." + $(this).attr("data-class")).hide();
				$("#" + $(this).attr("data-id")).show();

				$(".tab[data-class=" + $(this).attr("data-class") + "]").removeClass("tab-active");
				
				$(this).addClass("tab-active");
			}
		);
	}

	$(document).ready(
		function() {
			$(".tab").alive($.fn.tab);
		}
	);
})(jQuery);


(function($) {
	// like setTimeout, but with this reference

	$.fn.timeout = function(fn, millis) {
		var m = millis;

		if(m == null)
			m = 1;

		return this.each(
			function() {
				var self = this;

				setTimeout(function() {
					fn.apply(self);
				}, m); 
			}   
		);
	}
})(jQuery);


(function($) {
	$.fn.hideTip = function() {
		return this.each(
			function() {
				if(this.tip)
					$(this.tip).remove();

				this.tip = null;
			}
		);
	}

	$.fn.tip = function(html, options) {
		var settings = $.extend({ orientation: "horizontal", centered: true }, options);

		return this.each(
			function() {
				if(this.tip)
					this.tip.html("<p class='tip-content'>" + html + "</p>");
				else {
					var content = $("<div class='tip'><p class='tip-content'>" + html + "</p></div>");

					content.css("opacity", 0.9);

					$("body").append(content);

					this.tip = content;

					content.show();
					
					if(settings.orientation == "horizontal") {
						content.css("height", $(this).outerHeight());
						content.positionRelativeX(this, settings);
					} else {
						content.css("width", $(this).outerWidth());
						content.positionRelativeY(this, settings);
					}
				}
			}
		);
	}
})(jQuery);


(function($) {
	$.fn.toggle1 = function() {
		$(this).click(
			function(e) {
				e.preventDefault();

				var selector = "#" + $(this).attr("data-id");
				
				if($(selector).is(":visible"))
					$(selector).hide(); 
				else
					$(selector).show();
			}
		);
	}

	$.fn.toggle2 = function() {
		$(this).filter(".toggle-show").click(
			function(e) {
				e.preventDefault();

				var selector = $(this).attr("data-id");

				$("#" + selector).show();

				$(".toggle-hide[data-id=" + selector + "]").show();

				if($(".toggle-hide[data-id=" + selector + "]").size() > 0)
					$(this).hide();
			}
		);

		$(this).filter(".toggle-hide").click(
			function(e) {
				e.preventDefault();

				var selector = $(this).attr("data-id");

				$("#" + selector).hide();

				$(".toggle-show[data-id=" + selector + "]").show();

				$(this).hide();
			}
		);

		$(this).filter(".toggle-default").show();

		$.each(
			$(this).filter(".toggle-default.toggle-show"),
			function() {
				$("#" + $(this).attr("data-id")).hide();
			}
		);

		$.each(
			$(this).filter(".toggle-default.toggle-hide"),
			function() {
				$("#" + $(this).attr("data-id")).show();
			}
		);
	}

	$.fn.toggleOption = function() {
		$(this).click(
			function(e) {
				e.preventDefault();

				var selector_show = "#" + $(this).attr("data-id");

				$(selector_show).show();

				$(this).hide();
			}
		);

		$(this).filter(".toggle-default").show();
	}

	$(document).ready(
		function() {
			$(".toggle-option").alive($.fn.toggleOption);
			$(".toggle-show").alive($.fn.toggle2);
			$(".toggle-hide").alive($.fn.toggle2);
			$(".toggle").alive($.fn.toggle1);
		}
	);
})(jQuery);


(function($) {
	$.fn.tooltip = function(html) {
		// disable browser specific tooltip by copying title attribute to data-tooltip and
		// removing old title attribute

		if(!html) {
			this.each(
				function() {
					$(this).attr("data-tooltip", $(this).attr("title"));

					$(this).removeAttr("title", "");
				}
			);
		}

		$(this).hover(
			function(e) {
				var content = html || $(this).attr("data-tooltip");

				$("#tooltip").html(content).positionLargestQuad(e).show();
			},
			function() {
				$("#tooltip").hide();
			}
		);

		$(this).mousemove(
			function() {
				$("#tooltip").positionLargestQuad();
			}
		);

		$(this).click(
			function() {
				$("#tooltip").hide();
			}
		);
	}

	$(document).ready(
		function() {
			$("body").append("<div id='tooltip'></div>");

			$("#tooltip").css("opacity", 0.85);
		
			$("[title]:not(form)").alive($.fn.tooltip);
		}
	);
})(jQuery);

