Skip to content

Commit

Permalink
WIP: Add touch support on our carousel with Hammer
Browse files Browse the repository at this point in the history
  • Loading branch information
Johann-S committed Mar 4, 2018
1 parent a651d73 commit 89fcc36
Show file tree
Hide file tree
Showing 12 changed files with 638 additions and 4 deletions.
2 changes: 2 additions & 0 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ cdn:
jquery_hash: "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
popper: "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
popper_hash: "sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
hammer: "https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"
hammer_hash: "sha256-GMd3rFxMDNnM5JQEpiKLLl8kSrDuG5egqchk758z59g="

toc:
min_level: 2
Expand Down
2 changes: 2 additions & 0 deletions _includes/scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<script>window.jQuery || document.write('<script src="{{ site.baseurl }}/assets/js/vendor/jquery-slim.min.js"><\/script>')</script>

<script src="{{ site.baseurl }}/assets/js/vendor/popper.min.js"{% if site.github %} integrity="{{ site.cdn.popper_hash }}" crossorigin="anonymous"{% endif %}></script>
<script src="{{ site.baseurl }}/assets/js/vendor/hammer.min.js"{% if site.github %} integrity="{{ site.cdn.hammer_hash }}" crossorigin="anonymous"{% endif %}></script>


{%- if site.github -%}
<script src="{{ site.baseurl }}/dist/js/bootstrap.min.js" integrity="{{ site.cdn.js_hash }}" crossorigin="anonymous"></script>
Expand Down
7 changes: 7 additions & 0 deletions assets/js/vendor/hammer.min.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion build/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const BUNDLE = process.env.BUNDLE === 'true'
const year = new Date().getFullYear()

let fileDest = 'bootstrap.js'
const external = ['jquery', 'popper.js']
const external = ['jquery', 'hammerjs', 'popper.js']
const plugins = [
babel({
exclude: 'node_modules/**', // Only transpile our source code
Expand All @@ -23,6 +23,7 @@ const plugins = [
]
const globals = {
jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode
hammerjs: 'Hammer',
'popper.js': 'Popper'
}

Expand Down
35 changes: 33 additions & 2 deletions js/src/carousel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import $ from 'jquery'
import { Hammer } from 'hammerjs'
import Util from './util'

/**
Expand All @@ -25,6 +26,7 @@ const Carousel = (($) => {
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 HAMMER_ENABLED = typeof Hammer !== 'undefined'

const Default = {
interval : 5000,
Expand Down Expand Up @@ -57,7 +59,9 @@ const Carousel = (($) => {
MOUSELEAVE : `mouseleave${EVENT_KEY}`,
TOUCHEND : `touchend${EVENT_KEY}`,
LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}`,
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}`
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}`,
SWIPELEFT : 'swipeleft',
SWIPERIGHT : 'swiperight'
}

const ClassName = {
Expand All @@ -72,6 +76,7 @@ const Carousel = (($) => {
}

const Selector = {
CAROUSEL : `.${ClassName.CAROUSEL}`,
ACTIVE : '.active',
ACTIVE_ITEM : '.active.carousel-item',
ITEM : '.carousel-item',
Expand All @@ -97,13 +102,25 @@ const Carousel = (($) => {
this._isSliding = false

this.touchTimeout = null
this.hammer = null

this._config = this._getConfig(config)
this._element = $(element)[0]
this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0]

this._transitionDuration = this._getTransitionDuration()

if (HAMMER_ENABLED) {
this.hammer = new Hammer(this._element, {
recognizers: [[
Hammer.Swipe,
{
direction: Hammer.DIRECTION_HORIZONTAL
}
]]
})
}

this._addEventListeners()
}

Expand Down Expand Up @@ -244,16 +261,22 @@ const Carousel = (($) => {
}

_addEventListeners() {
const touchSupported = 'ontouchstart' in document.documentElement
if (this._config.keyboard) {
$(this._element)
.on(Event.KEYDOWN, (event) => this._keydown(event))
}

if (touchSupported) {
this.hammer.on(Event.SWIPELEFT, () => this.next())
this.hammer.on(Event.SWIPERIGHT, () => this.prev())
}

if (this._config.pause === 'hover') {
$(this._element)
.on(Event.MOUSEENTER, (event) => this.pause(event))
.on(Event.MOUSELEAVE, (event) => this.cycle(event))
if ('ontouchstart' in document.documentElement) {
if (touchSupported) {
// If it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
Expand Down Expand Up @@ -509,6 +532,14 @@ const Carousel = (($) => {
* ------------------------------------------------------------------------
*/

if (HAMMER_ENABLED) {
$(document).find(Selector.CAROUSEL)
.not(Selector.DATA_RIDE)
.each(function () {
Carousel._jQueryInterface.call($(this), $(this).data())
})
}

$(document)
.on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler)

Expand Down
4 changes: 4 additions & 0 deletions js/tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
}())
</script>
<script src="../../assets/js/vendor/popper.min.js"></script>
<script src="../../assets/js/vendor/hammer.min.js"></script>

