Skip to content

Commit

Permalink
Variable transition durations
Browse files Browse the repository at this point in the history
  • Loading branch information
MartijnCuppens authored and Johann-S committed Mar 12, 2018
1 parent 836de9c commit b06f41c
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 67 deletions.
2 changes: 1 addition & 1 deletion docs/4.0/components/carousel.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,4 +327,4 @@ $('#myCarousel').on('slide.bs.carousel', function () {

### Change transition duration

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.
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`).
5 changes: 3 additions & 2 deletions js/src/alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const Alert = (($) => {
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const TRANSITION_DURATION = 150

const Selector = {
DISMISS : '[data-dismiss="alert"]'
Expand Down Expand Up @@ -109,9 +108,11 @@ const Alert = (($) => {
return
}

const transitionDuration = Util.getTransitionDurationFromElement(element)

$(element)
.one(Util.TRANSITION_END, (event) => this._destroyElement(element, event))
.emulateTransitionEnd(TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)
}

_destroyElement(element) {
Expand Down
43 changes: 12 additions & 31 deletions js/src/carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,15 @@ const Carousel = (($) => {
* ------------------------------------------------------------------------
*/

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

const Default = {
interval : 5000,
Expand Down Expand Up @@ -102,8 +101,6 @@ const Carousel = (($) => {
this._element = $(element)[0]
this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0]

this._transitionDuration = this._getTransitionDuration()

this._addEventListeners()
}

Expand Down Expand Up @@ -225,24 +222,6 @@ const Carousel = (($) => {
return config
}

_getTransitionDuration() {
// Get transition-duration of first element in the carousel
let transitionDuration = $(this._element).find(Selector.ITEM).css('transition-duration')

// Return 0 carousel item is not found
if (!transitionDuration) {
return 0
}

// If multiple durations are defined, take the first
transitionDuration = transitionDuration.split(',')[0]

// Multiply by 1000 if transition-duration is defined in seconds
return transitionDuration.indexOf('ms') > -1
? parseFloat(transitionDuration)
: parseFloat(transitionDuration) * MILLISECONDS_MULTIPLIER
}

_addEventListeners() {
if (this._config.keyboard) {
$(this._element)
Expand Down Expand Up @@ -406,6 +385,8 @@ const Carousel = (($) => {
$(activeElement).addClass(directionalClassName)
$(nextElement).addClass(directionalClassName)

const transitionDuration = Util.getTransitionDurationFromElement(activeElement)

$(activeElement)
.one(Util.TRANSITION_END, () => {
$(nextElement)
Expand All @@ -418,7 +399,7 @@ const Carousel = (($) => {

setTimeout(() => $(this._element).trigger(slidEvent), 0)
})
.emulateTransitionEnd(this._transitionDuration)
.emulateTransitionEnd(transitionDuration)
} else {
$(activeElement).removeClass(ClassName.ACTIVE)
$(nextElement).addClass(ClassName.ACTIVE)
Expand Down
8 changes: 5 additions & 3 deletions js/src/collapse.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const Collapse = (($) => {
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const TRANSITION_DURATION = 600

const Default = {
toggle : true,
Expand Down Expand Up @@ -190,10 +189,11 @@ const Collapse = (($) => {

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

$(this._element)
.one(Util.TRANSITION_END, complete)
.emulateTransitionEnd(TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)

this._element.style[dimension] = `${this._element[scrollSize]}px`
}
Expand Down Expand Up @@ -252,9 +252,11 @@ const Collapse = (($) => {
return
}

const transitionDuration = Util.getTransitionDurationFromElement(this._element)

$(this._element)
.one(Util.TRANSITION_END, complete)
.emulateTransitionEnd(TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)
}

setTransitioning(isTransitioning) {
Expand Down
33 changes: 20 additions & 13 deletions js/src/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ const Modal = (($) => {
* ------------------------------------------------------------------------
*/

const NAME = 'modal'
const VERSION = '4.0.0'
const DATA_KEY = 'bs.modal'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const TRANSITION_DURATION = 300
const BACKDROP_TRANSITION_DURATION = 150
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
const NAME = 'modal'
const VERSION = '4.0.0'
const DATA_KEY = 'bs.modal'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key

const Default = {
backdrop : true,
Expand Down Expand Up @@ -187,10 +185,13 @@ const Modal = (($) => {
$(this._element).off(Event.CLICK_DISMISS)
$(this._dialog).off(Event.MOUSEDOWN_DISMISS)


if (transition) {
const transitionDuration = Util.getTransitionDurationFromElement(this._element)

$(this._element)
.one(Util.TRANSITION_END, (event) => this._hideModal(event))
.emulateTransitionEnd(TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)
} else {
this._hideModal()
}
Expand Down Expand Up @@ -263,9 +264,11 @@ const Modal = (($) => {
}

if (transition) {
const transitionDuration = Util.getTransitionDurationFromElement(this._element)

$(this._dialog)
.one(Util.TRANSITION_END, transitionComplete)
.emulateTransitionEnd(TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)
} else {
transitionComplete()
}
Expand Down Expand Up @@ -369,9 +372,11 @@ const Modal = (($) => {
return
}

const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)

$(this._backdrop)
.one(Util.TRANSITION_END, callback)
.emulateTransitionEnd(BACKDROP_TRANSITION_DURATION)
.emulateTransitionEnd(backdropTransitionDuration)
} else if (!this._isShown && this._backdrop) {
$(this._backdrop).removeClass(ClassName.SHOW)

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

if (Util.supportsTransitionEnd() &&
$(this._element).hasClass(ClassName.FADE)) {
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)

$(this._backdrop)
.one(Util.TRANSITION_END, callbackRemove)
.emulateTransitionEnd(BACKDROP_TRANSITION_DURATION)
.emulateTransitionEnd(backdropTransitionDuration)
} else {
callbackRemove()
}
Expand Down
17 changes: 9 additions & 8 deletions js/src/tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ const Tab = (($) => {
* ------------------------------------------------------------------------
*/

const NAME = 'tab'
const VERSION = '4.0.0'
const DATA_KEY = 'bs.tab'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const TRANSITION_DURATION = 150
const NAME = 'tab'
const VERSION = '4.0.0'
const DATA_KEY = 'bs.tab'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]

const Event = {
HIDE : `hide${EVENT_KEY}`,
Expand Down Expand Up @@ -162,9 +161,11 @@ const Tab = (($) => {
)

if (active && isTransitioning) {
const transitionDuration = Util.getTransitionDurationFromElement(active)

$(active)
.one(Util.TRANSITION_END, complete)
.emulateTransitionEnd(TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)
} else {
complete()
}
Expand Down
21 changes: 12 additions & 9 deletions js/src/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ const Tooltip = (($) => {
* ------------------------------------------------------------------------
*/

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

const DefaultType = {
Expand Down Expand Up @@ -335,9 +334,11 @@ const Tooltip = (($) => {
}

if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
const transitionDuration = Util.getTransitionDurationFromElement(this.tip)

$(this.tip)
.one(Util.TRANSITION_END, complete)
.emulateTransitionEnd(Tooltip._TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)
} else {
complete()
}
Expand Down Expand Up @@ -384,9 +385,11 @@ const Tooltip = (($) => {

if (Util.supportsTransitionEnd() &&
$(this.tip).hasClass(ClassName.FADE)) {
const transitionDuration = Util.getTransitionDurationFromElement(tip)

$(tip)
.one(Util.TRANSITION_END, complete)
.emulateTransitionEnd(TRANSITION_DURATION)
.emulateTransitionEnd(transitionDuration)
} else {
complete()
}
Expand Down
19 changes: 19 additions & 0 deletions js/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const Util = (($) => {
let transition = false

const MAX_UID = 1000000
const MILLISECONDS_MULTIPLIER = 1000

// Shoutout AngusCroll (https://goo.gl/pxwQGp)
function toType(obj) {
Expand Down Expand Up @@ -104,6 +105,24 @@ const Util = (($) => {
}
},

getTransitionDurationFromElement(element) {
// Get transition-duration of the element
let transitionDuration = $(element).css('transition-duration')

// Return 0 if element or transition duration is not found
if (!transitionDuration) {
return 0
}

// If multiple durations are defined, take the first
transitionDuration = transitionDuration.split(',')[0]

// Multiply by 1000 if transition-duration is defined in seconds
return transitionDuration.indexOf('ms') > -1
? parseFloat(transitionDuration)
: parseFloat(transitionDuration) * MILLISECONDS_MULTIPLIER
},

reflow(element) {
return element.offsetHeight
},
Expand Down
44 changes: 44 additions & 0 deletions js/tests/unit/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,50 @@ $(function () {
assert.strictEqual(typeof Util.isElement({}) === 'undefined', true)
})

QUnit.test('Util.getTransitionDurationFromElement should accept transition durations in milliseconds', function (assert) {
assert.expect(1)
var $div = $('<div style="transition: all 300ms ease-out;"></div>').appendTo($('#qunit-fixture'))

assert.strictEqual(Util.getTransitionDurationFromElement($div), 300)
})

QUnit.test('Util.getTransitionDurationFromElement should accept transition durations in seconds', function (assert) {
assert.expect(1)
var $div = $('<div style="transition: all .4s ease-out;"></div>').appendTo($('#qunit-fixture'))

assert.strictEqual(Util.getTransitionDurationFromElement($div), 400)
})

QUnit.test('Util.getTransitionDurationFromElement should get the first transition duration if multiple transition durations are defined', function (assert) {
assert.expect(1)
var $div = $('<div style="transition: transform .3s ease-out, opacity .2s;"></div>').appendTo($('#qunit-fixture'))

assert.strictEqual(Util.getTransitionDurationFromElement($div), 300)
})

QUnit.test('Util.getTransitionDurationFromElement should return 0 if transition duration is not defined', function (assert) {
assert.expect(1)
var $div = $('<div></div>').appendTo($('#qunit-fixture'))

assert.strictEqual(Util.getTransitionDurationFromElement($div), 0)
})

QUnit.test('Util.getTransitionDurationFromElement should return 0 if element is not found in DOM', function (assert) {
assert.expect(1)
var $div = $('#fake-id')

assert.strictEqual(Util.getTransitionDurationFromElement($div), 0)
})

QUnit.test('Util.getTransitionDurationFromElement should properly handle inherited transition durations', function (assert) {
assert.expect(1)
var $parent = $('<div style="transition-duration: 5s;"></div>')
var $child = $('<div style="transition-duration: inherit;"></div>')
$('#qunit-fixture').append($parent.append($child))

assert.strictEqual(Util.getTransitionDurationFromElement($child), 5000)
})

QUnit.test('Util.getUID should generate a new id uniq', function (assert) {
assert.expect(2)
var id = Util.getUID('test')
Expand Down
7 changes: 7 additions & 0 deletions js/tests/visual/alert.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ <h1>Alert <small>Bootstrap Visual Test</small></h1>
<button type="button" class="btn btn-primary">Or do this</button>
</p>
</div>

<div class="alert alert-warning alert-dismissible fade show" role="alert" style="transition-duration: 5s;">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
This alert will take 5 seconds to fade out.
</div>
</div>

<script src="../../../assets/js/vendor/jquery-slim.min.js"></script>
Expand Down
Loading

0 comments on commit b06f41c

Please sign in to comment.