Skip to content

Commit b06f41c

Browse files
MartijnCuppensJohann-S
authored andcommitted
Variable transition durations
1 parent 836de9c commit b06f41c

File tree

11 files changed

+169
-67
lines changed

11 files changed

+169
-67
lines changed

docs/4.0/components/carousel.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,4 +327,4 @@ $('#myCarousel').on('slide.bs.carousel', function () {
327327

328328
### Change transition duration
329329

330-
The transition duration of `.carousel-item` can be changed with the `$carousel-transition` Sass variable before compiling or custom styles if you're using the compiled CSS. If multiple transitions are applied, make sure the transform transition is defined first (eg. `transition: transform 2s ease, opacity .5s ease-out`). The transition duration must be the same for each carousel item.
330+
The transition duration of `.carousel-item` can be changed with the `$carousel-transition` Sass variable before compiling or custom styles if you're using the compiled CSS. If multiple transitions are applied, make sure the transform transition is defined first (eg. `transition: transform 2s ease, opacity .5s ease-out`).

js/src/alert.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const Alert = (($) => {
2121
const EVENT_KEY = `.${DATA_KEY}`
2222
const DATA_API_KEY = '.data-api'
2323
const JQUERY_NO_CONFLICT = $.fn[NAME]
24-
const TRANSITION_DURATION = 150
2524

2625
const Selector = {
2726
DISMISS : '[data-dismiss="alert"]'
@@ -109,9 +108,11 @@ const Alert = (($) => {
109108
return
110109
}
111110

111+
const transitionDuration = Util.getTransitionDurationFromElement(element)
112+
112113
$(element)
113114
.one(Util.TRANSITION_END, (event) => this._destroyElement(element, event))
114-
.emulateTransitionEnd(TRANSITION_DURATION)
115+
.emulateTransitionEnd(transitionDuration)
115116
}
116117

117118
_destroyElement(element) {

js/src/carousel.js

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,15 @@ const Carousel = (($) => {
1515
* ------------------------------------------------------------------------
1616
*/
1717

18-
const NAME = 'carousel'
19-
const VERSION = '4.0.0'
20-
const DATA_KEY = 'bs.carousel'
21-
const EVENT_KEY = `.${DATA_KEY}`
22-
const DATA_API_KEY = '.data-api'
23-
const JQUERY_NO_CONFLICT = $.fn[NAME]
24-
const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key
25-
const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key
26-
const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch
27-
const MILLISECONDS_MULTIPLIER = 1000
18+
const NAME = 'carousel'
19+
const VERSION = '4.0.0'
20+
const DATA_KEY = 'bs.carousel'
21+
const EVENT_KEY = `.${DATA_KEY}`
22+
const DATA_API_KEY = '.data-api'
23+
const JQUERY_NO_CONFLICT = $.fn[NAME]
24+
const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key
25+
const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key
26+
const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch
2827

2928
const Default = {
3029
interval : 5000,
@@ -102,8 +101,6 @@ const Carousel = (($) => {
102101
this._element = $(element)[0]
103102
this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0]
104103

105-
this._transitionDuration = this._getTransitionDuration()
106-
107104
this._addEventListeners()
108105
}
109106

@@ -225,24 +222,6 @@ const Carousel = (($) => {
225222
return config
226223
}
227224

228-
_getTransitionDuration() {
229-
// Get transition-duration of first element in the carousel
230-
let transitionDuration = $(this._element).find(Selector.ITEM).css('transition-duration')
231-
232-
// Return 0 carousel item is not found
233-
if (!transitionDuration) {
234-
return 0
235-
}
236-
237-
// If multiple durations are defined, take the first
238-
transitionDuration = transitionDuration.split(',')[0]
239-
240-
// Multiply by 1000 if transition-duration is defined in seconds
241-
return transitionDuration.indexOf('ms') > -1
242-
? parseFloat(transitionDuration)
243-
: parseFloat(transitionDuration) * MILLISECONDS_MULTIPLIER
244-
}
245-
246225
_addEventListeners() {
247226
if (this._config.keyboard) {
248227
$(this._element)
@@ -406,6 +385,8 @@ const Carousel = (($) => {
406385
$(activeElement).addClass(directionalClassName)
407386
$(nextElement).addClass(directionalClassName)
408387

388+
const transitionDuration = Util.getTransitionDurationFromElement(activeElement)
389+
409390
$(activeElement)
410391
.one(Util.TRANSITION_END, () => {
411392
$(nextElement)
@@ -418,7 +399,7 @@ const Carousel = (($) => {
418399

419400
setTimeout(() => $(this._element).trigger(slidEvent), 0)
420401
})
421-
.emulateTransitionEnd(this._transitionDuration)
402+
.emulateTransitionEnd(transitionDuration)
422403
} else {
423404
$(activeElement).removeClass(ClassName.ACTIVE)
424405
$(nextElement).addClass(ClassName.ACTIVE)

js/src/collapse.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const Collapse = (($) => {
2121
const EVENT_KEY = `.${DATA_KEY}`
2222
const DATA_API_KEY = '.data-api'
2323
const JQUERY_NO_CONFLICT = $.fn[NAME]
24-
const TRANSITION_DURATION = 600
2524

2625
const Default = {
2726
toggle : true,
@@ -190,10 +189,11 @@ const Collapse = (($) => {
190189

191190
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)
192191
const scrollSize = `scroll${capitalizedDimension}`
192+
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
193193

194194
$(this._element)
195195
.one(Util.TRANSITION_END, complete)
196-
.emulateTransitionEnd(TRANSITION_DURATION)
196+
.emulateTransitionEnd(transitionDuration)
197197

198198
this._element.style[dimension] = `${this._element[scrollSize]}px`
199199
}
@@ -252,9 +252,11 @@ const Collapse = (($) => {
252252
return
253253
}
254254

255+
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
256+
255257
$(this._element)
256258
.one(Util.TRANSITION_END, complete)
257-
.emulateTransitionEnd(TRANSITION_DURATION)
259+
.emulateTransitionEnd(transitionDuration)
258260
}
259261

260262
setTransitioning(isTransitioning) {

js/src/modal.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ const Modal = (($) => {
1515
* ------------------------------------------------------------------------
1616
*/
1717

18-
const NAME = 'modal'
19-
const VERSION = '4.0.0'
20-
const DATA_KEY = 'bs.modal'
21-
const EVENT_KEY = `.${DATA_KEY}`
22-
const DATA_API_KEY = '.data-api'
23-
const JQUERY_NO_CONFLICT = $.fn[NAME]
24-
const TRANSITION_DURATION = 300
25-
const BACKDROP_TRANSITION_DURATION = 150
26-
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
18+
const NAME = 'modal'
19+
const VERSION = '4.0.0'
20+
const DATA_KEY = 'bs.modal'
21+
const EVENT_KEY = `.${DATA_KEY}`
22+
const DATA_API_KEY = '.data-api'
23+
const JQUERY_NO_CONFLICT = $.fn[NAME]
24+
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
2725

2826
const Default = {
2927
backdrop : true,
@@ -187,10 +185,13 @@ const Modal = (($) => {
187185
$(this._element).off(Event.CLICK_DISMISS)
188186
$(this._dialog).off(Event.MOUSEDOWN_DISMISS)
189187

188+
190189
if (transition) {
190+
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
191+
191192
$(this._element)
192193
.one(Util.TRANSITION_END, (event) => this._hideModal(event))
193-
.emulateTransitionEnd(TRANSITION_DURATION)
194+
.emulateTransitionEnd(transitionDuration)
194195
} else {
195196
this._hideModal()
196197
}
@@ -263,9 +264,11 @@ const Modal = (($) => {
263264
}
264265

265266
if (transition) {
267+
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
268+
266269
$(this._dialog)
267270
.one(Util.TRANSITION_END, transitionComplete)
268-
.emulateTransitionEnd(TRANSITION_DURATION)
271+
.emulateTransitionEnd(transitionDuration)
269272
} else {
270273
transitionComplete()
271274
}
@@ -369,9 +372,11 @@ const Modal = (($) => {
369372
return
370373
}
371374

375+
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)
376+
372377
$(this._backdrop)
373378
.one(Util.TRANSITION_END, callback)
374-
.emulateTransitionEnd(BACKDROP_TRANSITION_DURATION)
379+
.emulateTransitionEnd(backdropTransitionDuration)
375380
} else if (!this._isShown && this._backdrop) {
376381
$(this._backdrop).removeClass(ClassName.SHOW)
377382

@@ -384,9 +389,11 @@ const Modal = (($) => {
384389

385390
if (Util.supportsTransitionEnd() &&
386391
$(this._element).hasClass(ClassName.FADE)) {
392+
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)
393+
387394
$(this._backdrop)
388395
.one(Util.TRANSITION_END, callbackRemove)
389-
.emulateTransitionEnd(BACKDROP_TRANSITION_DURATION)
396+
.emulateTransitionEnd(backdropTransitionDuration)
390397
} else {
391398
callbackRemove()
392399
}

js/src/tab.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ const Tab = (($) => {
1515
* ------------------------------------------------------------------------
1616
*/
1717

18-
const NAME = 'tab'
19-
const VERSION = '4.0.0'
20-
const DATA_KEY = 'bs.tab'
21-
const EVENT_KEY = `.${DATA_KEY}`
22-
const DATA_API_KEY = '.data-api'
23-
const JQUERY_NO_CONFLICT = $.fn[NAME]
24-
const TRANSITION_DURATION = 150
18+
const NAME = 'tab'
19+
const VERSION = '4.0.0'
20+
const DATA_KEY = 'bs.tab'
21+
const EVENT_KEY = `.${DATA_KEY}`
22+
const DATA_API_KEY = '.data-api'
23+
const JQUERY_NO_CONFLICT = $.fn[NAME]
2524

2625
const Event = {
2726
HIDE : `hide${EVENT_KEY}`,
@@ -162,9 +161,11 @@ const Tab = (($) => {
162161
)
163162

164163
if (active && isTransitioning) {
164+
const transitionDuration = Util.getTransitionDurationFromElement(active)
165+
165166
$(active)
166167
.one(Util.TRANSITION_END, complete)
167-
.emulateTransitionEnd(TRANSITION_DURATION)
168+
.emulateTransitionEnd(transitionDuration)
168169
} else {
169170
complete()
170171
}

js/src/tooltip.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@ const Tooltip = (($) => {
1616
* ------------------------------------------------------------------------
1717
*/
1818

19-
const NAME = 'tooltip'
20-
const VERSION = '4.0.0'
21-
const DATA_KEY = 'bs.tooltip'
22-
const EVENT_KEY = `.${DATA_KEY}`
23-
const JQUERY_NO_CONFLICT = $.fn[NAME]
24-
const TRANSITION_DURATION = 150
25-
const CLASS_PREFIX = 'bs-tooltip'
19+
const NAME = 'tooltip'
20+
const VERSION = '4.0.0'
21+
const DATA_KEY = 'bs.tooltip'
22+
const EVENT_KEY = `.${DATA_KEY}`
23+
const JQUERY_NO_CONFLICT = $.fn[NAME]
24+
const CLASS_PREFIX = 'bs-tooltip'
2625
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
2726

2827
const DefaultType = {
@@ -335,9 +334,11 @@ const Tooltip = (($) => {
335334
}
336335

337336
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
337+
const transitionDuration = Util.getTransitionDurationFromElement(this.tip)
338+
338339
$(this.tip)
339340
.one(Util.TRANSITION_END, complete)
340-
.emulateTransitionEnd(Tooltip._TRANSITION_DURATION)
341+
.emulateTransitionEnd(transitionDuration)
341342
} else {
342343
complete()
343344
}
@@ -384,9 +385,11 @@ const Tooltip = (($) => {
384385

385386
if (Util.supportsTransitionEnd() &&
386387
$(this.tip).hasClass(ClassName.FADE)) {
388+
const transitionDuration = Util.getTransitionDurationFromElement(tip)
389+
387390
$(tip)
388391
.one(Util.TRANSITION_END, complete)
389-
.emulateTransitionEnd(TRANSITION_DURATION)
392+
.emulateTransitionEnd(transitionDuration)
390393
} else {
391394
complete()
392395
}

js/src/util.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const Util = (($) => {
1717
let transition = false
1818

1919
const MAX_UID = 1000000
20+
const MILLISECONDS_MULTIPLIER = 1000
2021

2122
// Shoutout AngusCroll (https://goo.gl/pxwQGp)
2223
function toType(obj) {
@@ -104,6 +105,24 @@ const Util = (($) => {
104105
}
105106
},
106107

108+
getTransitionDurationFromElement(element) {
109+
// Get transition-duration of the element
110+
let transitionDuration = $(element).css('transition-duration')
111+
112+
// Return 0 if element or transition duration is not found
113+
if (!transitionDuration) {
114+
return 0
115+
}
116+
117+
// If multiple durations are defined, take the first
118+
transitionDuration = transitionDuration.split(',')[0]
119+
120+
// Multiply by 1000 if transition-duration is defined in seconds
121+
return transitionDuration.indexOf('ms') > -1
122+
? parseFloat(transitionDuration)
123+
: parseFloat(transitionDuration) * MILLISECONDS_MULTIPLIER
124+
},
125+
107126
reflow(element) {
108127
return element.offsetHeight
109128
},

js/tests/unit/util.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,50 @@ $(function () {
4242
assert.strictEqual(typeof Util.isElement({}) === 'undefined', true)
4343
})
4444

45+
QUnit.test('Util.getTransitionDurationFromElement should accept transition durations in milliseconds', function (assert) {
46+
assert.expect(1)
47+
var $div = $('<div style="transition: all 300ms ease-out;"></div>').appendTo($('#qunit-fixture'))
48+
49+
assert.strictEqual(Util.getTransitionDurationFromElement($div), 300)
50+
})
51+
52+
QUnit.test('Util.getTransitionDurationFromElement should accept transition durations in seconds', function (assert) {
53+
assert.expect(1)
54+
var $div = $('<div style="transition: all .4s ease-out;"></div>').appendTo($('#qunit-fixture'))
55+
56+
assert.strictEqual(Util.getTransitionDurationFromElement($div), 400)
57+
})
58+
59+
QUnit.test('Util.getTransitionDurationFromElement should get the first transition duration if multiple transition durations are defined', function (assert) {
60+
assert.expect(1)
61+
var $div = $('<div style="transition: transform .3s ease-out, opacity .2s;"></div>').appendTo($('#qunit-fixture'))
62+
63+
assert.strictEqual(Util.getTransitionDurationFromElement($div), 300)
64+
})
65+
66+
QUnit.test('Util.getTransitionDurationFromElement should return 0 if transition duration is not defined', function (assert) {
67+
assert.expect(1)
68+
var $div = $('<div></div>').appendTo($('#qunit-fixture'))
69+
70+
assert.strictEqual(Util.getTransitionDurationFromElement($div), 0)
71+
})
72+
73+
QUnit.test('Util.getTransitionDurationFromElement should return 0 if element is not found in DOM', function (assert) {
74+
assert.expect(1)
75+
var $div = $('#fake-id')
76+
77+
assert.strictEqual(Util.getTransitionDurationFromElement($div), 0)
78+
})
79+
80+
QUnit.test('Util.getTransitionDurationFromElement should properly handle inherited transition durations', function (assert) {
81+
assert.expect(1)
82+
var $parent = $('<div style="transition-duration: 5s;"></div>')
83+
var $child = $('<div style="transition-duration: inherit;"></div>')
84+
$('#qunit-fixture').append($parent.append($child))
85+
86+
assert.strictEqual(Util.getTransitionDurationFromElement($child), 5000)
87+
})
88+
4589
QUnit.test('Util.getUID should generate a new id uniq', function (assert) {
4690
assert.expect(2)
4791
var id = Util.getUID('test')

js/tests/visual/alert.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ <h1>Alert <small>Bootstrap Visual Test</small></h1>
4242
<button type="button" class="btn btn-primary">Or do this</button>
4343
</p>
4444
</div>
45+
46+
<div class="alert alert-warning alert-dismissible fade show" role="alert" style="transition-duration: 5s;">
47+
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
48+
<span aria-hidden="true">&times;</span>
49+
</button>
50+
This alert will take 5 seconds to fade out.
51+
</div>
4552
</div>
4653

4754
<script src="../../../assets/js/vendor/jquery-slim.min.js"></script>

0 commit comments

Comments
 (0)