text: /**
   * 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 accordion menu.
     * @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);
  
      this._init();
  
      Foundation.registerPlugin(this);
      Foundation.Keyboard.register('Orbit', {
          'ltr': {
            'ARROW_RIGHT': 'next',
            'ARROW_LEFT': 'previous'
          },
          'rtl': {
            'ARROW_LEFT': 'next',
            'ARROW_RIGHT': 'previous'
          }
      });
    }
    Orbit.defaults = {
      /**
       * Tells the JS to loadBullets.
       * @option
       * @example true
       */
      bullets: 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'
       */
      animInFromRight: 'slide-in-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'
       *
       */
      animInFromLeft: 'slide-in-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
       */
      autoPlay: true,
      /**
       * Amount of time, in ms, between slide transitions
       * @option
       * @example 5000
       */
      timerDelay: 5000,
      /**
       * 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
       */
      swipe: 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
       */
      accessible: true,
      /**
       * Class applied to the container of Orbit
       * @option
       * @example 'orbit-container'
       */
      containerClass: 'orbit-container',
      /**
       * 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'
       */
      boxOfBullets: 'orbit-bullets',
      /**
       * 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'
       */
      prevClass: 'orbit-previous'
    };
    /**
     * 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');
  
      if($images.length){
        Foundation.onImagesLoaded($images, this._prepareForOrbit.bind(this));
      }else{
        this._prepareForOrbit();//hehe
      }
  
      if(this.options.bullets){
        this._loadBullets();
      }
  
      this._events();
  
      if(this.options.autoPlay){
        this.geoSync();
      }
      if(this.options.accessible){ // allow wrapper to be focusable to enable arrow navigation
        this.$wrapper.attr('tabindex', 0);
      }
    };
    /**
     * 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
     */
    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.$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 === 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);
        });
      }
      //***************************************
  
      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.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.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.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, _this, {
          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);
  
  
      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(),
          $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);
        }
        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();
            }
            //do stuff?
            /**
             * 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(){
      delete this.timer;
      this.$element.off('.zf.orbit').find('*').off('.zf.orbit').end().hide();
      Foundation.unregisterPlugin(this);
    };
  
    Foundation.plugin(Orbit);
  
  }(jQuery, window.Foundation);
  