2 * jQuery UI Dialog 1.8.22
4 * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
8 * http://docs.jquery.com/UI/Dialog
14 * jquery.ui.draggable.js
16 * jquery.ui.position.js
17 * jquery.ui.resizable.js
19 (function( $, undefined ) {
24 'ui-widget-content ' +
26 sizeRelatedOptions
= {
35 resizableRelatedOptions
= {
41 // support for jQuery 1.3.2 - handle common attrFn methods for dialog
42 attrFn
= $.attrFn
|| {
54 $.widget("ui.dialog", {
73 // ensure that the titlebar is never outside the document
74 using: function(pos
) {
75 var topOffset
= $(this).css(pos
).offset().top
;
77 $(this).css('top', pos
.top
- topOffset
);
90 this.originalTitle
= this.element
.attr('title');
91 // #5742 - .attr() might return a DOMElement
92 if ( typeof this.originalTitle
!== "string" ) {
93 this.originalTitle
= "";
96 this.options
.title
= this.options
.title
|| this.originalTitle
;
98 options
= self
.options
,
100 title
= options
.title
|| ' ',
101 titleId
= $.ui
.dialog
.getTitleId(self
.element
),
103 uiDialog
= (self
.uiDialog
= $('<div></div>'))
104 .appendTo(document
.body
)
106 .addClass(uiDialogClasses
+ options
.dialogClass
)
108 zIndex
: options
.zIndex
110 // setting tabIndex makes the div focusable
111 // setting outline to 0 prevents a border on focus in Mozilla
112 .attr('tabIndex', -1).css('outline', 0).keydown(function(event
) {
113 if (options
.closeOnEscape
&& !event
.isDefaultPrevented() && event
.keyCode
&&
114 event
.keyCode
=== $.ui
.keyCode
.ESCAPE
) {
117 event
.preventDefault();
122 'aria-labelledby': titleId
124 .mousedown(function(event
) {
125 self
.moveToTop(false, event
);
128 uiDialogContent
= self
.element
132 'ui-dialog-content ' +
136 uiDialogTitlebar
= (self
.uiDialogTitlebar
= $('<div></div>'))
138 'ui-dialog-titlebar ' +
139 'ui-widget-header ' +
143 .prependTo(uiDialog
),
145 uiDialogTitlebarClose
= $('<a href="#"></a>')
147 'ui-dialog-titlebar-close ' +
150 .attr('role', 'button')
153 uiDialogTitlebarClose
.addClass('ui-state-hover');
156 uiDialogTitlebarClose
.removeClass('ui-state-hover');
160 uiDialogTitlebarClose
.addClass('ui-state-focus');
163 uiDialogTitlebarClose
.removeClass('ui-state-focus');
165 .click(function(event
) {
169 .appendTo(uiDialogTitlebar
),
171 uiDialogTitlebarCloseText
= (self
.uiDialogTitlebarCloseText
= $('<span></span>'))
176 .text(options
.closeText
)
177 .appendTo(uiDialogTitlebarClose
),
179 uiDialogTitle
= $('<span></span>')
180 .addClass('ui-dialog-title')
183 .prependTo(uiDialogTitlebar
);
185 //handling of deprecated beforeclose (vs beforeClose) option
186 //Ticket #4669 http://dev.jqueryui.com/ticket/4669
187 //TODO: remove in 1.9pre
188 if ($.isFunction(options
.beforeclose
) && !$.isFunction(options
.beforeClose
)) {
189 options
.beforeClose
= options
.beforeclose
;
192 uiDialogTitlebar
.find("*").add(uiDialogTitlebar
).disableSelection();
194 if (options
.draggable
&& $.fn
.draggable
) {
195 self
._makeDraggable();
197 if (options
.resizable
&& $.fn
.resizable
) {
198 self
._makeResizable();
201 self
._createButtons(options
.buttons
);
202 self
._isOpen
= false;
210 if ( this.options
.autoOpen
) {
215 destroy: function() {
219 self
.overlay
.destroy();
221 self
.uiDialog
.hide();
224 .removeData('dialog')
225 .removeClass('ui-dialog-content ui-widget-content')
226 .hide().appendTo('body');
227 self
.uiDialog
.remove();
229 if (self
.originalTitle
) {
230 self
.element
.attr('title', self
.originalTitle
);
237 return this.uiDialog
;
240 close: function(event
) {
244 if (false === self
._trigger('beforeClose', event
)) {
249 self
.overlay
.destroy();
251 self
.uiDialog
.unbind('keypress.ui-dialog');
253 self
._isOpen
= false;
255 if (self
.options
.hide
) {
256 self
.uiDialog
.hide(self
.options
.hide
, function() {
257 self
._trigger('close', event
);
260 self
.uiDialog
.hide();
261 self
._trigger('close', event
);
264 $.ui
.dialog
.overlay
.resize();
266 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
267 if (self
.options
.modal
) {
269 $('.ui-dialog').each(function() {
270 if (this !== self
.uiDialog
[0]) {
271 thisZ
= $(this).css('z-index');
273 maxZ
= Math
.max(maxZ
, thisZ
);
277 $.ui
.dialog
.maxZ
= maxZ
;
287 // the force parameter allows us to move modal dialogs to their correct
289 moveToTop: function(force
, event
) {
291 options
= self
.options
,
294 if ((options
.modal
&& !force
) ||
295 (!options
.stack
&& !options
.modal
)) {
296 return self
._trigger('focus', event
);
299 if (options
.zIndex
> $.ui
.dialog
.maxZ
) {
300 $.ui
.dialog
.maxZ
= options
.zIndex
;
303 $.ui
.dialog
.maxZ
+= 1;
304 self
.overlay
.$el
.css('z-index', $.ui
.dialog
.overlay
.maxZ
= $.ui
.dialog
.maxZ
);
307 //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed.
308 // http://ui.jquery.com/bugs/ticket/3193
309 saveScroll
= { scrollTop
: self
.element
.scrollTop(), scrollLeft
: self
.element
.scrollLeft() };
310 $.ui
.dialog
.maxZ
+= 1;
311 self
.uiDialog
.css('z-index', $.ui
.dialog
.maxZ
);
312 self
.element
.attr(saveScroll
);
313 self
._trigger('focus', event
);
319 if (this._isOpen
) { return; }
322 options
= self
.options
,
323 uiDialog
= self
.uiDialog
;
325 self
.overlay
= options
.modal
? new $.ui
.dialog
.overlay(self
) : null;
327 self
._position(options
.position
);
328 uiDialog
.show(options
.show
);
329 self
.moveToTop(true);
331 // prevent tabbing out of modal dialogs
332 if ( options
.modal
) {
333 uiDialog
.bind( "keydown.ui-dialog", function( event
) {
334 if ( event
.keyCode
!== $.ui
.keyCode
.TAB
) {
338 var tabbables
= $(':tabbable', this),
339 first
= tabbables
.filter(':first'),
340 last
= tabbables
.filter(':last');
342 if (event
.target
=== last
[0] && !event
.shiftKey
) {
345 } else if (event
.target
=== first
[0] && event
.shiftKey
) {
352 // set focus to the first tabbable element in the content area or the first button
353 // if there are no tabbable elements, set focus on the dialog itself
354 $(self
.element
.find(':tabbable').get().concat(
355 uiDialog
.find('.ui-dialog-buttonpane :tabbable').get().concat(
356 uiDialog
.get()))).eq(0).focus();
359 self
._trigger('open');
364 _createButtons: function(buttons
) {
367 uiDialogButtonPane
= $('<div></div>')
369 'ui-dialog-buttonpane ' +
370 'ui-widget-content ' +
373 uiButtonSet
= $( "<div></div>" )
374 .addClass( "ui-dialog-buttonset" )
375 .appendTo( uiDialogButtonPane
);
377 // if we already have a button pane, remove it
378 self
.uiDialog
.find('.ui-dialog-buttonpane').remove();
380 if (typeof buttons
=== 'object' && buttons
!== null) {
381 $.each(buttons
, function() {
382 return !(hasButtons
= true);
386 $.each(buttons
, function(name
, props
) {
387 props
= $.isFunction( props
) ?
388 { click
: props
, text
: name
} :
390 var button
= $('<button type="button"></button>')
392 props
.click
.apply(self
.element
[0], arguments
);
394 .appendTo(uiButtonSet
);
395 // can't use .attr( props, true ) with jQuery 1.3.2.
396 $.each( props
, function( key
, value
) {
397 if ( key
=== "click" ) {
400 if ( key
in attrFn
) {
401 button
[ key
]( value
);
403 button
.attr( key
, value
);
410 uiDialogButtonPane
.appendTo(self
.uiDialog
);
414 _makeDraggable: function() {
416 options
= self
.options
,
420 function filteredUi(ui
) {
422 position
: ui
.position
,
427 self
.uiDialog
.draggable({
428 cancel
: '.ui-dialog-content, .ui-dialog-titlebar-close',
429 handle
: '.ui-dialog-titlebar',
430 containment
: 'document',
431 start: function(event
, ui
) {
432 heightBeforeDrag
= options
.height
=== "auto" ? "auto" : $(this).height();
433 $(this).height($(this).height()).addClass("ui-dialog-dragging");
434 self
._trigger('dragStart', event
, filteredUi(ui
));
436 drag: function(event
, ui
) {
437 self
._trigger('drag', event
, filteredUi(ui
));
439 stop: function(event
, ui
) {
440 options
.position
= [ui
.position
.left
- doc
.scrollLeft(),
441 ui
.position
.top
- doc
.scrollTop()];
442 $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag
);
443 self
._trigger('dragStop', event
, filteredUi(ui
));
444 $.ui
.dialog
.overlay
.resize();
449 _makeResizable: function(handles
) {
450 handles
= (handles
=== undefined ? this.options
.resizable
: handles
);
452 options
= self
.options
,
453 // .ui-resizable has position: relative defined in the stylesheet
454 // but dialogs have to use absolute or fixed positioning
455 position
= self
.uiDialog
.css('position'),
456 resizeHandles
= (typeof handles
=== 'string' ?
458 'n,e,s,w,se,sw,ne,nw'
461 function filteredUi(ui
) {
463 originalPosition
: ui
.originalPosition
,
464 originalSize
: ui
.originalSize
,
465 position
: ui
.position
,
470 self
.uiDialog
.resizable({
471 cancel
: '.ui-dialog-content',
472 containment
: 'document',
473 alsoResize
: self
.element
,
474 maxWidth
: options
.maxWidth
,
475 maxHeight
: options
.maxHeight
,
476 minWidth
: options
.minWidth
,
477 minHeight
: self
._minHeight(),
478 handles
: resizeHandles
,
479 start: function(event
, ui
) {
480 $(this).addClass("ui-dialog-resizing");
481 self
._trigger('resizeStart', event
, filteredUi(ui
));
483 resize: function(event
, ui
) {
484 self
._trigger('resize', event
, filteredUi(ui
));
486 stop: function(event
, ui
) {
487 $(this).removeClass("ui-dialog-resizing");
488 options
.height
= $(this).height();
489 options
.width
= $(this).width();
490 self
._trigger('resizeStop', event
, filteredUi(ui
));
491 $.ui
.dialog
.overlay
.resize();
494 .css('position', position
)
495 .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
498 _minHeight: function() {
499 var options
= this.options
;
501 if (options
.height
=== 'auto') {
502 return options
.minHeight
;
504 return Math
.min(options
.minHeight
, options
.height
);
508 _position: function(position
) {
514 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
515 // if (typeof position == 'string' || $.isArray(position)) {
516 // myAt = $.isArray(position) ? position : position.split(' ');
518 if (typeof position
=== 'string' || (typeof position
=== 'object' && '0' in position
)) {
519 myAt
= position
.split
? position
.split(' ') : [position
[0], position
[1]];
520 if (myAt
.length
=== 1) {
524 $.each(['left', 'top'], function(i
, offsetPosition
) {
525 if (+myAt
[i
] === myAt
[i
]) {
527 myAt
[i
] = offsetPosition
;
534 offset
: offset
.join(" ")
538 position
= $.extend({}, $.ui
.dialog
.prototype.options
.position
, position
);
540 position
= $.ui
.dialog
.prototype.options
.position
;
543 // need to show the dialog to get the actual offset in the position plugin
544 isVisible
= this.uiDialog
.is(':visible');
546 this.uiDialog
.show();
549 // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
550 .css({ top
: 0, left
: 0 })
551 .position($.extend({ of: window
}, position
));
553 this.uiDialog
.hide();
557 _setOptions: function( options
) {
559 resizableOptions
= {},
562 $.each( options
, function( key
, value
) {
563 self
._setOption( key
, value
);
565 if ( key
in sizeRelatedOptions
) {
568 if ( key
in resizableRelatedOptions
) {
569 resizableOptions
[ key
] = value
;
576 if ( this.uiDialog
.is( ":data(resizable)" ) ) {
577 this.uiDialog
.resizable( "option", resizableOptions
);
581 _setOption: function(key
, value
){
583 uiDialog
= self
.uiDialog
;
586 //handling of deprecated beforeclose (vs beforeClose) option
587 //Ticket #4669 http://dev.jqueryui.com/ticket/4669
588 //TODO: remove in 1.9pre
593 self
._createButtons(value
);
596 // ensure that we always pass a string
597 self
.uiDialogTitlebarCloseText
.text("" + value
);
601 .removeClass(self
.options
.dialogClass
)
602 .addClass(uiDialogClasses
+ value
);
606 uiDialog
.addClass('ui-dialog-disabled');
608 uiDialog
.removeClass('ui-dialog-disabled');
612 var isDraggable
= uiDialog
.is( ":data(draggable)" );
613 if ( isDraggable
&& !value
) {
614 uiDialog
.draggable( "destroy" );
617 if ( !isDraggable
&& value
) {
618 self
._makeDraggable();
622 self
._position(value
);
625 // currently resizable, becoming non-resizable
626 var isResizable
= uiDialog
.is( ":data(resizable)" );
627 if (isResizable
&& !value
) {
628 uiDialog
.resizable('destroy');
631 // currently resizable, changing handles
632 if (isResizable
&& typeof value
=== 'string') {
633 uiDialog
.resizable('option', 'handles', value
);
636 // currently non-resizable, becoming resizable
637 if (!isResizable
&& value
!== false) {
638 self
._makeResizable(value
);
642 // convert whatever was passed in o a string, for html() to not throw up
643 $(".ui-dialog-title", self
.uiDialogTitlebar
).html("" + (value
|| ' '));
647 $.Widget
.prototype._setOption
.apply(self
, arguments
);
651 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
652 * divs will both have width and height set, so we need to reset them
654 var options
= this.options
,
657 isVisible
= this.uiDialog
.is( ":visible" );
659 // reset content sizing
660 this.element
.show().css({
666 if (options
.minWidth
> options
.width
) {
667 options
.width
= options
.minWidth
;
670 // reset wrapper sizing
671 // determine the height of all the non-content elements
672 nonContentHeight
= this.uiDialog
.css({
677 minContentHeight
= Math
.max( 0, options
.minHeight
- nonContentHeight
);
679 if ( options
.height
=== "auto" ) {
680 // only needed for IE6 support
681 if ( $.support
.minHeight
) {
683 minHeight
: minContentHeight
,
687 this.uiDialog
.show();
688 var autoHeight
= this.element
.css( "height", "auto" ).height();
690 this.uiDialog
.hide();
692 this.element
.height( Math
.max( autoHeight
, minContentHeight
) );
695 this.element
.height( Math
.max( options
.height
- nonContentHeight
, 0 ) );
698 if (this.uiDialog
.is(':data(resizable)')) {
699 this.uiDialog
.resizable('option', 'minHeight', this._minHeight());
704 $.extend($.ui
.dialog
, {
710 getTitleId: function($el
) {
711 var id
= $el
.attr('id');
716 return 'ui-dialog-title-' + id
;
719 overlay: function(dialog
) {
720 this.$el
= $.ui
.dialog
.overlay
.create(dialog
);
724 $.extend($.ui
.dialog
.overlay
, {
726 // reuse old instances due to IE memory leak with alpha transparency (see #5185)
729 events
: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
730 function(event
) { return event
+ '.dialog-overlay'; }).join(' '),
731 create: function(dialog
) {
732 if (this.instances
.length
=== 0) {
733 // prevent use of anchors and inputs
734 // we use a setTimeout in case the overlay is created from an
735 // event that we're going to be cancelling (see #2804)
736 setTimeout(function() {
737 // handle $(el).dialog().dialog('close') (see #4065)
738 if ($.ui
.dialog
.overlay
.instances
.length
) {
739 $(document
).bind($.ui
.dialog
.overlay
.events
, function(event
) {
740 // stop events if the z-index of the target is < the z-index of the overlay
741 // we cannot return true when we don't want to cancel the event (#3523)
742 if ($(event
.target
).zIndex() < $.ui
.dialog
.overlay
.maxZ
) {
749 // allow closing by pressing the escape key
750 $(document
).bind('keydown.dialog-overlay', function(event
) {
751 if (dialog
.options
.closeOnEscape
&& !event
.isDefaultPrevented() && event
.keyCode
&&
752 event
.keyCode
=== $.ui
.keyCode
.ESCAPE
) {
755 event
.preventDefault();
759 // handle window resize
760 $(window
).bind('resize.dialog-overlay', $.ui
.dialog
.overlay
.resize
);
763 var $el
= (this.oldInstances
.pop() || $('<div></div>').addClass('ui-widget-overlay'))
764 .appendTo(document
.body
)
767 height
: this.height()
774 this.instances
.push($el
);
778 destroy: function($el
) {
779 var indexOf
= $.inArray($el
, this.instances
);
781 this.oldInstances
.push(this.instances
.splice(indexOf
, 1)[0]);
784 if (this.instances
.length
=== 0) {
785 $([document
, window
]).unbind('.dialog-overlay');
790 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
792 $.each(this.instances
, function() {
793 maxZ
= Math
.max(maxZ
, this.css('z-index'));
802 if ($.browser
.msie
&& $.browser
.version
< 7) {
803 scrollHeight
= Math
.max(
804 document
.documentElement
.scrollHeight
,
805 document
.body
.scrollHeight
807 offsetHeight
= Math
.max(
808 document
.documentElement
.offsetHeight
,
809 document
.body
.offsetHeight
812 if (scrollHeight
< offsetHeight
) {
813 return $(window
).height() + 'px';
815 return scrollHeight
+ 'px';
817 // handle "good" browsers
819 return $(document
).height() + 'px';
827 if ( $.browser
.msie
) {
828 scrollWidth
= Math
.max(
829 document
.documentElement
.scrollWidth
,
830 document
.body
.scrollWidth
832 offsetWidth
= Math
.max(
833 document
.documentElement
.offsetWidth
,
834 document
.body
.offsetWidth
837 if (scrollWidth
< offsetWidth
) {
838 return $(window
).width() + 'px';
840 return scrollWidth
+ 'px';
842 // handle "good" browsers
844 return $(document
).width() + 'px';
849 /* If the dialog is draggable and the user drags it past the
850 * right edge of the window, the document becomes wider so we
851 * need to stretch the overlay. If the user then drags the
852 * dialog back to the left, the document will become narrower,
853 * so we need to shrink the overlay to the appropriate size.
854 * This is handled by shrinking the overlay before setting it
855 * to the full document size.
857 var $overlays
= $([]);
858 $.each($.ui
.dialog
.overlay
.instances
, function() {
859 $overlays
= $overlays
.add(this);
866 width
: $.ui
.dialog
.overlay
.width(),
867 height
: $.ui
.dialog
.overlay
.height()
872 $.extend($.ui
.dialog
.overlay
.prototype, {
873 destroy: function() {
874 $.ui
.dialog
.overlay
.destroy(this.$el
);