﻿/*************************************************************************************************************
DIALOGBOX.JS
Copyright 2010-2011 by Matthias Altmann, Systemberater (http://www.altmann.de)

Shows a centered dialog box while dimming the page content.

------------------------------------------------------------------------------------------------------------
PARAMETERS		Description / Default	
------------------------------------------------------------------------------------------------------------
	color:		The color of the dialogbox. The default is '#0000ff' (blue).
	title:		The title of the dialogbox. The default is 'Info'.
	text:		The text of the dialog box. The default is ''.
	onclose:	If using standard OK button this defines a function fpor this button.
	buttons:	The buttons and related functions as array of objects:
					capt:	The caption
					func:	The function
	rounded:	Use rounded corners for the dialogbox. The default is false.		
	

------------------------------------------------------------------------------------------------------------
SAMPLES
------------------------------------------------------------------------------------------------------------

Dialo box with simple OK button:
	DialogBox( { color:'red', title:'Hello!', text:'This is the text.' } );

Dialog box with simple OK button and some action on close:
	DialogBox( { color:'red', title:'Hello!', text:'Click OK to go back...', onclose:function(){history.back();} } );

Dialog box with multiple buttons and according actions:
	DialogBox( { 
					color: 	'red', 
					title: 	'Hello!', 
					text:	'Do you want to do this?', 
					buttons:[ 
								{capt:'Yes', 	func:function(){DoSomething();}}, 
								{capt:'No', 	func:null} 
							],
					rounded: true 
				});

------------------------------------------------------------------------------------------------------------
HISTORY
------------------------------------------------------------------------------------------------------------
Version	Date		Description
------------------------------------------------------------------------------------------------------------
1.0		2010-09-06	Initial Release
1.1		2010-07-25	Added handling for Enter as default key to close.
1.2		2010-09-06	Changed syntax for parameter button to allow variables as 
					caption, e.g. for multi-language environments
1.3		2010-09-06 	Complete re-design from procedural to objective
1.4		2010-09-07	Fixed bug in CreateHTML: 
					Changed for (var idx in thisObj.buttons) 
					to 		for (var idx=0;idx<thisObj.buttons.length;idx++)
1.5		2010-09-15	Introduced calculation of panel size based on document width/height
					and ialogbox position based on scroll offset	
1.6		2010-12-06	keyHandler returns TRUE on unhandled key to support form elements in dialog box		
1.7		2010-12-22	CreateHTML(): Workaround for IE and wrong counting of array members (buttons.length is 3 with only 2 elements)	
1.8		2011-04-29	KeyDownHandler(): ESC (code 27) is now also accepted as default key. Events are marked as handled.
*************************************************************************************************************/
// DEFAULTS
var dialogbox_default_color			= '#0000ff';					
var dialogbox_default_title			= 'Info';							
var dialogbox_default_text			= '';							
var dialogbox_default_buttons		= [ {capt:'OK',func:null} ];
var dialogbox_default_rounded		= true;
var dialogbox_default_shadow		= true;
var dialogbox_instances				= new Array();



//-------------------------------------------------------------------------------------------------------------
// Easy call wrapper
function DialogBox(params)
{
	new DialogBox_Class(params);
}


