modal.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. $(function () {
  2. 'use strict';
  3. QUnit.module('modal plugin')
  4. QUnit.test('should be defined on jquery object', function (assert) {
  5. assert.expect(1)
  6. assert.ok($(document.body).modal, 'modal method is defined')
  7. })
  8. QUnit.module('modal', {
  9. beforeEach: function () {
  10. // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
  11. $.fn.bootstrapModal = $.fn.modal.noConflict()
  12. },
  13. afterEach: function () {
  14. $.fn.modal = $.fn.bootstrapModal
  15. delete $.fn.bootstrapModal
  16. $('#qunit-fixture').html('')
  17. }
  18. })
  19. QUnit.test('should provide no conflict', function (assert) {
  20. assert.expect(1)
  21. assert.strictEqual($.fn.modal, undefined, 'modal was set back to undefined (orig value)')
  22. })
  23. QUnit.test('should return jquery collection containing the element', function (assert) {
  24. assert.expect(2)
  25. var $el = $('<div id="modal-test"/>').appendTo('#qunit-fixture')
  26. var $modal = $el.bootstrapModal()
  27. assert.ok($modal instanceof $, 'returns jquery collection')
  28. assert.strictEqual($modal[0], $el[0], 'collection contains element')
  29. })
  30. QUnit.test('should expose defaults var for settings', function (assert) {
  31. assert.expect(1)
  32. assert.ok($.fn.bootstrapModal.Constructor.DEFAULTS, 'default object exposed')
  33. })
  34. QUnit.test('should insert into dom when show method is called', function (assert) {
  35. assert.expect(1)
  36. var done = assert.async()
  37. $('<div id="modal-test"/>')
  38. .appendTo('#qunit-fixture')
  39. .on('shown.bs.modal', function () {
  40. assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
  41. done()
  42. })
  43. .bootstrapModal('show')
  44. })
  45. QUnit.test('should fire show event', function (assert) {
  46. assert.expect(1)
  47. var done = assert.async()
  48. $('<div id="modal-test"/>')
  49. .appendTo('#qunit-fixture')
  50. .on('show.bs.modal', function () {
  51. assert.ok(true, 'show event fired')
  52. done()
  53. })
  54. .bootstrapModal('show')
  55. })
  56. QUnit.test('should not fire shown when show was prevented', function (assert) {
  57. assert.expect(1)
  58. var done = assert.async()
  59. $('<div id="modal-test"/>')
  60. .appendTo('#qunit-fixture')
  61. .on('show.bs.modal', function (e) {
  62. e.preventDefault()
  63. assert.ok(true, 'show event fired')
  64. done()
  65. })
  66. .on('shown.bs.modal', function () {
  67. assert.ok(false, 'shown event fired')
  68. })
  69. .bootstrapModal('show')
  70. })
  71. QUnit.test('should hide modal when hide is called', function (assert) {
  72. assert.expect(3)
  73. var done = assert.async()
  74. $('<div id="modal-test"/>')
  75. .appendTo('#qunit-fixture')
  76. .on('shown.bs.modal', function () {
  77. assert.ok($('#modal-test').is(':visible'), 'modal visible')
  78. assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
  79. $(this).bootstrapModal('hide')
  80. })
  81. .on('hidden.bs.modal', function () {
  82. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  83. done()
  84. })
  85. .bootstrapModal('show')
  86. })
  87. QUnit.test('should toggle when toggle is called', function (assert) {
  88. assert.expect(3)
  89. var done = assert.async()
  90. $('<div id="modal-test"/>')
  91. .appendTo('#qunit-fixture')
  92. .on('shown.bs.modal', function () {
  93. assert.ok($('#modal-test').is(':visible'), 'modal visible')
  94. assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
  95. $(this).bootstrapModal('toggle')
  96. })
  97. .on('hidden.bs.modal', function () {
  98. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  99. done()
  100. })
  101. .bootstrapModal('toggle')
  102. })
  103. QUnit.test('should remove from dom when click [data-dismiss="modal"]', function (assert) {
  104. assert.expect(3)
  105. var done = assert.async()
  106. $('<div id="modal-test"><span class="close" data-dismiss="modal"/></div>')
  107. .appendTo('#qunit-fixture')
  108. .on('shown.bs.modal', function () {
  109. assert.ok($('#modal-test').is(':visible'), 'modal visible')
  110. assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
  111. $(this).find('.close').trigger('click')
  112. })
  113. .on('hidden.bs.modal', function () {
  114. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  115. done()
  116. })
  117. .bootstrapModal('toggle')
  118. })
  119. QUnit.test('should allow modal close with "backdrop:false"', function (assert) {
  120. assert.expect(2)
  121. var done = assert.async()
  122. $('<div id="modal-test" data-backdrop="false"/>')
  123. .appendTo('#qunit-fixture')
  124. .on('shown.bs.modal', function () {
  125. assert.ok($('#modal-test').is(':visible'), 'modal visible')
  126. $(this).bootstrapModal('hide')
  127. })
  128. .on('hidden.bs.modal', function () {
  129. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  130. done()
  131. })
  132. .bootstrapModal('show')
  133. })
  134. QUnit.test('should close modal when clicking outside of modal-content', function (assert) {
  135. assert.expect(3)
  136. var done = assert.async()
  137. $('<div id="modal-test"><div class="contents"/></div>')
  138. .appendTo('#qunit-fixture')
  139. .on('shown.bs.modal', function () {
  140. assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
  141. $('.contents').trigger('click')
  142. assert.ok($('#modal-test').is(':visible'), 'modal visible')
  143. $('#modal-test').trigger('click')
  144. })
  145. .on('hidden.bs.modal', function () {
  146. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  147. done()
  148. })
  149. .bootstrapModal('show')
  150. })
  151. QUnit.test('should close modal when escape key is pressed via keydown', function (assert) {
  152. assert.expect(3)
  153. var done = assert.async()
  154. var $div = $('<div id="modal-test"/>').appendTo('#qunit-fixture')
  155. $div
  156. .on('shown.bs.modal', function () {
  157. assert.ok($('#modal-test').length, 'modal inserted into dom')
  158. assert.ok($('#modal-test').is(':visible'), 'modal visible')
  159. $div.trigger($.Event('keydown', { which: 27 }))
  160. setTimeout(function () {
  161. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  162. $div.remove()
  163. done()
  164. }, 0)
  165. })
  166. .bootstrapModal('show')
  167. })
  168. QUnit.test('should not close modal when escape key is pressed via keyup', function (assert) {
  169. assert.expect(3)
  170. var done = assert.async()
  171. var $div = $('<div id="modal-test"/>').appendTo('#qunit-fixture')
  172. $div
  173. .on('shown.bs.modal', function () {
  174. assert.ok($('#modal-test').length, 'modal inserted into dom')
  175. assert.ok($('#modal-test').is(':visible'), 'modal visible')
  176. $div.trigger($.Event('keyup', { which: 27 }))
  177. setTimeout(function () {
  178. assert.ok($div.is(':visible'), 'modal still visible')
  179. $div.remove()
  180. done()
  181. }, 0)
  182. })
  183. .bootstrapModal('show')
  184. })
  185. QUnit.test('should trigger hide event once when clicking outside of modal-content', function (assert) {
  186. assert.expect(1)
  187. var done = assert.async()
  188. var triggered
  189. $('<div id="modal-test"><div class="contents"/></div>')
  190. .appendTo('#qunit-fixture')
  191. .on('shown.bs.modal', function () {
  192. triggered = 0
  193. $('#modal-test').trigger('click')
  194. })
  195. .on('hide.bs.modal', function () {
  196. triggered += 1
  197. assert.strictEqual(triggered, 1, 'modal hide triggered once')
  198. done()
  199. })
  200. .bootstrapModal('show')
  201. })
  202. QUnit.test('should close reopened modal with [data-dismiss="modal"] click', function (assert) {
  203. assert.expect(2)
  204. var done = assert.async()
  205. $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div></div>')
  206. .appendTo('#qunit-fixture')
  207. .one('shown.bs.modal', function () {
  208. $('#close').trigger('click')
  209. })
  210. .one('hidden.bs.modal', function () {
  211. // after one open-close cycle
  212. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  213. $(this)
  214. .one('shown.bs.modal', function () {
  215. $('#close').trigger('click')
  216. })
  217. .one('hidden.bs.modal', function () {
  218. assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
  219. done()
  220. })
  221. .bootstrapModal('show')
  222. })
  223. .bootstrapModal('show')
  224. })
  225. QUnit.test('should restore focus to toggling element when modal is hidden after having been opened via data-api', function (assert) {
  226. assert.expect(1)
  227. var done = assert.async()
  228. var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')
  229. $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div></div>')
  230. .appendTo('#qunit-fixture')
  231. .on('hidden.bs.modal', function () {
  232. setTimeout(function () {
  233. assert.ok($(document.activeElement).is($toggleBtn), 'toggling element is once again focused')
  234. done()
  235. }, 0)
  236. })
  237. .on('shown.bs.modal', function () {
  238. $('#close').trigger('click')
  239. })
  240. .appendTo('#qunit-fixture')
  241. $toggleBtn.trigger('click')
  242. })
  243. QUnit.test('should not restore focus to toggling element if the associated show event gets prevented', function (assert) {
  244. assert.expect(1)
  245. var done = assert.async()
  246. var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')
  247. var $otherBtn = $('<button id="other-btn"/>').appendTo('#qunit-fixture')
  248. $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div>')
  249. .appendTo('#qunit-fixture')
  250. .one('show.bs.modal', function (e) {
  251. e.preventDefault()
  252. $otherBtn.trigger('focus')
  253. setTimeout($.proxy(function () {
  254. $(this).bootstrapModal('show')
  255. }, this), 0)
  256. })
  257. .on('hidden.bs.modal', function () {
  258. setTimeout(function () {
  259. assert.ok($(document.activeElement).is($otherBtn), 'focus returned to toggling element')
  260. done()
  261. }, 0)
  262. })
  263. .on('shown.bs.modal', function () {
  264. $('#close').trigger('click')
  265. })
  266. .appendTo('#qunit-fixture')
  267. $toggleBtn.trigger('click')
  268. })
  269. QUnit.test('should restore inline body padding after closing', function (assert) {
  270. assert.expect(2)
  271. var done = assert.async()
  272. var originalBodyPad = 0
  273. var $body = $(document.body)
  274. $body.css('padding-right', originalBodyPad)
  275. $('<div id="modal-test"/>')
  276. .on('hidden.bs.modal', function () {
  277. var currentBodyPad = parseInt($body.css('padding-right'), 10)
  278. assert.notStrictEqual($body.attr('style'), '', 'body has non-empty style attribute')
  279. assert.strictEqual(currentBodyPad, originalBodyPad, 'original body padding was not changed')
  280. $body.removeAttr('style')
  281. done()
  282. })
  283. .on('shown.bs.modal', function () {
  284. $(this).bootstrapModal('hide')
  285. })
  286. .bootstrapModal('show')
  287. })
  288. QUnit.test('should ignore values set via CSS when trying to restore body padding after closing', function (assert) {
  289. assert.expect(1)
  290. var done = assert.async()
  291. var $body = $(document.body)
  292. var $style = $('<style>body { padding-right: 42px; }</style>').appendTo('head')
  293. $('<div id="modal-test"/>')
  294. .on('hidden.bs.modal', function () {
  295. assert.ok(!$body.attr('style'), 'body does not have inline padding set')
  296. $style.remove()
  297. done()
  298. })
  299. .on('shown.bs.modal', function () {
  300. $(this).bootstrapModal('hide')
  301. })
  302. .bootstrapModal('show')
  303. })
  304. QUnit.test('should ignore other inline styles when trying to restore body padding after closing', function (assert) {
  305. assert.expect(2)
  306. var done = assert.async()
  307. var $body = $(document.body)
  308. var $style = $('<style>body { padding-right: 42px; }</style>').appendTo('head')
  309. $body.css('color', 'red')
  310. $('<div id="modal-test"/>')
  311. .on('hidden.bs.modal', function () {
  312. assert.strictEqual($body[0].style.paddingRight, '', 'body does not have inline padding set')
  313. assert.strictEqual($body[0].style.color, 'red', 'body still has other inline styles set')
  314. $body.removeAttr('style')
  315. $style.remove()
  316. done()
  317. })
  318. .on('shown.bs.modal', function () {
  319. $(this).bootstrapModal('hide')
  320. })
  321. .bootstrapModal('show')
  322. })
  323. QUnit.test('should properly restore non-pixel inline body padding after closing', function (assert) {
  324. assert.expect(1)
  325. var done = assert.async()
  326. var $body = $(document.body)
  327. $body.css('padding-right', '5%')
  328. $('<div id="modal-test"/>')
  329. .on('hidden.bs.modal', function () {
  330. assert.strictEqual($body[0].style.paddingRight, '5%', 'body does not have inline padding set')
  331. $body.removeAttr('style')
  332. done()
  333. })
  334. .on('shown.bs.modal', function () {
  335. $(this).bootstrapModal('hide')
  336. })
  337. .bootstrapModal('show')
  338. })
  339. QUnit.test('should add padding-right of scrollbar width to .navbar-fixed-top and .navbar-fixed-bottom before open', function (assert) {
  340. assert.expect(2)
  341. var Modal = $.fn.bootstrapModal.Constructor
  342. var done = assert.async()
  343. var $body = $(document.body)
  344. var scrollbarWidth
  345. // simulate overflow scroll
  346. $body.css({ height: '2000px' })
  347. var $fixedTop = $('<nav class="navbar navbar-fixed-top" />').appendTo($body)
  348. var $fixedBottom = $('<nav class="navbar navbar-fixed-bottom" />').appendTo($body)
  349. // patch setScrollbar function to get scrollbar width
  350. var setScrollbar = Modal.prototype.setScrollbar
  351. Modal.prototype.setScrollbar = function () {
  352. setScrollbar.call(this)
  353. scrollbarWidth = this.scrollbarWidth + 'px'
  354. }
  355. $('<div id="modal-test"/>')
  356. .on('hidden.bs.modal', function () {
  357. $fixedTop.remove()
  358. $fixedBottom.remove()
  359. $body.removeAttr('style')
  360. // restore original setScrollbar
  361. Modal.prototype.setScrollbar = setScrollbar
  362. done()
  363. })
  364. .on('shown.bs.modal', function () {
  365. var fixedTopPaddingRight = $fixedTop.css('padding-right')
  366. var fixedBottomPaddingRight = $fixedBottom.css('padding-right')
  367. assert.strictEqual(scrollbarWidth, fixedTopPaddingRight,
  368. '.navbar-fixed-top has padding-right (' + fixedTopPaddingRight + ') equal to scrollbar width (' + scrollbarWidth + ')')
  369. assert.strictEqual(scrollbarWidth, fixedBottomPaddingRight,
  370. '.navbar-fixed-bottom has padding-right (' + fixedBottomPaddingRight + ') equal to scrollbar width (' + scrollbarWidth + ')')
  371. $(this).bootstrapModal('hide')
  372. })
  373. .bootstrapModal('show')
  374. })
  375. QUnit.test('should restore inline padding-right for .navbar-fixed-top and .navbar-fixed-bottom after close', function (assert) {
  376. assert.expect(2)
  377. var done = assert.async()
  378. var $body = $(document.body)
  379. var $styleshhet = $('<link rel="stylesheet" href="../../dist/css/bootstrap.css" />').appendTo(document.head)
  380. var $fixedTop = $('<nav class="navbar navbar-fixed-top" style="padding-right: 10px;" />').appendTo($body)
  381. var $fixedBottom = $('<nav class="navbar navbar-fixed-bottom" style="padding-right: 5%;" />').appendTo($body)
  382. // simulate overflow scroll
  383. $body.css({ height: '2000px' })
  384. $('<div id="modal-test"/>')
  385. .on('hidden.bs.modal', function () {
  386. assert.strictEqual($fixedTop.css('padding-right'), '10px',
  387. '.navbar-fixed-top has inline padding-right restored')
  388. assert.strictEqual($fixedBottom[0].style.paddingRight, '5%',
  389. '.navbar-fixed-bottom has right padding-right restored')
  390. $fixedTop.remove()
  391. $fixedBottom.remove()
  392. $body.removeAttr('style')
  393. $styleshhet.remove()
  394. done()
  395. })
  396. .on('shown.bs.modal', function () {
  397. $(this).bootstrapModal('hide')
  398. })
  399. .bootstrapModal('show')
  400. })
  401. })