PageSourceSearch

https://www.cinezoom.it/js/cz-mocha.js

js cinezoom.it collected 2026-10-10 00:58:41 UTC 134,260 bytes, 4,593 lines download raw bytes

1/* 
2
3Script: Core.js
4	MochaUI - A Web Applications User Interface Framework.
5
6Copyright:
7	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.
8
9License:
10	MIT-style license.
11
12Contributors:
13	- Scott F. Frederick
14	- Joel Lindau
15
16Note:
17	This documentation is taken directly from the javascript source files. It is built using Natural Docs.
18
19Todo:
20	Consider making title tooltips optional and using them more often.
21
22*/
23
24var MochaUI = new Hash({
25	options: new Hash({
26		useEffects: true  // Toggles the majority of window fade and move effects.
27	}),
28	Columns: {
29		instances:      new Hash()
30	},
31	Panels: {
32		instances:      new Hash()
33	},		
34	Windows: {	  
35		instances:      new Hash(),
36		indexLevel:     100,          // Used for z-Index
37		windowIDCount:  0,	          // Used for windows without an ID defined by the user
38		windowsVisible: true          // Ctrl-Alt-Q to toggle window visibility
39	},	
40	ieSupport:  'excanvas',   // Makes it easier to switch between Excanvas and Moocanvas for testing
41	focusingWindow: 'false',
42	/*
43	
44	Function: updateContent
45		Replace the content of a window or panel.
46		
47	Arguments:
48		element - The parent window or panel.
49		childElement - The child element of the window or panel recieving the content.
50		title - (string) Change this if you want to change the title of the window or panel.
51		content - (string or element) An html loadMethod option.
52		loadMethod - ('html', 'xhr', or 'iframe') Defaults to 'html'.
53		url - Used if loadMethod is set to 'xhr' or 'iframe'.
54		padding - (object)
55
56	*/	
57	updateContent: function(updateOptions){
58
59		var options = {
60			'element':      null,
61			'childElement': null,
62			'title':        null,
63			'content':      null,
64			'loadMethod':   null,
65			'url':          null,
66			'padding':      null
67		};
68		$extend(options, updateOptions);
69
70		if (!options.element) return;
71		var element = options.element;
72
73		if (MochaUI.Windows.instances.get(element.id)) {
74			var recipient = 'window';
75			var currentInstance = MochaUI.Windows.instances.get(element.id);
76			var spinnerEl = currentInstance.spinnerEl;
77			if (options.title) {
78				currentInstance.titleEl.set('html', options.title);
79			}
80		}
81		else {
82			var recipient = 'panel';
83			var currentInstance = MochaUI.Panels.instances.get(element.id);
84			if (options.title) {
85				currentInstance.titleEl.set('html', options.title);
86			}
87		}
88
89		var contentEl = currentInstance.contentEl;
90		if (options.childElement != null) {
91			var contentContainer = options.childElement;
92		}
93		else {
94			var contentContainer = currentInstance.contentEl;
95		}
96		
97		var loadMethod = options.loadMethod != null ? options.loadMethod : currentInstance.options.loadMethod;
98		
99		// Set scrollbars if loading content in main content container.
100		// Always use 'hidden' for iframe windows
101		if (contentContainer == currentInstance.contentEl) {
102			currentInstance.contentWrapperEl.setStyles({
103				'overflow': currentInstance.options.scrollbars == true && loadMethod != 'iframe' ? 'auto' : 'hidden'
104			});
105		}
106
107		var contentWrapperEl = currentInstance.contentWrapperEl;
108		
109		if (options.padding != null) {
110			contentEl.setStyles({
111				'padding-top': options.padding.top,
112				'padding-bottom': options.padding.bottom,
113				'padding-left': options.padding.left,
114				'padding-right': options.padding.right
115			});
116		}
117
118		// Remove old content.
119		if (contentContainer == contentEl){
120			contentEl.empty();
121		}
122
123		// Load new content.
124		switch(loadMethod){
125			case 'xhr':
126				new Request.HTML({
127					url: options.url,
128					update: contentContainer,
129					evalScripts: currentInstance.options.evalScripts,
130					evalResponse: currentInstance.options.evalResponse,
131					onRequest: function(){
132						if (recipient == 'window' && contentContainer == contentEl){
133							currentInstance.showSpinner(spinnerEl);
134						}
135						else if (recipient == 'panel' && contentContainer == contentEl && $('spinner')){
136							$('spinner').setStyle('visibility','visible');	
137						}
138					}.bind(this),
139					onFailure: function(){
140						if (contentContainer == contentEl){
141							contentContainer.set('html','<p><strong>Error Loading XMLHttpRequest</strong></p>');
142							if (recipient == 'window') {
143								currentInstance.hideSpinner(spinnerEl);
144							}
145							else if (recipient == 'panel' && $('spinner')) {
146								$('spinner').setStyle('visibility', 'hidden');
147							}
148						}
149					}.bind(this),
150					onException: function(){}.bind(this),
151					onSuccess: function(){
152						if (contentContainer == contentEl){
153							if (recipient == 'window'){
154								currentInstance.hideSpinner(spinnerEl);
155							}
156							else if (recipient == 'panel' && $('spinner')){
157								$('spinner').setStyle('visibility', 'hidden');
158							}
159							currentInstance.fireEvent('onContentLoaded', element);
160						}
161					}.bind(this),
162					onComplete: function(){}.bind(this)
163				}).get();
164				break;
165			case 'iframe': // May be able to streamline this if the iframe already exists.
166				if ( currentInstance.options.contentURL == '' || contentContainer != contentEl) {
167					break;
168				}
169				currentInstance.iframeEl = new Element('iframe', {
170					'id': currentInstance.options.id + '_iframe',
171					'name':  currentInstance.options.id + '_iframe',
172					'class': 'mochaIframe',
173					'src': options.url,
174					'marginwidth':  0,
175					'marginheight': 0,
176					'frameBorder':  0,
177					'scrolling':    'auto',
178					'styles': {
179						'height': contentWrapperEl.offsetHeight - contentWrapperEl.getStyle('border-top').toInt() - contentWrapperEl.getStyle('border-bottom').toInt(),
180						'width': currentInstance.panelEl ? contentWrapperEl.offsetWidth - contentWrapperEl.getStyle('border-left').toInt() - contentWrapperEl.getStyle('border-right').toInt() : '100%'	
181					}
182				}).injectInside(contentEl);
183
184				// Add onload event to iframe so we can hide the spinner and run onContentLoaded()
185				currentInstance.iframeEl.addEvent('load', function(e) {
186					if (recipient == 'window') {
187						currentInstance.hideSpinner(spinnerEl);
188					}
189					else if (recipient == 'panel' && contentContainer == contentEl && $('spinner')) {
190						$('spinner').setStyle('visibility', 'hidden');
191					}
192					currentInstance.fireEvent('onContentLoaded', element);
193				}.bind(this));
194				if (recipient == 'window') {
195					currentInstance.showSpinner(spinnerEl);
196				}
197				else if (recipient == 'panel' && contentContainer == contentEl && $('spinner')){
198					$('spinner').setStyle('visibility', 'visible');	
199				}
200				break;
201			case 'html':
202			default:
203				// Need to test injecting elements as content.
204				var elementTypes = new Array('element', 'textnode', 'whitespace', 'collection');
205				if (elementTypes.contains($type(options.content))){
206					options.content.inject(contentContainer);
207				} else {
208					contentContainer.set('html', options.content);
209				}
210				currentInstance.fireEvent('onContentLoaded', element);
211				break;
212		}
213
214	},
215	/*
216	
217	Function: reloadIframe
218		Reload an iframe. Fixes an issue in Firefox when trying to use location.reload on an iframe that has been destroyed and recreated.
219
220	Arguments:
221		iframe - This should be both the name and the id of the iframe.
222
223	Syntax:
224		(start code)
225		MochaUI.reloadIframe(element);
226		(end)
227
228	Example:
229		To reload an iframe from within another iframe:
230		(start code)
231		parent.MochaUI.reloadIframe('myIframeName');
232		(end)
233
234	*/
235	reloadIframe: function(iframe){
236		if (Browser.Engine.gecko) {
237			$(iframe).src = $(iframe).src;
238		}
239		else {
240			top.frames[iframe].location.reload(true);
241		}
242	},
243	collapseToggle: function(windowEl){
244		var instances = MochaUI.Windows.instances;
245		var currentInstance = instances.get(windowEl.id);
246		var handles = currentInstance.windowEl.getElements('.handle');
247		if (currentInstance.isMaximized == true) return;		
248		if (currentInstance.isCollapsed == false) {
249			currentInstance.isCollapsed = true;
250			handles.setStyle('display', 'none');
251			if ( currentInstance.iframeEl ) {
252				currentInstance.iframeEl.setStyle('visibility', 'hidden');
253			}
254			currentInstance.contentBorderEl.setStyles({
255				visibility: 'hidden',
256				position: 'absolute',
257				top: -10000,
258				left: -10000
259			});
260			if(currentInstance.toolbarWrapperEl){
261				currentInstance.toolbarWrapperEl.setStyles({
262					visibility: 'hidden',
263					position: 'absolute',
264					top: -10000,
265					left: -10000
266				});
267			}
268			currentInstance.drawWindowCollapsed(windowEl);
269		}
270		else {
271			currentInstance.isCollapsed = false;
272			currentInstance.drawWindow(windowEl);
273			currentInstance.contentBorderEl.setStyles({
274				visibility: 'visible',
275				position: null,
276				top: null,
277				left: null
278			});
279			if(currentInstance.toolbarWrapperEl){
280				currentInstance.toolbarWrapperEl.setStyles({
281					visibility: 'visible',
282					position: null,
283					top: null,
284					left: null
285				});
286			}
287			if ( currentInstance.iframeEl ) {
288				currentInstance.iframeEl.setStyle('visibility', 'visible');
289			}
290			handles.setStyle('display', 'block');
291		}
292	},
293	/*
294
295	Function: closeWindow
296		Closes a window.
297
298	Syntax:
299	(start code)
300		MochaUI.closeWindow();
301	(end)
302
303	Arguments: 
304		windowEl - the ID of the window to be closed
305
306	Returns:
307		true - the window was closed
308		false - the window was not closed
309
310	*/
311	closeWindow: function(windowEl){
312		// Does window exist and is not already in process of closing ?
313
314		var instances = MochaUI.Windows.instances;
315		var currentInstance = instances.get(windowEl.id);
316		if (windowEl != $(windowEl) || currentInstance.isClosing) return;
317			
318		currentInstance.isClosing = true;
319		currentInstance.fireEvent('onClose', windowEl);
320		if (currentInstance.check) currentInstance.check.destroy();
321
322		if ((currentInstance.options.type == 'modal' || currentInstance.options.type == 'modal2') && Browser.Engine.trident4){
323				$('modalFix').setStyle('display', 'none');
324		}
325
326		if (MochaUI.options.useEffects == false){
327			if (currentInstance.options.type == 'modal' || currentInstance.options.type == 'modal2'){
328				$('modalOverlay').setStyle('opacity', 0);
329			}
330			MochaUI.closingJobs(windowEl);
331			return true;	
332		}
333		else {
334			// Redraws IE windows without shadows since IE messes up canvas alpha when you change element opacity
335			if (Browser.Engine.trident) currentInstance.drawWindow(windowEl, false);
336			if (currentInstance.options.type == 'modal' || currentInstance.options.type == 'modal2'){
337				MochaUI.Modal.modalOverlayCloseMorph.start({
338					'opacity': 0
339				});
340			}
341			var closeMorph = new Fx.Morph(windowEl, {
342				duration: 120,
343				onComplete: function(){
344					MochaUI.closingJobs(windowEl);
345					return true;
346				}.bind(this)
347			});
348			closeMorph.start({
349				'opacity': .4
350			});
351		}
352
353	},
354	closingJobs: function(windowEl){
355
356		var instances = MochaUI.Windows.instances;
357		var currentInstance = instances.get(windowEl.id);
358		windowEl.setStyle('visibility', 'hidden');
359		windowEl.destroy();
360		currentInstance.fireEvent('onCloseComplete');
361		
362		if (currentInstance.options.type != 'notification'){
363			var newFocus = this.getWindowWithHighestZindex();
364			this.focusWindow(newFocus);
365		}
366
367		instances.erase(currentInstance.options.id);
368		if (this.loadingWorkspace == true) {
369			this.windowUnload();
370		}
371
372		if (MochaUI.Dock && $(MochaUI.options.dock) && currentInstance.options.type == 'window') {
373			var currentButton = $(currentInstance.options.id + '_dockTab');
374			if (currentButton != null) {
375				MochaUI.Dock.dockSortables.removeItems(currentButton).destroy();
376			}
377			// Need to resize everything in case the dock becomes smaller when a tab is removed
378			MochaUI.Desktop.setDesktopSize();
379		}
380	},
381	/*
382	
383	Function: closeAll	
384		Close all open windows.
385
386	*/
387	closeAll: function() {		
388		$$('div.mocha').each(function(windowEl){
389			this.closeWindow(windowEl);
390		}.bind(this));
391	},
392	/*
393
394	Function: toggleWindowVisibility
395		Toggle window visibility with Ctrl-Alt-Q.
396
397	*/	
398	toggleWindowVisibility: function(){
399		MochaUI.Windows.instances.each(function(instance){
400			if (instance.options.type == 'modal' || instance.options.type == 'modal2' || instance.isMinimized == true) return;									
401			var id = $(instance.options.id);
402			if (id.getStyle('visibility') == 'visible'){
403				if (instance.iframe){
404					instance.iframeEl.setStyle('visibility', 'hidden');
405				}
406				if (instance.toolbarEl){
407					instance.toolbarWrapperEl.setStyle('visibility', 'hidden');
408				}
409				instance.contentBorderEl.setStyle('visibility', 'hidden');
410
411				id.setStyle('visibility', 'hidden');
412				MochaUI.Windows.windowsVisible = false;
413			}
414			else {
415				id.setStyle('visibility', 'visible');
416				instance.contentBorderEl.setStyle('visibility', 'visible');
417				if (instance.iframe){
418					instance.iframeEl.setStyle('visibility', 'visible');
419				}
420				if (instance.toolbarEl){
421					instance.toolbarWrapperEl.setStyle('visibility', 'visible');
422				}
423				MochaUI.Windows.windowsVisible = true;
424			}
425		}.bind(this));
426
427	},
428	focusWindow: function(windowEl, fireEvent){
429
430		// This is used with blurAll
431		MochaUI.focusingWindow = 'true';
432		var windowClicked = function(){
433			MochaUI.focusingWindow = 'false';
434		};		
435		windowClicked.delay(170, this);
436
437		// Only focus when needed
438		if ($$('.mocha').length == 0) return;
439		if (windowEl != $(windowEl) || windowEl.hasClass('isFocused')) return;
440
441		var instances =  MochaUI.Windows.instances;
442		var currentInstance = instances.get(windowEl.id);
443	
444		if (currentInstance.options.type == 'notification') return;
445
446		MochaUI.Windows.indexLevel += 2;
447		windowEl.setStyle('zIndex', MochaUI.Windows.indexLevel);
448
449		// Used when dragging and resizing windows
450		$('windowUnderlay').setStyle('zIndex', MochaUI.Windows.indexLevel - 1).inject($(windowEl),'after');
451
452		// Fire onBlur for the window that lost focus.
453		instances.each(function(instance){
454			if (instance.windowEl.hasClass('isFocused')){
455				instance.fireEvent('onBlur', instance.windowEl);
456			}
457			instance.windowEl.removeClass('isFocused');
458		});
459
460		if (MochaUI.Dock && $(MochaUI.options.dock) && currentInstance.options.type == 'window') {
461			MochaUI.Dock.makeActiveTab();
462		}
463		currentInstance.windowEl.addClass('isFocused');
464
465		if (fireEvent != false){
466			currentInstance.fireEvent('onFocus', windowEl);
467		}
468
469	},
470	getWindowWithHighestZindex: function(){
471		this.highestZindex = 0;
472		$$('div.mocha').each(function(element){
473			this.zIndex = element.getStyle('zIndex');
474			if (this.zIndex >= this.highestZindex) {
475				this.highestZindex = this.zIndex;
476			}	
477		}.bind(this));
478		$$('div.mocha').each(function(element){
479			if (element.getStyle('zIndex') == this.highestZindex) {
480				this.windowWithHighestZindex = element;
481			}
482		}.bind(this));
483		return this.windowWithHighestZindex;
484	},
485	blurAll: function(){
486		if (MochaUI.focusingWindow == 'false') {
487			$$('.mocha').each(function(windowEl){
488				var instances =  MochaUI.Windows.instances;
489				var currentInstance = instances.get(windowEl.id);
490				if (currentInstance.options.type != 'modal' && currentInstance.options.type != 'modal2'){
491					windowEl.removeClass('isFocused');
492				}
493			});
494			$$('div.dockTab').removeClass('activeDockTab');
495		}
496	},
497	roundedRect: function(ctx, x, y, width, height, radius, rgb, a){
498		ctx.fillStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
499		ctx.beginPath();
500		ctx.moveTo(x, y + radius);
501		ctx.lineTo(x, y + height - radius);
502		ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
503		ctx.lineTo(x + width - radius, y + height);
504		ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
505		ctx.lineTo(x + width, y + radius);
506		ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
507		ctx.lineTo(x + radius, y);
508		ctx.quadraticCurveTo(x, y, x, y + radius);
509		ctx.fill(); 
510	},
511	triangle: function(ctx, x, y, width, height, rgb, a){
512		ctx.beginPath();
513		ctx.moveTo(x + width, y);
514		ctx.lineTo(x, y + height);
515		ctx.lineTo(x + width, y + height);
516		ctx.closePath();
517		ctx.fillStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
518		ctx.fill();
519	},
520	circle: function(ctx, x, y, diameter, rgb, a){
521		ctx.beginPath();
522		ctx.moveTo(x, y);
523		ctx.arc(x, y, diameter, 0, Math.PI*2, true);
524		ctx.fillStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
525		ctx.fill();
526	},
527	/*
528
529	Function: centerWindow
530		Center a window in it's container. If windowEl is undefined it will center the window that has focus.
531
532	*/
533	centerWindow: function(windowEl){
534		
535		if(!windowEl){
536			MochaUI.Windows.instances.each(function(instance){
537				if (instance.windowEl.hasClass('isFocused')){
538					windowEl = instance.windowEl;
539				}
540			});
541		}
542
543		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
544		var options = currentInstance.options;
545		var dimensions = options.container.getCoordinates();
546		var windowPosTop = (dimensions.height * .5) - ((options.height + currentInstance.headerFooterShadow) * .5);
547		if (windowPosTop < 0) {
548			windowPosTop = 0;
549		}
550		var windowPosLeft =	(dimensions.width * .5) - (options.width * .5);
551		if (windowPosLeft < 0) {
552			windowPosLeft = 0;
553		}
554		if (MochaUI.options.useEffects == true){
555			currentInstance.morph.start({
556				'top': windowPosTop,
557				'left': windowPosLeft
558			});
559		}
560		else {
561			windowEl.setStyles({
562				'top': windowPosTop,
563				'left': windowPosLeft
564			});
565		}
566	},
567	notification: function(message){
568			new MochaUI.Window({
569				loadMethod: 'html',
570				closeAfter: 1500,
571				type: 'notification',
572				addClass: 'notification',
573				content: message,
574				width: 220,
575				height: 40,
576				y: 53,
577				padding:  { top: 10, right: 12, bottom: 10, left: 12 },
578				shadowBlur: 5,
579				bodyBgColor: [255, 255, 255]	
580			});
581	},
582	/*
583
584	Function: dynamicResize
585		Use with a timer to resize a window as the window's content size changes, such as with an accordian.
586
587	*/
588	dynamicResize: function(windowEl){
589		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
590		var contentWrapperEl = currentInstance.contentWrapperEl;
591		var contentEl = currentInstance.contentEl;
592		
593		contentWrapperEl.setStyle('height', contentEl.offsetHeight);
594		contentWrapperEl.setStyle('width', contentEl.offsetWidth);			
595		currentInstance.drawWindow(windowEl);
596	},	
597	/*
598
599	Function: garbageCleanUp
600		Empties all windows of their children, and removes and garbages the windows. It is does not trigger onClose() or onCloseComplete(). This is useful to clear memory before the pageUnload.
601
602	Syntax:
603	(start code)
604		MochaUI.garbageCleanUp();
605	(end)
606	
607	*/
608	garbageCleanUp: function(){
609		$$('div.mocha').each(function(el){
610			el.destroy();
611		}.bind(this));
612	},
613	/*
614	
615	The underlay is inserted directly under windows when they are being dragged or resized
616	so that the cursor is not captured by iframes or other plugins (such as Flash)
617	underneath the window.
618	
619	*/
620	underlayInitialize: function(){
621		var windowUnderlay = new Element('div', {
622			'id': 'windowUnderlay',
623			'styles': {
624				'height': parent.getCoordinates().height,
625				'opacity': .01,
626				'display': 'none'
627			}
628		}).inject(document.body);
629	},
630	setUnderlaySize: function(){
631		$('windowUnderlay').setStyle('height', parent.getCoordinates().height);
632	}
633});
634
635/* 
636
637function: fixPNG
638	Bob Osola's PngFix for IE6.
639
640example:
641	(begin code)
642	<img src="xyz.png" alt="foo" width="10" height="20" onload="fixPNG(this)">
643	(end)
644
645note:
646	You must have the image height and width attributes specified in the markup.
647
648*/
649
650function fixPNG(myImage){
651	if (Browser.Engine.trident4 && document.body.filters){
652		var imgID = (myImage.id) ? "id='" + myImage.id + "' " : "";
653		var imgClass = (myImage.className) ? "class='" + myImage.className + "' " : "";
654		var imgTitle = (myImage.title) ? "title='" + myImage.title  + "' " : "title='" + myImage.alt + "' ";
655		var imgStyle = "display:inline-block;" + myImage.style.cssText;
656		var strNewHTML = "<span " + imgID + imgClass + imgTitle
657			+ " style=\"" + "width:" + myImage.width
658			+ "px; height:" + myImage.height
659			+ "px;" + imgStyle + ";"
660			+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
661			+ "(src=\'" + myImage.src + "\', sizingMethod='scale');\"></span>";
662		myImage.outerHTML = strNewHTML;		
663	}
664}
665
666// Toggle window visibility with Ctrl-Alt-Q
667document.addEvent('keydown', function(event){
668	if (event.key == 'q' && event.control && event.alt) {
669		MochaUI.toggleWindowVisibility();
670	}
671});
672
673// Blur all windows if user clicks anywhere else on the page
674document.addEvent('mousedown', function(event){
675	MochaUI.blurAll.delay(50);
676});
677
678window.addEvent('domready', function(){
679	MochaUI.underlayInitialize();
680});
681
682window.addEvent('resize', function(){
683		MochaUI.setUnderlaySize();
684});
685/*
686
687Script: Window.js
688	Build windows.
689
690Copyright:
691	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.
692
693License:
694	MIT-style license.	
695
696Requires:
697	Core.js
698
699*/
700
701/*
702Class: Window
703	Creates a single MochaUI window.
704	
705Syntax:
706	(start code)
707	new MochaUI.Window(options);
708	(end)	
709
710Arguments:
711	options
712
713Options:
714	id - The ID of the window. If not defined, it will be set to 'win' + windowIDCount.
715	title - The title of the window.
716	icon - Place an icon in the window's titlebar. This is either set to false or to the url of the icon. It is set up for icons that are 16 x 16px.
717	type - ('window', 'modal', 'modal2', or 'notification') Defaults to 'window'.
718	loadMethod - ('html', 'xhr', or 'iframe') Defaults to 'html'.
719	contentURL - Used if loadMethod is set to 'xhr' or 'iframe'.
720	closeAfter - Either false or time in milliseconds. Closes the window after a certain period of time in milliseconds. This is particularly useful for notifications.
721	evalScripts - (boolean) An xhr loadMethod option. Defaults to true.
722	evalResponse - (boolean) An xhr loadMethod option. Defaults to false.
723	content - (string or element) An html loadMethod option.
724	toolbar - (boolean) Create window toolbar. Defaults to false. This can be used for tabs, media controls, and so forth.
725	toolbarPosition - ('top' or 'bottom') Defaults to top.
726	toolbarHeight - (number)
727	toolbarURL - (url) Defaults to 'pages/lipsum.html'.
728	toolbarContent - (string)
729	container - (element ID) Element the window is injected in. The container defaults to 'desktop'. If no desktop then to document.body. Use 'pageWrapper' if you don't want the windows to overlap the toolbars.
730	restrict - (boolean) Restrict window to container when dragging.
731	shape - ('box' or 'gauge') Shape of window. Defaults to 'box'.
732	collapsible - (boolean) Defaults to true.
733	minimizable - (boolean) Requires MochaUI.Desktop and MochaUI.Dock. Defaults to true if dependenices are met. 
734	maximizable - (boolean) Requires MochaUI.Desktop. Defaults to true if dependenices are met.
735	closable - (boolean) Defaults to true. 
736	draggable - (boolean) Defaults to false for modals; otherwise true.
737	draggableGrid - (false or number) Distance in pixels for snap-to-grid dragging. Defaults to false. 
738	draggableLimit - (false or number) An object with x and y properties used to limit the movement of the Window. Defaults to false.
739	draggableSnap - (boolean) The distance to drag before the Window starts to respond to the drag. Defaults to false.
740	resizable - (boolean) Defaults to false for modals, notifications and gauges; otherwise true.
741	resizeLimit - (object) Minimum and maximum width and height of window when resized.
742	addClass - (string) Add a class to the window for more control over styling.	
743	width - (number) Width of content area.	
744	height - (number) Height of content area.
745	x - (number) If x and y are left undefined the window is centered on the page.
746	y - (number)
747	scrollbars - (boolean)
748	padding - (object)
749	shadowBlur - (number) Width of shadows.
750	shadowOffset - Should be positive and not be greater than the ShadowBlur.
751	controlsOffset - Change this if you want to reposition the window controls.
752	useCanvas - (boolean) Set this to false if you don't want a canvas body.
753	useCanvasControls - (boolean) Set this to false if you wish to use images for the buttons.
754	headerHeight - (number) Height of window titlebar.
755	footerHeight - (number) Height of window footer.
756	cornerRadius - (number)
757	contentBgColor - (hex) Body background color
758	headerStartColor - ([r,g,b,]) Titlebar gradient's top color
759	headerStopColor - ([r,g,b,]) Titlebar gradient's bottom color
760	bodyBgColor - ([r,g,b,]) Background color of the main canvas shape
761	minimizeBgColor - ([r,g,b,]) Minimize button background color
762	minimizeColor - ([r,g,b,]) Minimize button color
763	maximizeBgColor - ([r,g,b,]) Maximize button background color
764	maximizeColor - ([r,g,b,]) Maximize button color
765	closeBgColor - ([r,g,b,]) Close button background color
766	closeColor - ([r,g,b,]) Close button color
767	resizableColor - ([r,g,b,]) Resizable icon color
768	onBeforeBuild - (function) Fired just before the window is built.
769	onContentLoaded - (function) Fired when content is successfully loaded via XHR or Iframe.
770	onFocus - (function)  Fired when the window is focused.
771	onBlur - (function) Fired when window loses focus.
772	onResize - (function) Fired when the window is resized.
773	onMinimize - (function) Fired when the window is minimized.
774	onMaximize - (function) Fired when the window is maximized.
775	onRestore - (function) Fired when a window is restored from minimized or maximized.
776	onClose - (function) Fired just before the window is closed.
777	onCloseComplete - (function) Fired after the window is closed.
778
779Returns:
780	Window object.
781
782Example:
783	Define a window. It is suggested you name the function the same as your window ID + "Window".
784	(start code)
785	var mywindowWindow = function(){
786		new MochaUI.Window({
787			id: 'mywindow',
788			title: 'My Window',
789			loadMethod: 'xhr',
790			contentURL: 'pages/lipsum.html',
791			width: 340,
792			height: 150
793		});
794	}
795	(end)
796
797Example:
798	Create window onDomReady.
799	(start code)	
800	window.addEvent('domready', function(){
801		mywindow();
802	});
803	(end)
804
805Example:
806	Add link events to build future windows. It is suggested you give your anchor the same ID as your window + "WindowLink" or + "WindowLinkCheck". Use the latter if it is a link in the menu toolbar.
807
808	If you wish to add links in windows that open other windows remember to add events to those links when the windows are created.
809
810	(start code)
811	// Javascript:
812	if ($('mywindowLink')){
813		$('mywindowLink').addEvent('click', function(e) {
814			new Event(e).stop();
815			mywindow();
816		});
817	}
818
819	// HTML:
820	<a id="mywindowLink" href="pages/lipsum.html">My Window</a>	
821	(end)
822
823
824	Loading Content with an XMLHttpRequest(xhr):
825		For content to load via xhr all the files must be online and in the same domain. If you need to load content from another domain or wish to have it work offline, load the content in an iframe instead of using the xhr option.
826	
827	Iframes:
828		If you use the iframe loadMethod your iframe will automatically be resized when the window it is in is resized. If you want this same functionality when using one of the other load options simply add class="mochaIframe" to those iframes and they will be resized for you as well.
829
830*/
831
832// Having these options outside of the Class allows us to add, change, and remove
833// individual options without rewriting all of them.
834
835MochaUI.Windows.windowOptions = {
836	id:                null,
837	title:             'New Window',
838	icon:              false,
839	type:              'window',
840
841	loadMethod:        'html',
842	contentURL:        'pages/lipsum.html',
843
844	closeAfter:        false,
845
846	// xhr options
847	evalScripts:       true,
848	evalResponse:      false,
849
850	// html options
851	content:           'Window content',
852
853	// Toolbar
854	toolbar:           false,
855	toolbarPosition:   'top',
856	toolbarHeight:     29,
857	toolbarURL:        'pages/lipsum.html',
858	toolbarContent:    '',
859
860	// Toolbar
861	toolbar2:           false,
862	toolbar2Position:   'bottom',
863	toolbar2Height:     29,
864	toolbar2URL:        'pages/lipsum.html',
865	toolbar2Content:    '',	
866
867	// Container options
868	container:         null,
869	restrict:          true,
870	shape:             'box',
871
872	// Window Controls
873	collapsible:       true,
874	minimizable:       true,
875	maximizable:       true,
876	closable:          true,
877
878	// Draggable
879	draggable:         null,
880	draggableGrid:     false,
881	draggableLimit:    false,
882	draggableSnap:     false,
883
884	// Resizable
885	resizable:         null,
886	resizeLimit:       {'x': [250, 2500], 'y': [125, 2000]},
887	
888	// Style options:
889	addClass:          '',
890	width:             300,
891	height:            125,
892	x:                 null,
893	y:                 null,
894	scrollbars:        true,
895	padding:   		   { top: 10, right: 12, bottom: 10, left: 12 },
896	shadowBlur:        5,
897	shadowOffset:      {'x': 0, 'y': 1},
898	controlsOffset:    {'right': 6, 'top': 6},
899	useCanvas:         true,
900	useCanvasControls: true,
901	useSpinner:        true,    // Toggles whether or not the ajax spinners are displayed in window footers.
902
903	// Color options:		
904	headerHeight:      25,
905	footerHeight:      25,
906	cornerRadius:      8,
907	contentBgColor:    '#fff',
908	headerStartColor:  [250, 250, 250],
909	headerStopColor:   [229, 229, 229],
910	bodyBgColor:       [229, 229, 229],
911	minimizeBgColor:   [255, 255, 255],
912	minimizeColor:     [0, 0, 0],
913	maximizeBgColor:   [255, 255, 255],
914	maximizeColor:     [0, 0, 0],
915	closeBgColor:      [255, 255, 255],
916	closeColor:        [0, 0, 0],
917	resizableColor:    [254, 254, 254],
918
919	// Events
920	onBeforeBuild:     $empty,
921	onContentLoaded:   $empty,
922	onFocus:           $empty,
923	onBlur:            $empty,
924	onResize:          $empty,
925	onMinimize:        $empty,
926	onMaximize:        $empty,
927	onRestore:         $empty,
928	onClose:           $empty,
929	onCloseComplete:   $empty
930};
931
932MochaUI.Window = new Class({
933	options: MochaUI.Windows.windowOptions,
934	initialize: function(options){
935		this.setOptions(options);
936
937		// Shorten object chain
938		var options = this.options;
939
940		$extend(this, {
941			mochaControlsWidth: 0,
942			minimizebuttonX:  0,  // Minimize button horizontal position
943			maximizebuttonX: 0,  // Maximize button horizontal position
944			closebuttonX: 0,  // Close button horizontal position
945			headerFooterShadow: options.headerHeight + options.footerHeight + (options.shadowBlur * 2),
946			oldTop: 0,
947			oldLeft: 0,
948			isMaximized: false,
949			isMinimized: false,
950			isCollapsed: false,
951			timestamp: $time()
952		});
953		
954		// May be better to use if type != window
955		if (options.type != 'window'){
956			options.container = document.body;
957			options.minimizable = false;
958		}
959		if (!options.container){
960			options.container = MochaUI.Desktop.desktop ? MochaUI.Desktop.desktop : document.body;
961		}
962
963		// Set this.options.resizable to default if it was not defined
964		if (options.resizable == null){
965			if (options.type != 'window' || options.shape == 'gauge'){
966				options.resizable = false;
967			}
968			else {
969				options.resizable = true;	
970			}
971		}
972
973		// Set this.options.draggable if it was not defined
974		if (options.draggable == null){
975			if (options.type != 'window'){
976				options.draggable = false;
977			}
978			else {
979				options.draggable = true;
980			}
981		}
982
983		// Gauges are not maximizable or resizable
984		if (options.shape == 'gauge' || options.type == 'notification'){
985			options.collapsible = false;
986			options.maximizable = false;
987			options.contentBgColor = 'transparent';
988			options.scrollbars = false;
989			options.footerHeight = 0;
990		}
991		if (options.type == 'notification'){
992			options.closable = false;
993			options.headerHeight = 0;
994		}
995		
996		// Minimizable, dock is required and window cannot be modal
997		if (MochaUI.Dock && $(MochaUI.options.dock)){
998			if (MochaUI.Dock.dock && options.type != 'modal' && options.type != 'modal2'){
999				options.minimizable = options.minimizable;
1000			}
1001		}
1002		else {
1003			options.minimizable = false;
1004		}
1005
1006		// Maximizable, desktop is required
1007		options.maximizable = MochaUI.Desktop.desktop && options.maximizable && options.type != 'modal' && options.type != 'modal2';
1008
1009		if (this.options.type == 'modal2') {
1010			this.options.shadowBlur = 0;
1011			this.options.shadowOffset = {'x': 0, 'y': 0};
1012			this.options.useSpinner = false;
1013			this.options.useCanvas = false;
1014			this.options.footerHeight = 0;
1015			this.options.headerHeight = 0;
1016		}
1017
1018		// If window has no ID, give it one.
1019		if (options.id == null){
1020			options.id = 'win' + (++MochaUI.Windows.windowIDCount);
1021		}
1022		this.windowEl = $(options.id);
1023		
1024		this.newWindow();
1025		
1026		// Return window object
1027		return this;
1028	},
1029	saveValues: function(){	
1030		var coordinates = this.windowEl.getCoordinates();
1031		this.options.x = coordinates.left.toInt();
1032		this.options.y = coordinates.top.toInt();
1033	},
1034	/*
1035
1036	Internal Function: newWindow
1037	
1038	Arguments: 
1039		properties
1040
1041	*/
1042	newWindow: function(properties){ // options is not doing anything
1043
1044		// Shorten object chain
1045		var instances = MochaUI.Windows.instances;
1046		var instanceID = instances.get(this.options.id);
1047	
1048		// Here we check to see if there is already a class instance for this window
1049		if (instanceID){
1050			var currentInstance = instanceID;
1051		}
1052
1053		// Check if window already exists and is not in progress of closing
1054		if ( this.windowEl && !this.isClosing ){
1055			 // Restore if minimized
1056			if (currentInstance.isMinimized){
1057				MochaUI.Dock.restoreMinimized(this.windowEl);
1058			}
1059			// Expand and focus if collapsed
1060			if (currentInstance.isCollapsed){
1061				MochaUI.collapseToggle(this.windowEl);
1062				setTimeout(MochaUI.focusWindow.pass(this.windowEl, this),10);
1063			}
1064			// Else focus
1065			else {
1066				var coordinates = document.getCoordinates();
1067				if (this.windowEl.getStyle('left').toInt() > coordinates.width || this.windowEl.getStyle('top').toInt() > coordinates.height){
1068					MochaUI.centerWindow(this.windowEl);	
1069				}
1070				setTimeout(MochaUI.focusWindow.pass(this.windowEl, this),10);
1071			}
1072			return;
1073		}
1074		else {
1075			instances.set(this.options.id, this);
1076		}
1077
1078		this.isClosing = false;
1079		this.fireEvent('onBeforeBuild');
1080
1081		// Create window div
1082		MochaUI.Windows.indexLevel++;
1083		this.windowEl = new Element('div', {
1084			'class': 'mocha',
1085			'id':    this.options.id,
1086			'styles': {
1087				'width':   this.options.width,
1088				'height':  this.options.height,
1089				'display': 'block',
1090				'opacity': 0,
1091				'zIndex': MochaUI.Windows.indexLevel += 2
1092			}
1093		});
1094
1095		this.windowEl.addClass(this.options.addClass);
1096		
1097		if (this.options.type == 'modal2') {
1098			this.windowEl.addClass('modal2');
1099		}
1100
1101		// Fix a mouseover issue with gauges in IE7
1102		if ( Browser.Engine.trident && this.options.shape == 'gauge') {
1103			this.windowEl.setStyle('background', 'url(../images/spacer.gif)');
1104		}
1105
1106		if ((this.options.type == 'modal' || this.options.type == 'modal2' ) && Browser.Platform.mac && Browser.Engine.gecko){
1107			if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)) {
1108				var ffversion = new Number(RegExp.$1);
1109				if (ffversion < 3) {
1110					this.windowEl.setStyle('position', 'fixed');
1111				}
1112			}
1113		}
1114
1115		if (this.options.loadMethod == 'iframe') {
1116			this.options.padding = { top: 0, right: 0, bottom: 0, left: 0 };
1117		}
1118
1119		// Insert sub elements inside windowEl
1120		this.insertWindowElements();
1121
1122		// Set title
1123		this.titleEl.set('html',this.options.title);
1124
1125		// Set scrollbars, always use 'hidden' for iframe windows
1126		this.contentWrapperEl.setStyles({
1127			'overflow': 'hidden',
1128			'background': this.options.contentBgColor
1129		});
1130
1131		this.contentEl.setStyles({
1132			'padding-top': this.options.padding.top,
1133			'padding-bottom': this.options.padding.bottom,
1134			'padding-left': this.options.padding.left,
1135			'padding-right': this.options.padding.right
1136		});
1137
1138
1139		if (this.options.shape == 'gauge'){
1140			if (this.options.useCanvasControls){
1141				this.canvasControlsEl.setStyle('display', 'none');
1142			}
1143			else {
1144				this.controlsEl.setStyle('display', 'none');
1145			}
1146			this.windowEl.addEvent('mouseover', function(){
1147				this.mouseover = true;
1148				var showControls = function(){
1149					if (this.mouseover != false){
1150						if (this.options.useCanvasControls){
1151							this.canvasControlsEl.setStyle('display', 'block');
1152						}
1153						else {
1154							this.controlsEl.setStyle('display', 'block');
1155						}
1156						this.canvasHeaderEl.setStyle('display', 'block');
1157						this.titleEl.setStyle('display', 'block');
1158					}
1159				};
1160				showControls.delay(150, this);
1161
1162			}.bind(this));
1163			this.windowEl.addEvent('mouseleave', function(){
1164				this.mouseover = false;
1165				if (this.options.useCanvasControls){
1166					this.canvasControlsEl.setStyle('display', 'none');
1167				}
1168				else {
1169					this.controlsEl.setStyle('display', 'none');
1170				}
1171				this.canvasHeaderEl.setStyle('display', 'none');
1172				this.titleEl.setStyle('display', 'none');
1173			}.bind(this));
1174		}
1175
1176		// Inject window into DOM
1177		this.windowEl.injectInside(this.options.container);
1178
1179		if (this.options.type != 'notification'){
1180			this.setMochaControlsWidth();
1181		}		
1182
1183		// Add content to window.
1184		MochaUI.updateContent({
1185			'element': this.windowEl,
1186			'content':  this.options.content,
1187			'url':      this.options.contentURL
1188		});	
1189		
1190		// Add content to window toolbar.
1191		if (this.options.toolbar == true){
1192			MochaUI.updateContent({
1193				'element':       this.windowEl,
1194				'childElement':  this.toolbarEl,
1195				'content':       this.options.toolbarContent,
1196				'loadMethod':    'xhr',
1197				'url':           this.options.toolbarURL
1198			});
1199		}
1200
1201		// Add content to window toolbar.
1202		if (this.options.toolbar2 == true){
1203			MochaUI.updateContent({
1204				'element':       this.windowEl,
1205				'childElement':  this.toolbar2El,
1206				'content':       this.options.toolbar2Content,
1207				'loadMethod':    'xhr',
1208				'url':           this.options.toolbar2URL
1209			});
1210		}
1211		
1212		this.drawWindow(this.windowEl);
1213		
1214		// Attach events to the window
1215		this.attachDraggable(this.windowEl);
1216		this.attachResizable(this.windowEl);
1217		this.setupEvents(this.windowEl);
1218		
1219		if (this.options.resizable){
1220			this.adjustHandles();
1221		}
1222
1223		// Move window into position. If position not specified by user then center the window on the page.
1224		if (this.options.container == document.body || this.options.container == MochaUI.Desktop.desktop){
1225			var dimensions = window.getSize();
1226		}
1227		else {
1228			var dimensions = $(this.options.container).getSize();
1229		}
1230
1231		if (!this.options.y) {
1232			var y = (dimensions.y * .5) - ((this.options.height + this.headerFooterShadow + this.windowEl.getStyle('border-top').toInt() + this.windowEl.getStyle('border-bottom').toInt()) * .5);
1233		}
1234		else {
1235			var y = this.options.y - this.options.shadowBlur;
1236		}
1237
1238		if (!this.options.x) {
1239			var x =	(dimensions.x * .5) - (this.options.width * .5);
1240		}
1241		else {
1242			var x = this.options.x - this.options.shadowBlur;
1243		}
1244
1245		this.windowEl.setStyles({
1246			'top': y,
1247			'left': x
1248		});
1249
1250		// Create opacityMorph
1251		if (MochaUI.options.useEffects == true){
1252			// IE cannot handle both element opacity and VML alpha at the same time.
1253			if (Browser.Engine.trident){
1254				this.drawWindow(this.windowEl, false);
1255			}
1256			this.opacityMorph = new Fx.Morph(this.windowEl, {
1257				'duration': 350,
1258				onComplete: function(){
1259					if (Browser.Engine.trident){
1260						this.drawWindow(this.windowEl);
1261					}
1262				}.bind(this)
1263			});
1264		}
1265
1266		if (this.options.type == 'modal' || this.options.type == 'modal2') {
1267			MochaUI.currentModal = this.windowEl;
1268			if (Browser.Engine.trident4){
1269				$('modalFix').setStyle('display', 'block');
1270			}
1271			$('modalOverlay').setStyle('display', 'block');
1272			if (MochaUI.options.useEffects == false){
1273				$('modalOverlay').setStyle('opacity', .6);
1274				this.windowEl.setStyles({
1275					'zIndex': 11000,
1276					'opacity': 1
1277				});
1278			}
1279			else {
1280				MochaUI.Modal.modalOverlayCloseMorph.cancel();
1281				MochaUI.Modal.modalOverlayOpenMorph.start({
1282					'opacity': .6
1283				});
1284				this.windowEl.setStyles({
1285					'zIndex': 11000
1286				});
1287				this.opacityMorph.start({
1288					'opacity': 1
1289				});
1290			}
1291
1292			$$('.dockTab').removeClass('activeDockTab');
1293			$$('.mocha').removeClass('isFocused');
1294			this.windowEl.addClass('isFocused');
1295			
1296		}
1297		else if (MochaUI.options.useEffects == false){
1298			this.windowEl.setStyle('opacity', 1);
1299			setTimeout(MochaUI.focusWindow.pass(this.windowEl, this), 10);
1300		}
1301		else {
1302			this.opacityMorph.start({
1303				'opacity': 1
1304			});
1305			setTimeout(MochaUI.focusWindow.pass(this.windowEl, this), 10);
1306		}
1307
1308		// This is a generic morph that can be reused later by functions like centerWindow()
1309		this.morph = new Fx.Morph(this.windowEl, {
1310			'duration': 200
1311		});
1312
1313		// Add check mark to menu if link exists in menu
1314		// Need to make sure the check mark is not added to links not in menu
1315	
1316		if ($(this.windowEl.id + 'LinkCheck')){
1317			this.check = new Element('div', {
1318				'class': 'check',
1319				'id': this.options.id + '_check'
1320			}).inject(this.windowEl.id + 'LinkCheck');
1321		}
1322		
1323		if (this.options.closeAfter != false){
1324			MochaUI.closeWindow.delay(this.options.closeAfter, this, this.windowEl);
1325		}
1326
1327		if (MochaUI.Dock && $(MochaUI.options.dock) && this.options.type == 'window' ){
1328			MochaUI.Dock.createDockTab(this.windowEl);
1329		}
1330
1331	},
1332	setupEvents: function(windowEl) {
1333
1334		// Set events
1335		// Note: if a button does not exist, its due to properties passed to newWindow() stating otherwice
1336		if (this.closeButtonEl){
1337			this.closeButtonEl.addEvent('click', function(e) {
1338				new Event(e).stop();
1339				MochaUI.closeWindow(windowEl);
1340			}.bind(this));
1341		}
1342
1343		if (this.options.type == 'window'){
1344			windowEl.addEvent('mousedown', function() {
1345				MochaUI.focusWindow(windowEl);
1346			}.bind(this));
1347		}
1348
1349		if (this.minimizeButtonEl) {
1350			this.minimizeButtonEl.addEvent('click', function(e) {
1351				new Event(e).stop();
1352				MochaUI.Dock.minimizeWindow(windowEl);
1353		}.bind(this));
1354		}
1355
1356		if (this.maximizeButtonEl) {
1357			this.maximizeButtonEl.addEvent('click', function(e) {
1358				new Event(e).stop(); 
1359				if (this.isMaximized) {
1360					MochaUI.Desktop.restoreWindow(windowEl);
1361				} else {
1362					MochaUI.Desktop.maximizeWindow(windowEl);
1363				}
1364			}.bind(this));
1365		}
1366
1367		if (this.options.collapsible == true){
1368			// Keep titlebar text from being selected on double click in Safari.
1369			this.titleEl.addEvent('selectstart', function(e) {
1370				e = new Event(e).stop();
1371			}.bind(this));
1372			// Keep titlebar text from being selected on double click in Opera.
1373			this.titleBarEl.addEvent('mousedown', function(e) {
1374				if (Browser.Engine.trident) {
1375					this.titleEl.setCapture();
1376				}
1377			}.bind(this));
1378			this.titleBarEl.addEvent('mouseup', function(e) {
1379				if (Browser.Engine.trident) {
1380					this.titleEl.releaseCapture();
1381				}
1382			}.bind(this));
1383			this.titleBarEl.addEvent('dblclick', function(e) {
1384				e = new Event(e).stop();
1385				MochaUI.collapseToggle(this.windowEl);
1386			}.bind(this));
1387		}
1388
1389	},
1390	/*
1391
1392	Internal Function: attachDraggable()
1393		Make window draggable.
1394
1395	Arguments:
1396		windowEl
1397		
1398	*/
1399	attachDraggable: function(windowEl){
1400		if (!this.options.draggable) return;
1401		this.windowDrag = new Drag.Move(windowEl, {
1402			handle: this.titleBarEl,
1403			container: this.options.restrict == true ? $(this.options.container) : false,
1404			grid: this.options.draggableGrid,
1405			limit: this.options.draggableLimit,
1406			snap: this.options.draggableSnap,
1407			onStart: function() {
1408				if (this.options.type != 'modal' && this.options.type != 'modal2'){ 
1409					MochaUI.focusWindow(windowEl);
1410					$('windowUnderlay').setStyle('display','block');
1411				}
1412				if ( this.iframeEl )
1413					this.iframeEl.setStyle('visibility', 'hidden');
1414			}.bind(this),
1415			onComplete: function() {
1416				if (this.options.type != 'modal' && this.options.type != 'modal2') {
1417					$('windowUnderlay').setStyle('display', 'none');
1418				}
1419				if ( this.iframeEl ){
1420					this.iframeEl.setStyle('visibility', 'visible');
1421				}
1422				// Store new position in options.
1423				this.saveValues();
1424			}.bind(this)
1425		});
1426	},
1427	/*
1428
1429	Internal Function: attachResizable
1430		Make window resizable.
1431
1432	Arguments:
1433		windowEl
1434
1435	*/
1436	attachResizable: function(windowEl){
1437		if (!this.options.resizable) return;
1438		this.resizable1 = this.windowEl.makeResizable({
1439			handle: [this.n, this.ne, this.nw],
1440			limit: {
1441				y: [
1442					function(){
1443						return this.windowEl.getStyle('top').toInt() + this.windowEl.getStyle('height').toInt() - this.options.resizeLimit.y[1];
1444					}.bind(this),
1445					function(){
1446						return this.windowEl.getStyle('top').toInt() + this.windowEl.getStyle('height').toInt() - this.options.resizeLimit.y[0];
1447					}.bind(this)
1448				]
1449			},
1450			modifiers: {x: false, y: 'top'},
1451			onStart: function(){
1452				this.resizeOnStart();
1453				this.coords = this.contentWrapperEl.getCoordinates();
1454				this.y2 = this.coords.top.toInt() + this.contentWrapperEl.offsetHeight;
1455			}.bind(this),
1456			onDrag: function(){
1457				this.coords = this.contentWrapperEl.getCoordinates();
1458				this.contentWrapperEl.setStyle('height', this.y2 - this.coords.top.toInt());
1459				this.drawWindow(windowEl);
1460				this.adjustHandles();
1461			}.bind(this),
1462			onComplete: function(){
1463				this.resizeOnComplete();
1464			}.bind(this)
1465		});
1466
1467		this.resizable2 = this.contentWrapperEl.makeResizable({
1468			handle: [this.e, this.ne],
1469			limit: {
1470				x: [this.options.resizeLimit.x[0] - (this.options.shadowBlur * 2), this.options.resizeLimit.x[1] - (this.options.shadowBlur * 2) ]
1471			},	
1472			modifiers: {x: 'width', y: false},
1473			onStart: function(){
1474				this.resizeOnStart();
1475			}.bind(this),
1476			onDrag: function(){
1477				this.drawWindow(windowEl);
1478				this.adjustHandles();
1479			}.bind(this),
1480			onComplete: function(){
1481				this.resizeOnComplete();
1482			}.bind(this)
1483		});
1484
1485		this.resizable3 = this.contentWrapperEl.makeResizable({
1486			container: this.options.restrict == true ? $(this.options.container) : false,
1487			handle: this.se,
1488			limit: {
1489				x: [this.options.resizeLimit.x[0] - (this.options.shadowBlur * 2), this.options.resizeLimit.x[1] - (this.options.shadowBlur * 2) ],
1490				y: [this.options.resizeLimit.y[0] - this.headerFooterShadow, this.options.resizeLimit.y[1] - this.headerFooterShadow]
1491			},
1492			modifiers: {x: 'width', y: 'height'},
1493			onStart: function(){
1494				this.resizeOnStart();
1495			}.bind(this),
1496			onDrag: function(){
1497				this.drawWindow(windowEl);	
1498				this.adjustHandles();
1499			}.bind(this),
1500			onComplete: function(){
1501				this.resizeOnComplete();
1502			}.bind(this)	
1503		});
1504
1505		this.resizable4 = this.contentWrapperEl.makeResizable({
1506			handle: [this.s, this.sw],
1507			limit: {
1508				y: [this.options.resizeLimit.y[0] - this.headerFooterShadow, this.options.resizeLimit.y[1] - this.headerFooterShadow]
1509			},
1510			modifiers: {x: false, y: 'height'},
1511			onStart: function(){
1512				this.resizeOnStart();
1513			}.bind(this),
1514			onDrag: function(){
1515				this.drawWindow(windowEl);
1516				this.adjustHandles();
1517			}.bind(this),
1518			onComplete: function(){
1519				this.resizeOnComplete();
1520			}.bind(this)
1521		});
1522
1523		this.resizable5 = this.windowEl.makeResizable({
1524			handle: [this.w, this.sw, this.nw],
1525			limit: {
1526				x: [
1527					function(){
1528						return this.windowEl.getStyle('left').toInt() + this.windowEl.getStyle('width').toInt() - this.options.resizeLimit.x[1];
1529					}.bind(this),
1530				   function(){
1531					   return this.windowEl.getStyle('left').toInt() + this.windowEl.getStyle('width').toInt() - this.options.resizeLimit.x[0];
1532					}.bind(this)
1533				]
1534			},
1535			modifiers: {x: 'left', y: false},
1536			onStart: function(){
1537				this.resizeOnStart();
1538				this.coords = this.contentWrapperEl.getCoordinates();
1539				this.x2 = this.coords.left.toInt() + this.contentWrapperEl.offsetWidth;
1540			}.bind(this),
1541			onDrag: function(){
1542				this.coords = this.contentWrapperEl.getCoordinates();
1543				this.contentWrapperEl.setStyle('width', this.x2 - this.coords.left.toInt());
1544				this.drawWindow(windowEl);
1545				this.adjustHandles();
1546			}.bind(this),
1547			onComplete: function(){
1548				this.resizeOnComplete();
1549			}.bind(this)
1550		});
1551
1552	},
1553	resizeOnStart: function(){
1554		$('windowUnderlay').setStyle('display','block');
1555		if (this.iframeEl){
1556			this.iframeEl.setStyle('visibility', 'hidden');
1557		}	
1558	},	
1559	resizeOnComplete: function(){
1560		$('windowUnderlay').setStyle('display','none');
1561		if (this.iframeEl){
1562			this.iframeEl.setStyle('visibility', 'visible');
1563		}
1564		this.fireEvent('onResize', this.windowEl);
1565	},
1566	adjustHandles: function(){
1567
1568		var shadowBlur = this.options.shadowBlur;
1569		var shadowBlur2x = shadowBlur * 2;
1570		var shadowOffset = this.options.shadowOffset;
1571		var top = shadowBlur - shadowOffset.y - 1;
1572		var right = shadowBlur + shadowOffset.x - 1;
1573		var bottom = shadowBlur + shadowOffset.y - 1;
1574		var left = shadowBlur - shadowOffset.x - 1;
1575		
1576		var coordinates = this.windowEl.getCoordinates();
1577		var width = coordinates.width - shadowBlur2x + 2;
1578		var height = coordinates.height - shadowBlur2x + 2;
1579
1580		this.n.setStyles({
1581			'top': top,
1582			'left': left + 10,
1583			'width': width - 20
1584		});
1585		this.e.setStyles({
1586			'top': top + 10,
1587			'right': right,
1588			'height': height - 30
1589		});
1590		this.s.setStyles({
1591			'bottom': bottom,
1592			'left': left + 10,
1593			'width': width - 30
1594		});
1595		this.w.setStyles({
1596			'top': top + 10,
1597			'left': left,
1598			'height': height - 20
1599		});
1600		this.ne.setStyles({
1601			'top': top,
1602			'right': right	
1603		});
1604		this.se.setStyles({
1605			'bottom': bottom,
1606			'right': right
1607		});
1608		this.sw.setStyles({
1609			'bottom': bottom,
1610			'left': left
1611		});
1612		this.nw.setStyles({
1613			'top': top,
1614			'left': left
1615		});
1616	},
1617	detachResizable: function(){
1618			this.resizable1.detach();
1619			this.resizable2.detach();
1620			this.resizable3.detach();
1621			this.resizable4.detach();
1622			this.resizable5.detach();
1623			this.windowEl.getElements('.handle').setStyle('display', 'none');
1624	},
1625	reattachResizable: function(){
1626			this.resizable1.attach();
1627			this.resizable2.attach();
1628			this.resizable3.attach();
1629			this.resizable4.attach();
1630			this.resizable5.attach();
1631			this.windowEl.getElements('.handle').setStyle('display', 'block');
1632	},
1633	/*
1634
1635	Internal Function: insertWindowElements
1636
1637	Arguments:
1638		windowEl
1639
1640	*/
1641	insertWindowElements: function(){
1642		
1643		var options = this.options;
1644		var height = options.height;
1645		var width = options.width;
1646		var id = options.id;
1647
1648		var cache = {};
1649
1650		if (Browser.Engine.trident4){
1651			cache.zIndexFixEl = new Element('iframe', {
1652				'id': id + '_zIndexFix',
1653				'class': 'zIndexFix',
1654				'scrolling': 'no',
1655				'marginWidth': 0,
1656				'marginHeight': 0,
1657				'src': ''
1658			}).inject(this.windowEl);
1659		}
1660
1661		cache.overlayEl = new Element('div', {
1662			'id': id + '_overlay',
1663			'class': 'mochaOverlay'
1664		}).inject(this.windowEl);
1665
1666		cache.titleBarEl = new Element('div', {
1667			'id': id + '_titleBar',
1668			'class': 'mochaTitlebar',
1669			'styles': {
1670				'cursor': options.draggable ? 'move' : 'default'
1671			}
1672		}).inject(cache.overlayEl, 'top');
1673
1674		cache.titleEl = new Element('h3', {
1675			'id': id + '_title',
1676			'class': 'mochaTitle'
1677		}).inject(cache.titleBarEl);
1678
1679		if (options.icon != false){
1680			cache.titleBarEl.setStyles({
1681				'padding-left': 15,
1682				'background': 'url(' + options.icon + ') 5px 5px no-repeat'
1683			});
1684		}
1685		
1686		cache.contentBorderEl = new Element('div', {
1687			'id': id + '_contentBorder',
1688			'class': 'mochaContentBorder'
1689		}).inject(cache.overlayEl);
1690
1691		if (options.toolbar){
1692			cache.toolbarWrapperEl = new Element('div', {
1693				'id': id + '_toolbarWrapper',
1694				'class': 'mochaToolbarWrapper'
1695			}).inject(cache.contentBorderEl, options.toolbarPosition == 'bottom' ? 'after' : 'before');
1696
1697			if (options.toolbarPosition == 'bottom') {
1698				cache.toolbarWrapperEl.addClass('bottom');
1699			}
1700			cache.toolbarEl = new Element('div', {
1701				'id': id + '_toolbar',
1702				'class': 'mochaToolbar'
1703			}).inject(cache.toolbarWrapperEl);
1704		}
1705
1706		if (options.toolbar2){
1707			cache.toolbar2WrapperEl = new Element('div', {
1708				'id': id + '_toolbar2Wrapper',
1709				'class': 'mochaToolbarWrapper'
1710			}).inject(cache.contentBorderEl, options.toolbar2Position == 'bottom' ? 'after' : 'before');
1711
1712			if (options.toolbar2Position == 'bottom') {
1713				cache.toolbar2WrapperEl.addClass('bottom');
1714			}
1715			cache.toolbar2El = new Element('div', {
1716				'id': id + '_toolbar2',
1717				'class': 'mochaToolbar'
1718			}).inject(cache.toolbar2WrapperEl);
1719		}
1720
1721		cache.contentWrapperEl = new Element('div', {
1722			'id': id + '_contentWrapper',
1723			'class': 'mochaContentWrapper',
1724			'styles': {
1725				'width': width + 'px',
1726				'height': height + 'px'
1727			}
1728		}).inject(cache.contentBorderEl);
1729		
1730		if (this.options.shape == 'gauge'){
1731			cache.contentBorderEl.setStyle('borderWidth', 0);
1732		}
1733
1734		cache.contentEl = new Element('div', {
1735			'id': id + '_content',
1736			'class': 'mochaContent'
1737		}).inject(cache.contentWrapperEl);
1738
1739		if (this.options.useCanvas == true) {
1740			cache.canvasEl = new Element('canvas', {
1741				'id': id + '_canvas',
1742				'class': 'mochaCanvas',
1743				'width': 1,
1744				'height': 1
1745			}).inject(this.windowEl);
1746
1747			if (Browser.Engine.trident && MochaUI.ieSupport == 'excanvas'){
1748				G_vmlCanvasManager.initElement(cache.canvasEl);
1749				cache.canvasEl = this.windowEl.getElement('.mochaCanvas');
1750			}
1751		}
1752
1753		cache.controlsEl = new Element('div', {
1754			'id': id + '_controls',
1755			'class': 'mochaControls'
1756		}).inject(cache.overlayEl, 'after');
1757
1758		if (options.useCanvasControls == true){
1759			cache.canvasControlsEl = new Element('canvas', {
1760				'id': id + '_canvasControls',
1761				'class': 'mochaCanvasControls',
1762				'width': 14,
1763				'height': 14
1764			}).inject(this.windowEl);
1765
1766			if (Browser.Engine.trident && MochaUI.ieSupport == 'excanvas'){
1767				G_vmlCanvasManager.initElement(cache.canvasControlsEl);
1768				cache.canvasControlsEl = this.windowEl.getElement('.mochaCanvasControls');
1769			}
1770		}
1771
1772		if (options.closable){
1773			cache.closeButtonEl = new Element('div', {
1774				'id': id + '_closeButton',
1775				'class': 'mochaCloseButton',
1776				'title': 'Close'
1777			}).inject(cache.controlsEl);
1778			if (options.useCanvasControls == true){
1779				cache.closeButtonEl.setStyle('background', 'none');
1780			}
1781		}
1782
1783		if (options.maximizable){
1784			cache.maximizeButtonEl = new Element('div', {
1785				'id': id + '_maximizeButton',
1786				'class': 'mochaMaximizeButton',
1787				'title': 'Maximize'
1788			}).inject(cache.controlsEl);
1789			if (options.useCanvasControls == true){
1790				cache.maximizeButtonEl.setStyle('background', 'none');
1791			}
1792		}
1793
1794		if (options.minimizable){
1795			cache.minimizeButtonEl = new Element('div', {
1796				'id': id + '_minimizeButton',
1797				'class': 'mochaMinimizeButton',
1798				'title': 'Minimize'
1799			}).inject(cache.controlsEl);
1800			if (options.useCanvasControls == true){
1801				cache.minimizeButtonEl.setStyle('background', 'none');
1802			}
1803		}
1804
1805		if (options.useSpinner == true && options.shape != 'gauge' && options.type != 'notification'){
1806			cache.spinnerEl = new Element('div', {
1807				'id': id + '_spinner',
1808				'class': 'mochaSpinner',
1809				'width': 16,
1810				'height': 16
1811			}).inject(this.windowEl, 'bottom');
1812		}
1813
1814		if (this.options.shape == 'gauge'){
1815			cache.canvasHeaderEl = new Element('canvas', {
1816				'id': id + '_canvasHeader',
1817				'class': 'mochaCanvasHeader',
1818				'width': this.options.width,
1819				'height': 26
1820			}).inject(this.windowEl, 'bottom');
1821		
1822			if (Browser.Engine.trident && MochaUI.ieSupport == 'excanvas'){
1823				G_vmlCanvasManager.initElement(cache.canvasHeaderEl);
1824				cache.canvasHeaderEl = this.windowEl.getElement('.mochaCanvasHeader');
1825			}
1826		}
1827
1828		if ( Browser.Engine.trident ){
1829			cache.overlayEl.setStyle('zIndex', 2);
1830		}
1831
1832		// For Mac Firefox 2 to help reduce scrollbar bugs in that browser
1833		if (Browser.Platform.mac && Browser.Engine.gecko){
1834			if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
1835				var ffversion = new Number(RegExp.$1);
1836				if (ffversion < 3){
1837					cache.overlayEl.setStyle('overflow', 'auto');
1838				}
1839			}
1840		}
1841
1842		if (options.resizable){
1843			cache.n = new Element('div', {
1844				'id': id + '_resizeHandle_n',
1845				'class': 'handle',
1846				'styles': {
1847					'top': 0,
1848					'left': 10,
1849					'cursor': 'n-resize'
1850				}
1851			}).inject(cache.overlayEl, 'after');
1852
1853			cache.ne = new Element('div', {
1854				'id': id + '_resizeHandle_ne',
1855				'class': 'handle corner',
1856				'styles': {
1857					'top': 0,
1858					'right': 0,
1859					'cursor': 'ne-resize'
1860				}
1861			}).inject(cache.overlayEl, 'after');
1862			
1863			cache.e = new Element('div', {
1864				'id': id + '_resizeHandle_e',
1865				'class': 'handle',		
1866				'styles': {
1867					'top': 10,
1868					'right': 0,
1869					'cursor': 'e-resize'
1870				}
1871			}).inject(cache.overlayEl, 'after');
1872			
1873			cache.se = new Element('div', {
1874				'id': id + '_resizeHandle_se',
1875				'class': 'handle cornerSE',
1876				'styles': {
1877					'bottom': 0,
1878					'right': 0,
1879					'cursor': 'se-resize'
1880				}
1881			}).inject(cache.overlayEl, 'after');
1882
1883			cache.s = new Element('div', {
1884				'id': id + '_resizeHandle_s',
1885				'class': 'handle',
1886				'styles': {
1887					'bottom': 0,
1888					'left': 10,
1889					'cursor': 's-resize'
1890				}
1891			}).inject(cache.overlayEl, 'after');
1892			
1893			cache.sw = new Element('div', {
1894				'id': id + '_resizeHandle_sw',
1895				'class': 'handle corner',
1896				'styles': {
1897					'bottom': 0,
1898					'left': 0,
1899					'cursor': 'sw-resize'
1900				}
1901			}).inject(cache.overlayEl, 'after');
1902			
1903			cache.w = new Element('div', {
1904				'id': id + '_resizeHandle_w',
1905				'class': 'handle',		
1906				'styles': {
1907					'top': 10,
1908					'left': 0,
1909					'cursor': 'w-resize'
1910				}
1911			}).inject(cache.overlayEl, 'after');
1912			
1913			cache.nw = new Element('div', {
1914				'id': id + '_resizeHandle_nw',
1915				'class': 'handle corner',		
1916				'styles': {
1917					'top': 0,
1918					'left': 0,
1919					'cursor': 'nw-resize'
1920				}
1921			}).inject(cache.overlayEl, 'after');
1922		}
1923		$extend(this, cache);
1924		
1925	},
1926	/*
1927
1928	Internal function: drawWindow
1929		This is where we create the canvas GUI	
1930
1931	Arguments: 
1932		windowEl: the $(window)
1933		shadows: (boolean) false will draw a window without shadows
1934
1935	*/	
1936	drawWindow: function(windowEl, shadows) {
1937				
1938		if (this.isCollapsed){
1939			this.drawWindowCollapsed(windowEl, shadows);
1940			return;
1941		}
1942
1943		var options = this.options;
1944		var shadowBlur = options.shadowBlur;
1945		var shadowBlur2x = shadowBlur * 2;
1946		var shadowOffset = this.options.shadowOffset;
1947
1948		this.overlayEl.setStyles({
1949			'width': this.contentWrapperEl.offsetWidth
1950		});
1951
1952		// Resize iframe when window is resized
1953		if (this.iframeEl) {
1954			this.iframeEl.setStyles({
1955				'height': this.contentWrapperEl.offsetHeight
1956			});
1957		}
1958
1959		var borderHeight = this.contentBorderEl.getStyle('border-top').toInt() + this.contentBorderEl.getStyle('border-bottom').toInt();
1960		var toolbarHeight = this.toolbarWrapperEl ? this.toolbarWrapperEl.getStyle('height').toInt() + this.toolbarWrapperEl.getStyle('border-top').toInt() : 0;
1961		var toolbar2Height = this.toolbar2WrapperEl ? this.toolbar2WrapperEl.getStyle('height').toInt() + this.toolbar2WrapperEl.getStyle('border-top').toInt() : 0;
1962
1963		this.headerFooterShadow = options.headerHeight + options.footerHeight + shadowBlur2x;
1964		var height = this.contentWrapperEl.getStyle('height').toInt() + this.headerFooterShadow + toolbarHeight + toolbar2Height + borderHeight;
1965		var width = this.contentWrapperEl.getStyle('width').toInt() + shadowBlur2x;
1966		this.windowEl.setStyles({
1967			'height': height,
1968			'width': width
1969		});
1970
1971		this.overlayEl.setStyles({
1972			'height': height,
1973			'top': shadowBlur - shadowOffset.y,
1974			'left': shadowBlur - shadowOffset.x
1975		});		
1976
1977		// Opera requires the canvas height and width be set this way when resizing:
1978		if (this.options.useCanvas == true) {
1979			this.canvasEl.height = height;
1980			this.canvasEl.width = width;
1981		}
1982
1983		// Part of the fix for IE6 select z-index bug
1984		if (Browser.Engine.trident4){
1985			this.zIndexFixEl.setStyles({
1986				'width': width,
1987				'height': height
1988			})
1989		}
1990
1991		this.titleBarEl.setStyles({
1992			'width': width - shadowBlur2x,
1993			'height': options.headerHeight
1994		});
1995
1996		// Make sure loading icon is placed correctly.
1997		if (options.useSpinner == true && options.shape != 'gauge' && options.type != 'notification'){
1998			this.spinnerEl.setStyles({
1999				'left': shadowBlur - shadowOffset.x + 3,
2000				'bottom': shadowBlur + shadowOffset.y +  4
2001			});
2002		}
2003		
2004		if (this.options.useCanvas != false) {
2005		
2006			// Draw Window
2007			var ctx = this.canvasEl.getContext('2d');
2008			ctx.clearRect(0, 0, width, height);
2009			
2010			switch (options.shape) {
2011				case 'box':
2012					this.drawBox(ctx, width, height, shadowBlur, shadowOffset, shadows);
2013					break;
2014				case 'gauge':
2015					this.drawGauge(ctx, width, height, shadowBlur, shadowOffset, shadows);
2016					break;
2017			}
2018
2019
2020			if (options.resizable){ 
2021				MochaUI.triangle(
2022					ctx,
2023					width - (shadowBlur + shadowOffset.x + 17),
2024					height - (shadowBlur + shadowOffset.y + 18),
2025					11,
2026					11,
2027					options.resizableColor,
2028					1.0
2029				);
2030			}
2031
2032			// Invisible dummy object. The last element drawn is not rendered consistently while resizing in IE6 and IE7
2033			if (Browser.Engine.trident){
2034				MochaUI.triangle(ctx, 0, 0, 10, 10, options.resizableColor, 0);
2035			}
2036		}
2037		
2038		if (options.type != 'notification' && options.useCanvasControls == true){
2039			this.drawControls(width, height, shadows);
2040		}
2041
2042	},
2043	drawWindowCollapsed: function(windowEl, shadows) {
2044		
2045		var options = this.options;
2046		var shadowBlur = options.shadowBlur;
2047		var shadowBlur2x = shadowBlur * 2;
2048		var shadowOffset = options.shadowOffset;
2049		
2050		var headerShadow = options.headerHeight + shadowBlur2x + 2;
2051		var height = headerShadow;
2052		var width = this.contentWrapperEl.getStyle('width').toInt() + shadowBlur2x;
2053		this.windowEl.setStyle('height', height);
2054		
2055		this.overlayEl.setStyles({
2056			'height': height,
2057			'top': shadowBlur - shadowOffset.y,
2058			'left': shadowBlur - shadowOffset.x
2059		});		
2060
2061		// Opera height and width must be set like this, when resizing:
2062		this.canvasEl.height = height;
2063		this.canvasEl.width = width;
2064
2065		// Part of the fix for IE6 select z-index bug
2066		if (Browser.Engine.trident4){
2067			this.zIndexFixEl.setStyles({
2068				'width': width,
2069				'height': height
2070			});
2071		}
2072
2073		// Set width
2074		this.windowEl.setStyle('width', width);
2075		this.overlayEl.setStyle('width', width);
2076		this.titleBarEl.setStyles({
2077			'width': width - shadowBlur2x,
2078			'height': options.headerHeight
2079		});
2080	
2081		// Draw Window
2082		if (this.options.useCanvas != false) {
2083			var ctx = this.canvasEl.getContext('2d');
2084			ctx.clearRect(0, 0, width, height);
2085			
2086			this.drawBoxCollapsed(ctx, width, height, shadowBlur, shadowOffset, shadows);
2087			if (options.useCanvasControls == true) {
2088				this.drawControls(width, height, shadows);
2089			}
2090			
2091			// Invisible dummy object. The last element drawn is not rendered consistently while resizing in IE6 and IE7
2092			if (Browser.Engine.trident){
2093				MochaUI.triangle(ctx, 0, 0, 10, 10, options.resizableColor, 0);
2094			}
2095		}
2096
2097	},	
2098	drawControls : function(width, height, shadows){
2099		var options = this.options;
2100		var shadowBlur = options.shadowBlur;
2101		var shadowOffset = options.shadowOffset;
2102		var controlsOffset = options.controlsOffset;
2103		
2104		// Make sure controls are placed correctly.
2105		this.controlsEl.setStyles({
2106			'right': shadowBlur + shadowOffset.x + controlsOffset.right,
2107			'top': shadowBlur - shadowOffset.y + controlsOffset.top
2108		});
2109
2110		this.canvasControlsEl.setStyles({
2111			'right': shadowBlur + shadowOffset.x + controlsOffset.right,
2112			'top': shadowBlur - shadowOffset.y + controlsOffset.top
2113		});
2114
2115		// Calculate X position for controlbuttons
2116		//var mochaControlsWidth = 52;
2117		this.closebuttonX = options.closable ? this.mochaControlsWidth - 7 : this.mochaControlsWidth + 12;
2118		this.maximizebuttonX = this.closebuttonX - (options.maximizable ? 19 : 0);
2119		this.minimizebuttonX = this.maximizebuttonX - (options.minimizable ? 19 : 0);
2120		
2121		var ctx2 = this.canvasControlsEl.getContext('2d');
2122		ctx2.clearRect(0, 0, 100, 100);
2123
2124		if (this.options.closable){
2125			this.closebutton(
2126				ctx2,
2127				this.closebuttonX,
2128				7,
2129				options.closeBgColor,
2130				1.0,
2131				options.closeColor,
2132				1.0
2133			);
2134		}
2135		if (this.options.maximizable){
2136			this.maximizebutton(
2137				ctx2,
2138				this.maximizebuttonX,
2139				7,
2140				options.maximizeBgColor,
2141				1.0,
2142				options.maximizeColor,
2143				1.0
2144			);
2145		}
2146		if (this.options.minimizable){
2147			this.minimizebutton(
2148				ctx2,
2149				this.minimizebuttonX,
2150				7,
2151				options.minimizeBgColor,
2152				1.0,
2153				options.minimizeColor,
2154				1.0
2155			);
2156		}
2157		
2158	},
2159	drawBox: function(ctx, width, height, shadowBlur, shadowOffset, shadows){
2160
2161		var shadowBlur2x = shadowBlur * 2;
2162		var cornerRadius = this.options.cornerRadius;
2163
2164		// This is the drop shadow. It is created onion style.
2165		if ( shadows != false ) {	
2166			for (var x = 0; x <= shadowBlur; x++){
2167				MochaUI.roundedRect(
2168					ctx,
2169					shadowOffset.x + x,
2170					shadowOffset.y + x,
2171					width - (x * 2) - shadowOffset.x,
2172					height - (x * 2) - shadowOffset.y,
2173					cornerRadius + (shadowBlur - x),
2174					[0, 0, 0],
2175					x == shadowBlur ? .29 : .065 + (x * .01)
2176				);
2177			}
2178		}
2179		// Window body.
2180		this.bodyRoundedRect(
2181			ctx,                          // context
2182			shadowBlur - shadowOffset.x,  // x
2183			shadowBlur - shadowOffset.y,  // y
2184			width - shadowBlur2x,         // width
2185			height - shadowBlur2x,        // height
2186			cornerRadius,                 // corner radius
2187			this.options.bodyBgColor      // Footer color
2188		);
2189
2190		if (this.options.type != 'notification'){
2191		// Window header.
2192			this.topRoundedRect(
2193				ctx,                            // context
2194				shadowBlur - shadowOffset.x,    // x
2195				shadowBlur - shadowOffset.y,    // y
2196				width - shadowBlur2x,           // width
2197				this.options.headerHeight,      // height
2198				cornerRadius,                   // corner radius
2199				this.options.headerStartColor,  // Header gradient's top color
2200				this.options.headerStopColor    // Header gradient's bottom color
2201			);
2202		}	
2203	},
2204	drawBoxCollapsed: function(ctx, width, height, shadowBlur, shadowOffset, shadows){
2205
2206		var options = this.options;
2207		var shadowBlur2x = shadowBlur * 2;
2208		var cornerRadius = options.cornerRadius;
2209	
2210		// This is the drop shadow. It is created onion style.
2211		if ( shadows != false ){
2212			for (var x = 0; x <= shadowBlur; x++){
2213				MochaUI.roundedRect(
2214					ctx,
2215					shadowOffset.x + x,
2216					shadowOffset.y + x,
2217					width - (x * 2) - shadowOffset.x,
2218					height - (x * 2) - shadowOffset.y,
2219					cornerRadius + (shadowBlur - x),
2220					[0, 0, 0],
2221					x == shadowBlur ? .3 : .06 + (x * .01)
2222				);
2223			}
2224		}
2225
2226		// Window header
2227		this.topRoundedRect2(
2228			ctx,                          // context
2229			shadowBlur - shadowOffset.x,  // x
2230			shadowBlur - shadowOffset.y,  // y
2231			width - shadowBlur2x,         // width
2232			options.headerHeight + 2,     // height
2233			cornerRadius,                 // corner radius
2234			options.headerStartColor,     // Header gradient's top color
2235			options.headerStopColor       // Header gradient's bottom color
2236		);
2237
2238	},	
2239	drawGauge: function(ctx, width, height, shadowBlur, shadowOffset, shadows){
2240		var options = this.options;
2241		var radius = (width * .5) - (shadowBlur) + 16;
2242		if (shadows != false) {	
2243			for (var x = 0; x <= shadowBlur; x++){
2244				MochaUI.circle(
2245					ctx,
2246					width * .5 + shadowOffset.x,
2247					(height  + options.headerHeight) * .5 + shadowOffset.x,
2248					(width *.5) - (x * 2) - shadowOffset.x,
2249					[0, 0, 0],
2250					x == shadowBlur ? .75 : .075 + (x * .04)
2251				);
2252			}
2253		}
2254		MochaUI.circle(
2255			ctx,
2256			width * .5  - shadowOffset.x,
2257			(height + options.headerHeight) * .5  - shadowOffset.y,
2258			(width *.5) - shadowBlur,
2259			options.bodyBgColor,
2260			1
2261		);
2262
2263		// Draw gauge header
2264		this.canvasHeaderEl.setStyles({
2265			'top': shadowBlur - shadowOffset.y,
2266			'left': shadowBlur - shadowOffset.x
2267		});		
2268		var ctx = this.canvasHeaderEl.getContext('2d');
2269		ctx.clearRect(0, 0, width, 100);
2270		ctx.beginPath();
2271		ctx.lineWidth = 24;
2272		ctx.lineCap = 'round';
2273		ctx.moveTo(13, 13);
2274		ctx.lineTo(width - (shadowBlur*2) - 13, 13);
2275		ctx.strokeStyle = 'rgba(0, 0, 0, .65)';
2276		ctx.stroke();
2277	},
2278	bodyRoundedRect: function(ctx, x, y, width, height, radius, rgb){
2279		ctx.fillStyle = 'rgba(' + rgb.join(',') + ', 100)';
2280		ctx.beginPath();
2281		ctx.moveTo(x, y + radius);
2282		ctx.lineTo(x, y + height - radius);
2283		ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
2284		ctx.lineTo(x + width - radius, y + height);
2285		ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
2286		ctx.lineTo(x + width, y + radius);
2287		ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
2288		ctx.lineTo(x + radius, y);
2289		ctx.quadraticCurveTo(x, y, x, y + radius);
2290		ctx.fill();
2291
2292	},
2293	topRoundedRect: function(ctx, x, y, width, height, radius, headerStartColor, headerStopColor){
2294		var lingrad = ctx.createLinearGradient(0, 0, 0, height);
2295		lingrad.addColorStop(0, 'rgba(' + headerStartColor.join(',') + ', 1)');
2296		lingrad.addColorStop(1, 'rgba(' + headerStopColor.join(',') + ', 1)');		
2297		ctx.fillStyle = lingrad;
2298		ctx.beginPath();
2299		ctx.moveTo(x, y);
2300		ctx.lineTo(x, y + height);
2301		ctx.lineTo(x + width, y + height);
2302		ctx.lineTo(x + width, y + radius);
2303		ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
2304		ctx.lineTo(x + radius, y);
2305		ctx.quadraticCurveTo(x, y, x, y + radius);
2306		ctx.fill();
2307		/*
2308		ctx.beginPath();
2309		ctx.strokeStyle = '#000';
2310		ctx.lineWidth = 1;
2311		ctx.moveTo(x, y + height + .5);
2312		ctx.lineTo(x + width, y + height + .5);
2313		ctx.stroke();
2314		*/
2315
2316	},
2317	topRoundedRect2: function(ctx, x, y, width, height, radius, headerStartColor, headerStopColor){
2318		var lingrad = ctx.createLinearGradient(0, this.options.shadowBlur - 1, 0, height + this.options.shadowBlur + 3);
2319		lingrad.addColorStop(0, 'rgba(' + headerStartColor.join(',') + ', 1)');
2320		lingrad.addColorStop(1, 'rgba(' + headerStopColor.join(',') + ', 1)');
2321		ctx.fillStyle = lingrad;
2322		ctx.beginPath();
2323		ctx.moveTo(x, y + radius);
2324		ctx.lineTo(x, y + height - radius);
2325		ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
2326		ctx.lineTo(x + width - radius, y + height);
2327		ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
2328		ctx.lineTo(x + width, y + radius);
2329		ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
2330		ctx.lineTo(x + radius, y);
2331		ctx.quadraticCurveTo(x, y, x, y + radius);
2332		ctx.fill();	
2333	},
2334	maximizebutton: function(ctx, x, y, rgbBg, aBg, rgb, a){
2335		// Circle
2336		ctx.beginPath();
2337		ctx.moveTo(x, y);
2338		ctx.arc(x, y, 7, 0, Math.PI*2, true);
2339		ctx.fillStyle = 'rgba(' + rgbBg.join(',') + ',' + aBg + ')';
2340		ctx.fill();
2341		// X sign
2342		ctx.strokeStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
2343		ctx.beginPath();
2344		ctx.moveTo(x, y - 4);
2345		ctx.lineTo(x, y + 4);
2346		ctx.stroke();
2347		ctx.beginPath();
2348		ctx.moveTo(x - 4, y);
2349		ctx.lineTo(x + 4, y);
2350		ctx.stroke();
2351	},
2352	closebutton: function(ctx, x, y, rgbBg, aBg, rgb, a){
2353		// Circle
2354		ctx.beginPath();
2355		ctx.moveTo(x, y);
2356		ctx.arc(x, y, 7, 0, Math.PI*2, true);
2357		ctx.fillStyle = 'rgba(' + rgbBg.join(',') + ',' + aBg + ')';
2358		ctx.fill();
2359		// Plus sign
2360		ctx.strokeStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
2361		ctx.beginPath();
2362		ctx.moveTo(x - 3, y - 3);
2363		ctx.lineTo(x + 3, y + 3);
2364		ctx.stroke();
2365		ctx.beginPath();
2366		ctx.moveTo(x + 3, y - 3);
2367		ctx.lineTo(x - 3, y + 3);
2368		ctx.stroke();
2369	},
2370	minimizebutton: function(ctx, x, y, rgbBg, aBg, rgb, a){
2371		// Circle
2372		ctx.beginPath();
2373		ctx.moveTo(x,y);
2374		ctx.arc(x,y,7,0,Math.PI*2,true);
2375		ctx.fillStyle = 'rgba(' + rgbBg.join(',') + ',' + aBg + ')';
2376		ctx.fill();
2377		// Minus sign
2378		ctx.strokeStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
2379		ctx.beginPath();
2380		ctx.moveTo(x - 4, y);
2381		ctx.lineTo(x + 4, y);
2382		ctx.stroke();
2383	},
2384	/*
2385
2386	Function: hideSpinner
2387		Hides the spinner.
2388		
2389	*/	
2390	hideSpinner: function(spinner) {
2391		if ($(spinner))	$(spinner).setStyle('visibility', 'hidden');
2392	},
2393	/*
2394
2395	Function: showSpinner
2396		Shows the spinner.
2397	
2398	*/	
2399	showSpinner: function(spinner){
2400		if (!this.options.useSpinner || this.options.shape == 'gauge' || this.options.type == 'notification') return;
2401		$(spinner).setStyles({
2402			'visibility': 'visible'
2403		});
2404	},
2405	setMochaControlsWidth: function(){
2406		this.mochaControlsWidth = 0;
2407		var options = this.options;
2408		if (options.minimizable){
2409			this.mochaControlsWidth += (this.minimizeButtonEl.getStyle('margin-left').toInt() + this.minimizeButtonEl.getStyle('width').toInt());
2410		}
2411		if (options.maximizable){
2412			this.mochaControlsWidth += (this.maximizeButtonEl.getStyle('margin-left').toInt() + this.maximizeButtonEl.getStyle('width').toInt());
2413		}
2414		if (options.closable){
2415			this.mochaControlsWidth += (this.closeButtonEl.getStyle('margin-left').toInt() + this.closeButtonEl.getStyle('width').toInt());
2416		}
2417		this.controlsEl.setStyle('width', this.mochaControlsWidth);
2418		if (options.useCanvasControls == true){
2419			this.canvasControlsEl.setProperty('width', this.mochaControlsWidth);
2420		}
2421	}
2422});
2423MochaUI.Window.implement(new Options, new Events);
2424/*
2425
2426Script: Modal.js
2427	Create modal dialog windows.
2428
2429Copyright:
2430	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.	
2431
2432License:
2433	MIT-style license.	
2434
2435Requires:
2436	Core.js, Window.js
2437
2438See Also:
2439	<Window>	
2440	
2441*/
2442
2443MochaUI.Modal = new Class({
2444
2445	Extends: MochaUI.Window,
2446
2447	Implements: [Events, Options],
2448
2449	initialize: function(options){
2450
2451		this.modalInitialize();
2452		
2453		window.addEvent('resize', function(){
2454			this.setModalSize();
2455		}.bind(this));
2456
2457	},
2458	modalInitialize: function(){
2459		var modalOverlay = new Element('div', {
2460			'id': 'modalOverlay',
2461			'styles': {
2462				'height': document.getCoordinates().height,
2463				'opacity': .6
2464			}
2465		}).inject(document.body);
2466		
2467		modalOverlay.addEvent('click', function(e){
2468			MochaUI.closeWindow(MochaUI.currentModal);
2469		});
2470		
2471		if (Browser.Engine.trident4){
2472			var modalFix = new Element('iframe', {
2473				'id': 'modalFix',
2474				'scrolling': 'no',
2475				'marginWidth': 0,
2476				'marginHeight': 0,
2477				'src': '',
2478				'styles': {
2479					'height': document.getCoordinates().height
2480				}
2481			}).inject(document.body);
2482		}
2483
2484		this.modalOverlayOpenMorph = new Fx.Morph($('modalOverlay'), {
2485				'duration': 150
2486				});
2487		this.modalOverlayCloseMorph = new Fx.Morph($('modalOverlay'), {
2488			'duration': 150,
2489			onComplete: function(){
2490				$('modalOverlay').setStyle('display', 'none');
2491				if (Browser.Engine.trident4){
2492					$('modalFix').setStyle('display', 'none');
2493				}
2494			}.bind(this)
2495		});
2496	},
2497	setModalSize: function(){
2498		$('modalOverlay').setStyle('height', document.getCoordinates().height);
2499		if (Browser.Engine.trident4){
2500			$('modalFix').setStyle('height', document.getCoordinates().height);
2501		}
2502	}
2503});
2504MochaUI.Modal.implement(new Options, new Events);
2505/*
2506
2507Script: Windows-from-html.js
2508	Create windows from html markup in page.
2509
2510Copyright:
2511	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.	
2512
2513License:
2514	MIT-style license.	
2515
2516Requires:
2517	Core.js, Window.js
2518
2519Example:
2520	HTML markup.
2521	(start code)
2522<div class="mocha" id="mywindow" style="width:300px;height:255px;top:50px;left:350px">
2523	<h3 class="mochaTitle">My Window</h3>
2524	<p>My Window Content</p>
2525</div>	
2526	(end)
2527
2528See Also:
2529	<Window>
2530
2531*/
2532
2533MochaUI.extend({
2534	NewWindowsFromHTML: function(){
2535		$$('div.mocha').each(function(el) {
2536			// Get the window title and destroy that element, so it does not end up in window content
2537			if ( Browser.Engine.presto || Browser.Engine.trident5 ){
2538				el.setStyle('display','block'); // Required by Opera, and probably IE7
2539			}
2540			var title = el.getElement('h3.mochaTitle');
2541			var elDimensions = el.getStyles('height', 'width');
2542			var properties = {
2543				id: el.getProperty('id'),
2544				height: elDimensions.height.toInt(),
2545				width: elDimensions.width.toInt(),
2546				x: el.getStyle('left').toInt(),
2547				y: el.getStyle('top').toInt()
2548			};
2549			// If there is a title element, set title and destroy the element so it does not end up in window content
2550			if ( title ) {
2551				properties.title = title.innerHTML;
2552				title.destroy();
2553			}
2554		
2555			// Get content and destroy the element
2556			properties.content = el.innerHTML;
2557			el.destroy();
2558			
2559			// Create window
2560			new MochaUI.Window(properties, true);
2561		}.bind(this));
2562	}
2563});
2564/*
2565
2566Script: Windows-from-json.js
2567	Create one or more windows from JSON data. You can define all the same properties as you can for new MochaUI.Window(). Undefined properties are set to their defaults.
2568
2569Copyright:
2570	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.	
2571
2572License:
2573	MIT-style license.	
2574
2575Syntax:
2576	(start code)
2577	MochaUI.newWindowsFromJSON(properties);
2578	(end)
2579
2580Example:
2581	(start code)
2582	MochaUI.jsonWindows = function(){
2583		var url = 'data/json-windows-data.js';
2584		var request = new Request.JSON({
2585			url: url,
2586			method: 'get',
2587			onComplete: function(properties) {
2588				MochaUI.newWindowsFromJSON(properties.windows);
2589			}
2590		}).send();
2591	}
2592	(end)
2593
2594Note: 
2595	Windows created from JSON are not compatible with the current cookie based version
2596	of Save and Load Workspace.  	
2597
2598See Also:
2599	<Window>
2600
2601*/
2602
2603MochaUI.extend({	
2604	newWindowsFromJSON: function(properties){
2605		properties.each(function(properties) {
2606				new MochaUI.Window(properties);
2607		}.bind(this));
2608	}
2609});
2610/*
2611
2612Script: Arrange-cascade.js
2613	Cascade windows.
2614
2615Copyright:
2616	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.	
2617
2618License:
2619	MIT-style license.	
2620
2621Requires:
2622	Core.js, Window.js
2623
2624Syntax:
2625	(start code)
2626	MochaUI.arrangeCascade();
2627	(end)
2628
2629*/
2630
2631MochaUI.options.extend({
2632	viewportTopOffset:  30,    // Use a negative number if neccessary to place first window where you want it
2633	viewportLeftOffset: 20,
2634	windowTopOffset:    50,    // Initial vertical spacing of each window
2635	windowLeftOffset:   40     // Initial horizontal spacing of each window	
2636});
2637
2638MochaUI.extend({   
2639	arrangeCascade: function(){
2640		// See how much space we have to work with
2641		var coordinates = document.getCoordinates();
2642		
2643		var openWindows = 0;
2644		MochaUI.Windows.instances.each(function(instance){
2645			if (!instance.isMinimized) openWindows ++; 
2646		});
2647		
2648		if ((this.options.windowTopOffset * (openWindows + 1)) >= (coordinates.height - this.options.viewportTopOffset)) {
2649			var topOffset = (coordinates.height - this.options.viewportTopOffset) / (openWindows + 1);
2650		}
2651		else {
2652			var topOffset = this.options.windowTopOffset;
2653		}
2654		
2655		if ((this.options.windowLeftOffset * (openWindows + 1)) >= (coordinates.width - this.options.viewportLeftOffset - 20)) {
2656			var leftOffset = (coordinates.width - this.options.viewportLeftOffset - 20) / (openWindows + 1);
2657		}
2658		else {
2659			var leftOffset = this.options.windowLeftOffset;
2660		}
2661
2662		var x = this.options.viewportLeftOffset;
2663		var y = this.options.viewportTopOffset;
2664		$$('div.mocha').each(function(windowEl){
2665			var currentWindowClass = MochaUI.Windows.instances.get(windowEl.id);
2666			if (!currentWindowClass.isMinimized && !currentWindowClass.isMaximized){
2667				id = windowEl.id;
2668				MochaUI.focusWindow(windowEl);
2669				x += leftOffset;
2670				y += topOffset;
2671
2672				if (MochaUI.options.useEffects == false){
2673					windowEl.setStyles({
2674						'top': y,
2675						'left': x
2676					});
2677				}
2678				else {
2679					var cascadeMorph = new Fx.Morph(windowEl, {
2680						'duration': 550
2681					});
2682					cascadeMorph.start({
2683						'top': y,
2684						'left': x
2685					});
2686				}
2687			}
2688		}.bind(this));
2689	}
2690});
2691/*
2692
2693Script: Arrange-tile.js
2694	Cascade windows.
2695
2696Authors:
2697	Harry Roberts and Greg Houston
2698
2699License:
2700	MIT-style license.	
2701
2702Requires:
2703	Core.js, Window.js
2704
2705Syntax:
2706	(start code)
2707	MochaUI.arrangeTile();
2708	(end)
2709
2710*/
2711 
2712MochaUI.extend({
2713	arrangeTile: function(){
2714		var x = 10;
2715		var y = 10;
2716	
2717		var instances =  MochaUI.Windows.instances;
2718
2719		var windowsNum = 0;
2720
2721		instances.each(function(instance){
2722			if (!instance.isMinimized && !instance.isMaximized){
2723				windowsNum++;
2724			}
2725		});
2726
2727		var cols = 3;
2728		var rows = Math.ceil(windowsNum / cols);
2729		
2730		var coordinates = document.getCoordinates();
2731	
2732		var col_width = ((coordinates.width - this.options.viewportLeftOffset) / cols);
2733		var col_height = ((coordinates.height - this.options.viewportTopOffset) / rows);
2734		
2735		var row = 0;
2736		var col = 0;
2737		
2738		instances.each(function(instance){
2739			if (!instance.isMinimized && !instance.isMaximized){
2740				
2741				var content = instance.contentWrapperEl;
2742				var content_coords = content.getCoordinates();
2743				var window_coords = instance.windowEl.getCoordinates();
2744				
2745				// Calculate the amount of padding around the content window
2746				var padding_top = content_coords.top - window_coords.top;
2747				var padding_bottom = window_coords.height - content_coords.height - padding_top;
2748				var padding_left = content_coords.left - window_coords.left;
2749				var padding_right = window_coords.width - content_coords.width - padding_left;
2750
2751				/*
2752
2753				// This resizes the windows
2754				if (instance.options.shape != 'gauge' && instance.options.resizable == true){
2755					var width = (col_width - 3 - padding_left - padding_right);
2756					var height = (col_height - 3 - padding_top - padding_bottom);
2757
2758					if (width > instance.options.resizeLimit.x[0] && width < instance.options.resizeLimit.x[1]){
2759						content.setStyle('width', width);
2760					}
2761					if (height > instance.options.resizeLimit.y[0] && height < instance.options.resizeLimit.y[1]){
2762						content.setStyle('height', height);
2763					}
2764
2765				}*/
2766
2767				var left = (x + (col * col_width));
2768				var top = (y + (row * col_height));
2769
2770				instance.windowEl.setStyles({
2771					'left': left,
2772					'top': top
2773				});
2774
2775				instance.drawWindow(instance.windowEl);
2776
2777				MochaUI.focusWindow(instance.windowEl);
2778
2779				if (++col === cols) {
2780					row++;
2781					col = 0;
2782				}
2783			}
2784		}.bind(this));
2785	}
2786});/*
2787
2788Script: Tabs.js
2789	Functionality for window tabs.
2790
2791Copyright:
2792	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.	
2793
2794License:
2795	MIT-style license.
2796
2797Requires:
2798	Core.js, Window.js (for tabbed windows) or Layout.js (for tabbed panels)
2799
2800*/
2801
2802MochaUI.extend({
2803	/*
2804
2805	Function: initializeTabs
2806		Add click event to each list item that fires the selected function.
2807
2808	*/
2809	initializeTabs: function(el){
2810		$(el).getElements('li').each(function(listitem){
2811			listitem.addEvent('click', function(e){
2812				MochaUI.selected(this, el);
2813			});
2814		});
2815	},
2816	/*
2817
2818	Function: selected
2819		Add "selected" class to current list item and remove it from sibling list items.
2820
2821	Syntax:
2822		(start code)
2823			selected(el, parent);
2824		(end)
2825
2826Arguments:
2827	el - the list item
2828	parent - the ul
2829
2830	*/
2831	selected: function(el, parent){
2832		$(parent).getChildren().each(function(listitem){
2833			listitem.removeClass('selected');
2834		});
2835		el.addClass('selected');
2836	}
2837});
2838
2839/*
2840
2841Script: Layout.js
2842	Create web application layouts. Enables window maximize.
2843	
2844Copyright:
2845	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.
2846
2847License:
2848	MIT-style license.	
2849
2850Requires:
2851	Core.js, Window.js
2852	
2853*/
2854
2855MochaUI.Desktop = new Class({
2856
2857	Extends: MochaUI.Window,
2858
2859	Implements: [Events, Options],
2860	
2861	options: {
2862		// Naming options:
2863		// If you change the IDs of the Mocha Desktop containers in your HTML, you need to change them here as well.
2864		desktop:             'desktop',
2865		desktopHeader:       'desktopHeader',
2866		desktopFooter:       'desktopFooter',
2867		desktopNavBar:       'desktopNavbar',
2868		pageWrapper:         'pageWrapper',
2869		page:                'page',
2870		desktopFooter:       'desktopFooterWrapper'
2871	},	
2872	initialize: function(options){
2873		this.setOptions(options);
2874		this.desktop         = $(this.options.desktop);
2875		this.desktopHeader   = $(this.options.desktopHeader);
2876		this.desktopNavBar   = $(this.options.desktopNavBar);
2877		this.pageWrapper     = $(this.options.pageWrapper);
2878		this.page            = $(this.options.page);
2879		this.desktopFooter   = $(this.options.desktopFooter);		
2880	
2881		// This is run on dock initialize so no need to do it twice.
2882		if (!MochaUI.Dock.dockWrapper){
2883			this.setDesktopSize();
2884		}
2885		this.menuInitialize();		
2886
2887		// Resize desktop, page wrapper, modal overlay, and maximized windows when browser window is resized
2888		window.addEvent('resize', function(e){
2889			this.onBrowserResize();
2890		}.bind(this));
2891	},
2892	menuInitialize: function(){
2893		// Fix for dropdown menus in IE6
2894		if (Browser.Engine.trident4 && this.desktopNavBar){
2895			this.desktopNavBar.getElements('li').each(function(element) {
2896				element.addEvent('mouseenter', function(){
2897					this.addClass('ieHover');
2898				});
2899				element.addEvent('mouseleave', function(){
2900					this.removeClass('ieHover');
2901				});
2902			});
2903		};
2904	},
2905	onBrowserResize: function(){
2906		this.setDesktopSize();
2907		// Resize maximized windows to fit new browser window size
2908		setTimeout( function(){
2909			MochaUI.Windows.instances.each(function(instance){
2910				if (instance.isMaximized){
2911
2912					// Hide iframe while resize for better performance
2913					if ( instance.iframeEl ){
2914						instance.iframeEl.setStyle('visibility', 'hidden');
2915					}
2916
2917					var coordinates = document.getCoordinates();
2918					var borderHeight = instance.contentBorderEl.getStyle('border-top').toInt() + instance.contentBorderEl.getStyle('border-bottom').toInt();
2919					var toolbarHeight = instance.toolbarWrapperEl ? instance.toolbarWrapperEl.getStyle('height').toInt() + instance.toolbarWrapperEl.getStyle('border-top').toInt() : 0;
2920					instance.contentWrapperEl.setStyles({
2921						'height': coordinates.height - instance.options.headerHeight - instance.options.footerHeight - borderHeight - toolbarHeight,
2922						'width': coordinates.width
2923					});
2924
2925					instance.drawWindow($(instance.options.id));
2926					if ( instance.iframeEl ){
2927						instance.iframeEl.setStyles({
2928							'height': instance.contentWrapperEl.getStyle('height')
2929						});
2930						instance.iframeEl.setStyle('visibility', 'visible');
2931					}
2932
2933				}
2934			}.bind(this));
2935		}.bind(this), 100);
2936	},
2937	setDesktopSize: function(){
2938		var windowDimensions = window.getCoordinates();
2939
2940		// var dock = $(MochaUI.options.dock);
2941		var dockWrapper = $(MochaUI.options.dockWrapper);
2942		
2943		// Setting the desktop height may only be needed by IE7
2944		if (this.desktop){
2945			this.desktop.setStyle('height', windowDimensions.height);
2946		}
2947
2948		// Set pageWrapper height so the dock doesn't cover the pageWrapper scrollbars.
2949		if (this.pageWrapper) {
2950
2951			var dockOffset = MochaUI.dockVisible ? dockWrapper.offsetHeight : 0;
2952			var pageWrapperHeight = windowDimensions.height;
2953			pageWrapperHeight -= this.pageWrapper.getStyle('border-top').toInt();
2954			pageWrapperHeight -= this.pageWrapper.getStyle('border-bottom').toInt();
2955			if (this.desktopHeader){ pageWrapperHeight -= this.desktopHeader.offsetHeight; }
2956			if (this.desktopFooter){ pageWrapperHeight -= this.desktopFooter.offsetHeight; }
2957			pageWrapperHeight -= dockOffset;
2958
2959			if (pageWrapperHeight < 0){
2960				pageWrapperHeight = 0;
2961			}
2962			this.pageWrapper.setStyle('height', pageWrapperHeight);
2963		}
2964
2965		if (MochaUI.Columns.instances.getKeys().length > 0){ // Conditional is a fix for a bug in IE6 in the no toolbars demo.
2966			MochaUI.Desktop.resizePanels();
2967		}		
2968	},
2969	resizePanels: function(){
2970		if (Browser.Engine.trident4){
2971			$$('.pad').setStyle('display', 'none');
2972			$$('.rHeight').setStyle('height', 1);
2973		}
2974		MochaUI.panelHeight();
2975		MochaUI.rWidth();
2976		if (Browser.Engine.trident4) $$('.pad').setStyle('display', 'block');
2977	},
2978	/*
2979	
2980	Function: maximizeWindow
2981		Maximize a window.
2982	
2983	Syntax:
2984		(start code)
2985		MochaUI.Desktop.maximizeWindow(windowEl);
2986		(end)	
2987
2988	*/	
2989	maximizeWindow: function(windowEl){
2990
2991		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
2992		var options = currentInstance.options;
2993		var windowDrag = currentInstance.windowDrag;
2994
2995		// If window no longer exists or is maximized, stop
2996		if (windowEl != $(windowEl) || currentInstance.isMaximized ) return;
2997		
2998		if (currentInstance.isCollapsed){
2999			MochaUI.collapseToggle(windowEl);	
3000		}
3001
3002		currentInstance.isMaximized = true;
3003		
3004		// If window is restricted to a container, it should not be draggable when maximized.
3005		if (currentInstance.options.restrict){
3006			windowDrag.detach();
3007			if (options.resizable) {
3008				currentInstance.detachResizable();
3009			}
3010			currentInstance.titleBarEl.setStyle('cursor', 'default');
3011		}	
3012
3013		// If the window has a container that is not the desktop
3014		// temporarily move the window to the desktop while it is minimized.
3015		if (options.container != this.desktop){
3016			this.desktop.grab(windowEl);
3017			if (this.options.restrict){
3018			windowDrag.container = this.desktop;
3019			}
3020		}		
3021
3022		// Save original position
3023		currentInstance.oldTop = windowEl.getStyle('top');
3024		currentInstance.oldLeft = windowEl.getStyle('left');
3025
3026		var contentWrapperEl = currentInstance.contentWrapperEl;
3027
3028		// Save original dimensions
3029		contentWrapperEl.oldWidth = contentWrapperEl.getStyle('width');
3030		contentWrapperEl.oldHeight = contentWrapperEl.getStyle('height');
3031
3032		// Hide iframe
3033		// Iframe should be hidden when minimizing, maximizing, and moving for performance and Flash issues
3034		if ( currentInstance.iframeEl ) {
3035			currentInstance.iframeEl.setStyle('visibility', 'hidden');
3036		}
3037
3038		var windowDimensions = document.getCoordinates();
3039		var options = currentInstance.options;
3040		var shadowBlur = options.shadowBlur;
3041		var shadowOffset = options.shadowOffset;
3042		var newHeight = windowDimensions.height - options.headerHeight - options.footerHeight;
3043		newHeight -= currentInstance.contentBorderEl.getStyle('border-top').toInt();
3044		newHeight -= currentInstance.contentBorderEl.getStyle('border-bottom').toInt();
3045		newHeight -= (  currentInstance.toolbarWrapperEl ? currentInstance.toolbarWrapperEl.getStyle('height').toInt() + currentInstance.toolbarWrapperEl.getStyle('border-top').toInt() : 0);
3046
3047		if (MochaUI.options.useEffects == false){
3048			windowEl.setStyles({
3049				'top': shadowOffset.y - shadowBlur,
3050				'left': shadowOffset.x - shadowBlur
3051			});
3052			currentInstance.contentWrapperEl.setStyles({
3053				'height': newHeight,
3054				'width':  windowDimensions.width
3055			});
3056			currentInstance.drawWindow(windowEl);
3057			// Show iframe
3058			if ( currentInstance.iframeEl ) {
3059				currentInstance.iframeEl.setStyle('visibility', 'visible');
3060			}
3061			currentInstance.fireEvent('onMaximize', windowEl);
3062		}
3063		else {
3064
3065			// Todo: Initialize the variables for these morphs once in an initialize function and reuse them
3066
3067			var maximizeMorph = new Fx.Elements([contentWrapperEl, windowEl], { 
3068				duration: 70,
3069				onStart: function(windowEl){
3070					currentInstance.maximizeAnimation = currentInstance.drawWindow.periodical(20, currentInstance, windowEl);
3071				}.bind(this),
3072				onComplete: function(windowEl){
3073					$clear(currentInstance.maximizeAnimation);
3074					currentInstance.drawWindow(windowEl);
3075					// Show iframe
3076					if ( currentInstance.iframeEl ) {
3077						currentInstance.iframeEl.setStyle('visibility', 'visible');
3078					}
3079					currentInstance.fireEvent('onMaximize', windowEl);	
3080				}.bind(this)
3081			});
3082			maximizeMorph.start({
3083				'0': {	'height': newHeight,
3084						'width':  windowDimensions.width
3085				},
3086				'1': {	'top': shadowOffset.y - shadowBlur,
3087						'left': shadowOffset.x - shadowBlur 
3088				}
3089			});		
3090		}
3091		currentInstance.maximizeButtonEl.setProperty('title', 'Restore');
3092		MochaUI.focusWindow(windowEl);
3093
3094	},
3095	/*
3096
3097	Function: restoreWindow
3098		Restore a maximized window.
3099
3100	Syntax:
3101		(start code)
3102		MochaUI.Desktop.restoreWindow(windowEl);
3103		(end)	
3104
3105	*/	
3106	restoreWindow: function(windowEl){	
3107	
3108		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
3109		
3110		// Window exists and is maximized ?
3111		if (windowEl != $(windowEl) || !currentInstance.isMaximized) return;
3112			
3113		var options = currentInstance.options;
3114		currentInstance.isMaximized = false;
3115		
3116		if (options.restrict){
3117			currentInstance.windowDrag.attach();
3118			if (options.resizable){
3119				currentInstance.reattachResizable();
3120			}			
3121			currentInstance.titleBarEl.setStyle('cursor', 'move');
3122		}		
3123		
3124		// Hide iframe
3125		// Iframe should be hidden when minimizing, maximizing, and moving for performance and Flash issues
3126		if ( currentInstance.iframeEl ) {
3127			currentInstance.iframeEl.setStyle('visibility', 'hidden');
3128		}
3129		
3130		var contentWrapperEl = currentInstance.contentWrapperEl;
3131		
3132		if (MochaUI.options.useEffects == false){
3133			contentWrapperEl.setStyles({
3134				'width':  contentWrapperEl.oldWidth,
3135				'height': contentWrapperEl.oldHeight
3136			});
3137			currentInstance.drawWindow(windowEl);
3138			windowEl.setStyles({
3139				'top': currentInstance.oldTop,
3140				'left': currentInstance.oldLeft
3141			});
3142			if ( currentInstance.iframeEl ) {
3143				currentInstance.iframeEl.setStyle('visibility', 'visible');
3144			}			
3145			if (options.container != this.desktop){
3146				$(options.container).grab(windowEl);
3147				if (options.restrict){
3148					currentInstance.windowDrag.container = $(options.container);
3149				}
3150			}
3151			currentInstance.fireEvent('onRestore', windowEl);
3152		}
3153		else {
3154			var restoreMorph = new Fx.Elements([contentWrapperEl, windowEl], { 
3155				'duration':   150,
3156				'onStart': function(windowEl){
3157					currentInstance.maximizeAnimation = currentInstance.drawWindow.periodical(20, currentInstance, windowEl);
3158				}.bind(this),
3159				'onComplete': function(el){
3160					$clear(currentInstance.maximizeAnimation);
3161					currentInstance.drawWindow(windowEl);
3162					if (currentInstance.iframeEl){
3163						currentInstance.iframeEl.setStyle('visibility', 'visible');
3164					}
3165					if (options.container != this.desktop){
3166						$(options.container).grab(windowEl);
3167						if (options.restrict){	
3168							currentInstance.windowDrag.container = $(options.container);
3169						}
3170					}
3171					currentInstance.fireEvent('onRestore', windowEl);
3172				}.bind(this)
3173			});
3174			restoreMorph.start({ 
3175				'0': {	'height': contentWrapperEl.oldHeight,
3176						'width':  contentWrapperEl.oldWidth
3177				},
3178				'1': {	'top':  currentInstance.oldTop,
3179						'left': currentInstance.oldLeft
3180				}
3181			});
3182		}
3183		currentInstance.maximizeButtonEl.setProperty('title', 'Maximize');
3184	}
3185});
3186MochaUI.Desktop.implement(new Options, new Events);
3187
3188/*
3189
3190Class: Column
3191	Create a column. Columns should be created from left to right.
3192
3193Syntax:
3194(start code)
3195	MochaUI.Panel();
3196(end)
3197
3198Arguments:
3199	options
3200
3201Options:
3202	id - The ID of the column. This must be set when creating the column.	
3203	placement - Can be 'right', 'main', or 'left'. There must be at least one column with the 'main' option.
3204	width - 'main' column is fluid and should not be given a width.
3205	resizeLimit - resizelimit of a 'right' or 'left' column.
3206	onResize - (function) Fired when the column is resized.
3207	onCollapse - (function) Fired when the column is collapsed.
3208	onExpand - (function) Fired when the column is expanded.
3209		
3210*/
3211MochaUI.Column = new Class({
3212
3213	Extends: MochaUI.Desktop,
3214
3215	Implements: [Events, Options],
3216
3217	options: {
3218		id:            null, 
3219		placement:     null, 
3220		width:         null,
3221		resizeLimit:   [],
3222
3223		// Events
3224		onResize:     $empty, 
3225		onCollapse:   $empty,
3226		onExpand:     $empty
3227
3228	},
3229	initialize: function(options){
3230		this.setOptions(options);
3231		
3232		$extend(this, {
3233			timestamp: $time(),
3234			isCollapsed: false,
3235			oldWidth: 0
3236		});
3237
3238		// Shorten object chain
3239		var options = this.options;
3240		var instances = MochaUI.Columns.instances;
3241		var instanceID = instances.get(options.id);
3242
3243		// Check to see if there is already a class instance for this Column
3244		if (instanceID){
3245			var currentInstance = instanceID;
3246		}
3247
3248		// Check if column already exists
3249		if ( this.columnEl ){
3250			return;
3251		}
3252		else {			
3253			instances.set(options.id, this);
3254		}		
3255				
3256		this.columnEl = new Element('div', {
3257			'id': this.options.id,
3258			'class': 'column expanded',
3259			'styles': {
3260				'width': options.placement == 'main' ? null : options.width
3261			}
3262		}).inject($(MochaUI.Desktop.pageWrapper));
3263
3264		var parent = this.columnEl.getParent();
3265		var columnHeight = parent.getStyle('height').toInt();
3266		this.columnEl.setStyle('height', columnHeight);
3267
3268		if (options.placement == 'main'){
3269			this.columnEl.addClass('rWidth');
3270		}
3271
3272		this.spacerEl = new Element('div', {
3273			'id': this.options.id + '_spacer',
3274			'class': 'horizontalHandle'
3275		}).inject(this.columnEl);
3276
3277		switch (this.options.placement) {
3278			case 'left':
3279				this.handleEl = new Element('div', {
3280					'id': this.options.id + '_handle',
3281					'class': 'columnHandle'
3282				}).inject(this.columnEl, 'after');
3283
3284				this.handleIconEl = new Element('div', {
3285					'id': options.id + '_handle_icon',
3286					'class': 'handleIcon'
3287				}).inject(this.handleEl);
3288
3289				addResizeRight(this.columnEl, options.resizeLimit[0], options.resizeLimit[1]);
3290				break;
3291			case 'right':
3292				this.handleEl = new Element('div', {
3293					'id': this.options.id + '_handle',
3294					'class': 'columnHandle'
3295				}).inject(this.columnEl, 'before');
3296
3297				this.handleIconEl = new Element('div', {
3298					'id': options.id + '_handle_icon',
3299					'class': 'handleIcon'
3300				}).inject(this.handleEl);
3301				addResizeLeft(this.columnEl, options.resizeLimit[0], options.resizeLimit[1]);
3302				break;
3303		}
3304
3305		if (this.handleEl != null){
3306			this.handleEl.addEvent('dblclick', function(){
3307				this.columnToggle();
3308			}.bind(this));
3309		}
3310
3311		MochaUI.rWidth();
3312
3313	},
3314	columnToggle: function(){
3315		var column= this.columnEl;
3316		
3317		// Collapse
3318		if (this.isCollapsed == false){
3319			this.oldWidth = column.getStyle('width').toInt();
3320
3321			this.resize.detach();
3322			this.handleEl.removeEvents('dblclick');
3323			this.handleEl.addEvent('click', function(){
3324				this.columnToggle();
3325			}.bind(this));
3326			this.handleEl.setStyle('cursor', 'pointer').addClass('detached');
3327			
3328			column.setStyle('width', 0);
3329			this.isCollapsed = true;
3330			column.addClass('collapsed');
3331			column.removeClass('expanded');
3332
3333			MochaUI.rWidth();
3334			this.fireEvent('onCollapse');
3335		}
3336		// Expand
3337		else {
3338			column.setStyle('width', this.oldWidth);
3339			this.isCollapsed = false;
3340			column.addClass('expanded');
3341			column.removeClass('collapsed');
3342
3343			this.handleEl.removeEvents('click');
3344			this.handleEl.addEvent('dblclick', function(){
3345				this.columnToggle();
3346			}.bind(this));
3347			this.resize.attach();
3348			this.handleEl.setStyle('cursor', 'e-resize').addClass('attached');
3349
3350			MochaUI.rWidth();
3351			this.fireEvent('onExpand');
3352		}
3353	}
3354});
3355MochaUI.Column.implement(new Options, new Events);
3356
3357/*
3358
3359Class: Panel
3360	Create a panel. Panels go one on top of another in columns. Create your columns first and then add your panels. Panels should be created from top to bottom, left to right.
3361
3362Syntax:
3363(start code)
3364	MochaUI.Panel();
3365(end)
3366
3367Arguments:
3368	options
3369
3370Options:
3371	id - The ID of the panel. This must be set when creating the panel.
3372	column - Where to inject the panel. This must be set when creating the panel.
3373	loadMethod - ('html', 'xhr', or 'iframe')
3374	contentURL - Used if loadMethod is set to 'xhr' or 'iframe'.
3375	evalScripts - (boolean) An xhr loadMethod option. Defaults to true.
3376	evalResponse - (boolean) An xhr loadMethod option. Defaults to false.
3377	content - (string or element) An html loadMethod option.
3378	tabsURL - (url)	
3379	footer - (boolean)
3380	footerURL - (url)
3381	height - (number) Height of content area.
3382	addClass - (string) Add a class to the panel.
3383	scrollbars - (boolean)
3384	padding - (object)
3385	panelBackground - CSS background property for the panel.
3386	onBeforeBuild - (function) Fired before the panel is created.
3387	onContentLoaded - (function) Fired after the panel's conten is loaded.
3388	onResize - (function) Fired when the panel is resized.
3389	onCollapse - (function) Fired when the panel is collapsed.
3390	onExpand - (function) Fired when the panel is expanded.
3391		
3392*/
3393MochaUI.Panel = new Class({
3394							
3395	Extends: MochaUI.Desktop,
3396	
3397	Implements: [Events, Options],
3398	
3399	options: {
3400		id:               null,
3401		title:            'New Panel',
3402		column:           null,
3403		loadMethod:       'html',
3404		contentURL:       'pages/lipsum.html',
3405	
3406		// xhr options
3407		evalScripts:      true,
3408		evalResponse:     false,
3409	
3410		// html options
3411		content:          'Panel content',
3412		
3413		// Tabs
3414		tabsURL:          null,
3415
3416		footer:           false,
3417		footerURL:        'pages/lipsum.html',
3418		
3419		// Style options:
3420		height:           125,
3421		addClass:         '',
3422		scrollbars:       true,
3423		padding:   		  { top: 8, right: 8, bottom: 8, left: 8 },
3424
3425		// Color options:		
3426		panelBackground:   '#f8f8f8',
3427
3428		// Events
3429		onBeforeBuild:     $empty,
3430		onContentLoaded:   $empty,
3431		onResize:          $empty,
3432		onCollapse:        $empty,
3433		onExpand:          $empty
3434
3435	},	
3436	initialize: function(options){
3437		this.setOptions(options);
3438
3439		$extend(this, {
3440			timestamp: $time(),
3441			isCollapsed: false,
3442			oldHeight: 0,
3443			partner: null
3444		});
3445
3446		// Shorten object chain
3447		var instances = MochaUI.Panels.instances;
3448		var instanceID = instances.get(this.options.id);
3449	
3450		// Check to see if there is already a class instance for this panel
3451		if (instanceID){
3452			var currentInstance = instanceID;
3453		}
3454
3455		// Check if panel already exists
3456		if ( this.panelEl ){
3457			return;
3458		}
3459		else {			
3460			instances.set(this.options.id, this);
3461		}
3462
3463		this.fireEvent('onBeforeBuild');
3464		
3465		if (this.options.loadMethod == 'iframe') {
3466			// Iframes have their own scrollbars and padding.
3467			this.options.scrollbars = false;
3468			this.options.padding = { top: 0, right: 0, bottom: 0, left: 0 };
3469		}
3470
3471		this.showHandle = true;
3472		if ($(this.options.column).getChildren().length == 0){
3473			this.showHandle = false;
3474		}
3475
3476		this.panelEl = new Element('div', {
3477			'id': this.options.id,
3478			'class': 'panel expanded',
3479			'styles': {
3480				'height': this.options.height,
3481				'background': this.options.panelBackground
3482			}
3483		}).inject($(this.options.column));
3484
3485		this.panelEl.addClass(this.options.addClass);
3486
3487		this.contentEl = new Element('div', {
3488			'id': this.options.id + '_pad',
3489			'class': 'pad'
3490		}).inject(this.panelEl);
3491
3492		if (this.options.footer){
3493			this.footerWrapperEl = new Element('div', {
3494				'id': this.options.id + '_panelFooterWrapper',
3495				'class': 'panel-footerWrapper'
3496			}).inject(this.panelEl);
3497			
3498			this.footerEl = new Element('div', {
3499				'id': this.options.id + '_panelFooter',
3500				'class': 'panel-footer'
3501			}).inject(this.footerWrapperEl);
3502
3503
3504			MochaUI.updateContent({
3505				'element':       this.panelEl,
3506				'childElement':  this.footerEl,
3507				'loadMethod':    'xhr',
3508				'url':           this.options.footerURL
3509			});
3510			
3511		}
3512
3513		// This is in order to use the same variable as the windows do in updateContent.
3514		// May rethink this.
3515		this.contentWrapperEl = this.panelEl;
3516		
3517		// Set scrollbars, always use 'hidden' for iframe windows
3518		this.contentWrapperEl.setStyles({
3519			'overflow': this.options.scrollbars && !this.iframeEl ? 'auto' : 'hidden'
3520		});
3521
3522		this.contentEl.setStyles({
3523			'padding-top': this.options.padding.top,
3524			'padding-bottom': this.options.padding.bottom,
3525			'padding-left': this.options.padding.left,
3526			'padding-right': this.options.padding.right
3527		});			
3528		
3529		this.panelHeaderEl = new Element('div', {
3530			'id': this.options.id + '_header',
3531			'class': 'panel-header'
3532		}).inject(this.panelEl, 'before');
3533		
3534		this.panelHeaderToolboxEl = new Element('div', {
3535			'id': this.options.id + '_headerToolbox',
3536			'class': 'panel-header-toolbox'
3537		}).inject(this.panelHeaderEl);
3538
3539		this.collapseToggleEl = new Element('div', {
3540			'id': this.options.id + '_minmize',
3541			'class': 'panel-collapse icon16',
3542			'styles': {
3543				'width': 16,
3544				'height': 16
3545			},
3546			'title': 'Collapse Panel'
3547		}).inject(this.panelHeaderToolboxEl);
3548
3549		this.collapseToggleEl.addEvent('click', function(event){
3550			var panel = this.panelEl;
3551			
3552			// Get siblings and make sure they are not all collapsed.
3553			var instances = MochaUI.Panels.instances;
3554			var expandedSiblings = [];
3555			panel.getAllPrevious('.panel').each(function(sibling){
3556				var currentInstance = instances.get(sibling.id);
3557				if (currentInstance.isCollapsed == false){
3558					expandedSiblings.push(sibling);
3559				}
3560			});
3561			panel.getAllNext('.panel').each(function(sibling){
3562				var currentInstance = instances.get(sibling.id);
3563				if (currentInstance.isCollapsed == false){
3564					expandedSiblings.push(sibling);
3565				}
3566			});
3567
3568			if (this.isCollapsed == false) {
3569				var currentColumn = MochaUI.Columns.instances.get($(this.options.column).id);
3570
3571				if (expandedSiblings.length == 0 && currentColumn.options.placement != 'main'){
3572					var currentColumn = MochaUI.Columns.instances.get($(this.options.column).id);
3573					currentColumn.columnToggle();
3574					return;
3575				}
3576				else if (expandedSiblings.length == 0 && currentColumn.options.placement == 'main'){
3577					return;
3578				}
3579				this.oldHeight = panel.getStyle('height').toInt();
3580				if (this.oldHeight < 10) this.oldHeight = 20;
3581				panel.setStyle('height', 0);
3582				this.isCollapsed = true;
3583				panel.addClass('collapsed');
3584				panel.removeClass('expanded');
3585				MochaUI.panelHeight(this.options.column, panel, 'collapsing');
3586				this.collapseToggleEl.removeClass('panel-collapsed');
3587				this.collapseToggleEl.addClass('panel-expand');
3588				this.collapseToggleEl.setProperty('title','Expand Panel');
3589				this.fireEvent('onCollapse');
3590			}
3591			else {
3592				panel.setStyle('height', this.oldHeight);
3593				this.isCollapsed = false;
3594				panel.addClass('expanded');
3595				panel.removeClass('collapsed');
3596				MochaUI.panelHeight(this.options.column, panel, 'expanding');
3597				this.collapseToggleEl.removeClass('panel-expand');
3598				this.collapseToggleEl.addClass('panel-collapsed');
3599				this.collapseToggleEl.setProperty('title','Collapse Panel');
3600				this.fireEvent('onExpand');
3601			}
3602		}
3603		.bind(this));
3604		
3605		this.panelHeaderContentEl = new Element('div', {
3606			'id': this.options.id + '_headerContent',
3607			'class': 'panel-headerContent'
3608		}).inject(this.panelHeaderEl);
3609
3610		this.titleEl = new Element('h2', {
3611			'id': this.options.id + '_title'
3612		}).inject(this.panelHeaderContentEl);
3613
3614		if (this.options.tabsURL == null){
3615			this.titleEl.set('html', this.options.title);
3616		}		
3617		else {
3618			this.panelHeaderContentEl.addClass('tabs');
3619			MochaUI.updateContent({
3620				'element':      this.panelEl,
3621				'childElement': this.panelHeaderContentEl,
3622				'loadMethod':   'xhr',
3623				'url':          this.options.tabsURL
3624			});
3625		}
3626
3627		this.handleEl = new Element('div', {
3628			'id': this.options.id + '_handle',
3629			'class': 'horizontalHandle',
3630			'styles': {
3631				'display': this.showHandle == true ? 'block' : 'none'
3632			}
3633		}).inject(this.panelEl, 'after');
3634		
3635		this.handleIconEl = new Element('div', {
3636			'id': this.options.id + '_handle_icon',
3637			'class': 'handleIcon'
3638		}).inject(this.handleEl);
3639
3640		addResizeBottom(this.options.id);
3641
3642		// Add content to panel.
3643		MochaUI.updateContent({
3644			'element': this.panelEl,
3645			'content':  this.options.content,
3646			'url':      this.options.contentURL
3647		});
3648
3649		MochaUI.panelHeight(this.options.column, this.panelEl, 'new');
3650
3651	}
3652});
3653MochaUI.Panel.implement(new Options, new Events);
3654
3655
3656MochaUI.extend({
3657	// Panel Height	
3658	panelHeight: function(column, changing, action){
3659		if (column != null) {
3660			MochaUI.panelHeight2($(column), changing, action);
3661		}
3662		else {
3663			$$('.column').each(function(column){
3664				MochaUI.panelHeight2(column);
3665			}.bind(this));
3666		}
3667	},
3668	/*
3669
3670	actions can be new, collapsing or expanding.
3671
3672	*/
3673	panelHeight2: function(column, changing, action){
3674
3675			var instances = MochaUI.Panels.instances;
3676			
3677			var parent = column.getParent();
3678			var columnHeight = parent.getStyle('height').toInt();
3679			if (Browser.Engine.trident4){
3680				columnHeight -= 1;
3681			}
3682			column.setStyle('height', columnHeight);
3683
3684			var panels = column.getChildren('.panel');            // All the panels in the column.
3685			var panelsExpanded = column.getChildren('.expanded'); // All the expanded panels in the column.
3686			var panelsToResize = [];    // All the panels in the column whose height will be effected.
3687			var tallestPanel;           // The panel with the greatest height
3688			var tallestPanelHeight = 0;
3689
3690			this.panelsHeight = 0;		// Height of all the panels in the column	
3691			this.height = 0;            // Height of all the elements in the column	
3692
3693			// Set panel resize partners
3694			panels.each(function(panel){
3695				currentInstance = instances.get(panel.id);
3696				if (panel.hasClass('expanded') && panel.getNext('.expanded')){
3697					currentInstance.partner = panel.getNext('.expanded');
3698					currentInstance.resize.attach();
3699					currentInstance.handleEl.setStyles({
3700						'display': 'block',
3701						'cursor': 'n-resize'
3702					}).removeClass('detached');
3703				}
3704				else {
3705					currentInstance.resize.detach();
3706					currentInstance.handleEl.setStyle('cursor', null).addClass('detached');
3707				}
3708				if (panel.getNext('.panel') == null){
3709					currentInstance.handleEl.setStyle('display', 'none');
3710				}
3711			}.bind(this));
3712			
3713			// Get the total height of all the column's children
3714			column.getChildren().each(function(el){
3715
3716				if (el.hasClass('panel')){
3717					var currentInstance = instances.get(el.id);
3718
3719					// Are any next siblings Expanded?
3720					areAnyNextSiblingsExpanded = function(el){
3721						var test;
3722						el.getAllNext('.panel').each(function(sibling){
3723							var siblingInstance = instances.get(sibling.id);
3724							if (siblingInstance.isCollapsed == false){
3725								test = true;
3726							}
3727						}.bind(this));
3728						return test;
3729					}.bind(this);
3730
3731					// If a next sibling is expanding, are any of the nexts siblings of the expanding sibling Expanded?
3732					areAnyExpandingNextSiblingsExpanded = function(){
3733						var test;
3734						changing.getAllNext('.panel').each(function(sibling){
3735							var siblingInstance = instances.get(sibling.id);
3736							if (siblingInstance.isCollapsed == false){
3737								test = true;
3738							}
3739						}.bind(this));
3740						return test;
3741					}.bind(this);
3742					
3743					// Resize panels that are not collapsed or "new"
3744					if (action == 'new' ) {
3745						if (currentInstance.isCollapsed != true && el != changing) {
3746							panelsToResize.push(el);
3747						}
3748						
3749						// Height of panels that can be resized
3750						if (currentInstance.isCollapsed != true && el != changing) {
3751							this.panelsHeight += el.offsetHeight.toInt();
3752						}
3753					}
3754					// Resize panels that are not collapsed. If a panel is collapsing
3755					// resize any expanded panels below. If there are no expanded panels
3756					// below it, resize the expanded panels above it.
3757					else if (action == null || action == 'collapsing' ){
3758						if (currentInstance.isCollapsed != true && (el.getAllNext('.panel').contains(changing) != true || areAnyNextSiblingsExpanded(el) != true)){
3759							panelsToResize.push(el);
3760						}
3761						
3762						// Height of panels that can be resized
3763						if (currentInstance.isCollapsed != true && (el.getAllNext('.panel').contains(changing) != true || areAnyNextSiblingsExpanded(el) != true)){
3764							this.panelsHeight += el.offsetHeight.toInt();
3765						}
3766					}
3767					// Resize panels that are not collapsed and are not expanding.
3768					// Resize any expanded panels below the expanding panel. If there are no expanded panels
3769					// below it, resize the first expanded panel above it.
3770					else if (action == 'expanding'){
3771						   
3772						if (currentInstance.isCollapsed != true && (el.getAllNext('.panel').contains(changing) != true || (areAnyExpandingNextSiblingsExpanded() != true && el.getNext('.expanded') == changing)) && el != changing){
3773							panelsToResize.push(el);
3774						}
3775						// Height of panels that can be resized
3776						if (currentInstance.isCollapsed != true && (el.getAllNext('.panel').contains(changing) != true || (areAnyExpandingNextSiblingsExpanded() != true && el.getNext('.expanded') == changing)) && el != changing){
3777							this.panelsHeight += el.offsetHeight.toInt();
3778						}
3779					}
3780
3781					if (el.style.height){
3782						this.height += el.getStyle('height').toInt();
3783					}
3784				}
3785				else {
3786					this.height += el.offsetHeight.toInt();
3787				}
3788			}.bind(this));
3789
3790			// Get the remaining height
3791			var remainingHeight = column.offsetHeight.toInt() - this.height;
3792			
3793			this.height = 0;
3794
3795			// Get height of all the column's children
3796			column.getChildren().each(function(el){
3797				this.height += el.offsetHeight.toInt();
3798			}.bind(this));
3799				
3800			var remainingHeight = column.offsetHeight.toInt() - this.height;
3801
3802			panelsToResize.each(function(panel){
3803				var ratio = this.panelsHeight / panel.offsetHeight.toInt();
3804				var newPanelHeight = panel.getStyle('height').toInt() + (remainingHeight / ratio);
3805				if (newPanelHeight < 1){
3806					newPanelHeight = 0;
3807				}
3808				panel.setStyle('height', newPanelHeight);
3809			}.bind(this));	
3810
3811			// Make sure the remaining height is 0. If not add/subtract the
3812			// remaining height to the tallest panel. This makes up for browser resizing,
3813			// off ratios, and users trying to give panels too much height.
3814			
3815			// Get height of all the column's children
3816			this.height = 0;
3817			column.getChildren().each(function(el){
3818				this.height += el.offsetHeight.toInt();
3819				if (el.hasClass('panel') && el.getStyle('height').toInt() > tallestPanelHeight){
3820					tallestPanel = el;
3821					tallestPanelHeight = el.getStyle('height').toInt();
3822				}
3823			}.bind(this));
3824
3825			var remainingHeight = column.offsetHeight.toInt() - this.height;
3826
3827			if ((remainingHeight > 0 || remainingHeight < 0) && tallestPanelHeight > 0){
3828				tallestPanel.setStyle('height', tallestPanel.getStyle('height').toInt() + remainingHeight );
3829				if (tallestPanel.getStyle('height') < 1){
3830					tallestPanel.setStyle('height', 0 );
3831				}
3832			}
3833
3834			$$('.columnHandle').each(function(handle){
3835				var handleHeight = parent.getStyle('height').toInt() - handle.getStyle('border-top').toInt() - handle.getStyle('border-bottom').toInt();
3836				if (Browser.Engine.trident4){
3837					handleHeight -= 1;
3838				}
3839				handle.setStyle('height', handleHeight);
3840			});
3841			
3842			panelsExpanded.each(function(panel){
3843				MochaUI.resizeChildren(panel);
3844			}.bind(this));
3845	},
3846	// May rename this resizeIframeEl()
3847	resizeChildren: function(panel){
3848		var instances = MochaUI.Panels.instances;
3849		var currentInstance = instances.get(panel.id);
3850		var contentWrapperEl = currentInstance.contentWrapperEl;
3851
3852		if (currentInstance.iframeEl){
3853			currentInstance.iframeEl.setStyles({
3854				'height': contentWrapperEl.getStyle('height'),
3855				'width': contentWrapperEl.offsetWidth - contentWrapperEl.getStyle('border-left').toInt() - contentWrapperEl.getStyle('border-right').toInt()
3856			});
3857		}
3858	},
3859	// Remaining Width
3860	rWidth: function(){	
3861		$$('.rWidth').each(function(column){
3862			var currentWidth = column.offsetWidth.toInt();
3863			currentWidth -= column.getStyle('border-left').toInt();
3864			currentWidth -= column.getStyle('border-right').toInt();
3865
3866			var parent = column.getParent();
3867			this.width = 0;
3868			
3869			// Get the total width of all the parent element's children
3870			parent.getChildren().each(function(el){
3871				if (el.hasClass('mocha') != true){
3872					this.width += el.offsetWidth.toInt();
3873				}
3874			}.bind(this));
3875		
3876			// Add the remaining width to the current element
3877			var remainingWidth = parent.offsetWidth.toInt() - this.width;
3878			var newWidth =	currentWidth + remainingWidth;
3879			if (newWidth < 1) newWidth = 0;
3880			column.setStyle('width', newWidth);
3881			column.getChildren('.panel').each(function(panel){
3882				panel.setStyle('width', newWidth - panel.getStyle('border-left').toInt() - panel.getStyle('border-right').toInt());
3883				MochaUI.resizeChildren(panel);
3884			}.bind(this));
3885		});
3886	}
3887
3888});
3889
3890function addResizeRight(element, min, max){
3891	if (!$(element)) return;
3892	element = $(element);
3893
3894	var instances = MochaUI.Columns.instances;
3895	var currentInstance = instances.get(element.id);
3896
3897	var handle = element.getNext('.columnHandle');
3898	handle.setStyle('cursor', 'e-resize');	
3899	if (!min) min = 50;
3900	if (!max) max = 250;
3901	if (Browser.Engine.trident){
3902		handle.addEvents({
3903			'mousedown': function(){
3904				handle.setCapture();
3905			},
3906			'mouseup': function(){
3907				handle.releaseCapture();
3908			}
3909		});
3910	}
3911	currentInstance.resize = element.makeResizable({
3912		handle: handle,
3913		modifiers: {x: 'width', y: false},
3914		limit: { x: [min, max] },
3915		onStart: function(){
3916			element.getElements('iframe').setStyle('visibility','hidden');
3917			element.getNext('.column').getElements('iframe').setStyle('visibility','hidden');
3918		}.bind(this),
3919		onDrag: function(){
3920			MochaUI.rWidth();
3921			if (Browser.Engine.trident4){
3922				element.getChildren().each(function(el){
3923					var width = $(element).getStyle('width').toInt();
3924					width -= el.getStyle('border-right').toInt();
3925					width -= el.getStyle('border-left').toInt();
3926					width -= el.getStyle('padding-right').toInt();
3927					width -= el.getStyle('padding-left').toInt();
3928					el.setStyle('width', width);
3929				}.bind(this));
3930			}						
3931		}.bind(this),
3932		onComplete: function(){
3933			MochaUI.rWidth();
3934			element.getElements('iframe').setStyle('visibility','visible');
3935			element.getNext('.column').getElements('iframe').setStyle('visibility','visible');
3936			currentInstance.fireEvent('onResize');
3937		}.bind(this)
3938	});	
3939}
3940
3941function addResizeLeft(element, min, max){
3942	if (!$(element)) return;
3943	element = $(element);
3944
3945	var instances = MochaUI.Columns.instances;
3946	var currentInstance = instances.get(element.id);
3947
3948	var handle = element.getPrevious('.columnHandle');
3949	handle.setStyle('cursor', 'e-resize');
3950	var partner = element.getPrevious('.column');
3951	if (!min) min = 50;
3952	if (!max) max = 250;
3953	if (Browser.Engine.trident){	
3954		handle.addEvents({
3955			'mousedown': function(){
3956				handle.setCapture();
3957			},	
3958			'mouseup': function(){
3959				handle.releaseCapture();
3960			}
3961		});
3962	}
3963	currentInstance.resize = element.makeResizable({
3964		handle: handle,
3965		modifiers: {x: 'width' , y: false},
3966		invert: true,
3967		limit: { x: [min, max] },
3968		onStart: function(){
3969			$(element).getElements('iframe').setStyle('visibility','hidden');
3970			partner.getElements('iframe').setStyle('visibility','hidden');
3971		}.bind(this),
3972		onDrag: function(){
3973			MochaUI.rWidth();
3974		}.bind(this),
3975		onComplete: function(){
3976			MochaUI.rWidth();
3977			$(element).getElements('iframe').setStyle('visibility','visible');
3978			partner.getElements('iframe').setStyle('visibility','visible');
3979			currentInstance.fireEvent('onResize');
3980		}.bind(this)
3981	});
3982}
3983
3984function addResizeBottom(element){
3985	if (!$(element)) return;
3986	var element = $(element);
3987	
3988	var instances = MochaUI.Panels.instances;
3989	var currentInstance = instances.get(element.id);
3990	var handle = currentInstance.handleEl;
3991	handle.setStyle('cursor', 'n-resize');
3992	partner = currentInstance.partner;
3993	min = 0;
3994	max = function(){
3995		return element.getStyle('height').toInt() + partner.getStyle('height').toInt();
3996	}.bind(this);
3997	
3998	if (Browser.Engine.trident){	
3999		handle.addEvents({
4000			'mousedown': function(){
4001				handle.setCapture();
4002			},	
4003			'mouseup': function(){
4004				handle.releaseCapture();
4005			}
4006		});
4007	}
4008	currentInstance.resize = element.makeResizable({
4009		handle: handle,
4010		modifiers: {x: false, y: 'height'},
4011		limit: { y: [min, max] },
4012		invert: false,
4013		onBeforeStart: function(){
4014			partner = currentInstance.partner;
4015			this.originalHeight = element.getStyle('height').toInt();
4016			this.partnerOriginalHeight = partner.getStyle('height').toInt();
4017		}.bind(this),
4018		onStart: function(){
4019			if (currentInstance.iframeEl) {
4020				currentInstance.iframeEl.setStyle('visibility', 'hidden');
4021			}
4022			partner.getElements('iframe').setStyle('visibility','hidden');
4023		}.bind(this),
4024		onDrag: function(){
4025			partnerHeight = partnerOriginalHeight + (this.originalHeight - element.getStyle('height').toInt());
4026			partner.setStyle('height', partnerHeight);
4027			MochaUI.resizeChildren(element, element.getStyle('height').toInt());
4028			MochaUI.resizeChildren(partner, partnerHeight);
4029		}.bind(this),
4030		onComplete: function(){
4031			partnerHeight = partnerOriginalHeight + (this.originalHeight - element.getStyle('height').toInt());
4032			partner.setStyle('height', partnerHeight);
4033			MochaUI.resizeChildren(element, element.getStyle('height').toInt());
4034			MochaUI.resizeChildren(partner, partnerHeight);
4035			if (currentInstance.iframeEl) {
4036				currentInstance.iframeEl.setStyle('visibility', 'visible');
4037			}
4038			partner.getElements('iframe').setStyle('visibility','visible');
4039			currentInstance.fireEvent('onResize');
4040		}.bind(this)
4041	});
4042}
4043/*
4044
4045Script: Dock.js
4046	Implements the dock/taskbar. Enables window minimize.
4047
4048Copyright:
4049	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.	
4050
4051License:
4052	MIT-style license.
4053
4054Requires:
4055	Core.js, Window.js, Layout.js	
4056
4057Todo:
4058	- Make it so the dock requires no initial html markup.
4059
4060*/
4061
4062MochaUI.options.extend({
4063		// Naming options:
4064		// If you change the IDs of the Mocha Desktop containers in your HTML, you need to change them here as well.
4065		dockWrapper: 'dockWrapper',
4066		dock:        'dock'
4067});
4068
4069// Used by Desktop.js before MochaUI.Dock is initialized.
4070window.addEvent('domready', function(){	
4071	if ($('dockWrapper')) {
4072		MochaUI.dockVisible = true;
4073	}
4074});
4075
4076MochaUI.extend({
4077	/*
4078
4079	Function: minimizeAll
4080		Minimize all windows that are minimizable.
4081
4082	*/	
4083	minimizeAll: function() {
4084		$$('div.mocha').each(function(windowEl){
4085		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
4086			if (!currentInstance.isMinimized && currentInstance.options.minimizable == true){
4087				MochaUI.Dock.minimizeWindow(windowEl);
4088			}
4089		}.bind(this));
4090	}
4091});
4092
4093MochaUI.Dock = new Class({
4094	Extends: MochaUI.Window,
4095
4096	Implements: [Events, Options],
4097
4098	options: {
4099		useControls:          true,      // Toggles autohide and dock placement controls.
4100		dockPosition:         'top',     // Position the dock starts in, top or bottom.
4101		// Style options
4102		dockTabColor:         [255, 255, 255],
4103		trueButtonColor:      [70, 245, 70],     // Color for autohide on
4104		enabledButtonColor:   [125, 208, 250], 
4105		disabledButtonColor:  [170, 170, 170]
4106	},
4107	initialize: function(options){
4108		// Stops if MochaUI.Desktop is not implemented
4109		if (!MochaUI.Desktop) return;
4110		this.setOptions(options);
4111		
4112		this.dockWrapper   = $(MochaUI.options.dockWrapper);
4113		this.dock          = $(MochaUI.options.dock);
4114		this.autoHideEvent = null;		
4115		this.dockAutoHide  = false;  // True when dock autohide is set to on, false if set to off
4116
4117		if (!this.dockWrapper) return;
4118
4119		if (!this.options.useControls){
4120			if($('dockPlacement')){
4121				$('dockPlacement').setStyle('cursor', 'default');
4122			}
4123			if($('dockAutoHide')){
4124				$('dockAutoHide').setStyle('cursor', 'default');
4125			}
4126		}
4127
4128		this.dockWrapper.setStyles({
4129			'display':  'block',
4130			'position': 'absolute',
4131			'top':      null,
4132			'bottom':   MochaUI.Desktop.desktopFooter ? MochaUI.Desktop.desktopFooter.offsetHeight : 0,
4133			'left':     0
4134		});
4135		
4136		if (this.options.useControls){
4137			this.initializeDockControls();
4138		}
4139
4140		// Add check mark to menu if link exists in menu
4141		if ($('dockLinkCheck')){
4142			this.sidebarCheck = new Element('div', {
4143				'class': 'check',
4144				'id': 'dock_check'
4145			}).inject($('dockLinkCheck'));
4146		}
4147
4148		this.dockSortables = new Sortables('#dockSort', {
4149			opacity: Browser.Engine.trident ? 1 : .5,
4150			constrain: true,
4151			clone: false,
4152			revert: false
4153		});
4154
4155		MochaUI.Desktop.setDesktopSize();
4156	},
4157	initializeDockControls: function(){
4158		
4159		if (this.options.useControls){
4160			// Insert canvas
4161			var canvas = new Element('canvas', {
4162				'id':     'dockCanvas',
4163				'width':  '15',
4164				'height': '18'
4165			}).inject(this.dock);
4166
4167			// Dynamically initialize canvas using excanvas. This is only required by IE
4168			if (Browser.Engine.trident && MochaUI.ieSupport == 'excanvas'){
4169				G_vmlCanvasManager.initElement(canvas);
4170			}
4171		}
4172		
4173		var dockPlacement = $('dockPlacement');
4174		var dockAutoHide = $('dockAutoHide');
4175
4176		// Position top or bottom selector
4177		dockPlacement.setProperty('title','Position Dock Top');
4178
4179		// Attach event
4180		dockPlacement.addEvent('click', function(){
4181			this.moveDock();
4182		}.bind(this));
4183
4184		// Auto Hide toggle switch
4185		dockAutoHide.setProperty('title','Turn Auto Hide On');
4186		
4187		// Attach event Auto Hide 
4188		dockAutoHide.addEvent('click', function(event){
4189			if ( this.dockWrapper.getProperty('dockPosition') == 'top' )
4190				return false;
4191
4192			var ctx = $('dockCanvas').getContext('2d');
4193			this.dockAutoHide = !this.dockAutoHide;	// Toggle
4194			if (this.dockAutoHide){
4195				$('dockAutoHide').setProperty('title', 'Turn Auto Hide Off');
4196				//ctx.clearRect(0, 11, 100, 100);
4197				MochaUI.circle(ctx, 5 , 14, 3, this.options.trueButtonColor, 1.0);
4198
4199				// Define event
4200				this.autoHideEvent = function(event) {
4201					if (!this.dockAutoHide)
4202						return;
4203					if (!MochaUI.Desktop.desktopFooter) {
4204						var dockHotspotHeight = this.dockWrapper.offsetHeight;
4205						if (dockHotspotHeight < 25) dockHotspotHeight = 25;
4206					}
4207					else if (MochaUI.Desktop.desktopFooter) {
4208						var dockHotspotHeight = this.dockWrapper.offsetHeight + MochaUI.Desktop.desktopFooter.offsetHeight;
4209						if (dockHotspotHeight < 25) dockHotspotHeight = 25;
4210					}						
4211					if (!MochaUI.Desktop.desktopFooter && event.client.y > (document.getCoordinates().height - dockHotspotHeight)){
4212						if (!MochaUI.dockVisible){
4213							this.dockWrapper.setStyle('display', 'block');
4214							MochaUI.dockVisible = true;
4215							MochaUI.Desktop.setDesktopSize();
4216						}
4217					}
4218					else if (MochaUI.Desktop.desktopFooter && event.client.y > (document.getCoordinates().height - dockHotspotHeight)){
4219						if (!MochaUI.dockVisible){
4220							this.dockWrapper.setStyle('display', 'block');
4221							MochaUI.dockVisible = true;
4222							MochaUI.Desktop.setDesktopSize();
4223						}
4224					}
4225					else if (MochaUI.dockVisible){
4226						this.dockWrapper.setStyle('display', 'none');
4227						MochaUI.dockVisible = false;
4228						MochaUI.Desktop.setDesktopSize();
4229						
4230					}
4231				}.bind(this);
4232
4233				// Add event
4234				document.addEvent('mousemove', this.autoHideEvent);
4235
4236			} else {
4237				$('dockAutoHide').setProperty('title', 'Turn Auto Hide On');
4238				//ctx.clearRect(0, 11, 100, 100);
4239				MochaUI.circle(ctx, 5 , 14, 3, this.options.enabledButtonColor, 1.0);
4240				// Remove event
4241				document.removeEvent('mousemove', this.autoHideEvent);
4242			}
4243
4244		}.bind(this));
4245
4246		// Draw dock controls
4247		var ctx = $('dockCanvas').getContext('2d');
4248		ctx.clearRect(0, 0, 100, 100);
4249		MochaUI.circle(ctx, 5 , 4, 3, this.options.enabledButtonColor, 1.0);
4250		MochaUI.circle(ctx, 5 , 14, 3, this.options.enabledButtonColor, 1.0);
4251		
4252		if (this.options.dockPosition == 'top'){
4253			this.moveDock();
4254		}
4255
4256	},
4257	moveDock: function(){
4258			var ctx = $('dockCanvas').getContext('2d');
4259			// Move dock to top position
4260			if (this.dockWrapper.getStyle('position') != 'relative'){
4261				this.dockWrapper.setStyles({
4262					'position': 'relative',
4263					'bottom':   null
4264				});
4265				this.dockWrapper.addClass('top');
4266				MochaUI.Desktop.setDesktopSize();
4267				this.dockWrapper.setProperty('dockPosition','top');
4268				ctx.clearRect(0, 0, 100, 100);
4269				MochaUI.circle(ctx, 5, 4, 3, this.options.enabledButtonColor, 1.0);
4270				MochaUI.circle(ctx, 5, 14, 3, this.options.disabledButtonColor, 1.0);
4271				$('dockPlacement').setProperty('title', 'Position Dock Bottom');
4272				$('dockAutoHide').setProperty('title', 'Auto Hide Disabled in Top Dock Position');
4273				this.dockAutoHide = false;
4274			}
4275			// Move dock to bottom position
4276			else {
4277				this.dockWrapper.setStyles({
4278					'position':      'absolute',
4279					'bottom':        MochaUI.Desktop.desktopFooter ? MochaUI.Desktop.desktopFooter.offsetHeight : 0
4280				});
4281				this.dockWrapper.removeClass('top');
4282				MochaUI.Desktop.setDesktopSize();
4283				this.dockWrapper.setProperty('dockPosition', 'bottom');
4284				ctx.clearRect(0, 0, 100, 100);
4285				MochaUI.circle(ctx, 5, 4, 3, this.options.enabledButtonColor, 1.0);
4286				MochaUI.circle(ctx, 5 , 14, 3, this.options.enabledButtonColor, 1.0);
4287				$('dockPlacement').setProperty('title', 'Position Dock Top');
4288				$('dockAutoHide').setProperty('title', 'Turn Auto Hide On');
4289			}
4290	},
4291	createDockTab: function(windowEl){
4292
4293		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
4294
4295		var dockTab = new Element('div', {
4296			'id': currentInstance.options.id + '_dockTab',
4297			'class': 'dockTab',
4298			'title': titleText
4299		}).inject($('dockClear'), 'before');
4300		
4301		dockTab.addEvent('mousedown', function(e){
4302			new Event(e).stop();
4303			this.timeDown = $time();
4304		});
4305		
4306		dockTab.addEvent('mouseup', function(e){
4307			this.timeUp = $time();
4308			if ((this.timeUp - this.timeDown) < 275){
4309				// If the visibility of the windows on the page are toggled off, toggle visibility on.
4310				if (MochaUI.Windows.windowsVisible == false) {
4311					MochaUI.toggleWindowVisibility();
4312					if (currentInstance.isMinimized == true) {
4313						MochaUI.Dock.restoreMinimized.delay(25, MochaUI.Dock, windowEl);
4314					}
4315					else {
4316						MochaUI.focusWindow(windowEl);
4317					}
4318					return;
4319				}
4320				// If window is minimized, restore window.
4321				if (currentInstance.isMinimized == true) {
4322					MochaUI.Dock.restoreMinimized.delay(25, MochaUI.Dock, windowEl);
4323				}
4324				else{
4325					// If window is not minimized and is focused, minimize window.
4326					if (currentInstance.windowEl.hasClass('isFocused') && currentInstance.options.minimizable == true){
4327						MochaUI.Dock.minimizeWindow(windowEl)
4328					}
4329					// If window is not minimized and is not focused, focus window.	
4330					else{
4331						MochaUI.focusWindow(windowEl);
4332					}
4333					// if the window is not minimized and is outside the viewport, center it in the viewport.
4334					var coordinates = document.getCoordinates();
4335					if (windowEl.getStyle('left').toInt() > coordinates.width || windowEl.getStyle('top').toInt() > coordinates.height){
4336						MochaUI.centerWindow(windowEl);	
4337					}
4338				}
4339			}
4340		});
4341
4342		this.dockSortables.addItems(dockTab);
4343
4344		var titleText = currentInstance.titleEl.innerHTML;
4345
4346		var dockTabText = new Element('div', {
4347			'id': currentInstance.options.id + '_dockTabText',
4348			'class': 'dockText'
4349		}).set('html', titleText.substring(0,20) + (titleText.length > 20 ? '...' : '')).inject($(dockTab));
4350
4351		// If I implement this again, will need to also adjust the titleText truncate and the tab's
4352		// left padding.
4353		if (currentInstance.options.icon != false){
4354			// dockTabText.setStyle('background', 'url(' + currentInstance.options.icon + ') 4px 4px no-repeat');
4355		}
4356		
4357		// Need to resize everything in case the dock wraps when a new tab is added
4358		MochaUI.Desktop.setDesktopSize();
4359
4360	},
4361	makeActiveTab: function(){
4362
4363		// getWindowWith HighestZindex is used in case the currently focused window
4364		// is closed.		
4365		var windowEl = MochaUI.getWindowWithHighestZindex();
4366		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
4367		
4368		$$('div.dockTab').removeClass('activeDockTab');
4369		if (currentInstance.isMinimized != true) {
4370			
4371			currentInstance.windowEl.addClass('isFocused');
4372
4373			var currentButton = $(currentInstance.options.id + '_dockTab');
4374			if (currentButton != null) {
4375				currentButton.addClass('activeDockTab');
4376			}
4377		}
4378		else {
4379			currentInstance.windowEl.removeClass('isFocused');
4380		}	
4381	},	
4382	minimizeWindow: function(windowEl){
4383		if (windowEl != $(windowEl)) return;
4384		
4385		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
4386		currentInstance.isMinimized = true;
4387
4388		// Hide iframe
4389		// Iframe should be hidden when minimizing, maximizing, and moving for performance and Flash issues
4390		if ( currentInstance.iframeEl ) {
4391			currentInstance.iframeEl.setStyle('visibility', 'hidden');
4392		}
4393
4394		// Hide window and add to dock	
4395		currentInstance.contentBorderEl.setStyle('visibility', 'hidden');
4396		if(currentInstance.toolbarWrapperEl){		
4397			currentInstance.toolbarWrapperEl.setStyle('visibility', 'hidden');
4398		}
4399		windowEl.setStyle('visibility', 'hidden');
4400
4401		 // Fixes a scrollbar issue in Mac FF2
4402		if (Browser.Platform.mac && Browser.Engine.gecko){
4403			if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)) {
4404				var ffversion = new Number(RegExp.$1);
4405				if (ffversion < 3) {
4406					currentInstance.contentWrapperEl.setStyle('overflow', 'hidden');
4407				}
4408			}
4409		}
4410	
4411		MochaUI.Desktop.setDesktopSize();
4412
4413		// Have to use timeout because window gets focused when you click on the minimize button
4414		setTimeout(function(){
4415			windowEl.setStyle('zIndex', 1);
4416			windowEl.removeClass('isFocused');
4417			this.makeActiveTab();	
4418		}.bind(this),100);	
4419
4420		currentInstance.fireEvent('onMinimize', windowEl);
4421	},
4422	restoreMinimized: function(windowEl) {
4423
4424		var currentInstance = MochaUI.Windows.instances.get(windowEl.id);
4425
4426		if (currentInstance.isMinimized == false) return;
4427
4428		if (MochaUI.Windows.windowsVisible == false){
4429			MochaUI.toggleWindowVisibility();
4430		}
4431
4432		MochaUI.Desktop.setDesktopSize();
4433
4434		 // Part of Mac FF2 scrollbar fix
4435		if (currentInstance.options.scrollbars == true && !currentInstance.iframeEl){ 
4436			currentInstance.contentWrapperEl.setStyle('overflow', 'auto');
4437		}
4438
4439		if (currentInstance.isCollapsed) {
4440			MochaUI.collapseToggle(windowEl);
4441		}
4442
4443		windowEl.setStyle('visibility', 'visible');
4444		currentInstance.contentBorderEl.setStyle('visibility', 'visible');
4445		if(currentInstance.toolbarWrapperEl){
4446			currentInstance.toolbarWrapperEl.setStyle('visibility', 'visible');
4447		}
4448
4449		// Show iframe
4450		if ( currentInstance.iframeEl ) {
4451			currentInstance.iframeEl.setStyle('visibility', 'visible');
4452		}
4453
4454		currentInstance.isMinimized = false;
4455		MochaUI.focusWindow(windowEl);
4456		currentInstance.fireEvent('onRestore', windowEl);
4457
4458	}
4459});
4460MochaUI.Dock.implement(new Options, new Events);
4461/*
4462
4463Script: Workspaces.js
4464	Save and load workspaces. The Workspaces emulate Adobe Illustrator functionality remembering what windows are open and where they are positioned. There will be two versions, a limited version that saves state to a cookie, and a fully functional version that saves state to a database.
4465
4466Copyright:
4467	Copyright (c) 2007-2008 Greg Houston, <http://greghoustondesign.com/>.
4468
4469License:
4470	MIT-style license.
4471
4472Requires:
4473	Core.js, Window.js
4474
4475To do:
4476	- Move to Window
4477
4478*/
4479
4480MochaUI.extend({			   
4481	/*
4482	
4483	Function: saveWorkspace
4484		Save the current workspace.
4485	
4486	Syntax:
4487	(start code)
4488		MochaUI.saveWorkspace();
4489	(end)
4490	
4491	Notes:
4492		This is experimental. This version saves the ID of each open window to a cookie, and reloads those windows using the functions in mocha-init.js. This requires that each window have a function in mocha-init.js used to open them. Functions must be named the windowID + "Window". So if your window is called mywindow, it needs a function called mywindowWindow in mocha-init.js.
4493	
4494	*/
4495	saveWorkspace: function(){
4496		this.cookie = new Hash.Cookie('mochaUIworkspaceCookie', {duration: 3600});
4497		this.cookie.empty();
4498		MochaUI.Windows.instances.each(function(instance) {
4499			instance.saveValues();
4500			this.cookie.set(instance.options.id, {
4501				'id': instance.options.id,
4502				'top': instance.options.y,
4503				'left': instance.options.x
4504			});
4505		}.bind(this));
4506		this.cookie.save();
4507
4508		new MochaUI.Window({
4509			loadMethod: 'html',
4510			type: 'notification',
4511			addClass: 'notification',
4512			content: 'Workspace saved.',
4513			closeAfter: '1400',
4514			width: 200,
4515			height: 40,
4516			y: 53,
4517			padding:  { top: 10, right: 12, bottom: 10, left: 12 },
4518			shadowBlur: 5,
4519			bodyBgColor: [255, 255, 255]
4520		});
4521		
4522	},
4523	windowUnload: function(){
4524		if ($$('div.mocha').length == 0 && this.myChain){
4525			this.myChain.callChain();
4526		}		
4527	},
4528	loadWorkspace2: function(workspaceWindows){		
4529		workspaceWindows.each(function(instance){
4530			windowFunction = eval('MochaUI.' + instance.id + 'Window');
4531			if (windowFunction){
4532				eval('MochaUI.' + instance.id + 'Window();');
4533				$(instance.id).setStyles({
4534					top: instance.top,
4535					left: instance.left
4536				});
4537			}
4538		}.bind(this));
4539		this.loadingWorkspace = false;
4540	},
4541	/*
4542
4543	Function: loadWorkspace
4544		Load the saved workspace.
4545
4546	Syntax:
4547	(start code)
4548		MochaUI.loadWorkspace();
4549	(end)
4550
4551	*/
4552	loadWorkspace: function(){
4553		cookie = new Hash.Cookie('mochaUIworkspaceCookie', {duration: 3600});
4554		workspaceWindows = cookie.load();
4555
4556		if(!cookie.getKeys().length){
4557			new MochaUI.Window({
4558				loadMethod: 'html',
4559				type: 'notification',
4560				addClass: 'notification',
4561				content: 'You have no saved workspace.',
4562				closeAfter: '1400',
4563				width: 220,
4564				height: 40,
4565				y: 25,
4566				padding:  { top: 10, right: 12, bottom: 10, left: 12 },
4567				shadowBlur: 5,
4568				bodyBgColor: [255, 255, 255]
4569			});
4570			return;
4571		}
4572
4573		if ($$('div.mocha').length != 0){
4574			this.loadingWorkspace = true;
4575			this.myChain = new Chain();
4576			this.myChain.chain(
4577				function(){
4578					$$('div.mocha').each(function(el) {
4579						this.closeWindow(el);
4580					}.bind(this));
4581				}.bind(this),
4582				function(){
4583					this.loadWorkspace2(workspaceWindows);
4584				}.bind(this)
4585			);
4586			this.myChain.callChain();
4587		}
4588		else {
4589			this.loadWorkspace2(workspaceWindows);
4590		}
4591
4592	}
4593});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.