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