]> git.ipfire.org Git - thirdparty/foundation/foundation-sites.git/commitdiff
fixes #7549, adds flag to ensure there is more than one slide in orbit container...
authorChris Oyler <chris@zurb.com>
Wed, 6 Jan 2016 20:09:33 +0000 (12:09 -0800)
committerChris Oyler <chris@zurb.com>
Wed, 6 Jan 2016 20:09:33 +0000 (12:09 -0800)
js/foundation.orbit.js

index 3fa206e792a09da8e8b93087de731d1333bd28b8..dd5843794d9ed9d280c572c52e3fed8ba888b170 100644 (file)
@@ -1,19 +1,19 @@
 /**
- * Orbit module.
- * @module foundation.orbit
- * @requires foundation.util.keyboard
- * @requires foundation.util.motion
- * @requires foundation.util.timerAndImageLoader
- * @requires foundation.util.touch
- */
+* Orbit module.
+* @module foundation.orbit
+* @requires foundation.util.keyboard
+* @requires foundation.util.motion
+* @requires foundation.util.timerAndImageLoader
+* @requires foundation.util.touch
+*/
 !function($, Foundation){
   'use strict';
   /**
-   * Creates a new instance of an orbit carousel.
-   * @class
-   * @param {jQuery} element - jQuery object to make into an Orbit Carousel.
-   * @param {Object} options - Overrides to the default plugin settings.
-   */
+  * Creates a new instance of an orbit carousel.
+  * @class
+  * @param {jQuery} element - jQuery object to make into an Orbit Carousel.
+  * @param {Object} options - Overrides to the default plugin settings.
+  */
   function Orbit(element, options){
     this.$element = element;
     this.options = $.extend({}, Orbit.defaults, this.$element.data(), options);
 
     Foundation.registerPlugin(this, 'Orbit');
     Foundation.Keyboard.register('Orbit', {
-        'ltr': {
-          'ARROW_RIGHT': 'next',
-          'ARROW_LEFT': 'previous'
-        },
-        'rtl': {
-          'ARROW_LEFT': 'next',
-          'ARROW_RIGHT': 'previous'
-        }
+      'ltr': {
+        'ARROW_RIGHT': 'next',
+        'ARROW_LEFT': 'previous'
+      },
+      'rtl': {
+        'ARROW_LEFT': 'next',
+        'ARROW_RIGHT': 'previous'
+      }
     });
   }
   Orbit.defaults = {
     /**
-     * Tells the JS to loadBullets.
-     * @option
-     * @example true
-     */
+    * Tells the JS to loadBullets.
+    * @option
+    * @example true
+    */
     bullets: true,
     /**
-     * Tells the JS to apply event listeners to nav buttons
-     * @option
-     * @example true
-     */
+    * Tells the JS to apply event listeners to nav buttons
+    * @option
+    * @example true
+    */
     navButtons: true,
     /**
-     * motion-ui animation class to apply
-     * @option
-     * @example 'slide-in-right'
-     */
+    * motion-ui animation class to apply
+    * @option
+    * @example 'slide-in-right'
+    */
     animInFromRight: 'slide-in-right',
     /**
-     * motion-ui animation class to apply
-     * @option
-     * @example 'slide-out-right'
-     */
+    * motion-ui animation class to apply
+    * @option
+    * @example 'slide-out-right'
+    */
     animOutToRight: 'slide-out-right',
     /**
-     * motion-ui animation class to apply
-     * @option
-     * @example 'slide-in-left'
-     *
-     */
+    * motion-ui animation class to apply
+    * @option
+    * @example 'slide-in-left'
+    *
+    */
     animInFromLeft: 'slide-in-left',
     /**
-     * motion-ui animation class to apply
-     * @option
-     * @example 'slide-out-left'
-     */
+    * motion-ui animation class to apply
+    * @option
+    * @example 'slide-out-left'
+    */
     animOutToLeft: 'slide-out-left',
     /**
-     * Allows Orbit to automatically animate on page load.
-     * @option
-     * @example true
-     */
+    * Allows Orbit to automatically animate on page load.
+    * @option
+    * @example true
+    */
     autoPlay: true,
     /**
-     * Amount of time, in ms, between slide transitions
-     * @option
-     * @example 5000
-     */
+    * Amount of time, in ms, between slide transitions
+    * @option
+    * @example 5000
+    */
     timerDelay: 5000,
     /**
-     * Allows Orbit to infinitely loop through the slides
-     * @option
-     * @example true
-     */
+    * Allows Orbit to infinitely loop through the slides
+    * @option
+    * @example true
+    */
     infiniteWrap: true,
     /**
-     * Allows the Orbit slides to bind to swipe events for mobile, requires an additional util library
-     * @option
-     * @example true
-     */
+    * Allows the Orbit slides to bind to swipe events for mobile, requires an additional util library
+    * @option
+    * @example true
+    */
     swipe: true,
     /**
-     * Allows the timing function to pause animation on hover.
-     * @option
-     * @example true
-     */
+    * Allows the timing function to pause animation on hover.
+    * @option
+    * @example true
+    */
     pauseOnHover: true,
     /**
-     * Allows Orbit to bind keyboard events to the slider, to animate frames with arrow keys
-     * @option
-     * @example true
-     */
+    * Allows Orbit to bind keyboard events to the slider, to animate frames with arrow keys
+    * @option
+    * @example true
+    */
     accessible: true,
     /**
-     * Class applied to the container of Orbit
-     * @option
-     * @example 'orbit-container'
-     */
+    * Class applied to the container of Orbit
+    * @option
+    * @example 'orbit-container'
+    */
     containerClass: 'orbit-container',
     /**
-     * Class applied to individual slides.
-     * @option
-     * @example 'orbit-slide'
-     */
+    * Class applied to individual slides.
+    * @option
+    * @example 'orbit-slide'
+    */
     slideClass: 'orbit-slide',
     /**
-     * Class applied to the bullet container. You're welcome.
-     * @option
-     * @example 'orbit-bullets'
-     */
+    * Class applied to the bullet container. You're welcome.
+    * @option
+    * @example 'orbit-bullets'
+    */
     boxOfBullets: 'orbit-bullets',
     /**
-     * Class applied to the `next` navigation button.
-     * @option
-     * @example 'orbit-next'
-     */
+    * Class applied to the `next` navigation button.
+    * @option
+    * @example 'orbit-next'
+    */
     nextClass: 'orbit-next',
     /**
-     * Class applied to the `previous` navigation button.
-     * @option
-     * @example 'orbit-previous'
-     */
+    * Class applied to the `previous` navigation button.
+    * @option
+    * @example 'orbit-previous'
+    */
     prevClass: 'orbit-previous',
     /**
-     * Boolean to flag the js to use motion ui classes or not. Default to true for backwards compatability.
-     * @option
-     * @example true
-     */
+    * Boolean to flag the js to use motion ui classes or not. Default to true for backwards compatability.
+    * @option
+    * @example true
+    */
     useMUI: true
   };
   /**
-   * Initializes the plugin by creating jQuery collections, setting attributes, and starting the animation.
-   * @function
-   * @private
-   */
+  * Initializes the plugin by creating jQuery collections, setting attributes, and starting the animation.
+  * @function
+  * @private
+  */
   Orbit.prototype._init = function(){
     this.$wrapper = this.$element.find('.' + this.options.containerClass);
     this.$slides = this.$element.find('.' + this.options.slideClass);
     var $images = this.$element.find('img'),
-        initActive = this.$slides.filter('.is-active');
+    initActive = this.$slides.filter('.is-active');
 
     if(!initActive.length){
       this.$slides.eq(0).addClass('is-active');
 
     this._events();
 
-    if(this.options.autoPlay){
+    if(this.options.autoPlay && this.$slides.length > 1){
       this.geoSync();
     }
     if(this.options.accessible){ // allow wrapper to be focusable to enable arrow navigation
     }
   };
   /**
-   * Creates a jQuery collection of bullets, if they are being used.
-   * @function
-   * @private
-   */
+  * Creates a jQuery collection of bullets, if they are being used.
+  * @function
+  * @private
+  */
   Orbit.prototype._loadBullets = function(){
     this.$bullets = this.$element.find('.' + this.options.boxOfBullets).find('button');
   };
   /**
-   * Sets a `timer` object on the orbit, and starts the counter for the next slide.
-   * @function
-   */
+  * Sets a `timer` object on the orbit, and starts the counter for the next slide.
+  * @function
+  */
   Orbit.prototype.geoSync = function(){
     var _this = this;
     this.timer = new Foundation.Timer(
-                      this.$element,
-                      {duration: this.options.timerDelay,
-                       infinite: false},
-                      function(){
-                        _this.changeSlide(true);
-                      });
-    this.timer.start();
-  };
-  /**
-   * Sets wrapper and slide heights for the orbit.
-   * @function
-   * @private
-   */
-  Orbit.prototype._prepareForOrbit = function(){
-    var _this = this;
-    this._setWrapperHeight(function(max){
-      _this._setSlideHeight(max);
-    });
-  };
-  /**
-   * Calulates the height of each slide in the collection, and uses the tallest one for the wrapper height.
-   * @function
-   * @private
-   * @param {Function} cb - a callback function to fire when complete.
-   */
-  Orbit.prototype._setWrapperHeight = function(cb){//rewrite this to `for` loop
-    var max = 0, temp, counter = 0;
+      this.$element,
+      {duration: this.options.timerDelay,
+        infinite: false},
+        function(){
+          _this.changeSlide(true);
+        });
+        this.timer.start();
+      };
+      /**
+      * Sets wrapper and slide heights for the orbit.
+      * @function
+      * @private
+      */
+      Orbit.prototype._prepareForOrbit = function(){
+        var _this = this;
+        this._setWrapperHeight(function(max){
+          _this._setSlideHeight(max);
+        });
+      };
+      /**
+      * Calulates the height of each slide in the collection, and uses the tallest one for the wrapper height.
+      * @function
+      * @private
+      * @param {Function} cb - a callback function to fire when complete.
+      */
+      Orbit.prototype._setWrapperHeight = function(cb){//rewrite this to `for` loop
+        var max = 0, temp, counter = 0;
 
-    this.$slides.each(function(){
-      temp = this.getBoundingClientRect().height;
-      $(this).attr('data-slide', counter);
+        this.$slides.each(function(){
+          temp = this.getBoundingClientRect().height;
+          $(this).attr('data-slide', counter);
 
-      if(counter){//if not the first slide, set css position and display property
-        $(this).css({'position': 'relative', 'display': 'none'});
-      }
-      max = temp > max ? temp : max;
-      counter++;
-    });
+          if(counter){//if not the first slide, set css position and display property
+            $(this).css({'position': 'relative', 'display': 'none'});
+          }
+          max = temp > max ? temp : max;
+          counter++;
+        });
 
-    if(counter === this.$slides.length){
-      this.$wrapper.css({'height': max});//only change the wrapper height property once.
-      cb(max);//fire callback with max height dimension.
-    }
-  };
-  /**
-   * Sets the max-height of each slide.
-   * @function
-   * @private
-   */
-  Orbit.prototype._setSlideHeight = function(height){
-    this.$slides.each(function(){
-      $(this).css('max-height', height);
-    });
-  };
-  /**
-   * Adds event listeners to basically everything within the element.
-   * @function
-   * @private
-   */
-  Orbit.prototype._events = function(){
-    var _this = this;
+        if(counter === this.$slides.length){
+          this.$wrapper.css({'height': max});//only change the wrapper height property once.
+          cb(max);//fire callback with max height dimension.
+        }
+      };
+      /**
+      * Sets the max-height of each slide.
+      * @function
+      * @private
+      */
+      Orbit.prototype._setSlideHeight = function(height){
+        this.$slides.each(function(){
+          $(this).css('max-height', height);
+        });
+      };
+      /**
+      * Adds event listeners to basically everything within the element.
+      * @function
+      * @private
+      */
+      Orbit.prototype._events = function(){
+        var _this = this;
 
-    //***************************************
-    //**Now using custom event - thanks to:**
-    //**      Yohai Ararat of Toronto      **
-    //***************************************
-    if(this.options.swipe){
-      this.$slides.off('swipeleft.zf.orbit swiperight.zf.orbit')
-      .on('swipeleft.zf.orbit', function(e){
-        e.preventDefault();
-        _this.changeSlide(true);
-      }).on('swiperight.zf.orbit', function(e){
-        e.preventDefault();
-        _this.changeSlide(false);
-      });
-    }
-    //***************************************
+        //***************************************
+        //**Now using custom event - thanks to:**
+        //**      Yohai Ararat of Toronto      **
+        //***************************************
+        if(this.$slides.length > 1){
 
-    if(this.options.autoPlay){
-      this.$slides.on('click.zf.orbit', function(){
-        _this.$element.data('clickedOn', _this.$element.data('clickedOn') ? false : true);
-        _this.timer[_this.$element.data('clickedOn') ? 'pause' : 'start']();
-      });
-      if(this.options.pauseOnHover){
-        this.$element.on('mouseenter.zf.orbit', function(){
-          _this.timer.pause();
-        }).on('mouseleave.zf.orbit', function(){
-          if(!_this.$element.data('clickedOn')){
-            _this.timer.start();
+          if(this.options.swipe){
+            this.$slides.off('swipeleft.zf.orbit swiperight.zf.orbit')
+            .on('swipeleft.zf.orbit', function(e){
+              e.preventDefault();
+              _this.changeSlide(true);
+            }).on('swiperight.zf.orbit', function(e){
+              e.preventDefault();
+              _this.changeSlide(false);
+            });
           }
-        });
-      }
-    }
+          //***************************************
 
-    if(this.options.navButtons){
-      var $controls = this.$element.find('.' + this.options.nextClass + ', .' + this.options.prevClass);
-      $controls.attr('tabindex', 0)
-        //also need to handle enter/return and spacebar key presses
-               .on('click.zf.orbit touchend.zf.orbit', function(){
-                 _this.changeSlide($(this).hasClass(_this.options.nextClass));
-               });
-    }
+          if(this.options.autoPlay){
+            this.$slides.on('click.zf.orbit', function(){
+              _this.$element.data('clickedOn', _this.$element.data('clickedOn') ? false : true);
+              _this.timer[_this.$element.data('clickedOn') ? 'pause' : 'start']();
+            });
+            if(this.options.pauseOnHover){
+              this.$element.on('mouseenter.zf.orbit', function(){
+                _this.timer.pause();
+              }).on('mouseleave.zf.orbit', function(){
+                if(!_this.$element.data('clickedOn')){
+                  _this.timer.start();
+                }
+              });
+            }
+          }
 
-    if(this.options.bullets){
-      this.$bullets.on('click.zf.orbit touchend.zf.orbit', function(){
-        if(/is-active/g.test(this.className)){ return false; }//if this is active, kick out of function.
-        var idx = $(this).data('slide'),
-            ltr = idx > _this.$slides.filter('.is-active').data('slide'),
-            $slide = _this.$slides.eq(idx);
+          if(this.options.navButtons){
+            var $controls = this.$element.find('.' + this.options.nextClass + ', .' + this.options.prevClass);
+            $controls.attr('tabindex', 0)
+            //also need to handle enter/return and spacebar key presses
+            .on('click.zf.orbit touchend.zf.orbit', function(){
+              _this.changeSlide($(this).hasClass(_this.options.nextClass));
+            });
+          }
 
-        _this.changeSlide(ltr, $slide, idx);
-      });
-    }
+          if(this.options.bullets){
+            this.$bullets.on('click.zf.orbit touchend.zf.orbit', function(){
+              if(/is-active/g.test(this.className)){ return false; }//if this is active, kick out of function.
+              var idx = $(this).data('slide'),
+              ltr = idx > _this.$slides.filter('.is-active').data('slide'),
+              $slide = _this.$slides.eq(idx);
 
-    this.$wrapper.add(this.$bullets).on('keydown.zf.orbit', function(e){
-      // handle keyboard event with keyboard util
-      Foundation.Keyboard.handleKey(e, 'Orbit', {
-        next: function() {
-          _this.changeSlide(true);
-        },
-        previous: function() {
-          _this.changeSlide(false);
-        },
-        handled: function() { // if bullet is focused, make sure focus moves
-          if ($(e.target).is(_this.$bullets)) {
-            _this.$bullets.filter('.is-active').focus();
+              _this.changeSlide(ltr, $slide, idx);
+            });
           }
+
+          this.$wrapper.add(this.$bullets).on('keydown.zf.orbit', function(e){
+            // handle keyboard event with keyboard util
+            Foundation.Keyboard.handleKey(e, 'Orbit', {
+              next: function() {
+                _this.changeSlide(true);
+              },
+              previous: function() {
+                _this.changeSlide(false);
+              },
+              handled: function() { // if bullet is focused, make sure focus moves
+                if ($(e.target).is(_this.$bullets)) {
+                  _this.$bullets.filter('.is-active').focus();
+                }
+              }
+            });
+          });
         }
-      });
-    });
-  };
-  /**
-   * Changes the current slide to a new one.
-   * @function
-   * @param {Boolean} isLTR - flag if the slide should move left to right.
-   * @param {jQuery} chosenSlide - the jQuery element of the slide to show next, if one is selected.
-   * @param {Number} idx - the index of the new slide in its collection, if one chosen.
-   * @fires Orbit#slidechange
-   */
-  Orbit.prototype.changeSlide = function(isLTR, chosenSlide, idx){
-    var $curSlide = this.$slides.filter('.is-active').eq(0);
+      };
+      /**
+      * Changes the current slide to a new one.
+      * @function
+      * @param {Boolean} isLTR - flag if the slide should move left to right.
+      * @param {jQuery} chosenSlide - the jQuery element of the slide to show next, if one is selected.
+      * @param {Number} idx - the index of the new slide in its collection, if one chosen.
+      * @fires Orbit#slidechange
+      */
+      Orbit.prototype.changeSlide = function(isLTR, chosenSlide, idx){
+        var $curSlide = this.$slides.filter('.is-active').eq(0);
 
-    if(/mui/g.test($curSlide[0].className)){ return false; }//if the slide is currently animating, kick out of the function
+        if(/mui/g.test($curSlide[0].className)){ return false; }//if the slide is currently animating, kick out of the function
 
-    var $firstSlide = this.$slides.first(),
+        var $firstSlide = this.$slides.first(),
         $lastSlide = this.$slides.last(),
         dirIn = isLTR ? 'Right' : 'Left',
         dirOut = isLTR ? 'Left' : 'Right',
         _this = this,
         $newSlide;
 
-    if(!chosenSlide){//most of the time, this will be auto played or clicked from the navButtons.
-      $newSlide = isLTR ? //if wrapping enabled, check to see if there is a `next` or `prev` sibling, if not, select the first or last slide to fill in. if wrapping not enabled, attempt to select `next` or `prev`, if there's nothing there, the function will kick out on next step. CRAZY NESTED TERNARIES!!!!!
-                    (this.options.infiniteWrap ? $curSlide.next('.' + this.options.slideClass).length ? $curSlide.next('.' + this.options.slideClass) : $firstSlide : $curSlide.next('.' + this.options.slideClass))//pick next slide if moving left to right
-                    :
-                    (this.options.infiniteWrap ? $curSlide.prev('.' + this.options.slideClass).length ? $curSlide.prev('.' + this.options.slideClass) : $lastSlide : $curSlide.prev('.' + this.options.slideClass));//pick prev slide if moving right to left
-    }else{
-      $newSlide = chosenSlide;
-    }
-    if($newSlide.length){
-      if(this.options.bullets){
-        idx = idx || this.$slides.index($newSlide);//grab index to update bullets
-        this._updateBullets(idx);
-      }
-      if(this.options.useMUI){
+        if(!chosenSlide){//most of the time, this will be auto played or clicked from the navButtons.
+          $newSlide = isLTR ? //if wrapping enabled, check to see if there is a `next` or `prev` sibling, if not, select the first or last slide to fill in. if wrapping not enabled, attempt to select `next` or `prev`, if there's nothing there, the function will kick out on next step. CRAZY NESTED TERNARIES!!!!!
+          (this.options.infiniteWrap ? $curSlide.next('.' + this.options.slideClass).length ? $curSlide.next('.' + this.options.slideClass) : $firstSlide : $curSlide.next('.' + this.options.slideClass))//pick next slide if moving left to right
+          :
+          (this.options.infiniteWrap ? $curSlide.prev('.' + this.options.slideClass).length ? $curSlide.prev('.' + this.options.slideClass) : $lastSlide : $curSlide.prev('.' + this.options.slideClass));//pick prev slide if moving right to left
+        }else{
+          $newSlide = chosenSlide;
+        }
+        if($newSlide.length){
+          if(this.options.bullets){
+            idx = idx || this.$slides.index($newSlide);//grab index to update bullets
+            this._updateBullets(idx);
+          }
+          if(this.options.useMUI){
 
-        Foundation.Motion.animateIn(
-          $newSlide.addClass('is-active').css({'position': 'absolute', 'top': 0}),
-          this.options['animInFrom' + dirIn],
-          function(){
-            $newSlide.css({'position': 'relative', 'display': 'block'})
-                     .attr('aria-live', 'polite');
-          });
+            Foundation.Motion.animateIn(
+              $newSlide.addClass('is-active').css({'position': 'absolute', 'top': 0}),
+              this.options['animInFrom' + dirIn],
+              function(){
+                $newSlide.css({'position': 'relative', 'display': 'block'})
+                .attr('aria-live', 'polite');
+              });
 
-        Foundation.Motion.animateOut(
-          $curSlide.removeClass('is-active'),
-          this.options['animOutTo' + dirOut],
-          function(){
-            $curSlide.removeAttr('aria-live');
-            if(_this.options.autoPlay){
-              _this.timer.restart();
+              Foundation.Motion.animateOut(
+                $curSlide.removeClass('is-active'),
+                this.options['animOutTo' + dirOut],
+                function(){
+                  $curSlide.removeAttr('aria-live');
+                  if(_this.options.autoPlay){
+                    _this.timer.restart();
+                  }
+                  //do stuff?
+                });
+              }else{
+                $curSlide.removeClass('is-active is-in').removeAttr('aria-live').hide();
+                $newSlide.addClass('is-active is-in').attr('aria-live', 'polite').show();
+                if(this.options.autoPlay){
+                  this.timer.restart();
+                }
+              }
+              /**
+              * Triggers when the slide has finished animating in.
+              * @event Orbit#slidechange
+              */
+              this.$element.trigger('slidechange.zf.orbit', [$newSlide]);
             }
-            //do stuff?
-          });
-      }else{
-        $curSlide.removeClass('is-active is-in').removeAttr('aria-live').hide();
-        $newSlide.addClass('is-active is-in').attr('aria-live', 'polite').show();
-        if(this.options.autoPlay){
-          this.timer.restart();
-        }
-      }
-      /**
-       * Triggers when the slide has finished animating in.
-       * @event Orbit#slidechange
-       */
-      this.$element.trigger('slidechange.zf.orbit', [$newSlide]);
-    }
-  };
-  /**
-   * Updates the active state of the bullets, if displayed.
-   * @function
-   * @private
-   * @param {Number} idx - the index of the current slide.
-   */
-  Orbit.prototype._updateBullets = function(idx){
-    var $oldBullet = this.$element.find('.' + this.options.boxOfBullets)
-                                  .find('.is-active').removeClass('is-active').blur(),
-        span = $oldBullet.find('span:last').detach(),
-        $newBullet = this.$bullets.eq(idx).addClass('is-active').append(span);
-  };
-  /**
-   * Destroys the carousel and hides the element.
-   * @function
-   */
-  Orbit.prototype.destroy = function(){
-    this.$element.off('.zf.orbit').find('*').off('.zf.orbit').end().hide();
-    Foundation.unregisterPlugin(this);
-  };
+          };
+          /**
+          * Updates the active state of the bullets, if displayed.
+          * @function
+          * @private
+          * @param {Number} idx - the index of the current slide.
+          */
+          Orbit.prototype._updateBullets = function(idx){
+            var $oldBullet = this.$element.find('.' + this.options.boxOfBullets)
+            .find('.is-active').removeClass('is-active').blur(),
+            span = $oldBullet.find('span:last').detach(),
+            $newBullet = this.$bullets.eq(idx).addClass('is-active').append(span);
+          };
+          /**
+          * Destroys the carousel and hides the element.
+          * @function
+          */
+          Orbit.prototype.destroy = function(){
+            this.$element.off('.zf.orbit').find('*').off('.zf.orbit').end().hide();
+            Foundation.unregisterPlugin(this);
+          };
 
-  Foundation.plugin(Orbit, 'Orbit');
+          Foundation.plugin(Orbit, 'Orbit');
 
-}(jQuery, window.Foundation);
+        }(jQuery, window.Foundation);