// --------------------------------------------------------------------------------------------------------------------------------
// tooltip
// --------------------------------------------------------------------------------------------------------------------------------
(function(jQuery){

jQuery.fn.extend({

	scrollLeft: function(val) {
		if (!this[0]) error();
		if ( val != undefined )
			// set the scroll left
			return this.each(function() {
				if (this == window || this == document)
					window.scrollTo( val, $(window).scrollTop() );
				else
					this.scrollLeft = val;
			});
		
		// return the scroll left offest in pixels
		if ( this[0] == window || this[0] == document )
			return self.pageXOffset ||
				$.boxModel && document.documentElement.scrollLeft ||
				document.body.scrollLeft;
				
		return this[0].scrollLeft;
	},
	
	scrollTop: function(val) {
		if (!this[0]) error();
		if ( val != undefined )
			// set the scroll top
			return this.each(function() {
				if (this == window || this == document)
					window.scrollTo( $(window).scrollLeft(), val );
				else
					this.scrollTop = val;
			});
		
		// return the scroll top offset in pixels
		if ( this[0] == window || this[0] == document )
			return self.pageYOffset ||
				$.boxModel && document.documentElement.scrollTop ||
				document.body.scrollTop;

		return this[0].scrollTop;
	},
	
	getPosition: function(options, returnObject) {
		if (!this[0]) error();
		var x = 0, y = 0, sl = 0, st = 0,
		    elem = this[0], parent = this[0], op, parPos, elemPos = $.css(elem, 'position'),
		    mo = $.browser.mozilla, ie = $.browser.msie, oa = $.browser.opera,
		    sf = $.browser.safari, sf3 = $.browser.safari && parseInt($.browser.version) > 520,
		    absparent = false, relparent = false, 
		    options = $.extend({ margin: true, border: false, padding: false, scroll: true, lite: false, relativeTo: document.body }, options || {});
		
		if (elem.tagName == 'BODY') {
			// Safari 2 is the only one to get offsetLeft and offsetTop properties of the body "correct"
			// Except they all mess up when the body is positioned absolute or relative
			x = elem.offsetLeft;
			y = elem.offsetTop;
			// Mozilla ignores margin and subtracts border from body element
			if (mo) {
				x += num(elem, 'marginLeft') + (num(elem, 'borderLeftWidth')*2);
				y += num(elem, 'marginTop')  + (num(elem, 'borderTopWidth') *2);
			} else
			// Opera ignores margin
			if (oa) {
				x += num(elem, 'marginLeft');
				y += num(elem, 'marginTop');
			} else
			// IE does not add the border in Standards Mode
			if ((ie && jQuery.boxModel)) {
				x += num(elem, 'borderLeftWidth');
				y += num(elem, 'borderTopWidth');
			} else
			// Safari 3 doesn't not include border or margin
			if (sf3) {
				x += num(elem, 'marginLeft') + num(elem, 'borderLeftWidth');
				y += num(elem, 'marginTop')  + num(elem, 'borderTopWidth');
			}
		} else {
			do {
				parPos = $.css(parent, 'position');
			
				x += parent.offsetLeft;
				y += parent.offsetTop;

				// Mozilla and IE do not add the border
				// Mozilla adds the border for table cells
				if ((mo && !parent.tagName.match(/^t[d|h]$/i)) || ie || sf3) {
					// add borders to offset
					x += num(parent, 'borderLeftWidth');
					y += num(parent, 'borderTopWidth');

					// Mozilla does not include the border on body if an element isn't positioned absolute and is without an absolute parent
					if (mo && parPos == 'absolute') absparent = true;
					// IE does not include the border on the body if an element is position static and without an absolute or relative parent
					if (ie && parPos == 'relative') relparent = true;
				}

				op = parent.offsetParent || document.body;
				if (options.scroll || mo) {
					do {
						if (options.scroll) {
							// get scroll offsets
							sl += parent.scrollLeft;
							st += parent.scrollTop;
						}
						
						// Opera sometimes incorrectly reports scroll offset for elements with display set to table-row or inline
						if (oa && ($.css(parent, 'display') || '').match(/table-row|inline/)) {
							sl = sl - ((parent.scrollLeft == parent.offsetLeft) ? parent.scrollLeft : 0);
							st = st - ((parent.scrollTop == parent.offsetTop) ? parent.scrollTop : 0);
						}
				
						// Mozilla does not add the border for a parent that has overflow set to anything but visible
						if (mo && parent != elem && $.css(parent, 'overflow') != 'visible') {
							x += num(parent, 'borderLeftWidth');
							y += num(parent, 'borderTopWidth');
						}
				
						parent = parent.parentNode;
					} while (parent != op);
				}
				parent = op;
				
				// exit the loop if we are at the relativeTo option but not if it is the body or html tag
				if (parent == options.relativeTo && !(parent.tagName == 'BODY' || parent.tagName == 'HTML'))  {
					// Mozilla does not add the border for a parent that has overflow set to anything but visible
					if (mo && parent != elem && $.css(parent, 'overflow') != 'visible') {
						x += num(parent, 'borderLeftWidth');
						y += num(parent, 'borderTopWidth');
					}
					// Safari 2 and opera includes border on positioned parents
					if ( ((sf && !sf3) || oa) && parPos != 'static' ) {
						x -= num(op, 'borderLeftWidth');
						y -= num(op, 'borderTopWidth');
					}
					break;
				}
				if (parent.tagName == 'BODY' || parent.tagName == 'HTML') {
					// Safari 2 and IE Standards Mode doesn't add the body margin for elments positioned with static or relative
					if (((sf && !sf3) || (ie && $.boxModel)) && elemPos != 'absolute' && elemPos != 'fixed') {
						x += num(parent, 'marginLeft');
						y += num(parent, 'marginTop');
					}
					// Safari 3 does not include the border on body
					// Mozilla does not include the border on body if an element isn't positioned absolute and is without an absolute parent
					// IE does not include the border on the body if an element is positioned static and without an absolute or relative parent
					if ( sf3 || (mo && !absparent && elemPos != 'fixed') || 
					     (ie && elemPos == 'static' && !relparent) ) {
						x += num(parent, 'borderLeftWidth');
						y += num(parent, 'borderTopWidth');
					}
					break; // Exit the loop
				}
			} while (parent);
		}

		var returnValue = handleOffsetReturn(elem, options, x, y, sl, st);

		if (returnObject) { $.extend(returnObject, returnValue); return this; }
		else              { return returnValue; }
	},

	tooltip: function(tip, settings) {
		settings = jQuery.extend({
			leftOffset: -100,		// map || sat || (default)hybrid
			topOffset: -10
		},settings);
		$("#"+tip).hide();
		$("#"+tip).css('display','none');	// Safari 3 hide
		$("#"+tip).css('position','absolute');		// IE hide before hide
		$("#"+tip).css('top','1000px');
		$("#"+tip).css('left','1000px');
		var hasFocus = false;
		$("#"+tip).css("position", "absolute");
		return this.each(function(){
			var stayOnFocus = false;
			if ($("#"+this.id+":input").length > 0) { stayOnFocus = true; }
			$("#"+this.id).focus(
				function(){
					$("#"+tip).show();
					hasFocus = true;
				}
			);
			$("#"+this.id).blur(
				function(){
					$("#"+tip).hide();
					hasFocus = false;
				}
			);
			$("#"+this.id).hover(
				function(){
					var position = $("#"+this.id).getPosition();
					var left = position.left + settings.leftOffset;
					var top = position.top + settings.topOffset;
					$("#"+tip).css("top", top);
					$("#"+tip).css("left", left);
					$("#"+tip).show();
				},
				function(){
					if (!hasFocus) { $("#"+tip).hide(); }
				}
			);
		})
	}
});
})(jQuery); 

