
	


/*  */

// Main library file
// Contains all functions used by two or more widgets,
// Contains the main initialization and widget management code

/*  */

if (!$.any) $.any = {};

/* global notification code - Tim Benniks */
$.extend($.any,
{
	/**
	* Notification of messages resulting from interactions with AnyMeta.
	*/
	notification:
	{
		notice: function(msg, element)
		{
			$.any.notification._showNotice(msg, 'notice', element);
		},

		error: function(msg, element)
		{
			$.any.notification._showNotice(msg, 'error', element);
		},

		success: function(msg, element)
		{
			$.any.notification._showNotice(msg, 'success', element);
		},

		formError: function(msg, element)
		{
			$.any.notification._showNoticeForm(msg, 'form-error', element);
		},

        /**
         * Find the first element of class 'notification' that is
         * within the parents of the given element.
         */
        getNotificationElement: function(element)
        {
            var el = $(element).parents().prev('.notification:first');
            return el;
        },

		/**
		* Show the notice and calculate the timeout
		*/
		_showNotice: function(msg, kind, element)
		{
			$.any.notification.time  = 4000;
			$.any.notification.timer = null;

            if (element)
            {
                var notification = element;
            }
			else if($.any.dialog.opened())
			{
				var notification = $('.dialog .notification:first');
			}
			else
			{
				var notification = $('.notification:first');
			}

			if($('ul', notification).length)
			{
				$('ul', notification).append('<li class="'+ kind +'">'+ msg +'</li>');

				$('li', notification).each(function()
				{
					$.any.notification.time += 700;
				});

				$.any.notification._hideNotice(notification);
			}
			else
			{
				$('<ul></ul>').append('<li class="'+ kind +'">'+ msg +'</li>').appendTo(notification);

				setTimeout(function()
				{
					notification.animate({opacity: 'show', height: 'show'}, 300, function()
					{
						$('li', notification).each(function()
						{
							$.any.notification.time += 700;
						});

						$.any.notification._hideNotice(notification);
					});
				},

				10);
			}
		},

		/**
		* Hide all form-error notices and show the form submit notice
		*/
		_showNoticeForm: function(msg, kind, element)
		{
            if (element)
            {
				if($('span.'+kind, element).length)
				{
					$('span.'+kind, element).parents(".notification:eq(0)").remove();
				}
				$('<div></div>').addClass("notification").append('<span class="'+ kind +'">'+ msg +'</span>').prependTo(element).show();
			}
		},
		
		/*
		* After the timeout, remove the notices
		*/
		_hideNotice: function(notification)
		{
			clearTimeout($.any.notification.timer);

			$.any.notification.timer = setTimeout(function()
			{
				notification.animate({opacity: 'hide', height: 'hide'}, 300, function()
				{
					$(this).empty().hide();
				});
			},

			$.any.notification.time);
		},

		/**
		* Ask Anymeta explicitly if there are any outstanding notifications which I should show in the interface.
		*/
		notifyCheck: function(callback)
		{
			$.any.rest.get('anymeta.notifications.get', {}, function(data)
			{
				for(var i = 0; i < data.length; i++)
				{
					var n = data[i];

					if(typeof $.any.notification[n['class']] == 'function')
					{
						$.any.notification[n['class']](n['message']);
					}
					else
					{
						throw('wrong notification kind used.');
					}
				}
                if (typeof callback == "function")
                {
                    callback();
                }
			});
		},

		loader:
		{
			options:
			{
				count: 0,
				time: null,
				dialogAnimation: false
			},

			start: function()
			{
				$.any.notification.loader.options.count += 1;
				$.any.notification.loader.options.time = (new Date()).getTime();

				if($.any.dialog.opened())
				{
					$('.dialog .dialog-loader').fadeIn(150);
				}
			},

			stop: function()
			{
				$.any.notification.loader.options.count -= 1;

				if($.any.notification.loader.options.count > 0)
				{
					return;
				}
				else
				{
					$.any.notification.loader.options.count = 0;
				}

				var now = (new Date()).getTime();
				var diff = now - $.any.notification.loader.options.time;

				var remove = function()
				{
					$('.dialog .dialog-loader').fadeOut(150);
				};

				if(diff > 500)
				{
					remove();
				}
				else
				{
					setTimeout(remove, diff);
				}
			},
			
			addLoader: function(button)
		    {
		    	var self = this;
				
		        if(button.next('.action-expl').length)
		        {
					// As simple linking
		        	button.next('.action-expl').show().html('<img class="form-throbber" src="http://fast.mediamatic.nl/f/xqnl/image/throbberwait.gif" />');
				}
				else
				{
					// Outside of simple linking
		    		button.parents('.form-button').append('<img class="form-throbber" src="http://fast.mediamatic.nl/f/xqnl/image/throbberwait.gif" />');
		    	}
		    },
		    
		    removeLoader: function()
		    {
		    	$('.form-throbber').each(function()
		    	{
		    		$(this).remove();
		    	});
		    }

		}
	},

    /**
     * Parse a string in 'choose' format. Returns an array of objects,
       each object containing a kind, type and variant element (of
       which kind and variant can be false).
     */
    parseChoose: function(choose)
    {
        choose = jQuery.trim(choose);
        if (!choose.length)
        {
            return [];
        }
        var result = [];
        choose = choose.split(",");
        var tr = function(s) { return s ? jQuery.trim(s.toLowerCase()) : false; };

        for (var i=0; i<choose.length; i++)
        {
            var item = jQuery.trim(choose[i]);
            if (!item.length) continue;
            var l = item.split(":");
            result.push({kind: tr(l[0]), type: tr(l[1]), variant: tr(l[2])});
        }
        return result;
    }
});

//
// START Global Initialization code
//
window.widget_manager = null;
$(function()
{
	window.widget_manager = new WidgetManager( window.widget_names );

	// Initialize the widgets starting from the root
	init_widgets( document.body );

	$(window).unload(function()
	{
		// There might be things to save at
		// the moment a user clicks a link
		window.widget_manager.stopAll();
	});

	// #4825: ready function for edit_required_fields template
	if ( window.required_fields )
	{
		validate_update();
	}
});

// External callback for the widget
function widget_save( submit_form )
{
	var n = window.widget_manager.stopAll();
	var t = n > 0 ? 2000 : 1;
	setTimeout(
		function ()
		{
			submit_form.submit();
		},
		t
	);
	return false;
}

// Start widgets inside a given element/css selector
function init_widgets( context )
{
	var x = $( context ).get(0);
	x && window.widget_manager.startWidgets( x );
}

// CLASS WidgetManager
// Handles the inter-widget communication
function WidgetManager( widget_names )
{
	this.widgetNames 	= widget_names;
	this.currentWidgets = {};
	this.allWidgets 	= {};
}

// Return all widgets of a given type
WidgetManager.prototype.widgets = function ( name )
{
	return this.allWidgets[name];
};

// Make the Widget Manager aware of a new widget instance
WidgetManager.prototype.add = function ( name, w )
{
	this.allWidgets[name] = this.allWidgets[name] || [];
	this.allWidgets[name].push( w );
};

// Select all the widget instances of types defined in ws
// that match predicate function f
WidgetManager.prototype.find_all = function ( f, ws )
{
	ws = ws || ['editinplace','editatonce'];
	var rt = [];
	for ( var i in ws )
	{
		var a = this.allWidgets[ws[i]] || [];

		for ( var j in a )
		{
			if ( f( a[j] ) )
			{
				rt.push( a[j] );
			}
		}
	}
	return rt;
};

// Finds the first element belonging to one of the types
// defined in ws that matches predicate function f
WidgetManager.prototype.find = function ( f, ws )
{
	ws = ws || ['editinplace','editatonce'];
	for ( var i in ws )
	{
		var a = this.allWidgets[ws[i]] || [];

		for ( var j in a )
		{
			if ( f( a[j] ) )
			{
				return a[j];
			}
		}
	}
	return null;
};

// Returns the current/active widget of type name
WidgetManager.prototype.current = function ( name )
{
	return this.currentWidgets[name];
};

// Stop (blur) all widgets. Used for e.g when the page is unloading
WidgetManager.prototype.stopAll = function ()
{
	var count = 0;
	for ( var name in this.currentWidgets )
	{
		var w = this.currentWidgets[name];
		if ( w )
		{
			if ( w.widgetBlur( name, null ) )
			{
				count += 1;
			}
		}
	}
	return count;
};

// Stop the current/active widget instance of type name
WidgetManager.prototype.stop = function ( name )
{
	var w = this.currentWidgets[name];
	w && w.widgetBlur( name, null );
};

// Defined a widget instance as the new current/active element
// fot the widget type name
WidgetManager.prototype.widgetFocus = function ( name, obj )
{
	for ( i in this.currentWidgets )
	{
		var w = this.currentWidgets[i];
		w.widgetBlur && w.widgetBlur( name, obj );
	}

	this.currentWidgets[name] = obj;
};

// Main widget initialization function
// Does a traversal of the tree that starts at root, checking
// the css classes of all elements for the do_<widgetname> pattern
// that matches one of the allowed types defined in window.widgetNames
WidgetManager.prototype.startWidgets = function ( root )
{
	var stack = [root];
	var names = this.widgetNames;
    var widgets = [];
	var names_do = {};
	for ( var i in names )
	{
		names_do['do_' + names[i]] = names[i];
	}

	while ( stack.length > 0 )
	{
        // Old-style widget

		var e = stack.pop();
		if ( e.className && e.className.match( /do_[a-z_]+/ ) )
		{
			// Note: IE6 does not recognize the \b escape char
			// (whitespace in js regexps)
			var clsss = e.className.match( /do_[a-z_]+/g );
			for ( var i = 0; i < clsss.length; i++ )
			{
				var w = names_do[clsss[i]];
				if ( w )
				{
					eval("init_" + w + "( e )");
				}
			}
        }

        // New-style widget ($.any.ui)

        var objectClass;
		if(e.className && (objectClass = new RegExp("ui_([\\w_]+)", "g").exec(e.className)))
		{
			var base = objectClass[1];
            
                        var w = $.any.ui._instantiate(e, base);
                        
                        if (w)
                        {
                            widgets.push(w);
                        }
                }

		if ( e.childNodes )
		{
			for ( var i = 0 ; i < e.childNodes.length ; i++ )
			{
				if ( e.childNodes[i].nodeType != 3 )
				{
					// Only process if not a text node
					stack.unshift( e.childNodes[i] );
				}
			}
		}
	}

	var ends = ['editinplace','editatonce'];
	for ( var i in ends )
	{
		if ( jQuery.inArray( ends[i], names ) > -1)
		{
			eval( 'end_' + ends[i] + '()' );
		}
	}

    $.each(widgets, function(i,w) { w._postInit(); });
};

// Convert the name of a validated field into a
// string usable as a dom id attribute
function validate_field2id ( name )
{
	name = name.replace( /\./g, "_" );
	return 'required_fields_li_' + name;
}

function validate_cmpfield ( l )
{
	return function ( x )
	{
		return jQuery.inArray( x.options.ajax.field, l ) > -1;
	}
}

// Scroll down/up the window to make visible the edit place of
// a given validate field that was incorrect or missing
function validate_goto ( i )
{
	var e = window.widget_manager.find( validate_cmpfield( [i] ) );
	if ( e )
	{
		var p = jQuery.getPosition( e.container );
		scroll( 0, p.y - 100 );
	}
}

// Update the validate fields error information
function validate_update ()
{
	if ( jQuery.isEmptyObject( window.required_fields ) )
	{
		$( "#required_fields_main"  ).hide();
		$( "#required_fields_other" ).show();
		return;
	}

	$( "#required_fields_main" ).show();
	$( "#required_fields_other" ).hide();

	var fs = window.required_fields;
	var ul = $( "#required_fields_list" ).get( 0 );
	ul.innerHTML = '';
	var bind_click = function ( li, i )
	{
		var fu = function ( x )
		{
			return x.options.ajax.field == i;
		};

		var e = window.widget_manager.find( fu );

		if ( e && e.options )
		{
			var c = e.options.callback;
			c = c || function () {};

			var fc = function ( d )
			{
				delete( window.required_fields[i] );
				validate_update();
				c && c( d );
			}

			e.options.callback = fc;

			$( li ).bind( "click",
				function ()
				{
					validate_goto( i );
					return false;
				}
			);
		}
	};

	var gs = jQuery.objKeys( fs );
	var fu = validate_cmpfield( gs );
	var ws = window.widget_manager.find_all( fu );
	for ( var i in ws )
	{
		ws[i].addRequiredClass();
	}

	for ( var i in fs )
	{
		var li = document.createElement( "li" );
		var an = document.createElement( "a" );
		li.id = validate_field2id( i );
		li.className = "required_field_title";
		an.href='#';
		$( an  ).html( fs[i] );
		$( li ).append( an );
		$( ul ).append( li );
		bind_click( an, i );
	}
}

// Used by all widgets. Override the default widget 'docs'
// options with those 'o' specific for this instance
function apply_options( docs, o )
{
	for ( var i in docs )
	{
		var d	= docs[i];
		var ds	= d[0].split('.');
		if ( ds.length > 1 )
		{
			o[ds[0]][ds[1]]	= (typeof o[ds[0]][ds[1]] != 'undefined') ? o[ds[0]][ds[1]]	: d[1];
		}
		else
		{
			o[d[0]]			= (typeof o[d[0]] != 'undefined') 		  ? o[d[0]] 		: d[1];
		}
	}
	return o;
}


//
// END Global Initialization code
//

// Identity function
function identity ( x )
{
	return x;
}

jQuery.fn.opacity = function ( v )
{
	this.css('opacity', v );
	if ( jQuery.browser.msie )
	{
		this.css('filter', 'alpha(opacity=' + v * 100 + ')');
	}
}

