9

Extending jQuery UI Dialog to Include Minimize Button

Posted July 7th, 2010 in jQuery by admin

The jQuery UI plugin includes a great set of tools for quickly putting together professional looking interfaces. One of the greatest advantages to using jQuery UI is that it is easy to add new features to existing widgets or to create your own widget that inherits from existing UI widgets. This tutorial assumes a decent knowledge of how jQuery’s events and selectors work and is aimed at people who are familiar with jQuery and jQuery UI who are looking to quickly add functionality to existing widgets.

There are two ways of extending UI widgets to suit your needs. The first is to extend the current widget. This means writing code that will be added to the current implementation of the widget you are extending. The second way is to use jQuery’s extend functionality to create an entirely new widget. Since adding a minimize button is fairy simple I am going to modify the existing jQuery UI Dialog widget.

Here is the template we will be using to modify the Dialog widget. This code can be placed in its own javascript file and then included after the jQuery UI javascript file and it will be used in any jQuery UI Dialog we create.

(function($){
	var _init = $.ui.dialog.prototype._init;
 
	//Custom Dialog Init
	$.ui.dialog.prototype._init = function() {
		var self = this;
                       _init.apply(this, arguments);
 
		//custom init functionality, variables and event binding goes in here
 
 
	};
	$.extend($.ui.dialog.prototype, {
		//Custom Dialog Functions go in here
	});
})(jQuery);

There are a few things we need to do to add the minimize functionality.

  1. We need to actually add the html so that our minimize button is part of the dialog and also we will need to add a restore button.
  2. We need to bind these buttons to handlers so our code to minimize and restore a dialog box will be called.
  3. We need to write the custom functions that will be called by the button handlers.

The first thing to do is add some variables to support our functionality and also to add the minimize and restore button to the dialog HTML. The code for this is as follows and goes in the dialog init part of the template:

//Reference to the titlebar
uiDialogTitlebar = this.uiDialogTitlebar;
 
//Save the height of the titlebar for the minimize operation
this.titlebarHeight = uiDialogTitlebar.css('height') + uiDialogTitlebar.css('margin-top') + uiDialogTitlebar.css('margin-bottom');
 
//we need two variables to preserve the original width and height so that can be restored.
this.options.originalWidth = this.options.width;
this.options.originalHeight = this.options.height;
 
//save a reference to the resizable handle so we can hide it when necessary.
this.resizeableHandle =  this.uiDialog.resizable().find('.ui-resizable-se');
 
uiDialogTitlebar.append('<a href="#" id="dialog-minimize" class="dialog-minimize ui-dialog-titlebar-min"><span class="ui-icon ui-icon-minusthick"></span></a>');
uiDialogTitlebar.append('<a href="#"class="dialog-restore ui-dialog-titlebar-rest"><span class="ui-icon ui-icon-newwin"></span></a>');

We have now appended the HTML needed for the minimize and restore buttons to the dialog title bar but they need a small amount of CSS for them to look right. The following CSS can go in its own file or you can append it to the CSS file that comes with jQuery UI. If you look in the jQuery UI CSS file you will see it is a slightly modified version of the CSS used for the close button on the dialog.

