1
0

dialog.js 21 KB

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