jQuery.extend(
{
	objKeys: function ( obj )
	{
		var ret = [];
		for ( var i in obj )
		{
			ret.push( i );
		}
		return ret;
	},

	label: function ( path, def )
	{
		var names 	= path.split('.');
		var tmp 	= window.labels;

		while ( names.length > 0 && tmp )
		{
			tmp = tmp[names.shift()];
		}

		return tmp || def;
	},

	// Create a new cookie
	// @param	name	string		name of the cookie
	// @param	value	string		value to be stored
	// @param	days	int			expiry time in days
	createCookie: function ( name, value, days )
	{
		if ( days )
		{
			var date = new Date();
			date.setTime( date.getTime() + ( days * 24 * 60 * 60 * 1000 ) );
			var expires = "; expires=" + date.toGMTString();
		}
		else
		{
			var expires = "";
		}
		document.cookie = name + "=" + value+expires + "; path=/";
	},

	// Read the value of a cookie
	readCookie: function ( name )
	{
		var nameEQ = name + "=";
		var ca = document.cookie.split( ';' );
		for ( var i = 0 ; i < ca.length ; i++ )
		{
			var c = ca[i];
			while ( c.charAt(0) == ' ' )
			{
				c = c.substring( 1, c.length );
			}

			if ( c.indexOf( nameEQ ) == 0 )
			{
				return c.substring( nameEQ.length, c.length );
			}
		}
		return null;
	},

	// Delete a cookie
	eraseCookie: function( name )
	{
		jQuery.createCookie( name, "", -1 );
	},

	// Use the log function of firebug without messing with other browsers
	log: function ()
	{
		if ( window.console && window.console.log && window.console.assert )
		{
			window.console.log( arguments );
		}
	},

	warn: function(where, what)
	{
		$.any.notification.notice(where);
	},

	error: function ( msg , url , line )
	{
		$.any.notification.error(msg + " @ " + url + " @ " + line);
	},

	// Get the window size
	windowSize: function ()
	{
		var p = { w: 0, h: 0 };
        var e = document.documentElement;
        var b = document.body;

		if ( typeof( window.innerWidth ) == 'number' )
		{
		  //Non-IE
		  p.w = window.innerWidth;
		  p.h = window.innerHeight;
		}
		else if( e && ( e.clientWidth || e.clientHeight ) )
		{
		  //IE 6+ in 'standards compliant mode'
		  p.w = e.clientWidth;
		  p.h = e.clientHeight;
		}
		else if( b && ( b.clientWidth || b.clientHeight ) )
		{
		  //IE 4 compatible
		  p.w = b.clientWidth;
		  p.h = b.clientHeight;
		}

		return p;
	},

	mousePosition: function ( ev )
	{
		ev = ev || window.event;

		var x = 0, y = 0;

		if ( ev.pageX || ev.pageY )
		{
			x = ev.pageX;
			y = ev.pageY;
		}
		else if ( ev.clientX || ev.clientY )
		{
			x = ev.clientX + document.body.scrollLeft;
			y = ev.clientY + jQuery.pageScrollTop(); //document.body.scrollTop;
		}

		return { "x": x, "y": y };
	},

	// Coordinates of mouse in relation to the window
	mouseInWindow: function ( e )
	{
		var ret = {};
		if ( !e )
		{
			var e = window.event;
		}

		if ( e.clientX || e.clientY )
		{
			ret.x = e.clientX - Math.max( 0 , document.body.scrollLeft );
			ret.y = e.clientY - Math.max( 0 , document.body.scrollTop ); // document.body.scrollTop*/  + document.documentElement.scrollTop;
		}
		return ret;
	},

	// Override r with properties from object a
	assocMergeInto: function ( r , a )
	{
		if ( a )
		{
			for( var i in a )
			{
				r[i] = a[i];
			}
		}
		return r;
	},

	// Merge two objects (properties of the second
	// argument override those of the first), result is a new
	// object in memory
	assocMerge: function ( a , b )
	{
	 	return jQuery.assocMergeInto( jQuery.assocMergeInto( {}, a ),  b );
	},

	// Output a datetime
	dateFormat: function ( format , date )
	{
		format = format.replace( /\%Y/ , date.getFullYear() );
		format = format.replace( /\%m/ , date.getMonth() + 1 );
		format = format.replace( /\%d/ , date.getDate() );
		format = format.replace( /\%H/ , date.getHours() );
		format = format.replace( /\%M/ , date.getMinutes() );
		return format;
	},

	// Remove a parameter from the url
	remFromQuery: function ( url , name )
	{
		var reg = new RegExp( '&?' + name + '=[^&]*' );
		url = url.replace( reg, '' );
		return url;
	},


	// Add some query data to a url
	addToQuery: function ( url , data )
	{
		return url + ( url.match( /\?/ ) ? '&' : '?' ) + data;
	},

	// Parse options given inside the attribute of an element
	attrOptions: function ( e , name )
	{
		return eval( "({" + ((e.getAttribute( name ) || '').replace( /,\s*$/ , '' )) + "})" );
	},

	// DEPRECATED: Vertical scroll offset in pixels
	pageScrollTop: function ()
	{
        var pos = jQuery.getScroll();
        return pos.y;
	},

    getScroll: function ()
    {
        var p = {x: 0, y: 0};
        var e = document.documentElement;
        var b = document.body;

        if ( e && ( e.scrollLeft || e.scrollTop ) )
        {
            p.x = e.scrollLeft;
            p.y = e.scrollTop;

        }
        else if ( b && ( b.scrollLeft || b.scrollTop ) )
        {
            p.x = b.scrollLeft;
            p.y = b.scrollTop;
        }
        else if ( window.pageXOffset || window.pageYOffset )
        {
            p.x = window.pageXOffset;
            p.y = window.pageYOffset;
        }
        else if( window.scrollX || window.scrollY )
        {
            p.x = window.scrollX;
            p.y = window.scrollY;
        }
        return p;
    },


	// Calculate x,y position of a given dom element
	getPosition: function ( obj, ignoreRelative )
	{
        ignoreRelative = ignoreRelative || false;

		var curleft = curtop = 0;

		// Hack for IE not needed ?
		// Not sure but this check for IE gave problems in the end
		// Keep the if in until we're sure that it is not needed
		if ( false && jQuery.browser.msie )
		{
			// Hack for IE, naturally
			var childImg = false;
			for ( var i in obj.childNodes )
			{
				childImg = childImg || obj.childNodes[i].tagName == 'IMG';
			}

			if ( childImg )
			{
				curleft -= obj.offsetLeft;
			}
		}

		while ( obj )
		{
			if ( !ignoreRelative || jQuery( obj ).css('position') != "relative" )
			{
				curleft += obj.offsetLeft;
				curtop  += obj.offsetTop;
			}
			obj = obj.offsetParent;
		}
		return { x: curleft, y: curtop };
	},

	// Calculate dimensions of a dom element
	getSize : function(e)
	{
		var w = jQuery.css(e,'width');
		var h = jQuery.css(e,'height');
		var wb = 0;
		var hb = 0;
		es = e.style;

		if ( jQuery(e).css('display') != 'none' )
		{
			wb = e.offsetWidth;
			hb = e.offsetHeight;
		}
		else
		{
			oldVisibility = es.visibility;
			oldPosition = es.position;
			es.visibility = 'hidden';
			es.display = 'block';
			es.position = 'absolute';
			wb = e.offsetWidth;
			hb = e.offsetHeight;
			es.display = 'none';
			es.position = oldPosition;
			es.visibility = oldVisibility;
		}
		return { w:w, h:h, wb:wb, hb:hb };
	},

	validateForm: function ( frm , alrt )
	{
		if ( document.getElementById( frm ) )
		{
			var f = document.getElementById( frm );
		}
		else if ( document.forms[ frm ] )
		{
			var f = document.forms[ frm ];
		}
		else
		{
			f = frm;
		}

		if ( alrt == 'null' )
		{
			alrt = 'All fields are required';
		}

		var isValid		= true;
		var	vFormElems	= new Array();

		for ( i = 0 ; i < f.elements.length ; i++ )
		{
			elem  = f.elements[i];


			vCode = ( elem['alt'] ) ? elem['alt'] : elem.getAttribute('alt');

			if ( !( typeof vCode == 'undefined' || vCode == null || vCode == "" ) )
			{
				if ( jQuery.inArray( elem.name, vFormElems ) == -1)
				{
					v = jQuery.getValue( f.elements[elem.name] );

					if ( vCode == 'required' && v.length < 1 )
					{
						isValid = false;
					}
					vFormElems[i] = elem.name;
				}
			}
		}
		if (!isValid)
		{
			alert( alrt );
		}
		return isValid
	},

	// Returns value of a formfield
	getValue: function ( ffield , def )
	{
		v = '';
		t = ffield.type;

		if( !t )
		{
			t = ffield[0].type;
		}

		if( t == 'checkbox' )
		{
			if( ffield.length )
			{
				for( gv_i=0 ; gv_i < ffield.length ; gv_i++ )
				{
					if ( ffield[gv_i].checked )
					{
						v = ffield[gv_i].value;
					}
				}
			}
			else
			{
				if ( ffield.checked )
				{
					v = ffield.value;
				}
			}
		}
		else if ( t == 'file' )		v = ffield.value;
		else if ( t == 'hidden' )	v = ffield.value;
		else if ( t == 'password' ) v = ffield.value;
		else if ( t == 'radio' )
		{
			if ( ffield.length )
			{
				for ( gv_i=0 ; gv_i < ffield.length ; gv_i++)
				{
					if ( ffield[gv_i].checked ) v = ffield[gv_i].value;
				}
			}
			else
			{
				if ( ffield.checked ) v = ffield.value;
			}
		}
		else if (t == 'select-multiple' ) v = ffield.options[ffield.selectedIndex].value;
		else if (t == 'select-one' )	  v = ffield.options[ffield.selectedIndex].value;
		else if (t == 'text' )			  v = ffield.value;
		else if (t == 'textarea' )		  v = ffield.value;

		if (def != null && v == '')
		{
			return def;
		}
		return v;
	},

	byId: function ( id , doc )
	{
		if ( typeof id == "string" || id instanceof String )
		{
			if ( !doc )
			{
				doc = document;
			}
			return doc.getElementById ( id );
		}
		// assume it's a node
		return id;
	},

	textContent: function ( node )
	{
		var _result = "";
		if (node == null)
		{
			return _result;
		}

		for (var i = 0; i < node.childNodes.length; i++)
		{
			switch (node.childNodes[i].nodeType)
			{
				case 1: // ELEMENT_NODE
				case 5: // ENTITY_REFERENCE_NODE
					_result += jQuery.textContent(node.childNodes[i]);
					break;
				case 3: // TEXT_NODE
				case 2: // ATTRIBUTE_NODE
				case 4: // CDATA_SECTION_NODE
					_result += node.childNodes[i].nodeValue;
					break;
				default:
					break;
			}
		}
		return _result;
	},

	// used in form validator
	// maybe change in the future
	isSizeSmaller: function ( v , size )
	{
		if ( v.length < size )
		{
			return true;
		}
		else
		{
			return false;
		}
	},

	// used in form validator
	// maybe change in the future
	isSizeGreater: function ( v , size )
	{
		if ( v.length > size )
		{
			return true;
		}
		else
		{
			return false;
		}
	},

	// showhide functions
	// used while rest call state is failed/ok/wait
	showHide: function (str)
	{
		a = str.split(',');
		for ( var i = 0 ; i < a.length ; i++ )
		{
			s = a[i];
			c = s.charAt(0);
			v = 'block';

			if (c == '-')
			{
				v = 'none';
				s = s.substr( 1 , s.length-1);
			}
			else if ( c == '+')
			{
				s = s.substr( 1 , s.length - 1 );
			}

			if ( $( "#" + s ) )
			{
				$("#" + s).css( 'display', v );
			}
		}
	},

	// Hide all obj in an array or string and optionally show obj b (can be an array)
	// Parameters:	a	which obj to hide (can be an array)
	//				b	which obj should openend afterwards (hide all but ...)(can be an array)
	//				s	if s = true search for objects starting with the string 'a'
	hideAllBut: function ( a, b )
	{
		if ( jQuery.isObject( a ) )
		{
			for ( var p in a )
			{
				$( "#" + a[p] ).hide();
			}
		}
		else if ( jQuery.isArray(a) )
		{
			for ( i = 0 ; i < a.length ; i++ )
			{
				$( "#" + a[i] ).hide();
			}
		}
		else if ( jQuery.isString( a ) )
		{
			var d = document.getElementsByTagName( 'div' );
			for( i = 0 ; i < d.length ; i++ )
			{
				var l = a.length;
				var id = d[i].id;
				if ( id.substring( 0 , l ) == a )
				{
					$( "#" + d[i].id ).hide();
				}
			}
		}

		if ( jQuery.isArray( b ) )
		{
			for ( i = 0 ; i < a.length ; i++)
			{
				$( "#" + b[i] ).show();
			}
		}
		else if ( jQuery.isString( b ) )
		{
			$( "#" + b ).show();
		}
	},


	popup: function ( thg_id, o, l, t, w, h )
	{
		if ( l == null ) l = 100;
		if ( t == null ) t = 100;
		if ( w == null ) w = 400;
		if ( h == null ) h = 400;

		var aPopupWin = window.open( '', 'PopupWin', 'scrollbars=yes,menubar=no,location=no,directories=no,statusbar=no,toolbar=no,resizable=yes,width=' + w + ',height=' + h + ',top=' + t + ',left=' + l );
		aPopupWin.document.open();
		aPopupWin.document.close();
		order = '';
		if ( o != null ) order = '&order='+o;
		var p = 'popup.php?id=' + thg_id + order;

		aPopupWin.document.location.href = p;
		if( aPopupWin && !aPopupWin.closed )
		{
			aPopupWin.focus();
		}
	},

	resizePopup: function()
	{
		var mw = 400;

		if ( parseInt( navigator.appVersion.charAt( 0 ) ) >= 4 )
		{
			NN = ( navigator.appName=="Netscape" ) ? 1 : 0;
		}

		if ( document.images[0] )
		{
			ww = ( screen.width  );
			wh = ( screen.height );

			if (NN)
			{
				rw = document.images[0].width + 80;
				rh = document.images[0].height;
				if ( ww < rw ) rw = ww;
				if ( rw < mw ) rw = mw;
				if ( wh < rh ) rh = wh;
				if ( rh < wh - 140 ) rh = rh + 160;
				window.top.innerWidth  = rw;
				window.top.innerHeight = rh;
			}
			else
			{
				rw = document.images[0].width + 80;
				rh = document.images[0].height;
				if ( ww < rw ) rw = ww;
				if ( rw < mw ) rw = mw;
				if ( wh < rh ) rh = wh;
				if ( rh < wh - 140 ) rh = rh + 160;
				window.top.resizeTo( rw, rh );
			}
			parent.window.moveTo( ( screen.width - rw ) / 2, ( screen.height - rh ) / 2 );
		}
	},

	truncate: function(string, chars, after)
	{
		if (string.length <= chars)
		{
			return string;
		}

		if (typeof after == 'undefined')
		{
			after = '&hellip;';
		}

		string = string.substring(0, chars);
		string = string.replace(/\w+$/, '');

		var re  = new RegExp('[ 	\.\,\:\;\!\?]+$', 'g');
		string  = string.replace(re, '');
		string += ' ' + after;

		return string;
	}
});

// CLASS AjaxNotice
function AjaxNotice( sel )
{
	this.sel = sel;
}

// Start the notice
AjaxNotice.prototype.start = function ( text )
{
	if ( text == '...' )
	{
		text = '<img src="http://fast.mediamatic.nl/f/xqnl/image/throbberdots.gif" />';
	}

	$( this.sel ).addClass( 'ajax_notice' );
}

// Stop the notice
AjaxNotice.prototype.stop = function ()
{
	$( this.sel ).removeClass( 'ajax_notice' );
}

// External callback for the documentation functions
function docs_validate()
{
	var lm = jQuery.label( 'editinplace.validate.msg'	, 'Please input a valid value' );
	var lo = jQuery.label( 'editinplace.validate.out'	, 'Value out of range'  );

	return { opts:
		[[ "validate",			{},			"Input format validation" ]
		,[ "validate.regexp",	null,		"Regular expression to validate format" ]
		,[ "validate.name",		null,		"Name of predefined regular expression [integer|float]" ]
		,[ "validate.msg",		lm,			"Alert message to be displayed in case of wrong format" ]
		,[ "validate.min",		null,		"Minimum allowed value" ]
		,[ "validate.max",		null,		"Maximum allowed value" ]
		,[ "validate.empty",	false,		"Input value is allowed to be empty" ]
		,[ "validate.blank",	false,		"Input value is allowed to be empty/whitespace" ]
		,[ "validate.out",		lo,			"Alert message to be displayed in case of out of range number" ]
		]
	};
}

// CLASS Validate
// Used by EditAtOnce and EditInPlace to validate
// the presence or format of some fields
function Validate( opts )
{
	this.opts = opts;
	if ( "integer" == this.opts.name )
	{
		this.opts.msg		= jQuery.label( 'editinplace.validate.integer'	, 'Please input an integer number' );
		this.opts.regexp	= /^\s*[-+]?\d+\s*$/;
	}
	else if ( "float" == this.opts.name )
	{
		this.opts.msg		= jQuery.label( 'editinplace.validate.float'	, 'Please input a number' );
		this.opts.regexp	= /^\s*[-+]?\d+(\.\d+)?\s*$/;
	}
}

// Is the value inside this range?
Validate.prototype.range = function ( value )
{
	var fs 	= {'integer': parseInt, 'float': parseFloat};
	var f 	= fs[this.opts.name] || identity;
	value = f( value );

	return 	!(	this.opts.min && this.opts.min > value
			||	this.opts.max && this.opts.max < value );
}

// Is the value not empty?
Validate.prototype.value = function ( value )
{
	return ( this.opts.blank && value.match( /^\s*$/ ) )
		|| ( this.opts.empty && value == '' )
		|| ( this.opts.regexp && this.opts.regexp.exec( value ) )
		|| ( !this.opts.regexp );
}


// Comment this line to stop server-side reporting of javascript errors
//window.onerror = anyOnError;

window.handlingOnError = false;
window.handledErrors   = [];

// Function used for server-side reporting of javascript errors
function anyOnError( msg , url , line )
{
	var exclude = [ "uncaught exception: Permission denied to get property HTMLInputElement.parentNode"
				  , "uncaught exception: Permission denied to get property HTMLDivElement.parentNode" ];

	// Don't report errors in black list
	for ( var i in exclude )
	{
		if ( exclude[i] == msg )
		{
			jQuery.log( "Error belongs to blacklist, won't report it." );

			// Stop browser from declaring this error
			return true;
		}
	}

	// Don't report same error twice
	for ( var i in window.handledErrors )
	{
		if ( window.handledErrors[i] == msg )
		{
			jQuery.log( "Error already reported once on this session" );

			// Stop browser from declaring same error twice
			return true;
		}
	}

	// Don't report errors that may have happened
	// during the error-processing phase
	// (danger of infinite recursivity)
	if ( window.handlingOnError )
	{
		jQuery.log( "Trying to report an error while already busy reporting another one" );

		// Pass error onto browser
		return false;
	}

	// Lock (informal mutex)
	window.handlingOnError = true;

	jQuery.log( "Reporting error: " + msg );

	// Remember this error
	window.handledErrors.push( msg );

	// Values to send to the server
	var params = {};
	params.msg			= msg;
	params.pageurl		= location.href;
	params.scripturl	= url;
	params.linenumber	= line;
	params.referrer		= document.referrer;

	// Send error report o server
	$.any.rest.post('anymeta.error.log',
                        params ,
		        function ( result )
		        {
			    jQuery.log( 'Error was reported!' );
			    // Unlock (informal mutex)
			    window.handlingOnError = false;
		        }
	);

	// Pass error onto browser
	return false;
}

// Get a css style attribute for a html node
function anyGetComputedStyle( node , cssSelector , inValue )
{
	var cssSelector = toSelectorCase( cssSelector );
	var property = toCamelCase( cssSelector );
	if( !node || !node.style )
	{
		return inValue;
	}

	else if ( document.defaultView &&
			// mozilla segfaults when margin-* and node is removed from doc
			// FIXME: need to figure out a if there is quicker workaround
			isDescendantOf( node, node.ownerDocument ) )
	{ // W3, gecko, KHTML
		try
		{
			var cs = document.defaultView.getComputedStyle( node , "" );
			if ( cs )
			{
				return cs.getPropertyValue( cssSelector );
			}
		}
		catch( e )
		{ // reports are that Safari can throw an exception above
			if ( node.style.getPropertyValue )
			{ // W3
				return node.style.getPropertyValue( cssSelector );
			}
			else
			{
				return inValue;
			}
		}
	}
	else if ( node.currentStyle )
	{ // IE
		return node.currentStyle[property];
	}
	if ( node.style.getPropertyValue )
	{ // W3
		return node.style.getPropertyValue( cssSelector );
	}
	else
	{
		return inValue;
	}
}



// Change from fontSize to font-size
function toSelectorCase( selector )
{
	return selector.replace(/([A-Z])/g, "-$1" ).toLowerCase();
}


// Change from font-size to fontSize
function toCamelCase ( selector ) {
	var arr = selector.split('-'), cc = arr[0];
	for ( var i = 1 ; i < arr.length ; i++ )
	{
		cc += arr[i].charAt( 0 ).toUpperCase() + arr[i].substring( 1 );
	}
	return cc;
}


// Test if node is descendant of a given ancestor
function isDescendantOf( node, ancestor, guaranteeDescendant )
{
	// guaranteeDescendant allows us to be a "true" isDescendantOf function
	if( guaranteeDescendant && node )
	{
		node = node.parentNode;
	}

	while( node )
	{
		if ( node == ancestor )
		{
			return true;
		}
		node = node.parentNode;
	}
	return false;
}

// Convert these strings '#abc', '#aabbcc', 'abc', etc
// into this string 'aabbcc'
// TODO: Find better name
function validate_hex( s )
{
	s = s.replace( /#/, '' );
	var h3 = s.match(/^[a-fA-F0-9]{3}$/);
	if ( h3 )
	{
		var a = "";
		for ( var i = 0; i < 3; i++ )
		{
			var c = s.slice(i,i+1);
			a += c + c;
		}
		s = a;
	}
	return s;
}

// Get the background color of a dom node and convert it
// into an array of decimal numbers [255,255,255]
// TODO: Find better name
function parse_dec_a( elem, stl )
{
	var stl = stl || 'background-color';
	var color = anyGetComputedStyle( elem, stl );

	if ( color == 'transparent' )
	{
		color = '';
	}
	else
	{
		var ff_fr = ffrgb_s2dec_a( color );

		if ( ff_fr || ff_fr == 'transparent' )
		{
			color = ff_fr;
		}
		else
		{
			color = validate_hex( color );
			color = hex_s2dec_a( color );
		}
	}
	return color;
}

// Convert from firefox-returned color format 'rgb(12,34,12)'
// into an array of decimal numbers [12,34,12]
// TODO: Find better name
function ffrgb_s2dec_a( x )
{
	var a = null;
	var m = x.match(/rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/);

	if ( m )
	{
		a = [];
		for ( var i = 1; i < 4 ; i++ )
		{
			a.push( parseInt( m[i] ) );
		}
	}
	return a;
}

// Make the node in the first argument throb its background color
// using the bkg color of the second argument as the intermediate
function throb( selector, color_example )
{
	var elem = $( selector      ).get( 0 );
	var exmp = $( color_example ).get( 0 );

	if ( !elem || !exmp )
	{
		jQuery.log( 'throb: did not receive the correct arguments' );
		return;
	}

	// Get the base color
	var frcolor = parse_dec_a( elem );
	var tocolor = parse_dec_a( exmp );

	if ( !frcolor || !tocolor )
	{
		jQuery.log( 'throb: color values not parseable' );
		return;
	}


	// Get the start time for animation
	var start = (new Date()).getTime();

	// Total duration of animation
	var total = 5000;

	var anim = function ()
	{
		var diff = (new Date()).getTime() - start;
		if ( diff > total )
		{
			elem.style.backgroundColor = '#' + dec_a2hex_s( frcolor );
		}
		else
		{
			var x = [];
			var f = diff / total;
			var g = ( Math.cos(6 * Math.PI * f + Math.PI) + 1 ) / 2;
			for ( var i = 0; i < 3; i++ )
			{
				x[i] = Math.floor( g * tocolor[i] + (1 - g) * frcolor[i] )
			}
			elem.style.backgroundColor = '#' + dec_a2hex_s( x );
		}
	};
	setInterval( anim, 20 );
}



// Parse a mysql datetime field
// @param	String		datetime	The string containing the datetime value "YYYY-MM-DD HH-MM-SS"
// @return	Date					The parsed value
function mysqlDatetimeToDate ( datetime )
{
   var regex = /^([0-9]{2,4})-([0-1][0-9])-([0-3][0-9]) (?:([0-2][0-9]):([0-5][0-9]):([0-5][0-9]))?$/;
   var parts = datetime.replace( regex, "$1 $2 $3 $4 $5 $6" ).split( ' ' );
   return new Date( parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5] );
}



// Show a date relative to a given moment
// @param	Date		date		The date to represent
// @param	Date		now			Optional, used as reference, default new Date()
// @return	String					The formatted string
function showDateRelative( date, now )
{
	now = now || new Date();
	var prefix = '';
	if ( date.getFullYear() != now.getFullYear() || date.getMonth() != now.getMonth() || date.getDay() != now.getDay() )
	{
		prefix = '' + date.getFullYear() + '/' + ( date.getMonth() + 1 ) + '/' + date.getDate() + ' ';
	}
	return prefix + lpad( date.getHours(), 2, '0' ) + ':' + lpad( date.getMinutes(), 2, '0' );
}



// Left-pad a string to a desired length
// @param	String		s		The string to pad
// @param	Number		n		Final length of resulting string
// @param	String		c 		The character to repeat
// @return	String				The padded string
function lpad( s, n, c )
{
	// Make sure it is a string
	s = '' + s;

	while ( s.length < n )
	{
		s = c + s;
	}
	return s
}

// Convert [255,255,255] into 'ffffff'
// TODO: Find better name
function dec_a2hex_s( a )
{
	var x = '';
	for ( var i in a )
	{
		x += lpad( dec2hex( a[i] ), 2, '0' );
	}
	return x;
}

// Convert 'ffffff' into [255,255,255]
// TODO: Find better name
function hex_s2dec_a( s )
{
	var r = [];
	for ( var i = 0; i <= 4; i += 2 )
	{
		r.push( hex2dec( s.slice( i, i + 2 ) ) );
	}
	return r;
}

// Convert a decimal number/string into a hex string
function dec2hex( x )
{
	x = parseInt( x );
	var m = 16;
	var s = '';
	while ( x > 0 )
	{
		r = x % m;
		r = r > 9 ? "abcdef".slice( r-10, r-9 ) : '' + r;
		s = r + s;
		x = Math.floor( x / m );
	}
	return s;
}

// Convert a hex string into a decimal number
function hex2dec( x )
{
	x = '' + x;
	x = x.toLowerCase();
	s = "0123456789abcdef";
	n = 0;
	for ( var i = 0; i < x.length; i++ )
	{
		n = n * 16 + s.indexOf( x.slice(i,i+1) );
	}
	return n;
}

// Convert an array to string using a separator in between
function implode( arr, sep )
{
    var ret = ''
    for ( var i = 0; i < arr.length; i++ )
    {
        ret += ( i > 0 ? sep : '' ) + arr[i];
    }
    return ret;
}

function strip( str )
{
	str = str || '';
	str = str.replace( /^\s+/g, "" );
	str = str.replace( /\s+$/g, "" );
	return str;
}

jQuery.fn.extend({
	everyTime: function(interval, label, fn, times, belay) {
		return this.each(function() {
			jQuery.timer.add(this, interval, label, fn, times, belay);
		});
	},
	oneTime: function(interval, label, fn) {
		return this.each(function() {
			jQuery.timer.add(this, interval, label, fn, 1);
		});
	},
	stopTime: function(label, fn) {
		return this.each(function() {
			jQuery.timer.remove(this, label, fn);
		});
	}
});

