/*! * jQuery UI Dialog @VERSION * http://jqueryui.com * * Copyright 2012 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * * http://api.jqueryui.com/dialog/ * * Depends: * jquery.ui.core.js * jquery.ui.widget.js * jquery.ui.button.js * jquery.ui.draggable.js * jquery.ui.mouse.js * jquery.ui.position.js * jquery.ui.resizable.js */ (function( $, undefined ) { var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ", sizeRelatedOptions = { buttons: true, height: true, maxHeight: true, maxWidth: true, minHeight: true, minWidth: true, width: true }, resizableRelatedOptions = { maxHeight: true, maxWidth: true, minHeight: true, minWidth: true }; $.widget("ui.dialog", { version: "@VERSION", options: { autoOpen: true, buttons: {}, closeOnEscape: true, closeText: "close", dialogClass: "", draggable: true, hide: null, height: "auto", maxHeight: false, maxWidth: false, minHeight: 150, minWidth: 150, modal: false, position: { my: "center", at: "center", of: window, collision: "fit", // ensure that the titlebar is never outside the document using: function( pos ) { var topOffset = $( this ).css( pos ).offset().top; if ( topOffset < 0 ) { $( this ).css( "top", pos.top - topOffset ); } } }, resizable: true, show: null, title: "", width: 300 }, _create: function() { this.originalTitle = this.element.attr( "title" ); // #5742 - .attr() might return a DOMElement if ( typeof this.originalTitle !== "string" ) { this.originalTitle = ""; } this.oldPosition = { parent: this.element.parent(), index: this.element.parent().children().index( this.element ) }; this.options.title = this.options.title || this.originalTitle; var that = this, options = this.options, title = options.title || " ", uiDialog, uiDialogTitlebar, uiDialogTitlebarClose, uiDialogTitle, uiDialogButtonPane; uiDialog = ( this.uiDialog = $( "
" ) ) .addClass( uiDialogClasses + options.dialogClass ) .hide() // setting tabIndex makes the div focusable .attr( "tabIndex", -1) .keydown(function( event ) { if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && event.keyCode === $.ui.keyCode.ESCAPE ) { that.close( event ); event.preventDefault(); } }) .mousedown(function( event ) { that.moveToTop( event ); }) .appendTo( this.document[ 0 ].body ); this.element .show() .removeAttr( "title" ) .addClass( "ui-dialog-content ui-widget-content" ) .appendTo( uiDialog ); uiDialogTitlebar = ( this.uiDialogTitlebar = $( "
" ) ) .addClass( "ui-dialog-titlebar ui-widget-header " + "ui-corner-all ui-helper-clearfix" ) .bind( "mousedown", function() { // Dialog isn't getting focus when dragging (#8063) uiDialog.focus(); }) .prependTo( uiDialog ); uiDialogTitlebarClose = $( "" ) .addClass( "ui-dialog-titlebar-close ui-corner-all" ) .attr( "role", "button" ) .click(function( event ) { event.preventDefault(); that.close( event ); }) .appendTo( uiDialogTitlebar ); ( this.uiDialogTitlebarCloseText = $( "" ) ) .addClass( "ui-icon ui-icon-closethick" ) .text( options.closeText ) .appendTo( uiDialogTitlebarClose ); uiDialogTitle = $( "" ) .uniqueId() .addClass( "ui-dialog-title" ) .html( title ) .prependTo( uiDialogTitlebar ); uiDialogButtonPane = ( this.uiDialogButtonPane = $( "
" ) ) .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ); ( this.uiButtonSet = $( "
" ) ) .addClass( "ui-dialog-buttonset" ) .appendTo( uiDialogButtonPane ); uiDialog.attr({ role: "dialog", "aria-labelledby": uiDialogTitle.attr( "id" ) }); uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection(); this._hoverable( uiDialogTitlebarClose ); this._focusable( uiDialogTitlebarClose ); if ( options.draggable && $.fn.draggable ) { this._makeDraggable(); } if ( options.resizable && $.fn.resizable ) { this._makeResizable(); } this._createButtons( options.buttons ); this._isOpen = false; if ( $.fn.bgiframe ) { uiDialog.bgiframe(); } // prevent tabbing out of dialogs this._on( uiDialog, { keydown: function( event ) { if ( event.keyCode !== $.ui.keyCode.TAB ) { return; } var tabbables = $( ":tabbable", uiDialog ), first = tabbables.filter( ":first" ), last = tabbables.filter( ":last" ); if ( ( event.target === last[ 0 ] || event.target === uiDialog[ 0 ] ) && !event.shiftKey ) { first.focus( 1 ); return false; } else if ( ( event.target === first[ 0 ] || event.target === uiDialog[ 0 ] ) && event.shiftKey ) { last.focus( 1 ); return false; } }}); }, _init: function() { if ( this.options.autoOpen ) { this.open(); } }, _destroy: function() { var next, oldPosition = this.oldPosition; if ( this.overlay ) { this.overlay.destroy(); } this.uiDialog.hide(); this.element .removeClass( "ui-dialog-content ui-widget-content" ) .hide() .appendTo( "body" ); this.uiDialog.remove(); if ( this.originalTitle ) { this.element.attr( "title", this.originalTitle ); } next = oldPosition.parent.children().eq( oldPosition.index ); // Don't try to place the dialog next to itself (#8613) if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { next.before( this.element ); } else { oldPosition.parent.append( this.element ); } }, widget: function() { return this.uiDialog; }, close: function( event ) { var that = this; if ( !this._isOpen ) { return; } if ( false === this._trigger( "beforeClose", event ) ) { return; } this._isOpen = false; if ( this.overlay ) { this.overlay.destroy(); } if ( !this.opener.filter( ":focusable" ).focus().length ) { // Hiding a focused element doesn't trigger blur in WebKit // so in case we have nothing to focus on, explicitly blur the active element // https://bugs.webkit.org/show_bug.cgi?id=47182 $( this.document[ 0 ].activeElement ).blur(); } this._hide( this.uiDialog, this.options.hide, function() { that._trigger( "close", event ); }); }, isOpen: function() { return this._isOpen; }, moveToTop: function( event, silent ) { var moved = this.uiDialog.nextAll( ":visible" ).insertBefore( this.uiDialog ); if ( !silent && moved.length ) { this._trigger( "focus", event ); } }, open: function() { if ( this._isOpen ) { return; } var hasFocus, options = this.options, uiDialog = this.uiDialog; this.opener = $( this.document[ 0 ].activeElement ); this._size(); this._position( options.position ); this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null; this.moveToTop( null, true ); this._show( uiDialog, options.show ); // set focus to the first tabbable element in the content area or the first button // if there are no tabbable elements, set focus on the dialog itself hasFocus = this.element.find( ":tabbable" ); if ( !hasFocus.length ) { hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); if ( !hasFocus.length ) { hasFocus = uiDialog; } } hasFocus.eq( 0 ).focus(); this._isOpen = true; this._trigger( "open" ); this._trigger( "focus" ); return this; }, _keepFocus: function( event ) { function checkFocus() { var activeElement = this.document[ 0 ].activeElement, isActive = this.uiDialog[ 0 ] === activeElement || $.contains( this.uiDialog[ 0 ], activeElement ); if ( !isActive ) { this.uiDialog.focus(); } } event.preventDefault(); checkFocus.call( this ); // support: IE // IE <= 8 doesn't prevent moving focus even with event.preventDefault() // so we check again later this._delay( checkFocus ); }, _createButtons: function( buttons ) { var that = this, hasButtons = false; // if we already have a button pane, remove it this.uiDialogButtonPane.remove(); this.uiButtonSet.empty(); if ( typeof buttons === "object" && buttons !== null ) { $.each( buttons, function() { return !(hasButtons = true); }); } if ( hasButtons ) { $.each( buttons, function( name, props ) { props = $.isFunction( props ) ? { click: props, text: name } : props; var button = $( "" ) .attr( props, true ) .unbind( "click" ) .click(function() { props.click.apply( that.element[0], arguments ); }) .appendTo( that.uiButtonSet ); if ( $.fn.button ) { button.button(); } }); this.uiDialog.addClass( "ui-dialog-buttons" ); this.uiDialogButtonPane.appendTo( this.uiDialog ); } else { this.uiDialog.removeClass( "ui-dialog-buttons" ); } }, _makeDraggable: function() { var that = this, options = this.options; function filteredUi( ui ) { return { position: ui.position, offset: ui.offset }; } this.uiDialog.draggable({ cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", handle: ".ui-dialog-titlebar", containment: "document", start: function( event, ui ) { $( this ) .addClass( "ui-dialog-dragging" ); that._trigger( "dragStart", event, filteredUi( ui ) ); }, drag: function( event, ui ) { that._trigger( "drag", event, filteredUi( ui ) ); }, stop: function( event, ui ) { options.position = [ ui.position.left - that.document.scrollLeft(), ui.position.top - that.document.scrollTop() ]; $( this ) .removeClass( "ui-dialog-dragging" ); that._trigger( "dragStop", event, filteredUi( ui ) ); } }); }, _makeResizable: function( handles ) { handles = (handles === undefined ? this.options.resizable : handles); var that = this, options = this.options, // .ui-resizable has position: relative defined in the stylesheet // but dialogs have to use absolute or fixed positioning position = this.uiDialog.css( "position" ), resizeHandles = typeof handles === 'string' ? handles : "n,e,s,w,se,sw,ne,nw"; function filteredUi( ui ) { return { originalPosition: ui.originalPosition, originalSize: ui.originalSize, position: ui.position, size: ui.size }; } this.uiDialog.resizable({ cancel: ".ui-dialog-content", containment: "document", alsoResize: this.element, maxWidth: options.maxWidth, maxHeight: options.maxHeight, minWidth: options.minWidth, minHeight: this._minHeight(), handles: resizeHandles, start: function( event, ui ) { $( this ).addClass( "ui-dialog-resizing" ); that._trigger( "resizeStart", event, filteredUi( ui ) ); }, resize: function( event, ui ) { that._trigger( "resize", event, filteredUi( ui ) ); }, stop: function( event, ui ) { $( this ).removeClass( "ui-dialog-resizing" ); options.height = $( this ).height(); options.width = $( this ).width(); that._trigger( "resizeStop", event, filteredUi( ui ) ); } }) .css( "position", position ) .find( ".ui-resizable-se" ) .addClass( "ui-icon ui-icon-grip-diagonal-se" ); }, _minHeight: function() { var options = this.options; if ( options.height === "auto" ) { return options.minHeight; } else { return Math.min( options.minHeight, options.height ); } }, _position: function( position ) { var myAt = [], offset = [ 0, 0 ], isVisible; if ( position ) { // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( // if (typeof position == 'string' || $.isArray(position)) { // myAt = $.isArray(position) ? position : position.split(' '); if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ]; if ( myAt.length === 1 ) { myAt[ 1 ] = myAt[ 0 ]; } $.each( [ "left", "top" ], function( i, offsetPosition ) { if ( +myAt[ i ] === myAt[ i ] ) { offset[ i ] = myAt[ i ]; myAt[ i ] = offsetPosition; } }); position = { my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), at: myAt.join( " " ) }; } position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); } else { position = $.ui.dialog.prototype.options.position; } // need to show the dialog to get the actual offset in the position plugin isVisible = this.uiDialog.is( ":visible" ); if ( !isVisible ) { this.uiDialog.show(); } this.uiDialog.position( position ); if ( !isVisible ) { this.uiDialog.hide(); } }, _setOptions: function( options ) { var that = this, resizableOptions = {}, resize = false; $.each( options, function( key, value ) { that._setOption( key, value ); if ( key in sizeRelatedOptions ) { resize = true; } if ( key in resizableRelatedOptions ) { resizableOptions[ key ] = value; } }); if ( resize ) { this._size(); } if ( this.uiDialog.is( ":data(resizable)" ) ) { this.uiDialog.resizable( "option", resizableOptions ); } }, _setOption: function( key, value ) { var isDraggable, isResizable, uiDialog = this.uiDialog; switch ( key ) { case "buttons": this._createButtons( value ); break; case "closeText": // ensure that we always pass a string this.uiDialogTitlebarCloseText.text( "" + value ); break; case "dialogClass": uiDialog .removeClass( this.options.dialogClass ) .addClass( uiDialogClasses + value ); break; case "disabled": if ( value ) { uiDialog.addClass( "ui-dialog-disabled" ); } else { uiDialog.removeClass( "ui-dialog-disabled" ); } break; case "draggable": isDraggable = uiDialog.is( ":data(draggable)" ); if ( isDraggable && !value ) { uiDialog.draggable( "destroy" ); } if ( !isDraggable && value ) { this._makeDraggable(); } break; case "position": this._position( value ); break; case "resizable": // currently resizable, becoming non-resizable isResizable = uiDialog.is( ":data(resizable)" ); if ( isResizable && !value ) { uiDialog.resizable( "destroy" ); } // currently resizable, changing handles if ( isResizable && typeof value === "string" ) { uiDialog.resizable( "option", "handles", value ); } // currently non-resizable, becoming resizable if ( !isResizable && value !== false ) { this._makeResizable( value ); } break; case "title": // convert whatever was passed in o a string, for html() to not throw up $( ".ui-dialog-title", this.uiDialogTitlebar ) .html( "" + ( value || " " ) ); break; } this._super( key, value ); }, _size: function() { /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content * divs will both have width and height set, so we need to reset them */ var nonContentHeight, minContentHeight, autoHeight, options = this.options, isVisible = this.uiDialog.is( ":visible" ); // reset content sizing this.element.show().css({ width: "auto", minHeight: 0, height: 0 }); if ( options.minWidth > options.width ) { options.width = options.minWidth; } // reset wrapper sizing // determine the height of all the non-content elements nonContentHeight = this.uiDialog.css({ height: "auto", width: options.width }) .outerHeight(); minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); if ( options.height === "auto" ) { // only needed for IE6 support if ( $.support.minHeight ) { this.element.css({ minHeight: minContentHeight, height: "auto" }); } else { this.uiDialog.show(); autoHeight = this.element.css( "height", "auto" ).height(); if ( !isVisible ) { this.uiDialog.hide(); } this.element.height( Math.max( autoHeight, minContentHeight ) ); } } else { this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); } if (this.uiDialog.is( ":data(resizable)" ) ) { this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); } } }); $.extend($.ui.dialog, { uuid: 0, getTitleId: function($el) { var id = $el.attr( "id" ); if ( !id ) { this.uuid += 1; id = this.uuid; } return "ui-dialog-title-" + id; }, overlay: function( dialog ) { this.$el = $.ui.dialog.overlay.create( dialog ); } }); $.extend( $.ui.dialog.overlay, { instances: [], // reuse old instances due to IE memory leak with alpha transparency (see #5185) oldInstances: [], create: function( dialog ) { var $el = ( this.oldInstances.pop() || $( "
" ).addClass( "ui-widget-overlay ui-front" ) ); $el.appendTo( document.body ); $el.bind( "mousedown", function( event ) { dialog._keepFocus( event ); }); if ( $.fn.bgiframe ) { $el.bgiframe(); } this.instances.push( $el ); return $el; }, destroy: function( $el ) { var indexOf = $.inArray( $el, this.instances ); if ( indexOf !== -1 ) { this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] ); } if ( this.instances.length === 0 ) { $( [ document, window ] ).unbind( ".dialog-overlay" ); } $el.remove(); } }); $.extend( $.ui.dialog.overlay.prototype, { destroy: function() { $.ui.dialog.overlay.destroy( this.$el ); } }); }( jQuery ) );