<!-- QUnit -->
<link rel="stylesheet" href="vendor/qunit.css" media="screen">
<script src="vendor/qunit.js"></script>

<!-- Hammer simulator -->
<script src="vendor/hammer-simulator.js"></script>

<script>
// Disable jQuery event aliases to ensure we don't accidentally use any of them
[
Expand Down
2 changes: 2 additions & 0 deletions js/tests/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ module.exports = (config) => {
files: [
jqueryFile,
'assets/js/vendor/popper.min.js',
'assets/js/vendor/hammer.min.js',
'js/tests/vendor/hammer-simulator.js',
'js/dist/util.js',
'js/dist/tooltip.js',
'js/dist/!(util|index|tooltip).js', // include all of our js/dist files except util.js, index.js and tooltip.js
Expand Down
3 changes: 2 additions & 1 deletion js/tests/unit/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"jquery": true
},
"globals": {
"Util": false
"Util": false,
"Simulator": false
},
"parserOptions": {
"ecmaVersion": 5,
Expand Down
72 changes: 72 additions & 0 deletions js/tests/unit/carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ $(function () {
afterEach: function () {
$.fn.carousel = $.fn.bootstrapCarousel
delete $.fn.bootstrapCarousel
$('.carousel').remove()
}
})

Expand Down Expand Up @@ -940,4 +941,75 @@ $(function () {
}, 80)
}, 80)
})

QUnit.test('should allow swiperight and call prev', function (assert) {
assert.expect(2)
var done = assert.async()
document.documentElement.ontouchstart = $.noop

var carouselHTML =
'<div class="carousel" data-interval="false">' +
' <div class="carousel-inner">' +
' <div id="item" class="carousel-item">' +
' <img alt="">' +
' </div>' +
' <div class="carousel-item active">' +
' <img alt="">' +
' </div>' +
' </div>' +
'</div>'

var $carousel = $(carouselHTML)
$carousel.appendTo('#qunit-fixture')
var $item = $('#item')
$carousel.bootstrapCarousel()

$carousel.one('slid.bs.carousel', function () {
assert.ok(true, 'slid event fired')
assert.ok($item.hasClass('active'))
delete document.documentElement.ontouchstart
done()
})

Simulator.gestures.swipe($carousel[0], {
deltaX: 300,
deltaY: 0
})
})

QUnit.test('should allow swipeleft and call next', function (assert) {
assert.expect(2)
var done = assert.async()
document.documentElement.ontouchstart = $.noop

var carouselHTML =
'<div class="carousel" data-interval="false">' +
' <div class="carousel-inner">' +
' <div id="item" class="carousel-item active">' +
' <img alt="">' +
' </div>' +
' <div class="carousel-item">' +
' <img alt="">' +
' </div>' +
' </div>' +
'</div>'

var $carousel = $(carouselHTML)
$carousel.appendTo('#qunit-fixture')
var $item = $('#item')
$carousel.bootstrapCarousel()

$carousel.one('slid.bs.carousel', function () {
assert.ok(true, 'slid event fired')
assert.ok(!$item.hasClass('active'))
delete document.documentElement.ontouchstart
done()
})

Simulator.gestures.swipe($carousel[0], {
pos: [300, 10],
deltaX: -300,
deltaY: 0
})
})
})
Loading

0 comments on commit 89fcc36

Please sign in to comment.