jQuery.extend({
	timer: {
		guid: 1,
		global: {},
		regex: /^([0-9]+)\s*(.*s)?$/,
		powers: {
			// Yeah this is major overkill...
			'ms': 1,
			'cs': 10,
			'ds': 100,
			's': 1000,
			'das': 10000,
			'hs': 100000,
			'ks': 1000000
		},
		timeParse: function(value) {
			if (value == undefined || value == null)
				return null;
			var result = this.regex.exec(jQuery.trim(value.toString()));
			if (result && result[2]) {
				var num = parseInt(result[1], 10);
				var mult = this.powers[result[2]] || 1;
				return num * mult;
			} else {
				return value;
			}
		},
		add: function(element, interval, label, fn, times, belay) {
			var counter = 0;

			if (jQuery.isFunction(label)) {
				if (!times)
					times = fn;
				fn = label;
				label = interval;
			}

			interval = jQuery.timer.timeParse(interval);

			if (typeof interval != 'number' || isNaN(interval) || interval <= 0)
				return;

			if (times && times.constructor != Number) {
				belay = !!times;
				times = 0;
			}

			times = times || 0;
			belay = belay || false;

			if (!element.$timers)
				element.$timers = {};

			if (!element.$timers[label])
				element.$timers[label] = {};

			fn.$timerID = fn.$timerID || this.guid++;

			var handler = function() {
				if (belay && this.inProgress)
					return;
				this.inProgress = true;
				if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
					jQuery.timer.remove(element, label, fn);
				this.inProgress = false;
			};

			handler.$timerID = fn.$timerID;

			if (!element.$timers[label][fn.$timerID])
				element.$timers[label][fn.$timerID] = window.setInterval(handler,interval);

			if ( !this.global[label] )
				this.global[label] = [];
			this.global[label].push( element );

		},
		remove: function(element, label, fn) {
			var timers = element.$timers, ret;

			if ( timers ) {

				if (!label) {
					for ( label in timers )
						this.remove(element, label, fn);
				} else if ( timers[label] ) {
					if ( fn ) {
						if ( fn.$timerID ) {
							window.clearInterval(timers[label][fn.$timerID]);
							delete timers[label][fn.$timerID];
						}
					} else {
						for ( var fn in timers[label] ) {
							window.clearInterval(timers[label][fn]);
							delete timers[label][fn];
						}
					}

					for ( ret in timers[label] ) break;
					if ( !ret ) {
						ret = null;
						delete timers[label];
					}
				}

				for ( ret in timers ) break;
				if ( !ret )
					element.$timers = null;
			}
		}
	}
});

if (jQuery.browser.msie)
	jQuery(window).one("unload", function() {
		var global = jQuery.timer.global;
		for ( var label in global ) {
			var els = global[label], i = els.length;
			while ( --i )
				jQuery.timer.remove(els[i], label);
		}
	});


// rounded corners

	// adds 4 spans to element, positions using css in utils.css
	/*  EXAMPLE

	if( $.browser.msie){
		// add rounded corners to these elements for IE
		$('.list-context li').rounded_corners();
	};
	// add rounded corners to these elements for all browsers
	$('.fig li').rounded_corners();

	*/

	$.fn.rounded_corners = function(){
		if (!$(this).length)
		return false;

		$(this)
			.css({position: 'relative'})
			.hover(function(){
				$(this).addClass('cnrs-hovered');
			},function(){
				$(this).removeClass('cnrs-hovered');
			});

		$('<span class="cnrs cnr_nw"></span><span class="cnrs cnr_ne"></span><span class="cnrs cnr_sw"></span><span class="cnrs cnr_se"></span>')
		.css({ // will only accept numeric border widths
	 		marginTop: 		'-'+(parseInt($(this).css('border-top-width'))||0),
	 		marginRight: 	'-'+(parseInt($(this).css('border-right-width'))||0),
	 		marginBottom: 	'-'+(parseInt($(this).css('border-bottom-width'))||0),
	 		marginLeft: 	'-'+(parseInt($(this).css('border-left-width'))||0)
	 	})
		.appendTo(this);
		// ie odd values bug fix
		if( $.browser.msie && $.browser.version < 7){
			$(this).each(function(){
				var h = $(this).height();
				if (h%2){ $('.cnr_sw',this).css({bottom: '-1px'});$('.cnr_se',this).css({bottom: '-1px'}); };
				var w = $(this).width();
				if (w%2){ $('.cnr_ne',this).css({right: '-1px'});$('.cnr_se',this).css({right: '-1px'}); };
			});
		};
	};

// hoverintent plugin
;(function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY;};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))<cfg.sensitivity){$(ob).unbind("mousemove",track);ob.hoverIntent_s=1;return cfg.over.apply(ob,[ev]);}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob);},cfg.interval);}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=0;return cfg.out.apply(ob,[ev]);};var handleHover=function(e){var p=(e.type=="mouseover"?e.fromElement:e.toElement)||e.relatedTarget;while(p&&p!=this){try{p=p.parentNode;}catch(e){p=this;}}if(p==this){return false;}var ev=jQuery.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);}if(e.type=="mouseover"){pX=ev.pageX;pY=ev.pageY;$(ob).bind("mousemove",track);if(ob.hoverIntent_s!=1){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob);},cfg.interval);}}else{$(ob).unbind("mousemove",track);if(ob.hoverIntent_s==1){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob);},cfg.timeout);}}};return this.mouseover(handleHover).mouseout(handleHover);};})(jQuery);

// caret plugin (http://examplet.buss.hk/jquery/caret.php)
(function(k,e,i,j){k.fn.caret=function(b,l){var a,c,f=this[0],d=k.browser.msie;if(typeof b==="object"&&typeof b.start==="number"&&typeof b.end==="number"){a=b.start;c=b.end}else if(typeof b==="number"&&typeof l==="number"){a=b;c=l}else if(typeof b==="string")if((a=f.value.indexOf(b))>-1)c=a+b[e];else a=null;else if(Object.prototype.toString.call(b)==="[object RegExp]"){b=b.exec(f.value);if(b!=null){a=b.index;c=a+b[0][e]}}if(typeof a!="undefined"){if(d){d=this[0].createTextRange();d.collapse(true);
d.moveStart("character",a);d.moveEnd("character",c-a);d.select()}else{this[0].selectionStart=a;this[0].selectionEnd=c}this[0].focus();return this}else{if(d){c=document.selection;if(this[0].tagName.toLowerCase()!="textarea"){d=this.val();a=c[i]()[j]();a.moveEnd("character",d[e]);var g=a.text==""?d[e]:d.lastIndexOf(a.text);a=c[i]()[j]();a.moveStart("character",-d[e]);var h=a.text[e]}else{a=c[i]();c=a[j]();c.moveToElementText(this[0]);c.setEndPoint("EndToEnd",a);g=c.text[e]-a.text[e];h=g+a.text[e]}}else{g=
f.selectionStart;h=f.selectionEnd}a=f.value.substring(g,h);return{start:g,end:h,text:a,replace:function(m){return f.value.substring(0,g)+m+f.value.substring(h,f.value[e])}}}}})(jQuery,"length","createRange","duplicate");
// no queue in animation plugin
;(function($)
{
	$.fn.animnoq = function(type, prop, speed, easing, callback)
	{
		if($.inArray(type, ['mouseover', 'mouseenter', 'mouseout', 'mouseleave']) == -1) { return this; }

		var opt = typeof speed === 'object' ? speed : { complete: callback || !callback && easing || $.isFunction(speed) && speed, duration: speed, easing: callback && easing || easing && !$.isFunction(easing) && easing }
		opt.queue = false;
		var origCallback = opt.complete;

		opt.complete = function()
		{
			$(this).dequeue();
			if($.isFunction(origCallback)) origCallback.call(this);
		}

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

			if(type == 'mouseover' || type == 'mouseenter')
			{
				$this.data('jQuery.animnoq', true);
			}
			else
			{
				$this.removeData('jQuery.animnoq');
			}

			$this.queue(function()
			{
				var condition = (type == 'mouseover' || type == 'mouseenter') ? $this.data('jQuery.animnoq') !== undefined : $this.data('jQuery.animnoq') === undefined;
				if(condition) { $this.animate(prop, opt); } else { $this.queue([]); }
			});
		});
	};
})(jQuery);

// Empty value on click
// Return value when blur and no value
(function($)
{
    /**
     * Returns the value of the field element.
     */
    $.fieldValue = function(el, successful) {
        var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
        if (typeof successful == 'undefined') successful = true;

        if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
                           (t == 'checkbox' || t == 'radio') && !el.checked ||
                           (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
                           tag == 'select' && el.selectedIndex == -1))
            return null;

        if (tag == 'select') {
            var index = el.selectedIndex;
            if (index < 0) return null;
            var a = [], ops = el.options;
            var one = (t == 'select-one');
            var max = (one ? index+1 : ops.length);
            for(var i=(one ? index : 0); i < max; i++) {
                var op = ops[i];
                if (op.selected) {
				    var v = op.value;
				    if (!v) // extra pain for IE...
                	    v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
                    if (one) return v;
                    a.push(v);
                }
            }
            return a;
        }
        return el.value;
    };

})(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;
    }
};

// fixes problem in IE6,7 as explained by anymeta:#7873:
$(window).unload(function() 
{
	window["__flash__removeCallback"] = function (instance, name) 
	{
		return;
	};
});
/*  */
//
// Depends: Ajax/js/any/utils.js
//
// any.rest
/** Start of the newstyle rest functions */
;(function($)
{
    if (!$.any) $.any = {};
    $.extend($.any,
    {
        rest:
        {
            user: 
            {
                id: 0
            },

            init: function (userId)
            {
                $.any.rest.user.id = userId;

                $(window).bind('ajaxStart', $.any.notification.loader.start);
                $(window).bind('ajaxStop', $.any.notification.loader.stop);
            },
            
            /**
             * jQuery.param(), but filters out empty values first.
             */
            param: function (data)
            {
                var filterEmpty = function(data)
                {
                    var result;
                    switch (typeof data)
                    {
                    case "object":
                        result = {};
                        for (var k in data) {
                            if (data[k] === false || (typeof data[k] == "undefined") || (data[k] === null)) 
                            {
                                continue;
                            }
                            result[k] = filterEmpty(data[k]);
                        }
                        break;
                    default:
                        result = data;
                    }
                    return result;
                };
                return $.param(filterEmpty(data));
            },

            /**
             * Require the user to be logged on. If this is not the case,
             * we redirect to the logon URI; appending the current URI as
             * the 'goto' uri + extra arguments that are passed into this
             * function.
             * @return true if we are redirecting, otherwise false.
             */
            requireLogon: function( ret_args )
            {
                if ($.any.rest.user.id == 0)
                {
                    var uri = "/logon";
                    var go = document.location.href + '';
                    // Only keep the URL path part
                    go = go.replace(new RegExp('^.*?://.*?(/.*)$'), '$1');

				    go += go.match(/\?/) ? '&' : '?';
                    if (ret_args)
                    {
                        go += $.any.rest.param(ret_args);
                    }

                    uri += "?goto=" + escape(go);
                    $.any.rest.redirect(uri);
                    return true;
                }
                return false;
            },
            
            
            /**
             * Logoff the current user.
             */
            logoff: function (goto)
            {
                var arg = {doLogoff: true};
                $.any.ui.publish("logoff", arg, null);
                if (arg.doLogoff)
                {
                    $.any.rest.performLogoff(goto);
                }
            },

            /**
             * Actually perform the Anymeta logoff.
             */
            performLogoff: function (goto)
            {
                $.any.rest.post("authentication.user.logoff", {}, function() { 
                                    if (goto)
                                    {
                                        window.location.href = goto;
                                    }
                                    else
                                    {
                                        // Reload current page, but strip request arguments
                                        var l = document.location;
                                        document.location = l.protocol + '//' + l.host + l.pathname;
                                    }
                                });
            },


            /**
             * Call the api using HTTP POST. The callback function gets a
             * JSON object with the result; or, when an (API or HTTP)
             * error has been detected, the errback function is called.
             */
            post: function (method, params, callback, errback, notifycallback)
            {
                $.any.rest._doMethod('POST', method, params, callback, errback, notifycallback);
            },


            /**
             * Call the api using HTTP GET. The callback function gets a
             * JSON object with the result; or, when an (API or HTTP)
             * error has been detected, the errback function is called.
             */
            get: function (method, params, callback, errback, notifycallback)
            {
                $.any.rest._doMethod('GET', method, params, callback, errback, notifycallback);
            },


            /**
             * Internal function for handling the API calls.
             */
          _doMethod: function(verb, api_method, params, callback, errback, notifycallback)
            {
			    var opts = {
				    "type": verb.toUpperCase(),
				    "url": 	"http://www.depaviljoens.nl/services/rest/"
			    };

                params['format'] = 'json';
                params['method'] = api_method;
			    params['_n'] = '1'; // we want notifications
                
                try 
                {
                    if ( opts.type == 'GET' )
			        {
				        opts.url += '?' + $.any.rest.param( params );
			        }
                
			        if ( opts.type == 'POST' )
			        {
				        opts.data = $.any.rest.param( params );
			        }
                }
                catch (err)
                {
                    throw 'Encoding params for ' + api_method + ' failed: ' + err; 
                }

			    opts.success = function ( data )
			    {
                    //data = eval('(' + data + ')');

                    if (data && data['_n'])
                    {
                        // We got notifications
                        for (var i=0; i<data['_n'].length; i++)
                        {
                            var notice = data['_n'][i];

                            if (typeof notifycallback == 'function')
                            {
                                notifycallback(notice);
                            }
                        }
                    }

                    if (data && data.err && data.err['-attrib-'])
                    {
                        var error = {code:    data.err['-attrib-'].code,
                                     message: data.err['-attrib-'].msg};
                        if (typeof errback == 'function')
                        {
                            errback(error);
                            return;
                        }

                        // No errback, shout out to the world this was not right.
                        console.log("unhandled.... in data.err");
                        $.any.rest.unhandledError(error);
			        }

                    if (typeof callback == 'function')
                    {
			            callback( data );
                    }
			    };

			    opts.error = function ( request, text, errorThrown )
			    {
                    var error = {'code': request.status, 'type': 'http', 'message': text};
                    if (typeof errback == 'function')
                    {
                        errback(error);
                        return;
                    }
                    console.log(text);
                    console.log(errorThrown);


                    console.log(request);

                    $.any.rest.unhandledError(error);
			    };

			    $.ajax( opts );
            },

            /**
             * Redirect to a URL.
             */
            redirect: function ( url )
            {
                $.any.notification.loader.start();
                document.location.href = url;
            },


            /**
             * This function is called when a REST error has not been
             * handled by the caller (e.g., no error callback was
             * given).
             */
            unhandledError: function ( error )
            {
                $.any.notification.error(error.message);
                $.any.notification.loader.stop();
                throw error.code + ": " + error.message;
            }
	    }
    });
})(jQuery);
//

/*  */
/*  */



// External callback to initialize the widget
// @param   mixed   container   jQuery selector for the object to be used
// @param   dom     context     DOM object used as jQuery context. Defaults to document.body
// @return  undefined
function init_unlink( container , context )
{
	context = context || document;
	
	$( container, context ).each(
		function () 
		{
			var options		= jQuery.attrOptions( this , 'unlink' );
			options.ajax	= jQuery.attrOptions( this , 'unlink_ajax' );
            
            if ($(this).data("do_unlink"))
            {
                return;
            }
            $(this).data("do_unlink", true);
			new Unlink( this, options );
		}
	);
}



// External callback for the documentation functions
// @return  object      Structure containing 'examples' of usage, 'about' message, default 'opts', and 'classes' (never used...)
function docs_unlink()
{
	var a = 'Unlink things';
	var e = [];
	var c = [];
	var o = 
	[[ "unlink", 	jQuery.label( 'unlink.title'	, 'Unlink this item'),	"Label - html 'title' attribute of [x]" ]
	,[ "confirm",	jQuery.label( 'unlink.confirm'	, 'Remove'			),	"Label - confirmation text" ]
	,[ "yes",		jQuery.label( 'unlink.yes'		, 'Yes'				),	"Label - confirmation button" ]
	,[ "cancel",	jQuery.label( 'unlink.cancel'	, 'Cancel'			),	"Label - cancelation button" ]
	,[ "service",	"anymeta.edge.remove",	"Name of REST service" ]
	,[ "handle",	'<img src="http://fast.mediamatic.nl/f/xqnl/image/cross.gif" alt="" />', "specify link content" ]
	,[ "ajax",		{},						"Extra ajax parameters" ]
	];
	
	return { 'examples': e, 'about': a, 'opts': o, 'classes': c };
}



// Process the options for this widget (cached)
// @param   object  o   Widget options extracted from the html
// @return  object      Default options overriden by html options
function opts_unlink( o )
{
	window.unlink_opts = window.unlink_opts || docs_unlink().opts;
	return apply_options( window.unlink_opts, o );
}



function Unlink( container, options )
{
	options			= opts_unlink( options );
	this.options	= options;
	this.container	= container;

    this.show();
}



// Callback for when the widget gets out of focus
// @param   string  name    The name of the widget type
// @param   object  obj     The object replacing this one in the widget focus
// @return  bool            True if ajax request made, false otherwise
Unlink.prototype.widgetBlur = function ( name, obj )
{
	if ( obj != this )
	{
		this.selector_dont();
	}
	return false;
};



// Callback for when the [x] is clicked
// @param   event   ev      Click event
// @return  boolean         (Always) false to stop the event propagation
Unlink.prototype.x_fun = function ( ev, obj )
{
	window.widget_manager.widgetFocus( 'unlink', this );
	
    // this.marker.style.display 	= "none";
	// this.selector.style.display = "block";
	
	$(this.selector).fadeIn(300);
	
	var pos = $( obj ).offset();

	$(this.container).addClass('unlinking');

	$( this.selector ).css({
		position: 	"absolute",
		left: 		pos.left,
		top: 		pos.top
	});

	return false;
};



// Make the yes / no confirmation dialog
// @param   string      id      The suffix used in the dom ids of the different elements
// @return  undefined
Unlink.prototype.mk_selector = function ( id )
{
	var div = document.createElement( 'div' );
		div.id = 'unlink_confirm_' + id;
		div.className = 'unlink-confirm';
		div.innerHTML = '<span class="unlink-confirm-text">' + this.options.confirm + '</span>';
		div.style.display = 'none';
		div.style.zIndex = 50000;
		$( document.body ).append( div );

	var buty = document.createElement( 'button' );
		buty.className = 'unlink-confirm-yes cancel';
		buty.innerHTML = this.options.yes;
		$( div ).append( buty );

	var butn = document.createElement( 'button' );
		butn.id = 'unlink-confirm-cancel' + id;
		butn.className = 'cancel';
		butn.innerHTML = this.options.cancel;
		$( div ).append( butn );
		
	this.selector = div;
	this.selector_y = buty;
	this.selector_n = butn;
};



// Make the [x] marker
// @param   string      id      The suffix used in the dom ids of the different elements
// @return  undefined
Unlink.prototype.mk_marker = function ( id )
{
	var del = document.createElement( 'span' );
		del.id = 'unlink_' + id;
		del.className = "unlink-marker";

	var axx = document.createElement( 'a' );
		axx.title 			= this.options.unlink;
		axx.href  			= 'javascript:void(0);';
		
		$(axx).html( this.options.handle );	
		$(axx).css({cursor: 'pointer'});
		$(axx).attr('title', $.label('unlink.confirm'));

    $( del ).append( axx );
    $( this.container ).append( del );
    this.marker     = del;
    this.marker_x   = axx;
};

// Show the [x] symbol and initialize other structures
// @return  undefined
Unlink.prototype.show = function ()
{
	$( this.container ).addClass('unlink-hover');

	// the object which should be removed could be anither one of the 
	this.id = this.options.id || this.container.id;
	
	this.marker || this.mk_marker( this.id );
	// this.marker.style.display = 'block';
		
	this.selector || this.mk_selector( this.id );

	if ( this.container.tagName.toLowerCase() == 'button' ) 
	{
		var mdown = this.container;
	}
	else
	{
		var mdown = this.marker_x;
	}
	
	var self = this;
	
	var fdown = function ( ev )
	{ 
		ev.preventDefault();
		// $( mdown ).unbind( 'mousedown' , fdown );
		self.x_fun( ev, this );
		return false;
	} 
	
	$( mdown ).bind( 'mousedown' , fdown );
	
	$( this.selector_y ).click( 
		function ( ev )
		{ 
			self.selector_do();
			ev.preventDefault();
			return false;
		}
	);

	$( this.selector_n ).click( 
		function ( ev )
		{ 
			self.selector_dont();
			ev.preventDefault();
			return false;
		}
	);	
};



// Callback for when 'yes' is press on the confirmation dialog
// @return  undefined
Unlink.prototype.selector_do = function ()
{
	if ( this.is_unlinked && !this.options.toggle)
	{
		return;
	}

	this.is_unlinked = true;

	this.selector && $( this.selector ).remove();
	this.selector = null;

	var self = this;

    $.any.rest.post(this.options.service, 
                    this.options.ajax,
                    function (result)
                    {
						$( "#" + self.id ).fadeOut('slow');
						$( '#' + self.id ).remove();
                    }
	);
};



