aboutsummaryrefslogtreecommitdiffstats
path: root/ui/jquery.ui.dialog.js
diff options
context:
space:
mode:
Diffstat (limited to 'ui/jquery.ui.dialog.js')
-rw-r--r--ui/jquery.ui.dialog.js158
1 files changed, 96 insertions, 62 deletions
diff --git a/ui/jquery.ui.dialog.js b/ui/jquery.ui.dialog.js
index c5bd42ab5..7f90908bd 100644
--- a/ui/jquery.ui.dialog.js
+++ b/ui/jquery.ui.dialog.js
@@ -86,25 +86,25 @@ $.widget( "ui.dialog", {
_create: function() {
this.originalCss = {
- display: this.element[0].style.display,
- width: this.element[0].style.width,
- minHeight: this.element[0].style.minHeight,
- maxHeight: this.element[0].style.maxHeight,
- height: this.element[0].style.height
+ display: this.element[ 0 ].style.display,
+ width: this.element[ 0 ].style.width,
+ minHeight: this.element[ 0 ].style.minHeight,
+ maxHeight: this.element[ 0 ].style.maxHeight,
+ height: this.element[ 0 ].style.height
};
this.originalPosition = {
parent: this.element.parent(),
index: this.element.parent().children().index( this.element )
};
- this.originalTitle = this.element.attr("title");
+ this.originalTitle = this.element.attr( "title" );
this.options.title = this.options.title || this.originalTitle;
this._createWrapper();
this.element
.show()
- .removeAttr("title")
- .addClass("ui-dialog-content ui-widget-content")
+ .removeAttr( "title" )
+ .addClass( "ui-dialog-content ui-widget-content" )
.appendTo( this.uiDialog );
this._createTitlebar();
@@ -118,6 +118,8 @@ $.widget( "ui.dialog", {
}
this._isOpen = false;
+
+ this._trackFocus();
},
_init: function() {
@@ -142,7 +144,7 @@ $.widget( "ui.dialog", {
this.element
.removeUniqueId()
- .removeClass("ui-dialog-content ui-widget-content")
+ .removeClass( "ui-dialog-content ui-widget-content" )
.css( this.originalCss )
// Without detaching first, the following becomes really slow
.detach();
@@ -155,7 +157,7 @@ $.widget( "ui.dialog", {
next = originalPosition.parent.children().eq( originalPosition.index );
// Don't try to place the dialog next to itself (#8613)
- if ( next.length && next[0] !== this.element[0] ) {
+ if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
next.before( this.element );
} else {
originalPosition.parent.append( this.element );
@@ -178,9 +180,11 @@ $.widget( "ui.dialog", {
}
this._isOpen = false;
+ this._focusedElement = null;
this._destroyOverlay();
+ this._untrackInstance();
- if ( !this.opener.filter(":focusable").focus().length ) {
+ if ( !this.opener.filter( ":focusable" ).focus().length ) {
// support: IE9
// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
@@ -240,7 +244,7 @@ $.widget( "ui.dialog", {
}
this._isOpen = true;
- this.opener = $( this.document[0].activeElement );
+ this.opener = $( this.document[ 0 ].activeElement );
this._size();
this._position();
@@ -248,28 +252,32 @@ $.widget( "ui.dialog", {
this._moveToTop( null, true );
this._show( this.uiDialog, this.options.show, function() {
that._focusTabbable();
- that._trigger("focus");
+ that._trigger( "focus" );
});
- this._trigger("open");
+ this._trigger( "open" );
},
_focusTabbable: function() {
// Set focus to the first match:
- // 1. First element inside the dialog matching [autofocus]
- // 2. Tabbable element inside the content element
- // 3. Tabbable element inside the buttonpane
- // 4. The close button
- // 5. The dialog itself
- var hasFocus = this.element.find("[autofocus]");
+ // 1. An element that was focused previously
+ // 2. First element inside the dialog matching [autofocus]
+ // 3. Tabbable element inside the content element
+ // 4. Tabbable element inside the buttonpane
+ // 5. The close button
+ // 6. The dialog itself
+ var hasFocus = this._focusedElement;
+ if ( !hasFocus ) {
+ hasFocus = this.element.find( "[autofocus]" );
+ }
if ( !hasFocus.length ) {
- hasFocus = this.element.find(":tabbable");
+ hasFocus = this.element.find( ":tabbable" );
}
if ( !hasFocus.length ) {
- hasFocus = this.uiDialogButtonPane.find(":tabbable");
+ hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
}
if ( !hasFocus.length ) {
- hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
+ hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialog;
@@ -319,9 +327,9 @@ $.widget( "ui.dialog", {
if ( event.keyCode !== $.ui.keyCode.TAB ) {
return;
}
- var tabbables = this.uiDialog.find(":tabbable"),
- first = tabbables.filter(":first"),
- last = tabbables.filter(":last");
+ var tabbables = this.uiDialog.find( ":tabbable" ),
+ first = tabbables.filter( ":first" ),
+ last = tabbables.filter( ":last" );
if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
first.focus( 1 );
@@ -341,9 +349,9 @@ $.widget( "ui.dialog", {
// We assume that any existing aria-describedby attribute means
// that the dialog content is marked up properly
// otherwise we brute force the content as the description
- if ( !this.element.find("[aria-describedby]").length ) {
+ if ( !this.element.find( "[aria-describedby]" ).length ) {
this.uiDialog.attr({
- "aria-describedby": this.element.uniqueId().attr("id")
+ "aria-describedby": this.element.uniqueId().attr( "id" )
});
}
},
@@ -351,15 +359,15 @@ $.widget( "ui.dialog", {
_createTitlebar: function() {
var uiDialogTitle;
- this.uiDialogTitlebar = $("<div>")
- .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
+ this.uiDialogTitlebar = $( "<div>" )
+ .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
.prependTo( this.uiDialog );
this._on( this.uiDialogTitlebar, {
mousedown: function( event ) {
// Don't prevent click on close button (#8838)
// Focusing a dialog that is partially scrolled out of view
// causes the browser to scroll it into view, preventing the click event
- if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
+ if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
// Dialog isn't getting focus when dragging (#8063)
this.uiDialog.focus();
}
@@ -377,7 +385,7 @@ $.widget( "ui.dialog", {
},
text: false
})
- .addClass("ui-dialog-titlebar-close")
+ .addClass( "ui-dialog-titlebar-close" )
.appendTo( this.uiDialogTitlebar );
this._on( this.uiDialogTitlebarClose, {
click: function( event ) {
@@ -386,30 +394,30 @@ $.widget( "ui.dialog", {
}
});
- uiDialogTitle = $("<span>")
+ uiDialogTitle = $( "<span>" )
.uniqueId()
- .addClass("ui-dialog-title")
+ .addClass( "ui-dialog-title" )
.prependTo( this.uiDialogTitlebar );
this._title( uiDialogTitle );
this.uiDialog.attr({
- "aria-labelledby": uiDialogTitle.attr("id")
+ "aria-labelledby": uiDialogTitle.attr( "id" )
});
},
_title: function( title ) {
if ( !this.options.title ) {
- title.html("&#160;");
+ title.html( "&#160;" );
}
title.text( this.options.title );
},
_createButtonPane: function() {
- this.uiDialogButtonPane = $("<div>")
- .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
+ this.uiDialogButtonPane = $( "<div>" )
+ .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
- this.uiButtonSet = $("<div>")
- .addClass("ui-dialog-buttonset")
+ this.uiButtonSet = $( "<div>" )
+ .addClass( "ui-dialog-buttonset" )
.appendTo( this.uiDialogButtonPane );
this._createButtons();
@@ -424,7 +432,7 @@ $.widget( "ui.dialog", {
this.uiButtonSet.empty();
if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
- this.uiDialog.removeClass("ui-dialog-buttons");
+ this.uiDialog.removeClass( "ui-dialog-buttons" );
return;
}
@@ -438,7 +446,7 @@ $.widget( "ui.dialog", {
// Change the context for the click callback to be the main element
click = props.click;
props.click = function() {
- click.apply( that.element[0], arguments );
+ click.apply( that.element[ 0 ], arguments );
};
buttonOptions = {
icons: props.icons,
@@ -450,7 +458,7 @@ $.widget( "ui.dialog", {
.button( buttonOptions )
.appendTo( that.uiButtonSet );
});
- this.uiDialog.addClass("ui-dialog-buttons");
+ this.uiDialog.addClass( "ui-dialog-buttons" );
this.uiDialogButtonPane.appendTo( this.uiDialog );
},
@@ -470,7 +478,7 @@ $.widget( "ui.dialog", {
handle: ".ui-dialog-titlebar",
containment: "document",
start: function( event, ui ) {
- $( this ).addClass("ui-dialog-dragging");
+ $( this ).addClass( "ui-dialog-dragging" );
that._blockFrames();
that._trigger( "dragStart", event, filteredUi( ui ) );
},
@@ -487,7 +495,7 @@ $.widget( "ui.dialog", {
"top" + (top >= 0 ? "+" : "") + top,
of: that.window
};
- $( this ).removeClass("ui-dialog-dragging");
+ $( this ).removeClass( "ui-dialog-dragging" );
that._unblockFrames();
that._trigger( "dragStop", event, filteredUi( ui ) );
}
@@ -524,7 +532,7 @@ $.widget( "ui.dialog", {
minHeight: this._minHeight(),
handles: resizeHandles,
start: function( event, ui ) {
- $( this ).addClass("ui-dialog-resizing");
+ $( this ).addClass( "ui-dialog-resizing" );
that._blockFrames();
that._trigger( "resizeStart", event, filteredUi( ui ) );
},
@@ -544,7 +552,7 @@ $.widget( "ui.dialog", {
"top" + (top >= 0 ? "+" : "") + top,
of: that.window
};
- $( this ).removeClass("ui-dialog-resizing");
+ $( this ).removeClass( "ui-dialog-resizing" );
that._unblockFrames();
that._trigger( "resizeStop", event, filteredUi( ui ) );
}
@@ -552,6 +560,33 @@ $.widget( "ui.dialog", {
.css( "position", position );
},
+ _trackFocus: function() {
+ this._on( this.widget(), {
+ "focusin": function( event ) {
+ this._untrackInstance();
+ this._trackingInstances().unshift( this );
+ this._focusedElement = $( event.target );
+ }
+ });
+ },
+
+ _untrackInstance: function() {
+ var instances = this._trackingInstances(),
+ exists = $.inArray( this, instances );
+ if ( exists !== -1 ) {
+ instances.splice( exists, 1 );
+ }
+ },
+
+ _trackingInstances: function() {
+ var instances = this.document.data( "ui-dialog-instances" );
+ if ( !instances ) {
+ instances = [];
+ this.document.data( "ui-dialog-instances", instances );
+ }
+ return instances;
+ },
+
_minHeight: function() {
var options = this.options;
@@ -562,7 +597,7 @@ $.widget( "ui.dialog", {
_position: function() {
// Need to show the dialog to get the actual offset in the position plugin
- var isVisible = this.uiDialog.is(":visible");
+ var isVisible = this.uiDialog.is( ":visible" );
if ( !isVisible ) {
this.uiDialog.show();
}
@@ -592,7 +627,7 @@ $.widget( "ui.dialog", {
this._size();
this._position();
}
- if ( this.uiDialog.is(":data(ui-resizable)") ) {
+ if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
this.uiDialog.resizable( "option", resizableOptions );
}
},
@@ -629,9 +664,9 @@ $.widget( "ui.dialog", {
}
if ( key === "draggable" ) {
- isDraggable = uiDialog.is(":data(ui-draggable)");
+ isDraggable = uiDialog.is( ":data(ui-draggable)" );
if ( isDraggable && !value ) {
- uiDialog.draggable("destroy");
+ uiDialog.draggable( "destroy" );
}
if ( !isDraggable && value ) {
@@ -645,9 +680,9 @@ $.widget( "ui.dialog", {
if ( key === "resizable" ) {
// currently resizable, becoming non-resizable
- isResizable = uiDialog.is(":data(ui-resizable)");
+ isResizable = uiDialog.is( ":data(ui-resizable)" );
if ( isResizable && !value ) {
- uiDialog.resizable("destroy");
+ uiDialog.resizable( "destroy" );
}
// currently resizable, changing handles
@@ -662,7 +697,7 @@ $.widget( "ui.dialog", {
}
if ( key === "title" ) {
- this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
+ this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
}
},
@@ -706,7 +741,7 @@ $.widget( "ui.dialog", {
this.element.height( Math.max( 0, options.height - nonContentHeight ) );
}
- if (this.uiDialog.is(":data(ui-resizable)") ) {
+ if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
}
},
@@ -734,13 +769,13 @@ $.widget( "ui.dialog", {
},
_allowInteraction: function( event ) {
- if ( $( event.target ).closest(".ui-dialog").length ) {
+ if ( $( event.target ).closest( ".ui-dialog" ).length ) {
return true;
}
// TODO: Remove hack when datepicker implements
// the .ui-front logic (#8989)
- return !!$( event.target ).closest(".ui-datepicker").length;
+ return !!$( event.target ).closest( ".ui-datepicker" ).length;
},
_createOverlay: function() {
@@ -768,15 +803,14 @@ $.widget( "ui.dialog", {
if ( !this._allowInteraction( event ) ) {
event.preventDefault();
- this.document.find( ".ui-dialog:visible:last .ui-dialog-content" )
- .data( this.widgetFullName )._focusTabbable();
+ this._trackingInstances()[ 0 ]._focusTabbable();
}
}
});
}
- this.overlay = $("<div>")
- .addClass("ui-widget-overlay ui-front")
+ this.overlay = $( "<div>" )
+ .addClass( "ui-widget-overlay ui-front" )
.appendTo( this._appendTo() );
this._on( this.overlay, {
mousedown: "_keepFocus"
@@ -807,4 +841,4 @@ $.widget( "ui.dialog", {
}
});
-}( jQuery ) );
+}( jQuery ));