4 MUI - A Web Applications User Interface Framework.
7 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
17 This documentation is taken directly from the javascript source files. It is built using Natural Docs.
21 var MUI = MochaUI = new Hash({
23 version: '0.9.6 development',
27 advancedEffects: false, // Effects that require fast browsers and are cpu intensive.
28 standardEffects: true // Basic effects that tend to run smoothly.
32 source: 'scripts/source/', // Path to MochaUI source JavaScript
33 themes: 'themes/', // Path to MochaUI Themes
34 plugins: 'plugins/' // Path to Plugins
37 // Returns the path to the current theme directory
38 themePath: function(){
39 return MUI.path.themes + MUI.options.theme + '/';
46 MUI.files[MUI.path.source + 'Core/Core.js'] = 'loaded';
54 ieSupport: 'excanvas', // Makes it easier to switch between Excanvas and Moocanvas for testing
56 ieLegacySupport: Browser.Engine.trident && Browser.version < 9,
60 Function: updateContent
61 Replace the content of a window or panel.
64 updateOptions - (object)
67 element - The parent window or panel.
68 childElement - The child element of the window or panel receiving the content.
69 method - ('get', or 'post') The way data is transmitted.
70 data - (hash) Data to be transmitted
71 title - (string) Change this if you want to change the title of the window or panel.
72 content - (string or element) An html loadMethod option.
73 loadMethod - ('html', 'xhr', or 'iframe')
74 url - Used if loadMethod is set to 'xhr' or 'iframe'.
75 scrollbars - (boolean)
77 onContentLoaded - (function)
80 updateContent: function(options){
82 var options = $extend({
94 onContentLoaded: $empty
97 options.require = $extend({
98 css: [], images: [], js: [], onload: null
103 if (!options.element) return;
104 var element = options.element;
106 if (MUI.Windows.instances.get(element.id)){
107 args.recipient = 'window';
110 args.recipient = 'panel';
113 var instance = element.retrieve('instance');
114 if (options.title) instance.titleEl.set('html', options.title);
116 var contentEl = instance.contentEl;
117 args.contentContainer = options.childElement != null ? options.childElement : instance.contentEl;
118 var contentWrapperEl = instance.contentWrapperEl;
120 if (!options.loadMethod){
121 if (!instance.options.loadMethod){
123 options.loadMethod = 'html';
126 options.loadMethod = 'xhr';
130 options.loadMethod = instance.options.loadMethod;
134 // Set scrollbars if loading content in main content container.
135 // Always use 'hidden' for iframe windows
136 var scrollbars = options.scrollbars || instance.options.scrollbars;
137 if (args.contentContainer == instance.contentEl) {
138 contentWrapperEl.setStyles({
139 'overflow': scrollbars != false && options.loadMethod != 'iframe' ? 'auto' : 'hidden'
143 if (options.padding != null) {
144 contentEl.setStyles({
145 'padding-top': options.padding.top,
146 'padding-bottom': options.padding.bottom,
147 'padding-left': options.padding.left,
148 'padding-right': options.padding.right
152 // Remove old content.
153 if (args.contentContainer == contentEl) {
154 contentEl.empty().show();
155 // Panels are not loaded into the padding div, so we remove them separately.
156 contentEl.getAllNext('.column').destroy();
157 contentEl.getAllNext('.columnHandle').destroy();
160 args.onContentLoaded = function(){
162 if (options.require.js.length || typeof options.require.onload == 'function'){
164 js: options.require.js,
166 if (!$defined(options.require.onload))
168 if (Browser.Engine.presto){
169 options.require.onload.delay(100);
172 options.require.onload();
174 options.onContentLoaded ? options.onContentLoaded() : instance.fireEvent('onContentLoaded', element);
179 options.onContentLoaded ? options.onContentLoaded() : instance.fireEvent('onContentLoaded', element);
184 if (options.require.css.length || options.require.images.length){
186 css: options.require.css,
187 images: options.require.images,
189 this.loadSelect(instance, options, args);
194 this.loadSelect(instance, options, args);
198 loadSelect: function(instance, options, args){
201 switch(options.loadMethod){
203 this.updateContentXHR(instance, options, args);
206 this.updateContentIframe(instance, options, args);
210 this.updateContentHTML(instance, options, args);
216 updateContentXHR: function(instance, options, args){
217 var contentEl = instance.contentEl;
218 var contentContainer = args.contentContainer;
219 var onContentLoaded = args.onContentLoaded;
222 update: contentContainer,
223 method: options.method != null ? options.method : 'get',
224 data: options.data != null ? new Hash(options.data).toQueryString() : '',
225 evalScripts: instance.options.evalScripts,
226 evalResponse: instance.options.evalResponse,
227 onRequest: function(){
228 if (args.recipient == 'window' && contentContainer == contentEl){
229 instance.showSpinner();
231 else if (args.recipient == 'panel' && contentContainer == contentEl && $('spinner')){
235 onFailure: function(response){
236 if (contentContainer == contentEl){
237 var getTitle = new RegExp("<title>[\n\r\s]*(.*)[\n\r\s]*</title>", "gmi");
238 var error = getTitle.exec(response.responseText);
239 if (!error) error = 'Unknown';
240 contentContainer.set('html', '<h3>Error: ' + error + '</h3>');
241 if (args.recipient == 'window'){
242 instance.hideSpinner();
244 else if (args.recipient == 'panel' && $('spinner')){
249 onSuccess: function(){
250 if (contentContainer == contentEl){
251 if (args.recipient == 'window') instance.hideSpinner();
252 else if (args.recipient == 'panel' && $('spinner')) $('spinner').hide();
254 Browser.Engine.trident4 ? onContentLoaded.delay(750) : onContentLoaded();
256 onComplete: function(){}.bind(this)
260 updateContentIframe: function(instance, options, args){
261 var contentEl = instance.contentEl;
262 var contentContainer = args.contentContainer;
263 var contentWrapperEl = instance.contentWrapperEl;
264 var onContentLoaded = args.onContentLoaded;
265 if ( instance.options.contentURL == '' || contentContainer != contentEl) {
268 instance.iframeEl = new Element('iframe', {
269 'id': instance.options.id + '_iframe',
270 'name': instance.options.id + '_iframe',
271 'class': 'mochaIframe',
278 'height': contentWrapperEl.offsetHeight - contentWrapperEl.getStyle('margin-top').toInt() - contentWrapperEl.getStyle('margin-bottom').toInt(),
279 'width': instance.panelEl ? contentWrapperEl.offsetWidth - contentWrapperEl.getStyle('margin-left').toInt() - contentWrapperEl.getStyle('margin-right').toInt() : '100%'
281 }).injectInside(contentEl);
283 // Add onload event to iframe so we can hide the spinner and run onContentLoaded()
284 instance.iframeEl.addEvent('load', function(e) {
285 if (args.recipient == 'window') instance.hideSpinner();
286 else if (args.recipient == 'panel' && contentContainer == contentEl && $('spinner')) $('spinner').hide();
287 Browser.Engine.trident4 ? onContentLoaded.delay(50) : onContentLoaded();
289 if (args.recipient == 'window') instance.showSpinner();
290 else if (args.recipient == 'panel' && contentContainer == contentEl && $('spinner')) $('spinner').show();
293 updateContentHTML: function(instance, options, args){
294 var contentEl = instance.contentEl;
295 var contentContainer = args.contentContainer;
296 var onContentLoaded = args.onContentLoaded;
297 var elementTypes = new Array('element', 'textnode', 'whitespace', 'collection');
299 if (elementTypes.contains($type(options.content))){
300 options.content.inject(contentContainer);
302 contentContainer.set('html', options.content);
304 if (contentContainer == contentEl){
305 if (args.recipient == 'window') instance.hideSpinner();
306 else if (args.recipient == 'panel' && $('spinner')) $('spinner').hide();
308 Browser.Engine.trident4 ? onContentLoaded.delay(50) : onContentLoaded();
313 Function: reloadIframe
314 Reload an iframe. Fixes an issue in Firefox when trying to use location.reload on an iframe that has been destroyed and recreated.
317 iframe - This should be both the name and the id of the iframe.
321 MUI.reloadIframe(element);
325 To reload an iframe from within another iframe:
327 parent.MUI.reloadIframe('myIframeName');
331 reloadIframe: function(iframe){
332 Browser.Engine.gecko ? $(iframe).src = $(iframe).src : top.frames[iframe].location.reload(true);
335 roundedRect: function(ctx, x, y, width, height, radius, rgb, a){
336 ctx.fillStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
338 ctx.moveTo(x, y + radius);
339 ctx.lineTo(x, y + height - radius);
340 ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
341 ctx.lineTo(x + width - radius, y + height);
342 ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
343 ctx.lineTo(x + width, y + radius);
344 ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
345 ctx.lineTo(x + radius, y);
346 ctx.quadraticCurveTo(x, y, x, y + radius);
350 triangle: function(ctx, x, y, width, height, rgb, a){
352 ctx.moveTo(x + width, y);
353 ctx.lineTo(x, y + height);
354 ctx.lineTo(x + width, y + height);
356 ctx.fillStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
360 circle: function(ctx, x, y, diameter, rgb, a){
362 ctx.arc(x, y, diameter, 0, Math.PI*2, true);
363 ctx.fillStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
367 notification: function(message){
371 type: 'notification',
372 addClass: 'notification',
377 padding: { top: 10, right: 12, bottom: 10, left: 12 },
384 Function: toggleEffects
385 Turn effects on and off
388 toggleAdvancedEffects: function(link){
389 if (MUI.options.advancedEffects == false) {
390 MUI.options.advancedEffects = true;
392 this.toggleAdvancedEffectsLink = new Element('div', {
394 'id': 'toggleAdvancedEffects_check'
399 MUI.options.advancedEffects = false;
400 if (this.toggleAdvancedEffectsLink) {
401 this.toggleAdvancedEffectsLink.destroy();
407 Function: toggleStandardEffects
408 Turn standard effects on and off
411 toggleStandardEffects: function(link){
412 if (MUI.options.standardEffects == false) {
413 MUI.options.standardEffects = true;
415 this.toggleStandardEffectsLink = new Element('div', {
417 'id': 'toggleStandardEffects_check'
422 MUI.options.standardEffects = false;
423 if (this.toggleStandardEffectsLink) {
424 this.toggleStandardEffectsLink.destroy();
431 The underlay is inserted directly under windows when they are being dragged or resized
432 so that the cursor is not captured by iframes or other plugins (such as Flash)
433 underneath the window.
436 underlayInitialize: function(){
437 var windowUnderlay = new Element('div', {
438 'id': 'windowUnderlay',
440 'height': parent.getCoordinates().height,
444 }).inject(document.body);
446 setUnderlaySize: function(){
447 $('windowUnderlay').setStyle('height', parent.getCoordinates().height);
454 Bob Osola's PngFix for IE6.
458 <img src="xyz.png" alt="foo" width="10" height="20" onload="fixPNG(this)">
462 You must have the image height and width attributes specified in the markup.
466 function fixPNG(myImage){
467 if (Browser.Engine.trident4 && document.body.filters){
468 var imgID = (myImage.id) ? "id='" + myImage.id + "' " : "";
469 var imgClass = (myImage.className) ? "class='" + myImage.className + "' " : "";
470 var imgTitle = (myImage.title) ? "title='" + myImage.title + "' " : "title='" + myImage.alt + "' ";
471 var imgStyle = "display:inline-block;" + myImage.style.cssText;
472 var strNewHTML = "<span " + imgID + imgClass + imgTitle
473 + " style=\"" + "width:" + myImage.width
474 + "px; height:" + myImage.height
475 + "px;" + imgStyle + ";"
476 + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
477 + "(src=\'" + myImage.src + "\', sizingMethod='scale');\"></span>";
478 myImage.outerHTML = strNewHTML;
482 // Blur all windows if user clicks anywhere else on the page
483 document.addEvent('mousedown', function(event){
484 MUI.blurAll.delay(50);
487 window.addEvent('domready', function(){
488 MUI.underlayInitialize();
491 window.addEvent('resize', function(){
492 if ($('windowUnderlay')) {
493 MUI.setUnderlaySize();
496 MUI.underlayInitialize();
502 this.setStyle('display', 'none');
506 this.setStyle('display', 'block');
513 Shake effect by Uvumi Tools
514 http://tools.uvumi.com/element-shake.html
521 $('parametrics').shake()
527 shake: function(radius,duration){
528 radius = radius || 3;
529 duration = duration || 500;
530 duration = (duration/50).toInt() - 1;
531 var parent = this.getParent();
532 if(parent != $(document.body) && parent.getStyle('position') == 'static'){
533 parent.setStyle('position','relative');
535 var position = this.getStyle('position');
536 if(position == 'static'){
537 this.setStyle('position','relative');
538 position = 'relative';
540 if(MUI.ieLegacySupport){
541 parent.setStyle('height',parent.getStyle('height'));
543 var coords = this.getPosition(parent);
544 if(position == 'relative' && !Browser.Engine.presto){
545 coords.x -= parent.getStyle('paddingLeft').toInt();
546 coords.y -= parent.getStyle('paddingTop').toInt();
548 var morph = this.retrieve('morph');
551 var oldOptions = morph.options;
553 var morph = this.get('morph',{
557 for(var i=0 ; i < duration ; i++){
559 top:coords.y+$random(-radius,radius),
560 left:coords.x+$random(-radius,radius)
568 this.set('morph',oldOptions);
577 parseQueryString: function() {
578 var vars = this.split(/[&;]/);
580 if (vars.length) vars.each(function(val) {
581 var keys = val.split('=');
582 if (keys.length && keys.length == 2) rs[decodeURIComponent(keys[0])] = decodeURIComponent(keys[1]);
589 // Mootools Patch: Fixes issues in Safari, Chrome, and Internet Explorer caused by processing text as XML.
590 Request.HTML.implement({
592 processHTML: function(text){
593 var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
594 text = (match) ? match[1] : text;
595 var container = new Element('div');
596 return container.set('html', text);
605 getCSSRule('.myRule');
606 getCSSRule('#myRule');
610 MUI.getCSSRule = function(selector) {
611 for (var ii = 0; ii < document.styleSheets.length; ii++) {
612 var mysheet = document.styleSheets[ii];
613 var myrules = mysheet.cssRules ? mysheet.cssRules : mysheet.rules;
614 for (i = 0; i < myrules.length; i++){
615 if (myrules[i].selectorText == selector){
623 // This makes it so Request will work to some degree locally
624 if (location.protocol == "file:"){
627 isSuccess : function(status){
628 return (status == 0 || (status >= 200) && (status < 300));
632 Browser.Request = function(){
633 return $try(function(){
634 return new ActiveXObject('MSXML2.XMLHTTP');
636 return new XMLHttpRequest();
642 MUI.Require = new Class({
644 Implements: [Options],
653 initialize: function(options){
654 this.setOptions(options);
655 var options = this.options;
657 this.assetsToLoad = options.css.length + options.images.length + options.js.length;
658 this.assetsLoaded = 0;
662 // Load CSS before images and JavaScript
664 if (options.css.length){
665 options.css.each( function(sheet){
667 this.getAsset(sheet, function(){
668 if (cssLoaded == options.css.length - 1){
670 if (this.assetsLoaded == this.assetsToLoad - 1){
671 this.requireOnload();
674 // Add a little delay since we are relying on cached CSS from XHR request.
676 this.requireContinue.delay(50, this);
686 else if (!options.js.length && !options.images.length){
687 this.options.onload();
691 this.requireContinue.delay(50, this); // Delay is for Safari
696 requireOnload: function(){
698 if (this.assetsLoaded == this.assetsToLoad){
699 this.options.onload();
705 requireContinue: function(){
707 var options = this.options;
708 if (options.images.length){
709 options.images.each( function(image){
710 this.getAsset(image, this.requireOnload.bind(this));
714 if (options.js.length){
715 options.js.each( function(script){
716 this.getAsset(script, this.requireOnload.bind(this));
722 getAsset: function(source, onload){
724 // If the asset is loaded, fire the onload function.
725 if ( MUI.files[source] == 'loaded' ){
726 if (typeof onload == 'function'){
732 // If the asset is loading, wait until it is loaded and then fire the onload function.
733 // If asset doesn't load by a number of tries, fire onload anyway.
734 else if ( MUI.files[source] == 'loading' ){
736 var checker = (function(){
738 if (MUI.files[source] == 'loading' && tries < '100') return;
740 if (typeof onload == 'function'){
746 // If the asset is not yet loaded or loading, start loading the asset.
748 MUI.files[source] = 'loading';
751 'onload': onload != 'undefined' ? onload : $empty
754 // Add to the onload function
755 var oldonload = properties.onload;
756 properties.onload = function() {
757 MUI.files[source] = 'loaded';
763 switch ( source.match(/\.\w+$/)[0] ) {
764 case '.js': return Asset.javascript(source, properties);
765 case '.css': return Asset.css(source, properties);
768 case '.gif': return Asset.image(source, properties);
771 alert('The required file "' + source + '" could not be loaded');
779 /* Fix an Opera bug in Mootools 1.2 */
780 javascript: function(source, properties){
781 properties = $extend({
787 if ($(properties.id)) {
789 return $(properties.id);
792 var script = new Element('script', {'src': source, 'type': 'text/javascript'});
794 var load = properties.onload.bind(script), check = properties.check, doc = properties.document;
795 delete properties.onload; delete properties.check; delete properties.document;
797 if (!Browser.Engine.webkit419 && !Browser.Engine.presto){
800 readystatechange: function(){
801 if (MUI.ieLegacySupport && ['loaded', 'complete'].contains(this.readyState))
804 }).setProperties(properties);
807 var checker = (function(){
808 if (!$try(check)) return;
810 // Opera has difficulty with multiple scripts being injected into the head simultaneously. We need to give it time to catch up.
811 Browser.Engine.presto ? load.delay(500) : load();
814 return script.inject(doc.head);
817 // Get the CSS with XHR before appending it to document.head so that we can have an onload callback.
818 css: function(source, properties){
820 properties = $extend({
829 onComplete: function(response) {
830 var newSheet = new Element('link', {
833 'media': properties.media,
836 }).inject(document.head);
839 onFailure: function(response){
841 onSuccess: function(){
852 Register Components and Plugins for Lazy Loading
854 How this works may take a moment to grasp. Take a look at MUI.Window below.
855 If we try to create a new Window and Window.js has not been loaded then the function
856 below will run. It will load the CSS required by the MUI.Window Class and then
857 then it will load Window.js. Here is the interesting part. When Window.js loads,
858 it will overwrite the function below, and new MUI.Window(arg) will be ran
859 again. This time it will create a new MUI.Window instance, and any future calls
860 to new MUI.Window(arg) will immediately create new windows since the assets
861 have already been loaded and our temporary function below has been overwritten.
867 MyGadget: function(arg){
869 css: [MUI.path.plugins + 'myGadget/css/style.css'],
870 images: [MUI.path.plugins + 'myGadget/images/background.gif']
871 js: [MUI.path.plugins + 'myGadget/scripts/myGadget.js'],
873 new MyPlguins.MyGadget(arg);
880 -------------------------------------------------------------------- */
884 newWindowsFromJSON: function(arg){
886 js: [MUI.path.source + 'Window/Windows-from-json.js'],
888 new MUI.newWindowsFromJSON(arg);
893 arrangeCascade: function(){
895 js: [MUI.path.source + 'Window/Arrange-cascade.js'],
897 new MUI.arrangeCascade();
902 arrangeTile: function(){
904 js: [MUI.path.source + 'Window/Arrange-tile.js'],
906 new MUI.arrangeTile();
911 saveWorkspace: function(){
913 js: [MUI.path.source + 'Layout/Workspaces.js'],
915 new MUI.saveWorkspace();
920 loadWorkspace: function(){
922 js: [MUI.path.source + 'Layout/Workspaces.js'],
924 new MUI.loadWorkspace();
932 js: [MUI.path.source + 'Utilities/Themes.js'],
934 MUI.Themes.init(arg);
944 Allows for switching themes dynamically.
947 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
956 Themes are new and experimental.
960 new MUI.Themes.init(newTheme);
965 new MUI.Themes.init('charcoal');
969 newTheme - (string) The theme name
973 MUI.files[MUI.path.source + 'Utilities/Themes.js'] = 1;
980 Initialize a theme. This is experimental and not fully implemented yet.
983 init: function(newTheme){
984 this.newTheme = newTheme.toLowerCase();
985 if (!this.newTheme || this.newTheme == null || this.newTheme == MUI.options.theme.toLowerCase()) return;
987 if ($('spinner')) $('spinner').show();
992 $$('link').each( function(link){
993 var href = link.get('href');
994 if (href.contains(MUI.path.themes + MUI.options.theme)){
995 this.oldURIs.push(href);
996 this.oldSheets.push(link);
1001 MUI.files.each( function(value, key, hash){
1002 if (key.contains(MUI.path.themes + MUI.options.theme)){
1003 this.oldURIs.push(key);
1008 this.newSheetURLs = this.oldURIs.map(function(item, index){
1009 return item.replace("/" + MUI.options.theme + "/", "/" + MUI.Themes.newTheme + "/");
1012 this.sheetsToLoad = this.oldURIs.length;
1013 this.sheetsLoaded = 0;
1015 // Download new stylesheets and add them to an array
1016 this.newSheets = [];
1017 this.newSheetURLs.each( function(link){
1022 var cssRequest = new Request({
1025 onComplete: function(response) {
1026 var newSheet = new Element('link', {
1028 'rel': 'stylesheet',
1033 this.newSheets.push(newSheet);
1035 onFailure: function(response){
1036 this.themeLoadSuccess = false;
1037 if ($('spinner')) $('spinner').hide();
1038 MUI.notification('Stylesheets did not load.');
1040 onSuccess: function(){
1041 this.sheetsLoaded++;
1042 if (this.sheetsLoaded == this.sheetsToLoad) {
1043 this.updateThemeStylesheets();
1044 this.themeLoadSuccess = true;
1053 updateThemeStylesheets: function(){
1055 this.oldSheets.each( function(sheet){
1059 this.newSheets.each( function(sheet){
1060 MUI.files[sheet.get('href')] = 1;
1061 sheet.inject(document.head);
1064 // Delay gives the stylesheets time to take effect. IE6 needs more delay.
1065 if (MUI.ieLegacySupport){
1066 this.redraw.delay(1250, this);
1069 this.redraw.delay(250, this);
1075 $$('.replaced').removeClass('replaced');
1077 // Redraw open windows
1078 $$('.mocha').each( function(element){
1079 var instance = element.retrieve('instance');
1081 // Convert CSS colors to Canvas colors.
1082 instance.setColors();
1083 instance.drawWindow();
1087 if (MUI.Dock.options.useControls){
1088 MUI.Dock.setDockColors();
1089 MUI.Dock.renderDockControls();
1094 if (MUI.Desktop.desktop){
1095 var checker = (function(){
1096 // Make sure the style sheets are really ready.
1097 if (MUI.Desktop.desktop.getStyle('overflow') != 'hidden'){
1101 MUI.Desktop.setDesktopSize();
1105 if ($('spinner')) $('spinner').hide();
1106 MUI.options.theme = this.newTheme;
1109 this.cookie = new Hash.Cookie('mochaUIthemeCookie', {duration: 3600});
1110 this.cookie.empty();
1111 this.cookie.set('theme', MUI.options.theme);
1118 window.addEvent('load', function(){
1120 // Load theme the user was last using. This needs work.
1121 var cookie = new Hash.Cookie('mochaUIthemeCookie', {duration: 3600});
1122 var themeCookie = cookie.load();
1123 if(cookie.getKeys().length){
1124 if (themeCookie.get('theme') != MUI.Themes.options.theme){
1125 MUI.Themes.init.delay(1000, MUI.Themes, themeCookie.get('theme'));
1130 if ($('themeControl')){
1131 $('themeControl').getElements('option').setProperty('selected', 'false');
1132 if ($('chooseTheme')){
1133 $('chooseTheme').setProperty('selected', 'true');
1143 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
1153 MUI.files[MUI.path.source + 'Window/Window.js'] = 'loading';
1154 //$require(MUI.themePath() + '/css/Dock.css');
1158 Creates a single MochaUI window.
1162 new MUI.Window(options);
1169 id - The ID of the window. If not defined, it will be set to 'win' + windowIDCount.
1170 title - The title of the window.
1171 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.
1172 type - ('window', 'modal', 'modal2', or 'notification') Defaults to 'window'. Modals should be created with new MUI.Modal(options).
1173 loadMethod - ('html', 'xhr', or 'iframe') Defaults to 'html' if there is no contentURL. Defaults to 'xhr' if there is a contentURL. You only really need to set this if using the 'iframe' method.
1174 contentURL - Used if loadMethod is set to 'xhr' or 'iframe'.
1175 closeAfter - Either false or time in milliseconds. Closes the window after a certain period of time in milliseconds. This is particularly useful for notifications.
1176 evalScripts - (boolean) An xhr loadMethod option. Defaults to true.
1177 evalResponse - (boolean) An xhr loadMethod option. Defaults to false.
1178 content - (string or element) An html loadMethod option.
1179 toolbar - (boolean) Create window toolbar. Defaults to false. This can be used for tabs, media controls, and so forth.
1180 toolbarPosition - ('top' or 'bottom') Defaults to top.
1181 toolbarHeight - (number)
1182 toolbarURL - (url) Defaults to 'pages/lipsum.html'.
1183 toolbarContent - (string)
1184 toolbarOnload - (function)
1185 toolbar2 - (boolean) Create window toolbar. Defaults to false. This can be used for tabs, media controls, and so forth.
1186 toolbar2Position - ('top' or 'bottom') Defaults to top.
1187 toolbar2Height - (number)
1188 toolbar2URL - (url) Defaults to 'pages/lipsum.html'.
1189 toolbar2Content - (string)
1190 toolbar2Onload - (function)
1191 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.
1192 restrict - (boolean) Restrict window to container when dragging.
1193 shape - ('box' or 'gauge') Shape of window. Defaults to 'box'.
1194 collapsible - (boolean) Defaults to true.
1195 minimizable - (boolean) Requires MUI.Desktop and MUI.Dock. Defaults to true if dependenices are met.
1196 maximizable - (boolean) Requires MUI.Desktop. Defaults to true if dependenices are met.
1197 closable - (boolean) Defaults to true.
1198 storeOnClose - (boolean) Hides a window and it's dock tab rather than destroying them on close. If you try to create the window again it will unhide the window and dock tab.
1199 modalOverlayClose - (boolean) Whether or not you can close a modal by clicking on the modal overlay. Defaults to true.
1200 draggable - (boolean) Defaults to false for modals; otherwise true.
1201 draggableGrid - (false or number) Distance in pixels for snap-to-grid dragging. Defaults to false.
1202 draggableLimit - (false or number) An object with x and y properties used to limit the movement of the Window. Defaults to false.
1203 draggableSnap - (boolean) The distance to drag before the Window starts to respond to the drag. Defaults to false.
1204 resizable - (boolean) Defaults to false for modals, notifications and gauges; otherwise true.
1205 resizeLimit - (object) Minimum and maximum width and height of window when resized.
1206 addClass - (string) Add a class to the window for more control over styling.
1207 width - (number) Width of content area.
1208 height - (number) Height of content area.
1209 headerHeight - (number) Height of window titlebar.
1210 footerHeight - (number) Height of window footer.
1211 cornerRadius - (number)
1212 x - (number) If x and y are left undefined the window is centered on the page.
1214 scrollbars - (boolean)
1216 shadowBlur - (number) Width of shadows.
1217 shadowOffset - Should be positive and not be greater than the ShadowBlur.
1218 controlsOffset - Change this if you want to reposition the window controls.
1219 useCanvas - (boolean) Set this to false if you don't want a canvas body.
1220 useCanvasControls - (boolean) Set this to false if you wish to use images for the buttons.
1221 useSpinner - (boolean) Toggles whether or not the ajax spinners are displayed in window footers. Defaults to true.
1222 headerStartColor - ([r,g,b,]) Titlebar gradient's top color
1223 headerStopColor - ([r,g,b,]) Titlebar gradient's bottom color
1224 bodyBgColor - ([r,g,b,]) Background color of the main canvas shape
1225 minimizeBgColor - ([r,g,b,]) Minimize button background color
1226 minimizeColor - ([r,g,b,]) Minimize button color
1227 maximizeBgColor - ([r,g,b,]) Maximize button background color
1228 maximizeColor - ([r,g,b,]) Maximize button color
1229 closeBgColor - ([r,g,b,]) Close button background color
1230 closeColor - ([r,g,b,]) Close button color
1231 resizableColor - ([r,g,b,]) Resizable icon color
1232 onBeforeBuild - (function) Fired just before the window is built.
1233 onContentLoaded - (function) Fired when content is successfully loaded via XHR or Iframe.
1234 onFocus - (function) Fired when the window is focused.
1235 onBlur - (function) Fired when window loses focus.
1236 onResize - (function) Fired when the window is resized.
1237 onMinimize - (function) Fired when the window is minimized.
1238 onMaximize - (function) Fired when the window is maximized.
1239 onRestore - (function) Fired when a window is restored from minimized or maximized.
1240 onClose - (function) Fired just before the window is closed.
1241 onCloseComplete - (function) Fired after the window is closed.
1247 Define a window. It is suggested you name the function the same as your window ID + "Window".
1249 var mywindowWindow = function(){
1254 contentURL: 'pages/lipsum.html',
1262 Create window onDomReady.
1264 window.addEvent('domready', function(){
1270 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.
1272 If you wish to add links in windows that open other windows remember to add events to those links when the windows are created.
1276 if ($('mywindowLink')){
1277 $('mywindowLink').addEvent('click', function(e) {
1278 new Event(e).stop();
1284 <a id="mywindowLink" href="pages/lipsum.html">My Window</a>
1288 Loading Content with an XMLHttpRequest(xhr):
1289 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.
1292 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.
1296 // Having these options outside of the Class allows us to add, change, and remove
1297 // individual options without rewriting all of them.
1301 instances: new Hash(),
1302 indexLevel: 100, // Used for window z-Index
1303 windowIDCount: 0, // Used for windows without an ID defined by the user
1304 windowsVisible: true, // Ctrl-Alt-Q to toggle window visibility
1305 focusingWindow: false
1309 MUI.Windows.windowOptions = {
1311 title: 'New Window',
1329 evalResponse: false,
1332 content: 'Window content',
1336 toolbarPosition: 'top',
1338 toolbarURL: 'pages/lipsum.html',
1341 toolbarOnload: $empty,
1345 toolbar2Position: 'bottom',
1347 toolbar2URL: 'pages/lipsum.html',
1349 toolbar2Content: '',
1350 toolbar2Onload: $empty,
1352 // Container options
1364 storeOnClose: false,
1367 modalOverlayClose: true,
1371 draggableGrid: false,
1372 draggableLimit: false,
1373 draggableSnap: false,
1377 resizeLimit: {'x': [250, 2500], 'y': [125, 2000]},
1389 padding: { top: 10, right: 12, bottom: 10, left: 12 },
1391 shadowOffset: {'x': 0, 'y': 1},
1392 controlsOffset: {'right': 6, 'top': 6},
1394 useCanvasControls: true,
1398 headerStartColor: [250, 250, 250],
1399 headerStopColor: [229, 229, 229],
1400 bodyBgColor: [229, 229, 229],
1401 minimizeBgColor: [255, 255, 255],
1402 minimizeColor: [0, 0, 0],
1403 maximizeBgColor: [255, 255, 255],
1404 maximizeColor: [0, 0, 0],
1405 closeBgColor: [255, 255, 255],
1406 closeColor: [0, 0, 0],
1407 resizableColor: [254, 254, 254],
1410 onBeforeBuild: $empty,
1411 onContentLoaded: $empty,
1419 onCloseComplete: $empty
1422 MUI.Windows.windowOptionsOriginal = $merge(MUI.Windows.windowOptions);
1424 MUI.Window = new Class({
1426 Implements: [Events, Options],
1428 options: MUI.Windows.windowOptions,
1430 initialize: function(options){
1431 this.setOptions(options);
1433 // Shorten object chain
1434 var options = this.options;
1437 mochaControlsWidth: 0,
1438 minimizebuttonX: 0, // Minimize button horizontal position
1439 maximizebuttonX: 0, // Maximize button horizontal position
1440 closebuttonX: 0, // Close button horizontal position
1441 headerFooterShadow: options.headerHeight + options.footerHeight + (options.shadowBlur * 2),
1450 if (options.type != 'window'){
1451 options.container = document.body;
1452 options.minimizable = false;
1454 if (!options.container){
1455 options.container = MUI.Desktop && MUI.Desktop.desktop ? MUI.Desktop.desktop : document.body;
1458 // Set this.options.resizable to default if it was not defined
1459 if (options.resizable == null){
1460 if (options.type != 'window' || options.shape == 'gauge'){
1461 options.resizable = false;
1464 options.resizable = true;
1468 // Set this.options.draggable if it was not defined
1469 if (options.draggable == null){
1470 options.draggable = options.type != 'window' ? false : true;
1473 // Gauges are not maximizable or resizable
1474 if (options.shape == 'gauge' || options.type == 'notification'){
1475 options.collapsible = false;
1476 options.maximizable = false;
1477 options.contentBgColor = 'transparent';
1478 options.scrollbars = false;
1479 options.footerHeight = 0;
1481 if (options.type == 'notification'){
1482 options.closable = false;
1483 options.headerHeight = 0;
1486 // Minimizable, dock is required and window cannot be modal
1487 if (MUI.Dock && $(MUI.options.dock)){
1488 if (MUI.Dock.dock && options.type != 'modal' && options.type != 'modal2'){
1489 options.minimizable = options.minimizable;
1493 options.minimizable = false;
1496 // Maximizable, desktop is required
1497 options.maximizable = MUI.Desktop && MUI.Desktop.desktop && options.maximizable && options.type != 'modal' && options.type != 'modal2';
1499 if (this.options.type == 'modal2') {
1500 this.options.shadowBlur = 0;
1501 this.options.shadowOffset = {'x': 0, 'y': 0};
1502 this.options.useSpinner = false;
1503 this.options.useCanvas = false;
1504 this.options.footerHeight = 0;
1505 this.options.headerHeight = 0;
1508 // If window has no ID, give it one.
1509 options.id = options.id || 'win' + (++MUI.Windows.windowIDCount);
1511 this.windowEl = $(options.id);
1513 if (options.require.css.length || options.require.images.length){
1515 css: options.require.css,
1516 images: options.require.images,
1526 // Return window object
1529 saveValues: function(){
1530 var coordinates = this.windowEl.getCoordinates();
1531 this.options.x = coordinates.left.toInt();
1532 this.options.y = coordinates.top.toInt();
1537 Internal Function: newWindow
1543 newWindow: function(properties){ // options is not doing anything
1545 // Shorten object chain
1546 var instances = MUI.Windows.instances;
1547 var instanceID = MUI.Windows.instances.get(this.options.id);
1548 var options = this.options;
1550 // Here we check to see if there is already a class instance for this window
1551 if (instanceID) var instance = instanceID;
1553 // Check if window already exists and is not in progress of closing
1554 if ( this.windowEl && !this.isClosing ){
1555 // Restore if minimized
1556 if (instance.isMinimized){
1557 MUI.Dock.restoreMinimized(this.windowEl);
1559 // Expand and focus if collapsed
1560 else if (instance.isCollapsed){
1561 MUI.collapseToggle(this.windowEl);
1562 setTimeout(MUI.focusWindow.pass(this.windowEl, this),10);
1564 else if (this.windowEl.hasClass('windowClosed')){
1566 if (instance.check) instance.check.show();
1568 this.windowEl.removeClass('windowClosed');
1569 this.windowEl.setStyle('opacity', 0);
1570 this.windowEl.addClass('mocha');
1572 if (MUI.Dock && $(MUI.options.dock) && instance.options.type == 'window') {
1573 var currentButton = $(instance.options.id + '_dockTab');
1574 if (currentButton != null) {
1575 currentButton.show();
1577 MUI.Desktop.setDesktopSize();
1580 instance.displayNewWindow();
1585 var coordinates = document.getCoordinates();
1586 if (this.windowEl.getStyle('left').toInt() > coordinates.width || this.windowEl.getStyle('top').toInt() > coordinates.height){
1587 MUI.centerWindow(this.windowEl);
1589 setTimeout(MUI.focusWindow.pass(this.windowEl, this),10);
1590 if (MUI.options.standardEffects == true) {
1591 this.windowEl.shake();
1597 instances.set(options.id, this);
1600 this.isClosing = false;
1601 this.fireEvent('onBeforeBuild');
1603 // Create window div
1604 MUI.Windows.indexLevel++;
1605 this.windowEl = new Element('div', {
1609 'position': 'absolute',
1610 'width': options.width,
1611 'height': options.height,
1614 'zIndex': MUI.Windows.indexLevel += 2
1618 this.windowEl.store('instance', this);
1620 this.windowEl.addClass(options.addClass);
1622 if (options.type == 'modal2') {
1623 this.windowEl.addClass('modal2');
1626 // Fix a mouseover issue with gauges in IE7
1627 if ( MUI.ieLegacySupport && options.shape == 'gauge') {
1628 this.windowEl.setStyle('backgroundImage', 'url(../../images/spacer.gif)');
1631 if (options.loadMethod == 'iframe') {
1632 options.padding = { top: 0, right: 0, bottom: 0, left: 0 };
1635 // Insert sub elements inside windowEl
1636 this.insertWindowElements();
1639 this.titleEl.set('html', options.title);
1641 this.contentWrapperEl.setStyle('overflow', 'hidden');
1643 this.contentEl.setStyles({
1644 'padding-top': options.padding.top,
1645 'padding-bottom': options.padding.bottom,
1646 'padding-left': options.padding.left,
1647 'padding-right': options.padding.right
1650 if (options.shape == 'gauge'){
1651 if (options.useCanvasControls){
1652 this.canvasControlsEl.setStyle('visibility', 'hidden');
1655 this.controlsEl.setStyle('visibility', 'hidden');
1657 this.windowEl.addEvent('mouseover', function(){
1658 this.mouseover = true;
1659 var showControls = function(){
1660 if (this.mouseover != false){
1661 if (options.useCanvasControls){
1662 this.canvasControlsEl.setStyle('visibility', 'visible');
1665 this.controlsEl.setStyle('visibility', 'visible');
1667 this.canvasHeaderEl.setStyle('visibility', 'visible');
1668 this.titleEl.show();
1671 showControls.delay(0, this);
1674 this.windowEl.addEvent('mouseleave', function(){
1675 this.mouseover = false;
1676 if (this.options.useCanvasControls){
1677 this.canvasControlsEl.setStyle('visibility', 'hidden');
1680 this.controlsEl.setStyle('visibility', 'hidden');
1682 this.canvasHeaderEl.setStyle('visibility', 'hidden');
1683 this.titleEl.hide();
1687 // Inject window into DOM
1688 this.windowEl.inject(options.container);
1690 // Convert CSS colors to Canvas colors.
1693 if (options.type != 'notification'){
1694 this.setMochaControlsWidth();
1697 // Add content to window.
1699 'element': this.windowEl,
1700 'content': options.content,
1701 'method': options.method,
1702 'url': options.contentURL,
1703 'data': options.data,
1704 'onContentLoaded': null,
1706 js: options.require.js,
1707 onload: options.require.onload
1711 // Add content to window toolbar.
1712 if (this.options.toolbar == true){
1714 'element': this.windowEl,
1715 'childElement': this.toolbarEl,
1716 'content': options.toolbarContent,
1717 'loadMethod': 'xhr',
1718 'method': options.method,
1719 'url': options.toolbarURL,
1720 'data': options.toolbarData,
1721 'onContentLoaded': options.toolbarOnload
1725 // Add content to window toolbar.
1726 if (this.options.toolbar2 == true){
1728 'element': this.windowEl,
1729 'childElement': this.toolbar2El,
1730 'content': options.toolbar2Content,
1731 'loadMethod': 'xhr',
1732 'method': options.method,
1733 'url': options.toolbar2URL,
1734 'data': options.toolbar2Data,
1735 'onContentLoaded': options.toolbar2Onload
1741 // Attach events to the window
1742 this.attachDraggable();
1743 this.attachResizable();
1746 if (options.resizable){
1747 this.adjustHandles();
1750 // Position window. If position not specified by user then center the window on the page.
1751 if (options.container == document.body || options.container == MUI.Desktop.desktop){
1752 var dimensions = window.getSize();
1755 var dimensions = $(this.options.container).getSize();
1759 if (MUI.Desktop && MUI.Desktop.desktop) {
1760 var y = (dimensions.y * .5) - (this.windowEl.offsetHeight * .5);
1761 if (y < -options.shadowBlur) y = -options.shadowBlur;
1764 var y = window.getScroll().y + (window.getSize().y * .5) - (this.windowEl.offsetHeight * .5);
1765 if (y < -options.shadowBlur) y = -options.shadowBlur;
1769 var y = options.y - options.shadowBlur;
1772 if (!this.options.x) {
1773 var x = (dimensions.x * .5) - (this.windowEl.offsetWidth * .5);
1774 if (x < -options.shadowBlur) x = -options.shadowBlur;
1777 var x = options.x - options.shadowBlur;
1780 this.windowEl.setStyles({
1785 // Create opacityMorph
1787 this.opacityMorph = new Fx.Morph(this.windowEl, {
1789 transition: Fx.Transitions.Sine.easeInOut,
1790 onComplete: function(){
1791 if (MUI.ieLegacySupport){
1797 this.displayNewWindow();
1799 // This is a generic morph that can be reused later by functions like centerWindow()
1800 // It returns the windowEl element rather than this Class.
1801 this.morph = new Fx.Morph(this.windowEl, {
1804 this.windowEl.store('morph', this.morph);
1806 this.resizeMorph = new Fx.Elements([this.contentWrapperEl, this.windowEl], {
1808 transition: Fx.Transitions.Sine.easeInOut,
1809 onStart: function(){
1810 this.resizeAnimation = this.drawWindow.periodical(20, this);
1812 onComplete: function(){
1813 $clear(this.resizeAnimation);
1816 if ( this.iframeEl ) {
1817 this.iframeEl.setStyle('visibility', 'visible');
1821 this.windowEl.store('resizeMorph', this.resizeMorph);
1823 // Add check mark to menu if link exists in menu
1824 // Need to make sure the check mark is not added to links not in menu
1825 if ($(this.windowEl.id + 'LinkCheck')){
1826 this.check = new Element('div', {
1828 'id': this.options.id + '_check'
1829 }).inject(this.windowEl.id + 'LinkCheck');
1832 if (this.options.closeAfter != false){
1833 MUI.closeWindow.delay(this.options.closeAfter, this, this.windowEl);
1836 if (MUI.Dock && $(MUI.options.dock) && this.options.type == 'window' ){
1837 MUI.Dock.createDockTab(this.windowEl);
1841 displayNewWindow: function(){
1843 options = this.options;
1844 if (options.type == 'modal' || options.type == 'modal2') {
1845 MUI.currentModal = this.windowEl;
1846 if (Browser.Engine.trident4){
1847 $('modalFix').show();
1849 $('modalOverlay').show();
1850 if (MUI.options.advancedEffects == false){
1851 $('modalOverlay').setStyle('opacity', .6);
1852 this.windowEl.setStyles({
1858 MUI.Modal.modalOverlayCloseMorph.cancel();
1859 MUI.Modal.modalOverlayOpenMorph.start({
1862 this.windowEl.setStyles({
1865 this.opacityMorph.start({
1870 $$('.dockTab').removeClass('activeDockTab');
1871 $$('.mocha').removeClass('isFocused');
1872 this.windowEl.addClass('isFocused');
1875 else if (MUI.options.advancedEffects == false){
1876 this.windowEl.setStyle('opacity', 1);
1877 setTimeout(MUI.focusWindow.pass(this.windowEl, this), 10);
1880 // IE cannot handle both element opacity and VML alpha at the same time.
1881 if (MUI.ieLegacySupport){
1882 this.drawWindow(false);
1884 this.opacityMorph.start({
1887 setTimeout(MUI.focusWindow.pass(this.windowEl, this), 10);
1891 setupEvents: function() {
1892 var windowEl = this.windowEl;
1894 // Note: if a button does not exist, its due to properties passed to newWindow() stating otherwise
1895 if (this.closeButtonEl){
1896 this.closeButtonEl.addEvent('click', function(e) {
1897 new Event(e).stop();
1898 MUI.closeWindow(windowEl);
1902 if (this.options.type == 'window'){
1903 windowEl.addEvent('mousedown', function(e) {
1904 if (MUI.ieLegacySupport) {
1905 new Event(e).stop();
1907 MUI.focusWindow(windowEl);
1908 if (windowEl.getStyle('top').toInt() < -this.options.shadowBlur) {
1909 windowEl.setStyle('top', -this.options.shadowBlur);
1914 if (this.minimizeButtonEl) {
1915 this.minimizeButtonEl.addEvent('click', function(e) {
1916 new Event(e).stop();
1917 MUI.Dock.minimizeWindow(windowEl);
1921 if (this.maximizeButtonEl) {
1922 this.maximizeButtonEl.addEvent('click', function(e) {
1923 new Event(e).stop();
1924 if (this.isMaximized) {
1925 MUI.Desktop.restoreWindow(windowEl);
1927 MUI.Desktop.maximizeWindow(windowEl);
1932 if (this.options.collapsible == true){
1933 // Keep titlebar text from being selected on double click in Safari.
1934 this.titleEl.addEvent('selectstart', function(e) {
1935 e = new Event(e).stop();
1938 if (MUI.ieLegacySupport) {
1939 this.titleBarEl.addEvent('mousedown', function(e) {
1940 this.titleEl.setCapture();
1942 this.titleBarEl.addEvent('mouseup', function(e) {
1943 this.titleEl.releaseCapture();
1947 this.titleBarEl.addEvent('dblclick', function(e) {
1948 e = new Event(e).stop();
1949 MUI.collapseToggle(this.windowEl);
1956 Internal Function: attachDraggable()
1957 Make window draggable.
1960 attachDraggable: function(){
1961 var windowEl = this.windowEl;
1962 if (!this.options.draggable) return;
1963 this.windowDrag = new Drag.Move(windowEl, {
1964 handle: this.titleBarEl,
1965 container: this.options.restrict == true ? $(this.options.container) : false,
1966 grid: this.options.draggableGrid,
1967 limit: this.options.draggableLimit,
1968 snap: this.options.draggableSnap,
1969 onStart: function() {
1970 if (this.options.type != 'modal' && this.options.type != 'modal2'){
1971 MUI.focusWindow(windowEl);
1972 $('windowUnderlay').show();
1974 if (this.iframeEl) {
1975 if (!MUI.ieLegacySupport) {
1976 this.iframeEl.setStyle('visibility', 'hidden');
1979 this.iframeEl.hide();
1983 onComplete: function() {
1984 if (this.options.type != 'modal' && this.options.type != 'modal2') {
1985 $('windowUnderlay').hide();
1987 if ( this.iframeEl ){
1988 if (!MUI.ieLegacySupport) {
1989 this.iframeEl.setStyle('visibility', 'visible');
1992 this.iframeEl.show();
1995 // Store new position in options.
2002 Internal Function: attachResizable
2003 Make window resizable.
2006 attachResizable: function(){
2007 var windowEl = this.windowEl;
2008 if (!this.options.resizable) return;
2009 this.resizable1 = this.windowEl.makeResizable({
2010 handle: [this.n, this.ne, this.nw],
2014 return this.windowEl.getStyle('top').toInt() + this.windowEl.getStyle('height').toInt() - this.options.resizeLimit.y[1];
2017 return this.windowEl.getStyle('top').toInt() + this.windowEl.getStyle('height').toInt() - this.options.resizeLimit.y[0];
2021 modifiers: {x: false, y: 'top'},
2022 onStart: function(){
2023 this.resizeOnStart();
2024 this.coords = this.contentWrapperEl.getCoordinates();
2025 this.y2 = this.coords.top.toInt() + this.contentWrapperEl.offsetHeight;
2028 this.coords = this.contentWrapperEl.getCoordinates();
2029 this.contentWrapperEl.setStyle('height', this.y2 - this.coords.top.toInt());
2030 this.resizeOnDrag();
2032 onComplete: function(){
2033 this.resizeOnComplete();
2037 this.resizable2 = this.contentWrapperEl.makeResizable({
2038 handle: [this.e, this.ne],
2040 x: [this.options.resizeLimit.x[0] - (this.options.shadowBlur * 2), this.options.resizeLimit.x[1] - (this.options.shadowBlur * 2) ]
2042 modifiers: {x: 'width', y: false},
2043 onStart: function(){
2044 this.resizeOnStart();
2047 this.resizeOnDrag();
2049 onComplete: function(){
2050 this.resizeOnComplete();
2054 this.resizable3 = this.contentWrapperEl.makeResizable({
2055 container: this.options.restrict == true ? $(this.options.container) : false,
2058 x: [this.options.resizeLimit.x[0] - (this.options.shadowBlur * 2), this.options.resizeLimit.x[1] - (this.options.shadowBlur * 2) ],
2059 y: [this.options.resizeLimit.y[0] - this.headerFooterShadow, this.options.resizeLimit.y[1] - this.headerFooterShadow]
2061 modifiers: {x: 'width', y: 'height'},
2062 onStart: function(){
2063 this.resizeOnStart();
2066 this.resizeOnDrag();
2068 onComplete: function(){
2069 this.resizeOnComplete();
2073 this.resizable4 = this.contentWrapperEl.makeResizable({
2074 handle: [this.s, this.sw],
2076 y: [this.options.resizeLimit.y[0] - this.headerFooterShadow, this.options.resizeLimit.y[1] - this.headerFooterShadow]
2078 modifiers: {x: false, y: 'height'},
2079 onStart: function(){
2080 this.resizeOnStart();
2083 this.resizeOnDrag();
2085 onComplete: function(){
2086 this.resizeOnComplete();
2090 this.resizable5 = this.windowEl.makeResizable({
2091 handle: [this.w, this.sw, this.nw],
2095 return this.windowEl.getStyle('left').toInt() + this.windowEl.getStyle('width').toInt() - this.options.resizeLimit.x[1];
2098 return this.windowEl.getStyle('left').toInt() + this.windowEl.getStyle('width').toInt() - this.options.resizeLimit.x[0];
2102 modifiers: {x: 'left', y: false},
2103 onStart: function(){
2104 this.resizeOnStart();
2105 this.coords = this.contentWrapperEl.getCoordinates();
2106 this.x2 = this.coords.left.toInt() + this.contentWrapperEl.offsetWidth;
2109 this.coords = this.contentWrapperEl.getCoordinates();
2110 this.contentWrapperEl.setStyle('width', this.x2 - this.coords.left.toInt());
2111 this.resizeOnDrag();
2113 onComplete: function(){
2114 this.resizeOnComplete();
2119 resizeOnStart: function(){
2120 $('windowUnderlay').show();
2122 if (!MUI.ieLegacySupport) {
2123 this.iframeEl.setStyle('visibility', 'hidden');
2126 this.iframeEl.hide();
2130 resizeOnDrag: function(){
2132 this.adjustHandles();
2134 resizeOnComplete: function(){
2135 $('windowUnderlay').hide();
2137 if (!MUI.ieLegacySupport) {
2138 this.iframeEl.setStyle('visibility', 'visible');
2141 this.iframeEl.show();
2142 // The following hack is to get IE8 RC1 IE8 Standards Mode to properly resize an iframe
2143 // when only the vertical dimension is changed.
2144 this.iframeEl.setStyle('width', '99%');
2145 this.iframeEl.setStyle('height', this.contentWrapperEl.offsetHeight);
2146 this.iframeEl.setStyle('width', '100%');
2147 this.iframeEl.setStyle('height', this.contentWrapperEl.offsetHeight);
2151 // Resize panels if there are any
2152 if (this.contentWrapperEl.getChildren('.column') != null) {
2153 MUI.rWidth(this.contentWrapperEl);
2154 this.contentWrapperEl.getChildren('.column').each(function(column){
2155 MUI.panelHeight(column);
2159 this.fireEvent('onResize', this.windowEl);
2161 adjustHandles: function(){
2163 var shadowBlur = this.options.shadowBlur;
2164 var shadowBlur2x = shadowBlur * 2;
2165 var shadowOffset = this.options.shadowOffset;
2166 var top = shadowBlur - shadowOffset.y - 1;
2167 var right = shadowBlur + shadowOffset.x - 1;
2168 var bottom = shadowBlur + shadowOffset.y - 1;
2169 var left = shadowBlur - shadowOffset.x - 1;
2171 var coordinates = this.windowEl.getCoordinates();
2172 var width = coordinates.width - shadowBlur2x + 2;
2173 var height = coordinates.height - shadowBlur2x + 2;
2183 'height': height - 30
2193 'height': height - 20
2212 detachResizable: function(){
2213 this.resizable1.detach();
2214 this.resizable2.detach();
2215 this.resizable3.detach();
2216 this.resizable4.detach();
2217 this.resizable5.detach();
2218 this.windowEl.getElements('.handle').hide();
2220 reattachResizable: function(){
2221 this.resizable1.attach();
2222 this.resizable2.attach();
2223 this.resizable3.attach();
2224 this.resizable4.attach();
2225 this.resizable5.attach();
2226 this.windowEl.getElements('.handle').show();
2230 Internal Function: insertWindowElements
2236 insertWindowElements: function(){
2238 var options = this.options;
2239 var height = options.height;
2240 var width = options.width;
2241 var id = options.id;
2245 if (Browser.Engine.trident4){
2246 cache.zIndexFixEl = new Element('iframe', {
2247 'id': id + '_zIndexFix',
2248 'class': 'zIndexFix',
2254 'position': 'absolute' // This is set here to make theme transitions smoother
2256 }).inject(this.windowEl);
2259 cache.overlayEl = new Element('div', {
2260 'id': id + '_overlay',
2261 'class': 'mochaOverlay',
2263 'position': 'absolute', // This is set here to make theme transitions smoother
2267 }).inject(this.windowEl);
2269 cache.titleBarEl = new Element('div', {
2270 'id': id + '_titleBar',
2271 'class': 'mochaTitlebar',
2273 'cursor': options.draggable ? 'move' : 'default'
2275 }).inject(cache.overlayEl, 'top');
2277 cache.titleEl = new Element('h3', {
2278 'id': id + '_title',
2279 'class': 'mochaTitle'
2280 }).inject(cache.titleBarEl);
2282 if (options.icon != false){
2283 cache.titleEl.setStyles({
2285 'background': 'url(' + options.icon + ') 5px 4px no-repeat'
2289 cache.contentBorderEl = new Element('div', {
2290 'id': id + '_contentBorder',
2291 'class': 'mochaContentBorder'
2292 }).inject(cache.overlayEl);
2294 if (options.toolbar){
2295 cache.toolbarWrapperEl = new Element('div', {
2296 'id': id + '_toolbarWrapper',
2297 'class': 'mochaToolbarWrapper',
2298 'styles': { 'height': options.toolbarHeight }
2299 }).inject(cache.contentBorderEl, options.toolbarPosition == 'bottom' ? 'after' : 'before');
2301 if (options.toolbarPosition == 'bottom') {
2302 cache.toolbarWrapperEl.addClass('bottom');
2304 cache.toolbarEl = new Element('div', {
2305 'id': id + '_toolbar',
2306 'class': 'mochaToolbar',
2307 'styles': { 'height': options.toolbarHeight }
2308 }).inject(cache.toolbarWrapperEl);
2311 if (options.toolbar2){
2312 cache.toolbar2WrapperEl = new Element('div', {
2313 'id': id + '_toolbar2Wrapper',
2314 'class': 'mochaToolbarWrapper',
2315 'styles': { 'height': options.toolbar2Height }
2316 }).inject(cache.contentBorderEl, options.toolbar2Position == 'bottom' ? 'after' : 'before');
2318 if (options.toolbar2Position == 'bottom') {
2319 cache.toolbar2WrapperEl.addClass('bottom');
2321 cache.toolbar2El = new Element('div', {
2322 'id': id + '_toolbar2',
2323 'class': 'mochaToolbar',
2324 'styles': { 'height': options.toolbar2Height }
2325 }).inject(cache.toolbar2WrapperEl);
2328 cache.contentWrapperEl = new Element('div', {
2329 'id': id + '_contentWrapper',
2330 'class': 'mochaContentWrapper',
2332 'width': width + 'px',
2333 'height': height + 'px'
2335 }).inject(cache.contentBorderEl);
2337 if (this.options.shape == 'gauge'){
2338 cache.contentBorderEl.setStyle('borderWidth', 0);
2341 cache.contentEl = new Element('div', {
2342 'id': id + '_content',
2343 'class': 'mochaContent'
2344 }).inject(cache.contentWrapperEl);
2346 if (this.options.useCanvas == true && !MUI.ieLegacySupport) {
2347 cache.canvasEl = new Element('canvas', {
2348 'id': id + '_canvas',
2349 'class': 'mochaCanvas',
2352 }).inject(this.windowEl);
2355 if (this.options.useCanvas == true && MUI.ieLegacySupport) {
2356 cache.canvasEl = new Element('canvas', {
2357 'id': id + '_canvas',
2358 'class': 'mochaCanvas',
2359 'width': 50000, // IE8 excanvas requires these large numbers
2362 'position': 'absolute',
2366 }).inject(this.windowEl);
2368 if (MUI.ieLegacySupport && MUI.ieSupport == 'excanvas'){
2369 G_vmlCanvasManager.initElement(cache.canvasEl);
2370 cache.canvasEl = this.windowEl.getElement('.mochaCanvas');
2374 cache.controlsEl = new Element('div', {
2375 'id': id + '_controls',
2376 'class': 'mochaControls'
2377 }).inject(cache.overlayEl, 'after');
2379 if (options.useCanvasControls == true){
2380 cache.canvasControlsEl = new Element('canvas', {
2381 'id': id + '_canvasControls',
2382 'class': 'mochaCanvasControls',
2385 }).inject(this.windowEl);
2387 if (MUI.ieLegacySupport && MUI.ieSupport == 'excanvas'){
2388 G_vmlCanvasManager.initElement(cache.canvasControlsEl);
2389 cache.canvasControlsEl = this.windowEl.getElement('.mochaCanvasControls');
2393 if (options.closable){
2394 cache.closeButtonEl = new Element('div', {
2395 'id': id + '_closeButton',
2396 'class': 'mochaCloseButton mochaWindowButton',
2398 }).inject(cache.controlsEl);
2401 if (options.maximizable){
2402 cache.maximizeButtonEl = new Element('div', {
2403 'id': id + '_maximizeButton',
2404 'class': 'mochaMaximizeButton mochaWindowButton',
2406 }).inject(cache.controlsEl);
2409 if (options.minimizable){
2410 cache.minimizeButtonEl = new Element('div', {
2411 'id': id + '_minimizeButton',
2412 'class': 'mochaMinimizeButton mochaWindowButton',
2414 }).inject(cache.controlsEl);
2417 if (options.useSpinner == true && options.shape != 'gauge' && options.type != 'notification'){
2418 cache.spinnerEl = new Element('div', {
2419 'id': id + '_spinner',
2420 'class': 'mochaSpinner',
2423 }).inject(this.windowEl, 'bottom');
2426 if (this.options.shape == 'gauge'){
2427 cache.canvasHeaderEl = new Element('canvas', {
2428 'id': id + '_canvasHeader',
2429 'class': 'mochaCanvasHeader',
2430 'width': this.options.width,
2432 }).inject(this.windowEl, 'bottom');
2434 if (MUI.ieLegacySupport && MUI.ieSupport == 'excanvas'){
2435 G_vmlCanvasManager.initElement(cache.canvasHeaderEl);
2436 cache.canvasHeaderEl = this.windowEl.getElement('.mochaCanvasHeader');
2440 if ( MUI.ieLegacySupport ){
2441 cache.overlayEl.setStyle('zIndex', 2);
2444 if (options.resizable){
2445 cache.n = new Element('div', {
2446 'id': id + '_resizeHandle_n',
2451 'cursor': 'n-resize'
2453 }).inject(cache.overlayEl, 'after');
2455 cache.ne = new Element('div', {
2456 'id': id + '_resizeHandle_ne',
2457 'class': 'handle corner',
2461 'cursor': 'ne-resize'
2463 }).inject(cache.overlayEl, 'after');
2465 cache.e = new Element('div', {
2466 'id': id + '_resizeHandle_e',
2471 'cursor': 'e-resize'
2473 }).inject(cache.overlayEl, 'after');
2475 cache.se = new Element('div', {
2476 'id': id + '_resizeHandle_se',
2477 'class': 'handle cornerSE',
2481 'cursor': 'se-resize'
2483 }).inject(cache.overlayEl, 'after');
2485 cache.s = new Element('div', {
2486 'id': id + '_resizeHandle_s',
2491 'cursor': 's-resize'
2493 }).inject(cache.overlayEl, 'after');
2495 cache.sw = new Element('div', {
2496 'id': id + '_resizeHandle_sw',
2497 'class': 'handle corner',
2501 'cursor': 'sw-resize'
2503 }).inject(cache.overlayEl, 'after');
2505 cache.w = new Element('div', {
2506 'id': id + '_resizeHandle_w',
2511 'cursor': 'w-resize'
2513 }).inject(cache.overlayEl, 'after');
2515 cache.nw = new Element('div', {
2516 'id': id + '_resizeHandle_nw',
2517 'class': 'handle corner',
2521 'cursor': 'nw-resize'
2523 }).inject(cache.overlayEl, 'after');
2525 $extend(this, cache);
2530 Convert CSS colors to Canvas colors.
2533 setColors: function(){
2535 if (this.options.useCanvas == true) {
2537 // Set TitlebarColor
2538 var pattern = /\?(.*?)\)/;
2539 if (this.titleBarEl.getStyle('backgroundImage') != 'none'){
2540 var gradient = this.titleBarEl.getStyle('backgroundImage');
2541 gradient = gradient.match(pattern)[1];
2542 gradient = gradient.parseQueryString();
2543 var gradientFrom = gradient.from;
2544 var gradientTo = gradient.to.replace(/\"/, ''); // IE7 was adding a quotation mark in. No idea why.
2546 this.options.headerStartColor = new Color(gradientFrom);
2547 this.options.headerStopColor = new Color(gradientTo);
2548 this.titleBarEl.addClass('replaced');
2550 else if (this.titleBarEl.getStyle('background-color') !== '' && this.titleBarEl.getStyle('background-color') !== 'transparent') {
2551 this.options.headerStartColor = new Color(this.titleBarEl.getStyle('background-color')).mix('#fff', 20);
2552 this.options.headerStopColor = new Color(this.titleBarEl.getStyle('background-color')).mix('#000', 20);
2553 this.titleBarEl.addClass('replaced');
2557 if (this.windowEl.getStyle('background-color') !== '' && this.windowEl.getStyle('background-color') !== 'transparent') {
2558 this.options.bodyBgColor = new Color(this.windowEl.getStyle('background-color'));
2559 this.windowEl.addClass('replaced');
2562 // Set resizableColor, the color of the SE corner resize handle
2563 if (this.options.resizable && this.se.getStyle('background-color') !== '' && this.se.getStyle('background-color') !== 'transparent') {
2564 this.options.resizableColor = new Color(this.se.getStyle('background-color'));
2565 this.se.addClass('replaced');
2570 if (this.options.useCanvasControls == true){
2572 if (this.minimizeButtonEl){
2574 // Set Minimize Button Foreground Color
2575 if (this.minimizeButtonEl.getStyle('color') !== '' && this.minimizeButtonEl.getStyle('color') !== 'transparent') {
2576 this.options.minimizeColor = new Color(this.minimizeButtonEl.getStyle('color'));
2579 // Set Minimize Button Background Color
2580 if (this.minimizeButtonEl.getStyle('background-color') !== '' && this.minimizeButtonEl.getStyle('background-color') !== 'transparent') {
2581 this.options.minimizeBgColor = new Color(this.minimizeButtonEl.getStyle('background-color'));
2582 this.minimizeButtonEl.addClass('replaced');
2587 if (this.maximizeButtonEl){
2589 // Set Maximize Button Foreground Color
2590 if (this.maximizeButtonEl.getStyle('color') !== '' && this.maximizeButtonEl.getStyle('color') !== 'transparent') {
2591 this.options.maximizeColor = new Color(this.maximizeButtonEl.getStyle('color'));
2594 // Set Maximize Button Background Color
2595 if (this.maximizeButtonEl.getStyle('background-color') !== '' && this.maximizeButtonEl.getStyle('background-color') !== 'transparent') {
2596 this.options.maximizeBgColor = new Color(this.maximizeButtonEl.getStyle('background-color'));
2597 this.maximizeButtonEl.addClass('replaced');
2602 if (this.closeButtonEl){
2604 // Set Close Button Foreground Color
2605 if (this.closeButtonEl.getStyle('color') !== '' && this.closeButtonEl.getStyle('color') !== 'transparent') {
2606 this.options.closeColor = new Color(this.closeButtonEl.getStyle('color'));
2609 // Set Close Button Background Color
2610 if (this.closeButtonEl.getStyle('background-color') !== '' && this.closeButtonEl.getStyle('background-color') !== 'transparent') {
2611 this.options.closeBgColor = new Color(this.closeButtonEl.getStyle('background-color'));
2612 this.closeButtonEl.addClass('replaced');
2620 Internal function: drawWindow
2621 This is where we create the canvas GUI
2624 windowEl: the $(window)
2625 shadows: (boolean) false will draw a window without shadows
2628 drawWindow: function(shadows) {
2630 if (this.drawingWindow == true) return;
2631 this.drawingWindow = true;
2633 if (this.isCollapsed){
2634 this.drawWindowCollapsed(shadows);
2638 var windowEl = this.windowEl;
2640 var options = this.options;
2641 var shadowBlur = options.shadowBlur;
2642 var shadowBlur2x = shadowBlur * 2;
2643 var shadowOffset = this.options.shadowOffset;
2645 this.overlayEl.setStyles({
2646 'width': this.contentWrapperEl.offsetWidth
2649 // Resize iframe when window is resized
2650 if (this.iframeEl) {
2651 this.iframeEl.setStyle('height', this.contentWrapperEl.offsetHeight);
2654 var borderHeight = this.contentBorderEl.getStyle('margin-top').toInt() + this.contentBorderEl.getStyle('margin-bottom').toInt();
2655 var toolbarHeight = this.toolbarWrapperEl ? this.toolbarWrapperEl.getStyle('height').toInt() + this.toolbarWrapperEl.getStyle('margin-top').toInt() : 0;
2656 var toolbar2Height = this.toolbar2WrapperEl ? this.toolbar2WrapperEl.getStyle('height').toInt() + this.toolbar2WrapperEl.getStyle('margin-top').toInt() : 0;
2658 this.headerFooterShadow = options.headerHeight + options.footerHeight + shadowBlur2x;
2659 var height = this.contentWrapperEl.getStyle('height').toInt() + this.headerFooterShadow + toolbarHeight + toolbar2Height + borderHeight;
2660 var width = this.contentWrapperEl.getStyle('width').toInt() + shadowBlur2x;
2661 this.windowEl.setStyles({
2666 this.overlayEl.setStyles({
2668 'top': shadowBlur - shadowOffset.y,
2669 'left': shadowBlur - shadowOffset.x
2672 if (this.options.useCanvas == true) {
2673 if (MUI.ieLegacySupport) {
2674 this.canvasEl.height = 20000;
2675 this.canvasEl.width = 50000;
2677 this.canvasEl.height = height;
2678 this.canvasEl.width = width;
2681 // Part of the fix for IE6 select z-index bug
2682 if (Browser.Engine.trident4){
2683 this.zIndexFixEl.setStyles({
2689 this.titleBarEl.setStyles({
2690 'width': width - shadowBlur2x,
2691 'height': options.headerHeight
2694 // Make sure loading icon is placed correctly.
2695 if (options.useSpinner == true && options.shape != 'gauge' && options.type != 'notification'){
2696 this.spinnerEl.setStyles({
2697 'left': shadowBlur - shadowOffset.x + 3,
2698 'bottom': shadowBlur + shadowOffset.y + 4
2702 if (this.options.useCanvas != false) {
2705 var ctx = this.canvasEl.getContext('2d');
2706 ctx.clearRect(0, 0, width, height);
2708 switch (options.shape) {
2710 this.drawBox(ctx, width, height, shadowBlur, shadowOffset, shadows);
2713 this.drawGauge(ctx, width, height, shadowBlur, shadowOffset, shadows);
2717 if (options.resizable){
2720 width - (shadowBlur + shadowOffset.x + 17),
2721 height - (shadowBlur + shadowOffset.y + 18),
2724 options.resizableColor,
2729 // Invisible dummy object. The last element drawn is not rendered consistently while resizing in IE6 and IE7
2730 if (MUI.ieLegacySupport){
2731 MUI.triangle(ctx, 0, 0, 10, 10, options.resizableColor, 0);
2735 if (options.type != 'notification' && options.useCanvasControls == true){
2736 this.drawControls(width, height, shadows);
2739 // Resize panels if there are any
2740 if (MUI.Desktop && this.contentWrapperEl.getChildren('.column').length != 0) {
2741 MUI.rWidth(this.contentWrapperEl);
2742 this.contentWrapperEl.getChildren('.column').each(function(column){
2743 MUI.panelHeight(column);
2747 this.drawingWindow = false;
2751 drawWindowCollapsed: function(shadows) {
2753 var windowEl = this.windowEl;
2755 var options = this.options;
2756 var shadowBlur = options.shadowBlur;
2757 var shadowBlur2x = shadowBlur * 2;
2758 var shadowOffset = options.shadowOffset;
2760 var headerShadow = options.headerHeight + shadowBlur2x + 2;
2761 var height = headerShadow;
2762 var width = this.contentWrapperEl.getStyle('width').toInt() + shadowBlur2x;
2763 this.windowEl.setStyle('height', height);
2765 this.overlayEl.setStyles({
2767 'top': shadowBlur - shadowOffset.y,
2768 'left': shadowBlur - shadowOffset.x
2771 // Part of the fix for IE6 select z-index bug
2772 if (Browser.Engine.trident4){
2773 this.zIndexFixEl.setStyles({
2780 this.windowEl.setStyle('width', width);
2781 this.overlayEl.setStyle('width', width);
2782 this.titleBarEl.setStyles({
2783 'width': width - shadowBlur2x,
2784 'height': options.headerHeight
2788 if (this.options.useCanvas != false) {
2789 this.canvasEl.height = height;
2790 this.canvasEl.width = width;
2792 var ctx = this.canvasEl.getContext('2d');
2793 ctx.clearRect(0, 0, width, height);
2795 this.drawBoxCollapsed(ctx, width, height, shadowBlur, shadowOffset, shadows);
2796 if (options.useCanvasControls == true) {
2797 this.drawControls(width, height, shadows);
2800 // Invisible dummy object. The last element drawn is not rendered consistently while resizing in IE6 and IE7
2801 if (MUI.ieLegacySupport){
2802 MUI.triangle(ctx, 0, 0, 10, 10, options.resizableColor, 0);
2806 this.drawingWindow = false;
2810 drawControls : function(width, height, shadows){
2811 var options = this.options;
2812 var shadowBlur = options.shadowBlur;
2813 var shadowOffset = options.shadowOffset;
2814 var controlsOffset = options.controlsOffset;
2816 // Make sure controls are placed correctly.
2817 this.controlsEl.setStyles({
2818 'right': shadowBlur + shadowOffset.x + controlsOffset.right,
2819 'top': shadowBlur - shadowOffset.y + controlsOffset.top
2822 this.canvasControlsEl.setStyles({
2823 'right': shadowBlur + shadowOffset.x + controlsOffset.right,
2824 'top': shadowBlur - shadowOffset.y + controlsOffset.top
2827 // Calculate X position for controlbuttons
2828 //var mochaControlsWidth = 52;
2829 this.closebuttonX = options.closable ? this.mochaControlsWidth - 7 : this.mochaControlsWidth + 12;
2830 this.maximizebuttonX = this.closebuttonX - (options.maximizable ? 19 : 0);
2831 this.minimizebuttonX = this.maximizebuttonX - (options.minimizable ? 19 : 0);
2833 var ctx2 = this.canvasControlsEl.getContext('2d');
2834 ctx2.clearRect(0, 0, 100, 100);
2836 if (this.options.closable){
2841 options.closeBgColor,
2847 if (this.options.maximizable){
2848 this.maximizebutton(
2850 this.maximizebuttonX,
2852 options.maximizeBgColor,
2854 options.maximizeColor,
2858 if (this.options.minimizable){
2859 this.minimizebutton(
2861 this.minimizebuttonX,
2863 options.minimizeBgColor,
2865 options.minimizeColor,
2869 // Invisible dummy object. The last element drawn is not rendered consistently while resizing in IE6 and IE7
2870 if (MUI.ieLegacySupport){
2871 MUI.circle(ctx2, 0, 0, 3, this.options.resizableColor, 0);
2875 drawBox: function(ctx, width, height, shadowBlur, shadowOffset, shadows){
2877 var options = this.options;
2878 var shadowBlur2x = shadowBlur * 2;
2879 var cornerRadius = this.options.cornerRadius;
2881 // This is the drop shadow. It is created onion style.
2882 if ( shadows != false ) {
2883 for (var x = 0; x <= shadowBlur; x++){
2888 width - (x * 2) - shadowOffset.x,
2889 height - (x * 2) - shadowOffset.y,
2890 cornerRadius + (shadowBlur - x),
2892 x == shadowBlur ? .29 : .065 + (x * .01)
2897 this.bodyRoundedRect(
2899 shadowBlur - shadowOffset.x, // x
2900 shadowBlur - shadowOffset.y, // y
2901 width - shadowBlur2x, // width
2902 height - shadowBlur2x, // height
2903 cornerRadius, // corner radius
2904 options.bodyBgColor // Footer color
2907 if (this.options.type != 'notification'){
2909 this.topRoundedRect(
2911 shadowBlur - shadowOffset.x, // x
2912 shadowBlur - shadowOffset.y, // y
2913 width - shadowBlur2x, // width
2914 options.headerHeight, // height
2915 cornerRadius, // corner radius
2916 options.headerStartColor, // Header gradient's top color
2917 options.headerStopColor // Header gradient's bottom color
2921 drawBoxCollapsed: function(ctx, width, height, shadowBlur, shadowOffset, shadows){
2923 var options = this.options;
2924 var shadowBlur2x = shadowBlur * 2;
2925 var cornerRadius = options.cornerRadius;
2927 // This is the drop shadow. It is created onion style.
2928 if ( shadows != false ){
2929 for (var x = 0; x <= shadowBlur; x++){
2934 width - (x * 2) - shadowOffset.x,
2935 height - (x * 2) - shadowOffset.y,
2936 cornerRadius + (shadowBlur - x),
2938 x == shadowBlur ? .3 : .06 + (x * .01)
2944 this.topRoundedRect2(
2946 shadowBlur - shadowOffset.x, // x
2947 shadowBlur - shadowOffset.y, // y
2948 width - shadowBlur2x, // width
2949 options.headerHeight + 2, // height
2950 cornerRadius, // corner radius
2951 options.headerStartColor, // Header gradient's top color
2952 options.headerStopColor // Header gradient's bottom color
2956 drawGauge: function(ctx, width, height, shadowBlur, shadowOffset, shadows){
2957 var options = this.options;
2958 var radius = (width * .5) - (shadowBlur) + 16;
2959 if (shadows != false) {
2960 for (var x = 0; x <= shadowBlur; x++){
2963 width * .5 + shadowOffset.x,
2964 (height + options.headerHeight) * .5 + shadowOffset.x,
2965 (width *.5) - (x * 2) - shadowOffset.x,
2967 x == shadowBlur ? .75 : .075 + (x * .04)
2973 width * .5 - shadowOffset.x,
2974 (height + options.headerHeight) * .5 - shadowOffset.y,
2975 (width *.5) - shadowBlur,
2976 options.bodyBgColor,
2980 // Draw gauge header
2981 this.canvasHeaderEl.setStyles({
2982 'top': shadowBlur - shadowOffset.y,
2983 'left': shadowBlur - shadowOffset.x
2985 var ctx = this.canvasHeaderEl.getContext('2d');
2986 ctx.clearRect(0, 0, width, 100);
2989 ctx.lineCap = 'round';
2991 ctx.lineTo(width - (shadowBlur*2) - 13, 13);
2992 ctx.strokeStyle = 'rgba(0, 0, 0, .65)';
2995 bodyRoundedRect: function(ctx, x, y, width, height, radius, rgb){
2996 ctx.fillStyle = 'rgba(' + rgb.join(',') + ', 1)';
2998 ctx.moveTo(x, y + radius);
2999 ctx.lineTo(x, y + height - radius);
3000 ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
3001 ctx.lineTo(x + width - radius, y + height);
3002 ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
3003 ctx.lineTo(x + width, y + radius);
3004 ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
3005 ctx.lineTo(x + radius, y);
3006 ctx.quadraticCurveTo(x, y, x, y + radius);
3010 topRoundedRect: function(ctx, x, y, width, height, radius, headerStartColor, headerStopColor){
3011 var lingrad = ctx.createLinearGradient(0, 0, 0, height);
3012 lingrad.addColorStop(0, 'rgb(' + headerStartColor.join(',') + ')');
3013 lingrad.addColorStop(1, 'rgb(' + headerStopColor.join(',') + ')');
3014 ctx.fillStyle = lingrad;
3017 ctx.lineTo(x, y + height);
3018 ctx.lineTo(x + width, y + height);
3019 ctx.lineTo(x + width, y + radius);
3020 ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
3021 ctx.lineTo(x + radius, y);
3022 ctx.quadraticCurveTo(x, y, x, y + radius);
3026 topRoundedRect2: function(ctx, x, y, width, height, radius, headerStartColor, headerStopColor){
3027 // Chrome is having trouble rendering the LinearGradient in this particular case
3028 if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
3029 ctx.fillStyle = 'rgba(' + headerStopColor.join(',') + ', 1)';
3032 var lingrad = ctx.createLinearGradient(0, this.options.shadowBlur - 1, 0, height + this.options.shadowBlur + 3);
3033 lingrad.addColorStop(0, 'rgb(' + headerStartColor.join(',') + ')');
3034 lingrad.addColorStop(1, 'rgb(' + headerStopColor.join(',') + ')');
3035 ctx.fillStyle = lingrad;
3038 ctx.moveTo(x, y + radius);
3039 ctx.lineTo(x, y + height - radius);
3040 ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
3041 ctx.lineTo(x + width - radius, y + height);
3042 ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
3043 ctx.lineTo(x + width, y + radius);
3044 ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
3045 ctx.lineTo(x + radius, y);
3046 ctx.quadraticCurveTo(x, y, x, y + radius);
3049 maximizebutton: function(ctx, x, y, rgbBg, aBg, rgb, a){
3052 ctx.arc(x, y, 7, 0, Math.PI*2, true);
3053 ctx.fillStyle = 'rgba(' + rgbBg.join(',') + ',' + aBg + ')';
3056 ctx.strokeStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
3059 ctx.moveTo(x, y - 3.5);
3060 ctx.lineTo(x, y + 3.5);
3061 ctx.moveTo(x - 3.5, y);
3062 ctx.lineTo(x + 3.5, y);
3065 closebutton: function(ctx, x, y, rgbBg, aBg, rgb, a){
3068 ctx.arc(x, y, 7, 0, Math.PI*2, true);
3069 ctx.fillStyle = 'rgba(' + rgbBg.join(',') + ',' + aBg + ')';
3072 ctx.strokeStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
3075 ctx.moveTo(x - 3, y - 3);
3076 ctx.lineTo(x + 3, y + 3);
3077 ctx.moveTo(x + 3, y - 3);
3078 ctx.lineTo(x - 3, y + 3);
3081 minimizebutton: function(ctx, x, y, rgbBg, aBg, rgb, a){
3084 ctx.arc(x,y,7,0,Math.PI*2,true);
3085 ctx.fillStyle = 'rgba(' + rgbBg.join(',') + ',' + aBg + ')';
3088 ctx.strokeStyle = 'rgba(' + rgb.join(',') + ',' + a + ')';
3091 ctx.moveTo(x - 3.5, y);
3092 ctx.lineTo(x + 3.5, y);
3095 setMochaControlsWidth: function(){
3096 this.mochaControlsWidth = 0;
3097 var options = this.options;
3098 if (options.minimizable){
3099 this.mochaControlsWidth += (this.minimizeButtonEl.getStyle('margin-left').toInt() + this.minimizeButtonEl.getStyle('width').toInt());
3101 if (options.maximizable){
3102 this.mochaControlsWidth += (this.maximizeButtonEl.getStyle('margin-left').toInt() + this.maximizeButtonEl.getStyle('width').toInt());
3104 if (options.closable){
3105 this.mochaControlsWidth += (this.closeButtonEl.getStyle('margin-left').toInt() + this.closeButtonEl.getStyle('width').toInt());
3107 this.controlsEl.setStyle('width', this.mochaControlsWidth);
3108 if (options.useCanvasControls == true){
3109 this.canvasControlsEl.setProperty('width', this.mochaControlsWidth);
3114 Function: hideSpinner
3119 $('myWindow').retrieve('instance').hideSpinner();
3123 hideSpinner: function() {
3124 if (this.spinnerEl) this.spinnerEl.hide();
3129 Function: showSpinner
3134 $('myWindow').retrieve('instance').showSpinner();
3138 showSpinner: function(){
3139 if (this.spinnerEl) this.spinnerEl.show();
3145 Closes the window. This is an alternative to using MUI.Core.closeWindow().
3149 $('myWindow').retrieve('instance').close();
3153 close: function( ) {
3154 if (!this.isClosing) MUI.closeWindow(this.windowEl);
3160 Minimizes the window.
3164 $('myWindow').retrieve('instance').minimize();
3168 minimize: function( ){
3169 MUI.Dock.minimizeWindow(this.windowEl);
3175 Maximizes the window.
3179 $('myWindow').retrieve('instance').maximize();
3183 maximize: function( ) {
3184 if (this.isMinimized){
3185 MUI.Dock.restoreMinimized(this.windowEl);
3187 MUI.Desktop.maximizeWindow(this.windowEl);
3193 Restores a minimized/maximized window to its original size.
3197 $('myWindow').retrieve('instance').restore();
3201 restore: function() {
3202 if ( this.isMinimized )
3203 MUI.Dock.restoreMinimized(this.windowEl);
3204 else if ( this.isMaximized )
3205 MUI.Desktop.restoreWindow(this.windowEl);
3214 If Advanced Effects are on the resize is animated. If centered is set to true the window remains centered as it resizes.
3218 $('myWindow').retrieve('instance').resize({width:500,height:300,centered:true});
3222 resize: function(options){
3223 MUI.resizeWindow(this.windowEl, options);
3233 $('myWindow').retrieve('instance').center();
3237 center: function() {
3238 MUI.centerWindow(this.windowEl);
3243 this.windowEl.setStyle('display', 'none');
3248 this.windowEl.setStyle('display', 'block');
3257 Function: closeWindow
3266 windowEl - the ID of the window to be closed
3269 true - the window was closed
3270 false - the window was not closed
3273 closeWindow: function(windowEl){
3275 var instance = windowEl.retrieve('instance');
3277 // Does window exist and is not already in process of closing ?
3278 if (windowEl != $(windowEl) || instance.isClosing) return;
3280 instance.isClosing = true;
3281 instance.fireEvent('onClose', windowEl);
3283 if (instance.options.storeOnClose){
3284 this.storeOnClose(instance, windowEl);
3287 if (instance.check) instance.check.destroy();
3289 if ((instance.options.type == 'modal' || instance.options.type == 'modal2') && Browser.Engine.trident4){
3290 $('modalFix').hide();
3293 if (MUI.options.advancedEffects == false){
3294 if (instance.options.type == 'modal' || instance.options.type == 'modal2'){
3295 $('modalOverlay').setStyle('opacity', 0);
3297 MUI.closingJobs(windowEl);
3301 // Redraws IE windows without shadows since IE messes up canvas alpha when you change element opacity
3302 if (MUI.ieLegacySupport) instance.drawWindow(false);
3303 if (instance.options.type == 'modal' || instance.options.type == 'modal2'){
3304 MUI.Modal.modalOverlayCloseMorph.start({
3308 var closeMorph = new Fx.Morph(windowEl, {
3310 onComplete: function(){
3311 MUI.closingJobs(windowEl);
3321 closingJobs: function(windowEl){
3323 var instances = MUI.Windows.instances;
3324 var instance = instances.get(windowEl.id);
3325 windowEl.setStyle('visibility', 'hidden');
3326 // Destroy throws an error in IE8
3327 if (MUI.ieLegacySupport) {
3333 instance.fireEvent('onCloseComplete');
3335 if (instance.options.type != 'notification'){
3336 var newFocus = this.getWindowWithHighestZindex();
3337 this.focusWindow(newFocus);
3340 instances.erase(instance.options.id);
3341 if (this.loadingWorkspace == true) {
3342 this.windowUnload();
3345 if (MUI.Dock && $(MUI.options.dock) && instance.options.type == 'window') {
3346 var currentButton = $(instance.options.id + '_dockTab');
3347 if (currentButton != null) {
3348 MUI.Dock.dockSortables.removeItems(currentButton).destroy();
3350 // Need to resize everything in case the dock becomes smaller when a tab is removed
3351 MUI.Desktop.setDesktopSize();
3354 storeOnClose: function(instance, windowEl){
3356 if (instance.check) instance.check.hide();
3358 windowEl.setStyles({
3361 windowEl.addClass('windowClosed');
3362 windowEl.removeClass('mocha');
3364 if (MUI.Dock && $(MUI.options.dock) && instance.options.type == 'window') {
3365 var currentButton = $(instance.options.id + '_dockTab');
3366 if (currentButton != null) {
3367 currentButton.hide();
3369 MUI.Desktop.setDesktopSize();
3372 instance.fireEvent('onCloseComplete');
3374 if (instance.options.type != 'notification'){
3375 var newFocus = this.getWindowWithHighestZindex();
3376 this.focusWindow(newFocus);
3379 instance.isClosing = false;
3385 Close all open windows.
3388 closeAll: function() {
3389 $$('.mocha').each(function(windowEl){
3390 this.closeWindow(windowEl);
3395 Function: collapseToggle
3396 Collapses an expanded window. Expands a collapsed window.
3399 collapseToggle: function(windowEl){
3400 var instance = windowEl.retrieve('instance');
3401 var handles = windowEl.getElements('.handle');
3402 if (instance.isMaximized == true) return;
3403 if (instance.isCollapsed == false) {
3404 instance.isCollapsed = true;
3406 if ( instance.iframeEl ) {
3407 instance.iframeEl.setStyle('visibility', 'hidden');
3409 instance.contentBorderEl.setStyles({
3410 visibility: 'hidden',
3411 position: 'absolute',
3415 if(instance.toolbarWrapperEl){
3416 instance.toolbarWrapperEl.setStyles({
3417 visibility: 'hidden',
3418 position: 'absolute',
3423 instance.drawWindowCollapsed();
3426 instance.isCollapsed = false;
3427 instance.drawWindow();
3428 instance.contentBorderEl.setStyles({
3429 visibility: 'visible',
3434 if(instance.toolbarWrapperEl){
3435 instance.toolbarWrapperEl.setStyles({
3436 visibility: 'visible',
3442 if ( instance.iframeEl ) {
3443 instance.iframeEl.setStyle('visibility', 'visible');
3450 Function: toggleWindowVisibility
3451 Toggle window visibility with Ctrl-Alt-Q.
3454 toggleWindowVisibility: function(){
3455 MUI.Windows.instances.each(function(instance){
3456 if (instance.options.type == 'modal' || instance.options.type == 'modal2' || instance.isMinimized == true) return;
3457 var id = $(instance.options.id);
3458 if (id.getStyle('visibility') == 'visible'){
3459 if (instance.iframe){
3460 instance.iframeEl.setStyle('visibility', 'hidden');
3462 if (instance.toolbarEl){
3463 instance.toolbarWrapperEl.setStyle('visibility', 'hidden');
3465 instance.contentBorderEl.setStyle('visibility', 'hidden');
3466 id.setStyle('visibility', 'hidden');
3467 MUI.Windows.windowsVisible = false;
3470 id.setStyle('visibility', 'visible');
3471 instance.contentBorderEl.setStyle('visibility', 'visible');
3472 if (instance.iframe){
3473 instance.iframeEl.setStyle('visibility', 'visible');
3475 if (instance.toolbarEl){
3476 instance.toolbarWrapperEl.setStyle('visibility', 'visible');
3478 MUI.Windows.windowsVisible = true;
3483 focusWindow: function(windowEl, fireEvent){
3485 // This is used with blurAll
3486 MUI.Windows.focusingWindow = true;
3487 var windowClicked = function(){
3488 MUI.Windows.focusingWindow = false;
3490 windowClicked.delay(170, this);
3492 // Only focus when needed
3493 if ($$('.mocha').length == 0) return;
3494 if (windowEl != $(windowEl) || windowEl.hasClass('isFocused')) return;
3496 var instances = MUI.Windows.instances;
3497 var instance = instances.get(windowEl.id);
3499 if (instance.options.type == 'notification'){
3500 windowEl.setStyle('zIndex', 11001);
3504 MUI.Windows.indexLevel += 2;
3505 windowEl.setStyle('zIndex', MUI.Windows.indexLevel);
3507 // Used when dragging and resizing windows
3508 $('windowUnderlay').setStyle('zIndex', MUI.Windows.indexLevel - 1).inject($(windowEl),'after');
3510 // Fire onBlur for the window that lost focus.
3511 instances.each(function(instance){
3512 if (instance.windowEl.hasClass('isFocused')){
3513 instance.fireEvent('onBlur', instance.windowEl);
3515 instance.windowEl.removeClass('isFocused');
3518 if (MUI.Dock && $(MUI.options.dock) && instance.options.type == 'window') {
3519 MUI.Dock.makeActiveTab();
3521 windowEl.addClass('isFocused');
3523 if (fireEvent != false){
3524 instance.fireEvent('onFocus', windowEl);
3528 getWindowWithHighestZindex: function(){
3529 this.highestZindex = 0;
3530 $$('.mocha').each(function(element){
3531 this.zIndex = element.getStyle('zIndex');
3532 if (this.zIndex >= this.highestZindex) {
3533 this.highestZindex = this.zIndex;
3536 $$('.mocha').each(function(element){
3537 if (element.getStyle('zIndex') == this.highestZindex) {
3538 this.windowWithHighestZindex = element;
3541 return this.windowWithHighestZindex;
3543 blurAll: function(){
3544 if (MUI.Windows.focusingWindow == false) {
3545 $$('.mocha').each(function(windowEl){
3546 var instance = windowEl.retrieve('instance');
3547 if (instance.options.type != 'modal' && instance.options.type != 'modal2'){
3548 windowEl.removeClass('isFocused');
3551 $$('.dockTab').removeClass('activeDockTab');
3554 centerWindow: function(windowEl){
3557 MUI.Windows.instances.each(function(instance){
3558 if (instance.windowEl.hasClass('isFocused')){
3559 windowEl = instance.windowEl;
3564 var instance = windowEl.retrieve('instance');
3565 var options = instance.options;
3566 var dimensions = options.container.getCoordinates();
3568 var windowPosTop = window.getScroll().y + (window.getSize().y * .5) - (windowEl.offsetHeight * .5);
3569 if (windowPosTop < -instance.options.shadowBlur){
3570 windowPosTop = -instance.options.shadowBlur;
3572 var windowPosLeft = (dimensions.width * .5) - (windowEl.offsetWidth * .5);
3573 if (windowPosLeft < -instance.options.shadowBlur){
3574 windowPosLeft = -instance.options.shadowBlur;
3576 if (MUI.options.advancedEffects == true){
3577 instance.morph.start({
3578 'top': windowPosTop,
3579 'left': windowPosLeft
3583 windowEl.setStyles({
3584 'top': windowPosTop,
3585 'left': windowPosLeft
3589 resizeWindow: function(windowEl, options){
3590 var instance = windowEl.retrieve('instance');
3600 var oldWidth = windowEl.getStyle('width').toInt();
3601 var oldHeight = windowEl.getStyle('height').toInt();
3602 var oldTop = windowEl.getStyle('top').toInt();
3603 var oldLeft = windowEl.getStyle('left').toInt();
3605 if (options.centered){
3606 var top = options.top || oldTop - ((options.height - oldHeight) * .5);
3607 var left = options.left || oldLeft - ((options.width - oldWidth) * .5);
3610 var top = options.top || oldTop;
3611 var left = options.left || oldLeft;
3614 if (MUI.options.advancedEffects == false){
3615 windowEl.setStyles({
3619 instance.contentWrapperEl.setStyles({
3620 'height': options.height,
3621 'width': options.width
3623 instance.drawWindow();
3625 if (instance.iframeEl){
3626 if (!MUI.ieLegacySupport) {
3627 instance.iframeEl.setStyle('visibility', 'visible');
3630 instance.iframeEl.show();
3635 windowEl.retrieve('resizeMorph').start({
3636 '0': { 'height': options.height,
3637 'width': options.width
3648 Internal Function: dynamicResize
3649 Use with a timer to resize a window as the window's content size changes, such as with an accordion.
3652 dynamicResize: function(windowEl){
3653 var instance = windowEl.retrieve('instance');
3654 var contentWrapperEl = instance.contentWrapperEl;
3655 var contentEl = instance.contentEl;
3657 contentWrapperEl.setStyles({
3658 'height': contentEl.offsetHeight,
3659 'width': contentEl.offsetWidth
3661 instance.drawWindow();
3665 // Toggle window visibility with Ctrl-Alt-Q
3666 document.addEvent('keydown', function(event){
3667 if (event.key == 'q' && event.control && event.alt) {
3668 MUI.toggleWindowVisibility();
3674 Create modal dialog windows.
3677 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
3690 MUI.files[MUI.path.source + 'Window/Modal.js'] = 'loaded';
3692 MUI.Modal = new Class({
3694 Extends: MUI.Window,
3700 initialize: function(options){
3702 if (!$('modalOverlay')){
3703 this.modalInitialize();
3705 window.addEvent('resize', function(){
3706 this.setModalSize();
3709 this.parent(options);
3712 modalInitialize: function(){
3713 var modalOverlay = new Element('div', {
3714 'id': 'modalOverlay',
3716 'height': document.getCoordinates().height,
3719 }).inject(document.body);
3721 modalOverlay.setStyles({
3722 'position': Browser.Engine.trident4 ? 'absolute' : 'fixed'
3725 modalOverlay.addEvent('click', function(e){
3726 var instance = MUI.Windows.instances.get(MUI.currentModal.id);
3727 if (instance.options.modalOverlayClose == true) {
3728 MUI.closeWindow(MUI.currentModal);
3732 if (Browser.Engine.trident4){
3733 var modalFix = new Element('iframe', {
3740 'height': document.getCoordinates().height
3742 }).inject(document.body);
3745 MUI.Modal.modalOverlayOpenMorph = new Fx.Morph($('modalOverlay'), {
3748 MUI.Modal.modalOverlayCloseMorph = new Fx.Morph($('modalOverlay'), {
3750 onComplete: function(){
3751 $('modalOverlay').hide();
3752 if (Browser.Engine.trident4){
3753 $('modalFix').hide();
3758 setModalSize: function(){
3759 $('modalOverlay').setStyle('height', document.getCoordinates().height);
3760 if (Browser.Engine.trident4){
3761 $('modalFix').setStyle('height', document.getCoordinates().height);
3768 Script: Windows-from-html.js
3769 Create windows from html markup in page.
3772 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
3783 <div class="mocha" id="mywindow" style="width:300px;height:255px;top:50px;left:350px">
3784 <h3 class="mochaTitle">My Window</h3>
3785 <p>My Window Content</p>
3794 MUI.files[MUI.path.source + 'Window/Windows-from-html.js'] = 'loaded';
3797 NewWindowsFromHTML: function(){
3798 $$('.mocha').each(function(el) {
3799 // Get the window title and destroy that element, so it does not end up in window content
3800 if ( Browser.Engine.presto || Browser.Engine.trident5 ){
3801 el.hide(); // Required by Opera, and probably IE7
3803 var title = el.getElement('h3.mochaTitle');
3805 if(Browser.Engine.presto) el.show();
3807 var elDimensions = el.getStyles('height', 'width');
3809 id: el.getProperty('id'),
3810 height: elDimensions.height.toInt(),
3811 width: elDimensions.width.toInt(),
3812 x: el.getStyle('left').toInt(),
3813 y: el.getStyle('top').toInt()
3815 // If there is a title element, set title and destroy the element so it does not end up in window content
3817 properties.title = title.innerHTML;
3821 // Get content and destroy the element
3822 properties.content = el.innerHTML;
3826 new MUI.Window(properties, true);
3832 Script: Windows-from-json.js
3833 Create one or more windows from JSON data. You can define all the same properties as you can for new MUI.Window(). Undefined properties are set to their defaults.
3836 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
3843 MUI.newWindowsFromJSON(properties);
3848 MUI.jsonWindows = function(){
3849 var url = 'data/json-windows-data.js';
3850 var request = new Request.JSON({
3853 onComplete: function(properties) {
3854 MUI.newWindowsFromJSON(properties.windows);
3861 Windows created from JSON are not compatible with the current cookie based version
3862 of Save and Load Workspace.
3869 MUI.files[MUI.path.source + 'Window/Windows-from-json.js'] = 'loaded';
3872 newWindowsFromJSON: function(newWindows){
3873 newWindows.each(function(options) {
3874 var temp = new Hash(options);
3875 temp.each( function(value, key, hash) {
3876 if ($type(value) != 'string') return;
3877 if (value.substring(0,8) == 'function'){
3878 eval("options." + key + " = " + value);
3881 new MUI.Window(options);
3887 Script: Arrange-cascade.js
3891 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
3901 MUI.arrangeCascade();
3906 MUI.files[MUI.path.source + 'Window/Arrange-cascade.js'] = 'loaded';
3909 arrangeCascade: function(){
3911 var viewportTopOffset = 30; // Use a negative number if necessary to place first window where you want it
3912 var viewportLeftOffset = 20;
3913 var windowTopOffset = 50; // Initial vertical spacing of each window
3914 var windowLeftOffset = 40;
3916 // See how much space we have to work with
3917 var coordinates = document.getCoordinates();
3919 var openWindows = 0;
3920 MUI.Windows.instances.each(function(instance){
3921 if (!instance.isMinimized && instance.options.draggable) openWindows ++;
3924 if ((windowTopOffset * (openWindows + 1)) >= (coordinates.height - viewportTopOffset)) {
3925 var topOffset = (coordinates.height - viewportTopOffset) / (openWindows + 1);
3928 var topOffset = windowTopOffset;
3931 if ((windowLeftOffset * (openWindows + 1)) >= (coordinates.width - viewportLeftOffset - 20)) {
3932 var leftOffset = (coordinates.width - viewportLeftOffset - 20) / (openWindows + 1);
3935 var leftOffset = windowLeftOffset;
3938 var x = viewportLeftOffset;
3939 var y = viewportTopOffset;
3940 $$('.mocha').each(function(windowEl){
3941 var instance = windowEl.retrieve('instance');
3942 if (!instance.isMinimized && !instance.isMaximized && instance.options.draggable){
3944 MUI.focusWindow(windowEl);
3948 if (MUI.options.advancedEffects == false){
3949 windowEl.setStyles({
3955 var cascadeMorph = new Fx.Morph(windowEl, {
3958 cascadeMorph.start({
3969 Script: Arrange-tile.js
3973 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
3976 Harry Roberts and Greg Houston
3991 MUI.files[MUI.path.source + 'Window/Arrange-tile.js'] = 'loaded';
3994 arrangeTile: function(){
3996 var viewportTopOffset = 30; // Use a negative number if necessary to place first window where you want it
3997 var viewportLeftOffset = 20;
4002 var instances = MUI.Windows.instances;
4006 instances.each(function(instance){
4007 if (!instance.isMinimized && !instance.isMaximized){
4013 var rows = Math.ceil(windowsNum / cols);
4015 var coordinates = document.getCoordinates();
4017 var col_width = ((coordinates.width - viewportLeftOffset) / cols);
4018 var col_height = ((coordinates.height - viewportTopOffset) / rows);
4023 instances.each(function(instance){
4024 if (!instance.isMinimized && !instance.isMaximized && instance.options.draggable ){
4026 var content = instance.contentWrapperEl;
4027 var content_coords = content.getCoordinates();
4028 var window_coords = instance.windowEl.getCoordinates();
4030 // Calculate the amount of padding around the content window
4031 var padding_top = content_coords.top - window_coords.top;
4032 var padding_bottom = window_coords.height - content_coords.height - padding_top;
4033 var padding_left = content_coords.left - window_coords.left;
4034 var padding_right = window_coords.width - content_coords.width - padding_left;
4038 // This resizes the windows
4039 if (instance.options.shape != 'gauge' && instance.options.resizable == true){
4040 var width = (col_width - 3 - padding_left - padding_right);
4041 var height = (col_height - 3 - padding_top - padding_bottom);
4043 if (width > instance.options.resizeLimit.x[0] && width < instance.options.resizeLimit.x[1]){
4044 content.setStyle('width', width);
4046 if (height > instance.options.resizeLimit.y[0] && height < instance.options.resizeLimit.y[1]){
4047 content.setStyle('height', height);
4052 var left = (x + (col * col_width));
4053 var top = (y + (row * col_height));
4055 instance.drawWindow();
4057 MUI.focusWindow(instance.windowEl);
4059 if (MUI.options.advancedEffects == false){
4060 instance.windowEl.setStyles({
4066 var tileMorph = new Fx.Morph(instance.windowEl, {
4075 if (++col === cols) {
4086 Functionality for window tabs.
4089 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
4095 Core.js, Window.js (for tabbed windows) or Layout.js (for tabbed panels)
4099 MUI.files[MUI.path.source + 'Components/Tabs.js'] = 'loaded';
4104 Function: initializeTabs
4105 Add click event to each list item that fires the selected function.
4108 initializeTabs: function(el){
4109 $(el).setStyle('list-style', 'none'); // This is to fix a glitch that occurs in IE8 RC1 when dynamically switching themes
4110 $(el).getElements('li').addEvent('click', function(e){
4111 MUI.selected(this, el);
4117 Add "selected" class to current list item and remove it from sibling list items.
4121 selected(el, parent);
4129 selected: function(el, parent){
4130 $(parent).getChildren().each(function(listitem){
4131 listitem.removeClass('selected');
4133 el.addClass('selected');
4140 Create web application layouts. Enables window maximize.
4143 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
4153 MUI.files[MUI.path.source + 'Layout/Layout.js'] = 'loaded';
4157 instances: new Hash(),
4158 columnIDCount: 0 // Used for columns without an ID defined by the user
4161 instances: new Hash(),
4162 panelIDCount: 0 // Used for panels without an ID defined by the user
4170 // If you change the IDs of the MochaUI Desktop containers in your HTML, you need to change them here as well.
4172 desktopHeader: 'desktopHeader',
4173 desktopFooter: 'desktopFooter',
4174 desktopNavBar: 'desktopNavbar',
4175 pageWrapper: 'pageWrapper',
4177 desktopFooter: 'desktopFooterWrapper'
4179 initialize: function(){
4181 this.desktop = $(this.options.desktop);
4182 this.desktopHeader = $(this.options.desktopHeader);
4183 this.desktopNavBar = $(this.options.desktopNavBar);
4184 this.pageWrapper = $(this.options.pageWrapper);
4185 this.page = $(this.options.page);
4186 this.desktopFooter = $(this.options.desktopFooter);
4189 ($$('body')).setStyles({
4194 ($$('html')).setStyles({
4200 // This is run on dock initialize so no need to do it twice.
4202 this.setDesktopSize();
4204 this.menuInitialize();
4206 // Resize desktop, page wrapper, modal overlay, and maximized windows when browser window is resized
4207 window.addEvent('resize', function(e){
4208 this.onBrowserResize();
4212 MUI.myChain.callChain();
4216 menuInitialize: function(){
4217 // Fix for dropdown menus in IE6
4218 if (Browser.Engine.trident4 && this.desktopNavBar){
4219 this.desktopNavBar.getElements('li').each(function(element) {
4220 element.addEvent('mouseenter', function(){
4221 this.addClass('ieHover');
4223 element.addEvent('mouseleave', function(){
4224 this.removeClass('ieHover');
4229 onBrowserResize: function(){
4230 this.setDesktopSize();
4231 // Resize maximized windows to fit new browser window size
4232 setTimeout( function(){
4233 MUI.Windows.instances.each(function(instance){
4234 if (instance.isMaximized){
4236 // Hide iframe while resize for better performance
4237 if ( instance.iframeEl ){
4238 instance.iframeEl.setStyle('visibility', 'hidden');
4241 var coordinates = document.getCoordinates();
4242 var borderHeight = instance.contentBorderEl.getStyle('margin-top').toInt() + instance.contentBorderEl.getStyle('margin-bottom').toInt();
4243 var toolbarHeight = instance.toolbarWrapperEl ? instance.toolbarWrapperEl.getStyle('height').toInt() + instance.toolbarWrapperEl.getStyle('margin-top').toInt() : 0;
4244 instance.contentWrapperEl.setStyles({
4245 'height': coordinates.height - instance.options.headerHeight - instance.options.footerHeight - borderHeight - toolbarHeight,
4246 'width': coordinates.width
4249 instance.drawWindow();
4250 if ( instance.iframeEl ){
4251 instance.iframeEl.setStyles({
4252 'height': instance.contentWrapperEl.getStyle('height')
4254 instance.iframeEl.setStyle('visibility', 'visible');
4261 setDesktopSize: function(){
4262 var windowDimensions = window.getCoordinates();
4264 // var dock = $(MUI.options.dock);
4265 var dockWrapper = $(MUI.options.dockWrapper);
4267 // Setting the desktop height may only be needed by IE7
4269 this.desktop.setStyle('height', windowDimensions.height);
4272 // Set pageWrapper height so the dock doesn't cover the pageWrapper scrollbars.
4273 if (this.pageWrapper) {
4274 var dockOffset = MUI.dockVisible ? dockWrapper.offsetHeight : 0;
4275 var pageWrapperHeight = windowDimensions.height;
4276 pageWrapperHeight -= this.pageWrapper.getStyle('margin-top').toInt();
4277 pageWrapperHeight -= this.pageWrapper.getStyle('margin-bottom').toInt();
4278 if (this.desktopHeader){ pageWrapperHeight -= this.desktopHeader.offsetHeight; }
4279 if (this.desktopFooter){ pageWrapperHeight -= this.desktopFooter.offsetHeight; }
4280 pageWrapperHeight -= dockOffset;
4282 if (pageWrapperHeight < 0){
4283 pageWrapperHeight = 0;
4285 this.pageWrapper.setStyle('height', pageWrapperHeight);
4288 if (MUI.Columns.instances.getKeys().length > 0){ // Conditional is a fix for a bug in IE6 in the no toolbars demo.
4289 MUI.Desktop.resizePanels();
4292 resizePanels: function(){
4298 Function: maximizeWindow
4303 MUI.Desktop.maximizeWindow(windowEl);
4307 maximizeWindow: function(windowEl){
4309 var instance = MUI.Windows.instances.get(windowEl.id);
4310 var options = instance.options;
4311 var windowDrag = instance.windowDrag;
4313 // If window no longer exists or is maximized, stop
4314 if (windowEl != $(windowEl) || instance.isMaximized ) return;
4316 if (instance.isCollapsed){
4317 MUI.collapseToggle(windowEl);
4320 instance.isMaximized = true;
4322 // If window is restricted to a container, it should not be draggable when maximized.
4323 if (instance.options.restrict){
4324 windowDrag.detach();
4325 if (options.resizable) {
4326 instance.detachResizable();
4328 instance.titleBarEl.setStyle('cursor', 'default');
4331 // If the window has a container that is not the desktop
4332 // temporarily move the window to the desktop while it is minimized.
4333 if (options.container != this.desktop){
4334 this.desktop.grab(windowEl);
4335 if (this.options.restrict){
4336 windowDrag.container = this.desktop;
4340 // Save original position
4341 instance.oldTop = windowEl.getStyle('top');
4342 instance.oldLeft = windowEl.getStyle('left');
4344 var contentWrapperEl = instance.contentWrapperEl;
4346 // Save original dimensions
4347 contentWrapperEl.oldWidth = contentWrapperEl.getStyle('width');
4348 contentWrapperEl.oldHeight = contentWrapperEl.getStyle('height');
4351 // Iframe should be hidden when minimizing, maximizing, and moving for performance and Flash issues
4352 if ( instance.iframeEl ) {
4353 if (!MUI.ieLegacySupport) {
4354 instance.iframeEl.setStyle('visibility', 'hidden');
4357 instance.iframeEl.hide();
4361 var windowDimensions = document.getCoordinates();
4362 var options = instance.options;
4363 var shadowBlur = options.shadowBlur;
4364 var shadowOffset = options.shadowOffset;
4365 var newHeight = windowDimensions.height - options.headerHeight - options.footerHeight;
4366 newHeight -= instance.contentBorderEl.getStyle('margin-top').toInt();
4367 newHeight -= instance.contentBorderEl.getStyle('margin-bottom').toInt();
4368 newHeight -= (instance.toolbarWrapperEl ? instance.toolbarWrapperEl.getStyle('height').toInt() + instance.toolbarWrapperEl.getStyle('margin-top').toInt() : 0);
4370 MUI.resizeWindow(windowEl, {
4371 width: windowDimensions.width,
4373 top: shadowOffset.y - shadowBlur,
4374 left: shadowOffset.x - shadowBlur
4376 instance.fireEvent('onMaximize', windowEl);
4378 if (instance.maximizeButtonEl) {
4379 instance.maximizeButtonEl.setProperty('title', 'Restore');
4381 MUI.focusWindow(windowEl);
4386 Function: restoreWindow
4387 Restore a maximized window.
4391 MUI.Desktop.restoreWindow(windowEl);
4395 restoreWindow: function(windowEl){
4397 var instance = windowEl.retrieve('instance');
4399 // Window exists and is maximized ?
4400 if (windowEl != $(windowEl) || !instance.isMaximized) return;
4402 var options = instance.options;
4403 instance.isMaximized = false;
4405 if (options.restrict){
4406 instance.windowDrag.attach();
4407 if (options.resizable){
4408 instance.reattachResizable();
4410 instance.titleBarEl.setStyle('cursor', 'move');
4414 // Iframe should be hidden when minimizing, maximizing, and moving for performance and Flash issues
4415 if ( instance.iframeEl ) {
4416 if (!MUI.ieLegacySupport) {
4417 instance.iframeEl.setStyle('visibility', 'hidden');
4420 instance.iframeEl.hide();
4424 var contentWrapperEl = instance.contentWrapperEl;
4426 MUI.resizeWindow(windowEl,{
4427 width: contentWrapperEl.oldWidth,
4428 height: contentWrapperEl.oldHeight,
4429 top: instance.oldTop,
4430 left: instance.oldLeft
4432 instance.fireEvent('onRestore', windowEl);
4434 if (instance.maximizeButtonEl){
4435 instance.maximizeButtonEl.setProperty('title', 'Maximize');
4443 Create a column. Columns should be created from left to right.
4454 id - The ID of the column. This must be set when creating the column.
4455 container - Defaults to MUI.Desktop.pageWrapper.
4456 placement - Can be 'right', 'main', or 'left'. There must be at least one column with the 'main' option.
4457 width - 'main' column is fluid and should not be given a width.
4458 resizeLimit - resizelimit of a 'right' or 'left' column.
4459 sortable - (boolean) Whether the panels can be reordered via drag and drop.
4460 onResize - (function) Fired when the column is resized.
4461 onCollapse - (function) Fired when the column is collapsed.
4462 onExpand - (function) Fired when the column is expanded.
4465 MUI.Column = new Class({
4467 Implements: [Events, Options],
4484 initialize: function(options){
4485 this.setOptions(options);
4493 // If column has no ID, give it one.
4494 if (this.options.id == null){
4495 this.options.id = 'column' + (++MUI.Columns.columnIDCount);
4498 // Shorten object chain
4499 var options = this.options;
4500 var instances = MUI.Columns.instances;
4501 var instanceID = instances.get(options.id);
4503 if (options.container == null) {
4504 options.container = MUI.Desktop.pageWrapper
4507 $(options.container).setStyle('overflow', 'hidden');
4510 if (typeof this.options.container == 'string'){
4511 this.options.container = $(this.options.container);
4514 // Check to see if there is already a class instance for this Column
4516 var instance = instanceID;
4519 // Check if column already exists
4520 if ( this.columnEl ){
4524 instances.set(options.id, this);
4527 // If loading columns into a panel, hide the regular content container.
4528 if ($(options.container).getElement('.pad') != null) {
4529 $(options.container).getElement('.pad').hide();
4532 // If loading columns into a window, hide the regular content container.
4533 if ($(options.container).getElement('.mochaContent') != null) {
4534 $(options.container).getElement('.mochaContent').hide();
4537 this.columnEl = new Element('div', {
4538 'id': this.options.id,
4539 'class': 'column expanded',
4541 'width': options.placement == 'main' ? null : options.width
4543 }).inject($(options.container));
4545 this.columnEl.store('instance', this);
4547 var parent = this.columnEl.getParent();
4548 var columnHeight = parent.getStyle('height').toInt();
4549 this.columnEl.setStyle('height', columnHeight);
4551 if (this.options.sortable){
4552 if (!this.options.container.retrieve('sortables')){
4553 var sortables = new Sortables(this.columnEl, {
4555 handle: '.panel-header',
4559 $$('.column').each(function(column){
4560 column.getChildren('.panelWrapper').each(function(panelWrapper){
4561 panelWrapper.getElement('.panel').removeClass('bottomPanel');
4563 if (column.getChildren('.panelWrapper').getLast()){
4564 column.getChildren('.panelWrapper').getLast().getElement('.panel').addClass('bottomPanel');
4570 this.options.container.store('sortables', sortables);
4573 this.options.container.retrieve('sortables').addLists(this.columnEl);
4577 if (options.placement == 'main'){
4578 this.columnEl.addClass('rWidth');
4581 switch (this.options.placement) {
4583 this.handleEl = new Element('div', {
4584 'id': this.options.id + '_handle',
4585 'class': 'columnHandle'
4586 }).inject(this.columnEl, 'after');
4588 this.handleIconEl = new Element('div', {
4589 'id': options.id + '_handle_icon',
4590 'class': 'handleIcon'
4591 }).inject(this.handleEl);
4593 addResizeRight(this.columnEl, options.resizeLimit[0], options.resizeLimit[1]);
4596 this.handleEl = new Element('div', {
4597 'id': this.options.id + '_handle',
4598 'class': 'columnHandle'
4599 }).inject(this.columnEl, 'before');
4601 this.handleIconEl = new Element('div', {
4602 'id': options.id + '_handle_icon',
4603 'class': 'handleIcon'
4604 }).inject(this.handleEl);
4605 addResizeLeft(this.columnEl, options.resizeLimit[0], options.resizeLimit[1]);
4609 if (this.handleEl != null){
4610 this.handleEl.addEvent('dblclick', function(){
4611 this.columnToggle();
4618 columnToggle: function(){
4619 var column = this.columnEl;
4622 if (this.isCollapsed == false){
4623 this.oldWidth = column.getStyle('width').toInt();
4625 this.resize.detach();
4626 this.handleEl.removeEvents('dblclick');
4627 this.handleEl.addEvent('click', function(){
4628 this.columnToggle();
4630 this.handleEl.setStyle('cursor', 'pointer').addClass('detached');
4632 column.setStyle('width', 0);
4633 this.isCollapsed = true;
4634 column.addClass('collapsed');
4635 column.removeClass('expanded');
4637 this.fireEvent('onCollapse');
4641 column.setStyle('width', this.oldWidth);
4642 this.isCollapsed = false;
4643 column.addClass('expanded');
4644 column.removeClass('collapsed');
4646 this.handleEl.removeEvents('click');
4647 this.handleEl.addEvent('dblclick', function(){
4648 this.columnToggle();
4650 this.resize.attach();
4651 this.handleEl.setStyle('cursor', (Browser.Engine.webkit || Browser.Engine.gecko) ? 'col-resize' : 'e-resize').addClass('attached');
4654 this.fireEvent('onExpand');
4658 MUI.Column.implement(new Options, new Events);
4663 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.
4674 id - The ID of the panel. This must be set when creating the panel.
4675 column - Where to inject the panel. This must be set when creating the panel.
4676 loadMethod - ('html', 'xhr', or 'iframe') Defaults to 'html' if there is no contentURL. Defaults to 'xhr' if there is a contentURL. You only really need to set this if using the 'iframe' method. May create a 'panel' loadMethod in the future.
4677 contentURL - Used if loadMethod is set to 'xhr' or 'iframe'.
4678 method - ('get', or 'post') The method used to get the data. Defaults to 'get'.
4679 data - (hash) Data to send with the URL. Defaults to null.
4680 evalScripts - (boolean) An xhr loadMethod option. Defaults to true.
4681 evalResponse - (boolean) An xhr loadMethod option. Defaults to false.
4682 content - (string or element) An html loadMethod option.
4684 tabsData - (hash) Data to send with the URL. Defaults to null.
4685 tabsOnload - (function)
4686 header - (boolean) Display the panel header or not
4687 headerToolbox: (boolean)
4688 headerToolboxURL: (url)
4689 headerToolboxOnload: (function)
4690 height - (number) Height of content area.
4691 addClass - (string) Add a class to the panel.
4692 scrollbars - (boolean)
4694 collapsible - (boolean)
4695 onBeforeBuild - (function) Fired before the panel is created.
4696 onContentLoaded - (function) Fired after the panel's conten is loaded.
4697 onResize - (function) Fired when the panel is resized.
4698 onCollapse - (function) Fired when the panel is collapsed.
4699 onExpand - (function) Fired when the panel is expanded.
4702 MUI.Panel = new Class({
4704 Implements: [Events, Options],
4723 evalResponse: false,
4726 content: 'Panel content',
4734 headerToolbox: false,
4735 headerToolboxURL: 'pages/lipsum.html',
4736 headerToolboxOnload: $empty,
4742 padding: { top: 8, right: 8, bottom: 8, left: 8 },
4748 onBeforeBuild: $empty,
4749 onContentLoaded: $empty,
4755 initialize: function(options){
4756 this.setOptions(options);
4760 isCollapsed: false, // This is probably redundant since we can check for the class
4765 // If panel has no ID, give it one.
4766 if (this.options.id == null){
4767 this.options.id = 'panel' + (++MUI.Panels.panelIDCount);
4770 // Shorten object chain
4771 var instances = MUI.Panels.instances;
4772 var instanceID = instances.get(this.options.id);
4773 var options = this.options;
4775 // Check to see if there is already a class instance for this panel
4777 var instance = instanceID;
4780 // Check if panel already exists
4781 if ( this.panelEl ){
4785 instances.set(this.options.id, this);
4788 this.fireEvent('onBeforeBuild');
4790 if (options.loadMethod == 'iframe') {
4791 // Iframes have their own padding.
4792 options.padding = { top: 0, right: 0, bottom: 0, left: 0 };
4795 this.showHandle = true;
4796 if ($(options.column).getChildren().length == 0) {
4797 this.showHandle = false;
4800 this.panelWrapperEl = new Element('div', {
4801 'id': this.options.id + '_wrapper',
4802 'class': 'panelWrapper expanded'
4803 }).inject($(options.column));
4805 this.panelEl = new Element('div', {
4806 'id': this.options.id,
4807 'class': 'panel expanded',
4809 'height': options.height
4811 }).inject(this.panelWrapperEl);
4813 this.panelEl.store('instance', this);
4815 this.panelEl.addClass(options.addClass);
4817 this.contentEl = new Element('div', {
4818 'id': options.id + '_pad',
4820 }).inject(this.panelEl);
4822 // This is in order to use the same variable as the windows do in updateContent.
4823 // May rethink this.
4824 this.contentWrapperEl = this.panelEl;
4826 this.contentEl.setStyles({
4827 'padding-top': options.padding.top,
4828 'padding-bottom': options.padding.bottom,
4829 'padding-left': options.padding.left,
4830 'padding-right': options.padding.right
4833 this.panelHeaderEl = new Element('div', {
4834 'id': this.options.id + '_header',
4835 'class': 'panel-header',
4837 'display': options.header ? 'block' : 'none'
4839 }).inject(this.panelEl, 'before');
4841 var columnInstances = MUI.Columns.instances;
4842 var columnInstance = columnInstances.get(this.options.column);
4844 if (columnInstance.options.sortable){
4845 this.panelHeaderEl.setStyle('cursor', 'move');
4846 columnInstance.options.container.retrieve('sortables').addItems(this.panelWrapperEl);
4849 if (this.options.collapsible) {
4850 this.collapseToggleInit();
4853 if (this.options.headerToolbox) {
4854 this.panelHeaderToolboxEl = new Element('div', {
4855 'id': options.id + '_headerToolbox',
4856 'class': 'panel-header-toolbox'
4857 }).inject(this.panelHeaderEl);
4860 this.panelHeaderContentEl = new Element('div', {
4861 'id': options.id + '_headerContent',
4862 'class': 'panel-headerContent'
4863 }).inject(this.panelHeaderEl);
4865 this.titleEl = new Element('h2', {
4866 'id': options.id + '_title'
4867 }).inject(this.panelHeaderContentEl);
4869 this.handleEl = new Element('div', {
4870 'id': options.id + '_handle',
4871 'class': 'horizontalHandle',
4873 'display': this.showHandle == true ? 'block' : 'none'
4875 }).inject(this.panelEl, 'after');
4877 this.handleIconEl = new Element('div', {
4878 'id': options.id + '_handle_icon',
4879 'class': 'handleIcon'
4880 }).inject(this.handleEl);
4882 addResizeBottom(options.id);
4884 if (options.require.css.length || options.require.images.length){
4886 css: options.require.css,
4887 images: options.require.images,
4897 newPanel: function(){
4899 options = this.options;
4901 if (this.options.headerToolbox) {
4903 'element': this.panelEl,
4904 'childElement': this.panelHeaderToolboxEl,
4905 'loadMethod': 'xhr',
4906 'url': options.headerToolboxURL,
4907 'onContentLoaded': options.headerToolboxOnload
4911 if (options.tabsURL == null) {
4912 this.titleEl.set('html', options.title);
4914 this.panelHeaderContentEl.addClass('tabs');
4916 'element': this.panelEl,
4917 'childElement': this.panelHeaderContentEl,
4918 'loadMethod': 'xhr',
4919 'url': options.tabsURL,
4920 'data': options.tabsData,
4921 'onContentLoaded': options.tabsOnload
4925 // Add content to panel.
4927 'element': this.panelEl,
4928 'content': options.content,
4929 'method': options.method,
4930 'data': options.data,
4931 'url': options.contentURL,
4932 'onContentLoaded': null,
4934 js: options.require.js,
4935 onload: options.require.onload
4939 // Do this when creating and removing panels
4940 $(options.column).getChildren('.panelWrapper').each(function(panelWrapper){
4941 panelWrapper.getElement('.panel').removeClass('bottomPanel');
4943 $(options.column).getChildren('.panelWrapper').getLast().getElement('.panel').addClass('bottomPanel');
4945 MUI.panelHeight(options.column, this.panelEl, 'new');
4948 collapseToggleInit: function(options){
4950 var options = this.options;
4952 this.panelHeaderCollapseBoxEl = new Element('div', {
4953 'id': options.id + '_headerCollapseBox',
4955 }).inject(this.panelHeaderEl);
4957 if (options.headerToolbox) {
4958 this.panelHeaderCollapseBoxEl.addClass('divider');
4961 this.collapseToggleEl = new Element('div', {
4962 'id': options.id + '_collapseToggle',
4963 'class': 'panel-collapse icon16',
4968 'title': 'Collapse Panel'
4969 }).inject(this.panelHeaderCollapseBoxEl);
4971 this.collapseToggleEl.addEvent('click', function(event){
4972 var panel = this.panelEl;
4973 var panelWrapper = this.panelWrapperEl
4975 // Get siblings and make sure they are not all collapsed.
4976 // If they are all collapsed and the current panel is collapsing
4977 // Then collapse the column.
4978 var instances = MUI.Panels.instances;
4979 var expandedSiblings = [];
4981 panelWrapper.getAllPrevious('.panelWrapper').each(function(sibling){
4982 var instance = instances.get(sibling.getElement('.panel').id);
4983 if (instance.isCollapsed == false){
4984 expandedSiblings.push(sibling.getElement('.panel').id);
4988 panelWrapper.getAllNext('.panelWrapper').each(function(sibling){
4989 var instance = instances.get(sibling.getElement('.panel').id);
4990 if (instance.isCollapsed == false){
4991 expandedSiblings.push(sibling.getElement('.panel').id);
4996 if (this.isCollapsed == false) {
4997 var currentColumn = MUI.Columns.instances.get($(options.column).id);
4999 if (expandedSiblings.length == 0 && currentColumn.options.placement != 'main'){
5000 var currentColumn = MUI.Columns.instances.get($(options.column).id);
5001 currentColumn.columnToggle();
5004 else if (expandedSiblings.length == 0 && currentColumn.options.placement == 'main'){
5007 this.oldHeight = panel.getStyle('height').toInt();
5008 if (this.oldHeight < 10) this.oldHeight = 20;
5009 this.contentEl.setStyle('position', 'absolute'); // This is so IE6 and IE7 will collapse the panel all the way
5010 panel.setStyle('height', 0);
5011 this.isCollapsed = true;
5012 panelWrapper.addClass('collapsed');
5013 panelWrapper.removeClass('expanded');
5014 MUI.panelHeight(options.column, panel, 'collapsing');
5015 MUI.panelHeight(); // Run this a second time for panels within panels
5016 this.collapseToggleEl.removeClass('panel-collapsed');
5017 this.collapseToggleEl.addClass('panel-expand');
5018 this.collapseToggleEl.setProperty('title','Expand Panel');
5019 this.fireEvent('onCollapse');
5024 this.contentEl.setStyle('position', null); // This is so IE6 and IE7 will collapse the panel all the way
5025 panel.setStyle('height', this.oldHeight);
5026 this.isCollapsed = false;
5027 panelWrapper.addClass('expanded');
5028 panelWrapper.removeClass('collapsed');
5029 MUI.panelHeight(this.options.column, panel, 'expanding');
5030 MUI.panelHeight(); // Run this a second time for panels within panels
5031 this.collapseToggleEl.removeClass('panel-expand');
5032 this.collapseToggleEl.addClass('panel-collapsed');
5033 this.collapseToggleEl.setProperty('title','Collapse Panel');
5034 this.fireEvent('onExpand');
5039 MUI.Panel.implement(new Options, new Events);
5043 column - The column to resize the panels in
5044 changing - The panel that is collapsing, expanding, or new
5045 action - collapsing, expanding, or new
5051 panelHeight: function(column, changing, action){
5052 if (column != null) {
5053 MUI.panelHeight2($(column), changing, action);
5056 $$('.column').each(function(column){
5057 MUI.panelHeight2(column);
5063 actions can be new, collapsing or expanding.
5066 panelHeight2: function(column, changing, action){
5068 var instances = MUI.Panels.instances;
5070 var parent = column.getParent();
5071 var columnHeight = parent.getStyle('height').toInt();
5072 if (Browser.Engine.trident4 && parent == MUI.Desktop.pageWrapper) {
5075 column.setStyle('height', columnHeight);
5077 // Get column panels
5079 column.getChildren('.panelWrapper').each( function(panelWrapper){
5080 panels.push(panelWrapper.getElement('.panel'));
5083 // Get expanded column panels
5084 var panelsExpanded = [];
5085 column.getChildren('.expanded').each( function(panelWrapper){
5086 panelsExpanded.push(panelWrapper.getElement('.panel'));
5089 // All the panels in the column whose height will be effected.
5090 var panelsToResize = [];
5092 // The panel with the greatest height. Remainders will be added to this panel
5094 var tallestPanelHeight = 0;
5096 this.panelsTotalHeight = 0; // Height of all the panels in the column
5097 this.height = 0; // Height of all the elements in the column
5099 // Set panel resize partners
5100 panels.each(function(panel){
5101 instance = instances.get(panel.id);
5102 if (panel.getParent().hasClass('expanded') && panel.getParent().getNext('.expanded')) {
5103 instance.partner = panel.getParent().getNext('.expanded').getElement('.panel');
5104 instance.resize.attach();
5105 instance.handleEl.setStyles({
5107 'cursor': (Browser.Engine.webkit || Browser.Engine.gecko) ? 'row-resize' : 'n-resize'
5108 }).removeClass('detached');
5110 instance.resize.detach();
5111 instance.handleEl.setStyles({
5114 }).addClass('detached');
5116 if (panel.getParent().getNext('.panelWrapper') == null) {
5117 instance.handleEl.hide();
5121 // Add panels to panelsToResize
5122 // Get the total height of all the resizable panels
5123 // Get the total height of all the column's children
5124 column.getChildren().each(function(panelWrapper){
5126 panelWrapper.getChildren().each(function(el){
5128 if (el.hasClass('panel')){
5129 var instance = instances.get(el.id);
5131 // Are any next siblings Expanded?
5132 anyNextSiblingsExpanded = function(el){
5134 el.getParent().getAllNext('.panelWrapper').each(function(sibling){
5135 var siblingInstance = instances.get(sibling.getElement('.panel').id);
5136 if (siblingInstance.isCollapsed == false){
5143 // If a next sibling is expanding, are any of the nexts siblings of the expanding sibling Expanded?
5144 anyExpandingNextSiblingsExpanded = function(el){
5146 changing.getParent().getAllNext('.panelWrapper').each(function(sibling){
5147 var siblingInstance = instances.get(sibling.getElement('.panel').id);
5148 if (siblingInstance.isCollapsed == false){
5155 // Is the panel that is collapsing, expanding, or new located after this panel?
5156 anyNextContainsChanging = function(el){
5158 el.getParent().getAllNext('.panelWrapper').each(function(panelWrapper){
5159 allNext.push(panelWrapper.getElement('.panel'));
5161 var test = allNext.contains(changing);
5165 nextExpandedChanging = function(el){
5167 if (el.getParent().getNext('.expanded')){
5168 if (el.getParent().getNext('.expanded').getElement('.panel') == changing) test = true;
5174 // Resize panels that are "new" or not collapsed
5175 if (action == 'new') {
5176 if (!instance.isCollapsed && el != changing) {
5177 panelsToResize.push(el);
5178 this.panelsTotalHeight += el.offsetHeight.toInt();
5182 // COLLAPSING PANELS and CURRENTLY EXPANDED PANELS
5183 // Resize panels that are not collapsed.
5184 // If a panel is collapsing resize any expanded panels below.
5185 // If there are no expanded panels below it, resize the expanded panels above it.
5186 else if (action == null || action == 'collapsing' ){
5187 if (!instance.isCollapsed && (!anyNextContainsChanging(el) || !anyNextSiblingsExpanded(el))){
5188 panelsToResize.push(el);
5189 this.panelsTotalHeight += el.offsetHeight.toInt();
5194 // Resize panels that are not collapsed and are not expanding.
5195 // Resize any expanded panels below the expanding panel.
5196 // If there are no expanded panels below the expanding panel, resize the first expanded panel above it.
5197 else if (action == 'expanding' && !instance.isCollapsed && el != changing){
5198 if (!anyNextContainsChanging(el) || (!anyExpandingNextSiblingsExpanded(el) && nextExpandedChanging(el))){
5199 panelsToResize.push(el);
5200 this.panelsTotalHeight += el.offsetHeight.toInt();
5204 if (el.style.height){
5205 this.height += el.getStyle('height').toInt();
5209 this.height += el.offsetHeight.toInt();
5215 // Get the remaining height
5216 var remainingHeight = column.offsetHeight.toInt() - this.height;
5220 // Get height of all the column's children
5221 column.getChildren().each(function(el){
5222 this.height += el.offsetHeight.toInt();
5225 var remainingHeight = column.offsetHeight.toInt() - this.height;
5227 panelsToResize.each(function(panel){
5228 var ratio = this.panelsTotalHeight / panel.offsetHeight.toInt();
5229 var panelHeight = panel.getStyle('height').toInt();
5230 var newPanelHeight = remainingHeight / ratio;
5231 if (!isNaN(panelHeight))
5232 newPanelHeight += panelHeight;
5233 if (newPanelHeight < 1){
5236 panel.setStyle('height', newPanelHeight);
5239 // Make sure the remaining height is 0. If not add/subtract the
5240 // remaining height to the tallest panel. This makes up for browser resizing,
5241 // off ratios, and users trying to give panels too much height.
5243 // Get height of all the column's children
5245 column.getChildren().each(function(panelWrapper){
5246 panelWrapper.getChildren().each(function(el){
5247 this.height += el.offsetHeight.toInt();
5248 if (el.hasClass('panel') && el.getStyle('height').toInt() > tallestPanelHeight){
5250 tallestPanelHeight = el.getStyle('height').toInt();
5255 var remainingHeight = column.offsetHeight.toInt() - this.height;
5257 if (remainingHeight != 0 && tallestPanelHeight > 0){
5258 tallestPanel.setStyle('height', tallestPanel.getStyle('height').toInt() + remainingHeight );
5259 if (tallestPanel.getStyle('height') < 1){
5260 tallestPanel.setStyle('height', 0 );
5264 parent.getChildren('.columnHandle').each(function(handle){
5265 var parent = handle.getParent();
5266 if (parent.getStyle('height').toInt() < 1) return; // Keeps IE7 and 8 from throwing an error when collapsing a panel within a panel
5267 var handleHeight = parent.getStyle('height').toInt() - handle.getStyle('margin-top').toInt() - handle.getStyle('margin-bottom').toInt();
5268 if (Browser.Engine.trident4 && parent == MUI.Desktop.pageWrapper){
5271 handle.setStyle('height', handleHeight);
5274 panelsExpanded.each(function(panel){
5275 MUI.resizeChildren(panel);
5279 // May rename this resizeIframeEl()
5280 resizeChildren: function(panel){
5281 var instances = MUI.Panels.instances;
5282 var instance = instances.get(panel.id);
5283 var contentWrapperEl = instance.contentWrapperEl;
5285 if (instance.iframeEl) {
5286 if (!MUI.ieLegacySupport) {
5287 instance.iframeEl.setStyles({
5288 'height': contentWrapperEl.getStyle('height'),
5289 'width': contentWrapperEl.offsetWidth - contentWrapperEl.getStyle('margin-left').toInt() - contentWrapperEl.getStyle('margin-right').toInt()
5293 // The following hack is to get IE8 RC1 IE8 Standards Mode to properly resize an iframe
5294 // when only the vertical dimension is changed.
5295 instance.iframeEl.setStyles({
5296 'height': contentWrapperEl.getStyle('height'),
5297 'width': contentWrapperEl.offsetWidth - contentWrapperEl.getStyle('margin-left').toInt() - contentWrapperEl.getStyle('margin-right').toInt() - 1
5299 instance.iframeEl.setStyles({
5300 'width': contentWrapperEl.offsetWidth - contentWrapperEl.getStyle('margin-left').toInt() - contentWrapperEl.getStyle('margin-right').toInt()
5307 rWidth: function(container){
5308 if (container == null) {
5309 var container = MUI.Desktop.desktop;
5311 container.getElements('.rWidth').each(function(column){
5312 var currentWidth = column.offsetWidth.toInt();
5313 currentWidth -= column.getStyle('margin-left').toInt();
5314 currentWidth -= column.getStyle('margin-right').toInt();
5315 var parent = column.getParent();
5318 // Get the total width of all the parent element's children
5319 parent.getChildren().each(function(el){
5320 if (el.hasClass('mocha') != true) {
5321 this.width += el.offsetWidth.toInt();
5325 // Add the remaining width to the current element
5326 var remainingWidth = parent.offsetWidth.toInt() - this.width;
5327 var newWidth = currentWidth + remainingWidth;
5328 if (newWidth < 1) newWidth = 0;
5329 column.setStyle('width', newWidth);
5330 column.getChildren('.panel').each(function(panel){
5331 panel.setStyle('width', newWidth - panel.getStyle('margin-left').toInt() - panel.getStyle('margin-right').toInt());
5332 MUI.resizeChildren(panel);
5340 function addResizeRight(element, min, max){
5341 if (!$(element)) return;
5342 element = $(element);
5344 var instances = MUI.Columns.instances;
5345 var instance = instances.get(element.id);
5347 var handle = element.getNext('.columnHandle');
5348 handle.setStyle('cursor', (Browser.Engine.webkit || Browser.Engine.gecko) ? 'col-resize' : 'e-resize');
5350 if (!max) max = 250;
5351 if (MUI.ieLegacySupport) {
5353 'mousedown': function(){
5354 handle.setCapture();
5356 'mouseup': function(){
5357 handle.releaseCapture();
5361 instance.resize = element.makeResizable({
5370 onStart: function(){
5371 element.getElements('iframe').setStyle('visibility', 'hidden');
5372 element.getNext('.column').getElements('iframe').setStyle('visibility', 'hidden');
5375 MUI.rWidth(element.getParent());
5376 if (Browser.Engine.trident4) {
5377 element.getChildren().each(function(el){
5378 var width = $(element).getStyle('width').toInt();
5379 width -= el.getStyle('margin-right').toInt();
5380 width -= el.getStyle('margin-left').toInt();
5381 width -= el.getStyle('padding-right').toInt();
5382 width -= el.getStyle('padding-left').toInt();
5383 el.setStyle('width', width);
5387 onComplete: function(){
5388 MUI.rWidth(element.getParent());
5389 element.getElements('iframe').setStyle('visibility', 'visible');
5390 element.getNext('.column').getElements('iframe').setStyle('visibility', 'visible');
5391 instance.fireEvent('onResize');
5396 function addResizeLeft(element, min, max){
5397 if (!$(element)) return;
5398 element = $(element);
5400 var instances = MUI.Columns.instances;
5401 var instance = instances.get(element.id);
5403 var handle = element.getPrevious('.columnHandle');
5404 handle.setStyle('cursor', (Browser.Engine.webkit || Browser.Engine.gecko) ? 'col-resize' : 'e-resize');
5405 var partner = element.getPrevious('.column');
5407 if (!max) max = 250;
5408 if (MUI.ieLegacySupport){
5410 'mousedown': function(){
5411 handle.setCapture();
5413 'mouseup': function(){
5414 handle.releaseCapture();
5418 instance.resize = element.makeResizable({
5420 modifiers: {x: 'width' , y: false},
5422 limit: { x: [min, max] },
5423 onStart: function(){
5424 $(element).getElements('iframe').setStyle('visibility','hidden');
5425 partner.getElements('iframe').setStyle('visibility','hidden');
5428 MUI.rWidth(element.getParent());
5430 onComplete: function(){
5431 MUI.rWidth(element.getParent());
5432 $(element).getElements('iframe').setStyle('visibility','visible');
5433 partner.getElements('iframe').setStyle('visibility','visible');
5434 instance.fireEvent('onResize');
5439 function addResizeBottom(element){
5440 if (!$(element)) return;
5441 var element = $(element);
5443 var instances = MUI.Panels.instances;
5444 var instance = instances.get(element.id);
5445 var handle = instance.handleEl;
5446 handle.setStyle('cursor', (Browser.Engine.webkit || Browser.Engine.gecko) ? 'row-resize' : 'n-resize');
5447 partner = instance.partner;
5450 return element.getStyle('height').toInt() + partner.getStyle('height').toInt();
5453 if (MUI.ieLegacySupport) {
5455 'mousedown': function(){
5456 handle.setCapture();
5458 'mouseup': function(){
5459 handle.releaseCapture();
5463 instance.resize = element.makeResizable({
5465 modifiers: {x: false, y: 'height'},
5466 limit: { y: [min, max] },
5468 onBeforeStart: function(){
5469 partner = instance.partner;
5470 this.originalHeight = element.getStyle('height').toInt();
5471 this.partnerOriginalHeight = partner.getStyle('height').toInt();
5473 onStart: function(){
5474 if (instance.iframeEl) {
5475 if (!MUI.ieLegacySupport) {
5476 instance.iframeEl.setStyle('visibility', 'hidden');
5477 partner.getElements('iframe').setStyle('visibility','hidden');
5480 instance.iframeEl.hide();
5481 partner.getElements('iframe').hide();
5487 partnerHeight = partnerOriginalHeight;
5488 partnerHeight += (this.originalHeight - element.getStyle('height').toInt());
5489 partner.setStyle('height', partnerHeight);
5490 MUI.resizeChildren(element, element.getStyle('height').toInt());
5491 MUI.resizeChildren(partner, partnerHeight);
5492 element.getChildren('.column').each( function(column){
5493 MUI.panelHeight(column);
5495 partner.getChildren('.column').each( function(column){
5496 MUI.panelHeight(column);
5499 onComplete: function(){
5500 partnerHeight = partnerOriginalHeight;
5501 partnerHeight += (this.originalHeight - element.getStyle('height').toInt());
5502 partner.setStyle('height', partnerHeight);
5503 MUI.resizeChildren(element, element.getStyle('height').toInt());
5504 MUI.resizeChildren(partner, partnerHeight);
5505 element.getChildren('.column').each( function(column){
5506 MUI.panelHeight(column);
5508 partner.getChildren('.column').each( function(column){
5509 MUI.panelHeight(column);
5511 if (instance.iframeEl) {
5512 if (!MUI.ieLegacySupport) {
5513 instance.iframeEl.setStyle('visibility', 'visible');
5514 partner.getElements('iframe').setStyle('visibility','visible');
5517 instance.iframeEl.show();
5518 partner.getElements('iframe').show();
5519 // The following hack is to get IE8 Standards Mode to properly resize an iframe
5520 // when only the vertical dimension is changed.
5521 var width = instance.iframeEl.getStyle('width').toInt();
5522 instance.iframeEl.setStyle('width', width - 1);
5524 instance.iframeEl.setStyle('width', width);
5527 instance.fireEvent('onResize');
5535 Function: closeColumn
5536 Destroys/removes a column.
5544 columnEl - the ID of the column to be closed
5547 true - the column was closed
5548 false - the column was not closed
5551 closeColumn: function(columnEl){
5552 var instances = MUI.Columns.instances;
5553 var instance = instances.get(columnEl.id);
5554 if (columnEl != $(columnEl) || instance.isClosing) return;
5556 instance.isClosing = true;
5558 if (instance.options.sortable){
5559 instance.container.retrieve('sortables').removeLists(this.columnEl);
5562 // Destroy all the panels in the column.
5563 var panels = columnEl.getChildren('.panel');
5564 panels.each(function(panel){
5565 MUI.closePanel($(panel.id));
5568 if (MUI.ieLegacySupport) {
5570 if (instance.handleEl != null) {
5571 instance.handleEl.dispose();
5576 if (instance.handleEl != null) {
5577 instance.handleEl.destroy();
5581 MUI.Desktop.resizePanels();
5583 instances.erase(instance.options.id);
5588 Function: closePanel
5589 Destroys/removes a panel.
5597 panelEl - the ID of the panel to be closed
5600 true - the panel was closed
5601 false - the panel was not closed
5604 closePanel: function(panelEl){
5605 var instances = MUI.Panels.instances;
5606 var instance = instances.get(panelEl.id);
5607 if (panelEl != $(panelEl) || instance.isClosing) return;
5609 var column = instance.options.column;
5611 instance.isClosing = true;
5613 var columnInstances = MUI.Columns.instances;
5614 var columnInstance = columnInstances.get(column);
5616 if (columnInstance.options.sortable){
5617 columnInstance.options.container.retrieve('sortables').removeItems(instance.panelWrapperEl);
5620 instance.panelWrapperEl.destroy();
5623 MUI.Desktop.resizePanels();
5626 // Do this when creating and removing panels
5627 $(column).getChildren('.panelWrapper').each(function(panelWrapper){
5628 panelWrapper.getElement('.panel').removeClass('bottomPanel');
5630 $(column).getChildren('.panelWrapper').getLast().getElement('.panel').addClass('bottomPanel');
5632 instances.erase(instance.options.id);
5640 Implements the dock/taskbar. Enables window minimize.
5643 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
5649 Core.js, Window.js, Layout.js
5652 - Make it so the dock requires no initial html markup.
5656 MUI.files[MUI.path.source + 'Layout/Dock.js'] = 'loaded';
5658 MUI.options.extend({
5660 // If you change the IDs of the Mocha Desktop containers in your HTML, you need to change them here as well.
5661 dockWrapper: 'dockWrapper',
5668 Function: minimizeAll
5669 Minimize all windows that are minimizable.
5672 minimizeAll: function() {
5673 $$('.mocha').each(function(windowEl){
5674 var instance = windowEl.retrieve('instance');
5675 if (!instance.isMinimized && instance.options.minimizable == true){
5676 MUI.Dock.minimizeWindow(windowEl);
5685 useControls: true, // Toggles autohide and dock placement controls.
5686 dockPosition: 'bottom', // Position the dock starts in, top or bottom.
5688 trueButtonColor: [70, 245, 70], // Color for autohide on
5689 enabledButtonColor: [115, 153, 191],
5690 disabledButtonColor: [170, 170, 170]
5693 initialize: function(options){
5694 // Stops if MUI.Desktop is not implemented
5695 if (!MUI.Desktop) return;
5697 MUI.dockVisible = true;
5698 this.dockWrapper = $(MUI.options.dockWrapper);
5699 this.dock = $(MUI.options.dock);
5700 this.autoHideEvent = null;
5701 this.dockAutoHide = false; // True when dock autohide is set to on, false if set to off
5703 if (!this.dockWrapper) return;
5705 if (!this.options.useControls){
5706 if($('dockPlacement')){
5707 $('dockPlacement').setStyle('cursor', 'default');
5709 if($('dockAutoHide')){
5710 $('dockAutoHide').setStyle('cursor', 'default');
5714 this.dockWrapper.setStyles({
5716 'position': 'absolute',
5718 'bottom': MUI.Desktop.desktopFooter ? MUI.Desktop.desktopFooter.offsetHeight : 0,
5722 if (this.options.useControls){
5723 this.initializeDockControls();
5726 // Add check mark to menu if link exists in menu
5727 if ($('dockLinkCheck')){
5728 this.sidebarCheck = new Element('div', {
5731 }).inject($('dockLinkCheck'));
5734 this.dockSortables = new Sortables('#dockSort', {
5741 MUI.Desktop.setDesktopSize();
5744 MUI.myChain.callChain();
5749 initializeDockControls: function(){
5751 // Convert CSS colors to Canvas colors.
5752 this.setDockColors();
5754 if (this.options.useControls){
5756 var canvas = new Element('canvas', {
5760 }).inject(this.dock);
5762 // Dynamically initialize canvas using excanvas. This is only required by IE
5763 if (MUI.ieLegacySupport && MUI.ieSupport == 'excanvas'){
5764 G_vmlCanvasManager.initElement(canvas);
5768 var dockPlacement = $('dockPlacement');
5769 var dockAutoHide = $('dockAutoHide');
5771 // Position top or bottom selector
5772 dockPlacement.setProperty('title','Position Dock Top');
5775 dockPlacement.addEvent('click', function(){
5779 // Auto Hide toggle switch
5780 dockAutoHide.setProperty('title','Turn Auto Hide On');
5782 // Attach event Auto Hide
5783 dockAutoHide.addEvent('click', function(event){
5784 if ( this.dockWrapper.getProperty('dockPosition') == 'top' )
5787 var ctx = $('dockCanvas').getContext('2d');
5788 this.dockAutoHide = !this.dockAutoHide; // Toggle
5789 if (this.dockAutoHide){
5790 $('dockAutoHide').setProperty('title', 'Turn Auto Hide Off');
5791 //ctx.clearRect(0, 11, 100, 100);
5792 MUI.circle(ctx, 5 , 14, 3, this.options.trueButtonColor, 1.0);
5795 this.autoHideEvent = function(event) {
5796 if (!this.dockAutoHide)
5798 if (!MUI.Desktop.desktopFooter) {
5799 var dockHotspotHeight = this.dockWrapper.offsetHeight;
5800 if (dockHotspotHeight < 25) dockHotspotHeight = 25;
5802 else if (MUI.Desktop.desktopFooter) {
5803 var dockHotspotHeight = this.dockWrapper.offsetHeight + MUI.Desktop.desktopFooter.offsetHeight;
5804 if (dockHotspotHeight < 25) dockHotspotHeight = 25;
5806 if (!MUI.Desktop.desktopFooter && event.client.y > (document.getCoordinates().height - dockHotspotHeight)){
5807 if (!MUI.dockVisible){
5808 this.dockWrapper.show();
5809 MUI.dockVisible = true;
5810 MUI.Desktop.setDesktopSize();
5813 else if (MUI.Desktop.desktopFooter && event.client.y > (document.getCoordinates().height - dockHotspotHeight)){
5814 if (!MUI.dockVisible){
5815 this.dockWrapper.show();
5816 MUI.dockVisible = true;
5817 MUI.Desktop.setDesktopSize();
5820 else if (MUI.dockVisible){
5821 this.dockWrapper.hide();
5822 MUI.dockVisible = false;
5823 MUI.Desktop.setDesktopSize();
5829 document.addEvent('mousemove', this.autoHideEvent);
5832 $('dockAutoHide').setProperty('title', 'Turn Auto Hide On');
5833 //ctx.clearRect(0, 11, 100, 100);
5834 MUI.circle(ctx, 5 , 14, 3, this.options.enabledButtonColor, 1.0);
5836 document.removeEvent('mousemove', this.autoHideEvent);
5841 this.renderDockControls();
5843 if (this.options.dockPosition == 'top'){
5849 setDockColors: function(){
5850 var dockButtonEnabled = MUI.getCSSRule('.dockButtonEnabled');
5851 if (dockButtonEnabled && dockButtonEnabled.style.backgroundColor){
5852 this.options.enabledButtonColor = new Color(dockButtonEnabled.style.backgroundColor);
5855 var dockButtonDisabled = MUI.getCSSRule('.dockButtonDisabled');
5856 if (dockButtonDisabled && dockButtonDisabled.style.backgroundColor){
5857 this.options.disabledButtonColor = new Color(dockButtonDisabled.style.backgroundColor);
5860 var trueButtonColor = MUI.getCSSRule('.dockButtonTrue');
5861 if (trueButtonColor && trueButtonColor.style.backgroundColor){
5862 this.options.trueButtonColor = new Color(trueButtonColor.style.backgroundColor);
5866 renderDockControls: function(){
5867 // Draw dock controls
5868 var ctx = $('dockCanvas').getContext('2d');
5869 ctx.clearRect(0, 0, 100, 100);
5870 MUI.circle(ctx, 5 , 4, 3, this.options.enabledButtonColor, 1.0);
5872 if( this.dockWrapper.getProperty('dockPosition') == 'top'){
5873 MUI.circle(ctx, 5 , 14, 3, this.options.disabledButtonColor, 1.0)
5875 else if (this.dockAutoHide){
5876 MUI.circle(ctx, 5 , 14, 3, this.options.trueButtonColor, 1.0);
5879 MUI.circle(ctx, 5 , 14, 3, this.options.enabledButtonColor, 1.0);
5883 moveDock: function(){
5884 var ctx = $('dockCanvas').getContext('2d');
5885 // Move dock to top position
5886 if (this.dockWrapper.getStyle('position') != 'relative'){
5887 this.dockWrapper.setStyles({
5888 'position': 'relative',
5891 this.dockWrapper.addClass('top');
5892 MUI.Desktop.setDesktopSize();
5893 this.dockWrapper.setProperty('dockPosition','top');
5894 ctx.clearRect(0, 0, 100, 100);
5895 MUI.circle(ctx, 5, 4, 3, this.options.enabledButtonColor, 1.0);
5896 MUI.circle(ctx, 5, 14, 3, this.options.disabledButtonColor, 1.0);
5897 $('dockPlacement').setProperty('title', 'Position Dock Bottom');
5898 $('dockAutoHide').setProperty('title', 'Auto Hide Disabled in Top Dock Position');
5899 this.dockAutoHide = false;
5901 // Move dock to bottom position
5903 this.dockWrapper.setStyles({
5904 'position': 'absolute',
5905 'bottom': MUI.Desktop.desktopFooter ? MUI.Desktop.desktopFooter.offsetHeight : 0
5907 this.dockWrapper.removeClass('top');
5908 MUI.Desktop.setDesktopSize();
5909 this.dockWrapper.setProperty('dockPosition', 'bottom');
5910 ctx.clearRect(0, 0, 100, 100);
5911 MUI.circle(ctx, 5, 4, 3, this.options.enabledButtonColor, 1.0);
5912 MUI.circle(ctx, 5 , 14, 3, this.options.enabledButtonColor, 1.0);
5913 $('dockPlacement').setProperty('title', 'Position Dock Top');
5914 $('dockAutoHide').setProperty('title', 'Turn Auto Hide On');
5918 createDockTab: function(windowEl){
5920 var instance = windowEl.retrieve('instance');
5921 var titleText = instance.titleEl.innerHTML;
5923 var dockTab = new Element('div', {
5924 'id': instance.options.id + '_dockTab',
5927 }).inject($('dockClear'), 'before');
5929 dockTab.addEvent('mousedown', function(e){
5930 new Event(e).stop();
5931 this.timeDown = $time();
5934 dockTab.addEvent('mouseup', function(e){
5935 this.timeUp = $time();
5936 if ((this.timeUp - this.timeDown) < 275){
5937 // If the visibility of the windows on the page are toggled off, toggle visibility on.
5938 if (MUI.Windows.windowsVisible == false) {
5939 MUI.toggleWindowVisibility();
5940 if (instance.isMinimized == true) {
5941 MUI.Dock.restoreMinimized.delay(25, MUI.Dock, windowEl);
5944 MUI.focusWindow(windowEl);
5948 // If window is minimized, restore window.
5949 if (instance.isMinimized == true) {
5950 MUI.Dock.restoreMinimized.delay(25, MUI.Dock, windowEl);
5953 // If window is not minimized and is focused, minimize window.
5954 if (instance.windowEl.hasClass('isFocused') && instance.options.minimizable == true){
5955 MUI.Dock.minimizeWindow(windowEl)
5957 // If window is not minimized and is not focused, focus window.
5959 MUI.focusWindow(windowEl);
5961 // if the window is not minimized and is outside the viewport, center it in the viewport.
5962 var coordinates = document.getCoordinates();
5963 if (windowEl.getStyle('left').toInt() > coordinates.width || windowEl.getStyle('top').toInt() > coordinates.height){
5964 MUI.centerWindow(windowEl);
5970 this.dockSortables.addItems(dockTab);
5972 var dockTabText = new Element('div', {
5973 'id': instance.options.id + '_dockTabText',
5975 }).set('html', titleText.substring(0,19) + (titleText.length > 19 ? '...' : '')).inject($(dockTab));
5977 // If I implement this again, will need to also adjust the titleText truncate and the tab's
5979 if (instance.options.icon != false){
5980 // dockTabText.setStyle('background', 'url(' + instance.options.icon + ') 4px 4px no-repeat');
5983 // Need to resize everything in case the dock wraps when a new tab is added
5984 MUI.Desktop.setDesktopSize();
5988 makeActiveTab: function(){
5990 // getWindowWith HighestZindex is used in case the currently focused window
5992 var windowEl = MUI.getWindowWithHighestZindex();
5993 var instance = windowEl.retrieve('instance');
5995 $$('.dockTab').removeClass('activeDockTab');
5996 if (instance.isMinimized != true) {
5998 instance.windowEl.addClass('isFocused');
6000 var currentButton = $(instance.options.id + '_dockTab');
6001 if (currentButton != null) {
6002 currentButton.addClass('activeDockTab');
6006 instance.windowEl.removeClass('isFocused');
6010 minimizeWindow: function(windowEl){
6011 if (windowEl != $(windowEl)) return;
6013 var instance = windowEl.retrieve('instance');
6014 instance.isMinimized = true;
6017 // Iframe should be hidden when minimizing, maximizing, and moving for performance and Flash issues
6018 if ( instance.iframeEl ) {
6019 // Some elements are still visible in IE8 in the iframe when the iframe's visibility is set to hidden.
6020 if (!MUI.ieLegacySupport) {
6021 instance.iframeEl.setStyle('visibility', 'hidden');
6024 instance.iframeEl.hide();
6028 // Hide window and add to dock
6029 instance.contentBorderEl.setStyle('visibility', 'hidden');
6030 if(instance.toolbarWrapperEl){
6031 instance.toolbarWrapperEl.hide();
6033 windowEl.setStyle('visibility', 'hidden');
6035 MUI.Desktop.setDesktopSize();
6037 // Have to use timeout because window gets focused when you click on the minimize button
6038 setTimeout(function(){
6039 windowEl.setStyle('zIndex', 1);
6040 windowEl.removeClass('isFocused');
6041 this.makeActiveTab();
6044 instance.fireEvent('onMinimize', windowEl);
6047 restoreMinimized: function(windowEl) {
6049 var instance = windowEl.retrieve('instance');
6051 if (instance.isMinimized == false) return;
6053 if (MUI.Windows.windowsVisible == false){
6054 MUI.toggleWindowVisibility();
6057 MUI.Desktop.setDesktopSize();
6059 // Part of Mac FF2 scrollbar fix
6060 if (instance.options.scrollbars == true && !instance.iframeEl){
6061 instance.contentWrapperEl.setStyle('overflow', 'auto');
6064 if (instance.isCollapsed) {
6065 MUI.collapseToggle(windowEl);
6068 windowEl.setStyle('visibility', 'visible');
6069 instance.contentBorderEl.setStyle('visibility', 'visible');
6070 if(instance.toolbarWrapperEl){
6071 instance.toolbarWrapperEl.show();
6075 if (instance.iframeEl){
6076 if (!MUI.ieLegacySupport){
6077 instance.iframeEl.setStyle('visibility', 'visible');
6080 instance.iframeEl.show();
6084 instance.isMinimized = false;
6085 MUI.focusWindow(windowEl);
6086 instance.fireEvent('onRestore', windowEl);
6092 Script: Workspaces.js
6093 Save and load workspaces. The Workspaces emulate Adobe Illustrator functionality remembering what windows are open and where they are positioned.
6096 Copyright (c) 2007-2009 Greg Houston, <http://greghoustondesign.com/>.
6109 MUI.files[MUI.path.source + 'Layout/Workspaces.js'] = 'loaded';
6114 Function: saveWorkspace
6115 Save the current workspace.
6119 MUI.saveWorkspace();
6123 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.
6126 saveWorkspace: function(){
6127 this.cookie = new Hash.Cookie('mochaUIworkspaceCookie', {duration: 3600});
6128 this.cookie.empty();
6129 MUI.Windows.instances.each(function(instance) {
6130 instance.saveValues();
6131 this.cookie.set(instance.options.id, {
6132 'id': instance.options.id,
6133 'top': instance.options.y,
6134 'left': instance.options.x,
6135 'width': instance.contentWrapperEl.getStyle('width').toInt(),
6136 'height': instance.contentWrapperEl.getStyle('height').toInt()
6143 type: 'notification',
6144 addClass: 'notification',
6145 content: 'Workspace saved.',
6150 padding: { top: 10, right: 12, bottom: 10, left: 12 },
6152 bodyBgColor: [255, 255, 255]
6156 windowUnload: function(){
6157 if ($$('.mocha').length == 0 && this.myChain){
6158 this.myChain.callChain();
6161 loadWorkspace2: function(workspaceWindows){
6162 workspaceWindows.each(function(workspaceWindow){
6163 windowFunction = eval('MUI.' + workspaceWindow.id + 'Window');
6164 if (windowFunction){
6165 eval('MUI.' + workspaceWindow.id + 'Window({width:'+ workspaceWindow.width +',height:' + workspaceWindow.height + '});');
6166 var windowEl = $(workspaceWindow.id);
6167 windowEl.setStyles({
6168 'top': workspaceWindow.top,
6169 'left': workspaceWindow.left
6171 var instance = windowEl.retrieve('instance');
6172 instance.contentWrapperEl.setStyles({
6173 'width': workspaceWindow.width,
6174 'height': workspaceWindow.height
6176 instance.drawWindow();
6179 this.loadingWorkspace = false;
6183 Function: loadWorkspace
6184 Load the saved workspace.
6188 MUI.loadWorkspace();
6192 loadWorkspace: function(){
6193 cookie = new Hash.Cookie('mochaUIworkspaceCookie', {duration: 3600});
6194 workspaceWindows = cookie.load();
6196 if(!cookie.getKeys().length){
6199 type: 'notification',
6200 addClass: 'notification',
6201 content: 'You have no saved workspace.',
6206 padding: { top: 10, right: 12, bottom: 10, left: 12 },
6208 bodyBgColor: [255, 255, 255]
6213 if ($$('.mocha').length != 0){
6214 this.loadingWorkspace = true;
6215 this.myChain = new Chain();
6218 $$('.mocha').each(function(el) {
6219 this.closeWindow(el);
6223 this.loadWorkspace2(workspaceWindows);
6226 this.myChain.callChain();
6229 this.loadWorkspace2(workspaceWindows);