// Callback for when 'no' is pressed in the confirmation dialog
// @return  undefined
Unlink.prototype.selector_dont = function ()
{
    if ( this.selector )
    {
        $(this.selector).slideUp(100);
        // this.selector.style.display = 'none';
    }
	$( this.container ).removeClass('unlink-hover').removeClass('unlinking');
};


/*  */
/*  */
// Depends: Ajax/js/any/wysiwyg.js
// Depends: Ajax/js/any/wysiwyg_conf.js
// Depends: Ajax/js/any/tooltip.js

/*  */


// External callback, close all widgets
// @return  undefined
function end_editinplace()
{
	var all = window.widget_manager.widgets( 'editinplace' );
	var fls = window.required_fields;
    
	if ( all && fls )
	{
		for ( var i in all )
		{
			if ( fls[all[i].options.ajax.field] )
			{ 
				all[i].addRequiredClass();
			}
		}
	}
} 


// External callback to initialize the widget
// @param	mixed	    container	jQuery selector for the object to be used
// @param	dom		    context		DOM object used as jQuery context. Defaults to document.body
// @return  undefined
function init_editinplace( container, context )
{
	context = context || document.body;
	
	$( container, context ).each( 
		function ()
		{
			var opts		= jQuery.attrOptions( this, 'editinplace' );
			opts.ajax		= jQuery.attrOptions( this, 'editinplace_ajax' );
			opts.validate	= jQuery.attrOptions( this, 'editinplace_validate' );
			opts.data		= jQuery.attrOptions( this, 'editinplace_data' );
    
			window.widget_manager.add( "editinplace", new EditInPlace( this, opts ) );
		}
	);
}


// External callback for the documentation functions
// @return  undefined
function docs_editinplace()
{
	var a = 'Edit in place implementation';
	var e = 
	[['<div id="ed_body" style=\'display: none;\'>\n<span id="wc_body"></span> words\n</div>\n<div class="do_editinplace" editinplace=\'invisibleId: "ed_body", wordCountId: "wc_body"\' ...>\nmy text\n</div>',
		"Using invisible and word count"]
	,['<div  ... editinplace_validate=\'name: "integer"\' >', 
		"Validation -- must be an integer"]
	,['<span ... editinplace_validate=\'name: "float", min: 0\' >', 
		"Validation -- must be a positive number"]
	,['<p ... editinplace_validate=\'regexp: /[a-z]\w*/, msg: "Please insert a proper variable name"\' >', 
		"Validation -- must be a variable name"]
	];
    
	var c = [];
	
	var le = jQuery.label( 'editinplace.onempty'		, 'Add value'	 );
	var la = jQuery.label( 'editinplace.save'			, 'Save'		 );
	var lc = jQuery.label( 'editinplace.cancel'			, 'Cancel'		 );
	var lm = jQuery.label( 'editinplace.charcountmax'	, 'Too many characters'		 );
	
	var o = 
	[[ "onEmpty",			le,			"Text displayed when field is empty" ]
	,[ "save",				la,			"Label for save button" ]
	,[ "cancel",			lc,			"Label for cancel button" ]
	,[ "paramName",			'value',	"Parameter name in which to send value in ajax request" ]
	,[ "callback",			null,		"Function that gets called after a value is saved" ]
	,[ "type",				'text',		"Type of editinplace [select,text,textarea]" ]
	,[ "minHeight",			400,		"Minimum height of textarea" ]
	,[ "maxHeight",			2000,		"Maximum height of textarea" ]
	,[ "extraHeight",		150,		"Fixed height padding (not added to minimum height)" ]
	,[ "width",				null,		"CSS width for element. Ignores other width options. Use '90%' or '400px'" ]
	,[ "minWidth",			80,			"Minimum width of textarea" ]
	,[ "remWidth",			0,			"Fixed width negative padding (not removed from minimum width)" ]
	,[ "editClass",			null,		"Css class added to container element when in edit mode" ]
	,[ "invisibleId",		null,		"Id of element to show only when in edit mode" ]
	,[ "wordCountId",		null,		"Id of element where the number of words type by the user is to be displayed" ]
	,[ "charCountId",		null,		"Id of element where the number of chars type by the user is to be displayed" ]
	,[ "charCountMax",		null,		"Maximum characters which can be used inside a textarea" ]
	,[ "charCountMaxText",	lm,			"text displayed when too many characters are typed" ]
	,[ "countMaxClass",		'count_max_notice', "Class added when more then the maximum characters is used inside a textarea" ]
	,[ "scompEdit",			null,		"Name of the scomp to fetch and inject as a form" ]
	,[ "scompView",			null,		"Name of the scomp used to display after save" ]
	,[ "ajax",				{},			"Extra ajax parameters" ]
	,[ "data",				{},			"Data for select menu (and later, checkboxes)" ]
	];
	
	o = o.concat( docs_validate().opts );
	
	return { 'examples': e, 'about': a, 'opts': o, 'classes': c };	
}


// Process the options for this widget (cached)
// @param   object  o   Widget options extracted from the html
// @return  object      Default options overriden by html options
function opts_editinplace( o )
{
	window.editinplace_opts = window.editinplace_opts || docs_editinplace().opts;
	return apply_options( window.editinplace_opts, o );
}


// CLASS EditInPlace
function EditInPlace( container, options )
{
	options			= opts_editinplace( options );
	this.options	= options;
	this.throbber	= '<img src="http://fast.mediamatic.nl/f/xqnl/image/throbberdots.gif" />';
	
	this.container	= container;
	this.invisible	= document.getElementById( options.invisibleId );
	this.wordCount	= document.getElementById( options.wordCountId );
	this.charCount	= document.getElementById( options.charCountId );
	this.validate	= new Validate( options.validate );
    
	this.container.editinplace_widget	= this;
	this.ajaxNotice = new AjaxNotice( this.container );
    
	this.spaceHolder();
	this.orgHTML 		= this.container.innerHTML; 
    
	var self = this;

	$(self.container).addClass('editable-area');

	$(container).bind('mouseover', function (e) 
	{
		if(!self.editing)
		{
			$(self.container).addClass('editinplace-hover');
		}
	})
	.bind('mouseout', function(e) 
	{
		if(!self.editing)
		{
			$(self.container).removeClass('editinplace-hover');
		}
	})
	.bind('mousedown', function(e) 
	{
		$(self.container).removeClass('editinplace-hover').removeClass('editable-area').addClass('editinplace-active');
		self.show();
	});
	
	options.showonload && this.show();
}


// Callback for when the widget gets out of focus
// @param   string  name    The name of the widget type
// @param   object  obj     The object replacing this one in the widget focus
// @return	boolean	        True if ajax request made, false otherwise
EditInPlace.prototype.widgetBlur = function( name, obj )
{
	var s = false;
	if ( obj != this && this.editing )
	{
		s = this.save( true );
		s || this.cancel();
	}
	return s;
};


// Reset the html (close widget)
// @return  undefined
EditInPlace.prototype.reset = function( html )
{
	$(this.container)
		.html(html != null ? html : this.orgHTML)
		.removeClass('editinplace-active');
	this.spaceHolder();
};


// When an empty string was saved we use a space holder with some text
// @return  undefined
EditInPlace.prototype.spaceHolder = function ()
{
	if ( this.container.innerHTML.match( /^(\s*)$/ ) ) 
	{
		this.container.innerHTML = '<span class="editinplace-onempty">' + this.options.onEmpty + '</span>';
		this.required && this.addRequiredClass();
	}
};


// Element is a required field,
// Add css class
// @return undefined
EditInPlace.prototype.addRequiredClass = function ()
{
	this.required = true;
	$( this.container ).addClass( 'required_field' );
};


// Remove css class of required field
// @return  undefined
EditInPlace.prototype.remRequiredClass = function ()
{
	$( this.container ).removeClass( 'required_field' );
};


// Go into edit mode
// @return  undefined
EditInPlace.prototype.editable = function ()
{
	window.widget_manager.widgetFocus( 'editinplace', this );
    
	this.required && this.remRequiredClass();
    
	this.editing 		= true;
	this.orgHeight		= jQuery.getSize( this.container ).h;
	this.orgWidth		= jQuery.getSize( this.container ).w;
	//this.orgTop			= jQuery.getPosition( this.container ).y;
	//this.orgLeft		= jQuery.getPosition( this.container ).x;
	
	$(this.container).html(this.throbber);
	
	//var loader = $('<div></div>').addClass('loading').css({color: '#8c8c8c', opacity: .60, position: 'absolute', top: this.orgTop, left: this.orgLeft, height: this.orgHeight, width: this.orgWidth}).html(this.throbber);
	//$(document.body).append(loader);
	
	this.invisible && $( this.invisible ).show();
		
	if ( this.options.editClass )
	{
		$( this.container ).addClass( this.options.editClass );
	}
    
	if ( this.options.type == 'scomp' )
	{
		var ajax = jQuery.assocMerge( this.options.ajax, { name: this.options.scompEdit } );
        var method = 'anymeta.html.scomp';
	}
	else
	{
		var ajax = this.options.ajax;

		var method = this.options.ajax.edge ? 'anymeta.edge.attribute.get' : 'anymeta.predicates.get';
	}
    
	var self = this;        

	var call = function ( result ) 
	{ 
		self.ajaxNotice.stop();
		self.processGet( result );
		//loader.remove();
	}; 

 	
	this.ajaxNotice.start( '...' );
	$.any.rest.get(method, ajax, call, function(error) {self.showError(error, self)} );
};


// Go into edit mode if not there alreaady
// @return  undefined
EditInPlace.prototype.show = function ()
{
	if ( this.editing )
	{
		return;
	}
    
	this.saving = false;
	this.editable();
};


// Copy relevant css styles from the one element to another
// @param   dom         o   Node to copy style from 
// @param   dom         n   Node to copy style to
// @return  undefined
EditInPlace.prototype.copyStyle = function( o , n )
{
	var fs = anyGetComputedStyle( o , 'font-size' );
	
	if ( fs.search( '%' ) < 0 && fs.search( 'em' ) < 0 )
	{
		// Set the font size and the line height
		n.style.fontSize	= fs;
		n.style.lineHeight	= anyGetComputedStyle( o , 'line-height' );
	}
	else
	{
		// If the font size is given in percentage, set it 
		// to 100% and don't set the line height 
		n.style.fontSize 	= '100%';
		n.style.lineHeight	= anyGetComputedStyle( o , 'line-height' );
	}
	
	// Copy other relevant css values
	n.style.fontFamily		= anyGetComputedStyle( o , 'font-family' );
	n.style.fontWeight		= anyGetComputedStyle( o , 'font-weight' );
	n.style.textTransform	= anyGetComputedStyle( o , 'text-transform' );
	n.style.color			= anyGetComputedStyle( o , 'color' );
	n.style.fontStyle	 	= anyGetComputedStyle( o , 'font-style' );
	n.style.backgroundColor = copyStyleWhile( o , 'background-color', 'rgba(0, 0, 0, 0)' , 'grey' );
};


// Do not react to Escape and Enter keyboard commands
// @param   dom         i       Input node to which events are attached
// @param   boolean     enter   True if return key should be used for submiting
// @return  undefined
EditInPlace.prototype.applyInputEvents = function ( i, enter )
{
	var self = this;
	$( i ).keydown( 
		function( e ) 
		{
			if ( e.keyCode == 27 ) 
			{ 
				// ESC
				e.preventDefault();
				$(self.container).addClass('editable-area');
				self.cancel();
			} 
			else if ( e.keyCode == 13 && enter )
			{ 
				// Enter
				e.preventDefault();
				$(self.container).addClass('editable-area');
				self.save();
			}
		}
	);
};


// Get edited-in-place value
// @return  string      Value the user entered
EditInPlace.prototype.getValue = function ()
{
	var ret = {};
	ret[this.options.paramName] = this.mydiv.i.value;
	return ret;
};


// Append Save and Cancel buttons
// @return  undefined
EditInPlace.prototype.appendButtons = function ()
{
	var bSave	= this.addButton( this.options.save   , 'submit' );
	var bCancel	= this.addButton( this.options.cancel , 'cancel' );
    
	var self = this;
	$( bSave ).click( 
		function ( e ) 
		{
			e.preventDefault();
			$(self.container).addClass('editable-area');
			self.save();
			return false;
		}
	);
	
	$( bCancel ).click( 
		function ( e ) 
		{
			e.preventDefault();
			$(self.container).addClass('editable-area');
			self.cancel();
			return false;
		}
	);
};


// Add a button for the editinplace form (used for submit/cancel buttons)
// @param   string  value   Button text
// @param   string  c       Suffix of the classname of the button ('editinplace_<c>')
// @param   string  t       Type of button (optional)
// @return  dom             New input field
EditInPlace.prototype.addButton = function ( value , c , t )
{
	var b		= document.createElement("button");
//	b.type		= t || 'submit';
	b.innerHTML	= value;
	b.className	= 'editinplace-' + c ;
	this.mydiv.appendChild( b );
	return b;
};


// When edit mode form elements come from a server scomp instead
// of being generated with js, this function is used to save the 
// (indeterminate number of) values
// @param   boolean    silent  Not used in this function. Here for consistency  
// @return  object             Data to be sent to server 
EditInPlace.prototype.saveScomp = function ( silent )
{
	var self = this;
	var vals = {};
	vals['field'] = [];
	vals['value'] = [];
	var func = function () 
	{
		if ( this.type != 'button' && this.type != 'submit' )
		{
			vals['field'].push( this.name  );
			vals['value'].push( this.value );
		}
	};
	
	$( 'input',		this.scomp ).each( func );
	$( 'textarea',	this.scomp ).each( func );
	$( 'select',	this.scomp ).each( func );
	
	return jQuery.assocMerge( this.options.ajax, vals );
};


// Save the edit mode values when the form was generated using js
// @param   boolean    silent  Don't notify the user about errors
// @return  object             Data to be sent to server 
EditInPlace.prototype.saveInline = function ( silent )
{
	var v	= this.getValue();
	var x	= v[this.options.paramName];
	
	if ( !this.validate.value( x ) )
	{
		silent || alert( this.validate.opts.msg );
		return false;
	}
    
	if ( !this.validate.range( x ) )
	{
		silent || alert( this.validate.opts.out );
		return false;
	}
	
	return jQuery.assocMerge( this.options.ajax, v );
};


// Get the edit mode form values, send them to server
// @param   boolean    silent   Don't notify the user about errors
// @return  boolean             False if save action was not executed 
EditInPlace.prototype.save = function ( silent )
{
	if ( !this.saving )
	{
		var o = this.options.type == 'scomp' ? this.saveScomp( silent ) : this.saveInline( silent );
		if ( o )
		{
			// if too many characters are typed show a message 
			var v = false;				
			if ( $( 'textarea', this.container ).get(0)
			  && $( 'textarea', this.container ).get(0).value )
			{
				v = this.countChars( $( 'textarea', this.container ).get(0).value );
			}
			else if ( $( 'input', this.container ).get(0)
			  	  && $( 'input', this.container ).get(0).value )
			{
				v = this.countChars( $( 'input', this.container ).get(0).value );
			}

			$(this.container).html(this.throbber).removeClass('editinplace-active');

			if ( v
			  && this.options.charCountMax 
			  && v > this.options.charCountMax )
			{
				this.invisible && $( this.invisible ).show();
			}
			else
			{
				this.invisible && $( this.invisible ).hide();
			}
			this.saving = true;
    
			if ( this.options.scompView )
			{
				o.name = this.options.scompView;
			}
    
			var self = this;		
			var m = this.options.ajax.edge ? "anymeta.edge.attribute.set" : "anymeta.predicates.set";

			var f = function ( result )
			{
				self.ajaxNotice.stop();
				self.processSet( result ); 
			};
    		
            
			this.ajaxNotice.start( '...' );
			$.any.rest.post( m, o, f, self.showError );

			if (EditInPlace.prototype.helptext)
			{
				$(this.container).attr('title',EditInPlace.prototype.helptext);
			}
			
			return true;
		}
	}
	return false;
};


EditInPlace.prototype.showError = function(error, self)
{
    jQuery.warn( "EditInPlace" , error.message );
    console.info(self, error);
	self.reset();
	self.editing = false;
	return;
    
    self.ajaxNotice.stop();

}

// Cancel the edit-in-place, put the form back where it was
// @return  undefined
EditInPlace.prototype.cancel = function ()
{
	$( this.container ).removeClass( 'editinplace-hover' );
	this.reset();
	this.options.editClass  &&  $( this.container ).removeClass( this.options.editClass );
	this.editing 		= false;
	this.invisible && $( this.invisible ).hide();
	
	if (EditInPlace.prototype.helptext)
	{
		$(this.container).attr('title',EditInPlace.prototype.helptext);
	}
};


// Callback for when the scomp comes from the server. 
// Insert it into the page
// @param   result  result     Return from the ajax request
// @return  null    Always returns null
EditInPlace.prototype.processGetScomp = function ( result )
{
	var ts	= result.html;
	if ( ts )
	{
		this.scomp = document.createElement( 'span' );
    
		$( this.scomp ).append( ts ); 
		$( this.mydiv ).append( this.scomp ); 
		var self = this;
		$( 'input', this.scomp ).each(
			function () 
			{
				self.applyInputEvents( this, true );
			}
		);
	}
	
	return null;
};

// Callback for when the server replies with the editable value
// Create a form and inject the value into it
// @param   object result     Return from ajax request
// @return  dom               The first input field (to call focus() on)            
EditInPlace.prototype.processGetInline = function ( result )
{
	var r = result.result;

	var firstInput = this.appendInputs( r );

	return firstInput;
};

// Callback for ajax request that gets the value from the server
// @param   object         result     Return from ajax request
// @return  undefined
EditInPlace.prototype.processGet = function ( result )
{
	this.container.innerHTML = '';
	
	this.mydiv = document.createElement( 'div' );
	this.mydiv.style.display = 'inline';
    
	if ( this.options.type == 'scomp' )
	{
		var firstInput = this.processGetScomp( result );
	}
	else
	{
		var firstInput = this.processGetInline( result );
	}
	
	this.appendButtons();
	
	// For some reason this has to be done after the 
	// me.mydiv.innerHTML is altered, otherwise IE fails
	this.container.appendChild( this.mydiv );
	
	// initialize the editorial editor
	$(firstInput).wysiwyg({
		field: this.options.ajax.field
	});
	
	this.calculateInputSize(firstInput);
	this.addhelptexts(firstInput);
	
	$(firstInput).focus();	
};

// Append parent width to inputs and textareas
EditInPlace.prototype.calculateInputSize = function(input)
{
    // Append width to input box
    var borderWidths = parseInt($(input).css('borderLeftWidth'), 10) + parseInt($(input).css('borderRightWidth'), 10);
    var paddingWidths = parseInt($(input).css('paddingLeft'), 10) + parseInt($(input).css('paddingRight'), 10);
    $(input).css({ width: $(this.container).width() - (borderWidths + paddingWidths) });
};

EditInPlace.prototype.addhelptexts = function(obj)
{
	EditInPlace.prototype.helptext = $(this.container).attr('title');
	
	if(EditInPlace.prototype.helptext)
	{
		var el = $('<div></div>').addClass('help-text').html('<p>'+EditInPlace.prototype.helptext+'</p>');
		$(obj).parent().before(el);
		$(this.container).attr('title','');
	}
}

// Callback for ajax request that sets the value from the server
// @param   object     result     The value return by the ajax request
// @return  boolean         True on success
EditInPlace.prototype.processSet = function ( result )
{
        if (typeof result.result == 'string')
        {
                // We have a string in result: replace the old value with it
                r = result.result
        }
        else
        {
                // We have an object: take the first value
                for (key in result.result)
                {
                        r = result.result[key];
                        break; 
                }
        }
	
        this.orgHTML = r;
	this.container.innerHTML = r;
        
	// Insert the space holder if blank
	this.spaceHolder();
	
	// Callback if necessary
	this.options.callback && this.options.callback( this.container ); 
	
	// Release
	this.editing = false;
    
    return false;
};


// Add an input field
// @param   string  tag     Html tag name (which kind of html node to create)
// @param   string  value   The value
// @param   string  cla     The suffix for the classname 
// @param   string  type    The type
// @return  dom             The created input element
EditInPlace.prototype.addInput = function ( tag , value , cla , type )
{
	var i = document.createElement( tag );
	this.mydiv.appendChild( i );
	this.mydiv.i	= i;
	i.value			= value;
	xtr_class = '';
	if ( type == 'text' )
	{
		xtr_class = 'text';
	}
	i.className 	= '' + xtr_class + ' editinplace-input editinplace-' + cla;
	
	if ( type )
	{
		i.type = type;
	}
	
	this.copyStyle( this.container , i );
	this.applyInputEvents( i, this.options.type == 'text'  );
	
	return i;
};


// Count the words in a string. Used when the wordCountId options is set.
// @param   string      str     Text
// @return  integer             Number of words
EditInPlace.prototype.countWords = function ( str )
{
	words = str.split( /[^\w\-]+/ );
	var n = words.length;
 	n -= words[0] 				== '' ? 1 : 0;
 	n -= words[words.length-1]	== '' ? 1 : 0;
	return n < 0 ? 0 : n;
};

