inkstream 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +21 -0
  3. data/README.md +93 -0
  4. data/_config.yml +122 -0
  5. data/_includes/button.html +4 -0
  6. data/_includes/icon.html +1 -0
  7. data/_includes/nav-default.html +23 -0
  8. data/_includes/nav-header.html +25 -0
  9. data/_includes/post-list.html +59 -0
  10. data/_includes/post-meta.html +0 -0
  11. data/_includes/post-pagination.html +29 -0
  12. data/_includes/promo-section.html +12 -0
  13. data/_includes/site-before-end.html +1 -0
  14. data/_includes/site-before-start.html +1 -0
  15. data/_includes/site-favicons.html +7 -0
  16. data/_includes/site-fonts.html +13 -0
  17. data/_includes/site-footer-default.html +17 -0
  18. data/_includes/site-footer.html +12 -0
  19. data/_includes/site-header.html +46 -0
  20. data/_includes/site-styles.html +6 -0
  21. data/_layouts/blog.html +24 -0
  22. data/_layouts/default.html +62 -0
  23. data/_layouts/page.html +35 -0
  24. data/_layouts/post.html +201 -0
  25. data/assets/css/styles.css +11167 -0
  26. data/assets/images/about-me.jpg +0 -0
  27. data/assets/images/blog/blog-post-banner.jpg +0 -0
  28. data/assets/images/blog/blog-post-thumb-1.jpg +0 -0
  29. data/assets/images/blog/blog-post-thumb-10.jpg +0 -0
  30. data/assets/images/blog/blog-post-thumb-11.jpg +0 -0
  31. data/assets/images/blog/blog-post-thumb-12.jpg +0 -0
  32. data/assets/images/blog/blog-post-thumb-2.jpg +0 -0
  33. data/assets/images/blog/blog-post-thumb-3.jpg +0 -0
  34. data/assets/images/blog/blog-post-thumb-4.jpg +0 -0
  35. data/assets/images/blog/blog-post-thumb-5.jpg +0 -0
  36. data/assets/images/blog/blog-post-thumb-6.jpg +0 -0
  37. data/assets/images/blog/blog-post-thumb-7.jpg +0 -0
  38. data/assets/images/blog/blog-post-thumb-8.jpg +0 -0
  39. data/assets/images/blog/blog-post-thumb-9.jpg +0 -0
  40. data/assets/images/posts/default-post-img.jpg +0 -0
  41. data/assets/images/posts/text-syntax.jpg +0 -0
  42. data/assets/images/posts/welcome.jpg +0 -0
  43. data/assets/images/profile.png +0 -0
  44. data/assets/images/promo-banner.jpg +0 -0
  45. data/assets/js/blog.js +9 -0
  46. data/assets/js/demo/style-switcher.js +45 -0
  47. data/assets/plugins/bootstrap/js/bootstrap.min.js +7 -0
  48. data/assets/plugins/jquery-3.3.1.min.js +2 -0
  49. data/assets/plugins/popper.min.js +5 -0
  50. data/assets/scss/bootstrap/js/dist/alert.js +199 -0
  51. data/assets/scss/bootstrap/js/dist/alert.js.map +1 -0
  52. data/assets/scss/bootstrap/js/dist/button.js +187 -0
  53. data/assets/scss/bootstrap/js/dist/button.js.map +1 -0
  54. data/assets/scss/bootstrap/js/dist/carousel.js +668 -0
  55. data/assets/scss/bootstrap/js/dist/carousel.js.map +1 -0
  56. data/assets/scss/bootstrap/js/dist/collapse.js +428 -0
  57. data/assets/scss/bootstrap/js/dist/collapse.js.map +1 -0
  58. data/assets/scss/bootstrap/js/dist/dropdown.js +595 -0
  59. data/assets/scss/bootstrap/js/dist/dropdown.js.map +1 -0
  60. data/assets/scss/bootstrap/js/dist/index.js +23 -0
  61. data/assets/scss/bootstrap/js/dist/index.js.map +1 -0
  62. data/assets/scss/bootstrap/js/dist/modal.js +650 -0
  63. data/assets/scss/bootstrap/js/dist/modal.js.map +1 -0
  64. data/assets/scss/bootstrap/js/dist/popover.js +261 -0
  65. data/assets/scss/bootstrap/js/dist/popover.js.map +1 -0
  66. data/assets/scss/bootstrap/js/dist/scrollspy.js +375 -0
  67. data/assets/scss/bootstrap/js/dist/scrollspy.js.map +1 -0
  68. data/assets/scss/bootstrap/js/dist/tab.js +269 -0
  69. data/assets/scss/bootstrap/js/dist/tab.js.map +1 -0
  70. data/assets/scss/bootstrap/js/dist/toast.js +283 -0
  71. data/assets/scss/bootstrap/js/dist/toast.js.map +1 -0
  72. data/assets/scss/bootstrap/js/dist/tooltip.js +760 -0
  73. data/assets/scss/bootstrap/js/dist/tooltip.js.map +1 -0
  74. data/assets/scss/bootstrap/js/dist/util.js +172 -0
  75. data/assets/scss/bootstrap/js/dist/util.js.map +1 -0
  76. data/assets/scss/bootstrap/js/src/alert.js +179 -0
  77. data/assets/scss/bootstrap/js/src/button.js +171 -0
  78. data/assets/scss/bootstrap/js/src/carousel.js +606 -0
  79. data/assets/scss/bootstrap/js/src/collapse.js +402 -0
  80. data/assets/scss/bootstrap/js/src/dropdown.js +545 -0
  81. data/assets/scss/bootstrap/js/src/index.js +52 -0
  82. data/assets/scss/bootstrap/js/src/modal.js +594 -0
  83. data/assets/scss/bootstrap/js/src/popover.js +184 -0
  84. data/assets/scss/bootstrap/js/src/scrollspy.js +326 -0
  85. data/assets/scss/bootstrap/js/src/tab.js +260 -0
  86. data/assets/scss/bootstrap/js/src/toast.js +227 -0
  87. data/assets/scss/bootstrap/js/src/tooltip.js +752 -0
  88. data/assets/scss/bootstrap/js/src/util.js +177 -0
  89. data/assets/scss/bootstrap/js/tests/README.md +69 -0
  90. data/assets/scss/bootstrap/js/tests/browsers.js +82 -0
  91. data/assets/scss/bootstrap/js/tests/index.html +133 -0
  92. data/assets/scss/bootstrap/js/tests/integration/bundle.js +8 -0
  93. data/assets/scss/bootstrap/js/tests/integration/index.html +66 -0
  94. data/assets/scss/bootstrap/js/tests/integration/rollup.bundle.js +20 -0
  95. data/assets/scss/bootstrap/js/tests/karma.conf.js +143 -0
  96. data/assets/scss/bootstrap/js/tests/unit/.eslintrc.json +40 -0
  97. data/assets/scss/bootstrap/js/tests/unit/alert.js +123 -0
  98. data/assets/scss/bootstrap/js/tests/unit/button.js +222 -0
  99. data/assets/scss/bootstrap/js/tests/unit/carousel.js +1333 -0
  100. data/assets/scss/bootstrap/js/tests/unit/collapse.js +892 -0
  101. data/assets/scss/bootstrap/js/tests/unit/dropdown.js +1419 -0
  102. data/assets/scss/bootstrap/js/tests/unit/modal.js +815 -0
  103. data/assets/scss/bootstrap/js/tests/unit/popover.js +471 -0
  104. data/assets/scss/bootstrap/js/tests/unit/scrollspy.js +728 -0
  105. data/assets/scss/bootstrap/js/tests/unit/tab.js +518 -0
  106. data/assets/scss/bootstrap/js/tests/unit/toast.js +259 -0
  107. data/assets/scss/bootstrap/js/tests/unit/tooltip.js +1109 -0
  108. data/assets/scss/bootstrap/js/tests/unit/util.js +163 -0
  109. data/assets/scss/bootstrap/js/tests/visual/alert.html +58 -0
  110. data/assets/scss/bootstrap/js/tests/visual/button.html +51 -0
  111. data/assets/scss/bootstrap/js/tests/visual/carousel.html +66 -0
  112. data/assets/scss/bootstrap/js/tests/visual/collapse.html +78 -0
  113. data/assets/scss/bootstrap/js/tests/visual/dropdown.html +212 -0
  114. data/assets/scss/bootstrap/js/tests/visual/modal.html +268 -0
  115. data/assets/scss/bootstrap/js/tests/visual/popover.html +46 -0
  116. data/assets/scss/bootstrap/js/tests/visual/scrollspy.html +95 -0
  117. data/assets/scss/bootstrap/js/tests/visual/tab.html +234 -0
  118. data/assets/scss/bootstrap/js/tests/visual/toast.html +72 -0
  119. data/assets/scss/bootstrap/js/tests/visual/tooltip.html +106 -0
  120. data/assets/scss/bootstrap/scss/_alert.scss +51 -0
  121. data/assets/scss/bootstrap/scss/_badge.scss +54 -0
  122. data/assets/scss/bootstrap/scss/_breadcrumb.scss +41 -0
  123. data/assets/scss/bootstrap/scss/_button-group.scss +163 -0
  124. data/assets/scss/bootstrap/scss/_buttons.scss +137 -0
  125. data/assets/scss/bootstrap/scss/_card.scss +289 -0
  126. data/assets/scss/bootstrap/scss/_carousel.scss +197 -0
  127. data/assets/scss/bootstrap/scss/_close.scss +41 -0
  128. data/assets/scss/bootstrap/scss/_code.scss +48 -0
  129. data/assets/scss/bootstrap/scss/_custom-forms.scss +507 -0
  130. data/assets/scss/bootstrap/scss/_dropdown.scss +191 -0
  131. data/assets/scss/bootstrap/scss/_forms.scss +330 -0
  132. data/assets/scss/bootstrap/scss/_functions.scss +86 -0
  133. data/assets/scss/bootstrap/scss/_grid.scss +52 -0
  134. data/assets/scss/bootstrap/scss/_images.scss +42 -0
  135. data/assets/scss/bootstrap/scss/_input-group.scss +193 -0
  136. data/assets/scss/bootstrap/scss/_jumbotron.scss +17 -0
  137. data/assets/scss/bootstrap/scss/_list-group.scss +149 -0
  138. data/assets/scss/bootstrap/scss/_media.scss +8 -0
  139. data/assets/scss/bootstrap/scss/_mixins.scss +47 -0
  140. data/assets/scss/bootstrap/scss/_modal.scss +229 -0
  141. data/assets/scss/bootstrap/scss/_nav.scss +120 -0
  142. data/assets/scss/bootstrap/scss/_navbar.scss +294 -0
  143. data/assets/scss/bootstrap/scss/_pagination.scss +73 -0
  144. data/assets/scss/bootstrap/scss/_popover.scss +171 -0
  145. data/assets/scss/bootstrap/scss/_print.scss +141 -0
  146. data/assets/scss/bootstrap/scss/_progress.scss +43 -0
  147. data/assets/scss/bootstrap/scss/_reboot.scss +483 -0
  148. data/assets/scss/bootstrap/scss/_root.scss +19 -0
  149. data/assets/scss/bootstrap/scss/_spinners.scss +55 -0
  150. data/assets/scss/bootstrap/scss/_tables.scss +185 -0
  151. data/assets/scss/bootstrap/scss/_toasts.scss +44 -0
  152. data/assets/scss/bootstrap/scss/_tooltip.scss +115 -0
  153. data/assets/scss/bootstrap/scss/_transitions.scss +20 -0
  154. data/assets/scss/bootstrap/scss/_type.scss +125 -0
  155. data/assets/scss/bootstrap/scss/_utilities.scss +17 -0
  156. data/assets/scss/bootstrap/scss/_variables.scss +1123 -0
  157. data/assets/scss/bootstrap/scss/bootstrap-grid.scss +29 -0
  158. data/assets/scss/bootstrap/scss/bootstrap-reboot.scss +12 -0
  159. data/assets/scss/bootstrap/scss/bootstrap.scss +44 -0
  160. data/assets/scss/bootstrap/scss/mixins/_alert.scss +13 -0
  161. data/assets/scss/bootstrap/scss/mixins/_background-variant.scss +21 -0
  162. data/assets/scss/bootstrap/scss/mixins/_badge.scss +17 -0
  163. data/assets/scss/bootstrap/scss/mixins/_border-radius.scss +63 -0
  164. data/assets/scss/bootstrap/scss/mixins/_box-shadow.scss +20 -0
  165. data/assets/scss/bootstrap/scss/mixins/_breakpoints.scss +123 -0
  166. data/assets/scss/bootstrap/scss/mixins/_buttons.scss +107 -0
  167. data/assets/scss/bootstrap/scss/mixins/_caret.scss +62 -0
  168. data/assets/scss/bootstrap/scss/mixins/_clearfix.scss +7 -0
  169. data/assets/scss/bootstrap/scss/mixins/_deprecate.scss +10 -0
  170. data/assets/scss/bootstrap/scss/mixins/_float.scss +14 -0
  171. data/assets/scss/bootstrap/scss/mixins/_forms.scss +192 -0
  172. data/assets/scss/bootstrap/scss/mixins/_gradients.scss +45 -0
  173. data/assets/scss/bootstrap/scss/mixins/_grid-framework.scss +66 -0
  174. data/assets/scss/bootstrap/scss/mixins/_grid.scss +51 -0
  175. data/assets/scss/bootstrap/scss/mixins/_hover.scss +37 -0
  176. data/assets/scss/bootstrap/scss/mixins/_image.scss +36 -0
  177. data/assets/scss/bootstrap/scss/mixins/_list-group.scss +21 -0
  178. data/assets/scss/bootstrap/scss/mixins/_lists.scss +7 -0
  179. data/assets/scss/bootstrap/scss/mixins/_nav-divider.scss +10 -0
  180. data/assets/scss/bootstrap/scss/mixins/_pagination.scss +22 -0
  181. data/assets/scss/bootstrap/scss/mixins/_reset-text.scss +17 -0
  182. data/assets/scss/bootstrap/scss/mixins/_resize.scss +6 -0
  183. data/assets/scss/bootstrap/scss/mixins/_screen-reader.scss +33 -0
  184. data/assets/scss/bootstrap/scss/mixins/_size.scss +7 -0
  185. data/assets/scss/bootstrap/scss/mixins/_table-row.scss +39 -0
  186. data/assets/scss/bootstrap/scss/mixins/_text-emphasis.scss +16 -0
  187. data/assets/scss/bootstrap/scss/mixins/_text-hide.scss +11 -0
  188. data/assets/scss/bootstrap/scss/mixins/_text-truncate.scss +8 -0
  189. data/assets/scss/bootstrap/scss/mixins/_transition.scss +16 -0
  190. data/assets/scss/bootstrap/scss/mixins/_visibility.scss +8 -0
  191. data/assets/scss/bootstrap/scss/utilities/_align.scss +8 -0
  192. data/assets/scss/bootstrap/scss/utilities/_background.scss +19 -0
  193. data/assets/scss/bootstrap/scss/utilities/_borders.scss +75 -0
  194. data/assets/scss/bootstrap/scss/utilities/_clearfix.scss +3 -0
  195. data/assets/scss/bootstrap/scss/utilities/_display.scss +26 -0
  196. data/assets/scss/bootstrap/scss/utilities/_embed.scss +39 -0
  197. data/assets/scss/bootstrap/scss/utilities/_flex.scss +51 -0
  198. data/assets/scss/bootstrap/scss/utilities/_float.scss +11 -0
  199. data/assets/scss/bootstrap/scss/utilities/_overflow.scss +5 -0
  200. data/assets/scss/bootstrap/scss/utilities/_position.scss +32 -0
  201. data/assets/scss/bootstrap/scss/utilities/_screenreaders.scss +11 -0
  202. data/assets/scss/bootstrap/scss/utilities/_shadows.scss +6 -0
  203. data/assets/scss/bootstrap/scss/utilities/_sizing.scss +20 -0
  204. data/assets/scss/bootstrap/scss/utilities/_spacing.scss +73 -0
  205. data/assets/scss/bootstrap/scss/utilities/_stretched-link.scss +19 -0
  206. data/assets/scss/bootstrap/scss/utilities/_text.scss +72 -0
  207. data/assets/scss/bootstrap/scss/utilities/_visibility.scss +13 -0
  208. data/assets/scss/bootstrap/scss/vendor/_rfs.scss +212 -0
  209. data/assets/scss/theme/_about.scss +28 -0
  210. data/assets/scss/theme/_base.scss +207 -0
  211. data/assets/scss/theme/_blog.scss +140 -0
  212. data/assets/scss/theme/_demo.scss +153 -0
  213. data/assets/scss/theme/_mixins.scss +34 -0
  214. data/assets/scss/theme/_responsive.scss +88 -0
  215. data/assets/scss/theme/styles.scss +14 -0
  216. data/assets/scss/theme-8.scss +41 -0
  217. data/assets/styles.scss +6 -0
  218. metadata +219 -3
