]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Rewrite carousel without jquery
authorJohann-S <johann.servoire@gmail.com>
Thu, 24 Aug 2017 20:22:02 +0000 (22:22 +0200)
committerXhmikosR <xhmikosr@gmail.com>
Wed, 20 Feb 2019 20:05:45 +0000 (22:05 +0200)
js/src/carousel.js
js/src/dom/data.js
js/src/dom/eventHandler.js
js/src/util.js
js/tests/unit/.eslintrc.json
js/tests/unit/carousel.js
js/tests/visual/carousel.html

index fa0ce331a1b6cd24a861881e107a6421c042d874..5bc83243b7b07917eeea3f3ca2a4c85ae793085e 100644 (file)
@@ -5,7 +5,9 @@
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
+import Data from './dom/data'
+import EventHandler from './dom/eventHandler'
+import SelectorEngine from './dom/selectorEngine'
 import Util from './util'
 
 /**
@@ -112,7 +114,7 @@ class Carousel {
 
     this._config            = this._getConfig(config)
     this._element           = element
-    this._indicatorsElement = this._element.querySelector(Selector.INDICATORS)
+    this._indicatorsElement = SelectorEngine.findOne(Selector.INDICATORS, this._element)
     this._touchSupported    = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
     this._pointerEvent      = Boolean(window.PointerEvent || window.MSPointerEvent)
 
@@ -140,8 +142,7 @@ class Carousel {
   nextWhenVisible() {
     // Don't call next when the page isn't visible
     // or the carousel or its parent isn't visible
-    if (!document.hidden &&
-      ($(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden')) {
+    if (!document.hidden && Util.isVisible(this._element)) {
       this.next()
     }
   }
@@ -157,7 +158,7 @@ class Carousel {
       this._isPaused = true
     }
 
-    if (this._element.querySelector(Selector.NEXT_PREV)) {
+    if (SelectorEngine.findOne(Selector.NEXT_PREV, this._element)) {
       Util.triggerTransitionEnd(this._element)
       this.cycle(true)
     }
@@ -185,8 +186,7 @@ class Carousel {
   }
 
   to(index) {
-    this._activeElement = this._element.querySelector(Selector.ACTIVE_ITEM)
-
+    this._activeElement = SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element)
     const activeIndex = this._getItemIndex(this._activeElement)
 
     if (index > this._items.length - 1 || index < 0) {
@@ -194,7 +194,7 @@ class Carousel {
     }
 
     if (this._isSliding) {
-      $(this._element).one(Event.SLID, () => this.to(index))
+      EventHandler.one(this._element, Event.SLID, () => this.to(index))
       return
     }
 
@@ -212,8 +212,8 @@ class Carousel {
   }
 
   dispose() {
-    $(this._element).off(EVENT_KEY)
-    $.removeData(this._element, DATA_KEY)
+    EventHandler.off(this._element, DATA_KEY)
+    Data.removeData(this._element, DATA_KEY)
 
     this._items             = null
     this._config            = null
@@ -258,14 +258,15 @@ class Carousel {
 
   _addEventListeners() {
     if (this._config.keyboard) {
-      $(this._element)
-        .on(Event.KEYDOWN, (event) => this._keydown(event))
+      EventHandler
+        .on(this._element, Event.KEYDOWN, (event) => this._keydown(event))
     }
 
     if (this._config.pause === 'hover') {
-      $(this._element)
-        .on(Event.MOUSEENTER, (event) => this.pause(event))
-        .on(Event.MOUSELEAVE, (event) => this.cycle(event))
+      EventHandler
+        .on(this._element, Event.MOUSEENTER, (event) => this.pause(event))
+      EventHandler
+        .on(this._element, Event.MOUSELEAVE, (event) => this.cycle(event))
     }
 
     if (this._config.touch) {
@@ -279,25 +280,25 @@ class Carousel {
     }
 
     const start = (event) => {
-      if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
-        this.touchStartX = event.originalEvent.clientX
+      if (this._pointerEvent && PointerType[event.pointerType.toUpperCase()]) {
+        this.touchStartX = event.clientX
       } else if (!this._pointerEvent) {
-        this.touchStartX = event.originalEvent.touches[0].clientX
+        this.touchStartX = event.touches[0].clientX
       }
     }
 
     const move = (event) => {
       // ensure swiping with one touch and not pinching
-      if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {
+      if (event.touches && event.touches.length > 1) {
         this.touchDeltaX = 0
       } else {
-        this.touchDeltaX = event.originalEvent.touches[0].clientX - this.touchStartX
+        this.touchDeltaX = event.touches[0].clientX - this.touchStartX
       }
     }
 
     const end = (event) => {
       if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
-        this.touchDeltaX = event.originalEvent.clientX - this.touchStartX
+        this.touchDeltaX = event.clientX - this.touchStartX
       }
 
       this._handleSwipe()
@@ -318,16 +319,18 @@ class Carousel {
       }
     }
 
-    $(this._element.querySelectorAll(Selector.ITEM_IMG)).on(Event.DRAG_START, (e) => e.preventDefault())
+    [].slice.call(SelectorEngine.find(Selector.ITEM_IMG, this._element)).forEach((itemImg) => {
+      EventHandler.on(itemImg, Event.DRAG_START, (e) => e.preventDefault())
+    })
     if (this._pointerEvent) {
-      $(this._element).on(Event.POINTERDOWN, (event) => start(event))
-      $(this._element).on(Event.POINTERUP, (event) => end(event))
+      EventHandler.on(this._element, Event.POINTERDOWN, (event) => start(event))
+      EventHandler.on(this._element, Event.POINTERUP, (event) => end(event))
 
       this._element.classList.add(ClassName.POINTER_EVENT)
     } else {
-      $(this._element).on(Event.TOUCHSTART, (event) => start(event))
-      $(this._element).on(Event.TOUCHMOVE, (event) => move(event))
-      $(this._element).on(Event.TOUCHEND, (event) => end(event))
+      EventHandler.on(this._element, Event.TOUCHSTART, (event) => start(event))
+      EventHandler.on(this._element, Event.TOUCHMOVE, (event) => move(event))
+      EventHandler.on(this._element, Event.TOUCHEND, (event) => end(event))
     }
   }
 
@@ -351,8 +354,9 @@ class Carousel {
 
   _getItemIndex(element) {
     this._items = element && element.parentNode
-      ? [].slice.call(element.parentNode.querySelectorAll(Selector.ITEM))
+      ? [].slice.call(SelectorEngine.find(Selector.ITEM, element.parentNode))
       : []
+
     return this._items.indexOf(element)
   }
 
@@ -377,40 +381,39 @@ class Carousel {
 
   _triggerSlideEvent(relatedTarget, eventDirectionName) {
     const targetIndex = this._getItemIndex(relatedTarget)
-    const fromIndex = this._getItemIndex(this._element.querySelector(Selector.ACTIVE_ITEM))
-    const slideEvent = $.Event(Event.SLIDE, {
+    const fromIndex = this._getItemIndex(SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element))
+
+    return EventHandler.trigger(this._element, Event.SLIDE, {
       relatedTarget,
       direction: eventDirectionName,
       from: fromIndex,
       to: targetIndex
     })
-
-    $(this._element).trigger(slideEvent)
-
-    return slideEvent
   }
 
   _setActiveIndicatorElement(element) {
     if (this._indicatorsElement) {
-      const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector.ACTIVE))
-      $(indicators)
-        .removeClass(ClassName.ACTIVE)
+      const indicators = SelectorEngine.find(Selector.ACTIVE, this._indicatorsElement)
+      for (let i = 0; i < indicators.length; i++) {
+        indicators[i].classList.remove(ClassName.ACTIVE)
+      }
 
       const nextIndicator = this._indicatorsElement.children[
         this._getItemIndex(element)
       ]
 
       if (nextIndicator) {
-        $(nextIndicator).addClass(ClassName.ACTIVE)
+        nextIndicator.classList.add(ClassName.ACTIVE)
       }
     }
   }
 
   _slide(direction, element) {
-    const activeElement = this._element.querySelector(Selector.ACTIVE_ITEM)
+    const activeElement = SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element)
     const activeElementIndex = this._getItemIndex(activeElement)
     const nextElement   = element || activeElement &&
       this._getItemByDirection(direction, activeElement)
+
     const nextElementIndex = this._getItemIndex(nextElement)
     const isCycling = Boolean(this._interval)
 
@@ -428,13 +431,13 @@ class Carousel {
       eventDirectionName = Direction.RIGHT
     }
 
-    if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) {
+    if (nextElement && nextElement.classList.contains(ClassName.ACTIVE)) {
       this._isSliding = false
       return
     }
 
     const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)
-    if (slideEvent.isDefaultPrevented()) {
+    if (slideEvent.defaultPrevented) {
       return
     }
 
@@ -451,51 +454,50 @@ class Carousel {
 
     this._setActiveIndicatorElement(nextElement)
 
-    const slidEvent = $.Event(Event.SLID, {
-      relatedTarget: nextElement,
-      direction: eventDirectionName,
-      from: activeElementIndex,
-      to: nextElementIndex
-    })
-
-    if ($(this._element).hasClass(ClassName.SLIDE)) {
-      $(nextElement).addClass(orderClassName)
+    if (this._element.classList.contains(ClassName.SLIDE)) {
+      nextElement.classList.add(orderClassName)
 
       Util.reflow(nextElement)
 
-      $(activeElement).addClass(directionalClassName)
-      $(nextElement).addClass(directionalClassName)
-
-      const nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10)
-      if (nextElementInterval) {
-        this._config.defaultInterval = this._config.defaultInterval || this._config.interval
-        this._config.interval = nextElementInterval
-      } else {
-        this._config.interval = this._config.defaultInterval || this._config.interval
-      }
+      activeElement.classList.add(directionalClassName)
+      nextElement.classList.add(directionalClassName)
 
       const transitionDuration = Util.getTransitionDurationFromElement(activeElement)
 
-      $(activeElement)
-        .one(Util.TRANSITION_END, () => {
-          $(nextElement)
-            .removeClass(`${directionalClassName} ${orderClassName}`)
-            .addClass(ClassName.ACTIVE)
+      EventHandler
+        .one(activeElement, Util.TRANSITION_END, () => {
+          nextElement.classList.remove(directionalClassName)
+          nextElement.classList.remove(orderClassName)
+          nextElement.classList.add(ClassName.ACTIVE)
 
-          $(activeElement).removeClass(`${ClassName.ACTIVE} ${orderClassName} ${directionalClassName}`)
+          activeElement.classList.remove(ClassName.ACTIVE)
+          activeElement.classList.remove(orderClassName)
+          activeElement.classList.remove(directionalClassName)
 
           this._isSliding = false
 
-          setTimeout(() => $(this._element).trigger(slidEvent), 0)
+          setTimeout(() => {
+            EventHandler.trigger(this._element, Event.SLID, {
+              relatedTarget: nextElement,
+              direction: eventDirectionName,
+              from: activeElementIndex,
+              to: nextElementIndex
+            })
+          }, 0)
         })
 
-      Util.emulateTransitionEnd(transitionDuration)
+      Util.emulateTransitionEnd(activeElement, transitionDuration)
     } else {
-      $(activeElement).removeClass(ClassName.ACTIVE)
-      $(nextElement).addClass(ClassName.ACTIVE)
+      activeElement.classList.remove(ClassName.ACTIVE)
+      nextElement.classList.add(ClassName.ACTIVE)
 
       this._isSliding = false
-      $(this._element).trigger(slidEvent)
+      EventHandler.trigger(this._element, Event.SLID, {
+        relatedTarget: nextElement,
+        direction: eventDirectionName,
+        from: activeElementIndex,
+        to: nextElementIndex
+      })
     }
 
     if (isCycling) {
@@ -507,10 +509,10 @@ class Carousel {
 
   static _jQueryInterface(config) {
     return this.each(function () {
-      let data = $(this).data(DATA_KEY)
+      let data      = Data.getData(this, DATA_KEY)
       let _config = {
         ...Default,
-        ...$(this).data()
+        ...Data.getData(this, DATA_KEY)
       }
 
       if (typeof config === 'object') {
@@ -524,7 +526,7 @@ class Carousel {
 
       if (!data) {
         data = new Carousel(this, _config)
-        $(this).data(DATA_KEY, data)
+        Data.setData(this, DATA_KEY, data)
       }
 
       if (typeof config === 'number') {
@@ -548,15 +550,15 @@ class Carousel {
       return
     }
 
-    const target = $(selector)[0]
+    const target = SelectorEngine.findOne(selector)
 
-    if (!target || !$(target).hasClass(ClassName.CAROUSEL)) {
+    if (!target || !target.classList.contains(ClassName.CAROUSEL)) {
       return
     }
 
     const config = {
-      ...$(target).data(),
-      ...$(this).data()
+      ...Util.getDataAttributes(target),
+      ...Util.getDataAttributes(this)
     }
     const slideIndex = this.getAttribute('data-slide-to')
 
@@ -567,7 +569,7 @@ class Carousel {
     Carousel._jQueryInterface.call($(target), config)
 
     if (slideIndex) {
-      $(target).data(DATA_KEY).to(slideIndex)
+      Data.getData(target, DATA_KEY).to(slideIndex)
     }
 
     event.preventDefault()
@@ -580,17 +582,17 @@ class Carousel {
  * ------------------------------------------------------------------------
  */
 