// Count the characters in a string. Used when the charCountId options is set.
// @param   string      str     Text
// @return  integer             Number of chars
EditInPlace.prototype.countChars = function ( str )
{
	chars = str.length;
	return chars <= 0 ? 0 : chars;
};

// Event handler for the word counting feature
// @param   dom         elem   Input element that will contain the text 
// @return  undefined 
EditInPlace.prototype.addWordCount = function ( elem )
{
	if ( this.wordCount )
	{
		var self = this;
		$( elem ).keyup( 
			function ( e ) 
			{
				var key = e.charCode || e.keyCode || -1;
				switch( key ) {
					case 8: 	// backspace
					case 13: 	// enter
					case 32: 	// space
						self.lastup = true;
						break;
					case 27: 	// escape
					case 35: 	// end
					case 36: 	// home
					case 38: 	// up
					case 40: 	// down
					case 63232: // up 
					case 63233: // down
					case 63273: // home
					case 63275: // end 
						var exit = self.lastup;
						self.lastup = true;
						break;
					default:
						var exit = !self.lastup;
						self.lastup = false;
						break;
				}
				
				if ( !exit )
				{
					$( self.wordCount ).html( self.countWords( elem.value ) );
				}
			}
		);
	}
};

// Event handler for the char counting feature
// @param   dom         elem   Input element that will contain the text 
// @return  undefined 
EditInPlace.prototype.addCharCount = function ( elem )
{
	if ( this.charCount )
	{
		var self = this;
		$( elem ).keyup( 
			function ( e ) 
			{
				var key = e.charCode || e.keyCode || -1;
				switch( key ) {
					case 13: 	// enter
					case 27: 	// escape
					case 35: 	// end
					case 36: 	// home
					case 38: 	// up
					case 40: 	// down
					case 63232: // up 
					case 63233: // down
					case 63273: // home
					case 63275: // end 
						var exit = false;
						break;
					default:
						var exit = true;
						break;
				}
				
				if ( exit )
				{
					v = self.countChars( elem.value );
					self.addCharCountShow( elem, v );
				}
			}
		);
		v = this.countChars( elem.value );
		this.addCharCountShow( elem, v );
	}
};

// @param   elem, v
// @return  null    
EditInPlace.prototype.addCharCountShow = function ( elem, v )
{
	if ( this.options.charCountMax 
	  && v > this.options.charCountMax )
	{
		$( elem ).css('background-color', '');
		$( elem ).addClass( this.options.countMaxClass );
		$( this.charCount ).html( '<span class="' + this.options.countMaxClass + '">' + this.options.charCountMaxText + '</span> ' + v );
	}
	else
	{
		$( elem ).css('background-color', 'transparent');
		$( elem ).removeClass( this.options.countMaxClass );
		$( this.charCount ).html( '' + v + '' );
	}
};

// Generate the editinplace for a select type of value 
// Not sure if it is being used anywhere at the moment!
// @param   
// @return  null    
EditInPlace.prototype.dropdown = function ( v )
{
	var d = this.options.data;
	var r = document.createElement( 'select' );
	var o = null;
	for ( var i in d )
	{
		o = document.createElement( 'option' );
		o.innerHTML = d[i];
		o.value		= i;
		if ( i == v )
		{
			o.selected = 'yes';
		}
		r.appendChild( o );
	}
	this.mydiv.appendChild( r );
	this.mydiv.i = r;
	return null;
};


// Generate the editinplace for a checkbox type of value 
// Not sure if it is being used anywhere at the moment!
// @return  null
EditInPlace.prototype.checkbox = function ()
{
	var d = this.options.data;
	var o = null;
	for ( var i in d )
	{
		o = document.createElement( 'input' );
		o.type		= 'checkbox';
		o.value		= i;
		if ( d[i] )
		{
			o.checked = "yes";
		}
		this.mydiv.appendChild( o );
	}
	this.mydiv.i = null;
	return null;
};


// Add the correct input elements in the page
// @param   string  v   Editable value as requested from server
// @return  dom         Node to append
EditInPlace.prototype.appendInputs = function ( v )
{
	var r = null;
	var width;
	
	if ( this.options.type == "textarea" ) 
	{
		r = this.addInput( 'textarea' , v , 'multiline' );
		
		if ( this.wordCount )
		{
			$( this.wordCount ).html( this.countWords( v ) );
		}
		this.addWordCount( r );

		if ( this.charCount )
		{
			$( this.charCount ).html( this.countChars( v ) );
		}
		this.addCharCount( r );

		r.style.height	= Math.min( Math.max( this.orgHeight + this.options.extraHeight , this.options.minHeight ) , this.options.maxHeight ) + 'px';
		if ( this.options.width )
		{
			width = this.options.width;
		}
		else
		{
			width = Math.max( this.orgWidth - this.options.remWidth , this.options.minWidth );
		}

		// The witdh could be percentual or in pixels. Do not add the px again
		if ( isNaN(width) && (width.indexOf("%") >= 0 || width.indexOf("px") >= 0) )
		{
			r.style.width = width;
		}
		else
		{
			r.style.width = width  + 'px';
			
			// If this check is done in IE it breaks
			if ($.browser.safari)
			{
				r.style.maxWidth = width - 16 + 'px'; // Safari scrolls horizontally otherwise
			}
		}
		
	}
	else if ( this.options.type == "text" )
	{
		var r 		= this.addInput( 'input' , v , 'oneline' , 'text' );
		if ( this.charCount )
		{
			$( this.charCount ).html( this.countChars( v ) );
		}
		this.addCharCount( r );

		r.style.width	= '96%';
	}
	else if ( this.options.type == 'select' )
	{
		r = this.dropdown( v );
	}
	else if ( this.options.type == 'checkbox' )
	{
		r = this.checkbox();
	}
	
	return r;
};


// Left-pad a string
// @param   object  value   Value to pad 
// @param   integer size    Number of characters to pad string to
// @param   string  c       Character to pad with
// @return  string          Padded string with minimum length 'size'
function pad( value, size, c )
{
	c = c || '0';
	value = '' + value;
	size  = Math.max( size - value.length , 0 );
	while ( size-- )
	{
		value = c + value;
	}
	return value;
}


// Copy entire style definition of a node into another
// @param   dom         target     Node to copy style to 
// @param   dom         source     Node to copy style from
// @return  undefined
function copyAllStyle ( target , source ) 
{
	// work around for opera which doesn't have cssText, and for IE which fails on setAttribute 
	if ( !source.style.cssText )
	{
		target.setAttribute( "style", source.getAttribute( "style" ) );
	}
	else
	{
		target.style.cssText = source.style.cssText; 
	}
    
	$( target ).addClass( source.className );
}


// Get the css value for an attribute of a node, using a value as stop condition
// @param   dom     e       Node to start from
// @param   string  name    Css attribute name
// @param   object  value   Stop value
// @param   object  def     Default value to return in case of failure
// @return  object          Css value
function copyStyleWhile( e , name , value , def )
{
	var x = '';
    
	do 
	{
		x = anyGetComputedStyle( e , name );
		e = e.parentNode;
	}
	while ( ( !x || x == value ) && e );
	
	if ( !x || x == value )
	{
		x = def;
	}
	return x;
}

/*  */
(function($) 
 { 	/*
	*	wysiwyg
	*	Has the default values, and initiates the editor
	*
	*	@param	options		Array of all options
	*/
	$.fn.wysiwyg = function(options) 
	 { 		var opts = $.extend({}, $.fn.wysiwyg.defaults, options);
		
		$.fn.wysiwyg.label_add_link 	= jQuery.label('wysiwyg.add_link' 		, 'add the link');
		$.fn.wysiwyg.label_add_youtube	= jQuery.label('wysiwyg.add_youtube'	, 'add youtube');
		$.fn.wysiwyg.label_add_title 	= jQuery.label('wysiwyg.add_title' 		, 'add the title of the link');
		$.fn.wysiwyg.label_ok		 	= jQuery.label('wysiwyg.ok' 			, 'ok');
		$.fn.wysiwyg.label_cancel 		= jQuery.label('wysiwyg.cancel' 		, 'cancel');
		$.fn.wysiwyg.label_youtube_expl = jQuery.label('wysiwyg.youtube_expl' 	, 'You can find the YouTube code in the link, for example http://www.youtube.com/watch?v=nogDHP0gl9M, gives the code nogDHP0gl9M. Youhave to copy the movie code between = and before the &.');
 				
		return this.each( function() 
		 { 			$.fn.wysiwyg.initEditor(this, opts);
		});
 } 	
	/*
	*	wysiwyg.initEditor
	*	creates wapper div, reads the options array and calls the activate buttons function
	*	
	*	@param	object		The object you are working on
	*	@param	opts		The array of options
	*/
	$.fn.wysiwyg.initEditor = function(object, opts) 
	 { 		if(!!document.selection)
		 { 			$(object)
			.keyup(function()
			 { 				$.fn.wysiwyg.range = document.selection.createRange();
			})
			.click(function()
			 { 				$.fn.wysiwyg.range = document.selection.createRange();
			});
	 } 
		var ctr = opts.controls;
		var fld	= opts.field;
	
		if(ctr[fld])
		 { 			$.fn.wysiwyg.toolbar = $('<div></div>', object).addClass('toolbar clearfix');
			$(object).before(this.toolbar);
			
			$(object).resizable( { 
				handles: "s",
				preventDefault: true
			});

			for(i = 0; i < ctr[fld].length; i++)
			 { 				$.fn.wysiwyg.addButton(object, ctr[fld][i][3], ctr[fld][i][0], ctr[fld][i][1], ctr[fld][i][2]);		
		 } 	 }  } 
	
	/*
	*	wysiwyg.addButton
	*	creates the buttons, is there an array key that says own_function = true, then it does special stuff
	*
	*	@param	object			The object you are working on
	*	@param	classname		Classname of the button you are adding	
	*	@param	html			Html to write in the button
	*	@param	prefix			The prefix of the wiki tag	
	*	@param	suffix			The suffix of the wiki tag	
	*/
	$.fn.wysiwyg.addButton = function(object, classname, html, prefix, suffix)
	 { 		$('<button></button>')
				.addClass('toolbar-button-' + classname)
				.html(html)
				.click(function() 
				 { 					if(classname == 'youtube')
					 { 						$.fn.wysiwyg.doYoutube(object);
				 } 					else if(classname == 'link')
					 { 						$.fn.wysiwyg.doLink(object);
				 } 					else
					 { 						$.fn.wysiwyg.wrapSelection(object, prefix, suffix);
				 } 				})
				.appendTo(this.toolbar);
 } 	
	/*
	*	wysiwyg.getSelection
	*	returns the selection
	*
	*	@param	object			The object you are working on
	*/	
	$.fn.wysiwyg.getSelection = function(object)
	 { 		if(!!document.selection)
		 { 			return document.selection.createRange().text;
	 } 		else if(!!object.setSelectionRange)
		 { 			return object.value.substring(object.selectionStart,object.selectionEnd);
	 } 		else
		 {  
			return false;
	 }  } 
	/*
	*	wysiwyg.replaceSelection
	*	replaces the selection
	*
	*	@param	object			The object you are working on
	*	@param	string			string of thext to replace	
	*/	
	$.fn.wysiwyg.replaceSelection = function(object, text)
	 { 		var scroll_top = object.scrollTop;
				
		if(!!document.selection)
		 { 			$(object).focus();
			var range = (this.range) ? this.range : document.selection.createRange();
			
			range.text = text;
				
			range.select();
	 } 		else if(!!object.setSelectionRange)
		 { 			var selection_start = object.selectionStart;
			object.value 		= object.value.substring(0, selection_start) + text + object.value.substring(object.selectionEnd);
			
			object.setSelectionRange(selection_start + text.length, selection_start + text.length);
	 } 		
		object.scrollTop = scroll_top;
 } 	
	/*
	*	wysiwyg.wrapSelection
	*	wraps the selection with tags
	*
	*	@param	object			The object you are working on
	*	@param	before			string of thext	
	*	@param	after			string of thext	
	*/
	$.fn.wysiwyg.wrapSelection = function(object, before, after)
	 { 		var range = $(object).focus().caret();
		
		var new_val = $(object).caret().replace(before + range.text + after);
		
		$(object).val(new_val);
		
		var caret_pos = range.start + before.length + range.text.length;
		
		if (range.text)
		 { 			caret_pos += after.length;
	 } 		
		if ($.browser.msie) // IE counts line breaks differently, correct this
		 { 			var num_enters = Math.floor( object.value.substr(0,caret_pos).split(/(\r\n)/).length / 2 );
			caret_pos -= num_enters;
	 } 		
		$(object).blur().focus().caret(caret_pos,caret_pos); // blur().focus() is for Fx
 } 	
  	/* special functions */
  	
  	$.fn.wysiwyg.youtubeForm = function(object, what)
	 { 	  	if(what == 'create') 
	  	 { 
	  		$.fn.wysiwyg.youtube_form = $('<div class="youtube_form_wrapper"><p style="font-size: .9em;">'+$.fn.wysiwyg.label_youtube_expl+'</p><input type="text" value="'+$.fn.wysiwyg.label_add_youtube+'" class="youtube_code" /><button class="youtube_button_ok">'+$.fn.wysiwyg.label_ok+'</button><button class="youtube_button_cancel">'+$.fn.wysiwyg.label_cancel+'</button></div>', object);
	   		
	   		this.youtube_form.hide();
	   		this.youtube_form.appendTo(this.toolbar);
	    } 	   	
	   	if(what == 'show')  { $.fn.wysiwyg.youtube_form.slideDown('fast'); } 	   	if(what == 'hide')  { $.fn.wysiwyg.youtube_form.slideUp('fast'); } 	   	if(what == 'remove')  { $.fn.wysiwyg.youtube_form.remove(); }  } 	
	$.fn.wysiwyg.linkForm = function(object, what)
	 { 	  if(what == 'create_all') 
	   	 { 
	   		$.fn.wysiwyg.link_form = $('<div class="link_form_wrapper"><input type="text" class="link_url" value="'+$.fn.wysiwyg.label_add_link+'" />&nbsp;<input type="text" class="link_title" value="'+$.fn.wysiwyg.label_add_title+'" /><button class="link_button_ok">'+$.fn.wysiwyg.label_ok+'</button><button class="link_button_cancel">cancel</button></div>', object);
	   		
	   		this.link_form.hide();
	   		this.link_form.appendTo(this.toolbar);
	    } 	   	
	   	if(what == 'create_url') 
	   	 { 
	   		$.fn.wysiwyg.link_form = $('<div class="link_form_wrapper"><input type="text" class="link_url" value="'+$.fn.wysiwyg.label_add_link+'" /><button class="link_button_ok">'+$.fn.wysiwyg.label_ok+'</button><button class="link_button_cancel">'+$.fn.wysiwyg.label_cancel+'</button></div>', object);
	   		
	   		this.link_form.hide();
	   		this.link_form.appendTo(this.toolbar);
	    } 	   	
	   	if(what == 'show')  { $.fn.wysiwyg.link_form.slideDown('fast'); } 	   	if(what == 'hide')  { $.fn.wysiwyg.link_form.slideUp('fast'); } 	   	if(what == 'remove')  { $.fn.wysiwyg.link_form.remove(); }  }   	
  	$.fn.wysiwyg.doYoutube = function(object)
  	 { 		if ( $('.youtube_form_wrapper').length )
		 {   			return;
	 } 		else
		 { 			var selection = this.getSelection(object);  
			
			if(selection)
			 { 				this.replaceSelection(object, '[[youtube ' + selection +']]');  
		 } 			else
			 { 				this.youtubeForm(object, 'create');
				this.youtubeForm(object, 'show');
				
				$('.youtube_button_ok').click(function()
				 { 					var youtube_code = $('.youtube_code').val();
					
					$.fn.wysiwyg.replaceSelection(object, '[[youtube ' + youtube_code +']]');  
					$.fn.wysiwyg.youtubeForm(object, 'remove');
				});
				
				$('.youtube_button_cancel').click(function() 
				 { 					$.fn.wysiwyg.youtubeForm(object, 'remove');
					$(object).focus();
				});
		 } 	 }    }   	
  	$.fn.wysiwyg.doLink = function(object)
  	 { 		if ( $('.link_form_wrapper').length )
		 {   			return;
	 } 		else
		 { 		
			var selection = this.getSelection(object);  
			
			if(selection)
			 { 				this.linkForm(object, 'create_url');
				this.linkForm(object, 'show');
				
				$('.link_button_ok').click(function()
				 { 					var url = $('.link_url').val();
					$.fn.wysiwyg.replaceSelection(object, '[' + url + ' ' + selection + ']');
					$.fn.wysiwyg.linkForm(object, 'remove');
				});
		 } 			else
			 { 				this.linkForm(object, 'create_all');
				this.linkForm(object, 'show');		
					
				$('.link_button_ok').click(function()
				 { 					var url 	= $('.link_url').val();
					var title 	= $('.link_title').val();
					
					$.fn.wysiwyg.replaceSelection(object, '[' + url + ' ' + title + ']');
					$.fn.wysiwyg.linkForm(object, 'remove');
				});
		 } 			
			$('.link_button_cancel').click(function() 
			 { 				$.fn.wysiwyg.linkForm(object, 'remove');
				$(object).focus();
			});
	 }    }   	
  	$.fn.wysiwyg.wikidefaults = 
	 { 		h3: 	 ['subhead','+++ ',''],
		h4: 	 ['small subhead','++++ ',''],
		bold: 	 ['bold','**','**'],
		italic:  ['italic','//','//'],
		link: 	 ['link','',''],
		youtube: ['youtube','','']
	};
	
	$.fn.wysiwyg.defaults =  { 		controls:
		 { 			'text.intro':
			[
				$.fn.wysiwyg.wikidefaults.italic,
				$.fn.wysiwyg.wikidefaults.link
			],
			'text.body':
			[
				$.fn.wysiwyg.wikidefaults.h3,
				$.fn.wysiwyg.wikidefaults.italic,
				$.fn.wysiwyg.wikidefaults.link,
				$.fn.wysiwyg.wikidefaults.youtube
			]
	 } 	};	
})(jQuery);

$.fn.wysiwyg.label_buttons_bold 	= jQuery.label('wysiwyg.buttons.bold', 		'bold');
$.fn.wysiwyg.label_buttons_italic 	= jQuery.label('wysiwyg.buttons.italic', 	'italic');
$.fn.wysiwyg.label_buttons_link 	= jQuery.label('wysiwyg.buttons.link', 		'link');
$.fn.wysiwyg.label_buttons_youtube 	= jQuery.label('wysiwyg.buttons.youtube', 	'youtube');
$.fn.wysiwyg.label_buttons_h1	 	= jQuery.label('wysiwyg.buttons.h1', 		'hige head');
$.fn.wysiwyg.label_buttons_h2	 	= jQuery.label('wysiwyg.buttons.h2', 		'medium head');
$.fn.wysiwyg.label_buttons_h3	 	= jQuery.label('wysiwyg.buttons.h3', 		'subhead');
$.fn.wysiwyg.label_buttons_h4	 	= jQuery.label('wysiwyg.buttons.h4', 		'small subhead');

$.fn.wysiwyg.wikidefaults = 
{
	h1:		[$.fn.wysiwyg.label_buttons_h1,'+ ','','h1'],
	h2:		[$.fn.wysiwyg.label_buttons_h2,'++ ','', 'h2'],
	h3: 	[$.fn.wysiwyg.label_buttons_h3,'+++ ','', 'h3'],
	h4: 	[$.fn.wysiwyg.label_buttons_h4,'++++ ','', 'h4'],
	bold: 	[$.fn.wysiwyg.label_buttons_bold,'**','**', 'bold'],
	italic: [$.fn.wysiwyg.label_buttons_italic,'//','//', 'italic'],
	link: 	[$.fn.wysiwyg.label_buttons_link,'','', 'link'],
	youtube:[$.fn.wysiwyg.label_buttons_youtube,'','', 'youtube']
};

$.fn.wysiwyg.defaults = {
	controls:
	{
	
			'text.intro':
		[
					$.fn.wysiwyg.wikidefaults.italic,					$.fn.wysiwyg.wikidefaults.link,					$.fn.wysiwyg.wikidefaults.youtube				],			'text.body':
		[
					$.fn.wysiwyg.wikidefaults.h4,					$.fn.wysiwyg.wikidefaults.bold,					$.fn.wysiwyg.wikidefaults.italic,					$.fn.wysiwyg.wikidefaults.link,					$.fn.wysiwyg.wikidefaults.youtube				]			}
}
//
// External callback to initialize the widget
// @param	mixed	container	jQuery selector for the object to be used
// @param	dom		context		DOM object used as jQuery context. Defaults to document.body
function init_tooltip ( container, context )
{
	context = context || document.body;
	
	$(container, context).each(function()
	{
		var opts = jQuery.attrOptions( this , 'tooltip' );
		new Tooltip( this, opts );
	});
}