var num = function(el, prop) {
	return parseInt($.css(el.jquery?el[0]:el,prop))||0;
};

var handleOffsetReturn = function(elem, options, x, y, sl, st) {
	if ( !options.margin ) {
		x -= num(elem, 'marginLeft');
		y -= num(elem, 'marginTop');
	}

	// Safari and Opera do not add the border for the element
	if ( options.border && (($.browser.safari && parseInt($.browser.version) < 520) || $.browser.opera) ) {
		x += num(elem, 'borderLeftWidth');
		y += num(elem, 'borderTopWidth');
	} else if ( !options.border && !(($.browser.safari && parseInt($.browser.version) < 520) || $.browser.opera) ) {
		x -= num(elem, 'borderLeftWidth');
		y -= num(elem, 'borderTopWidth');
	}

	if ( options.padding ) {
		x += num(elem, 'paddingLeft');
		y += num(elem, 'paddingTop');
	}
	
	// do not include scroll offset on the element ... opera sometimes reports scroll offset as actual offset
	if ( options.scroll && (!$.browser.opera || elem.offsetLeft != elem.scrollLeft && elem.offsetTop != elem.scrollLeft) ) {
		sl -= elem.scrollLeft;
		st -= elem.scrollTop;
	}

	return options.scroll ? { top: y - st, left: x - sl, scrollTop:  st, scrollLeft: sl }
	                      : { top: y, left: x };
};


