2 * jQuery UI Dialog 1.9.2
5 * Copyright 2012 jQuery Foundation and other contributors
6 * Released under the MIT license.
7 * http://jquery.org/license
9 * http://api.jqueryui.com/dialog/
15 * jquery.ui.draggable.js
17 * jquery.ui.position.js
18 * jquery.ui.resizable.js
20 (function( $, undefined ) {
22 var uiDialogClasses
= "ui-dialog ui-widget ui-widget-content ui-corner-all ",
23 sizeRelatedOptions
= {
32 resizableRelatedOptions
= {
39 $.widget("ui.dialog", {
60 // ensure that the titlebar is never outside the document
61 using: function( pos
) {
62 var topOffset
= $( this ).css( pos
).offset().top
;
63 if ( topOffset
< 0 ) {
64 $( this ).css( "top", pos
.top
- topOffset
);
77 this.originalTitle
= this.element
.attr( "title" );
78 // #5742 - .attr() might return a DOMElement
79 if ( typeof this.originalTitle
!== "string" ) {
80 this.originalTitle
= "";
83 parent
: this.element
.parent(),
84 index
: this.element
.parent().children().index( this.element
)
86 this.options
.title
= this.options
.title
|| this.originalTitle
;
88 options
= this.options
,
90 title
= options
.title
|| " ",
93 uiDialogTitlebarClose
,
97 uiDialog
= ( this.uiDialog
= $( "<div>" ) )
98 .addClass( uiDialogClasses
+ options
.dialogClass
)
101 outline
: 0, // TODO: move to stylesheet
102 zIndex
: options
.zIndex
104 // setting tabIndex makes the div focusable
105 .attr( "tabIndex", -1)
106 .keydown(function( event
) {
107 if ( options
.closeOnEscape
&& !event
.isDefaultPrevented() && event
.keyCode
&&
108 event
.keyCode
=== $.ui
.keyCode
.ESCAPE
) {
110 event
.preventDefault();
113 .mousedown(function( event
) {
114 that
.moveToTop( false, event
);
120 .removeAttr( "title" )
121 .addClass( "ui-dialog-content ui-widget-content" )
122 .appendTo( uiDialog
);
124 uiDialogTitlebar
= ( this.uiDialogTitlebar
= $( "<div>" ) )
125 .addClass( "ui-dialog-titlebar ui-widget-header " +
126 "ui-corner-all ui-helper-clearfix" )
127 .bind( "mousedown", function() {
128 // Dialog isn't getting focus when dragging (#8063)
131 .prependTo( uiDialog
);
133 uiDialogTitlebarClose
= $( "<a href='#'></a>" )
134 .addClass( "ui-dialog-titlebar-close ui-corner-all" )
135 .attr( "role", "button" )
136 .click(function( event
) {
137 event
.preventDefault();
140 .appendTo( uiDialogTitlebar
);
142 ( this.uiDialogTitlebarCloseText
= $( "<span>" ) )
143 .addClass( "ui-icon ui-icon-closethick" )
144 .text( options
.closeText
)
145 .appendTo( uiDialogTitlebarClose
);
147 uiDialogTitle
= $( "<span>" )
149 .addClass( "ui-dialog-title" )
151 .prependTo( uiDialogTitlebar
);
153 uiDialogButtonPane
= ( this.uiDialogButtonPane
= $( "<div>" ) )
154 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
156 ( this.uiButtonSet
= $( "<div>" ) )
157 .addClass( "ui-dialog-buttonset" )
158 .appendTo( uiDialogButtonPane
);
162 "aria-labelledby": uiDialogTitle
.attr( "id" )
165 uiDialogTitlebar
.find( "*" ).add( uiDialogTitlebar
).disableSelection();
166 this._hoverable( uiDialogTitlebarClose
);
167 this._focusable( uiDialogTitlebarClose
);
169 if ( options
.draggable
&& $.fn
.draggable
) {
170 this._makeDraggable();
172 if ( options
.resizable
&& $.fn
.resizable
) {
173 this._makeResizable();
176 this._createButtons( options
.buttons
);
177 this._isOpen
= false;
179 if ( $.fn
.bgiframe
) {
183 // prevent tabbing out of modal dialogs
184 this._on( uiDialog
, { keydown: function( event
) {
185 if ( !options
.modal
|| event
.keyCode
!== $.ui
.keyCode
.TAB
) {
189 var tabbables
= $( ":tabbable", uiDialog
),
190 first
= tabbables
.filter( ":first" ),
191 last
= tabbables
.filter( ":last" );
193 if ( event
.target
=== last
[0] && !event
.shiftKey
) {
196 } else if ( event
.target
=== first
[0] && event
.shiftKey
) {
204 if ( this.options
.autoOpen
) {
209 _destroy: function() {
211 oldPosition
= this.oldPosition
;
213 if ( this.overlay
) {
214 this.overlay
.destroy();
216 this.uiDialog
.hide();
218 .removeClass( "ui-dialog-content ui-widget-content" )
221 this.uiDialog
.remove();
223 if ( this.originalTitle
) {
224 this.element
.attr( "title", this.originalTitle
);
227 next
= oldPosition
.parent
.children().eq( oldPosition
.index
);
228 // Don't try to place the dialog next to itself (#8613)
229 if ( next
.length
&& next
[ 0 ] !== this.element
[ 0 ] ) {
230 next
.before( this.element
);
232 oldPosition
.parent
.append( this.element
);
237 return this.uiDialog
;
240 close: function( event
) {
244 if ( !this._isOpen
) {
248 if ( false === this._trigger( "beforeClose", event
) ) {
252 this._isOpen
= false;
254 if ( this.overlay
) {
255 this.overlay
.destroy();
258 if ( this.options
.hide
) {
259 this._hide( this.uiDialog
, this.options
.hide
, function() {
260 that
._trigger( "close", event
);
263 this.uiDialog
.hide();
264 this._trigger( "close", event
);
267 $.ui
.dialog
.overlay
.resize();
269 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
270 if ( this.options
.modal
) {
272 $( ".ui-dialog" ).each(function() {
273 if ( this !== that
.uiDialog
[0] ) {
274 thisZ
= $( this ).css( "z-index" );
275 if ( !isNaN( thisZ
) ) {
276 maxZ
= Math
.max( maxZ
, thisZ
);
280 $.ui
.dialog
.maxZ
= maxZ
;
290 // the force parameter allows us to move modal dialogs to their correct
292 moveToTop: function( force
, event
) {
293 var options
= this.options
,
296 if ( ( options
.modal
&& !force
) ||
297 ( !options
.stack
&& !options
.modal
) ) {
298 return this._trigger( "focus", event
);
301 if ( options
.zIndex
> $.ui
.dialog
.maxZ
) {
302 $.ui
.dialog
.maxZ
= options
.zIndex
;
304 if ( this.overlay
) {
305 $.ui
.dialog
.maxZ
+= 1;
306 $.ui
.dialog
.overlay
.maxZ
= $.ui
.dialog
.maxZ
;
307 this.overlay
.$el
.css( "z-index", $.ui
.dialog
.overlay
.maxZ
);
310 // Save and then restore scroll
311 // Opera 9.5+ resets when parent z-index is changed.
312 // http://bugs.jqueryui.com/ticket/3193
314 scrollTop
: this.element
.scrollTop(),
315 scrollLeft
: this.element
.scrollLeft()
317 $.ui
.dialog
.maxZ
+= 1;
318 this.uiDialog
.css( "z-index", $.ui
.dialog
.maxZ
);
319 this.element
.attr( saveScroll
);
320 this._trigger( "focus", event
);
326 if ( this._isOpen
) {
331 options
= this.options
,
332 uiDialog
= this.uiDialog
;
335 this._position( options
.position
);
336 uiDialog
.show( options
.show
);
337 this.overlay
= options
.modal
? new $.ui
.dialog
.overlay( this ) : null;
338 this.moveToTop( true );
340 // set focus to the first tabbable element in the content area or the first button
341 // if there are no tabbable elements, set focus on the dialog itself
342 hasFocus
= this.element
.find( ":tabbable" );
343 if ( !hasFocus
.length
) {
344 hasFocus
= this.uiDialogButtonPane
.find( ":tabbable" );
345 if ( !hasFocus
.length
) {
349 hasFocus
.eq( 0 ).focus();
352 this._trigger( "open" );
357 _createButtons: function( buttons
) {
361 // if we already have a button pane, remove it
362 this.uiDialogButtonPane
.remove();
363 this.uiButtonSet
.empty();
365 if ( typeof buttons
=== "object" && buttons
!== null ) {
366 $.each( buttons
, function() {
367 return !(hasButtons
= true);
371 $.each( buttons
, function( name
, props
) {
373 props
= $.isFunction( props
) ?
374 { click
: props
, text
: name
} :
376 // Default to a non-submitting button
377 props
= $.extend( { type
: "button" }, props
);
378 // Change the context for the click callback to be the main element
380 props
.click = function() {
381 click
.apply( that
.element
[0], arguments
);
383 button
= $( "<button></button>", props
)
384 .appendTo( that
.uiButtonSet
);
389 this.uiDialog
.addClass( "ui-dialog-buttons" );
390 this.uiDialogButtonPane
.appendTo( this.uiDialog
);
392 this.uiDialog
.removeClass( "ui-dialog-buttons" );
396 _makeDraggable: function() {
398 options
= this.options
;
400 function filteredUi( ui
) {
402 position
: ui
.position
,
407 this.uiDialog
.draggable({
408 cancel
: ".ui-dialog-content, .ui-dialog-titlebar-close",
409 handle
: ".ui-dialog-titlebar",
410 containment
: "document",
411 start: function( event
, ui
) {
413 .addClass( "ui-dialog-dragging" );
414 that
._trigger( "dragStart", event
, filteredUi( ui
) );
416 drag: function( event
, ui
) {
417 that
._trigger( "drag", event
, filteredUi( ui
) );
419 stop: function( event
, ui
) {
421 ui
.position
.left
- that
.document
.scrollLeft(),
422 ui
.position
.top
- that
.document
.scrollTop()
425 .removeClass( "ui-dialog-dragging" );
426 that
._trigger( "dragStop", event
, filteredUi( ui
) );
427 $.ui
.dialog
.overlay
.resize();
432 _makeResizable: function( handles
) {
433 handles
= (handles
=== undefined ? this.options
.resizable
: handles
);
435 options
= this.options
,
436 // .ui-resizable has position: relative defined in the stylesheet
437 // but dialogs have to use absolute or fixed positioning
438 position
= this.uiDialog
.css( "position" ),
439 resizeHandles
= typeof handles
=== 'string' ?
441 "n,e,s,w,se,sw,ne,nw";
443 function filteredUi( ui
) {
445 originalPosition
: ui
.originalPosition
,
446 originalSize
: ui
.originalSize
,
447 position
: ui
.position
,
452 this.uiDialog
.resizable({
453 cancel
: ".ui-dialog-content",
454 containment
: "document",
455 alsoResize
: this.element
,
456 maxWidth
: options
.maxWidth
,
457 maxHeight
: options
.maxHeight
,
458 minWidth
: options
.minWidth
,
459 minHeight
: this._minHeight(),
460 handles
: resizeHandles
,
461 start: function( event
, ui
) {
462 $( this ).addClass( "ui-dialog-resizing" );
463 that
._trigger( "resizeStart", event
, filteredUi( ui
) );
465 resize: function( event
, ui
) {
466 that
._trigger( "resize", event
, filteredUi( ui
) );
468 stop: function( event
, ui
) {
469 $( this ).removeClass( "ui-dialog-resizing" );
470 options
.height
= $( this ).height();
471 options
.width
= $( this ).width();
472 that
._trigger( "resizeStop", event
, filteredUi( ui
) );
473 $.ui
.dialog
.overlay
.resize();
476 .css( "position", position
)
477 .find( ".ui-resizable-se" )
478 .addClass( "ui-icon ui-icon-grip-diagonal-se" );
481 _minHeight: function() {
482 var options
= this.options
;
484 if ( options
.height
=== "auto" ) {
485 return options
.minHeight
;
487 return Math
.min( options
.minHeight
, options
.height
);
491 _position: function( position
) {
497 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
498 // if (typeof position == 'string' || $.isArray(position)) {
499 // myAt = $.isArray(position) ? position : position.split(' ');
501 if ( typeof position
=== "string" || (typeof position
=== "object" && "0" in position
) ) {
502 myAt
= position
.split
? position
.split( " " ) : [ position
[ 0 ], position
[ 1 ] ];
503 if ( myAt
.length
=== 1 ) {
504 myAt
[ 1 ] = myAt
[ 0 ];
507 $.each( [ "left", "top" ], function( i
, offsetPosition
) {
508 if ( +myAt
[ i
] === myAt
[ i
] ) {
509 offset
[ i
] = myAt
[ i
];
510 myAt
[ i
] = offsetPosition
;
515 my
: myAt
[0] + (offset
[0] < 0 ? offset
[0] : "+" + offset
[0]) + " " +
516 myAt
[1] + (offset
[1] < 0 ? offset
[1] : "+" + offset
[1]),
521 position
= $.extend( {}, $.ui
.dialog
.prototype.options
.position
, position
);
523 position
= $.ui
.dialog
.prototype.options
.position
;
526 // need to show the dialog to get the actual offset in the position plugin
527 isVisible
= this.uiDialog
.is( ":visible" );
529 this.uiDialog
.show();
531 this.uiDialog
.position( position
);
533 this.uiDialog
.hide();
537 _setOptions: function( options
) {
539 resizableOptions
= {},
542 $.each( options
, function( key
, value
) {
543 that
._setOption( key
, value
);
545 if ( key
in sizeRelatedOptions
) {
548 if ( key
in resizableRelatedOptions
) {
549 resizableOptions
[ key
] = value
;
556 if ( this.uiDialog
.is( ":data(resizable)" ) ) {
557 this.uiDialog
.resizable( "option", resizableOptions
);
561 _setOption: function( key
, value
) {
562 var isDraggable
, isResizable
,
563 uiDialog
= this.uiDialog
;
567 this._createButtons( value
);
570 // ensure that we always pass a string
571 this.uiDialogTitlebarCloseText
.text( "" + value
);
575 .removeClass( this.options
.dialogClass
)
576 .addClass( uiDialogClasses
+ value
);
580 uiDialog
.addClass( "ui-dialog-disabled" );
582 uiDialog
.removeClass( "ui-dialog-disabled" );
586 isDraggable
= uiDialog
.is( ":data(draggable)" );
587 if ( isDraggable
&& !value
) {
588 uiDialog
.draggable( "destroy" );
591 if ( !isDraggable
&& value
) {
592 this._makeDraggable();
596 this._position( value
);
599 // currently resizable, becoming non-resizable
600 isResizable
= uiDialog
.is( ":data(resizable)" );
601 if ( isResizable
&& !value
) {
602 uiDialog
.resizable( "destroy" );
605 // currently resizable, changing handles
606 if ( isResizable
&& typeof value
=== "string" ) {
607 uiDialog
.resizable( "option", "handles", value
);
610 // currently non-resizable, becoming resizable
611 if ( !isResizable
&& value
!== false ) {
612 this._makeResizable( value
);
616 // convert whatever was passed in o a string, for html() to not throw up
617 $( ".ui-dialog-title", this.uiDialogTitlebar
)
618 .html( "" + ( value
|| " " ) );
622 this._super( key
, value
);
626 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
627 * divs will both have width and height set, so we need to reset them
629 var nonContentHeight
, minContentHeight
, autoHeight
,
630 options
= this.options
,
631 isVisible
= this.uiDialog
.is( ":visible" );
633 // reset content sizing
634 this.element
.show().css({
640 if ( options
.minWidth
> options
.width
) {
641 options
.width
= options
.minWidth
;
644 // reset wrapper sizing
645 // determine the height of all the non-content elements
646 nonContentHeight
= this.uiDialog
.css({
651 minContentHeight
= Math
.max( 0, options
.minHeight
- nonContentHeight
);
653 if ( options
.height
=== "auto" ) {
654 // only needed for IE6 support
655 if ( $.support
.minHeight
) {
657 minHeight
: minContentHeight
,
661 this.uiDialog
.show();
662 autoHeight
= this.element
.css( "height", "auto" ).height();
664 this.uiDialog
.hide();
666 this.element
.height( Math
.max( autoHeight
, minContentHeight
) );
669 this.element
.height( Math
.max( options
.height
- nonContentHeight
, 0 ) );
672 if (this.uiDialog
.is( ":data(resizable)" ) ) {
673 this.uiDialog
.resizable( "option", "minHeight", this._minHeight() );
678 $.extend($.ui
.dialog
, {
682 getTitleId: function($el
) {
683 var id
= $el
.attr( "id" );
688 return "ui-dialog-title-" + id
;
691 overlay: function( dialog
) {
692 this.$el
= $.ui
.dialog
.overlay
.create( dialog
);
696 $.extend( $.ui
.dialog
.overlay
, {
698 // reuse old instances due to IE memory leak with alpha transparency (see #5185)
702 "focus,mousedown,mouseup,keydown,keypress,click".split( "," ),
704 return event
+ ".dialog-overlay";
707 create: function( dialog
) {
708 if ( this.instances
.length
=== 0 ) {
709 // prevent use of anchors and inputs
710 // we use a setTimeout in case the overlay is created from an
711 // event that we're going to be cancelling (see #2804)
712 setTimeout(function() {
713 // handle $(el).dialog().dialog('close') (see #4065)
714 if ( $.ui
.dialog
.overlay
.instances
.length
) {
715 $( document
).bind( $.ui
.dialog
.overlay
.events
, function( event
) {
716 // stop events if the z-index of the target is < the z-index of the overlay
717 // we cannot return true when we don't want to cancel the event (#3523)
718 if ( $( event
.target
).zIndex() < $.ui
.dialog
.overlay
.maxZ
) {
725 // handle window resize
726 $( window
).bind( "resize.dialog-overlay", $.ui
.dialog
.overlay
.resize
);
729 var $el
= ( this.oldInstances
.pop() || $( "<div>" ).addClass( "ui-widget-overlay" ) );
731 // allow closing by pressing the escape key
732 $( document
).bind( "keydown.dialog-overlay", function( event
) {
733 var instances
= $.ui
.dialog
.overlay
.instances
;
734 // only react to the event if we're the top overlay
735 if ( instances
.length
!== 0 && instances
[ instances
.length
- 1 ] === $el
&&
736 dialog
.options
.closeOnEscape
&& !event
.isDefaultPrevented() && event
.keyCode
&&
737 event
.keyCode
=== $.ui
.keyCode
.ESCAPE
) {
739 dialog
.close( event
);
740 event
.preventDefault();
744 $el
.appendTo( document
.body
).css({
746 height
: this.height()
749 if ( $.fn
.bgiframe
) {
753 this.instances
.push( $el
);
757 destroy: function( $el
) {
758 var indexOf
= $.inArray( $el
, this.instances
),
761 if ( indexOf
!== -1 ) {
762 this.oldInstances
.push( this.instances
.splice( indexOf
, 1 )[ 0 ] );
765 if ( this.instances
.length
=== 0 ) {
766 $( [ document
, window
] ).unbind( ".dialog-overlay" );
769 $el
.height( 0 ).width( 0 ).remove();
771 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
772 $.each( this.instances
, function() {
773 maxZ
= Math
.max( maxZ
, this.css( "z-index" ) );
783 scrollHeight
= Math
.max(
784 document
.documentElement
.scrollHeight
,
785 document
.body
.scrollHeight
787 offsetHeight
= Math
.max(
788 document
.documentElement
.offsetHeight
,
789 document
.body
.offsetHeight
792 if ( scrollHeight
< offsetHeight
) {
793 return $( window
).height() + "px";
795 return scrollHeight
+ "px";
797 // handle "good" browsers
799 return $( document
).height() + "px";
808 scrollWidth
= Math
.max(
809 document
.documentElement
.scrollWidth
,
810 document
.body
.scrollWidth
812 offsetWidth
= Math
.max(
813 document
.documentElement
.offsetWidth
,
814 document
.body
.offsetWidth
817 if ( scrollWidth
< offsetWidth
) {
818 return $( window
).width() + "px";
820 return scrollWidth
+ "px";
822 // handle "good" browsers
824 return $( document
).width() + "px";
829 /* If the dialog is draggable and the user drags it past the
830 * right edge of the window, the document becomes wider so we
831 * need to stretch the overlay. If the user then drags the
832 * dialog back to the left, the document will become narrower,
833 * so we need to shrink the overlay to the appropriate size.
834 * This is handled by shrinking the overlay before setting it
835 * to the full document size.
837 var $overlays
= $( [] );
838 $.each( $.ui
.dialog
.overlay
.instances
, function() {
839 $overlays
= $overlays
.add( this );
846 width
: $.ui
.dialog
.overlay
.width(),
847 height
: $.ui
.dialog
.overlay
.height()
852 $.extend( $.ui
.dialog
.overlay
.prototype, {
853 destroy: function() {
854 $.ui
.dialog
.overlay
.destroy( this.$el
);