// External callback for the documentation functions
// @return  object      Structure containing 'examples' of usage, 'about' message, default 'opts', and 'classes' (never used...)
function docs_tooltip()
{
	var a = 'Mouse-pivoted tooltip that behaves intelligently against screen limits';
	var e = 
	[
		[ '<a class="do_tooltip" title="my tooltip text"', "simple popup using a custom div id" ],
	];
	
	var c = [];
	
	var o = 
	[ 
	 	[ 'timeover'			,50,				  					'Number of milliseconds before tooltip appears' ],
		[ 'effectover'			,{opacity: "show"}, 				 	'Action when hovering over. {opacity: \'toggle\', height: \'toggle\'}' ],
	 	[ 'effectover_duration'	,150,	  								'Duration of out effect' ],
	 	[ 'effectout' 			,{opacity: "hide"},  				  	'Action when hovering out. Other examples can be hide(), fadeOut(\'slow\')' ],
	 	[ 'effectout_duration'	,100,	  								'Duration of hover effect' ],
	 	[ 'offy'				,0, 				  					'Vertical distance from the mouse pointer' ],
	 	[ 'offx'				,5, 				  					'Horizontal distance from the mouse pointer' ],
	 	[ 'follow'				,true,	  								'Follow the mouse cursor' ],
		[ 'extra_image'			,'',									'Add an extra image to the ' ],
	 	[ 'inevent'				,'mouseover', 	  	  					'Bind this action when hovering over, choose mousemove when tooltip should move with mouse' ],
	 	[ 'outevent' 			,'mouseout', 		  					'Bind this action when hovering out' ],
	 	[ 'width'				,'auto', 			  					'Width of the tooltip' ],
	 	[ 'selectable'			,1, 	  	  	  					    'Set to true when it should be possible to select the text in the tooltip' ],
	 	[ 'cursor'				,'', 	  	  	  					    'tooltip parent cursor' ],
	 	[ 'maxwidth'			,'300px',								'the maximum width of the tooltip' ],
	 	[ 'type'				,'',									'is the type an input?' ],
	 	[ 'html'				,'',									'The html to be injected into the tooltip div' ],
	 	[ 'dom_id'				,'',									'what dom id to use for filling the tooltip' ]
	];
	
	return { 'examples': e, 'about': a, 'opts': o, 'classes': c };
}

// Process the options for this widget
// @param   object  o   Widget options extracted from the html
// @return  object      Default options overriden by html options
function opts_tooltip( o )
{
	return apply_options( docs_tooltip().opts, o );
}

function Tooltip( container, options )
{
	options			= opts_tooltip( options );
	this.options	= options;
    this.container  = container;
        
	$(container).tooltip(
    {
    	timein: 			options.timeover,
    	ineffect: 			options.effectover,
    	ineffectduratrion: 	options.effectover_duration, 
    	outeffect: 			options.effectout,
    	outeffectduratrion: options.effectout_duration, 
    	offsetY:			options.offy,
    	offsetX: 			options.offx,
    	follow: 			options.follow,
    	extra_image: 		options.extra_image,
	   	inevent: 			options.inevent,
    	outevent: 			options.outevent,
    	width: 				options.width,
    	cursor:				options.cursor,
    	maxwidth:			options.maxwidth,
    	type:				options.type,
    	html:				options.html,
    	dom_id:				options.dom_id
    });
}

(function(jQuery) 
{
	jQuery.fn.tooltip = function(options)
	{
		var defaults = {
			timein: 			300, 
			ineffect: 			{opacity: 'show'},
			ineffectduration: 	200, 
			outeffect: 			{opacity: 'hide'},
			outeffectduration: 	300, 
			offsetY: 			-15,
			offsetX: 			15,
			follow: 			true,
			extra_image: 		'<span class="tooltip-arrow"></span>',
			inevent: 			'mouseover',
			outevent: 			'mouseout',
			width: 				'auto',
			cursor: 			'',
			maxwidth: 			'330px',
			type: 				'',
			html: 				'',
			dom_id:				''
  		};
  		
  		var options = jQuery.extend(defaults, options);
  			
  		return this.each(function() 
		{
			obj = jQuery(this);
		
			obj.css({cursor: options.cursor});			
			
			if(this.title == '' && !options.dom_id && !options.html)
			{
				obj.unbind(options.inevent, options.outevent);
				return false;
			}

			obj.bind(options.inevent, function(e) 
			{
				this.tip = this.title;
				
				if(options.html)
				{
					var tip_content = options.html;
				}
				else if(options.dom_id)
				{
					var tip_content = $('#' + options.dom_id).html();
				}
				else
				{
					var tip_content = this.tip;
				}
				
				this.title = "";
				
				tip = jQuery('<div></div>')
						.addClass('tooltip')
						.html(options.extra_image + tip_content)
						.css({top: e.pageY + options.offsetY, left: e.pageX + options.offsetX, width: options.width, maxWidth: options.maxwidth });
				
				jQuery(document.body).append(tip);
								
				if(options.follow)
				{
					jQuery(document).bind('mousemove', function(e)
					{ 
						tip.css({top: e.pageY + options.offsetY});
						
						if(e.pageX + tip.width() > jQuery.windowSize().w)
						{
							tip.css({left: e.pageX - options.offsetX - tip.width() - 30});
						}
						else if(e.pageX + tip.width() < jQuery.windowSize().w)
						{
							tip.css({left: e.pageX + options.offsetX });
						}
						else
						{
							tip.css({left: e.pageX + options.offsetX });
						}
					});
				}
				else
				{
					var left = jQuery.getPosition(this).x;
					var top  = jQuery.getPosition(this).y;
					
					tip.css({top: top - tip.height() - 10});
					
					if(left + tip.width() > jQuery.windowSize().w)
					{
						tip.css({left: left - (obj.width() / 2) - (tip.width() / 2 )});
					}
					else
					{
						tip.css({left: left + (obj.width() / 2) - (tip.width() / 2 )});
					}
									
					if(options.type == 'input')
					{
						tip.css({ left: left + obj.width() + 15, top: top});
					}
				}
								
				tip.oneTime(options.timein, function()
				{
					jQuery(this).stop().animate(options.ineffect, options.ineffectduration);
				});
			});
			
			obj.bind(options.outevent, function(e) 
			{
				if (typeof tip == "undefined") return;

				tip.stop().animate(options.outeffect, options.outeffectduration, function()
				{
					jQuery(this).remove();
				});
				
				jQuery.fn.tooltip.destroy();
				this.title = this.tip;
			});
			
			jQuery.fn.tooltip.destroy = function()
			{
				obj.unbind(options.inevent, options.outevent);
				jQuery(document).unbind('mousemove');
			}
		});			
	}
})(jQuery);
//
/*  */

/*  */

// Notes
// ULs and LIs margin values are set to 0
// LIs get display: block
// Style the menu and get it working first with CSS, then add this JS to make it nicer

// External callback to initialize the widget
// @param	mixed	container	jQuery selector for the object to be used
// @param	dom		context		DOM object used as jQuery context. Defaults to document.body
function init_menu( container, context )
{
	context = context || document.body;
	
	$( container, context ).each( 
		function () 
		{
			var opts = "";
			opts = jQuery.attrOptions( this , "menu" );
			new Menu( this, opts );
		}
	);
}

// External callback for the documentation functions
// @return  object Structure containing 'examples' of usage, 'about' message, default 'opts', and 'classes' (never used...)
function docs_menu()
{
	var a = "Dynamic cascading menu item. Notes: Get it working with CSS only first, then use this file to make it nice.";
	var e = [
		['<ul class="do_menu" menu="animationOver: {ldelim}height:\'show\',opacity: .9{rdelim}, speedOver: 400, dropShadows: true">\n<li>A.root\n\t<ul>\n\t<li>A.1</li>\n\t<li>A.2</li>\n\t</ul>\n</li>\n<li>B.root\n\t<ul>\n\t<li>B.1</li>\n\t</ul>\n</li>\n</ul>',
		"Superfish menu"]
	];
	var c = [];
	
	var o = 
	[[ "hoverClass", 	'sfHover', 		 				"the class applied to hovered list items" ]
	,[ "pathClass", 	'overideThisToUse',				"the class you have applied to list items that lead to the current page" ]
	,[ "pathLevels", 	1,								"the number of levels of submenus that remain open or are restored using pathClass" ]
	,[ "delay",  		400,							"the delay in milliseconds that the mouse can remain outside a submenu without it closing" ]
	,[ 'animationOver',	{height:'show'},				"exmp: {opacity:.85}, {height:'show'}, Animation on mouse over. See jQueryÍs .animate() method" ]
	,[ "speedOver",		300, 			 				"speed of the mouse over animation (in milliseconds). Equivalent to second parameter of jQueryÍs .animate() method" ]
	,[ 'animationOut',	{opacity:'hide',height:'hide'},	"{opacity:'hide'}, {height:'hide'}, Animation on mouse out" ]
	,[ "speedOut", 		200, 			 				"speed of the mouse out animation (in milliseconds). Equivalent to second parameter of jQueryÍs .animate() method" ]
	,[ "dropShadows",	false, 			 				"completely disable drop shadows by setting this to false" ]
	];
	
	return { 'examples': e, 'about': a, 'opts': o, 'classes': c };
}


// Process the options for this widget (cached)
// @param   object  o   Widget options extracted from the html
// @return  object      Default options overriden by html options
function opts_menu( o )
{
	return apply_options( docs_menu().opts, o );
}



function Menu( container, opts )
{
	opts			= opts_menu( opts );
	this.container	= container;
	this.opts		= opts;
	
	
	$(container).superfish(
	{
		hoverClass: 	this.opts.hoverClass,
		pathClass: 		this.opts.pathClass,
		pathLevels: 	this.opts.pathLevels,
		delay: 			this.opts.delay,
		animationOver:	this.opts.animationOver,
		speedOver:		this.opts.speedOver,
		animationOut:	this.opts.animationOut,
		speedOut:		this.opts.speedOut,
		dropShadows:	this.opts.dropShadows
	}	
	);	
	
}

;(function($){
	$.fn.superfish = function(op){

		var sf = $.fn.superfish,
			c = sf.c,
			over = function(){
				var $$ = $(this), menu = getMenu($$);
				clearTimeout(menu.sfTimer);
				$$.showSuperfishUl().siblings().hideSuperfishUl();
			},
			out = function(){
				var $$ = $(this), menu = getMenu($$), o = sf.op;
				clearTimeout(menu.sfTimer);
				menu.sfTimer=setTimeout(function(){
					o.retainPath=($.inArray($$[0],o.$path)>-1);
					$$.hideSuperfishUl();
					if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}
				},o.delay);	
			},
			getMenu = function($menu){
				var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];
				sf.op = sf.o[menu.serial];
				return menu;
			};
			
		return this.each(function() {
			var s = this.serial = sf.o.length;
			var o = $.extend({},sf.defaults,op);
			o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){
				$(this).addClass([o.hoverClass,c.bcClass].join(' '))
					.filter('li:has(ul)').removeClass(o.pathClass);
			});
			sf.o[s] = sf.op = o;
			
			$('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).not('.'+c.bcClass).hideSuperfishUl();
			
			var $a = $('a',this);
			$a.each(function(i){
				var $li = $a.eq(i).parents('li');
				$a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});
			});
			o.onInit.call(this);
			
		}).each(function() {
			menuClasses = [c.menuClass];
			if (sf.op.dropShadows  && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);
			$(this).addClass(menuClasses.join(' '));
		});
	};

	var sf = $.fn.superfish;
	sf.o = [];
	sf.op = {};
	sf.IE7fixAdd = function(){
		var o = sf.op;
		if ($.browser.msie && $.browser.version > 6 && o.dropShadows )
			this.addClass(sf.c.shadowClass+'-off');
		};
	sf.IE7fixRemove = function(){
		var o = sf.op;
		if ($.browser.msie && $.browser.version > 6 && o.dropShadows )
			this.removeClass(sf.c.shadowClass+'-off');
		};
	sf.c = {
		bcClass     : 'sf-breadcrumb',
		menuClass   : 'sf-js-enabled',
		shadowClass : 'sf-shadow'
	};
	sf.defaults = {
		disableHI	: true,		// true disables hoverIntent detection
		onInit		: function(){}, // callback functions
		onBeforeShow: function(){},
		onShow		: function(){},
		onHide		: function(){}
	};
	$.fn.extend({
		hideSuperfishUl : function(){
		
			var o = sf.op,
			not = (o.retainPath===true) ? o.$path : '';
			o.retainPath = false;
			
			var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).find('>ul:visible')
			sf.IE7fixAdd.call($ul);		
			
			// important fix for ff2 opacity issues on a mac
			if (navigator.appVersion.indexOf("Mac")!=-1 && ($.browser.mozilla && $.browser.version.substr(0,3) == 1.8)) o.animationOut.opacity = 1;
			
			$ul.animate(o.animationOut,o.speedOut,function(){$(this).parent().removeClass(o.hoverClass); sf.IE7fixRemove.call($ul);});
			
			$ul.children().removeClass(o.hoverClass); // #8051
			
			o.onHide.call($ul);
			return this;
		},
		showSuperfishUl : function(){
			var o = sf.op,
				sh = sf.c.shadowClass+'-off',
				$ul = this.addClass(o.hoverClass)
					.find('>ul:hidden').css('visibility','visible');
					
			sf.IE7fixAdd.call($ul);
			o.onBeforeShow.call($ul);
			
			// important fix for ff2 opacity issues on a mac
			if (navigator.appVersion.indexOf("Mac")!=-1 && ($.browser.mozilla && $.browser.version.substr(0,3) == 1.8)) o.animationOut.opacity = 1;
						
			$ul.animate(o.animationOver,o.speedOver,function(){ sf.IE7fixRemove.call($ul); o.onShow.call($ul); });
			return this;
		}
	});

})(jQuery);

/*  */
// 
//function init_imgzoomer(container, context)
//{
//	context = context || document.body;
//
//	$(container, context).each(function() 
//	{
//		var opts = "";
//		opts = jQuery.attrOptions(this, "imgzoomer");
//		new Imgzoomer(this, opts);
//	});
//}
//
//function docs_imgzoomer()
//{
//	var a = "An image zoomer.";
//	var e = [ ['<img class="do_imgzoomer" src="" />', "Image zoomer"] ];
//	var c = [];
//	
//	var o = 
//	[
//		[ "showZoomer", 	'true',		"Show the zoomer in the bar" ],
//		[ "showMakeBig", 	'true',		"Show the button to make the image big" ]
//	];
//	
//	return { 'examples': e, 'about': a, 'opts': o, 'classes': c };
//}
//
//function opts_imgzoomer(o)
//{
//	return apply_options(docs_imgzoomer().opts, o);
//}
//
//function Imgzoomer(container, opts)
//{
//	opts			= opts_imgzoomer( opts );
//	this.container	= container;
//	this.opts		= opts;
//	
//	$(container).img_zoomer(
//	{
//		showZoomer: this.opts.showZoomer,
//		showMakeBig: this.opts.showMakeBig	
//	});	
//}

;(function($)
{
	$.fn.img_zoomer = function(options) 
	{
		//if($.browser.msie) 
		//{
		//	try { document.execCommand("BackgroundImageCache", false, true); } catch(err) { }
		//}
		
		var defaults = {
			showZoomer: false,
			showMakeBig: true
  		}
  		
  		var options = jQuery.extend({}, defaults, options);

		return this.each(function() 
		{
			var origImg 		= $(this);	
			var imgWidth 		= origImg.width();
			var imgHeight 		= origImg.height();
			var img_id 			= origImg.attr('usemap').replace('#',''); // find the <map> that belongs to this image
			
		
			var usemap, imgVars, imgSrc, originalWidth, originalHeight;
			
			if($('map[name='+ img_id +']').length)
			{
				usemap 			= $('map[name='+ img_id +']');
				imgVars 		= usemap.attr('title').split(",");
				imgSrc 			= imgVars[2];
				originalWidth 	= parseInt(imgVars[0]);
				originalHeight 	= parseInt(imgVars[1]);
			}
			
			var perc = 1;
		
			if(imgWidth != originalWidth)
			{			
				perc = (imgWidth / originalWidth);
			}
	

			var a = false;
		
			// create wrapper div if it not in the template
			if(!origImg.parents('.img-wrapper').length) 
			{
				// wrap the image in a div for annotation positioning		
				wrapper = $('<div class="img-wrapper"></div>')
							.attr({rel: img_id})
							.css({width: imgWidth, height: imgHeight});
							
				if(origImg.parents('a').length)
				{
					a = origImg.parents('a');
					origImg.parents('a').wrap(wrapper);
				}
				else
				{
					origImg.wrap(wrapper);
				}
			}
			else
			{
	 			if(origImg.parents('a').length)
				{
					a = origImg.parents('a');
				}
			}
		
		
			var wrapper = origImg.parents('.img-wrapper');
			
			// if image does not need zoomer, finish here, and skip to the next iteration
			var zoomImg = true;
			if(!perc || perc > .85 || imgWidth < 280)
			{
				wrapper.addClass('img-no-zoom');
				zoomImg = false; 
			}
		
			if($('.img-toolbar', wrapper).length)
			{
				var toolbar = $('.img-toolbar', wrapper);
			}
			else
			{
				// find toolbar div, add it to the wrapper
				var toolbar = wrapper.siblings('.img-toolbar').prependTo(wrapper);
			}
		
			// bind hovers
			wrapper
				.mouseover(function()
				{
					// load hi res image if present
					if(!$('.img-zoomer-hi-res',this).attr('src') && perc < .85)
					{
						imgViewerFunctions.loadBigImage($('.img-zoomer-hi-res', this));
					}
												
					$(this).addClass('img_hovered');			
					toolbar.show();
				})
				.mouseout(function()
				{	
					$(this).removeClass('img_hovered');

					toolbar = $('.img-toolbar', this);
					toolbar.hide();
				});
		
			toolbar.prependTo(wrapper)
		
			// add tags button, set binds and title	
			var tagText = $('.edit-img-tags', toolbar).text().split(',')[0];

			$('.edit-img-tags', toolbar).html( '<span class="text-shadow">' + tagText + '</span>' );

			var img 	= $('<img />').addClass('img-zoomer-hi-res').css({position: 'absolute'}).hide().insertAfter(origImg);	
/*
			if (zoomImg)
			{
				var loader = $('<span></span>', origImg).addClass('loading-toolbar').hide().prependTo(toolbar);
			}
*/

			// if zooming tools don't exist, add them to the toolbar
			if(!$('.img-zoomer-tools',toolbar).length)
			{
				var zoomer = $('<div></div>').addClass('img-zoomer-tools').prependTo(toolbar);
			}
			else 
			{
				var zoomer = $('.img-zoomer-tools', toolbar);
			}
		
			// build zoom slider and add to zoomer
			/*
			if(options.showZoomer)
			{			
				$('<div></div>').slider({
					max: (perc * 100)+100,
					start: function()
					{
						origImg.hide();
						img.show();
								
						if(!wrapper.hasClass('zooming-img'))
						{
							wrapper.addClass('zooming-img');
						}
					},
					slide: function()
					{	
						if($('.ui-slider',toolbar).slider('value') > 1)
						{
							$('.img-zoomer-tool-reset', toolbar).animate({opacity: 1}, 200);
							$('.annotation', wrapper).hide();
						}
					
						var val 		= $(this).slider('value');
						var newPerc 	= (val / 100 ) + 1;			
						var percWidth 	= (imgWidth * newPerc);
						var percHeight 	= (imgHeight * newPerc);
						var left 		= (imgWidth - percWidth) / 2;
						var top 		= (imgHeight - percHeight) / 2;
					
						img.css({width: percWidth,height: percHeight,top: top,left: left});			
					},
					stop: function()
					{									
						if(a)
						{
							a.click(function()
							{ 
								return false 
							});
						}
					
						if($(this).slider('value') < 1)
						{
						 	imgViewerFunctions.resetImage($(this), img, origImg, toolbar, wrapper, a);
						}
					}		
				})
				.appendTo(zoomer);
			
				$('<span>+</span>').addClass('img-zoomer-tool-add').mousedown(function() { $(this).siblings('.ui-slider').slider("moveTo", "+=15"); }).appendTo(zoomer);
				$('<span>-</span>').addClass('img-zoomer-tool-less').mousedown(function() { if($(this).siblings('.ui-slider').slider('value') < 1) { imgViewerFunctions.resetImage($(this).siblings('.ui-slider'), img, origImg, toolbar, wrapper, a); } else { $(this).siblings('.ui-slider').slider("moveTo", "-=15"); } }).prependTo(zoomer);	
				$('<span>r</span>').addClass('img-zoomer-tool-reset').mouseup(function() { imgViewerFunctions.resetImage($(this).siblings('.ui-slider'), img, origImg, toolbar, wrapper, a); }).css({opacity: .4}).prependTo(zoomer);
			}
			*/
			
			if(options.showMakeBig)
			{
				$('<span class="img-zoomer-tool-fullscreen"><span class="text-shadow">Vergroot</span></span>')
					.click(function(e)
					{
						imgViewerFunctions.imageGoFullsize(img, wrapper, origImg, toolbar);
						e.stopPropagation();
					})
					.prependTo(zoomer);
			}
		});
	}
})(jQuery);
	
