]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
[V4] Throw error when a plugin is in transition (#17823)
authorJohann <johann.servoire@gmail.com>
Fri, 2 Dec 2016 17:52:19 +0000 (18:52 +0100)
committerMark Otto <markd.otto@gmail.com>
Fri, 2 Dec 2016 17:52:19 +0000 (09:52 -0800)
* Throw error when a plugin is in transition
* Add unit tests about plugins in transition

js/src/carousel.js
js/src/collapse.js
js/src/modal.js
js/src/tooltip.js
js/tests/visual/carousel.html
js/tests/visual/collapse.html
js/tests/visual/modal.html
js/tests/visual/tooltip.html

index e56d4f0f291daa82617d6eaec46008dd8e307a8b..7fda8f6152f287c48debe00ff281387c77576af3 100644 (file)
@@ -116,9 +116,10 @@ const Carousel = (($) => {
     // public
 
     next() {
-      if (!this._isSliding) {
-        this._slide(Direction.NEXT)
+      if (this._isSliding) {
+        throw new Error('Carousel is sliding')
       }
+      this._slide(Direction.NEXT)
     }
 
     nextWhenVisible() {
@@ -129,9 +130,10 @@ const Carousel = (($) => {
     }
 
     prev() {
-      if (!this._isSliding) {
-        this._slide(Direction.PREVIOUS)
+      if (this._isSliding) {
+        throw new Error('Carousel is sliding')
       }
+      this._slide(Direction.PREVIOUS)
     }
 
     pause(event) {
index ebc3e24cfe6c819f1c23c0b19c786fcd0dca8068..1e4730ff7333b7d2f83de5aa070766947ef73d4a 100644 (file)
@@ -112,8 +112,11 @@ const Collapse = (($) => {
     }
 
     show() {
-      if (this._isTransitioning ||
-        $(this._element).hasClass(ClassName.ACTIVE)) {
+      if (this._isTransitioning) {
+        throw new Error('Collapse is transitioning')
+      }
+
+      if ($(this._element).hasClass(ClassName.ACTIVE)) {
         return
       }
 
@@ -193,8 +196,11 @@ const Collapse = (($) => {
     }
 
     hide() {
-      if (this._isTransitioning ||
-        !$(this._element).hasClass(ClassName.ACTIVE)) {
+      if (this._isTransitioning) {
+        throw new Error('Collapse is transitioning')
+      }
+
+      if (!$(this._element).hasClass(ClassName.ACTIVE)) {
         return
       }
 
index 61a28dbf5df74724228284d84b3fd83af58feb94..70bb68e42a29c675bed7e51a2369127c733955f6 100644 (file)
@@ -87,6 +87,7 @@ const Modal = (($) => {
       this._isShown             = false
       this._isBodyOverflowing   = false
       this._ignoreBackdropClick = false
+      this._isTransitioning     = false
       this._originalBodyPadding = 0
       this._scrollbarWidth      = 0
     }
@@ -110,6 +111,14 @@ const Modal = (($) => {
     }
 
     show(relatedTarget) {
+      if (this._isTransitioning) {
+        throw new Error('Modal is transitioning')
+      }
+
+      if (Util.supportsTransitionEnd() &&
+        $(this._element).hasClass(ClassName.FADE)) {
+        this._isTransitioning = true
+      }
       const showEvent = $.Event(Event.SHOW, {
         relatedTarget
       })
@@ -152,8 +161,17 @@ const Modal = (($) => {
         event.preventDefault()
       }
 
-      const hideEvent = $.Event(Event.HIDE)
+      if (this._isTransitioning) {
+        throw new Error('Modal is transitioning')
+      }
 
+      const transition = Util.supportsTransitionEnd() &&
+        $(this._element).hasClass(ClassName.FADE)
+      if (transition) {
+        this._isTransitioning = true
+      }
+
+      const hideEvent = $.Event(Event.HIDE)
       $(this._element).trigger(hideEvent)
 
       if (!this._isShown || hideEvent.isDefaultPrevented()) {
@@ -172,9 +190,7 @@ const Modal = (($) => {
       $(this._element).off(Event.CLICK_DISMISS)
       $(this._dialog).off(Event.MOUSEDOWN_DISMISS)
 
-      if (Util.supportsTransitionEnd() &&
-         $(this._element).hasClass(ClassName.FADE)) {
-
+      if (transition) {
         $(this._element)
           .one(Util.TRANSITION_END, (event) => this._hideModal(event))
           .emulateTransitionEnd(TRANSITION_DURATION)
@@ -240,6 +256,7 @@ const Modal = (($) => {
         if (this._config.focus) {
           this._element.focus()
         }
+        this._isTransitioning = false
         $(this._element).trigger(shownEvent)
       }
 
@@ -287,7 +304,8 @@ const Modal = (($) => {
 
     _hideModal() {
       this._element.style.display = 'none'
-      this._element.setAttribute('aria-hidden', true)
+      this._element.setAttribute('aria-hidden', 'true')
+      this._isTransitioning = false
       this._showBackdrop(() => {
         $(document.body).removeClass(ClassName.OPEN)
         this._resetAdjustments()
index 2b659b88540316dad8c2f5799b34725f69ad00b3..dc291a72ca98e6b6161daaa6eb3493729426e459 100644 (file)
@@ -123,11 +123,12 @@ const Tooltip = (($) => {
     constructor(element, config) {
 
       // private
-      this._isEnabled     = true
-      this._timeout       = 0
-      this._hoverState    = ''
-      this._activeTrigger = {}
-      this._tether        = null
+      this._isEnabled        = true
+      this._timeout          = 0
+      this._hoverState       = ''
+      this._activeTrigger    = {}
+      this._isTransitioning  = false
+      this._tether           = null
 
       // protected
       this.element = element
@@ -245,9 +246,12 @@ const Tooltip = (($) => {
       if ($(this.element).css('display') === 'none') {
         throw new Error('Please use show on visible elements')
       }
-      const showEvent = $.Event(this.constructor.Event.SHOW)
 
+      const showEvent = $.Event(this.constructor.Event.SHOW)
       if (this.isWithContent() && this._isEnabled) {
+        if (this._isTransitioning) {
+          throw new Error('Tooltip is transitioning')
+        }
         $(this.element).trigger(showEvent)
 
         const isInTheDom = $.contains(
@@ -303,7 +307,8 @@ const Tooltip = (($) => {
 
         const complete = () => {
           const prevHoverState = this._hoverState
-          this._hoverState     = null
+          this._hoverState   = null
+          this._isTransitioning = false
 
           $(this.element).trigger(this.constructor.Event.SHOWN)
 
@@ -313,6 +318,7 @@ const Tooltip = (($) => {
         }
 
         if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
+          this._isTransitioning = true
           $(this.tip)
             .one(Util.TRANSITION_END, complete)
             .emulateTransitionEnd(Tooltip._TRANSITION_DURATION)
@@ -326,6 +332,9 @@ const Tooltip = (($) => {
     hide(callback) {
       const tip       = this.getTipElement()
       const hideEvent = $.Event(this.constructor.Event.HIDE)
+      if (this._isTransitioning) {
+        throw new Error('Tooltip is transitioning')
+      }
       const complete  = () => {
         if (this._hoverState !== HoverState.ACTIVE && tip.parentNode) {
           tip.parentNode.removeChild(tip)
@@ -333,6 +342,7 @@ const Tooltip = (($) => {
 
         this.element.removeAttribute('aria-describedby')
         $(this.element).trigger(this.constructor.Event.HIDDEN)
+        this._isTransitioning = false
         this.cleanupTether()
 
         if (callback) {
@@ -350,7 +360,7 @@ const Tooltip = (($) => {
 
       if (Util.supportsTransitionEnd() &&
           $(this.tip).hasClass(ClassName.FADE)) {
-
+        this._isTransitioning = true
         $(tip)
           .one(Util.TRANSITION_END, complete)
           .emulateTransitionEnd(TRANSITION_DURATION)
index 2017f338b296c325f40610bcfc0fe912f48ecd8f..b26fb4a0d494ced9f5bb3e447eeaeeca43af845a 100644 (file)
     <script src="../../dist/carousel.js"></script>
 
     <script>
-      $(function() {
+      // Should throw an error because carousel is in transition
+      function testCarouselTransitionError() {
+        var err = false
+        var $carousel = $('#carousel-example-generic')
+        $carousel.on('slid.bs.carousel', function () {
+          $carousel.off('slid.bs.carousel')
+          if (!err) {
+            alert('No error thrown for : testCarouselTransitionError')
+          }
+        })
+        try {
+          $carousel.carousel('next').carousel('prev')
+        }
+        catch (e) {
+          err = true
+          console.error(e.message)
+        }
+      }
+
+      $(function () {
         // Test to show that the carousel doesn't slide when the current tab isn't visible
-        $('#carousel-example-generic').on('slid.bs.carousel', function(event) {
+        $('#carousel-example-generic').on('slid.bs.carousel', function (event) {
           console.log('slid at ', event.timeStamp)
         })
+        testCarouselTransitionError()
       })
     </script>
   </body>
index e13597984adc30a25bd9a5ea855c9fd5b9ed8ca3..973d3c5ee65e71e2d68c9b3c6b7b1afdb26a3c82 100644 (file)
     <script src="../vendor/jquery.min.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/collapse.js"></script>
+    <script>
+      // JavaScript Test
+      $(function () {
+        testCollapseTransitionError()
+      });
+
+      // Should throw an error because carousel is in transition
+      function testCollapseTransitionError() {
+        var err = false
+        $('#collapseOne').on('hidden.bs.collapse', function (e) {
+          $(this).off('hidden.bs.collapse')
+          if (!err) {
+            alert('No error thrown for : testCollapseTransitionError')
+          }
+        })
+
+        try {
+          $('#collapseOne').collapse('hide').collapse('show')
+        }
+        catch (e) {
+          err = true
+          console.error(e.message)
+        }
+      }
+    </script>
   </body>
 </html>
index fa5bd368aa167b14846c285e40840687bf698404..69d3923506e8a2a873b1c5c7be9438d85e45e8e3 100644 (file)
         }
       }
 
+      // Should throw an error because modal is in transition
+      function testModalTransitionError() {
+        var err = false
+        // Close #myModal
+        $('#myModal').on('shown.bs.modal', function () {
+          $('#myModal').modal('hide').off('shown.bs.modal')
+          if (!err) {
+            alert('No error thrown for : testModalTransitionError')
+          }
+        })
+
+        try {
+          $('#myModal').modal('show').modal('hide')
+        }
+        catch (e) {
+          err = true
+          console.error(e.message)
+        }
+      }
+
       $(function () {
         $('[data-toggle="popover"]').popover()
         $('[data-toggle="tooltip"]').tooltip()
           $('#firefoxModal').on('focus', reportFirefoxTestResult.bind(false))
           $('#ff-bug-input').on('focus', reportFirefoxTestResult.bind(true))
         })
+        testModalTransitionError()
       })
     </script>
   </body>
index 999e7eda626b91c3142c6640288043a0ba2caa59..6cd33e7e68096e74eca413413923bc002a60341e 100644 (file)
     <script>
       $(function () {
         $('[data-toggle="tooltip"]').tooltip()
+        testTooltipTransitionError()
       })
+
+      // Should throw an error because tooltip is in transition
+      function testTooltipTransitionError() {
+        var err = false
+        $('#btnOne').on('shown.bs.tooltip', function () {
+          $('#btnOne').tooltip('hide').off('shown.bs.tooltip')
+          if (!err) {
+            alert('No error thrown for : testTooltipTransitionError')
+          }
+        })
+        try {
+          $('#btnOne').tooltip('show').tooltip('hide')
+        }
+        catch (e) {
+          err = true
+          console.error(e.message)
+        }
+      }
     </script>
   </body>
 </html>