-$(document)
-  .on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler)
+EventHandler
+  .on(document, Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler)
 
-$(window).on(Event.LOAD_DATA_API, () => {
-  const carousels = [].slice.call(document.querySelectorAll(Selector.DATA_RIDE))
+EventHandler.on(window, Event.LOAD_DATA_API, () => {
+  const carousels = Util.makeArray(SelectorEngine.find(Selector.DATA_RIDE))
   for (let i = 0, len = carousels.length; i < len; i++) {
-    const $carousel = $(carousels[i])
-    Carousel._jQueryInterface.call($carousel, $carousel.data())
+    Carousel._jQueryInterface.call($(carousels[i]), Data.getData(carousels[i], DATA_KEY))
   }
 })
 
+
 /**
  * ------------------------------------------------------------------------
  * jQuery
index 3e8fdc009df17c07a57f218323f1fc908e8ace91..655706fbc3a2da273aa76e68c390bbe37bb3b77b 100644 (file)
@@ -39,6 +39,7 @@ const mapData = (() => {
       const keyProperties = element.key
       if (keyProperties.key === key) {
         delete storeData[keyProperties.id]
+        delete element.key
       }
     }
   }
index 42c91c0906e481719c178fc5bfd13b04c69dcebe..476f7af26f5ca8800ea7bacaf4cbc470cb8bd6c8 100644 (file)
@@ -1,3 +1,5 @@
+import Util from '../util'
+
 /**
  * --------------------------------------------------------------------------
  * Bootstrap (v4.0.0-beta): dom/eventHandler.js
@@ -60,6 +62,7 @@ if (!window.Event || typeof window.Event !== 'function') {
 
 const namespaceRegex = /[^.]*(?=\..*)\.|.*/
 const stripNameRegex = /\..*/
+const keyEventRegex  = /^key/
 
 // Events storage
 const eventRegistry = {}
@@ -87,14 +90,29 @@ const nativeEvents = [
   'error', 'abort', 'scroll'
 ]
 
+const customEvents = {
+  mouseenter: 'mouseover',
+  mouseleave: 'mouseout'
+}
+
+function fixEvent(event) {
+  // Add which for key events
+  if (event.which === null && keyEventRegex.test(event.type)) {
+    event.which = event.charCode !== null ? event.charCode : event.keyCode
+  }
+  return event
+}
+
 function bootstrapHandler(element, fn) {
   return function (event) {
+    event = fixEvent(event)
     return fn.apply(element, [event])
   }
 }
 
 function bootstrapDelegationHandler(selector, fn) {
   return function (event) {
+    event = fixEvent(event)
     const domElements = document.querySelectorAll(selector)
     for (let target = event.target; target && target !== this; target = target.parentNode) {
       for (let i = domElements.length; i--;) {
@@ -117,8 +135,15 @@ const EventHandler = {
 
     const delegation      = typeof handler === 'string'
     const originalHandler = delegation ? delegationFn : handler
+
     // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
     let typeEvent = originalTypeEvent.replace(stripNameRegex, '')
+
+    const custom = customEvents[typeEvent]
+    if (custom) {
+      typeEvent = custom
+    }
+
     const isNative = nativeEvents.indexOf(typeEvent) > -1
     if (!isNative) {
       typeEvent = originalTypeEvent
@@ -131,20 +156,17 @@ const EventHandler = {
     }
 
     const fn = !delegation ? bootstrapHandler(element, handler) : bootstrapDelegationHandler(handler, delegationFn)
+    fn.isDelegation = delegation
     handlers[uid] = fn
     originalHandler.uidEvent = uid
+    fn.originalHandler = originalHandler
     element.addEventListener(typeEvent, fn, delegation)
   },
 
   one(element, event, handler) {
     function complete(e) {
-      const typeEvent = event.replace(stripNameRegex, '')
-      const events = getEvent(element)
-      if (!events || !events[typeEvent]) {
-        return
-      }
-      handler.apply(element, [e])
       EventHandler.off(element, event, complete)
+      handler.apply(element, [e])
     }
     EventHandler.on(element, event, complete)
   },
@@ -155,16 +177,46 @@ const EventHandler = {
       return
     }
 
-    const typeEvent = originalTypeEvent.replace(stripNameRegex, '')
-    const events = getEvent(element)
-    if (!events || !events[typeEvent]) {
-      return
+    const events      = getEvent(element)
+    let typeEvent     = originalTypeEvent.replace(stripNameRegex, '')
+    const inNamespace = typeEvent !== originalTypeEvent
+    const custom      = customEvents[typeEvent]
+    if (custom) {
+      typeEvent = custom
+    }
+    const isNative = nativeEvents.indexOf(typeEvent) > -1
+    if (!isNative) {
+      typeEvent = originalTypeEvent
     }
 
-    const uidEvent = handler.uidEvent
-    const fn = events[typeEvent][uidEvent]
-    element.removeEventListener(typeEvent, fn, false)
-    delete events[typeEvent][uidEvent]
+    if (typeof handler === 'undefined') {
+      for (const elementEvent in events) {
+        if (!Object.prototype.hasOwnProperty.call(events, elementEvent)) {
+          continue
+        }
+
+        const storeElementEvent = events[elementEvent]
+        for (const keyHandlers in storeElementEvent) {
+          if (!Object.prototype.hasOwnProperty.call(storeElementEvent, keyHandlers)) {
+            continue
+          }
+          // delete all the namespaced listeners
+          if (inNamespace && keyHandlers.indexOf(originalTypeEvent) > -1) {
+            const handlerFn = events[elementEvent][keyHandlers]
+            EventHandler.off(element, elementEvent, handlerFn.originalHandler)
+          }
+        }
+      }
+    } else {
+      if (!events || !events[typeEvent]) {
+        return
+      }
+
+      const uidEvent = handler.uidEvent
+      const fn = events[typeEvent][uidEvent]
+      element.removeEventListener(typeEvent, fn, fn.delegation)
+      delete events[typeEvent][uidEvent]
+    }
   },
 
   trigger(element, event, args) {
@@ -172,24 +224,27 @@ const EventHandler = {
         (typeof element === 'undefined' || element === null)) {
       return null
     }
-    const typeEvent = event.replace(stripNameRegex, '')
-    const isNative = nativeEvents.indexOf(typeEvent) > -1
-    let returnedEvent = null
+
+    const typeEvent   = event.replace(stripNameRegex, '')
+    const isNative    = nativeEvents.indexOf(typeEvent) > -1
+    let evt           = null
+
     if (isNative) {
-      const evt = document.createEvent('HTMLEvents')
-      evt.initEvent(typeEvent, true, true, typeof args !== 'undefined' ? args : {})
-      element.dispatchEvent(evt)
-      returnedEvent = evt
+      evt = document.createEvent('HTMLEvents')
+      evt.initEvent(typeEvent, true, true)
     } else {
-      const eventToDispatch = new CustomEvent(event, {
+      evt = new CustomEvent(event, {
         bubbles: true,
-        cancelable: true,
-        detail: typeof args !== 'undefined' ? args : {}
+        cancelable: true
       })
-      element.dispatchEvent(eventToDispatch)
-      returnedEvent = eventToDispatch
     }
-    return returnedEvent
+
+    // merge custom informations in our event
+    if (typeof args !== 'undefined') {
+      evt = Util.extend(evt, args)
+    }
+    element.dispatchEvent(evt)
+    return evt
   }
 }
 
index fb777e4f73ffba2b1e9a0042c93918d31f8d154b..ad147a1be7cadf7d109e46078068edb549cac911 100644 (file)
@@ -111,6 +111,59 @@ const Util = {
             `but expected type "${expectedTypes}".`)
         }
       }
+    },
+
+    extend(obj1, obj2) {
+      for (const secondProp in obj2) {
+        if (Object.prototype.hasOwnProperty.call(obj2, secondProp)) {
+          const secondVal = obj2[secondProp]
+          // Is this value an object?  If so, iterate over its properties, copying them over
+          if (secondVal && Object.prototype.toString.call(secondVal) === '[object Object]') {
+            obj1[secondProp] = obj1[secondProp] || {}
+            Util.extend(obj1[secondProp], secondVal)
+          } else {
+            obj1[secondProp] = secondVal
+          }
+        }
+      }
+      return obj1
+    },
+
+    makeArray(nodeList) {
+      if (typeof nodeList === 'undefined' || nodeList === null) {
+        return []
+      }
+      return Array.prototype.slice.call(nodeList)
+    },
+
+    getDataAttributes(element) {
+      if (typeof element === 'undefined' || element === null) {
+        return {}
+      }
+
+      const attributes = {}
+      for (let i = 0; i < element.attributes.length; i++) {
+        const attribute = element.attributes[i]
+        if (attribute.nodeName.indexOf('data-') !== -1) {
+          // remove 'data-' part of the attribute name
+          const attributeName = attribute.nodeName.substring('data-'.length)
+          attributes[attributeName] = attribute.nodeValue
+        }
+      }
+      return attributes
+    },
+
+    isVisible(element) {
+      if (typeof element === 'undefined' || element === null) {
+        return false
+      }
+
+      if (element.style !== null && element.parentNode !== null && typeof element.parentNode.style !== 'undefined') {
+        return element.style.display !== 'none'
+          && element.parentNode.style.display !== 'none'
+          && element.style.visibility !== 'hidden'
+      }
+      return false
     }
   },
 
index b07efd269d17026d767beb10cc6c6d2777796d7b..487ba6c168a4d3bb4a61f2201521e6f03f9fdce9 100644 (file)
@@ -13,7 +13,8 @@
     "Carousel": false,
     "Simulator": false,
     "Toast": false,
-    "EventHandler": false
+    "EventHandler": false,
+    "Data": false
   },
   "parserOptions": {
     "ecmaVersion": 5,
index 0d2a0f327104f2fef5b3cea35f98db20c79f92d7..615318ad32388215c01b6ce6256dc9183a9fbe6a 100644 (file)
@@ -34,6 +34,7 @@ $(function () {
       $.fn.bootstrapCarousel = $.fn.carousel.noConflict()
     },
     afterEach: function () {
+      $('.carousel').bootstrapCarousel('dispose')
       $.fn.carousel = $.fn.bootstrapCarousel
       delete $.fn.bootstrapCarousel
       $('#qunit-fixture').html('')
@@ -112,16 +113,18 @@ $(function () {
   QUnit.test('should not fire slid when slide is prevented', function (assert) {
     assert.expect(1)
     var done = assert.async()
-    $('<div class="carousel"/>')
-      .on('slide.bs.carousel', function (e) {
-        e.preventDefault()
-        assert.ok(true, 'slide event fired')
-        done()
-      })
-      .on('slid.bs.carousel', function () {
-        assert.ok(false, 'slid event fired')
-      })
-      .bootstrapCarousel('next')
+    var $carousel = $('<div class="carousel"/>')
+    $carousel.appendTo('#qunit-fixture')
+
+    EventHandler.on($carousel[0], 'slide.bs.carousel', function (e) {
+      e.preventDefault()
+      assert.ok(true, 'slide event fired')
+      done()
+    })
+    EventHandler.on($carousel[0], 'slid.bs.carousel', function () {
+      assert.ok(false, 'slid event fired')
+    })
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should reset when slide is prevented', function (assert) {
@@ -147,10 +150,11 @@ $(function () {
         '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' +
         '</div>'
     var $carousel = $(carouselHTML)
+    $carousel.appendTo('#qunit-fixture')
 
     var done = assert.async()
-    $carousel
-      .one('slide.bs.carousel', function (e) {
+    EventHandler
+      .one($carousel[0], 'slide.bs.carousel', function (e) {
         e.preventDefault()
         setTimeout(function () {
           assert.ok($carousel.find('.carousel-item:nth-child(1)').is('.active'), 'first item still active')
@@ -158,7 +162,9 @@ $(function () {
           $carousel.bootstrapCarousel('next')
         }, 0)
       })
-      .one('slid.bs.carousel', function () {
+
+    EventHandler
+      .one($carousel[0], 'slid.bs.carousel', function () {
         setTimeout(function () {
           assert.ok(!$carousel.find('.carousel-item:nth-child(1)').is('.active'), 'first item still active')
           assert.ok(!$carousel.find('.carousel-indicators li:nth-child(1)').is('.active'), 'first indicator still active')
@@ -167,7 +173,8 @@ $(function () {
           done()
         }, 0)
       })
-      .bootstrapCarousel('next')
+
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should fire slide event with direction', function (assert) {
@@ -206,23 +213,24 @@ $(function () {
         '<a class="right carousel-control" href="#myCarousel" data-slide="next">&rsaquo;</a>' +
         '</div>'
     var $carousel = $(carouselHTML)
+    $carousel.appendTo('#qunit-fixture')
 
     var done = assert.async()
 
-    $carousel
-      .one('slide.bs.carousel', function (e) {
+    EventHandler
+      .one($carousel[0], 'slide.bs.carousel', function (e) {
         assert.ok(e.direction, 'direction present on next')
         assert.strictEqual(e.direction, 'left', 'direction is left on next')
 
-        $carousel
-          .one('slide.bs.carousel', function (e) {
+        EventHandler
+          .one($carousel[0], 'slide.bs.carousel', function (e) {
             assert.ok(e.direction, 'direction present on prev')
             assert.strictEqual(e.direction, 'right', 'direction is right on prev')
             done()
           })
-          .bootstrapCarousel('prev')
+        $carousel.bootstrapCarousel('prev')
       })
-      .bootstrapCarousel('next')
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should fire slid event with direction', function (assert) {
@@ -261,23 +269,24 @@ $(function () {
         '<a class="right carousel-control" href="#myCarousel" data-slide="next">&rsaquo;</a>' +
         '</div>'
     var $carousel = $(carouselHTML)
+    $carousel.appendTo('#qunit-fixture')
 
     var done = assert.async()
 
-    $carousel
-      .one('slid.bs.carousel', function (e) {
+    EventHandler
+      .one($carousel[0], 'slid.bs.carousel', function (e) {
         assert.ok(e.direction, 'direction present on next')
         assert.strictEqual(e.direction, 'left', 'direction is left on next')
 
-        $carousel
-          .one('slid.bs.carousel', function (e) {
+        EventHandler
+          .one($carousel[0], 'slid.bs.carousel', function (e) {
             assert.ok(e.direction, 'direction present on prev')
             assert.strictEqual(e.direction, 'right', 'direction is right on prev')
             done()
           })
-          .bootstrapCarousel('prev')
+        $carousel.bootstrapCarousel('prev')
       })
-      .bootstrapCarousel('next')
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should fire slide event with relatedTarget', function (assert) {
@@ -317,14 +326,17 @@ $(function () {
         '</div>'
 
     var done = assert.async()
+    var $carousel = $(template)
+    $carousel.appendTo('#qunit-fixture')
 
-    $(template)
-      .on('slide.bs.carousel', function (e) {
+    EventHandler
+      .one($carousel[0], 'slide.bs.carousel', function (e) {
         assert.ok(e.relatedTarget, 'relatedTarget present')
         assert.ok($(e.relatedTarget).hasClass('carousel-item'), 'relatedTarget has class "item"')
         done()
       })
-      .bootstrapCarousel('next')
+
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should fire slid event with relatedTarget', function (assert) {
@@ -364,14 +376,17 @@ $(function () {
         '</div>'
 
     var done = assert.async()
+    var $carousel = $(template)
+    $carousel.appendTo('#qunit-fixture')
 
-    $(template)
-      .on('slid.bs.carousel', function (e) {
+    EventHandler
+      .one($carousel[0], 'slid.bs.carousel', function (e) {
         assert.ok(e.relatedTarget, 'relatedTarget present')
         assert.ok($(e.relatedTarget).hasClass('carousel-item'), 'relatedTarget has class "item"')
         done()
       })
-      .bootstrapCarousel('next')
+
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should fire slid and slide events with from and to', function (assert) {
@@ -402,19 +417,22 @@ $(function () {
         '</div>'
 
     var done = assert.async()
-    $(template)
-      .on('slid.bs.carousel', function (e) {
+    var $carousel = $(template)
+
+    EventHandler
+      .one($carousel[0], 'slid.bs.carousel', function (e) {
         assert.ok(typeof e.from !== 'undefined', 'from present')
         assert.ok(typeof e.to !== 'undefined', 'to present')
-        $(this).off()
         done()
       })
-      .on('slide.bs.carousel', function (e) {
+
+    EventHandler
+      .one($carousel[0], 'slide.bs.carousel', function (e) {
         assert.ok(typeof e.from !== 'undefined', 'from present')
         assert.ok(typeof e.to !== 'undefined', 'to present')
-        $(this).off('slide.bs.carousel')
       })
-      .bootstrapCarousel('next')
+
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should set interval from data attribute', function (assert) {
@@ -456,26 +474,27 @@ $(function () {
     $carousel.attr('data-interval', 1814)
 
     $carousel.appendTo('body')
-    $('[data-slide]').first().trigger('click')
-    assert.strictEqual($carousel.data('bs.carousel')._config.interval, 1814)
+    EventHandler.trigger($('[data-slide]').first()[0], 'click')
+    assert.strictEqual(Data.getData($carousel[0], 'bs.carousel')._config.interval, 1814)
     $carousel.remove()
 
     $carousel.appendTo('body').attr('data-modal', 'foobar')
-    $('[data-slide]').first().trigger('click')
-    assert.strictEqual($carousel.data('bs.carousel')._config.interval, 1814, 'even if there is an data-modal attribute set')
+    EventHandler.trigger($('[data-slide]').first()[0], 'click')
+    assert.strictEqual(Data.getData($carousel[0], 'bs.carousel')._config.interval, 1814, 'even if there is an data-modal attribute set')
     $carousel.remove()
 
     $carousel.appendTo('body')
-    $('[data-slide]').first().trigger('click')
+    EventHandler.trigger($('[data-slide]').first()[0], 'click')
     $carousel.attr('data-interval', 1860)
-    $('[data-slide]').first().trigger('click')
-    assert.strictEqual($carousel.data('bs.carousel')._config.interval, 1814, 'attributes should be read only on initialization')
+    EventHandler.trigger($('[data-slide]').first()[0], 'click')
+    assert.strictEqual(Data.getData($carousel[0], 'bs.carousel')._config.interval, 1814, 'attributes should be read only on initialization')
+    $carousel.bootstrapCarousel('dispose')
     $carousel.remove()
 
     $carousel.attr('data-interval', false)
     $carousel.appendTo('body')
     $carousel.bootstrapCarousel(1)
-    assert.strictEqual($carousel.data('bs.carousel')._config.interval, false, 'data attribute has higher priority than default options')
+    assert.strictEqual(Data.getData($carousel[0], 'bs.carousel')._config.interval, false, 'data attribute has higher priority than default options')
     $carousel.remove()
   })
 
@@ -600,9 +619,13 @@ $(function () {
 
     assert.strictEqual($template.find('.carousel-item')[1], $template.find('.active')[0], 'second item active')
 
+<<<<<<< HEAD
     $template.trigger($.Event('keydown', {
       which: 37
     }))
+=======
+    EventHandler.trigger($template[0], 'keydown', { which: 37 })
+>>>>>>> fix unit test for carousel
 
     assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active')
   })
@@ -628,9 +651,13 @@ $(function () {
 
     assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active')
 
+<<<<<<< HEAD
     $template.trigger($.Event('keydown', {
       which: 39
     }))
+=======
+    EventHandler.trigger($template[0], 'keydown', { which: 39 })
+>>>>>>> fix unit test for carousel
 
     assert.strictEqual($template.find('.carousel-item')[1], $template.find('.active')[0], 'second item active')
   })
@@ -649,6 +676,7 @@ $(function () {
     $template.bootstrapCarousel()
     var done = assert.async()
 
+<<<<<<< HEAD
     var eventArrowDown = $.Event('keydown', {
       which: 40
     })
@@ -658,16 +686,22 @@ $(function () {
 
     $template.one('keydown', function (event) {
       assert.strictEqual(event.isDefaultPrevented(), false)
+=======
+    EventHandler.one($template[0], 'keydown', function (event) {
+      assert.strictEqual(event.defaultPrevented, false)
+>>>>>>> fix unit test for carousel
     })
 
-    $template.trigger(eventArrowDown)
+    // arrow down
+    EventHandler.trigger($template[0], 'keydown', { which: 40 })
 
-    $template.one('keydown', function (event) {
-      assert.strictEqual(event.isDefaultPrevented(), false)
+    EventHandler.one($template[0], 'keydown', function (event) {
+      assert.strictEqual(event.defaultPrevented, false)
       done()
     })
 
-    $template.trigger(eventArrowUp)
+    // arrow up
+    EventHandler.trigger($template[0], 'keydown', { which: 38 })
   })
 
   QUnit.test('should support disabling the keyboard navigation', function (assert) {
@@ -782,22 +816,21 @@ $(function () {
 
     var done = assert.async()
 
-    $carousel
-      .one('slid.bs.carousel', function () {
-        assert.strictEqual(getActiveId(), 'two', 'carousel slid from 1st to 2nd slide')
-        $carousel
-          .one('slid.bs.carousel', function () {
-            assert.strictEqual(getActiveId(), 'three', 'carousel slid from 2nd to 3rd slide')
-            $carousel
-              .one('slid.bs.carousel', function () {
-                assert.strictEqual(getActiveId(), 'one', 'carousel wrapped around and slid from 3rd to 1st slide')
-                done()
-              })
-              .bootstrapCarousel('next')
-          })
-          .bootstrapCarousel('next')
+    EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+      assert.strictEqual(getActiveId(), 'two', 'carousel slid from 1st to 2nd slide')
+
+      EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+        assert.strictEqual(getActiveId(), 'three', 'carousel slid from 2nd to 3rd slide')
+
+        EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+          assert.strictEqual(getActiveId(), 'one', 'carousel wrapped around and slid from 3rd to 1st slide')
+          done()
+        })
+        $carousel.bootstrapCarousel('next')
       })
-      .bootstrapCarousel('next')
+      $carousel.bootstrapCarousel('next')
+    })
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should wrap around from start to end when wrap option is true', function (assert) {
@@ -826,12 +859,11 @@ $(function () {
 
     var done = assert.async()
 
-    $carousel
-      .on('slid.bs.carousel', function () {
-        assert.strictEqual($carousel.find('.carousel-item.active').attr('id'), 'three', 'carousel wrapped around and slid from 1st to 3rd slide')
-        done()
-      })
-      .bootstrapCarousel('prev')
+    EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+      assert.strictEqual($carousel.find('.carousel-item.active').attr('id'), 'three', 'carousel wrapped around and slid from 1st to 3rd slide')
+      done()
+    })
+    $carousel.bootstrapCarousel('prev')
   })
 
   QUnit.test('should stay at the end when the next method is called and wrap is false', function (assert) {
@@ -863,23 +895,22 @@ $(function () {
 
     var done = assert.async()
 
-    $carousel
-      .one('slid.bs.carousel', function () {
-        assert.strictEqual(getActiveId(), 'two', 'carousel slid from 1st to 2nd slide')
-        $carousel
-          .one('slid.bs.carousel', function () {
-            assert.strictEqual(getActiveId(), 'three', 'carousel slid from 2nd to 3rd slide')
-            $carousel
-              .one('slid.bs.carousel', function () {
-                assert.ok(false, 'carousel slid when it should not have slid')
-              })
-              .bootstrapCarousel('next')
-            assert.strictEqual(getActiveId(), 'three', 'carousel did not wrap around and stayed on 3rd slide')
-            done()
-          })
-          .bootstrapCarousel('next')
+    EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+      assert.strictEqual(getActiveId(), 'two', 'carousel slid from 1st to 2nd slide')
+
+      EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+        assert.strictEqual(getActiveId(), 'three', 'carousel slid from 2nd to 3rd slide')
+
+        EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+          assert.ok(false, 'carousel slid when it should not have slid')
+        })
+        $carousel.bootstrapCarousel('next')
+        assert.strictEqual(getActiveId(), 'three', 'carousel did not wrap around and stayed on 3rd slide')
+        done()
       })
-      .bootstrapCarousel('next')
+      $carousel.bootstrapCarousel('next')
+    })
+    $carousel.bootstrapCarousel('next')
   })
 
   QUnit.test('should stay at the start when the prev method is called and wrap is false', function (assert) {
@@ -906,11 +937,10 @@ $(function () {
         '</div>'
     var $carousel = $(carouselHTML)
 
-    $carousel
-      .on('slid.bs.carousel', function () {
-        assert.ok(false, 'carousel slid when it should not have slid')
-      })
-      .bootstrapCarousel('prev')
+    EventHandler.one($carousel[0], 'slid.bs.carousel', function () {
+      assert.ok(false, 'carousel slid when it should not have slid')
+    })
+    $carousel.bootstrapCarousel('prev')
     assert.strictEqual($carousel.find('.carousel-item.active').attr('id'), 'one', 'carousel did not wrap around and stayed on 1st slide')
   })
 
index d1376b39b9f5c996f4733911d3687bf7c1762108..aa6c5e4c71e1269a2fd9ca15d09b40c4c82ca678 100644 (file)
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
     <script src="../../dist/dom/eventHandler.js"></script>
+    <script src="../../dist/dom/selectorEngine.js"></script>
+    <script src="../../dist/dom/data.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/carousel.js"></script>
     <script>
       $(function() {
         var t0, t1;
+        var carousel = SelectorEngine.find('#carousel-example-generic')
 
         // Test to show that the carousel doesn't slide when the current tab isn't visible
         // Test to show that transition-duration can be changed with css
-        $('#carousel-example-generic').on('slid.bs.carousel', function(event) {
+        EventHandler.on(carousel, 'slid.bs.carousel', function (event) {
           t1 = performance.now()
           console.log('transition-duration took' + (t1 - t0) + 'ms, slid at ', event.timeStamp)
-        }).on('slide.bs.carousel', function() {
+        })
+        EventHandler.on(carousel, 'slide.bs.carousel', function () {
           t0 = performance.now()
         })
       })