imgViewerFunctions = 
{
	loadBigImage: function(img)
	{
		var wrapper = img.parents('div');
		var toolbar = $('.img-toolbar', wrapper);
		// var zoomer 	= $('.img-zoomer-tools', wrapper).show();
		// var loader  = $('.loading-toolbar', wrapper).show();
		var imgVars	= $('map[name='+ wrapper.attr('rel') +']').attr('title').split(",");
		var imgSrc 	= imgVars[2];
		
		// load hi-res image	
		img
			.css({position:'absolute',left:-999999})
			.attr({src: imgSrc})
			.load(function()
			{
				// loader.hide();
				
			
				$(this)
					.attr({rel: $(this).width()+','+$(this).height()})
					.css({width: wrapper.width(),height: wrapper.height()})
					.unbind('load')
					.css({position:'static',left:'auto'});
			})
			.draggable(
			{
				start: function(e, ui)
				{
					uiWidth  = - (ui.helper.width() - wrapper.width());
					uiHeight = - (ui.helper.height() - wrapper.height());
				},
				
				drag: function(e, ui)
				{
					if(ui.position.left >= 0) 		ui.position.left = 1;
					if(ui.position.top >= 0) 		ui.position.top = 1;
					if(ui.position.left <= uiWidth) ui.position.left = (uiWidth + 1);
					if(ui.position.top <= uiHeight)	ui.position.top = (uiHeight + 1);
				}
			});
	},
	
	resetImage: function(slider, img, origImg, toolbar, wrapper, a)
	{
		a = a || false;
		
		if(slider.slider('value') > 1)
		{
			slider.slider("moveTo", "1");
		}
		
		img.hide()
	 	origImg.show()
	 	
	 	$('.img_zoomer_tool_reset', toolbar).css({opacity: .4});
		$('.annotation', wrapper).show().animate({opacity: 1},300,function()
		{
			wrapper.removeClass('zooming-img');
		});
		
		if(a)
		{
			a.unbind('click');
		}
	},
	
	imageGoFullsize: function(img, wrapper, origImg, toolbar)
	{
		var zoomDimen 		= img.attr('rel').split(',');
		var zoomImgWidth 	= zoomDimen[0];
		var zoomImgHeight 	= zoomDimen[1];
		var fullWidth 		= zoomImgWidth;
		var fullHeight 		= zoomImgHeight;

		// never wider than window
		if(zoomImgWidth > $(window).width())
		{
			fullWidth  = $(window).width() - 40;
			fullHeight = zoomImgHeight * (fullWidth / zoomImgWidth);	
		}		
		
		// re-position when window resizes
		$(window).resize(function()
		{
			if($(window).width() < zoomImgWidth)
			{
				$('.full-screen-img').animate({ 
					width: 	($(window).width() - 40),
					height: zoomImgHeight * (($(window).width() - 40) / zoomImgWidth),
					left: 	($(window).width() / 2) - (($(window).width() - 40) / 2)
				}, 200);
			} 
			else
			{
				$('.full-screen-img').animate({ 
					width: 	zoomImgWidth,
					height: zoomImgHeight,
					left: 	($(window).width() / 2) - (zoomImgWidth / 2)
				}, 200);
			}			
		});
 		
		leftPos = ($(window).width() / 2) - (fullWidth / 2);
		topPos  = $(window).scrollTop() + 10;
				
		// overlay
		$('<span class="popup-overlay"></span>')
			.css({opacity: .5, height: $(document).height(), backgroundColor: '#000000'})
			.click(function()
			{
				imgViewerFunctions.closeBigImage(toolbar, origImg, wrapper);	
			})
			.appendTo('body');
			
		// clone the large image, and animate to full screen
		img
			.clone()
			.show()
			.addClass('full-screen-img')
			.css({left: wrapper.offset().left, top: wrapper.offset().top})
			.appendTo('body')
			.animate({width: fullWidth, height: fullHeight, left: leftPos, top: topPos}, 300, 'easeOutCirc')
			.click(function()
			{
				imgViewerFunctions.closeBigImage(toolbar, origImg, wrapper);
			});
			
		$(document)
			.unbind('keypress.imageZoomer')
			.bind('keypress.imageZoomer', function(e)
			{
				var key;
				if($.browser.msie) 	{ key = e.which } else { key = e.keyCode }
				if(key == 27) { $('.popup-overlay').click(); }
			});	
	},
	
	closeBigImage: function(toolbar, origImg, wrapper)
	{
		$('.popup-overlay').fadeOut(300,function()
		{
			$(this).remove() 
		});
		
		$('.full-screen-img').animate({width: origImg.width(),height: origImg.height(), left: wrapper.offset().left,top: wrapper.offset().top}, 200, function()
		{ 
			$(this).remove(); 
			toolbar.show();
		})	
	}
}
// 
// 
//function init_imgannotations(container, context)
//{
//	context = context || document.body;
//
//	$(container, context).each(function() 
//	{
//		var opts = "";
//		opts = jQuery.attrOptions(this, "imgannotations");
//		new Imgannotations(this, opts);
//	});
//}
//
//function docs_imgannotations()
//{
//	var a = "An image annotator.";
//	var e = [ ['<img class="do_imgannotations" src="" />', "Image Annotator"] ];
//	var c = [];
//	var o = [];
//	return { 'examples': e, 'about': a, 'opts': o, 'classes': c };
//}
//
//function opts_imgannotations(o)
//{
//	return apply_options(docs_imgannotations().opts, o);
//}
//
//function Imgannotations(container, opts)
//{
//	opts			= opts_imgannotations( opts );
//	this.container	= container;
//	this.opts		= opts;
//	
//	$(container).img_annotations();
//}

;(function($)
{
	$.fn.img_annotations = function() 
	{
		return this.each(function() 
		{
			var obj	  	= $(this);
			var imgId 	= $(this).attr('usemap').replace("#","");
			objParent 	= obj.parent();
				
			// create label for future use
			if(!$('.annotation-label').length)
			{
				$('<span class="annotation-label"></span>').css({opacity: .9}).appendTo('body');
			}
	
			if($('map[name='+imgId+']').length)
			{
				// remove usemap
				var imgWidth 		= $(this).width();
				var imgHeight 		= $(this).height();
				var usemap 			= $('map[name='+imgId+']');			// find the <map> that belongs to this image
				var imgVars			= usemap.attr('title').split(",");
				var originalWidth	= parseInt(imgVars[0]);
				var originalHeight	= parseInt(imgVars[1]);
				var percWidth 		= 1;
				var percHeight 		= 1;
			}
			else
			{
				return;
			}
					
			if(imgWidth	 != originalWidth){ percWidth = (imgWidth / originalWidth) }
			if(imgHeight != originalHeight){ percHeight = (imgHeight / originalHeight) }
			
			// remove <a> from around image if in edit mode
			if(obj.parents('a:first').length) 
			{
				attachmentLink = obj.parents('a:first').clone();
			}
			
			// create wrapper div if it not in the template
			if(!obj.parents('.img-wrapper').length) 
			{
				// wrap the image in a div for annotation positioning		
				img_wrapper = $('<div class="img-wrapper '+imgId+'_wrap"></div>').addClass('img-with-annotations').attr({rel: imgId}).css({width: imgWidth,height: imgHeight});
				
				if(obj.parents('a:first').length)
				{
					obj.parents('a:first').wrap(img_wrapper);
				}
				else
				{
					obj.wrap(img_wrapper);
				}
			}
			else 
			{
				img_wrapper = obj.parents('.img-wrapper').addClass('img-with-annotations '+imgId+'_wrap').attr({rel: imgId});
			}
			
			objParent = obj.parents('.img-wrapper');
			
			// find and add toolbar
			if($('.img-toolbar',objParent).length)
			{
				toolbar = $('.img-toolbar',objParent);
			}
			else
			{
				// find toolbar div, add it to the wrapper
				toolbar = objParent.siblings('.img-toolbar:first').prependTo(objParent);
			}
			
			// Set up image 
			objParent.siblings('.help-text:first').fadeOut();
			objParent.siblings('.temp-actor-list').remove()
			objParent.removeClass('in_edit');
			
			actorList = $('.list-actor .list-view-simple');
			
			highlight_annotation_from_li(actorList, objParent, toolbar);
			
			// Create annotations from <map><area>'s
			if(obj.siblings('.annotation').length < 1)
			{
				$("area", usemap).each(function(i)
				{	
					// post ids = thing_id , edge_id, actor id
					var postIds 	= $(this).attr('rel').split(",");
					var thing_id 	= postIds[0];
					var actor_id 	= postIds[1];
					var edge_id 	= postIds[2];
					var coords 		= $(this).attr('coords').split(",");			
					var width 		= (coords[2] - coords[0]) * percWidth; // find the saved dimensions for the annotation
					var height 		= (coords[3] - coords[1]) * percHeight;
					var left 		= parseInt(coords[0]) * percHeight;
					var top 		= parseInt(coords[1]) * percHeight;
					var full_title  = $(this).attr("title").split(",");
			
					// create annotation
					annotation = $('<a id="annot'+actor_id+'" rel="'+postIds+'" href="'+$(this).attr("href")+'"><span class="drag">'+full_title+'</span></a>');
		
					$('span.drag',annotation).css({width: width, height: height, zIndex: ( 9998 - ( width + height ) ) });
					
					// IE fix
					if($.browser.msie) 
					{
						$('span.drag',annotation).css({backgroundColor: '#ccc',opacity: 0});
						$('body').addClass('isIE');
					}
					
					// make outer wrapper wider for border
					width = (width + 2);
							
					$(annotation)
						.addClass('annotation')
						.css({width: width, top: top, left: left, zIndex: ( 9998 - ( width + height ) ) })
						.prependTo('.'+imgId+'_wrap');
				});
			}
		
			// Bind image and annotation hover states
			annotations = $('.annotation', objParent);
			annotations.css({opacity: 1})
				// pause before fading
				.animate({opacity: 1},1500, function()
				{
					// fade annotations out
					$(this).animate({opacity: 0},500,function()
					{
						// if image has gone into edit, and show annotations
						if(img_wrapper.hasClass('in_edit'))
						{
							$(this).css({opacity: 1});
						}
					});
				})
				.each(function()
				{
					// show label on hover
					$(this).hover(function()
					{
						annotations.css({opacity: 1});
									
						if(!labelText) 
						{
							var labelText = $(this).text();
							$('span.annotation-label').text(labelText);
						}
				
						$(this).mousemove(function(e){
							$('span.annotation-label').css({ left: e.pageX, top: e.pageY, zIndex: 9999999 });
						});
						
						// underline li in actor list that matches annotation title
						var text = $('span:first',this).text().split(',');
				
						$('.list-view-simple-thing:contains('+text[0]+')',actorList).css({textDecoration: 'underline'});		
					},
					function()
					{
						hide_label();
						$('.list-view-simple-thing',actorList).css({textDecoration: 'none'});
					})
				});
			
			obj.removeAttr('alt');
			
			objParent
				.bind('mouseenter', function()
				{
					annotations = $('.annotation', this);
					toolbar 	= $('.img-toolbar', this);
					
					$(this).addClass('img_hovered');
					
					if(!objParent.hasClass('zooming-img'))
					{
						annotations.show();
					}
					
					// load hi res image if present and has not been loaded yet
					if($('.img-zoomer-hi-res',this).length && !$('.img-zoomer-hi-res',this).attr('src'))
					{
						imgViewerFunctions.loadBigImage($('.img-zoomer-hi-res',this));
					}
					
					if(toolbar.length && toolbar.html() != '') 
					{
						// toolbar.stop().css({opacity: 1});
					}
				})
				.bind('mouseleave', function()
				{	
					annotations = $('.annotation',this);
					toolbar 	= $('.img-toolbar',this);
					
					$(this).removeClass('img_hovered');
					
					annotations.hide();
					// toolbar.css({opacity: 0});
				});
	
			// Fix for IE, image-link wasn't clickable because usemap was in the way. Parent attribute href being called to still get it to work!
			if($.browser.msie && obj.parents('a:first').length) 
			{
				$('.edit-img-tags', objParent).click(function(e)
				{
					e.stopPropagation();
				});
			
				objParent.click(function()
				{
					location.href = obj.parents('a:first').attr("href");
				})
			}
					
			// remove areas for edit mode - needed for IE
			$("area", usemap).remove();
		});
	}
})(jQuery);

function hide_label()
{
	$('span.annotation-label').css({top: -99999});
}

// highlight annotation when actor li is hovered
function highlight_annotation_from_li(actorList, objParent, toolbar)
{
	$('.list-view-simple-thing', actorList).unbind('mouseover', 'mouseout');
	
	$('.list-view-simple-thing', actorList).hover(function()
	{
		if(!$(".annotation", objParent).length)
		{
			return false;
		}

		annotations.animate({opacity: 1});
		
		var search_text = $.trim( $(this).removeAttr('title').text() );
		
		$(".annotation:contains("+search_text+")",objParent).addClass('hovered');
		objParent.trigger('mouseover');
		
		toolbar.css({top: -9999});	
	}, 
	function()
	{
		if( !$(".annotation",objParent).length )
		return false;
		
		$(".annotation",objParent).removeClass('hovered');
		objParent.trigger('mouseout');
		
		toolbar.hide().css({top: 0});
	});
}

//
/*  $Id: lightbox.js 43278 2009-08-24 09:34:49Z blaise $ */


// STATIC 

window.lightbox_pointer = null;


// Static hook to kill the currently active lightbox
// @return  undefined
function lightbox_remove()
{
	window.widget_manager.stop( 'lightbox' );
}


// Static hook to add an item to the top bar of the currently active lightbox
// @return  undefined
function lightbox_bar_add( x )
{
	$( "#lightbox-wrap-buttons" ).append( x );
}

// Static hook to add an button to the top bar of the currently active lightbox
// @return  undefined
function lightbox_bar_add_button( value, functionName )
{
	var str =  "<button onclick='lightbox_pointer." + functionName + "();'>" + value + "</button>";
	lightbox_bar_add( str );
}

// External callback to initialize the widget
// @param   mixed   container   jQuery selector for the object to be used
// @param   dom     context     DOM object used as jQuery context. Defaults to document.body
// @return  undefined
function init_lightbox( container, context )
{
	context = context || document;

	$( container, context ).each(
		function ()
		{
			var opts	= jQuery.attrOptions( this , 'lightbox' );
			var ajax	= jQuery.attrOptions( this , 'lightbox_ajax' );
			
			opts.ajax = ajax;
			
			new Lightbox( this, opts );
		}
	);
}


// External callback for the documentation functions
// @return  object      Structure containing 'examples' of usage, 'about' message, default 'opts', and 'classes' (never used...)
function docs_lightbox()
{
	var a = "A slightly too versatile lightbox implementation...";
	var e = [];
	var c = [];
	var s = jQuery.label( 'lightbox.cancel', 'Cancel' );
	var o = 
	[[ 'url', 			null, 	"Url to be loaded. Defaults to the href attribute in the element, and then to null" ]
	,[ 'lbl_cancel',	s, 		"Cancel button name" ]
	,[ 'width',			"60%", 	"Css width of the lightbox" ]
	,[ 'height',		"60%", 	"Css height of the lightbox" ]
	,[ 'freeze',		false, 	"Whether the lightbox size should be fixed instead of adapting to content"]
	,[ 'ajax',			{}, 	"Parameters to be added to lightbox url" ]
	,[ 'className',		"", 	"Class that will be added to the lightbox frame" ]
	];
	
	return { 'examples': e, 'about': a, 'opts': o, 'classes': c };
}


// Process the options for this widget (cached)
// // @param   object  o   Widget options extracted from the html
// // @return  object      Default options overriden by html options
function opts_lightbox( o )
{
	return apply_options( docs_lightbox().opts, o );	
}


function Lightbox( container, options )
{
	options			= opts_lightbox( options, container );
	options.url		= options.url || container.href || null;
	options.width	= ( "" + options.width  ).replace( 'px' , '' );
	options.height	= ( "" + options.height ).replace( 'px' , '' );

	this.options	= options;
	
	container = $( container ).get(0);
	container.obj_lightbox = this;

	var self = this;
	$( container ).click( 
		function (event)
		{
			window.lastEvent = event;
			self.show();
			return false;
		}
	);

	if ( options.showonload )
	{
		// bug#1732
		//
		// http://support.microsoft.com/default.aspx/kb/927917
		// http://clientside.cnet.com/code-snippets/manipulating-the-dom/ie-and-operation-aborted/
		//
		// The "operation is aborted" when we generate DOM content in the parent of a container of a script.
		// It is also aborted when we try to add DOM content to a container that is not yet ready.
		// We fix this IE problem by generating the lightbox inside the container that has the showonload parameter.
		//
		if ($.browser.msie)
		{
			this.show(container);
		}
		else
		{
			this.show();
		}
		container.blur();	
	}
}


// Callback for when the widget gets out of focus
// // @param   string  name    The name of the widget type
// // @param   object  obj     The object replacing this one in the widget focus
// // @return  bool            True if ajax request made, false otherwise
Lightbox.prototype.widgetBlur = function ( name, obj )
{
	if ( obj == null )
	{
		this.remove();
	}
	return false;
};



// Create the dom structure necessary to display lightbox
// @param container optional container where to create the lightbox
// @return  undefined
Lightbox.prototype.domCreate = function ( container )
{
	var self = this;
	
	var lo	= document.createElement( "div" );
	var lf	= document.createElement( "div" );
	var lw	= document.createElement( "div" );
	var lc	= document.createElement( "div" );
	var wb	= document.createElement( "div" );
	
	var cb	= $('<div></div>')
					.attr({id: 'lightbox-cancel', title: this.options.lbl_cancel})
					.click(function() 
					{ 
						self.remove();
					});
	
	lo.id	= "lightbox-overlay";
	lf.id	= "lightbox-frame";
	lw.id	= "lightbox-window";
	lc.id	= "lightbox-bar";
	wb.id	= "lightbox-wrap-buttons";
	
	lf.className = this.options.className;
	
	lf.style.position	= "absolute";
	lw.style.width		= "100%";
	lw.style.height		= "100%";
	
	if (container)
	{
		$( container ).append( lo );
		$( container ).append( lf );
	}
	else
	{
		$( "body" ).append( lo );
		$( "body" ).append( lf );
	}
		
	$( lf ).append( lc );
	$( lf ).append( lw );
	$( wb ).append( cb );
	$( lc ).append( wb );
	$( lc ).addClass('clearfix');
	
};


// Clear the timer used to resize the lightbox
// @return  undefined
Lightbox.prototype.clearResizeInterval = function()
{
	if ( window.lightbox_pointer && window.lightbox_pointer.interval )
	{
		clearInterval( window.lightbox_pointer.interval );
		window.lightbox_pointer.interval = null;
	}
};


// Remove this lightbox
// @return  undefined
Lightbox.prototype.remove = function ()
{
	this.clearResizeInterval();
	
	// $( document ).unkeyup();

	// Timeout is needed when this function is called from within the lightbox itself
	var self = this;
	setTimeout(
		function () 
		{
			$('#lightbox-window,#lightbox-frame,#lightbox-overlay').remove();
			self.showObjects();
		},
		500
	);
};


// Get the height of the page inside the lightbox 
// @return  undefined
Lightbox.prototype.size_of_content = function ()
{
	var fr = document.getElementById("lightbox-iframeContent").contentWindow;
	var h1 = 0;
	var h2 = 0;
	
	if ( fr && fr.document )
	{
		if ( fr.document.documentElement && fr.document.documentElement.scrollHeight )
		{
			h1 = fr.document.documentElement.scrollHeight;
		}

		if ( fr.document.body && fr.document.body.scrollHeight )
		{
			h2 = fr.document.body.scrollHeight;
		}
	}

	var h = Math.max( h1, h2 );
	var s = jQuery.getSize( document.getElementById( 'lightbox-frame'  ) );

	h = s.h < h ? h + 60 : 0;
	
	return h;
};


// Resize the lightbox in accordance to its contents
Lightbox.prototype.size = function ()
{
	if ( document.getElementById( "lightbox-iframeContent" ) )
	{
		var h = this.size_of_content();
		h > 0 && $( "#lightbox-frame" ).css( 'height', h + 'px' );
	}
};


// Convert a size in "%" into a value in "px"
// @param   string      x   Percentage value
// @param   integer     y   Absolute value
// @return  integer         Resulting pixel value
Lightbox.prototype.pixelizeSize = function ( x, y )
{
	x = parseInt( x.match( /\d+/ ) );
	x = Math.max( x , 0 );
	x = Math.min( x , 100 );
	x = Math.round( y * x / 100 );
	return x;
};


// Determine the width (horizontal position)
// @return  undefined
Lightbox.prototype.h_position = function ()
{
	var l = 0;
	var w = (typeof this.options != 'undefined') ? this.options.width : '60%';
	var d = jQuery.windowSize();

	if ( w.match( /\%/ ) )
	{
		w = this.pixelizeSize( w, d.w );
	}

	l = ( d.w - w ) / 2;

	$( "#lightbox-frame"  ).css( 'left',  l + 'px' );	
	$( "#lightbox-bar" ).css( 'width', w  - 2 + 'px' );
	$( "#lightbox-window" ).css( 'width', w + 'px' );
	
	this.overlaySize();	
};


