Location: PHPKode > projects > GroundOS > groundos/logic/view/view.class.php
<?PHP
/**
 * /logic/view/view.class.php
 *
 * Outputs to the web browser
 * @package AgaresCore4
 * @author Agares Media <hide@address.com>
 * @copyright Copyright (c) 2007, 2008, 2009 Agares Media.  All rights reserved.
 */

/**
 * view() Class
 *
 * Outputs to the web browser
 * @package AgaresCore4
 */
class view extends rootclass {
	/**
	 * The microtime when the view was first called.
	 * @var mixed $benchmark_start
	 */
	var $benchmark_start;

	/**
	 * An array containing each javascript library dependancy that has been previously called
	 * @var array $dependancylist
	 * @access private
	 */
	private $dependancylist = array();

	/**
	 * True if the document is XHTML, false otherwise.
	 * @var boolean $xhtml
	 * @access public
	 */
	public $xhtml = false;	
	

	/**
	 * The constructor begins counting the time it takes to execute the script
	 */
	public function __construct($title = NULL, $keywords = NULL, $description = NULL, $doctype = 'xhtml', $realdoctype='xhtml 1.0 frameset', $realencode='utf-8', $headtop_output = '', $headbottom_output = '', $dependancyArray = NULL) { // Constructor
		try {
			$this->benchmark_start = microtime();
			header('Pragma: public'); 
			header("Status: 200");
			if($title != NULL) {
				global $headtop_output;
				global $headbottom_output;
				global $domain;
				global $database; 

				$finalout = NULL;
					
				ob_start();
				
				@apache_setenv('no-gzip', 1);
			    @ini_set('zlib.output_compression', 0);
			    @ini_set('implicit_flush', 1);
			    	
				while (ob_get_level()) {
				    ob_end_flush();
				}
				// start output buffering
				if (ob_get_length() === false) {
				    ob_start();
				}
				
	   			ob_implicit_flush(1);		
			    ob_start();
				
				if($doctype = strtolower('xhtml')) {
					$this->toscreen($this->encodetype('xhtml',$realencode));	// Set the XHTML to UTF-8,  Delete this if not using XHTML
				}
				$this->toscreen($this->doctype(strtolower($realdoctype)));
				$this->toscreen($this->html());								// Create a <html> tag
				$this->toscreen($this->head());							// Create a <head> tag
				$this->toscreen($this->encodetype($realencode));		// Use a meta tag to specify UTF-8 as well
				$this->toscreen($this->title($title));				// Set the meta tag title of the page
				$this->toscreen($this->metakeywords($keywords));	// Set the meta tag for keywords
				$this->toscreen($this->metadesc($description));		// Set the meta tag for description
				$this->toscreen($this->stripwhitespace($headtop_output));					//  Load any CSS or other top most content intended for the head tag
				$this->toscreen('<script type="text/javascript"><!--//--><![CDATA[//><!--
								document.domain = "'.$domain.'";
							  //--><!]]></script>');
				if($dependancyArray!=NULL && is_array($dependancyArray)) {
					foreach ($dependancyArray as $currentDependancy) {
						$this->toscreen($this->dependancy($currentDependancy));
					}
				}
				
				$this->toscreen($headbottom_output);				//  Load any Javascript or othercontent intended for the bottom of head tag
				$this->toscreen($this->head('close'));					// Close the </head> tag
						
			}
		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	public function __destruct() {
		try {

		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	/**
	 * body_output() Method
	 * 
	 * Echoes the current value of the $body_output global variable
	 */
	public function body_output() {
		global $body_output;
		echo $body_output;	
	}
	
	/**
	 * toscreen() Method
	 * 
	 * Attempts to flush the output to the screen
	 * @param string $string A string to echo immediately, which will be flushed to the output device.
	 * @return void
	 */
	public function toscreen($string=NULL) {
		ob_start();
		echo $string;	
		try {
		    ob_flush();
		    flush();
		    ob_end_flush();
		    ob_start(); 
		} catch(Exception $e) {

		}		
	}
	
	
	/**
	 * isxhtml() Method
	 * 
	 * Returns true if the document has been set to XHTML, false if not.
	 * @access public
	 * @return boolean $this->xhtml
	 */
	public function isxhtml() {
		return $this->xhtml;	
	}
	
	/**
	 * setxhtml() Method
	 * 
	 * Sets the value of $this->xhtml to the value specified in the $value parameter
	 * @access public
	 * @param boolean $value 
	 * @return void
	 */
	public function setxhtml($value) {
		$this->xhtml = $value;
	}
	
	/**
	 * dependany() Method
	 * 
	 * The dependancy method takes a request for a javascript library, providing the following benefits:
	 * 1) Javascript files will only be loaded once, even if the file is called multiple times
	 * 2) The javascript itself from all files is put into 1 single compressed file resulting in only 1 http request and reduced overall file transfer size
	 * 
	 * @access public
	 * @param string $filetoload The javascript file you wish to load, full or relative path
	 * @param string $tagoption This will allow you to add things to the script tag, such as defer="defer"
	 * @return string
	 */
	public function dependancy($filetoload, $tagoption=NULL) {
		global $debug;
		$load = true;
		foreach($this->dependancylist as $cycle) {
				if($cycle==$filetoload) {
					$load = false;	
				}
		}
		if ($load==true) {
			$minified ='';
			if($debug==true) {
				$minified .='
				 <!-- SOURCE FILE: '.$filetoload .' --> 
				 ';	
			}
			$minified .= $this->jscompress(file_get_contents($filetoload), $tagoption);
			$minified .= '';
			$this->dependancylist[] = $filetoload; // Add this file to the previously loaded dependancy list so that we do not load again
			return $minified;
		} else {
			return NULL;	
		}
	}
	
	/**
	 * jscompress() Method
	 * 
	 * Shrinks javascript by removing white spaces and comments.  Uses the jsmin library
	 * @access public
	 * @param string $toshrink The javascript to minify
	 * @param string $tagoption This will allow you to add things to the script tag, such as defer="defer"
	 * @return string
	 */
	public function jscompress($toshrink, $tagoption=NULL) {
		require_once('./libraries/3rdparty/jsmin/jsmin.php');
		try {
			$value = '
			<script type="text/javascript"'.$tagoption.'><!--//--><![CDATA[//><!--';
			if(!$value .= JSMin::minify($toshrink)) {
				throw new Exception('Error minifying javascript');
			} else {
				$value .= '//--><!]]></script>
				';
				return $value;
			}
		} catch(Exception $e) {
			$this->errorReport($e);
		}			
	}
	
	
	/**
	 * doctype() Method
	 *
	 * Returns a string containing the correct declaration for most common doc types.
	 * @access public
	 * @param mixed $value Either a string or an integer which specifies which doctype to choose
	 * @return string $doctype Returns a string containing the correct declaration for most common doc types.
	 */
	public function doctype($value=NULL) {
		try {
			if($value==0||$value==NULL||strtolower($value)=='html 4.01 strict') {$doccode='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">';}
			if($value==1||strtolower($value)=='html 4.01 transitional') {$doccode='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';}
			if($value==2||strtolower($value)=='html 4.01 frameset') {$doccode='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';}
			if($value==3||strtolower($value)=='xhtml 1.0 strict') {$this->setxhtml(true);$doccode='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';}
			if($value==4||strtolower($value)=='xhtml 1.0 transitional') {$this->setxhtml(true);$doccode='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';}
			if($value==5||strtolower($value)=='xhtml 1.0 frameset') {$this->setxhtml(true);$doccode='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';}
			return $doccode;
		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	/**
	 * encodetype() Method
	 *
	 * Returns a string containing the correct declaration for most encoding types
	 * @access public
	 * @param mixed $value Either a string or an integer which specifies which encoding type to choose
	 * @param mixed $value2 A string for a custom encoding type.  Whatever is specified in this string will be used.
	 * @return string $doccode Returns a string containing the correct declaration for most encoding types
	 */
	public function encodetype($value=NULL, $value2=NULL) {
		try {
			if($value==0||$value==NULL||strtolower($value)=='utf-8') {$doccode='<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';}
			if($value==1||strtolower($value)=='iso-8859-1') {$doccode='<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />';}
			if($value==2||strtolower($value)=='other' || isset($value2)) {$doccode='<meta http-equiv="Content-Type" content="text/html; charset='.$value2.'" />';}
			if($value==3||strtolower($value)=='xhtml') {$this->setxhtml(true);$doccode='<?xml version="1.0" encoding="'.$value2.'"?>';} // This over writes the value of $doccode that is set in the statement above
			return $doccode;
		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	/**
	 * html() Method
	 *
	 * Outputs an html tag
	 * @access public
	 * @param mixed $action If this parameter is null, then an opening tag is created.  If the parameter is 0 or close it will close the tag
	 * @return string Returns a string with HTML
	 */
	public function html($action=NULL) {
		try {
			if ($action==NULL) {
				if($this->isxhtml()) {
					return '<html xmlns="http://www.w3.org/1999/xhtml">';	
				} else {
					return '<html>';
				}
			} elseif($action==strtolower('close')||$action==0) {
				return '</html>';
			}
		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	/**
	 * head() Method
	 *
	 * Outputs an head tag
	 * @access public
	 * @param mixed $action If this parameter is null, then an opening tag is created.  If the parameter is 0 or close it will close the tag
	 * @param string $headload If you need to load anything immediately after the head tag open, specify what you need loaded in this string
	 * @return string Returns a string with HTML
	 */
	public function head($action=NULL, $headload=NULL) {
		try {
			if ($action==NULL) {
				return '<head>'.$headload;
			} elseif($action==strtolower('close')||$action==0) {
				return '</head>';
			}
		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	/**
	 * title() Method
	 *
	 * Outputs a title meta tag
	 * @access public
	 * @param string $title The title of the webpage
	 * @return string Returns a string with HTML
	 */	
	public function title($title) {
		return '<title>'.$title.'</title>';
	}

	/**
	 * meta() Method
	 *
	 * Outputs a standard meta tag
	 * @access public
	 * @param string $meta The metatag you wish to set the value of
	 * @param string $value The value that you would like to set the metatag to
	 * @return string Returns a string with HTML
	 */		
	public function meta($metatag, $value) {
		return '<meta name="'.$metatag.'" content="'.$value.'" />';
	}

	/**
	 * metakeywords() Method
	 *
	 * Outputs a metatag keyword tag
	 * @access public
	 * @param string $keywords A string containing a comma seperated list of keywords
	 * @return string Returns a string with HTML
	 */		
	public function metakeywords($keywords) {
		return $this->meta('keywords', $keywords);
	}

	/**
	 * metadesc() Method
	 *
	 * Outputs a metatag description tag
	 * @access public
	 * @param string $desc A string containing the meta description for the page
	 * @return string Returns a string with HTML
	 */		
	public function metadesc($desc) {
		return $this->meta('description', $desc);
	}

	/**
	 * body() Method
	 *
	 * Outputs a body tag, and optionally loads Javascript/CSS style information into the tag using $bodyload
	 * @access public
	 * @param mixed $action If this parameter is null, then an opening tag is created.  If the parameter is 0 or close it will close the tag
	 * @param string $bodymarkup If you need to write anything inside the opening body tag, specify what you need loaded in this string
	 * @return string Returns a string with HTML
	 */
	public function body($action=NULL, $bodymarkup=NULL) {
		try {
			if ($bodymarkup!=NULL || $action!=strtolower('close')||$action!=0) {
				return '<body'.$bodymarkup.'>';
			} elseif($action==strtolower('close')||$action==0) {
				return '</body>';
			}
		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	/**
	 * form() Method
	 * 
	 * Creates a new form
	 * 
	 * @access public
	 * @param string $action URL to send form data on submission.  Required. If the parameter is 0 or close it will close the form tag.
	 * @param string $formmarkup If you need to write anything inside the form tag, such as method, enctype, name, class, etc, do it here.
	 * @return string
	 */
	public function form($action, $formmarkup=NULL) {
		if($action!=strtolower('close')||$action!=0) {
			$output = '<form action="'.$action.'" '.$formmarkup.'>';
		} else {
			$output = '</form>';	
		}
		return $output; 
	}	
	
	
	/**
	 * css() Method
	 * 
	 * Set and control CSS values. Here's an example of how to use this method in a view file in your application:
	 * 
	 * <code>
	 * <?php
	 * 	loadclass('view');
	 * 	$view = new view();
	 * 
	 * 	$headtop_output .= '
	 * 	<style type="text/css">';
	 * 	$headtop_output .= $view->css('body', array(1=>
	 * 		'font-family','arial,verdana',
	 * 		'background','#FFFFFF',
	 * 		'color','#000000',
	 * 		'font-size','11px',
	 * 		)
	 * 	);
	 * 	$headtop_output .= '
	 * 	</style>
	 * 	';
	 * 
	 * 	echo $headtop_output; // This echo statement should not be in a view file.  Rather you should always echo the $view->output() method of the $view object.
	 * 
	 * ?>
	 * </code>
	 * 
	 * The example above would echo out $headtop_output, with this as the result:
	 * <code>
	 * <style type="text/css">
	 * 	body {
	 * 		font-family:arial,verdana;
	 * 		background:#FFFFFF;
	 * 		color:#000000;
	 * 		font-size:11px;
	 * }
	 * </style>
	 * </code>
	 * 
	 * @access public
	 * @param string $target The target is an HTML tag (html, body, ul, li, img tags etc), ID, or class
	 * @param array $value An array with each CSS attribute to be edited is in each odd numbered array element, the value to set that attribute to is in the even numbered array elements. See the example.
	 * @return string $returnValue Returns a string with HTML
	 */
	public function css($target, $value) {
		global $homedir;
		global $body_output;
		global $bodymarkup;
		global $headtop_output;
		global $headbottom_output;
		global $windowhistory;		

		try {
			$returnValue = "
$target {
";
		// This loops iterates through the $value array and creates the CSS output
		$icounter = 0;
		$total = count($value);
		while($icounter <= $total) {
			$bcounter = $icounter + 1;
			
			if(isset($value[$icounter]) && isset($value[$bcounter]) && $icounter % 2 != 0 ) {
				$returnValue .= '	'.$value[$icounter] .':'. $value[$bcounter].';
'; 
			}
			$icounter++;
		}
			$returnValue .= "}
";
		
		return $returnValue;
			
		} catch(Exception $e) {
			$this->errorReport($e);
		}		
	}
	
	/**
	 * style() Method
	 * 
	 * The style() method is a completely different method than the css() method.  The style() method 
	 * connects to the database and attempts to pull the CSS for each target for the specified application
	 * and view from that app.  It returns a string with all the CSS for the view, and it includes the style
	 * tags as well.
	 * 
	 * Here's an example:
	 * <code>
	 * echo $view->style('sitedesigner', 'createproject');
	 * </code>
	 * 
	 * Now since the style() method calls the database, you would need to have some data populated in the database
	 * in order for this to return anything other than opening and closing style tags.  Here's the result of this
	 * code on my test machine:
	 * 
	 * <code>
	 * <style type="text/css">body{font-family:arial,verdana;background:#FFFFFF;color:#000000;font-size:11px;}#previewurl span, #previewpath span{color:#777777;text-decoration:underline;}</style>
	 * </code>
	 * 
	 * @access public
	 * @param string $application The name of the application 
	 * @param string $view The name of the view from the application in which the style will be loaded and applied to
	 * @return string $returnValue Returns a string with HTML
	 */
	public function style($application, $view) {
		global $database; // Let's use the already open global db connection

		$cssquery = $database->query("SELECT * FROM `css` WHERE `application`='$application' AND `view`='$view';"); // Let's load the CSS from the database
		$returnValue = '<style type="text/css">';
		$targetHistory[] = NULL;
		$icounter = 0;
		foreach($cssquery as $iteration) { // This foreach loop sorts the CSS by the element ID/reference
			$previouscounter = $icounter - 1;
			if($previouscounter == -1) {$previouscounter=0;}
			if($iteration['target']==$targetHistory[$previouscounter]) { // If we're still processing the same CSS target as the last iteration
				$returnValue .= $iteration['attribute'].':'.$iteration['value'].';';
			} else { // If we're targeting a new CSS element
				if($icounter>0) { // If $icounter is greater than 0 we know we need to close the brackets for the last CSS
					$returnValue .= '}';
				}
				$returnValue .= $iteration['target'] . '{';
				$returnValue .= $iteration['attribute'].':'.$iteration['value'].';';
			}
			$targetHistory[$icounter] = $iteration['target']; // This saves the last target, so we can look at it later
			$icounter++;
		}
		$returnValue .= '}</style>';
		return $returnValue;
	}
	

	
	/**
	 * stripwhitespace() Method
	 * 
	 * Strips whitespace from a string.
	 * 
	 * @access public
	 * @param string $string The string you wish to remove excessive whitespace from.  Not Javascript safe.  Us the jscompress() method for Javascript.
	 * @return string
	 */
	public function stripwhitespace($string) {
		return preg_replace('/\s\s+/', ' ', $string);
	}
	
	
	/**
	 * output() Method
	 *
	 * Creates a valid HTML/XHTML webpage
	 * @access public
	 * @param string $title The meta tag title value
	 * @param string $keywords The meta tag keyword value
	 * @param string $description The meta tag description value
	 * @param mixed $doctype The doctype of the output.  Used only for xhtml.  If using html, set this value to NULL
	 * @param string $realdoctype The doctype of the output
	 * @param string $realencode The encoding type of the document
	 * @param string $headtop_output Anything that needs to go directly at the top of the head should go here.  CSS should always load before Javascript
	 * @param string $headbottom_output Anything that needs to go directly near the bottom of the head should go here.  Javascript should go here.
	 * @param string $bodymarkup If you need custom code in your opening <body> html tag, put it here
	 * @param string $body_output The content of the web page should go here
	 * @return string Returns a string with HTML
	 */	
	public function output($title = 'AgaresCore 4', $keywords = 'AgaresCore 4', $description = 'AgaresCore 4', $doctype = 'xhtml', $realdoctype='xhtml 1.0 frameset', $realencode='utf-8', $headtop_output = '', $headbottom_output = '', $bodymarkup = NULL, $body_output = '') {
		global $body_output;
		global $headtop_output;
		global $headbottom_output;
		global $domain;
		global $database; 
		global $installed; // To detect if the database is installed

		try {
			$finalout = NULL;
				
			if($doctype = strtolower('xhtml')) {
				$finalout .= $this->encodetype('xhtml',$realencode);	// Set the XHTML to UTF-8,  Delete this if not using XHTML
			}
			$finalout .= $this->doctype(strtolower($realdoctype));
			$finalout .= $this->html();								// Create a <html> tag
			$finalout .= $this->head();							// Create a <head> tag
			$finalout .= $this->encodetype($realencode);		// Use a meta tag to specify UTF-8 as well
			$finalout .= $this->title($title);				// Set the meta tag title of the page
			$finalout .= $this->metakeywords($keywords);	// Set the meta tag for keywords
			$finalout .= $this->metadesc($description);		// Set the meta tag for description
			$finalout .= $this->stripwhitespace($headtop_output);					//  Load any CSS or other top most content intended for the head tag
			$finalout .= '<script type="text/javascript"><!--//--><![CDATA[//><!--
							document.domain = "'.$domain.'";
						  //--><!]]></script>';
			$finalout .= $headbottom_output;				//  Load any Javascript or othercontent intended for the bottom of head tag
			$finalout .= $this->head('close');					// Close the </head> tag
			$finalout .= $this->body(NULL, $bodymarkup);							// Open the body tag.  To insert custom style of javascript, insert a string into the parameter.
			$finalout .= $body_output;						// Output the body of the document
			
			$benchmark = microtime() - $this->benchmark_start;
			$finalout .= '<!-- Script Execution Time: ' . $benchmark . '-->';
			if ($installed == true) { // Only display the database queries, if the database has been installed.
				$finalout .= '<!-- Database queries: '.$database->get_query_count().'-->';
			}
			
			$finalout .= $this->body('close');					// Close the </body> tag
			$finalout .= $this->html('close');						// Close the </html> tag
			return $finalout;
		} catch(Exception $e) {
			$this->errorReport($e);
		}
	}

	/**
	 * window() Method
	 * 
	 * Creates an ajax window using the Prototype library and Windowjs.
	 * 
	 * @access public
	 * @param string $title The title of the window.
	 * @param string $content $content is either a URL if the $windowtype is set to "taskbar", "window", "subwindow" or "all", or alternatively $content should be the ID of a DIV that already exists if $windowtype is "widget"
	 * @param string $windowid A unique ID to give the window to allow us to manipulate the window with javascript.  Prefix this value with an ampersand @ character to make this id the actual ID used, otherwise unique numbers will be appended to the window ID
	 * @param integer $winwidth The width in pixels of the window.  Note that this refers to the internal dimensions of the content that is diplayed inside the window.  The actual external size is determined by the size and dimensions of the window decoration you specify in $decoration
	 * @param integer $winheight The height in pixels of the window.  Note that this refers to the internal dimensions of the content that is diplayed inside the window.  The actual external size is determined by the size and dimensions of the window decoration you specify in $decoration
	 * @param string $decoration The window skin you wish to apply to this window.  Themes are located in \libraries\3rdparty\windowsjs\themes\  If this value is not specified then the default decoration specified in $windowdecoration in the settings.php file, is choosen by default
	 * @param integer $zindex The zindex you wish the window to be at. You should leave this to the default 500 unless you have a specific reason to adjust the z-index of the window you're creating.
	 * @param string $destroyonclose If this is set to the string value of "false", then windows are not destroyed in the DOM even after they are closed.  It is better to leave this to the default value of 'true' so that you free up memory.
	 * @param string $recenterauto If this is set to the string value of "true" then 
	 * @param integer $toppos The number of pixels from the top of the screen in which to position the window.  This parameter only applies when $leftpos is also set to a value.  If one or both of those parameters are not set, then the window will be displayed in the center of the users browser screen.  If set to 0 it is the same as NULL 
	 * @param integer $leftpos The number of pixels from the left of the screen in which to position the window.  This parameter only applies when $toppos is also set to a value.  If one or both of those parameters are not set, then the window will be displayed in the center of the users browser screen. If set to 0 it is the same as NULL 
	 * @param string $usetags If this is set to the string value of "true" then XHTML valid closing and opening tags will be used.  If set to the string value of "false" then all the code is outputted to a single line, suitable for use in onclick and other inline javascript.
	 * @param string $windowtype The accepted values for $windowtype are "taskbar", "window", "subwindow", "widget" or "all".  If this value is not specified, it is set to "taskbar" by default. $content is either a URL if the $windowtype is taskbar or all.  It should be the ID of a DIV that already exists if $windowtype is widget
	 * @param string $isresizable If this is set to the string value of "true" then the window can be resized to any dimension.
	 * @param string $iscloseable If this is set to the string value of "true" then the window can be closed. See the $destroyonclose parameter.
	 * @param string $isminimizable If this is set to the string value of "true" then the window can be minimized.
	 * @param string $ismaximizable If this is set to the string value of "true" then the window can be maximized to fill it's parent.
	 * @param string $isdraggable If this is set to the string value of "true" then the window can be dragged by the user and repositioned.  "false" 
	 * @param string $windowclose The javascript code to execute whenever the window is closed
	 * @param string $windowopen The javascript code to execute whenever the window is opened
	 * @param string $resizewindow The javascript code to execute whenever the window is resized
	 * @param string $windowminimize The javascript code to execute whenever the window is (un)minimized.
	 * @param string $windowmaximize The javascript code to execute whenever the window is (un)maximized.
	 * @param string $windowmove The javascript code to execute whenever the window is done being moved.
	 * @param string $windowshow The javascript code to execute whenever the window is first shown.
	 * @return string Returns a string with HTML
	 * @see awindow()
	 * @todo Right now observers Javascript code is called everytime for every window.  Instead, we need to make one set of observers that will work for all windows win = new Window({onClose: function() {customCloseFunction(Arguments);}})
	 * @todo Windows/widgets should have the optional ability to automatically expand by height, width, or both.
	 * @todo Windows/widgets positioned below an automatically expanding window/widget should optionally move down
	 * @todo 
	 */		
	public function window($title = NULL, $content = NULL, $windowid = NULL, $winwidth=320, $winheight=200, $decoration = NULL, $zindex = 500, $destroyonclose = 'true', $recenterauto = 'false', $toppos = NULL, $leftpos = NULL, $usetags = 'false', $windowtype = 'taskbar', $isresizable='true', $iscloseable='true', $isminimizable='true', $ismaximizable = 'true', $isdraggable = 'true', $windowclose=NULL, $windowopen=NULL, $resizewindow=NULL, $windowminimize=NULL, $windowmaximize=NULL, $windowmove=NULL, $windowshow = NULL) {
		global $homedir;
		global $body_output;
		global $bodymarkup;
		global $headtop_output;
		global $headbottom_output;
		global $windowhistory;
		global $debug;
		global $windowdecoration;
		global $groundos;
		global $savegroundoswindows;
		global $defaultx;
		global $defaulty;
		
		if ($decoration==NULL) {
			$decoration = $windowdecoration;
		}
		
		if ($windowid==NULL) { // Create a random window id if none was explictly set
			$windowid = 'winid' . rand(0, getrandmax()) . rand(0, getrandmax());
		} else {
			if(substr($windowid, 0, 1)!='@') {
				$windowid = $windowid . rand(0, getrandmax()) . rand(0, getrandmax());
			} else {
				$windowid = substr($windowid, 1, strlen($windowid));
				$windowid = $windowid;
			}
		}

		if ($windowhistory==NULL) {
			$headtop_output .= '
			<link href="'.$homedir.'/libraries/3rdparty/windowsjs/themes/default.css" rel="stylesheet" type="text/css"></link> 
			<link href="'.$homedir.'/libraries/3rdparty/windowsjs/themes/'.$decoration.'.css" rel="stylesheet" type="text/css"></link> 
			<link href="'.$homedir.'/libraries/3rdparty/windowsjs/themes/debug.css" rel="stylesheet" type="text/css"></link>
			<link href="'.$homedir.'/libraries/3rdparty/windowsjs/themes/alert.css" rel="stylesheet" type="text/css"></link>  
			';
			
			$headbottom_output .= $this->dependancy('./libraries/3rdparty/prototype/prototype.js');
			$headbottom_output .= $this->dependancy('./libraries/3rdparty/script.aculo.us/src/effects.js');	
			$headbottom_output .= $this->dependancy('./libraries/3rdparty/windowsjs/javascripts/window.js');
			$headbottom_output .= $this->dependancy('./libraries/3rdparty/windowsjs/javascripts/window_effects.js');
			$headbottom_output .= $this->dependancy('./libraries/3rdparty/windowsjs/javascripts/debug.js');
			$headbottom_output .= $this->dependancy('./libraries/3rdparty/windowsjs/javascripts/extended_debug.js');

			$windowhistory = true; // When we set $windowhistory to true, we stop ourselves from reloading the same stuff in the header.
		}

		// This code block creates the custom javascript handlers specified in $windowclose, $windowopen, $resizewindow, $windowminimize, $windowmove, and other applicable parameters for each potentially open window

		$handlers = NULL;
		// This statement is for $windowclose 
		if($debug==true||$windowclose!=NULL) {
			$handlers .= '
				function windowClose'.$windowid.'() {
					top.Effect.Shrink("task'.$windowid.'", { duration: 1.0, fps: 100, afterFinish: function() { var el = top.document.getElementById(\'task'.$windowid.'\');el.parentNode.removeChild(el); }});
					top.debug("Window closed: window id: '.$windowid.'");
					'.$windowclose.'
					return true;
				}			
			'; 
		}
		
		// This statement is for $windowopen 
		if($debug==true||$windowopen!=NULL) {
			$handlers .= '
				function windowOpen'.$windowid.'() {
					top.debug("Window opened: window id: '.$windowid.'");
					'.$windowopen.'
					return true;
				}	
			'; 
		}	
			
		
		// This statement is for $resizewindow 
		if($debug==true||$resizewindow!=NULL) {
			$handlers .= '
				function resizeWindow'.$windowid.'() {
					var currentWindowSize = '.$windowid.'.getSize();
					top.debug("Window resized to: " + currentWindowSize[\'width\'] + "x" + currentWindowSize[\'height\'] + "px window id: '.$windowid.'");
					'.$resizewindow.'
					return true;
				}
			'; 
		}		

		// This statement is for $windowminimize 
		if($debug==true||$windowminimize!=NULL) {
			$handlers .= '
				function windowMinimize'.$windowid.'() {
					'.$windowid.'.setStatusBar("<img src=\\\''.$homedir.'/data/gif/ajax-loader003.gif\\\' alt=\\\'Done...\\\' />");
					if('.$windowid.'.isMinimized()) {						
						top.debug("Window minimized: window id: '.$windowid.'");
					} else {
						top.debug("Window unminimized: window id: '.$windowid.'");
					}
					'.$windowminimize.'					
					return true;
				}	
			'; 
		}			
		
		// This statement is for $windowmaximize
		if($debug==true||$windowmaximize!=NULL) {
			$handlers .= '
				function windowMaximize'.$windowid.'() {
					if('.$windowid.'.isMaximized()) {
						top.debug("Window maximized: window id: '.$windowid.'");
					} else {
						top.debug("Window unmaximized: window id: '.$windowid.'");
						
					}
					'.$windowmaximize.'	
					return true;
				}	
			'; 
		}			
		
			// This statement is for $windowmove
		if($debug==true||$windowmove!=NULL) {
			$handlers .= '
				function windowMove'.$windowid.'() {
					'.$windowmove.'
					var currentWindowPos = '.$windowid.'.getLocation();
					top.debug("Window moved to: TOP: " + currentWindowPos[\'top\'] + " LEFT: " + currentWindowPos[\'left\'] + " window id: '.$windowid.'");
					return true;
				}		
			'; 
		}

		// This statement is for $windowshow
		if($debug==true||$windowshow!=NULL) {
			$handlers .= '
				function windowShow'.$windowid.'() {
					'.$windowid.'.setStatusBar("<img src=\\\''.$homedir.'/data/gif/ajax-loader003.gif\\\' alt=\\\'Done...\\\' />");
					'.$windowshow;

			// If we're saving window locations to the database, we'll do it with an ajax call here.
			if ($groundos==true && $savegroundoswindows==true) {
				
				if(!function_exists('boolnumber')) {
					require('./logic/_boolean/_boolean.functions.php');
				}
				
				// Lets prepare a few of values for insertion into the db
				if($toppos==NULL) {	$topposdb = 0;} else {$topposdb = $toppos;}
				if($leftpos==NULL) { $leftposdb = 0; } else { $leftposdb = $toppos;	}		
				
				$handlers .= '
				  			new Ajax.Request(\''.$homedir.'/admin/savewindow\',{
								asynchronous:true,
								method: "post",
								parameters: {
									title: "'.base64_encode($title).'",
									content: "'.base64_encode($content).'",
									windowid: "'.base64_encode($windowid).'",
									winwidth: "'.$winwidth.'",
									winheight: "'.$winheight.'",
									decoration: "'.$decoration.'",
									zindex: "'.$zindex.'",
									destroyonclose: "'.$destroyonclose.'",
									recenterauto: "'.$recenterauto.'",
									toppos: "'.$topposdb.'",
									leftpos: "'.$leftposdb.'",
									windowtype: "'.$windowtype.'",
									isresizable: "'.boolnumber($isresizable).'",
									iscloseable: "'.boolnumber($iscloseable).'",
									isminimizable: "'.boolnumber($isminimizable).'",
									ismaximizable: "'.boolnumber($ismaximizable).'",
									isdraggable: "'.boolnumber($isdraggable).'",
									windowstate: "opened"
								},
								onSuccess: function() {
									top.debug("Window saved to database");
								},
								onFailure: function() {
									top.debug("Window failed to save to database");
								}								
								
							}); 				
				';				
			}
			
			$handlers .= '
					return true;
				}		
			'; 
		}		

		// If we're within GroundOS, then we need to store windows on the task list, and react when they're clicked.
		if($groundos==true) {
			$handlers .= '
					function taskWindow(windowid) {
						windowid.toFront();
						top.debug("Taskbar clicked for window id: " + windowid.getId());
						if(windowid.isMinimized()==true){
							windowid.minimize();
						}				
						return true;
					}	
			';	
		}	
		
		if($handlers!=NULL) {
			$headbottom_output .= $this->jscompress($handlers, ' defer="defer"');
		}
		
		// This little block of code looks to see whether we're creating a "window" (pulling content into an iframe window) or creating a widget (a window that is created from a preexisting DIV.)
		$contentoption = NULL;
		$contentoption2 = NULL;
		if(strtolower($windowtype=='widget')) {
			$contentoption2 = "$windowid.setContent('$content', false, false); ";
			$contenttarget = NULL; // Widgets should always open inside of the current window, whether or not it is the true root, or merely an iframe window itself.
		} elseif(strtolower($windowtype!='widget')) {
			$contentoption = "url: '$content',";
			$contentoption2 = "$windowid.setStatusBar('<center><img src=\'$homedir/data/gif/ajax-loader002.gif\' alt=\'Loading...\' /></center>');";
			$contenttarget = "window.parent."; // Windows should always open from the root parent DOM
		}

		if(strtolower($windowtype=='subwindow')) {
			$contentoption = "url: '$content',";
			$contenttarget = NULL;
		}
		// End little block of code :)

		/**
		 * @todo This block of code actually creates the window javascript.  Need to allow the ability to explicitly set the parent/top attribute for maximum control of the DOM
		 */
		$output = NULL;
		if (strtolower($usetags)=='true') { // If $usetags = 'true' then we will create the wrapping Javascript tags.  Set to false if you need to put the window creation code in a link/onclick etc
			$output = "<script type=\"text/javascript\" defer=\"defer\"><!--//--><![CDATA[//><!--
			";
		}
		$thecookietime = time()+36000000;
		$output .= "$windowid = new {$contenttarget}Window({onClose:windowClose$windowid, onBeforeShow:windowOpen$windowid, onload:windowShow$windowid, onEndResize:resizeWindow$windowid, onMinimize:windowMinimize$windowid, onMaximize:windowMaximize$windowid, onEndMove:windowMove$windowid, className: '$decoration', title: '$title', zindex: $zindex, width:$winwidth, height:$winheight, $contentoption destroyOnClose: $destroyonclose, recenterAuto:$recenterauto, resizable:$isresizable, closable:$iscloseable, minimizable:$isminimizable, maximizable:$ismaximizable, draggable:$isdraggable, showEffect:Effect.Grow, showEffectOptions:{ duration: 0.5, fps: 100 }, hideEffectOptions:{ duration: 0.3, fps: 100 }, hideEffect:Effect.Puff});$contentoption2";

		if($toppos==0) { $toppos=NULL;}
		if($leftpos==0) { $leftpos=NULL; }		
		if ($toppos!=NULL && $leftpos!=NULL) {
			$output .= "$windowid.setLocation($toppos, $leftpos);$windowid.show();";
		} else {
			$output .= "$windowid.showCenter();";
		}
		if (strtolower($usetags)=='true') {
			$output .="//--><!]]></script>";
		} 
		// End window javascript creation code.

	
		// This code adds the window to the taskbar within GroundOS if it's necessary
		if($groundos==true && strtolower($windowtype) != 'widget' && strtolower($windowtype) != 'subwindow') {
			if(strtolower($usetags)=='true') {
				$output .= "<script type=\"text/javascript\" defer=\"defer\"><!--//--><![CDATA[//><!--
				";
			}

			//$output .= "	top.document.getElementById('taskbar').innerHTML = top.document.getElementById('taskbar').innerHTML + '<div class=\\'openwindow\\' id=\\'task$windowid\\' onClick=\\'taskWindow($windowid);\\'>$title</div>';";
			$output .= " var task$windowid = document.createElement('div');task$windowid.id = 'task$windowid';top.window.document.getElementById('taskbar').appendChild(task$windowid);var targetDiv$windowid = top.window.document.getElementById('task$windowid');targetDiv$windowid.style.display='none';targetDiv$windowid.innerHTML = '$title';targetDiv$windowid.className = 'openwindow';top.Effect.Grow('task$windowid', {fps: 100});targetDiv$windowid.onclick=function() {taskWindow($windowid);};";	
			
			if(strtolower($usetags)=='true') {
				$output .= "//--><!]]></script>";
			}

		}
		// End taskbar code


		return $output;
	}

	/**
	 * awindow() Method
	 * 
	 * The awindow() method is identical to the window() method, except it is configured through an array, rather than individual properties.
	 * Note that you must completely populate the entire array to avoid PHP notices.
	 * 
	 * @access public
	 * @param array $arrayOptions The array should specify the following attributes: title, content, windowid, winwidth, winheight, decoration, zindex, destroyonclose, recenterauto, toppos, leftpos, usetags, windowtype, isresizable, iscloseable, isminimizable, ismaximizable, and isdraggable.  See the window() method for information on the expected and permitted values for each property.
	 * @return string Returns a string produced by the window() method
	 * @see window()
	 */	
	public function awindow($arrayOptions) {
		return $this->window($arrayOptions['title'], $arrayOptions['content'], $arrayOptions['windowid'], $arrayOptions['winwidth'], $arrayOptions['winheight'], $arrayOptions['decoration'], $arrayOptions['zindex'], $arrayOptions['destroyonclose'], $arrayOptions['recenterauto'], $arrayOptions['toppos'], $arrayOptions['leftpos'], $arrayOptions['usetags'], $arrayOptions['windowtype'], $arrayOptions['isresizable'], $arrayOptions['iscloseable'], $arrayOptions['isminimizable'], $arrayOptions['ismaximizable'], $arrayOptions['isdraggable']);
	}

	/**
	 * openwin() Method
	 * 
	 * Provides a single line javascript/HTML code used to open the application specified in $appToOpen.  All data is pulled from the applications config.php file
	 * @param string $appToOpen The application you wish to load.  The suffix should always end with a trailing slash.
	 * @param string $caption The caption used for the window title if no config file is found.
	 * @param integer $defaultx The width of the window if no config file is found.  Defaults to 385px.
	 * @param integer $defaulty The height of the window if no config file is found.  Defaults to 425px.
	 * @param string $specifyConfigFile If you need to load a config.php file from a specific location, use this.  This is useful if you're application is not the default view/logic file (index.php)
	 */	
	public function openwin($appToOpen, $caption="Application ", $defaultx=385, $defaulty=425, $specifyConfigFile=NULL) {
		global $localpath, $homedir, $_p;
		if($specifyConfigFile!=NULL) {
			$configLocation = $specifyConfigFile;
		} else {
			$configLocation = $localpath . "{$_p}applications{$_p}". $appToOpen . 'config.php';
		}
		if(file_exists($configLocation)) { // Let's try and pull information about the app from the config file
			include($localpath . "{$_p}applications{$_p}". $appToOpen . 'config.php');
			$app['applicationname'] = $applicationname;
			$app['applicationicon'] = $applicationicon;
			$app['applicationicon16'] = $applicationicon16;
			$app['applicationmenuname'] = $applicationmenuname;
			$app['applicationdescription'] = $applicationdescription;
			$app['displayonmenu'] = $displayonmenu;
			if(isset($applicationx) && isset($applicationy)) {
				$app['windowx'] = $applicationx;
				$app['windowy'] = $applicationy;
				unset($applicationx);
				unset($applicationy);						
			} else {
				$app['windowx'] = $defaultx;
				$app['windowy'] = $defaulty;						
			}
			if(isset($destroyonclose)) {
				$app['destroyonclose'] = $destroyonclose;
			} else {
				$app['destroyonclose'] = 'true';
			}
		} else { // If there was no config file, lets use defaults
			$app['applicationname'] = $appToOpen;
			$app['applicationicon'] = '';
			$app['applicationicon16'] = '';
			$app['applicationmenuname'] = $caption;
			$app['applicationdescription'] = '';
			$app['displayonmenu'] = '';
			$app['windowx'] = $defaultx;
			$app['windowy'] = $defaulty;
			$app['destroyonclose'] = 'true';
		}				
		
		if(!file_exists($localpath . "{$_p}applications{$_p}". $appToOpen)) {
			return false;	
		} else {
			return $this->window('<img src=\\\''.$app['applicationicon16'].'\\\' alt=\\\'\\\' /> '.$app['applicationmenuname'], $homedir.'/'.$app['applicationname'], $app['applicationname'], $app['windowx'], $app['windowy'], NULL, 5000, $app['destroyonclose'], 'false', NULL, NULL, 'false');
		}	
	}
	
	
	/**
	 * 
	 */
	public function widget($toload, $subwidget='index.php') {
		global $localpath;
		if(!file_exists($localpath . '\widget\\'. $toload .'\\'.$subwidget)) {
			return false;	
		} else {
			include($localpath . '\widget\\'. $toload .'\\'.$subwidget);
			return true;
		}		
	}
	
	
	/**
	 * login() method
	 * 
	 * Displays a login window.
	 * @return string Returns a string containing the javascript necessary to show a login window.
	 */
	public function login() {
		global $homedir;
		$loginWindowOptions = array (
			'title' => 'Login',
			'content' => $homedir.'/login/admin',
			'windowid' => 'login',
			'winwidth' => '300',
			'winheight' => '200',
			'decoration' => NULL,
			'zindex' => '500',
			'destroyonclose' => 'true',
			'recenterauto' => 'true',
			'toppos' => NULL,
			'leftpos' => NULL,
			'usetags' => 'true',
			'windowtype' => 'window', 
			'isresizable' => 'false', 
			'iscloseable' => 'false', 
			'isminimizable' => 'false', 
			'ismaximizable' => 'false', 
			'isdraggable' => 'true', 
		);

		return $this->awindow($loginWindowOptions);	
	}
	
	/**
	 * tablekit() Method
	 * 
	 * PHP wrapper for the javascript, Prototype based TableKit library which "implements row striping, column sorting, column resizing and cell editing using Ajax"
	 * <pre>
	 * $body_output .= $view->table('sortable resizable editable', $table_insides);
	 * $body_output .= $view->tablekit();
	 * </pre>
	 * 
	 * @access public
	 * @param array $options Configure the table
	 * @see http://www.millstream.com.au/upload/code/tablekit/
	 * @see table()
	 * @todo Add the options array
	 */
	public function tablekit($options=NULL) {
		global $body_output;
		global $headtop_output;
		global $headbottom_output;
				
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/prototype/prototype.js');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/fastinit/fastinit.js');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/tablekit/tablekit-demo/js/tablekit.js');
	}
	
	/**
	 * table() Method
	 * 
	 * Creates a table, compatible with the tablekit() method
	 * <pre>
	 * $body_output .= $view->table('sortable resizable editable', $table_insides);
	 * </pre>
	 * 
	 * @access public
	 * @param string $class Defines the class of the table.  If using this with tablekit(), use the space seperated class names: sortable, resizable, or editable, to use those tablekit methods
	 * @param string $values the rest of the HTML for the table
	 * @return string 
	 * @see tablekit()
	 */
	public function table($class, $values) {
		$output = '<table class="'.$class.'">';
		$output .= $values;
		$output .= '</table>';
		return $output;
	}

	/**
	 * draggable() Method
	 * 
	 * Takes or creates a DIV and makes it draggable.  Example usage:
	 * <pre>
	 * loadclass('view');
	 * $view = new view();
	 * $body_output .= $view->draggable('<img src="'.$homedir.'data/icons/32x32_MomentumIcons/star.png" alt="" />', NULL, NULL, NULL, 'star');
	 * </pre>
	 * 
	 * The resulting page would allow you to drag around the star.png image inside a newly created DIV with the ID star.
	 * 
	 * @access public
	 * @param string $content This is the content of the DIV.  If you are using a pre-existing DIV, set this to NULL
	 * @param string $id The ID of a pre-existing element to make draggable.  Set this to NULL to create a new DIV
	 * @param string $class The CSS class you wish to assign to created DIV (does not apply if $id was populated)
	 * @param string $style The inline CSS to insert into the DIV tag (does not apply if $id was populated)
	 * @param string $forceid The ID you would like to assign to the created DIV (does not apply if $id was populated)
	 * @return string Returns a string
	 */
	
	public function draggable($content=NULL, $id=NULL, $class=NULL, $style=NULL, $forceid=NULL) {
		global $headbottom_output, $homedir;
		
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/prototype/prototype.js');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/script.aculo.us/src/effects.js', ' defer="defer"');			
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/script.aculo.us/src/dragdrop.js', ' defer="defer"');

		$output = NULL;
		if ($id==NULL) {
			if($forceid==NULL) {
				$id = 'drag' . rand(0, 99999);
			} else {
				$id = $forceid;
			}
			$classinsert = NULL;
			$styleinsert = NULL;
			if($class!=NULL) {
				$classinsert = ' class="'.$class.'"';	
			}
			if($style!=NULL) {
				$styleinsert = ' style="'.$style.'"';	
			}			
			$output .= '<div id="'.$id.'"'.$classinsert.$styleinsert.'>'.$content.'</div>';
		}
		
		$output .= $this->jscompress('
			Draggables.addObserver({ 
			    onStart: function(eventName, draggable) {   
			      document.body.appendChild(draggable.element)
			    }
			});		
		
			new Draggable(\''.$id.'\');
		', ' defer="defer"');	

		$output .= $this->debug('New draggable created: '.$id);
	
		return $output;
	}
	
	/**
	 * droppable() Method
	 * 
	 * Takes a pre-existing element and makes it a droppable.  Example usage:
	 * <pre>
	 * loadclass('view');
	 * $view = new view();
	 * $body_output .= $view->draggable('<img src="'.$homedir.'data/icons/32x32_MomentumIcons/star.png" alt="" />', NULL, NULL, NULL, 'star');
	 * $body_output .= '<div id="the_id" style="width:100px;height:100px;min-width:100px;min-height:100px;border:1px solid #000000;">Drop stuff here.</div>';
	 * $body_output .= $view->droppable('the_id'); // Makes the element with the id "the_id" a droppable area.  Items that are draggable may be dropped here.
	 * </pre>
	 * 
	 * @access public
	 * @param string $id The ID of a pre-existing element to make droppable.  
	 * @param string $options Javascript options to configure the droppable() 
	 * @return string Returns a string
	 */
	public function droppable($id, $options=NULL) {
		global $headbottom_output, $homedir;
		
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/prototype/prototype.js');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/script.aculo.us/src/effects.js', ' defer="defer"');			
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/script.aculo.us/src/dragdrop.js', ' defer="defer"');		
		
		$output = NULL;
		if($options!=NULL) {
			$options = ', '. $options;	
		}
		$output .= $this->jscompress("
			Droppables.add('$id'$options);
		", ' defer="defer"');
			
		return $output;
	}
	
	/**
	 * tabs() Method
	 * 
	 * @access public
	 * @param string $id The ID of a pre-existing list to make into tabs 
	 * @return string Returns a string  
	 */
	public function tabs($id) {
		global $headbottom_output, $homedir;
		
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/prototype/prototype.js');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/livepipe/src/livepipe.js', ' defer="defer"');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/livepipe/src/tabs.js', ' defer="defer"');	
		
		$output = NULL;
		$output .= $this->jscompress("
			new Control.Tabs('$id');  		
		", ' defer="defer"');
		
		return $output;
	}
	
	
	/**
	 * contextmenu() Method
	 * 
	 * @access public
	 * @param string $id The ID of a pre-existing element to make it have a context menu.  
	 * @param array $menuitems An array of Javascript options to configure the contextmenu() method
	 * @return string Returns a string
	 */
	public function contextmenu($id, $menuitems=NULL) {
		global $headbottom_output, $homedir;
		
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/prototype/prototype.js');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/livepipe/src/livepipe.js', ' defer="defer"');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/livepipe/src/contextmenu.js', ' defer="defer"');
		$output = NULL;

		// The dom:loaded stuff is to allow compatiblity with Internet Explorer
		$output .= '	
		document.observe("dom:loaded", function () {
		var context_menu_'.$id.' = new Control.ContextMenu(\''.$id.'\');  
		';
		
		if(is_array($menuitems)) {
			foreach($menuitems as $menuitem) {
				$output .= '
				context_menu_'.$id.'.addItem({  
						'.$menuitem.'
				});  
				';	
			}
		}
		
		$output .= '});';
		return $this->jscompress($output, ' defer="defer"');
	}
	
	/**
	 * hotkey() Method
	 * 
	 * @access public
	 * @param string $letter The letter you wish to detect as a hotkey.  If you wish to require the use of shift, alt, and/or cntrl, use the $modifier parameter
	 * @param string $action The javascript you would like to execute when the hotkey is pressed
	 * @param string $element The element you wish to target.  If none specified the target will be the body.
	 * @param string $modifier Additional configuration options for hotkey.js 
	 */
	public function hotkey($letter, $action='', $elementid='body', $modifier=NULL) {
		global $headbottom_output, $homedir;
		
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/prototype/prototype.js');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/livepipe/src/livepipe.js', ' defer="defer"');
		$headbottom_output .= $this->dependancy('./libraries/3rdparty/livepipe/src/hotkey.js', ' defer="defer"');
		$output = NULL;
				
		$output .= '		
		new HotKey("'.$letter.'",function(event){
			'.$action.'  
			top.debug("Hotkey: '.$letter.' modifiers: '.$modifier.'pressed.");  
		},{  
			Element:'.$elementid.',
			'.$modifier.'
		});
		';
	}
	
	/**
	 * mainmenu() Method - Deprecated.  Terrible code
	 * 
	 * The mainmenu() method creates a menu, similar to a desktop style main menus which typically have "File Edit Help" menus, etc.  Example usage:
	 * <pre>
	 * $optionsArray[0] = array (
	 * 	'title' => 'File',
	 * 	'subtitle' => array (
	 * 		0 => array (
	 * 			'submenu' => 'New folder',
	 * 			'href' => '#',
	 * 			'onclick' => 'new_folder();',
	 * 			'icon' => './data/jpg/new_folder.jpg'
	 * 			),
	 * 		1 => array (
	 * 			'submenu' => 'New blank file',
	 * 			'href' => '#',
	 * 			'onclick' => 'new_file();',
	 * 			'icon' => './data/jpg/new_file.jpg'
	 * 			),
	 * 		2 => array (
	 * 			'submenu' => 'Exit',
	 * 			'href' => '#',
	 * 			'onclick' => 'window.parent.Window.close(\'filebrowser\');',
	 * 			'icon' => './data/jpg/exit.jpg'
	 * 			),
	 * 		),		
	 * );
	 * </pre>
	 *  
	 * @deprecated 
	 * @access public  
	 * @param array $optionsArray  
	 * @return void
	 */
	public function mainmenu($optionsArray) {
		global $homedir;
		global $body_output;
		global $bodymarkup;
		global $headtop_output;
		global $headbottom_output;
		global $mainmenuhistory;

		if ($mainmenuhistory==NULL) {
			$headtop_output .= '
			<style type="text/css">
				.menuholder {
					width:100%;
					color: #000000;
					display: block;
					position: relative;
					z-index:100;
				}
			
				.menu {
					position:fixed;
					top:0;
					left:0;
					width:100%;
					font-size:10px;
					color:#000000;
					z-index:100;
				}
				
				/* Navigation */
				#nav, #nav ul {
					list-style: none;
					margin: 0;
					padding: 0; 
				}
			
				#nav {
					font-family: Verdana, Arial, Helvetica, sans-serif;
					z-index: 100;
					position: relative;
				}
				
				#nav li {
					background: url(\''.$homedir.'/libraries/3rdparty/mainmenu/menu_back.jpg\') top left repeat-x;			
					border-bottom:1px #DDDDDD solid;
					float: left;
					margin: 0;
					padding: 0;
					position: relative;
					z-index:100;
				}
				
				#nav li a, #nav li a:link, #nav li a:active, #nav li a:visited {
					font: 12px Verdana, Arial, Helvetica, sans-serif;
					height:19px;
					color: #000000;
					display: block;
					padding: 0 9px;
					text-decoration: none;
					position:relative;
					z-index: 101;
					
				}
			
				#nav li a:hover {
					background: #7eb3e2;
					color: #000;	
				}
				
		
				#nav ul {
					background: #EEEEEE;
					background-image:none;
					border-bottom: 1px solid #000;
					list-style: none;
					margin: 0;
					position: absolute;
					top: -999em;
					left: -1px;
					font-size:10px;
				}
				
				#nav li:hover ul,	#nav li.sfHover ul {
					top: 19px;
				}
				
				#nav ul li {
					border: 0;
					float: none;
				}
				
				#nav ul a {
					border: 0px solid #000;
					border-bottom: 0;
					padding-right: 20px;
					width: 140px;
					white-space: nowrap;
					position:relative;
					z-index:100;		
				}
				
				#nav ul a:hover {
					background: #2f6499;
					color: #000;
				}			
			</style>
			';

			$headbottom_output .= $this->dependancy('./libraries/3rdparty/mainmenu/mainmenu.js');

			$mainmenuhistory = true; // When we set $mainmenuhistory to true, we stop ourselves from reloading the same stuff in the header.
		}

		$body_output .= '
		<div class="menuholder">
		<ul id="nav">
		';


		foreach($optionsArray as $menuitem) {
			$body_output .= '
				<li class="mainmenuli">';
			$body_output .= '
					<div><a href="">'.$menuitem['title'].'</a></div>
					<ul>';
			foreach($menuitem['subtitle'] as $submenu) {
				$body_output .= '<li class="mainmenusub"><a href="'.$submenu['href'].'" onclick="'.$submenu['onclick'].'">'.$submenu['submenu'].'</a></li>';
			}
			$body_output .= '</ul>';
			$body_output .= '
				</li>';
		}

		$body_output .= '
		</ul>
		</div>
		<script type="text/javascript"><!--//--><![CDATA[//><!--
			top.debug("MainMenu created.");
		//--><!]]></script>
		';

	}

}

?>
Return current item: GroundOS