dialog.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. /*!
  2. * jQuery UI Dialog 1.11.4
  3. * http://jqueryui.com
  4. *
  5. * Copyright jQuery Foundation and other contributors
  6. * Released under the MIT license.
  7. * http://jquery.org/license
  8. *
  9. * http://api.jqueryui.com/dialog/
  10. */
  11. (function( factory ) {
  12. if ( typeof define === "function" && define.amd ) {
  13. // AMD. Register as an anonymous module.
  14. define([
  15. "jquery",
  16. "./core",
  17. "./widget",
  18. "./button",
  19. "./draggable",
  20. "./mouse",
  21. "./position",
  22. "./resizable"
  23. ], factory );
  24. } else {
  25. // Browser globals
  26. factory( jQuery );
  27. }
  28. }(function( $ ) {
  29. return $.widget( "ui.dialog", {
  30. version: "1.11.4",
  31. options: {
  32. appendTo: "body",
  33. autoOpen: true,
  34. buttons: [],
  35. closeOnEscape: true,
  36. closeText: "Close",
  37. dialogClass: "",
  38. draggable: true,
  39. hide: null,
  40. height: "auto",
  41. maxHeight: null,
  42. maxWidth: null,
  43. minHeight: 150,
  44. minWidth: 150,
  45. modal: false,
  46. position: {
  47. my: "center",
  48. at: "center",
  49. of: window,
  50. collision: "fit",
  51. // Ensure the titlebar is always visible
  52. using: function( pos ) {
  53. var topOffset = $( this ).css( pos ).offset().top;
  54. if ( topOffset < 0 ) {
  55. $( this ).css( "top", pos.top - topOffset );
  56. }
  57. }
  58. },
  59. resizable: true,
  60. show: null,
  61. title: null,
  62. width: 300,
  63. // callbacks
  64. beforeClose: null,
  65. close: null,
  66. drag: null,
  67. dragStart: null,
  68. dragStop: null,
  69. focus: null,
  70. open: null,
  71. resize: null,
  72. resizeStart: null,
  73. resizeStop: null
  74. },
  75. sizeRelatedOptions: {
  76. buttons: true,
  77. height: true,
  78. maxHeight: true,
  79. maxWidth: true,
  80. minHeight: true,
  81. minWidth: true,
  82. width: true
  83. },
  84. resizableRelatedOptions: {
  85. maxHeight: true,
  86. maxWidth: true,
  87. minHeight: true,
  88. minWidth: true
  89. },
  90. _create: function() {
  91. this.originalCss = {
  92. display: this.element[ 0 ].style.display,
  93. width: this.element[ 0 ].style.width,
  94. minHeight: this.element[ 0 ].style.minHeight,
  95. maxHeight: this.element[ 0 ].style.maxHeight,
  96. height: this.element[ 0 ].style.height
  97. };
  98. this.originalPosition = {
  99. parent: this.element.parent(),
  100. index: this.element.parent().children().index( this.element )
  101. };
  102. this.originalTitle = this.element.attr( "title" );
  103. this.options.title = this.options.title || this.originalTitle;
  104. this._createWrapper();
  105. this.element
  106. .show()
  107. .removeAttr( "title" )
  108. .addClass( "ui-dialog-content ui-widget-content" )
  109. .appendTo( this.uiDialog );
  110. this._createTitlebar();
  111. this._createButtonPane();
  112. if ( this.options.draggable && $.fn.draggable ) {
  113. this._makeDraggable();
  114. }
  115. if ( this.options.resizable && $.fn.resizable ) {
  116. this._makeResizable();
  117. }
  118. this._isOpen = false;
  119. this._trackFocus();
  120. },
  121. _init: function() {
  122. if ( this.options.autoOpen ) {
  123. this.open();
  124. }
  125. },
  126. _appendTo: function() {
  127. var element = this.options.appendTo;
  128. if ( element && (element.jquery || element.nodeType) ) {
  129. return $( element );
  130. }
  131. return this.document.find( element || "body" ).eq( 0 );
  132. },
  133. _destroy: function() {
  134. var next,
  135. originalPosition = this.originalPosition;
  136. this._untrackInstance();
  137. this._destroyOverlay();
  138. this.element
  139. .removeUniqueId()
  140. .removeClass( "ui-dialog-content ui-widget-content" )
  141. .css( this.originalCss )
  142. // Without detaching first, the following becomes really slow
  143. .detach();
  144. this.uiDialog.stop( true, true ).remove();
  145. if ( this.originalTitle ) {
  146. this.element.attr( "title", this.originalTitle );
  147. }
  148. next = originalPosition.parent.children().eq( originalPosition.index );
  149. // Don't try to place the dialog next to itself (#8613)
  150. if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
  151. next.before( this.element );
  152. } else {
  153. originalPosition.parent.append( this.element );
  154. }
  155. },
  156. widget: function() {
  157. return this.uiDialog;
  158. },
  159. disable: $.noop,
  160. enable: $.noop,
  161. close: function( event ) {
  162. var activeElement,
  163. that = this;
  164. if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
  165. return;
  166. }
  167. this._isOpen = false;
  168. this._focusedElement = null;
  169. this._destroyOverlay();
  170. this._untrackInstance();
  171. if ( !this.opener.filter( ":focusable" ).focus().length ) {
  172. // support: IE9
  173. // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
  174. try {
  175. activeElement = this.document[ 0 ].activeElement;
  176. // Support: IE9, IE10
  177. // If the <body> is blurred, IE will switch windows, see #4520
  178. if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
  179. // Hiding a focused element doesn't trigger blur in WebKit
  180. // so in case we have nothing to focus on, explicitly blur the active element
  181. // https://bugs.webkit.org/show_bug.cgi?id=47182
  182. $( activeElement ).blur();
  183. }
  184. } catch ( error ) {}
  185. }
  186. this._hide( this.uiDialog, this.options.hide, function() {
  187. that._trigger( "close", event );
  188. });
  189. },
  190. isOpen: function() {
  191. return this._isOpen;
  192. },
  193. moveToTop: function() {
  194. this._moveToTop();
  195. },
  196. _moveToTop: function( event, silent ) {
  197. var moved = false,
  198. zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
  199. return +$( this ).css( "z-index" );
  200. }).get(),
  201. zIndexMax = Math.max.apply( null, zIndices );
  202. if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
  203. this.uiDialog.css( "z-index", zIndexMax + 1 );
  204. moved = true;
  205. }
  206. if ( moved && !silent ) {
  207. this._trigger( "focus", event );
  208. }
  209. return moved;
  210. },
  211. open: function() {
  212. var that = this;
  213. if ( this._isOpen ) {
  214. if ( this._moveToTop() ) {
  215. this._focusTabbable();
  216. }
  217. return;
  218. }
  219. this._isOpen = true;
  220. this.opener = $( this.document[ 0 ].activeElement );
  221. this._size();
  222. this._position();
  223. this._createOverlay();
  224. this._moveToTop( null, true );
  225. // Ensure the overlay is moved to the top with the dialog, but only when
  226. // opening. The overlay shouldn't move after the dialog is open so that
  227. // modeless dialogs opened after the modal dialog stack properly.
  228. if ( this.overlay ) {
  229. this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
  230. }
  231. this._show( this.uiDialog, this.options.show, function() {
  232. that._focusTabbable();
  233. that._trigger( "focus" );
  234. });
  235. // Track the dialog immediately upon openening in case a focus event
  236. // somehow occurs outside of the dialog before an element inside the
  237. // dialog is focused (#10152)
  238. this._makeFocusTarget();
  239. this._trigger( "open" );
  240. },
  241. _focusTabbable: function() {
  242. // Set focus to the first match:
  243. // 1. An element that was focused previously
  244. // 2. First element inside the dialog matching [autofocus]
  245. // 3. Tabbable element inside the content element
  246. // 4. Tabbable element inside the buttonpane
  247. // 5. The close button
  248. // 6. The dialog itself
  249. var hasFocus = this._focusedElement;
  250. if ( !hasFocus ) {
  251. hasFocus = this.element.find( "[autofocus]" );
  252. }
  253. if ( !hasFocus.length ) {
  254. hasFocus = this.element.find( ":tabbable" );
  255. }
  256. if ( !hasFocus.length ) {
  257. hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
  258. }
  259. if ( !hasFocus.length ) {
  260. hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
  261. }
  262. if ( !hasFocus.length ) {
  263. hasFocus = this.uiDialog;
  264. }
  265. hasFocus.eq( 0 ).focus();
  266. },
  267. _keepFocus: function( event ) {
  268. function checkFocus() {
  269. var activeElement = this.document[0].activeElement,
  270. isActive = this.uiDialog[0] === activeElement ||
  271. $.contains( this.uiDialog[0], activeElement );
  272. if ( !isActive ) {
  273. this._focusTabbable();
  274. }
  275. }
  276. event.preventDefault();
  277. checkFocus.call( this );
  278. // support: IE
  279. // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
  280. // so we check again later
  281. this._delay( checkFocus );
  282. },
  283. _createWrapper: function() {
  284. this.uiDialog = $("<div>")
  285. .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
  286. this.options.dialogClass )
  287. .hide()
  288. .attr({
  289. // Setting tabIndex makes the div focusable
  290. tabIndex: -1,
  291. role: "dialog"
  292. })
  293. .appendTo( this._appendTo() );
  294. this._on( this.uiDialog, {
  295. keydown: function( event ) {
  296. if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
  297. event.keyCode === $.ui.keyCode.ESCAPE ) {
  298. event.preventDefault();
  299. this.close( event );
  300. return;
  301. }
  302. // prevent tabbing out of dialogs
  303. if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
  304. return;
  305. }
  306. var tabbables = this.uiDialog.find( ":tabbable" ),
  307. first = tabbables.filter( ":first" ),
  308. last = tabbables.filter( ":last" );
  309. if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
  310. this._delay(function() {
  311. first.focus();
  312. });
  313. event.preventDefault();
  314. } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
  315. this._delay(function() {
  316. last.focus();
  317. });
  318. event.preventDefault();
  319. }
  320. },
  321. mousedown: function( event ) {
  322. if ( this._moveToTop( event ) ) {
  323. this._focusTabbable();
  324. }
  325. }
  326. });
  327. // We assume that any existing aria-describedby attribute means
  328. // that the dialog content is marked up properly
  329. // otherwise we brute force the content as the description
  330. if ( !this.element.find( "[aria-describedby]" ).length ) {
  331. this.uiDialog.attr({
  332. "aria-describedby": this.element.uniqueId().attr( "id" )
  333. });
  334. }
  335. },
  336. _createTitlebar: function() {
  337. var uiDialogTitle;
  338. this.uiDialogTitlebar = $( "<div>" )
  339. .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
  340. .prependTo( this.uiDialog );
  341. this._on( this.uiDialogTitlebar, {
  342. mousedown: function( event ) {
  343. // Don't prevent click on close button (#8838)
  344. // Focusing a dialog that is partially scrolled out of view
  345. // causes the browser to scroll it into view, preventing the click event
  346. if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
  347. // Dialog isn't getting focus when dragging (#8063)
  348. this.uiDialog.focus();
  349. }
  350. }
  351. });
  352. // support: IE
  353. // Use type="button" to prevent enter keypresses in textboxes from closing the
  354. // dialog in IE (#9312)
  355. this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
  356. .button({
  357. label: this.options.closeText,
  358. icons: {
  359. primary: "ui-icon-closethick"
  360. },
  361. text: false
  362. })
  363. .addClass( "ui-dialog-titlebar-close" )
  364. .appendTo( this.uiDialogTitlebar );
  365. this._on( this.uiDialogTitlebarClose, {
  366. click: function( event ) {
  367. event.preventDefault();
  368. this.close( event );
  369. }
  370. });
  371. uiDialogTitle = $( "<span>" )
  372. .uniqueId()
  373. .addClass( "ui-dialog-title" )
  374. .prependTo( this.uiDialogTitlebar );
  375. this._title( uiDialogTitle );
  376. this.uiDialog.attr({
  377. "aria-labelledby": uiDialogTitle.attr( "id" )
  378. });
  379. },
  380. _title: function( title ) {
  381. if ( !this.options.title ) {
  382. title.html( "&#160;" );
  383. }
  384. title.text( this.options.title );
  385. },
  386. _createButtonPane: function() {
  387. this.uiDialogButtonPane = $( "<div>" )
  388. .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
  389. this.uiButtonSet = $( "<div>" )
  390. .addClass( "ui-dialog-buttonset" )
  391. .appendTo( this.uiDialogButtonPane );
  392. this._createButtons();
  393. },
  394. _createButtons: function() {
  395. var that = this,
  396. buttons = this.options.buttons;
  397. // if we already have a button pane, remove it
  398. this.uiDialogButtonPane.remove();
  399. this.uiButtonSet.empty();
  400. if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
  401. this.uiDialog.removeClass( "ui-dialog-buttons" );
  402. return;
  403. }
  404. $.each( buttons, function( name, props ) {
  405. var click, buttonOptions;
  406. props = $.isFunction( props ) ?
  407. { click: props, text: name } :
  408. props;
  409. // Default to a non-submitting button
  410. props = $.extend( { type: "button" }, props );
  411. // Change the context for the click callback to be the main element
  412. click = props.click;
  413. props.click = function() {
  414. click.apply( that.element[ 0 ], arguments );
  415. };
  416. buttonOptions = {
  417. icons: props.icons,
  418. text: props.showText
  419. };
  420. delete props.icons;
  421. delete props.showText;
  422. $( "<button></button>", props )
  423. .button( buttonOptions )
  424. .appendTo( that.uiButtonSet );
  425. });
  426. this.uiDialog.addClass( "ui-dialog-buttons" );
  427. this.uiDialogButtonPane.appendTo( this.uiDialog );
  428. },
  429. _makeDraggable: function() {
  430. var that = this,
  431. options = this.options;
  432. function filteredUi( ui ) {
  433. return {
  434. position: ui.position,
  435. offset: ui.offset
  436. };
  437. }
  438. this.uiDialog.draggable({
  439. cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
  440. handle: ".ui-dialog-titlebar",
  441. containment: "document",
  442. start: function( event, ui ) {
  443. $( this ).addClass( "ui-dialog-dragging" );
  444. that._blockFrames();
  445. that._trigger( "dragStart", event, filteredUi( ui ) );
  446. },
  447. drag: function( event, ui ) {
  448. that._trigger( "drag", event, filteredUi( ui ) );
  449. },
  450. stop: function( event, ui ) {
  451. var left = ui.offset.left - that.document.scrollLeft(),
  452. top = ui.offset.top - that.document.scrollTop();
  453. options.position = {
  454. my: "left top",
  455. at: "left" + (left >= 0 ? "+" : "") + left + " " +
  456. "top" + (top >= 0 ? "+" : "") + top,
  457. of: that.window
  458. };
  459. $( this ).removeClass( "ui-dialog-dragging" );
  460. that._unblockFrames();
  461. that._trigger( "dragStop", event, filteredUi( ui ) );
  462. }
  463. });
  464. },
  465. _makeResizable: function() {
  466. var that = this,
  467. options = this.options,
  468. handles = options.resizable,
  469. // .ui-resizable has position: relative defined in the stylesheet
  470. // but dialogs have to use absolute or fixed positioning
  471. position = this.uiDialog.css("position"),
  472. resizeHandles = typeof handles === "string" ?
  473. handles :
  474. "n,e,s,w,se,sw,ne,nw";
  475. function filteredUi( ui ) {
  476. return {
  477. originalPosition: ui.originalPosition,
  478. originalSize: ui.originalSize,
  479. position: ui.position,
  480. size: ui.size
  481. };
  482. }
  483. this.uiDialog.resizable({
  484. cancel: ".ui-dialog-content",
  485. containment: "document",
  486. alsoResize: this.element,
  487. maxWidth: options.maxWidth,
  488. maxHeight: options.maxHeight,
  489. minWidth: options.minWidth,
  490. minHeight: this._minHeight(),
  491. handles: resizeHandles,
  492. start: function( event, ui ) {
  493. $( this ).addClass( "ui-dialog-resizing" );
  494. that._blockFrames();
  495. that._trigger( "resizeStart", event, filteredUi( ui ) );
  496. },
  497. resize: function( event, ui ) {
  498. that._trigger( "resize", event, filteredUi( ui ) );
  499. },
  500. stop: function( event, ui ) {
  501. var offset = that.uiDialog.offset(),
  502. left = offset.left - that.document.scrollLeft(),
  503. top = offset.top - that.document.scrollTop();
  504. options.height = that.uiDialog.height();
  505. options.width = that.uiDialog.width();
  506. options.position = {
  507. my: "left top",
  508. at: "left" + (left >= 0 ? "+" : "") + left + " " +
  509. "top" + (top >= 0 ? "+" : "") + top,
  510. of: that.window
  511. };
  512. $( this ).removeClass( "ui-dialog-resizing" );
  513. that._unblockFrames();
  514. that._trigger( "resizeStop", event, filteredUi( ui ) );
  515. }
  516. })
  517. .css( "position", position );
  518. },
  519. _trackFocus: function() {
  520. this._on( this.widget(), {
  521. focusin: function( event ) {
  522. this._makeFocusTarget();
  523. this._focusedElement = $( event.target );
  524. }
  525. });
  526. },
  527. _makeFocusTarget: function() {
  528. this._untrackInstance();
  529. this._trackingInstances().unshift( this );
  530. },
  531. _untrackInstance: function() {
  532. var instances = this._trackingInstances(),
  533. exists = $.inArray( this, instances );
  534. if ( exists !== -1 ) {
  535. instances.splice( exists, 1 );
  536. }
  537. },
  538. _trackingInstances: function() {
  539. var instances = this.document.data( "ui-dialog-instances" );
  540. if ( !instances ) {
  541. instances = [];
  542. this.document.data( "ui-dialog-instances", instances );
  543. }
  544. return instances;
  545. },
  546. _minHeight: function() {
  547. var options = this.options;
  548. return options.height === "auto" ?
  549. options.minHeight :
  550. Math.min( options.minHeight, options.height );
  551. },
  552. _position: function() {
  553. // Need to show the dialog to get the actual offset in the position plugin
  554. var isVisible = this.uiDialog.is( ":visible" );
  555. if ( !isVisible ) {
  556. this.uiDialog.show();
  557. }
  558. this.uiDialog.position( this.options.position );
  559. if ( !isVisible ) {
  560. this.uiDialog.hide();
  561. }
  562. },
  563. _setOptions: function( options ) {
  564. var that = this,
  565. resize = false,
  566. resizableOptions = {};
  567. $.each( options, function( key, value ) {
  568. that._setOption( key, value );
  569. if ( key in that.sizeRelatedOptions ) {
  570. resize = true;
  571. }
  572. if ( key in that.resizableRelatedOptions ) {
  573. resizableOptions[ key ] = value;
  574. }
  575. });
  576. if ( resize ) {
  577. this._size();
  578. this._position();
  579. }
  580. if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
  581. this.uiDialog.resizable( "option", resizableOptions );
  582. }
  583. },
  584. _setOption: function( key, value ) {
  585. var isDraggable, isResizable,
  586. uiDialog = this.uiDialog;
  587. if ( key === "dialogClass" ) {
  588. uiDialog
  589. .removeClass( this.options.dialogClass )
  590. .addClass( value );
  591. }
  592. if ( key === "disabled" ) {
  593. return;
  594. }
  595. this._super( key, value );
  596. if ( key === "appendTo" ) {
  597. this.uiDialog.appendTo( this._appendTo() );
  598. }
  599. if ( key === "buttons" ) {
  600. this._createButtons();
  601. }
  602. if ( key === "closeText" ) {
  603. this.uiDialogTitlebarClose.button({
  604. // Ensure that we always pass a string
  605. label: "" + value
  606. });
  607. }
  608. if ( key === "draggable" ) {
  609. isDraggable = uiDialog.is( ":data(ui-draggable)" );
  610. if ( isDraggable && !value ) {
  611. uiDialog.draggable( "destroy" );
  612. }
  613. if ( !isDraggable && value ) {
  614. this._makeDraggable();
  615. }
  616. }
  617. if ( key === "position" ) {
  618. this._position();
  619. }
  620. if ( key === "resizable" ) {
  621. // currently resizable, becoming non-resizable
  622. isResizable = uiDialog.is( ":data(ui-resizable)" );
  623. if ( isResizable && !value ) {
  624. uiDialog.resizable( "destroy" );
  625. }
  626. // currently resizable, changing handles
  627. if ( isResizable && typeof value === "string" ) {
  628. uiDialog.resizable( "option", "handles", value );
  629. }
  630. // currently non-resizable, becoming resizable
  631. if ( !isResizable && value !== false ) {
  632. this._makeResizable();
  633. }
  634. }
  635. if ( key === "title" ) {
  636. this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
  637. }
  638. },
  639. _size: function() {
  640. // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
  641. // divs will both have width and height set, so we need to reset them
  642. var nonContentHeight, minContentHeight, maxContentHeight,
  643. options = this.options;
  644. // Reset content sizing
  645. this.element.show().css({
  646. width: "auto",
  647. minHeight: 0,
  648. maxHeight: "none",
  649. height: 0
  650. });
  651. if ( options.minWidth > options.width ) {
  652. options.width = options.minWidth;
  653. }
  654. // reset wrapper sizing
  655. // determine the height of all the non-content elements
  656. nonContentHeight = this.uiDialog.css({
  657. height: "auto",
  658. width: options.width
  659. })
  660. .outerHeight();
  661. minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
  662. maxContentHeight = typeof options.maxHeight === "number" ?
  663. Math.max( 0, options.maxHeight - nonContentHeight ) :
  664. "none";
  665. if ( options.height === "auto" ) {
  666. this.element.css({
  667. minHeight: minContentHeight,
  668. maxHeight: maxContentHeight,
  669. height: "auto"
  670. });
  671. } else {
  672. this.element.height( Math.max( 0, options.height - nonContentHeight ) );
  673. }
  674. if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
  675. this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
  676. }
  677. },
  678. _blockFrames: function() {
  679. this.iframeBlocks = this.document.find( "iframe" ).map(function() {
  680. var iframe = $( this );
  681. return $( "<div>" )
  682. .css({
  683. position: "absolute",
  684. width: iframe.outerWidth(),
  685. height: iframe.outerHeight()
  686. })
  687. .appendTo( iframe.parent() )
  688. .offset( iframe.offset() )[0];
  689. });
  690. },
  691. _unblockFrames: function() {
  692. if ( this.iframeBlocks ) {
  693. this.iframeBlocks.remove();
  694. delete this.iframeBlocks;
  695. }
  696. },
  697. _allowInteraction: function( event ) {
  698. if ( $( event.target ).closest( ".ui-dialog" ).length ) {
  699. return true;
  700. }
  701. // TODO: Remove hack when datepicker implements
  702. // the .ui-front logic (#8989)
  703. return !!$( event.target ).closest( ".ui-datepicker" ).length;
  704. },
  705. _createOverlay: function() {
  706. if ( !this.options.modal ) {
  707. return;
  708. }
  709. // We use a delay in case the overlay is created from an
  710. // event that we're going to be cancelling (#2804)
  711. var isOpening = true;
  712. this._delay(function() {
  713. isOpening = false;
  714. });
  715. if ( !this.document.data( "ui-dialog-overlays" ) ) {
  716. // Prevent use of anchors and inputs
  717. // Using _on() for an event handler shared across many instances is
  718. // safe because the dialogs stack and must be closed in reverse order
  719. this._on( this.document, {
  720. focusin: function( event ) {
  721. if ( isOpening ) {
  722. return;
  723. }
  724. if ( !this._allowInteraction( event ) ) {
  725. event.preventDefault();
  726. this._trackingInstances()[ 0 ]._focusTabbable();
  727. }
  728. }
  729. });
  730. }
  731. this.overlay = $( "<div>" )
  732. .addClass( "ui-widget-overlay ui-front" )
  733. .appendTo( this._appendTo() );
  734. this._on( this.overlay, {
  735. mousedown: "_keepFocus"
  736. });
  737. this.document.data( "ui-dialog-overlays",
  738. (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
  739. },
  740. _destroyOverlay: function() {
  741. if ( !this.options.modal ) {
  742. return;
  743. }
  744. if ( this.overlay ) {
  745. var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
  746. if ( !overlays ) {
  747. this.document
  748. .unbind( "focusin" )
  749. .removeData( "ui-dialog-overlays" );
  750. } else {
  751. this.document.data( "ui-dialog-overlays", overlays );
  752. }
  753. this.overlay.remove();
  754. this.overlay = null;
  755. }
  756. }
  757. });
  758. }));