.ui-dialog .ui-dialog-titlebar-min{ position: absolute; right: 23px; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-min span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-min:hover, .ui-dialog .ui-dialog-titlebar-min:focus { padding: 0; }
 
.ui-dialog .ui-dialog-titlebar-rest{ position: absolute; right: 23px; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-rest span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-rest:hover, .ui-dialog .ui-dialog-titlebar-rest:focus { padding: 0; }

Now that the buttons have been correctly placed in the title bar of the dialog box, we need to bind handlers for their functionality. The following code will also go in the init part of the template.

//Minimize Button
this.uiDialogTitlebarMin = $('.dialog-minimize', uiDialogTitlebar).hover(function(){
	$(this).addClass('ui-state-hover');
}, function(){
	$(this).removeClass('ui-state-hover');
}).click(function(){
	self.minimize();
	return false;
});
 
//Restore Button
this.uiDialogTitlebarRest = $('.dialog-restore', uiDialogTitlebar).hover(function(){
	$(this).addClass('ui-state-hover');
}, function(){
	$(this).removeClass('ui-state-hover');
}).click(function(){
	self.restore();
	self.moveToTop(true);
	return false;
}).hide();

The code above creates a handler for the minimize button and one for the restore button and assign the buttons to a variable we will be able to use with the widget. The code uses jQuery’s useful method of chaining functions together after a selector. The restore button is also initially hidden since only one of the buttons should be visible at a time. The hover handlers are so the button’s hover functions mimic what happens when you hover over the close button. The click handler is calling a custom functions we have not defined yet: ‘self.minimize’ and ‘self.restore’.

The final step is to implement the minimize and restore functions. These functions will go in the second part of the template. Here is the implementation of the two functions, you will see it is mostly simple CSS manipulations to create the minimize and maximize behavior.

restore: function() {
 
	//restore resizable functionality
	this.uiDialog.resizable( "option", "disabled", false );
	//show the resizeable handle
	this.resizeableHandle.show();
 
	//We want to prevent the dialog from expanding off the screen
	var windowHeight = $(window).height();
	var dialogHeight = this.options.originalHeight;
	var dialogTop = parseInt(this.uiDialog.css('top'));
	if(dialogHeight+dialogTop > windowHeight)
	{
		var newTop = windowHeight-dialogHeight;
		this.uiDialog.css('top',newTop);
	}			
	var windowWidth = $(window).width();
	var dialogWidth = this.options.originalWidth;
	var dialogLeft = parseInt(this.uiDialog.css('left'));
	if(dialogWidth+dialogLeft > windowWidth)
	{
		var newLeft = windowWidth-dialogWidth;
		this.uiDialog.css('left',newLeft);
	}
 
	//restore the orignal dimensions
	this.uiDialog.css({width: this.options.originalWidth, height:this.options.originalHeight});
	//show the dialog content
	this.element.show();
 
	//swap the buttons
	this.uiDialogTitlebarRest.hide();
	this.uiDialogTitlebarMin.show();
},
minimize: function() { 
	//disable resizable
	this.uiDialog.resizable( "option", "disabled", true );
	this.resizeableHandle.hide();
 
	//Store the original height/width
	this.options.originalWidth = this.options.width;
	this.options.originalHeight = this.options.height;
 
	//collapse dialog
	this.uiDialog.animate({width: 200, height:this.titlebarHeight},200);
	//hide the content
	this.element.hide();
 
	//swap buttons to show restore
	this.uiDialogTitlebarMin.hide();
	this.uiDialogTitlebarRest.show();
}

The extended dialog widget is complete. When you put it all together here is the source code: Source

Here is a demo of the code: Demo

Further Extension

One function some people may like is for the dialog to minimize and stay fixed in a certain spot. This can be achieved easily by adding in some CSS manipulation to put the dialog in an absolute position on the screen and saving coordinates to restore it to.

Resources and Additional Reading

9 Responses so far.

  1. Max says:

    In the demo the minimize function fails if you resize the dialog either before or after any other minimize event on that dialog.

    • admin says:

      You’re right… I hastily did a cut and paste job from a much more complex dialog implementation to make this simple demo and left out something important. Thanks for the heads up.

  2. Hey there, great article, great code. One nit: line 16(ish) of your code needs a ‘var’ in front of the uiDialogTitlebar. Keep up the rockin’ work, and thanks for the lesson.

  3. Deroude says:

    Just dropped by to say thank you for a very nice extension; hope to see it soon in the official release ;)

  4. David says:

    Thank you very much for this extension. Great stuff!

  5. Vaughn says:

    Using your method, is there a way to force the dialogs to start minimized? I haven’t been able to work out the “hook” to do this.

    There’s also a bug that will force non-resizable windows to have a resize option based on your restore code, but I fixed that with a couple if statements based on this.options.resizable

  6. Vaughn says:

    Sorry about that, nevermind, .dialog(‘minimize’) to the rescue :)

  7. Marcus says:

    What is making the title bar of the dialog transparent while minimized? I need to change the opacity and haven’t quite found what is causing that yet.

Leave a Reply