// --------------------------------------------------------------------------------------------------------------------------------
// Mapin 
// - construct a mapin object with the given settings.
// --------------------------------------------------------------------------------------------------------------------------------
(function(jQuery) {
jQuery.fn.extend({

mapin: function(settings) {
	var version = "1.3.1";
	settings = jQuery.extend({
		maptype: "hybrid",		// map || sat || (default)hybrid
		center: [39.825413103,-104.94140625],
		zoom: 12,
		controlsize: "small",	// (default)small || large || none
		showtype: true,
		showoverview: false,
		clickmarker: true,
		staticMap: false
	},settings);
	
	// Initialize the marker array
	this.setMarkers = [];
	this.mapContainer = this[0].id;
	
	this.icon = new GIcon();
	this.icon.image = "http://www.irishpubreviews.com/images/mapIcon.png";
	this.icon.shadow = "http://www.irishpubreviews.com/images/mapIconShadow.png";
	this.icon.iconAnchor = new GPoint(16,32); 
	this.icon.infoWindowAnchor = new GPoint(16,32);//22,6);
			
	return this.each(function(){
		this.map = new GMap2(this);
		var mapin = this.map;
		var loadmap = G_HYBRID_MAP;
		switch(settings.maptype) {
			case "map":
				loadmap = G_NORMAL_MAP;
				break;
			case "sat":
				loadmap = G_SATELLITE_MAP;
				break;
		}
		this.map.checkResize();
		mapin.setCenter(new GLatLng(settings.center[0],settings.center[1]),settings.zoom,loadmap);
		mapin.enableScrollWheelZoom();
		mapin.enableContinuousZoom();
		switch(settings.controlsize)
		{
			case "small":
				mapin.addControl(new GSmallMapControl());
				break;
			case "large":
				mapin.addControl(new GLargeMapControl());
				break;
			case "none":
				break;
			default:
				mapin.addControl(new GSmallMapControl());
		}
		if (settings.showtype === true){
			mapin.addControl(new GMapTypeControl());// Type of map Control
		}
		if (settings.showoverview === true){
			mapin.addControl(new GOverviewMapControl());//Overview Map
		}
		if (settings.staticMap) {
			mapin.disableDragging();
			mapin.disableScrollWheelZoom();
		}
	});
},	// End mapin

// --------------------------------------------------------------------------------------------------------------------------------
// getClick
// - waits for a click on the current map and returns the lat/long to the callback function
// @callback - On completion, calls this function with the lat and long of the point clicked.
// @placeMaker - If true, a placemarker will be set at the clicked point.
// @draggable - Makes the marker draggable, the callback will be called on dragEnd, 
//				but lat and long must be accessed differently, this.x (long) and this.y (lat)
// @onlyOnce - If true, the listener will be disabled after one click.
// @location - address, city, state, country, zop code. This is where the map will be centered.
// --------------------------------------------------------------------------------------------------------------------------------
getClick: function(callback, placeMarker, draggable, onlyOnce, location) {
	var mapin = this[0].map;
	var icon = this.icon;
	this.clickMarker;
	if (location) {
		var position = function(point) {
			mapin.setCenter(point);
		}
		this.geocodeAddress(position, location);
	}
	var l = GEvent.addListener(mapin, "click", function(marker, point){
		if (marker) {
			mapin.removeOverlay(marker);
		} else {
			if (placeMarker) {
				if (mapin.tempMarker) { mapin.removeOverlay(mapin.tempMarker); }
				this.clickMarker = new GMarker(point, {icon: icon, draggable: true });
				if (draggable) { this.clickMarker.enableDragging(); }
				var dragEndF = function() { return callback(this.clickMarker.getLatLng().lat(), this.clickMarker.getLatLng().lng()); };
				GEvent.bind(this.clickMarker, "dragend", this, dragEndF );
				mapin.tempMarker = this.clickMarker;
				mapin.addOverlay(this.clickMarker);
			}
			if (onlyOnce) { GEvent.removeListener(l); }
			return callback(point.lat(), point.lng());
		}
	});
},

setMarker: function(lat, lng, zoom) {
	var marker = new GMarker(new GLatLng(lat, lng), this.icon);
	this[0].map.addOverlay(marker);
	if (zoom === undefined) { zoom = 3; }
	this[0].map.checkResize();
	this[0].map.setCenter(new GLatLng(lat, lng), zoom);
},

// --------------------------------------------------------------------------------------------------------------------------------
// geocodeAddress
// - waits for a click on the current map and returns the point to the callback function
// @callback - On completion, calls this function with the lat and long of the address.
// @address - The address at which to get the cordinates.
// @placeMaker - If true, a placemarker will be set at the coodinates.
// @centerMap - If true, the map will be center at the given location
// --------------------------------------------------------------------------------------------------------------------------------
geocodeAddress: function(callback, address, placeMarker, centerMap) {
	var mapin = this[0].map;
	var geocoder = new GClientGeocoder();
	geocoder.getLatLng(
		address,
		function(point) {
			if (!point) {
				return callback(address + " not found");
			} else {
				if (centerMap) {
					mapin.setCenter(point, 13);
				}
				if (placeMarker) {
					this[0].map.checkResize();
					this[0].map.setCenter(point, 13);
					var marker = new GMarker(point, this.icon);
					mapin.addOverlay(marker);
					return callback(point, marker);
				} else {
					return callback(point);
				}
			}
		}
	);
},

// --------------------------------------------------------------------------------------------------------------------------------
// addGeoRSS
// - Adds an overlay from the given RSS url.
// @geoRssUrl - URL of the rss feed to add.
// --------------------------------------------------------------------------------------------------------------------------------
addGeoRSS: function(geoRssUrl) {
	this.geoXml = new GGeoXml(geoRssUrl);
	this[0].map.addOverlay(this.geoXml);
},

// --------------------------------------------------------------------------------------------------------------------------------
// clearGeoRSS
// - Removes the overlay added by the addGeoRSS function
// --------------------------------------------------------------------------------------------------------------------------------
clearGeoRSS: function() {
	this[0].map.removeOverlay(this.geoXml);
},

// --------------------------------------------------------------------------------------------------------------------------------
// addMakerSet
// - Adds an array of data to the map, with the given name so it can be removed later. 
// - You can add many sets, but all will be removed as one.
// @infoArray - JSON array inclucing, lat, long, and html.
// --------------------------------------------------------------------------------------------------------------------------------
addMarkerSet: function(markerArray) {
	var markerSetClick = function(markerObject) {
		this[0].map.closeInfoWindow();
		this[0].map.openInfoWindow(markerObject.latLng, markerObject.content);
	};
	var infoArray = markerArray.markers;
	for (var i=0; i < infoArray.length; i++) {
		var markerObject = {};
		markerObject.latLng = new GLatLng(parseFloat(infoArray[i].lat), parseFloat(infoArray[i].lng));
		markerObject.gmarker = new GMarker(markerObject.latLng, this.icon);
		markerObject.content = infoArray[i].html;
		var clickHandler = this.method_closure(this, markerSetClick, [markerObject]);
		GEvent.bind(markerObject.gmarker, "click", this, clickHandler);
		this.setMarkers.push(markerObject);
		this[0].map.addOverlay(markerObject.gmarker);
	}
},

// --------------------------------------------------------------------------------------------------------------------------------
// removeMakerSet
// - Removes the marker set with given name.
// @setName - The name of the set to remove.
// --------------------------------------------------------------------------------------------------------------------------------
removeMarkerSet: function(setName) {
	for (var i=0; i < this.setMarkers.length; i++) {
		this[0].map.removeOverlay(this.setMarkers[i].gmarker);
	}
},

// --------------------------------------------------------------------------------------------------------------------------------
// searchLocal
// - searches the map for the given string at the given point and places custom markers
// @searchString - The string to search for i.e. starbucks.
// @centerPoint - The point around which to search, i.e. denver, co OR 80238, OR Sydney, Australia.
// @infoOptions - Options for the display of the infoWindow which will be opened when markers are clicked.
// --------------------------------------------------------------------------------------------------------------------------------
searchLocal: function(searchString, centerPoint, infoOptions, callback) {
	// Set the default infoOptions
	infoOptions = jQuery.extend({
		resultsContainer: "",	// Container to put the text results
		cssClass: "",			// css class to apply to the infoWindow
		tabLabel: "",			// Tab to add to the infoWindow (only if showDDTab=true, otherwise no tabs)
		linkText: "",			// Link text, will be place after tabContent (can be html element)
		linkFunction: "",		// Function name (string) to be called, will be passed marker info
		googLinkText: "More",	// Text to show for the google link (can be html element, i.e. <div...)
		showGoogLink: false,	// Show a link to the google page with reviews, photos and stuff
		showTitle: true,		// Show the title in the infoWindow
		showPhone: true,		// Show the phone number in the infoWindow
		showAddress: false,		// Show the address in the infoWindow
		showDDLink: false,		// Show the "driving direction to" link
		showDDTab: false		// Show the driving direction links in a second tab
	}, infoOptions);
		
	// Callback function for when all the markers are added.
	if (callback) { this.searchLocalCallback = callback; }
	
	// Array to store the searchLocal overlay data
	this.searchLocalMarkers = [];
	this.searchLocalResultsContainer = infoOptions.resultsContainer;
	
	// When the marker is clicked, it will call this function
	this.markerClick = function(markerObject) {
		this[0].map.closeInfoWindow();
		var result = markerObject.result;
		var tabArray = [];
		
		var html = "<div class=\"" + infoOptions.cssClass + "\">";
		// Show the title
		if (infoOptions.showTitle) {
			html += "<b>" + result.titleNoFormatting.replace(/'/g, "&#39;") + "</b>";
		}
		// Show the phone number
		var phoneNumber = "";
		if (infoOptions.showPhone) {
			if (result.phoneNumbers.length > 0) { 
				phoneNumber = result.phoneNumbers[0].number;
				html += "<br />" + phoneNumber;
			}
		}
		// Show the address
		if (infoOptions.showAddress) {
			html += "<br />" + result.streetAddress;
			html += "<br />" + result.city ;
			if (result.region !== "" ) { html += ", " + result.region; }
			html += ", " + result.country;
		}
		// Show the 'driving directions to' link
		if (infoOptions.showDDLink) {
			html += "<br /><a href='" + result.ddUrlToHere + "'>Driving Directions to here</a>";
		}
		// Show the link to google
		if (infoOptions.showGoogLink) {
			html += "<hr width=\"250px\" />";
			html += "<a href='" + result.url + "'>" + infoOptions.googLinkText + "</a>";
		}
		// Show the link at the bootom
		if (infoOptions.linkText !== "") {
			var functionString = infoOptions.linkFunction + "(";
			functionString += "\"" + result.titleNoFormatting.replace(/'/g, "&#39;") + "\", ";
			functionString += "\"" + result.lat + "\", ";
			functionString += "\"" + result.lng + "\", ";
			functionString += "\"" + result.streetAddress + ", " + result.city + ", " + result.region + ", " + result.country + "\", ";
			functionString += "\"" + phoneNumber + "\"";
			functionString += ")";
			if (infoOptions.showGoogLink) {
				html += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='#' onclick='eval(" + functionString + ")'>" + infoOptions.linkText + "</a>"; 
			} else {
				html += "<a href='#' onclick='eval(" + functionString + ")'>" + infoOptions.linkText + "</a>"; 
			}
		}
		// Create the main tab
		var infoTab = new GInfoWindowTab(infoOptions.tabLabel,  html);
		tabArray.push(infoTab);
		// Create the driving direction tab
		if (infoOptions.showDDTab) {
			var ddHtml = "<br /><a href='" + result.ddUrlToHere + "'>get Driving Directions to here</a>";
			var ddTab = new GInfoWindowTab("Directions",  ddHtml);
			tabArray.push(ddTab);
		}
		html += "</div>";
		// Open the info window, only use tabs if they want the DD tab
		if (infoOptions.showDDTab) {
			this[0].map.openInfoWindowTabs(markerObject.latLng, tabArray);
		} else {
			this[0].map.openInfoWindow(markerObject.latLng, html);
		}
	};
	
	// Setup and execute the search
	var searchControl = new GSearchControl();
	searchControl.setResultSetSize(GSearch.LARGE_RESULTSET)
	var localSearch = new GlocalSearch();
	this.localSearch = localSearch;
	var options = new GsearcherOptions();
	options.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
	searchControl.addSearcher(localSearch, options);
	this[0].map.checkResize();
	localSearch.setCenterPoint(centerPoint);
	searchControl.draw(null);
	searchControl.setSearchCompleteCallback(this, this.searchLocalComplete);
	searchControl.execute(searchString);
},

// --------------------------------------------------------------------------------------------------------------------------------
// searchLocalComplete
// - takes the results of the local search and places markers on the map
// --------------------------------------------------------------------------------------------------------------------------------
searchLocalComplete: function(sc, searcher) {
    // if we have local search results, put them on the map
	if ( searcher.results && searcher.results.length > 0) {
		this[0].map.checkResize();
		this[0].map.setCenter(new GLatLng(searcher.results[0].lat, searcher.results[0].lng), 10);
		for (var i = 0; i < searcher.results.length; i++) {
			var result = searcher.results[i];
			// if this is a local search result, then proceed...
			if (result.GsearchResultClass === GlocalSearch.RESULT_CLASS ) {
				// Add the marker to the map
				var markerObject = {};
				markerObject.result = result;
				markerObject.latLng = new GLatLng(parseFloat(result.lat), parseFloat(result.lng));
				markerObject.gmarker = new GMarker(markerObject.latLng, this.icon);
				var clickHandler = this.method_closure(this, this.markerClick, [markerObject]);
				GEvent.bind(markerObject.gmarker, "click", this, clickHandler);
				this.searchLocalMarkers.push(markerObject);
				this[0].map.addOverlay(markerObject.gmarker);
				// Add the text to the resultContainer
				//$("#"+this.searchLocalResultsContainer).append(result.html)
			}
		}
		if (this.searchLocalCallback) {
			return this.searchLocalCallback(searcher.results[0].lat, searcher.results[0].lng);
		}			
	}
},

// --------------------------------------------------------------------------------------------------------------------------------
// clearSearchLocal
// - clears the markers placed by the searchLocal function
// --------------------------------------------------------------------------------------------------------------------------------
clearSearchLocal: function() {
	for (var i=0; i < this.searchLocalMarkers.length; i++) {
		this[0].map.removeOverlay(this.searchLocalMarkers[i].gmarker);
	}
},

// --------------------------------------------------------------------------------------------------------------------------------
// getMap
// - returns the GMap2 object of mapin
// --------------------------------------------------------------------------------------------------------------------------------
getMap: function() {
	return this[0].map;
},

// --------------------------------------------------------------------------------------------------------------------------------
// method_closure
// - helper function to define the scope of called function
// --------------------------------------------------------------------------------------------------------------------------------
method_closure: function (object, method, opt_argArray) {
	return function() {
		return method.apply(object, opt_argArray);
	};
}

// Ending
});
})(jQuery); 


// --------------------------------------------------------------------------------------------------------------------------------
// jsRater 
// --------------------------------------------------------------------------------------------------------------------------------
(function(jQuery) {
jQuery.fn.extend({

jsRater: function(callback, image) {
	if (image === "") { image = "../images/star.gif"; }
	
	var onClicked = function(num) {
		var percent = 0.0;
		for (var i=0; i < num; i++) {
			percent += 20;
		}
		jQuery(".current-rating").css("width", percent+"%");
		return callback(num);
	};
	
	jQuery(".one-star").click(function() { onClicked(1); });
	jQuery(".two-stars").click(function() { onClicked(2); });
	jQuery(".three-stars").click(function() { onClicked(3); });
	jQuery(".four-stars").click(function() { onClicked(4); });
	jQuery(".five-stars").click(function() { onClicked(5); });
}


// Ending
});
})(jQuery); 


///////////////////////////////////////////////////////////////////////////////////////////////////////////////// JBOX
/*
 * jBox 1.0 - a webpage UI dialog widget written in javascript on top of the jQuery library
 * By Daniel Lin(http://www.aspstat.com)
 * Copyright (c) 2007 Daniel Lin
 * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
*/
var jBox={
    imgs:['min.gif', 'images/close.gif', 'restore.gif','resize.gif'],
	boxes: [],minimizeorder: 0,
	init:function(id){
		var holder =$('#jBoxHolder');
	    if (holder.length == 0){ 
		   holder = $('<div id="jBoxHolder"></div>');
		   $(document.body).append( holder );   
		}
		var box = $('<div class="jBox" id="jb'+id+'"></div' ).appendTo(holder);
			box.append('<div class="jBoxHandler">jBox<div style="right:2px; top:2px" class="jBoxControls"><img src="'+this.imgs[0]+'" title="Minimize" /><img src="'+this.imgs[1]+'" title="Close"/></div></div>')
            .append('<div class="jBoxContent"></div>')
		    .append('<div class="jBoxStatus"><div class="jBoxResize" style="background: url('+this.imgs[3]+')  no-repeat;">�</div></div');
		box.css( 'zIndex' , $('div.jBox').length+99);
		box.handler = box.find('div.jBoxHandler');
		box.controls = box.find( 'div.jBoxControls');
		box.content = box.find('div.jBoxContent');
		box.status = box.find( 'div.jBoxStatus' );
		box.Resize = box.find( 'div.jBoxResize' );
		box.handler._parent=box;
		box.controls._parent=box;
		box.content._parent=box;
        box.onclose=function(){return true};
		box.isResize=function(bol){jBox.isResize(this, bol);};
	    box.isScrolling=function(bol){jBox.isScrolling(this, bol);};		
	    box.setSize=function(w, h){jBox.setSize(this, w, h);};
	    box.moveTo=function(x, y){jBox.moveTo(this, x, y);};
	    box.show=function(){ jBox.show(this);};
	    box.hide=function(){ jBox.close(this);};
	    box.load=function(type, source, title,ajaxOpt){jBox.load(this, type, source, title,ajaxOpt);};
	    box.dispose = function(){ jBox.dispose(this);}
		box.attr( 'jBoxID' , this.boxes.length );
		box.jBoxID = this.boxes.length;
	    this.boxes[this.boxes.length]=box;		
	    return box;
	},
	load:function(box,type,source,title,ajaxOpt){
	    var type=type.toLowerCase();
  	    if (typeof title!='undefined') box.handler.get(0).firstChild.nodeValue=title;
        if (title==''){
			 box.handler.css( 'backgroundColor' ,'#fff' );
             box.handler.css('padding' ,'0px');
             box.content.css('padding','0px 10px');
		}
	    if (type=="inline"){
		     box.content.html(source);
	    }
	    else if (type=="div"){
		     box.content.html($('#'+source).html());
	    }else if (type=="iframe"){
		     box.content.css('overflow','hidden');
		     if ( box.content.children().length<1 || box.content.children().get(0).tagName!="IFRAME") {
					 box.content.html('<iframe src="" style="margin:0; padding:0; width:100%; height: 100%" frameborder="0" scrolling="no" name="_iframe-'+box.jBoxID+'"></iframe>');
			 }
		     window.frames["_iframe-"+box.jBoxID].location.replace(source);		     
		}
	    box.content.datatype=type;
	},
	open:function( id, type, source, title,attr,ajaxOpt){	
		function getValue(Name){
			var config=new RegExp(Name+"=([^,]+)", "i");
			return (config.test(attr))? eval( '('+RegExp.$1+')') : 0;
		}
		var box;
		//Find a jbox element has been created else create new element
		if ($('#jb'+id).length==0)
			box=this.init(id);
		else{
			box=jBox.boxes[ parseInt( $('#jb'+id).get(0).getAttribute('jBoxID') ) ];
		}
		box.setSize(getValue(("width")), (getValue("height")));
		var xpos=getValue("center")? "middle" : getValue("left");
		var ypos=getValue("center")? "middle" : getValue("top");
		box.css("visibility" ,"visible");
	    box.css("display" , "block");
	    box.content.css("display","block");
		box.isResize(getValue("resize")); 
		box.isScrolling(getValue("scrolling")); 			    	    
	    box.isModel = getValue("model");
	    if ( box.isModel ) jBox.showModel();
		box.minimizable=getValue("minimizable");
		if( !box.minimizable  ){if (box.controls.find('img[@title=Minimize]').length>0)box.controls.find('img[@title=Minimize]').remove()};	
		if ( getValue("draggable") ){box.handler.mousedown(function(e){jBox.etarget=this;jBox.setupDrag(e);});}
		if ( getValue("scrolling") ){box.Resize.mousedown(function(e){jBox.etarget=this;jBox.setupDrag(e);});}
        box.controls.click( function(e){jBox.setupControls(e);} );	
		box.load(type, source, title,ajaxOpt);     
		box.moveTo(xpos, ypos);
		return box;
    },
	isResize:function(box, bol){box.status.css("display",(bol)? "block" : "none");box.resizeBool=(bol)? 1 : 0},
    isScrolling:function(box, bol){box.content.css("overflow",(bol)? "auto" : "hidden");},
	setSize:function(box, w, h){box.css("width",Math.max(parseInt(w),150)+'px');box.content.css("height",Math.max(parseInt(h),150)+'px');},
	reSize:function(box, e){
	      box.css('width', Math.max(jBox.width+jBox.distancex, 150)+"px");
	      box.content.css('height',Math.max(jBox.contentheight+jBox.distancey, 100)+"px");
    },
	moveTo:function(box, x, y){
	    this.getViewPoint();
        box.css("left",(x=="middle")? this.scrollPos[0]+(this.docSize[0]-box.get(0).offsetWidth)/2+"px" : this.scrollPos[0]+parseInt(x)+"px");
        box.css("top",(y=="middle")? this.scrollPos[1]+(this.docSize[1]-box.get(0).offsetHeight)/2+"px" : this.scrollPos[1]+parseInt(y)+"px");
	},
    show:function(box){
		box.css('display','block');
		box.state='restore';
		if ( box.isModel ) jBox.showModel();
	},
    close:function(box){
	   try{var closewinbol=box.onclose();}
	   catch(err){var closewinbol=true;}
	   finally{
		 if (typeof closewinbol=="undefined"){
			alert("An error has occured somwhere inside your \"onclose\" event handler")
			var closewinbol=true
		 }
	   }
	   if (closewinbol){
		 if (box.state!="minimized") 
			jBox.saveViewState(box);
		 box.css('display','none');
	     if ( box.isModel ) jBox.hideModel();
	   }
	   return closewinbol;
    },
    dispose:function(box){
       if ( box.isModel) jBox.hideModel();       
       for (var i=0; i<jBox.boxes.length; i++){
         if ( jBox.boxes[i] == box ){
            box.handler._parent=null;
		    box.controls._parent=null;
		    box.content._parent=null;          
		    jBox.boxes[i] = null;  
            break;
         }
       }   
       box.remove();
    },
	minimize:function(btn,box){
       jBox.saveViewState(box);
	   btn.setAttribute('src',jBox.imgs[2]);
	   btn.setAttribute('title','Restore');
	   box.state = 'minimized';
	   box.content.css('display','none');
	   box.status.css('display','none');
	   if( typeof box.minimizeorder == 'undefined' ){
		   jBox.minimizeorder++;
		   box.minimizeorder = jBox.minimizeorder;
	   }
	   box.css('left','10px');
	   box.css('width','200px');
       var margin = box.minimizeorder*10;
	   box.css('top',jBox.scrollPos[1]+jBox.docSize[1]-(box.handler.get(0).offsetHeight*box.minimizeorder)-margin+'px');
	},
	restore:function(btn,box){
		jBox.getViewPoint();
		btn.setAttribute('src',jBox.imgs[0]);
		btn.setAttribute('title','Minimize');
		
		box.state='restore';
		box.css('display','block');
		box.content.css('display','block');
		if( box.resizeBool )
			box.status.css('display','block');
		box.css( 'left',parseInt(box.lastPos[0])+jBox.scrollPos[0]+'px');
		box.css( 'top',parseInt(box.lastPos[1])+jBox.scrollPos[1]+'px');
		box.css( 'width',parseInt(box.lastSize[0])+'px');
	},
    setupControls:function(e){
		var j=jBox;		
	    var sourceobj=window.event? window.event.srcElement : e.target;
		var box = j._retBox(sourceobj);
		
	    if (/Minimize/i.test(sourceobj.getAttribute("title")))
		   j.minimize(sourceobj, box);
	    else if (/Restore/i.test(sourceobj.getAttribute("title")))
		   j.restore(sourceobj, box);
	    else if (/Close/i.test(sourceobj.getAttribute("title")))
		   j.close(box);
	    return false;
	},
	showModel:function(){
      var model =$('#jBox_hideIframe');      
 
	  if ( model.length==0 )
	  {
		//<div id="hooha"  display:block; z-index:1000;">Hallo</div>
		//model = $('<div id="cloudBack" style="position:absolute; top:0px; left:0px;bottom:0px;right:0px;-moz-opacity:0.7; opacity:0.7;filter:alpha(opacity=70);background:#000;"></div><iframe src="https://about:blank" id="jBox_hideIframe" scrolling="no" frameborder="0"></iframe>');
		model = $('<div id="cloudBack" style="position:absolute; top:0px; left:0px;bottom:0px;right:0px;-moz-opacity:0.7; opacity:0.7;filter:alpha(opacity=70);background:#000;"></div>');
		model.appendTo( document.body );
		$(window).bind( 'resize', function(){jBox.showModel();})
	  }
	  jBox.getViewPoint();
	  model.css('width' , jBox.pageSize[0]+'px');
	  model.css('height', jBox.pageSize[1]+'px');	  	  
	},
    hideModel:function(){
	    $(window).unbind( 'resize')
		$("#cloudBack").remove();
	    var model =$('#jBox_hideIframe');
	    if ( model.length>0 )	
    	   model.remove();
    },
    setupDrag:function(e){
		var j=jBox;
	    var boxE=j.etarget;
		var box = j._retBox(boxE);
	    var e=window.event || e;
	    j.initmousex=e.clientX;
	    j.initmousey=e.clientY;
	    j.initx=parseInt(box.get(0).offsetLeft);
	    j.inity=parseInt(box.get(0).offsetTop);
	    j.width=parseInt(box.get(0).offsetWidth);
	    j.contentheight=parseInt(box.content.get(0).offsetHeight);
	    if (box.content.datatype=="iframe"){
		   box.css('backgroundColor','#F8F8F8');
		   box.content.css('visibility','hidden');
	    }
	    document.onmousemove=j.getDistance;
	    document.onmouseup=function(){
		  if (box.content.datatype=="iframe"){
			 box.content.css('visibility','visible');
		  }
		  j.stopDrag();
	    }
	    return false;
	},
	getDistance:function(e){
		var j=jBox;
	    var etarget=j.etarget;
	    var e=window.event || e;
	    j.distancex=e.clientX-j.initmousex;
	    j.distancey=e.clientY-j.initmousey;
		var box = j._retBox(etarget);
	    if (etarget.className=='jBoxHandler')
		{
			box.css('left',j.distancex+j.initx+'px')
   	        box.css('top',j.distancey+j.inity+'px')
		}
	    else if (etarget.className=='jBoxResize')
		   j.reSize(box, e);
	    return false;
	},
	stopDrag:function(){
		jBox.etarget=null;
	    document.onmousemove=null;
	    document.onmouseup=null;
	},
	getViewPoint:function(){ 
		var ie=document.all && !window.opera
		var domclientWidth=document.documentElement && parseInt(document.documentElement.clientWidth) || 100000;
		this.standardbody=(document.compatMode=="CSS1Compat")? document.documentElement : document.body;
		this.scrollPos= [(ie)? this.standardbody.scrollLeft : window.pageXOffset,
			(ie)? this.standardbody.scrollTop : window.pageYOffset];	
		this.docSize=[(ie)? this.standardbody.clientWidth : (/Safari/i.test(navigator.userAgent))? window.innerWidth : Math.min(domclientWidth, window.innerWidth-16),
			(ie)? this.standardbody.clientHeight: window.innerHeight];
		if ( ie ){
		   this.scrollSize  = [(document.body.scrollWidth > document.body.offsetWidth)?document.body.scrollWidth:document.body.offsetWidth,
			   (document.body.scrollHeight > document.body.offsetHeight)?document.body.scrollHeight:document.body.offsetHeight];
		}
		else{
		   this.scrollSize = [document.body.scrollWidth,window.innerHeight + window.scrollMaxY];
		}
		this.pageSize = [(this.scrollSize[0] < this.docSize[0])?this.docSize[0]:this.scrollSize[0],
			(this.scrollSize[1]< this.docSize[1])?this.docSize[1]:this.scrollSize[1]];
    },
	saveViewState:function(box){
		this.getViewPoint();
		box.lastPos=[ parseInt((box.css('left')||box.get(0).offsetLeft))-jBox.scrollPos[0],
			parseInt((box.css('top')||box.get(0).offsetTop))-jBox.scrollPos[1] ];
		box.lastSize = [parseInt (box.css('width')),
			parseInt( box.css('height'))];

		
	},
    _retBox:function(dom){		
		return jBox.boxes[ parseInt(  $(dom).parents('div.jBox').get(0).getAttribute('jBoxID') ) ];
	}
}

jQuery.fn.openjBox = function(boxAttr,title){
	var $this = jQuery(this);
	$this.attr( 'jBoxID' , jBox.open( 'jBox'+$this.attr('id') ,'div',$this.attr('id'),title,boxAttr).jBoxID );
}
jQuery.fn.disposejBox = function(boxAttr,title){
	var $this = jQuery(this);
	if ( $this.get(0).getAttribute( 'jBoxID' )!=null ){
	   jBox.boxes[parseInt($this.get(0).getAttribute( 'jBoxID' ))].dispose();
	   $this.removeAttr('jBoxID' );
	}
	else{
	   alert( 'pls use openjBox first to Instance a jBox instance!');
	}
}
jQuery.fn.showjBox = function(boxAttr,title){
	var $this = jQuery(this); 
	if (  $this.get(0).getAttribute( 'jBoxID' )!=null  ){
	   jBox.boxes[parseInt($this.get(0).getAttribute( 'jBoxID' ))].show();
	}
	else{
	   alert( 'pls use openjBox first to Instance a jBox instance!');
	}
}
jQuery.fn.hidejBox = function(boxAttr,title){
	var $this = jQuery(this);
	if ( $this.get(0).getAttribute( 'jBoxID' )!=null  ){
	   jBox.boxes[parseInt($this.get(0).getAttribute( 'jBoxID' ))].hide();
	}
	else{
	   alert( 'pls use openjBox first to Instance a jBox instance!');
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////// JBOX