// Determine the position  (vertical position)
// @return  undefined
Lightbox.prototype.v_position = function ()
{
	var pagesize   = jQuery.windowSize();	
	var pageScroll = jQuery.pageScrollTop();
	
	var t = 0;
	var h = (typeof this.options != 'undefined') ? this.options.height : '60%';
	var d = jQuery.windowSize();

	if ( h.match( /\%/ ) )
	{
		h = this.pixelizeSize( h, d.h );
	}

	t = ( d.h - h ) / 2;
	
	t = jQuery.pageScrollTop() + t;

	$( "#lightbox-frame" ).css({
		top:    t + 'px',
		height: h + 'px'
	});
};


// Determine size of dark mask 
// @return  undefined
Lightbox.prototype.overlaySize = function ()
{
	if ( window.innerHeight && window.scrollMaxY )
	{	
		yScroll = window.innerHeight + window.scrollMaxY;
	}
	else if ( document.body.scrollHeight > document.body.offsetHeight )
	{
		 // all but Explorer Mac
		yScroll = document.body.scrollHeight;
	}
	else
	{ 
		// Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
		yScroll = document.body.offsetHeight;
  	}

	$( "#lightbox-overlay" ).css( {height: yScroll + "px", cursor: 'pointer' })
							.bind('click', function()
							{
								Lightbox.prototype.remove();
							});
};


// Update de size of the lightbox at a regular time interval
// @return  undefined
Lightbox.prototype.setRegularUpdate = function ()
{
	var self 	= this;
	var fr 		= document.getElementById("lightbox-iframeContent");
	fr.interval = setInterval( 
		function () 
		{ 
			self.size() 
		}, 
		800 
	);
};

Lightbox.prototype.hideObjects = function ()
{
	var self = this;
	$( 'embed,select' ).each(
		function ()
		{
			this.preLightboxVisibility = $( this ).css( 'visibility' );
			this.style.visibility = 'hidden';
		}
	);
};

Lightbox.prototype.showObjects = function ()
{
	var self = this;
	$( 'embed,select' ).each(
		function ()
		{
			this.style.visibility = this.preLightboxVisibility;
		}
	);
};


// Show the lightbox
// @param container, optional container where to generate the lightbox
// @return  undefined
Lightbox.prototype.show = function ( container )
{
	try 
	{
		window.widget_manager.widgetFocus( 'lightbox', this );
		
		$( "#lightbox-overlay" ).get( 0 ) || this.domCreate(container);
		
		var scroll = jQuery.pageScrollTop();

/*		window.scrollTo( 0, scroll );*/

		this.overlaySize();

		this.options.before_ajax && this.options.before_ajax( this.options );
		
		// Let the request know it is inside a lightbox
		this.options.ajax.in_lightbox = '1';
		
		var url		= jQuery.addToQuery( this.options.url , jQuery.param( this.options.ajax ) );
		var rand	= Math.floor( Math.random() * 100000 );
		
		if ( document.getElementById( "lightbox-iframeContent" ) == null )
		{
			$("#lightbox-window").append(
				"<iframe src='" + url + "' name='frame" + rand + "' id='lightbox-iframeContent' frameborder='0' border='0' style='width: 100%; height: 100%;'></iframe>" );
		}
		else
		{
			$( "#lightbox-iframeContent").get(0).src = url;
		}
		
		this.v_position();
		this.h_position();
		
 		$( "#lightbox-window,#lightbox-frame" ).css( 'display' , 'block' );

		this.options.freeze || this.setRegularUpdate();
		
		window.lightbox_pointer = window.frames['frame'+rand];
		
		var self = this;
		$( window ).resize(function () 
		{
			self.h_position();
			self.v_position();
		});	
		
		setTimeout(
			function ()
			{
				self.hideObjects();
			},
			20
		)
	}
	catch( e ) 
	{
		jQuery.warn( "Lightbox" , "An error occurred when opening the lightbox." , e );
	}
};

var LightboxHelper = 
{
	isLightbox: function(uri) 
	{
		if (!window.parent || window.parent.document.location.href == document.location.href)
		{
			return false;
		}
		if (!uri) uri = document.location.href;
		if (uri.match(/\bin_lightbox=1\b/))
		{
			return true;
		}
		
		return false;
	},

	openLightbox: function(url, container, options)
	{
		options['url'] = url;
		var lb = new Lightbox (container, options);
		lb.show();
	}
};

/**/
//
// any.dialog and any.dialogTrigger

;(function($)
{
	if (!$.any) $.any = {};

	$.extend($.any,
	{		 
		dialog: 
		{
			/**
			 * The defaults for the dialog.
			 */
			defaults: 
			{
				/* options for the layout */
				width: '500px',					// The width of the dialog'
				height: 'auto',					// The height of the dialog
				ineffect: {opacity: 'show'},	// Animation when opening
				ineffectTime: 250,				// ... + duration
				outeffect: {opacity: 'hide'},	// Animation when closing
				outeffectTime: 10,				// ... + duration
				title: '',
				overlay: true,
				url: '',
				html: '',
				dom_id: '',				   
				arrow: false,
				closeonmouseout: false,
                closeonmouseclick: true,
				callback: null,				  	// callback on close
				openCallback: null, 			// callback op open
				underObj: false,
				offsetX: 11,
				offsetY: 11,
                dialogTop: false,
				dialogLeft: false,
			    className: '',					// Extra classnames
                helptexts: []
			},
			
			
			/**
			 * This variable contains the options of the currently opened dialog.
			 */
		        currentOptions: {},
		            
			
			/**
			 * Open a dialog. By design, only one dialog can be opened
			 * at the same time, so this function makes sure the
			 * previous dialog closes.
			 */
			open: function(options, parent)
			{				 
				if($.any.dialog.opened())
				{
					// Remove the dialog.	
					$.any.dialog.close(function() 
					{
						$.any.dialog._showDialog(options, parent);
					});
				}
				else
				{
					$.any.dialog._showDialog(options, parent);
				}
			},
			
			
			/**
			 * Close the dialog, if there is one. Will call a callback
			 * function afterwards. Returns TRUE if the dialog was
			 * closed, or FALSE if none was open (so you can call the
			 * callback yourself if you want).
			 */
			close: function(callback)
			{
				var theBox = $('.dialog');
				
				if(!theBox.length)
				{
					return false;
				}

				var opts = $.any.dialog.currentOptions;

				$.any.dialog.currentOptions = {};

				theBox.animate(opts.outeffect, opts.outeffectTime, function()
				{
					// Remove autocompleter ( #5762 )
					// This should be removed when the new autocompleter ( #5472 ) is implemented
					if ($("#autocompleteHelper").length != 0)
					{
						$("#autocompleteHelper").remove();
					}
					
					// eventually hide the confirm
					$(".dialog-confirm").remove();

					// Remove the overlay
					$('.dialog-overlay').remove();								   

					$('.dialog').unbind('mouseleave');

					theBox.remove();
					
					if($.browser.msie && $.browser.version < 7) 
					{
						$('select').each(function()
						{
							$(this).css({visibility: 'visible'});
						});
					}
					
					if(typeof callback == 'function') 
					{
						callback();
					}
					else if(typeof callback == 'string' && window[callback]) 
					{
						window[callback]();
					}
					
					if(typeof opts.callback == 'function') 
					{ 
						opts.callback();
					}
					else if(typeof opts.callback == 'string' && window[opts.callback])
					{
						window[opts.callback]();
					}
				});
				
				return true;				
			},

			/**
			 * Closes the dialog, but ONLY if there are no forms in
			   the dialog which are deemed 'complex'.
			 */
			closeIfNotComplex: function(callback)
			{
				var isComplex = $.any.dialog._isComplex();

				if (!isComplex)
				{
					$.any.dialog._trackDialog({action: "dialog close by clicking outside"});
					return $.any.dialog.close(callback);
				}
				return false;
			},

			
			/**
			 * Return whether a dialog is opened.
			 */
			opened: function()
			{
				return $('.dialog').length > 0;				   
			},

			
			/**
			 * Return the container for the content area of the dialog.
			 */
			contentArea: function()
			{
				return $('.dialog-content');
			},
			
			
			/**
			 * Get the title of the current dialog
			 */
			getTitle: function()
			{
				return $('.dialog-drag-handle-text').html();
			},


			/**
			 * Set the title of the current dialog
			 */
			setTitle: function(title)
			{
				$('.dialog-drag-handle-text').html(title);
			},


			/**
			 * Add helptext to the current dialog
			 */
		    setHelpText: function(text)
			{
				if(!$.any.dialog.opened()) return;
			        
				if(!$('.action-help').length) 
				{
					$('<div></div>').addClass('action-help').appendTo($('.dialog-content'));
				}
                if (!text)
                {
                    $('.action-help').remove();
                }
                else
                {
			        $('.action-help').html(text);
                }
			},
                        
            pushHelpText: function()
            {
                if(!$.any.dialog.opened()) return;
                
                var opts = $.any.dialog.currentOptions;
                opts.helptexts.push($('.action-help').html());
                
            },
                    
			/**
			 * Add helptext to the current dialog
			 */
			popHelpText: function()
			{
                            if(!$.any.dialog.opened()) return;
                            
                            var opts = $.any.dialog.currentOptions;
                            var text = opts.helptexts.pop();
                            
                            $('.action-help').html(text);
			},
			
			/**
			 * Remove helptext from the current dialog
			 */
			removeHelpText: function()
			{
				$('.action-help').remove();
			},


            /**
             * Always return to the top of the dialog if the top
             * of the dialog is not visible (page scrolled down).
             */
            gotoDialogTop: function(modifierFunction) 
            {
                if (!$.any.dialog.opened())
                {
                	modifierFunction();
                    return;
                }
                var dc = $.any.dialog.contentArea();

                modifierFunction();

                $.any.dialog._moveOffstageContent();
				
	            // Scroll up to the input box
    	        if($('html,body').scrollTop() > dc.offset().top)
        	    {
					$('html,body').animate({scrollTop: dc.offset().top-72}, 100);
				}
			},

            
            /**
             * Move offstage content if it's not a direct child of .dialog-content
             */
            _moveOffstageContent: function()
            {
                var dc = $.any.dialog.contentArea();

                var offstage = dc.find('.action-offstage');
                if (!offstage.length) return;

                // Remove already moved contentareas
                dc.find('.action-offstage-moved').remove();

                if (offstage.parents('.action-stage-wrapper').length)
                {
                	if (dc.find('.action-help').length)
                	{
                		offstage.insertBefore('.action-help:last');
                	} else
                	{
                		offstage.insertAfter( dc.find('.action-stage-wrapper:first') );
                	}
                	offstage.addClass('action-offstage-moved');
                }
            },


			/**
			 * Private function for showing the dialog.
			 */
			_showDialog: function(options, parent)
			{
				options = $.extend({}, $.any.dialog.defaults, options);
				
				$.any.dialog.currentOptions = options;
			
				var theBox, closeButton, dialogContent, overlayDiv, dragHandle, dialogTop, dialogLeft, boxHeight, buttonText, parent = $(parent || document.body);
				
				$.any.dialog._trackDialog({action: "dialog open"});

				// The close button
				closeButton = $('<span></span>').addClass('dialog-close').html('x').click(function()
				{
					var isComplex = $.any.dialog._isComplex();
					
					if (isComplex)
				    {
				    	$("body").append($("<div></div>")
								    	.addClass("dialog-confirm")
								    	.html('<span class="dialog-confirm-text">Weet je het zeker?</span>')
			    						.append($("<button></button>")
													.addClass("cancel")
													.text("Ja")
													.click( function() {
														$.any.dialog._trackDialog({action: "dialog close by cross"});
														$(".dialog-confirm").remove();
														$.any.dialog.close();
													}))
										.append($("<button></button>")
													.addClass("cancel")
													.text("Nee")
													.click( function() {
														$(".dialog-confirm").remove();
														return false;
													}))
										.css({position: "absolute", top: $(this).offset().top, left: $(this).offset().left})
										.animate({opacity: 1}, 300)
									);
					}
					else
					{
						$.any.dialog._trackDialog({action: "dialog close by cross"});
						$.any.dialog.close();
					}
				});

				if(options.overlay)
				{
					overlayDiv = $('<div></div>').addClass('dialog-overlay').css({zIndex: 35000, height: $(document).height() });
				}
						
				if(typeof options.height == 'string')
				{
					boxHeight = 'auto';
				}
				else
				{
					boxHeight = options.height.replace('px', '') - 52;
				}
				
				if (options.dialogTop || options.dialogLeft)
				{
                    dialogTop   = options.dialogTop;
					dialogLeft  = options.dialogLeft;
				}
				else if(parent[0] != document.body)
				{
					buttonText	= parent.text();
					dialogTop	= parseInt(parent.offset().top + options.offsetY);
					dialogLeft	= parseInt(parent.offset().left + options.offsetX);
					
					if(options.underObj)
					{
						dialogTop += parseInt(parent.height());
						if(options.arrow)
						{
							dialogTop += 7;
						}
					}
				}
				else
				{
					dialogTop	= $(window).scrollTop() + Math.floor($(window).height() / 3);
					dialogLeft	= ($(window).width() / 2) - (parseInt(options.width) / 2);
				}

				if(options.title)
				{
					buttonText	= options.title;
				}

				theBox			= $('<div></div>').addClass('dialog').addClass(options.className).css({position: "absolute", top: dialogTop, left: dialogLeft, width: options.width, height: boxHeight});
				dialogContent	= $('<div></div>')
										.addClass('dialog-content')
										.appendTo(theBox);
				
				dragHandle	= $('<div></div>')
								.addClass('dialog-drag-handle')
								.html('<span class="dialog-drag-handle-text">'+buttonText+'</span>')
								.mousedown(function() { 
									$(this).addClass('pressed');
									// Hide all wizard confirms
									$(".dialog-confirm").remove();
								})
								.mouseup(function() { $(this).removeClass('pressed'); })
								.prependTo(theBox);
				
				if(options.arrow) $('<div></div>').addClass('dialog-drag-handle-arrow').prependTo(theBox);

				// Remove opacity on IE browsers because it creates ugly edges
				var removeOpacity = function()
				{
					if ($.browser.msie) 
					{
						theBox.css({ filter: '' });
					}
				};
				
				theBox.draggable({ handle: dragHandle, start: removeOpacity, stop: removeOpacity, containment: 'document'});
				
				// No shadow on and hide all selects on ie6 
				if($.browser.msie) 
				{
					theBox.css({background: 'none', padding: 0});
					
					if($.browser.version < 7)
					{
						$('select').each(function()
						{
							$(this).css({visibility: 'hidden'});
						});
					}
				}
					
				if(options.overlay) $(document.body).append(overlayDiv);				
				
				// Destroy on escape
				$(document).keyup(function(e)
				{
					if(e.keyCode == $.ui.keyCode.ESCAPE)
					{
						$.any.dialog._trackDialog({action: "dialog close by escape"});
						$.any.dialog.closeIfNotComplex();
					}
					return false;
				});
				
				// Destroy on outside click
				if(options.closeonmouseclick)
				{
					if(!options.overlay)
					{
						$(document).mousedown(function(e)
						{
							if(!$(e.target).hasClass('dialog') && !$(e.target).parents.hasClass('dialog') || !$(e.target).parents().attr('id') == 'ui-datepicker-div' || !$(e.target).parents().hasClass('dialog-confirm'))
							{
								$.any.dialog.closeIfNotComplex();
							}
							else
							{
								return;
							}
						});
					}				
					else
					{
						overlayDiv.click(function()
						{
					        $.any.dialog.closeIfNotComplex();
						});
					}
				}
				
				// main content function
				var setContent = function(html)
				{
					$(document.body).append(theBox);
					
					dialogContent.html(html).prepend('<div class="notification"></div>');
					
					theBox.animate(options.ineffect, options.ineffectTime, function()
					{
						var left = $(this).offset().left;
						var top	 = $(this).offset().top;
						
						if(top + $(this).height() + 20 - $(window).scrollTop() > $(window).height())
						{
							top = Math.max(20 + $(window).scrollTop(), top - $(this).height());
						}
						
						if(left + $(this).width() > $(window).width())
						{
							left = Math.max($(window).scrollLeft(), $(window).width() - $(this).width() - 40);
						}
						
						$(this).animate({left: left, top: top}, 150);
						
						if (typeof options.openCallback == "function") options.openCallback();
						dragHandle.append(closeButton);
					});

					if(options.closeonmouseout)
					{
						// Destroy on mouse leave - This piece off code needs to be placed here for it to work. Weird
						$('.dialog').bind('mouseleave', function()
						{
							setTimeout(function()
							{ 
								$.any.dialog.close();
							}, 1200);
						});
					}
                    
                    $.any.dialog._minimumHeight = dialogContent.height();
				};
				
				// Call the content
				if(options.scomp)
				{
					// Used from within actiondialog_triger
		            $.any.rest.get('anymeta.html.scomp',
                    {
                        'name': options.scomp,
                        'thg_id': options.thg_id
                    },
                    function (json)
                    {
						setContent(json.html);
                    });
				} 
				else if(options.url)
				{
					// Still used in modules/GoogleMaps/templates/gmaps_viewonmap_link.tpl
					$.ajax({
						type: 'GET',
						url: options.url,
						success: function(data)
						{
							setContent(data);
						}
					});
				} 
				else if(options.dom_id)
				{
					setContent($(options.dom_id).clone(true));
				} 
				else if(options.html)
				{
					setContent(options.html);
				} 
				else 
				{
					setContent('<p>Specify content using dom_id or url</p>');
				}
			},
			
			/**
			 * Returns if a dialog is complex
			 * A complex dialog has a ui form with the isComplex option
			 */
			_isComplex: function()
			{
				var el = $.any.dialog.contentArea();
				var isComplex = false;

				$(".ui_form", el).each(function() {
					var form = $(this).data("ui");
					if (form && form.options.isComplex)
					{
						isComplex = true;
					}
				});
				
				return isComplex;
			},

			/**
			 * Trac this click with google analytics
			 */
			_trackDialog: function(trackOptions)
			{
				var opts = $.any.dialog.currentOptions;

				if (opts.dialogTrack)
				{
					var optsAction = opts.dialogTrack.action || "";
					var optsLabel = opts.dialogTrack.label || "";
					var optsValue = opts.dialogTrack.value || "";
				
					$.any.ui.trackEvent.track({
						category: trackOptions.category ? $.trim(trackOptions.category + " " + opts.dialogTrack.category) : opts.dialogTrack.category,
						action: trackOptions.action ? $.trim(trackOptions.action + " " + optsAction) : optsAction,
						label: trackOptions.label ? $.trim(trackOptions.label + " " + optsLabel) : optsLabel,
						value: trackOptions.value ? $.trim(trackOptions.value + " " + optsValue) : optsValue
					});
				}
			},

			/**
			 * Set the width of a dialog. Can be reset to the old value.
			 */
			setWidth: function(obj, width)
			{
				if (width == 'reset')
				{
					// Use the 'old' width
					width = $(obj).data("width");
					var dialogLeft = ($(window).width() / 2) - (parseInt(width) / 2);
					if (width && dialogLeft)
					{
						$(obj).css({"width": width+"px", "left": dialogLeft});
					}

					// Reset data
					$(obj).data("width","");
				}
				else if (!$(obj).data("width"))
				{
					// Remember the actual width
					$(obj).data("width",$(obj).width());

					// Set the new width
					var dialogLeft = ($(window).width() / 2) - (parseInt(width) / 2);
					$(obj).css({"width": width+"px", "left": dialogLeft});
				}
			}
		}
	});
	
	/**
	 * DialogTrigger ui element
	 */
	$.any.ui("dialogtrigger",
	{
		_init: function()
		{
			var self = this;

			if(self.options.direct)
			{
				$.any.dialog._trackDialog({action: "dialog open direct"});
				$.any.dialog.open(self.options, self.element);
			}
					
			if(self.options.hover)
			{
				self.element.hoverIntent(
				{
					//sensitivity threshold (must be 1 or higher)
					sensitivity: 7,
					
					//milliseconds for onMouseOver polling interval
					interval:	 self.options.hoverTime,
					
					//milliseconds delay before onMouseOut				
					timeout:	 500,							 
					
					//onMouseOver callback
					over: function()
					{
						$.any.dialog.open(self.options, self.element); 
					},					
					
					//onMouseOut callback
					out: function() {}	  
				});
			}
					
			if(self.options.click)
			{
				self.element.click(function(e) { self.open();});
			}			
		},
		
		open: function (callback) 
		{
			var opts = $.extend({}, this.options);
			if (callback) opts.openCallback = callback;
			$.any.dialog.open(opts, this.element);
		}
	},
			 
	/**
	 * Defaults for dialogTrigger
	 */				
	{
		/* options for the triggering of the dialog */				  
		click: true,
		hover: false,
		hoverTime: 250,
		direct: false
	});

})(jQuery);
//