@@ -0,0 +1,815 @@
1
+ $(function () {
2
+ 'use strict'
3
+
4
+ window.Util = typeof bootstrap !== 'undefined' ? bootstrap.Util : Util
5
+
6
+ QUnit.module('modal plugin')
7
+
8
+ QUnit.test('should be defined on jquery object', function (assert) {
9
+ assert.expect(1)
10
+ assert.ok($(document.body).modal, 'modal method is defined')
11
+ })
12
+
13
+ QUnit.module('modal', {
14
+ before: function () {
15
+ // Enable the scrollbar measurer
16
+ $('<style type="text/css"> .modal-scrollbar-measure { position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll; } </style>').appendTo('head')
17
+ // Function to calculate the scrollbar width which is then compared to the padding or margin changes
18
+ $.fn.getScrollbarWidth = $.fn.modal.Constructor.prototype._getScrollbarWidth
19
+
20
+ // Simulate scrollbars
21
+ $('html').css('padding-right', '16px')
22
+ },
23
+ beforeEach: function () {
24
+ // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
25
+ $.fn.bootstrapModal = $.fn.modal.noConflict()
26
+ },
27
+ afterEach: function () {
28
+ $('.modal-backdrop, #modal-test').remove()
29
+ $(document.body).removeClass('modal-open')
30
+ $.fn.modal = $.fn.bootstrapModal
31
+ delete $.fn.bootstrapModal
32
+ $('#qunit-fixture').html('')
33
+ }
34
+ })
35
+
36
+ QUnit.test('should provide no conflict', function (assert) {
37
+ assert.expect(1)
38
+ assert.strictEqual(typeof $.fn.modal, 'undefined', 'modal was set back to undefined (orig value)')
39
+ })
40
+
41
+ QUnit.test('should throw explicit error on undefined method', function (assert) {
42
+ assert.expect(1)
43
+ var $el = $('<div id="modal-test"/>')
44
+ $el.bootstrapModal()
45
+ try {
46
+ $el.bootstrapModal('noMethod')
47
+ } catch (err) {
48
+ assert.strictEqual(err.message, 'No method named "noMethod"')
49
+ }
50
+ })
51
+
52
+ QUnit.test('should return jquery collection containing the element', function (assert) {
53
+ assert.expect(2)
54
+ var $el = $('<div id="modal-test"/>')
55
+ var $modal = $el.bootstrapModal()
56
+ assert.ok($modal instanceof $, 'returns jquery collection')
57
+ assert.strictEqual($modal[0], $el[0], 'collection contains element')
58
+ })
59
+
60
+ QUnit.test('should expose defaults var for settings', function (assert) {
61
+ assert.expect(1)
62
+ assert.ok($.fn.bootstrapModal.Constructor.Default, 'default object exposed')
63
+ })
64
+
65
+ QUnit.test('should insert into dom when show method is called', function (assert) {
66
+ assert.expect(1)
67
+ var done = assert.async()
68
+
69
+ $('<div id="modal-test"/>')
70
+ .on('shown.bs.modal', function () {
71
+ assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
72
+ done()
73
+ })
74
+ .bootstrapModal('show')
75
+ })
76
+
77
+ QUnit.test('should fire show event', function (assert) {
78
+ assert.expect(1)
79
+ var done = assert.async()
80
+
81
+ $('<div id="modal-test"/>')
82
+ .on('show.bs.modal', function () {
83
+ assert.ok(true, 'show event fired')
84
+ done()
85
+ })
86
+ .bootstrapModal('show')
87
+ })
88
+
89
+ QUnit.test('should not fire shown when show was prevented', function (assert) {
90
+ assert.expect(1)
91
+ var done = assert.async()
92
+
93
+ $('<div id="modal-test"/>')
94
+ .on('show.bs.modal', function (e) {
95
+ e.preventDefault()
96
+ assert.ok(true, 'show event fired')
97
+ done()
98
+ })
99
+ .on('shown.bs.modal', function () {
100
+ assert.ok(false, 'shown event fired')
101
+ })
102
+ .bootstrapModal('show')
103
+ })
104
+
105
+ QUnit.test('should hide modal when hide is called', function (assert) {
106
+ assert.expect(3)
107
+ var done = assert.async()
108
+
109
+ $('<div id="modal-test"/>')
110
+ .on('shown.bs.modal', function () {
111
+ assert.ok($('#modal-test').is(':visible'), 'modal visible')
112
+ assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
113
+ $(this).bootstrapModal('hide')
114
+ })
115
+ .on('hidden.bs.modal', function () {
116
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
117
+ done()
118
+ })
119
+ .bootstrapModal('show')
120
+ })
121
+
122
+ QUnit.test('should toggle when toggle is called', function (assert) {
123
+ assert.expect(3)
124
+ var done = assert.async()
125
+
126
+ $('<div id="modal-test"/>')
127
+ .on('shown.bs.modal', function () {
128
+ assert.ok($('#modal-test').is(':visible'), 'modal visible')
129
+ assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
130
+ $(this).bootstrapModal('toggle')
131
+ })
132
+ .on('hidden.bs.modal', function () {
133
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
134
+ done()
135
+ })
136
+ .bootstrapModal('toggle')
137
+ })
138
+
139
+ QUnit.test('should remove from dom when click [data-dismiss="modal"]', function (assert) {
140
+ assert.expect(3)
141
+ var done = assert.async()
142
+
143
+ $('<div id="modal-test"><span class="close" data-dismiss="modal"/></div>')
144
+ .on('shown.bs.modal', function () {
145
+ assert.ok($('#modal-test').is(':visible'), 'modal visible')
146
+ assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
147
+ $(this).find('.close').trigger('click')
148
+ })
149
+ .on('hidden.bs.modal', function () {
150
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
151
+ done()
152
+ })
153
+ .bootstrapModal('toggle')
154
+ })
155
+
156
+ QUnit.test('should allow modal close with "backdrop:false"', function (assert) {
157
+ assert.expect(2)
158
+ var done = assert.async()
159
+
160
+ $('<div id="modal-test" data-backdrop="false"/>')
161
+ .on('shown.bs.modal', function () {
162
+ assert.ok($('#modal-test').is(':visible'), 'modal visible')
163
+ $(this).bootstrapModal('hide')
164
+ })
165
+ .on('hidden.bs.modal', function () {
166
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
167
+ done()
168
+ })
169
+ .bootstrapModal('show')
170
+ })
171
+
172
+ QUnit.test('should close modal when clicking outside of modal-content', function (assert) {
173
+ assert.expect(3)
174
+ var done = assert.async()
175
+
176
+ $('<div id="modal-test"><div class="contents"/></div>')
177
+ .on('shown.bs.modal', function () {
178
+ assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
179
+ $('.contents').trigger('click')
180
+ assert.ok($('#modal-test').is(':visible'), 'modal visible')
181
+ $('#modal-test').trigger('click')
182
+ })
183
+ .on('hidden.bs.modal', function () {
184
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
185
+ done()
186
+ })
187
+ .bootstrapModal('show')
188
+ })
189
+
190
+ QUnit.test('should not close modal when clicking outside of modal-content if data-backdrop="true"', function (assert) {
191
+ assert.expect(1)
192
+ var done = assert.async()
193
+
194
+ $('<div id="modal-test" data-backdrop="false"><div class="contents"/></div>')
195
+ .on('shown.bs.modal', function () {
196
+ $('#modal-test').trigger('click')
197
+ assert.ok($('#modal-test').is(':visible'), 'modal not hidden')
198
+ done()
199
+ })
200
+ .bootstrapModal('show')
201
+ })
202
+
203
+ QUnit.test('should close modal when escape key is pressed via keydown', function (assert) {
204
+ assert.expect(3)
205
+ var done = assert.async()
206
+
207
+ var $div = $('<div id="modal-test"/>')
208
+ $div
209
+ .on('shown.bs.modal', function () {
210
+ assert.ok($('#modal-test').length, 'modal inserted into dom')
211
+ assert.ok($('#modal-test').is(':visible'), 'modal visible')
212
+ $div.trigger($.Event('keydown', {
213
+ which: 27
214
+ }))
215
+
216
+ setTimeout(function () {
217
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
218
+ $div.remove()
219
+ done()
220
+ }, 0)
221
+ })
222
+ .bootstrapModal('show')
223
+ })
224
+
225
+ QUnit.test('should not close modal when escape key is pressed via keyup', function (assert) {
226
+ assert.expect(3)
227
+ var done = assert.async()
228
+
229
+ var $div = $('<div id="modal-test"/>')
230
+ $div
231
+ .on('shown.bs.modal', function () {
232
+ assert.ok($('#modal-test').length, 'modal inserted into dom')
233
+ assert.ok($('#modal-test').is(':visible'), 'modal visible')
234
+ $div.trigger($.Event('keyup', {
235
+ which: 27
236
+ }))
237
+
238
+ setTimeout(function () {
239
+ assert.ok($div.is(':visible'), 'modal still visible')
240
+ $div.remove()
241
+ done()
242
+ }, 0)
243
+ })
244
+ .bootstrapModal('show')
245
+ })
246
+
247
+ QUnit.test('should trigger hide event once when clicking outside of modal-content', function (assert) {
248
+ assert.expect(1)
249
+ var done = assert.async()
250
+
251
+ var triggered
252
+
253
+ $('<div id="modal-test"><div class="contents"/></div>')
254
+ .on('shown.bs.modal', function () {
255
+ triggered = 0
256
+ $('#modal-test').trigger('click')
257
+ })
258
+ .on('hide.bs.modal', function () {
259
+ triggered += 1
260
+ assert.strictEqual(triggered, 1, 'modal hide triggered once')
261
+ done()
262
+ })
263
+ .bootstrapModal('show')
264
+ })
265
+
266
+ QUnit.test('should remove aria-hidden attribute when shown, add it back when hidden', function (assert) {
267
+ assert.expect(3)
268
+ var done = assert.async()
269
+
270
+ $('<div id="modal-test" aria-hidden="true"/>')
271
+ .on('shown.bs.modal', function () {
272
+ assert.notOk($('#modal-test').is('[aria-hidden]'), 'aria-hidden attribute removed')
273
+ $(this).bootstrapModal('hide')
274
+ })
275
+ .on('hidden.bs.modal', function () {
276
+ assert.ok($('#modal-test').is('[aria-hidden]'), 'aria-hidden attribute added')
277
+ assert.strictEqual($('#modal-test').attr('aria-hidden'), 'true', 'correct aria-hidden="true" added')
278
+ done()
279
+ })
280
+ .bootstrapModal('show')
281
+ })
282
+
283
+ QUnit.test('should add aria-modal attribute when shown, remove it again when hidden', function (assert) {
284
+ assert.expect(3)
285
+ var done = assert.async()
286
+
287
+ $('<div id="modal-test"/>')
288
+ .on('shown.bs.modal', function () {
289
+ assert.ok($('#modal-test').is('[aria-modal]'), 'aria-modal attribute added')
290
+ assert.strictEqual($('#modal-test').attr('aria-modal'), 'true', 'correct aria-modal="true" added')
291
+ $(this).bootstrapModal('hide')
292
+ })
293
+ .on('hidden.bs.modal', function () {
294
+ assert.notOk($('#modal-test').is('[aria-modal]'), 'aria-modal attribute removed')
295
+ done()
296
+ })
297
+ .bootstrapModal('show')
298
+ })
299
+
300
+ QUnit.test('should close reopened modal with [data-dismiss="modal"] click', function (assert) {
301
+ assert.expect(2)
302
+ var done = assert.async()
303
+
304
+ $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div></div>')
305
+ .one('shown.bs.modal', function () {
306
+ $('#close').trigger('click')
307
+ })
308
+ .one('hidden.bs.modal', function () {
309
+ // After one open-close cycle
310
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
311
+ $(this)
312
+ .one('shown.bs.modal', function () {
313
+ $('#close').trigger('click')
314
+ })
315
+ .one('hidden.bs.modal', function () {
316
+ assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
317
+ done()
318
+ })
319
+ .bootstrapModal('show')
320
+ })
321
+ .bootstrapModal('show')
322
+ })
323
+
324
+ QUnit.test('should restore focus to toggling element when modal is hidden after having been opened via data-api', function (assert) {
325
+ assert.expect(1)
326
+ var done = assert.async()
327
+
328
+ var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')
329
+
330
+ $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div></div>')
331
+ .on('hidden.bs.modal', function () {
332
+ setTimeout(function () {
333
+ assert.ok($(document.activeElement).is($toggleBtn), 'toggling element is once again focused')
334
+ done()
335
+ }, 0)
336
+ })
337
+ .on('shown.bs.modal', function () {
338
+ $('#close').trigger('click')
339
+ })
340
+ .appendTo('#qunit-fixture')
341
+
342
+ $toggleBtn.trigger('click')
343
+ })
344
+
345
+ QUnit.test('should not restore focus to toggling element if the associated show event gets prevented', function (assert) {
346
+ assert.expect(1)
347
+ var done = assert.async()
348
+ var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')
349
+ var $otherBtn = $('<button id="other-btn"/>').appendTo('#qunit-fixture')
350
+
351
+ $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div>')
352
+ .one('show.bs.modal', function (e) {
353
+ e.preventDefault()
354
+ $otherBtn.trigger('focus')
355
+ setTimeout($.proxy(function () {
356
+ $(this).bootstrapModal('show')
357
+ }, this), 0)
358
+ })
359
+ .on('hidden.bs.modal', function () {
360
+ setTimeout(function () {
361
+ assert.ok($(document.activeElement).is($otherBtn), 'focus returned to toggling element')
362
+ done()
363
+ }, 0)
364
+ })
365
+ .on('shown.bs.modal', function () {
366
+ $('#close').trigger('click')
367
+ })
368
+ .appendTo('#qunit-fixture')
369
+
370
+ $toggleBtn.trigger('click')
371
+ })
372
+
373
+ QUnit.test('should adjust the inline padding of the modal when opening', function (assert) {
374
+ assert.expect(1)
375
+ var done = assert.async()
376
+
377
+ $('<div id="modal-test"/>')
378
+ .on('shown.bs.modal', function () {
379
+ var expectedPadding = $(this).getScrollbarWidth() + 'px'
380
+ var currentPadding = $(this).css('padding-right')
381
+ assert.strictEqual(currentPadding, expectedPadding, 'modal padding should be adjusted while opening')
382
+ done()
383
+ })
384
+ .bootstrapModal('show')
385
+ })
386
+
387
+ QUnit.test('should adjust the inline body padding when opening and restore when closing', function (assert) {
388
+ assert.expect(2)
389
+ var done = assert.async()
390
+ var $body = $(document.body)
391
+ var originalPadding = $body.css('padding-right')
392
+
393
+ $('<div id="modal-test"/>')
394
+ .on('hidden.bs.modal', function () {
395
+ var currentPadding = $body.css('padding-right')
396
+ assert.strictEqual(currentPadding, originalPadding, 'body padding should be reset after closing')
397
+ $body.removeAttr('style')
398
+ done()
399
+ })
400
+ .on('shown.bs.modal', function () {
401
+ var expectedPadding = parseFloat(originalPadding) + $(this).getScrollbarWidth() + 'px'
402
+ var currentPadding = $body.css('padding-right')
403
+ assert.strictEqual(currentPadding, expectedPadding, 'body padding should be adjusted while opening')
404
+ $(this).bootstrapModal('hide')
405
+ })
406
+ .bootstrapModal('show')
407
+ })
408
+
409
+ QUnit.test('should store the original body padding in data-padding-right before showing', function (assert) {
410
+ assert.expect(2)
411
+ var done = assert.async()
412
+ var $body = $(document.body)
413
+ var originalPadding = '0px'
414
+ $body.css('padding-right', originalPadding)
415
+
416
+ $('<div id="modal-test"/>')
417
+ .on('hidden.bs.modal', function () {
418
+ assert.strictEqual(typeof $body.data('padding-right'), 'undefined', 'data-padding-right should be cleared after closing')
419
+ $body.removeAttr('style')
420
+ done()
421
+ })
422
+ .on('shown.bs.modal', function () {
423
+ assert.strictEqual($body.data('padding-right'), originalPadding, 'original body padding should be stored in data-padding-right')
424
+ $(this).bootstrapModal('hide')
425
+ })
426
+ .bootstrapModal('show')
427
+ })
428
+
429
+ QUnit.test('should not adjust the inline body padding when it does not overflow', function (assert) {
430
+ assert.expect(1)
431
+ var done = assert.async()
432
+ var $body = $(document.body)
433
+ var originalPadding = $body.css('padding-right')
434
+
435
+ // Hide scrollbars to prevent the body overflowing
436
+ $body.css('overflow', 'hidden') // Real scrollbar (for in-browser testing)
437
+ $('html').css('padding-right', '0px') // Simulated scrollbar (for PhantomJS)
438
+
439
+ $('<div id="modal-test"/>')
440
+ .on('shown.bs.modal', function () {
441
+ var currentPadding = $body.css('padding-right')
442
+ assert.strictEqual(currentPadding, originalPadding, 'body padding should not be adjusted')
443
+ $(this).bootstrapModal('hide')
444
+
445
+ // Restore scrollbars
446
+ $body.css('overflow', 'auto')
447
+ $('html').css('padding-right', '16px')
448
+ done()
449
+ })
450
+ .bootstrapModal('show')
451
+ })
452
+
453
+ QUnit.test('should adjust the inline padding of fixed elements when opening and restore when closing', function (assert) {
454
+ assert.expect(2)
455
+ var done = assert.async()
456
+ var $element = $('<div class="fixed-top"></div>').appendTo('#qunit-fixture')
457
+ var originalPadding = $element.css('padding-right')
458
+
459
+ $('<div id="modal-test"/>')
460
+ .on('hidden.bs.modal', function () {
461
+ var currentPadding = $element.css('padding-right')
462
+ assert.strictEqual(currentPadding, originalPadding, 'fixed element padding should be reset after closing')
463
+ $element.remove()
464
+ done()
465
+ })
466
+ .on('shown.bs.modal', function () {
467
+ var expectedPadding = parseFloat(originalPadding) + $(this).getScrollbarWidth() + 'px'
468
+ var currentPadding = $element.css('padding-right')
469
+ assert.strictEqual(currentPadding, expectedPadding, 'fixed element padding should be adjusted while opening')
470
+ $(this).bootstrapModal('hide')
471
+ })
472
+ .bootstrapModal('show')
473
+ })
474
+
475
+ QUnit.test('should store the original padding of fixed elements in data-padding-right before showing', function (assert) {
476
+ assert.expect(2)
477
+ var done = assert.async()
478
+ var $element = $('<div class="fixed-top"></div>').appendTo('#qunit-fixture')
479
+ var originalPadding = '0px'
480
+ $element.css('padding-right', originalPadding)
481
+
482
+ $('<div id="modal-test"/>')
483
+ .on('hidden.bs.modal', function () {
484
+ assert.strictEqual(typeof $element.data('padding-right'), 'undefined', 'data-padding-right should be cleared after closing')
485
+ $element.remove()
486
+ done()
487
+ })
488
+ .on('shown.bs.modal', function () {
489
+ assert.strictEqual($element.data('padding-right'), originalPadding, 'original fixed element padding should be stored in data-padding-right')
490
+ $(this).bootstrapModal('hide')
491
+ })
492
+ .bootstrapModal('show')
493
+ })
494
+
495
+ QUnit.test('should adjust the inline margin of sticky elements when opening and restore when closing', function (assert) {
496
+ assert.expect(2)
497
+ var done = assert.async()
498
+ var $element = $('<div class="sticky-top"></div>').appendTo('#qunit-fixture')
499
+ var originalPadding = $element.css('margin-right')
500
+
501
+ $('<div id="modal-test"/>')
502
+ .on('hidden.bs.modal', function () {
503
+ var currentPadding = $element.css('margin-right')
504
+ assert.strictEqual(currentPadding, originalPadding, 'sticky element margin should be reset after closing')
505
+ $element.remove()
506
+ done()
507
+ })
508
+ .on('shown.bs.modal', function () {
509
+ var expectedPadding = parseFloat(originalPadding) - $(this).getScrollbarWidth() + 'px'
510
+ var currentPadding = $element.css('margin-right')
511
+ assert.strictEqual(currentPadding, expectedPadding, 'sticky element margin should be adjusted while opening')
512
+ $(this).bootstrapModal('hide')
513
+ })
514
+ .bootstrapModal('show')
515
+ })
516
+
517
+ QUnit.test('should store the original margin of sticky elements in data-margin-right before showing', function (assert) {
518
+ assert.expect(2)
519
+ var done = assert.async()
520
+ var $element = $('<div class="sticky-top"></div>').appendTo('#qunit-fixture')
521
+ var originalPadding = '0px'
522
+ $element.css('margin-right', originalPadding)
523
+
524
+ $('<div id="modal-test"/>')
525
+ .on('hidden.bs.modal', function () {
526
+ assert.strictEqual(typeof $element.data('margin-right'), 'undefined', 'data-margin-right should be cleared after closing')
527
+ $element.remove()
528
+ done()
529
+ })
530
+ .on('shown.bs.modal', function () {
531
+ assert.strictEqual($element.data('margin-right'), originalPadding, 'original sticky element margin should be stored in data-margin-right')
532
+ $(this).bootstrapModal('hide')
533
+ })
534
+ .bootstrapModal('show')
535
+ })
536
+
537
+ QUnit.test('should ignore values set via CSS when trying to restore body padding after closing', function (assert) {
538
+ assert.expect(1)
539
+ var done = assert.async()
540
+ var $body = $(document.body)
541
+ var $style = $('<style>body { padding-right: 42px; }</style>').appendTo('head')
542
+
543
+ $('<div id="modal-test"/>')
544
+ .on('hidden.bs.modal', function () {
545
+ assert.strictEqual($body.attr('style').indexOf('padding-right'), -1, 'body does not have inline padding set')
546
+ $style.remove()
547
+ done()
548
+ })
549
+ .on('shown.bs.modal', function () {
550
+ $(this).bootstrapModal('hide')
551
+ })
552
+ .bootstrapModal('show')
553
+ })
554
+
555
+ QUnit.test('should ignore other inline styles when trying to restore body padding after closing', function (assert) {
556
+ assert.expect(2)
557
+ var done = assert.async()
558
+ var $body = $(document.body)
559
+ var $style = $('<style>body { padding-right: 42px; }</style>').appendTo('head')
560
+
561
+ $body.css('color', 'red')
562
+
563
+ $('<div id="modal-test"/>')
564
+ .on('hidden.bs.modal', function () {
565
+ assert.strictEqual($body[0].style.paddingRight, '', 'body does not have inline padding set')
566
+ assert.strictEqual($body[0].style.color, 'red', 'body still has other inline styles set')
567
+ $body.removeAttr('style')
568
+ $style.remove()
569
+ done()
570
+ })
571
+ .on('shown.bs.modal', function () {
572
+ $(this).bootstrapModal('hide')
573
+ })
574
+ .bootstrapModal('show')
575
+ })
576
+
577
+ QUnit.test('should properly restore non-pixel inline body padding after closing', function (assert) {
578
+ assert.expect(1)
579
+ var done = assert.async()
580
+ var $body = $(document.body)
581
+
582
+ $body.css('padding-right', '5%')
583
+
584
+ $('<div id="modal-test"/>')
585
+ .on('hidden.bs.modal', function () {
586
+ assert.strictEqual($body[0].style.paddingRight, '5%', 'body does not have inline padding set')
587
+ $body.removeAttr('style')
588
+ done()
589
+ })
590
+ .on('shown.bs.modal', function () {
591
+ $(this).bootstrapModal('hide')
592
+ })
593
+ .bootstrapModal('show')
594
+ })
595
+
596
+ QUnit.test('should not follow link in area tag', function (assert) {
597
+ assert.expect(2)
598
+ var done = assert.async()
599
+
600
+ $('<map><area id="test" shape="default" data-toggle="modal" data-target="#modal-test" href="demo.html"/></map>')
601
+ .appendTo('#qunit-fixture')
602
+
603
+ $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div></div>')
604
+ .appendTo('#qunit-fixture')
605
+
606
+ $('#test')
607
+ .on('click.bs.modal.data-api', function (event) {
608
+ assert.notOk(event.isDefaultPrevented(), 'navigating to href will happen')
609
+
610
+ setTimeout(function () {
611
+ assert.ok(event.isDefaultPrevented(), 'model shown instead of navigating to href')
612
+ done()
613
+ }, 1)
614
+ })
615
+ .trigger('click')
616
+ })
617
+
618
+ QUnit.test('should not parse target as html', function (assert) {
619
+ assert.expect(1)
620
+ var done = assert.async()
621
+
622
+ var $toggleBtn = $('<button data-toggle="modal" data-target="&lt;div id=&quot;modal-test&quot;&gt;&lt;div class=&quot;contents&quot;&lt;div&lt;div id=&quot;close&quot; data-dismiss=&quot;modal&quot;/&gt;&lt;/div&gt;&lt;/div&gt;"/>')
623
+ .appendTo('#qunit-fixture')
624
+
625
+ $toggleBtn.trigger('click')
626
+ setTimeout(function () {
627
+ assert.strictEqual($('#modal-test').length, 0, 'target has not been parsed and added to the document')
628
+ done()
629
+ }, 0)
630
+ })
631
+
632
+ QUnit.test('should not execute js from target', function (assert) {
633
+ assert.expect(0)
634
+ var done = assert.async()
635
+
636
+ // This toggle button contains XSS payload in its data-target
637
+ // Note: it uses the onerror handler of an img element to execute the js, because a simple script element does not work here
638
+ // a script element works in manual tests though, so here it is likely blocked by the qunit framework
639
+ var $toggleBtn = $('<button data-toggle="modal" data-target="&lt;div&gt;&lt;image src=&quot;missing.png&quot; onerror=&quot;$(&apos;#qunit-fixture button.control&apos;).trigger(&apos;click&apos;)&quot;&gt;&lt;/div&gt;"/>')
640
+ .appendTo('#qunit-fixture')
641
+ // The XSS payload above does not have a closure over this function and cannot access the assert object directly
642
+ // However, it can send a click event to the following control button, which will then fail the assert
643
+ $('<button>')
644
+ .addClass('control')
645
+ .on('click', function () {
646
+ assert.notOk(true, 'XSS payload is not executed as js')
647
+ })
648
+ .appendTo('#qunit-fixture')
649
+
650
+ $toggleBtn.trigger('click')
651
+
652
+ setTimeout(done, 500)
653
+ })
654
+
655
+ QUnit.test('should not try to open a modal which is already visible', function (assert) {
656
+ assert.expect(1)
657
+ var done = assert.async()
658
+ var count = 0
659
+
660
+ $('<div id="modal-test"/>').on('shown.bs.modal', function () {
661
+ count++
662
+ }).on('hidden.bs.modal', function () {
663
+ assert.strictEqual(count, 1, 'show() runs only once')
664
+ done()
665
+ })
666
+ .bootstrapModal('show')
667
+ .bootstrapModal('show')
668
+ .bootstrapModal('hide')
669
+ })
670
+
671
+ QUnit.test('transition duration should be the modal-dialog duration before triggering shown event', function (assert) {
672
+ assert.expect(1)
673
+ var done = assert.async()
674
+ var style = [
675
+ '<style>',
676
+ ' .modal.fade .modal-dialog {',
677
+ ' transition: -webkit-transform .3s ease-out;',
678
+ ' transition: transform .3s ease-out;',
679
+ ' transition: transform .3s ease-out,-webkit-transform .3s ease-out;',
680
+ ' -webkit-transform: translate(0,-50px);',
681
+ ' transform: translate(0,-50px);',
682
+ ' }',
683
+ '</style>'
684
+ ].join('')
685
+
686
+ var $style = $(style).appendTo('head')
687
+ var modalHTML = [
688
+ '<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">',
689
+ ' <div class="modal-dialog" role="document">',
690
+ ' <div class="modal-content">',
691
+ ' <div class="modal-body">...</div>',
692
+ ' </div>',
693
+ ' </div>',
694
+ '</div>'
695
+ ].join('')
696
+
697
+ var $modal = $(modalHTML).appendTo('#qunit-fixture')
698
+ var expectedTransitionDuration = 300
699
+ var spy = sinon.spy(Util, 'getTransitionDurationFromElement')
700
+
701
+ $modal.on('shown.bs.modal', function () {
702
+ assert.ok(spy.returned(expectedTransitionDuration))
703
+ $style.remove()
704
+ spy.restore()
705
+ done()
706
+ })
707
+ .bootstrapModal('show')
708
+ })
709
+
710
+ QUnit.test('should dispose modal', function (assert) {
711
+ assert.expect(3)
712
+ var done = assert.async()
713
+
714
+ var $modal = $([
715
+ '<div id="modal-test">',
716
+ ' <div class="modal-dialog">',
717
+ ' <div class="modal-content">',
718
+ ' <div class="modal-body" />',
719
+ ' </div>',
720
+ ' </div>',
721
+ '</div>'
722
+ ].join('')).appendTo('#qunit-fixture')
723
+
724
+ $modal.on('shown.bs.modal', function () {
725
+ var spy = sinon.spy($.fn, 'off')
726
+
727
+ $(this).bootstrapModal('dispose')
728
+
729
+ var modalDataApiEvent = []
730
+ $._data(document, 'events').click
731
+ .forEach(function (e) {
732
+ if (e.namespace === 'bs.data-api.modal') {
733
+ modalDataApiEvent.push(e)
734
+ }
735
+ })
736
+
737
+ assert.ok(typeof $(this).data('bs.modal') === 'undefined', 'modal data object was disposed')
738
+
739
+ assert.ok(spy.callCount === 4, '`jQuery.off` was called')
740
+
741
+ assert.ok(modalDataApiEvent.length === 1, '`Event.CLICK_DATA_API` on `document` was not removed')
742
+
743
+ $.fn.off.restore()
744
+ done()
745
+ }).bootstrapModal('show')
746
+ })
747
+
748
+ QUnit.test('should enforce focus', function (assert) {
749
+ assert.expect(4)
750
+ var done = assert.async()
751
+
752
+ var $modal = $([
753
+ '<div id="modal-test" data-show="false">',
754
+ ' <div class="modal-dialog">',
755
+ ' <div class="modal-content">',
756
+ ' <div class="modal-body" />',
757
+ ' </div>',
758
+ ' </div>',
759
+ '</div>'
760
+ ].join(''))
761
+ .bootstrapModal()
762
+ .appendTo('#qunit-fixture')
763
+
764
+ var modal = $modal.data('bs.modal')
765
+ var spy = sinon.spy(modal, '_enforceFocus')
766
+ var spyDocOff = sinon.spy($(document), 'off')
767
+ var spyDocOn = sinon.spy($(document), 'on')
768
+
769
+ $modal.one('shown.bs.modal', function () {
770
+ assert.ok(spy.called, '_enforceFocus called')
771
+ assert.ok(spyDocOff.withArgs('focusin.bs.modal'))
772
+ assert.ok(spyDocOn.withArgs('focusin.bs.modal'))
773
+
774
+ var spyFocus = sinon.spy(modal._element, 'focus')
775
+ var event = $.Event('focusin', {
776
+ target: $('#qunit-fixture')[0]
777
+ })
778
+
779
+ $(document).one('focusin', function () {
780
+ assert.ok(spyFocus.called)
781
+ done()
782
+ })
783
+
784
+ $(document).trigger(event)
785
+ })
786
+ .bootstrapModal('show')
787
+ })
788
+
789
+ QUnit.test('should scroll to top of the modal body if the modal has .modal-dialog-scrollable class', function (assert) {
790
+ assert.expect(2)
791
+ var done = assert.async()
792
+
793
+ var $modal = $([
794
+ '<div id="modal-test">',
795
+ ' <div class="modal-dialog modal-dialog-scrollable">',
796
+ ' <div class="modal-content">',
797
+ ' <div class="modal-body" style="height: 100px; overflow-y: auto;">',
798
+ ' <div style="height: 200px" />',
799
+ ' </div>',
800
+ ' </div>',
801
+ ' </div>',
802
+ '</div>'
803
+ ].join('')).appendTo('#qunit-fixture')
804
+
805
+ var $modalBody = $('.modal-body')
806
+ $modalBody.scrollTop(100)
807
+ assert.strictEqual($modalBody.scrollTop(), 100)
808
+
809
+ $modal.on('shown.bs.modal', function () {
810
+ assert.strictEqual($modalBody.scrollTop(), 0, 'modal body scrollTop should be 0 when opened')
811
+ done()
812
+ })
813
+ .bootstrapModal('show')
814
+ })
815
+ })