//=============================================================================================================
function DialogBox_Class (params) {
	
	var thisObj 		= this;							// closure wrapper to avoind conflicts with event handlers
	thisObj.InitTime	= new Date();
	thisObj.ID			= null;							// will be generated at initialization
	thisObj.color		= dialogbox_default_color;
	thisObj.title		= dialogbox_default_title;
	thisObj.text		= dialogbox_default_text;
	thisObj.buttons		= dialogbox_default_buttons;
	thisObj.rounded		= dialogbox_default_rounded;
	thisObj.shadow		= dialogbox_default_shadow;
	thisObj.previous_keydown_handler = null;
	
	//---------------------------------------------------------------------------------------------------------
	// constructor
	//---------------------------------------------------------------------------------------------------------
	this.Initialize = function(params) 
	{
		if (params.color)	{thisObj.color		= params.color;}
		if (params.title)	{thisObj.title		= params.title;}
		if (params.text)	{thisObj.text		= params.text;}
		if (params.buttons) {thisObj.buttons 	= params.buttons;}
		if (params.rounded) {thisObj.rounded 	= params.rounded;}
		if (params.shadow) 	{thisObj.shadow 	= params.shadow;}
		if (params.onclose != null)	{thisObj.buttons[0].func = params.onclose; }
		thisObj.GenerateID();
		thisObj.CreateHTML();
		thisObj.Register();
		thisObj.previous_keydown_handler = document.onkeydown;
		document.onkeydown = thisObj.KeyDownHandler;
	};
	
	//------------------------------------------------------------------------------------------------------------
	// internal: generate a unique ID based on date, time, milliseconds
	this.GenerateID = function() 
	{
		var ye = thisObj.InitTime.getFullYear();
		var mo = (thisObj.InitTime.getMonth()+1)+''; 	if (mo.length < 2) {mo = '0'+mo;}
		var da = thisObj.InitTime.getDate()+''; 		if (da.length < 2) {da = '0'+da;}
		var hr = thisObj.InitTime.getHours()+''; 		if (hr.length < 2) {hr = '0'+hr;}
		var mi = thisObj.InitTime.getMinutes()+''; 		if (mi.length < 2) {mi = '0'+mi;}
		var se = thisObj.InitTime.getSeconds()+''; 		if (se.length < 2) {se = '0'+se;}
		var ms = thisObj.InitTime.getMilliseconds()+''; if (se.length < 4) {ms = '0'+ms;}
		thisObj.ID = ye+mo+da+hr+mi+se+ms;	
	}
	//------------------------------------------------------------------------------------------------------------
	// internal: create a DOM attribute
	this.Attribute = function(name,value) 
	{
		var a = document.createAttribute(name);
		a.nodeValue = value;
		return a;
	}
	//------------------------------------------------------------------------------------------------------------
	// internal: get the height of the current document (cross browser)
	this.GetDocumentDimensions = function()
	{
		var d = document;
		var x = Math.max(
							Math.max(d.body.scrollWidth, d.documentElement.scrollWidth),
							Math.max(d.body.offsetWidth, d.documentElement.offsetWidth),
							Math.max(d.body.clientWidth, d.documentElement.clientWidth)
						);
		var y = Math.max(
							Math.max(d.body.scrollHeight, d.documentElement.scrollHeight),
							Math.max(d.body.offsetHeight, d.documentElement.offsetHeight),
							Math.max(d.body.clientHeight, d.documentElement.clientHeight)
						);
		return {w:x, h:y, toString:function(){return 'w:'+x+', h:'+y;}};
	}
	
	
	//------------------------------------------------------------------------------------------------------------
	// internal: get the scroll offset (cross browser)
	this.GetScrollOffset = function()
	{
		var x,y;
		if (self.pageYOffset) // all except Explorer
			{x = self.pageXOffset; y = self.pageYOffset;}
		else if (document.documentElement && document.documentElement.scrollTop)
			// Explorer 6 Strict
			{x = document.documentElement.scrollLeft; y = document.documentElement.scrollTop;}
		else if (document.body) // all other Explorers
			{x = document.body.scrollLeft; y = document.body.scrollTop;}
		return {w:x, h:y, toString:function(){return 'w:'+x+', h:'+y;}};
	}
	//------------------------------------------------------------------------------------------------------------
	// internal: create the DOM objects for the dialogbox */
	this.CreateHTML = function() 
	{
		var daObj = thisObj; // for IE debugging
	
		var imgurl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAAA1BMVEX///+nxBvIAAAAAXRSTlPDQotLbAAAAAxJREFUCJljYGBgAAAABAABowoV4wAAAABJRU5ErkJggg==';
		var boxcnt = dialogbox_instances.length;
		var Panel = document.createElement('div'); 
		Panel.setAttributeNode(thisObj.Attribute('id','dialogbox_'+thisObj.ID+'_panel'));
		
		// calculate panel size
		var panel_width 	= '100%';	
		var panel_height 	= '100%';
		doc_dim = thisObj.GetDocumentDimensions();
		//console.log('DialogBox - document dimensions: '+doc_dim.toString());
		if (doc_dim.w) 	{panel_width = doc_dim.w+'px';}
		if (doc_dim.h) 	{panel_height = doc_dim.h+'px';}
		
		
		// calculate box top coordinates
		var box_y			= (200+boxcnt*10);
		//console.log('DialogBox - box_y before height calculation: '+box_y);
		scr_off = thisObj.GetScrollOffset();
		//console.log('DialogBox - scroll offset: '+scr_off.toString());
		if (scr_off.h) 	{box_y += scr_off.h;}
		//console.log('DialogBox - box_y after height calculation: '+box_y);
		box_y += 'px';
		
		
		Panel.setAttributeNode(thisObj.Attribute('style','z-index:'+(9999+boxcnt)+'; position:absolute; left:0px; top:0px; width:'+panel_width+'; height:'+panel_height+'; display:none; background-image:url('+imgurl+'); background-repeat:repeat; '));
		
		var Center = document.createElement('center');
	
		var Box = document.createElement('div');
		Box.setAttributeNode(thisObj.Attribute('id','dialogbox_'+thisObj.ID+'_box'));
		Box.setAttributeNode(thisObj.Attribute('style','position:relative; top:'+box_y+'; width:400px; background-color:white; opacity:1.0; border:1px solid silver; padding:0px; padding-bottom:10px; text-align:left; ' 
												+ ( thisObj.rounded ? '-webkit-border-radius:5px; -moz-border-radius:5px;' : '') 
												+ ( thisObj.shadow  ? '-webkit-box-shadow: 5px 5px 5px #888; -moz-box-shadow: 5px 5px 5px #888;' : '') ));
	
		var Title = document.createElement('div');
		Title.setAttributeNode(thisObj.Attribute('id','dialogbox_'+thisObj.ID+'_title'));
		Title.setAttributeNode(thisObj.Attribute('style','position:relative; left:0px; top:0px;  background-color:'+thisObj.color+'; opacity:1.0; color:white; font-weight:bold; font-size:12pt; padding:2px; padding-left:5px; ' + ( thisObj.rounded ? '-webkit-border-radius:5px; -moz-border-radius:5px;' : '') ));
		var Title_Text = document.createTextNode(thisObj.title);
		Title.appendChild(Title_Text);
		
		var Text = document.createElement('div');
		Text.setAttributeNode(thisObj.Attribute('id','dialogbox_'+thisObj.ID+'_text'));
		Text.setAttributeNode(thisObj.Attribute('style','position:relative; padding:20px; max-width:360px;'));
		// to support not only Text but also HTML use innerHTML below!
		//var Text_Text = document.createTextNode(thisObj.text);
		//Text.appendChild(Text_Text);
	
		var Button_Bar = document.createElement('div');
		Button_Bar.setAttributeNode(thisObj.Attribute('id','dialogbox_'+thisObj.ID+'_buttonbar'));
		Button_Bar.setAttributeNode(thisObj.Attribute('style','text-align:center;'));
		
		Panel.appendChild(Center);
		Center.appendChild(Box);
		Box.appendChild(Title);
		Box.appendChild(Text);
		Box.appendChild(Button_Bar);
	
		//console.log('buttons.length: '+thisObj.buttons.length);
		 
		for (var idx=0; idx<thisObj.buttons.length;idx++)
		{
			//console.log('idx: '+idx);
			if (thisObj.buttons[idx]) // workaround for IE which counts one more element
			{
				var Button = document.createElement('button');
				Button.setAttributeNode(thisObj.Attribute('id','dialogbox_'+thisObj.ID+'_button_'+idx));
				Button.setAttributeNode(thisObj.Attribute('type','button'));
				//Button.setAttributeNode(thisObj.Attribute('onclick','dialogbox_Hide('+idx+');'));
				//Button.setAttributeNode(thisObj.Attribute('onclick',function(){thisObj.Close(idx);} ));
				var Button_Text = document.createTextNode(thisObj.buttons[idx].capt);
				Button.appendChild(Button_Text);
				Button_Bar.appendChild(Button);	
			}
		}
		// insert after <BODY> tag
		var Body = document.getElementsByTagName('body')[0];
		if (Body) 
		{
			var Body_FirstChild = Body.firstChild;
			Body.insertBefore(Panel,Body_FirstChild);
		}
		// insert text (with HTML support)
		document.getElementById('dialogbox_'+thisObj.ID+'_text').innerHTML = thisObj.text;
		// now we can assign handlers to generated buttons...
		for (var idx=0; idx<thisObj.buttons.length;idx++)
		{
			if (thisObj.buttons[idx]) // workaround for IE which counts one more element
			{
				document.getElementById('dialogbox_'+thisObj.ID+'_button_'+idx).onclick = function()
				{
				// get button index from button ID
					var butidx = this.id.substr(this.id.lastIndexOf('_')+1); 
					thisObj.Close(butidx);
				}
			}
		}
		document.getElementById('dialogbox_'+thisObj.ID+'_panel').style.display = 'block';
	};
	//------------------------------------------------------------------------------------------------------------
	// internal: register this box to the global registry
	this.Register = function()
	{
		dialogbox_instances.push(thisObj);
	}
	//------------------------------------------------------------------------------------------------------------
	// internal: unregister this box from the global registry
	this.Unregister = function()
	{
		for (var i=0; i<dialogbox_instances.length; i++)
		{
			if (dialogbox_instances[i].ID == thisObj.ID) {dialogbox_instances.splice(i,1);break;}
		}
	}
	//------------------------------------------------------------------------------------------------------------
	/* internal function: close the dialogbox and execute the function related to the button */
	this.Close = function(button_index)
	{
		document.getElementById('dialogbox_'+thisObj.ID+'_panel').style.display = 'none';
		document.onkeydown = null;
		//dialogbox_OnClose();
		if (thisObj.buttons[button_index] && thisObj.buttons[button_index].func)
		{
			thisObj.buttons[button_index].func();
		}
		document.onkeydown = thisObj.previous_keydown_handler;
		thisObj.Unregister();
	}	
	//------------------------------------------------------------------------------------------------------------
	/* internal function: capture Enter key */
	this.KeyDownHandler = function(Event)
	{
		var keycode = null;
		if (!Event) {Event = window.event;}
		if 		(Event.which)	{keycode = Event.which;}
		else if (Event.keyCode)	{keycode = Event.keyCode;}
		if (keycode == 13) {thisObj.Close(0); return false;}
		if (keycode == 27) {thisObj.Close(0); return false;}
		return true;
	}	
	
	
	
	thisObj.Initialize(params);
}



