Template:Heidelberg/js/jqueryjcarousel

/*! jCarousel - v0.3.3 - 2015-04-07

  • http://sorgalla.com/jcarousel/
  • Copyright (c) 2006-2015 Jan Sorgalla; Licensed MIT */

(function($) {

   'use strict';
   var jCarousel = $.jCarousel = {};
   jCarousel.version = '0.3.3';
   var rRelativeTarget = /^([+\-]=)?(.+)$/;
   jCarousel.parseTarget = function(target) {
       var relative = false,
           parts    = typeof target !== 'object' ?
                          rRelativeTarget.exec(target) :
                          null;
       if (parts) {
           target = parseInt(parts[2], 10) || 0;
           if (parts[1]) {
               relative = true;
               if (parts[1] === '-=') {
                   target *= -1;
               }
           }
       } else if (typeof target !== 'object') {
           target = parseInt(target, 10) || 0;
       }
       return {
           target: target,
           relative: relative
       };
   };
   jCarousel.detectCarousel = function(element) {
       var carousel;
       while (element.length > 0) {
           carousel = element.filter('[data-jcarousel]');
           if (carousel.length > 0) {
               return carousel;
           }
           carousel = element.find('[data-jcarousel]');
           if (carousel.length > 0) {
               return carousel;
           }
           element = element.parent();
       }
       return null;
   };
   jCarousel.base = function(pluginName) {
       return {
           version:  jCarousel.version,
           _options:  {},
           _element:  null,
           _carousel: null,
           _init:     $.noop,
           _create:   $.noop,
           _destroy:  $.noop,
           _reload:   $.noop,
           create: function() {
               this._element
                   .attr('data-' + pluginName.toLowerCase(), true)
                   .data(pluginName, this);
               if (false === this._trigger('create')) {
                   return this;
               }
               this._create();
               this._trigger('createend');
               return this;
           },
           destroy: function() {
               if (false === this._trigger('destroy')) {
                   return this;
               }
               this._destroy();
               this._trigger('destroyend');
               this._element
                   .removeData(pluginName)
                   .removeAttr('data-' + pluginName.toLowerCase());
               return this;
           },
           reload: function(options) {
               if (false === this._trigger('reload')) {
                   return this;
               }
               if (options) {
                   this.options(options);
               }
               this._reload();
               this._trigger('reloadend');
               return this;
           },
           element: function() {
               return this._element;
           },
           options: function(key, value) {
               if (arguments.length === 0) {
                   return $.extend({}, this._options);
               }
               if (typeof key === 'string') {
                   if (typeof value === 'undefined') {
                       return typeof this._options[key] === 'undefined' ?
                               null :
                               this._options[key];
                   }
                   this._options[key] = value;
               } else {
                   this._options = $.extend({}, this._options, key);
               }
               return this;
           },
           carousel: function() {
               if (!this._carousel) {
                   this._carousel = jCarousel.detectCarousel(this.options('carousel') || this._element);
                   if (!this._carousel) {
                       $.error('Could not detect carousel for plugin "' + pluginName + '"');
                   }
               }
               return this._carousel;
           },
           _trigger: function(type, element, data) {
               var event,
                   defaultPrevented = false;
               data = [this].concat(data || []);
               (element || this._element).each(function() {
                   event = $.Event((pluginName + ':' + type).toLowerCase());
                   $(this).trigger(event, data);
                   if (event.isDefaultPrevented()) {
                       defaultPrevented = true;
                   }
               });
               return !defaultPrevented;
           }
       };
   };
   jCarousel.plugin = function(pluginName, pluginPrototype) {
       var Plugin = $[pluginName] = function(element, options) {
           this._element = $(element);
           this.options(options);
           this._init();
           this.create();
       };
       Plugin.fn = Plugin.prototype = $.extend(
           {},
           jCarousel.base(pluginName),
           pluginPrototype
       );
       $.fn[pluginName] = function(options) {
           var args        = Array.prototype.slice.call(arguments, 1),
               returnValue = this;
           if (typeof options === 'string') {
               this.each(function() {
                   var instance = $(this).data(pluginName);
                   if (!instance) {
                       return $.error(
                           'Cannot call methods on ' + pluginName + ' prior to initialization; ' +
                           'attempted to call method "' + options + '"'
                       );
                   }
                   if (!$.isFunction(instance[options]) || options.charAt(0) === '_') {
                       return $.error(
                           'No such method "' + options + '" for ' + pluginName + ' instance'
                       );
                   }
                   var methodValue = instance[options].apply(instance, args);
                   if (methodValue !== instance && typeof methodValue !== 'undefined') {
                       returnValue = methodValue;
                       return false;
                   }
               });
           } else {
               this.each(function() {
                   var instance = $(this).data(pluginName);
                   if (instance instanceof Plugin) {
                       instance.reload(options);
                   } else {
                       new Plugin(this, options);
                   }
               });
           }
           return returnValue;
       };
       return Plugin;
   };

}(jQuery));

(function($, window) {

   'use strict';
   var toFloat = function(val) {
       return parseFloat(val) || 0;
   };
   $.jCarousel.plugin('jcarousel', {
       animating:   false,
       tail:        0,
       inTail:      false,
       resizeTimer: null,
       lt:          null,
       vertical:    false,
       rtl:         false,
       circular:    false,
       underflow:   false,
       relative:    false,
       _options: {
           list: function() {
               return this.element().children().eq(0);
           },
           items: function() {
               return this.list().children();
           },
           animation:   400,
           transitions: false,
           wrap:        null,
           vertical:    null,
           rtl:         null,
           center:      false
       },
       // Protected, don't access directly
       _list:         null,
       _items:        null,
       _target:       $(),
       _first:        $(),
       _last:         $(),
       _visible:      $(),
       _fullyvisible: $(),
       _init: function() {
           var self = this;
           this.onWindowResize = function() {
               if (self.resizeTimer) {
                   clearTimeout(self.resizeTimer);
               }
               self.resizeTimer = setTimeout(function() {
                   self.reload();
               }, 100);
           };
           return this;
       },
       _create: function() {
           this._reload();
           $(window).on('resize.jcarousel', this.onWindowResize);
       },
       _destroy: function() {
           $(window).off('resize.jcarousel', this.onWindowResize);
       },
       _reload: function() {
           this.vertical = this.options('vertical');
           if (this.vertical == null) {
               this.vertical = this.list().height() > this.list().width();
           }
           this.rtl = this.options('rtl');
           if (this.rtl == null) {
               this.rtl = (function(element) {
                   if (( + element.attr('dir')).toLowerCase() === 'rtl') {
                       return true;
                   }
                   var found = false;
                   element.parents('[dir]').each(function() {
                       if ((/rtl/i).test($(this).attr('dir'))) {
                           found = true;
                           return false;
                       }
                   });
                   return found;
               }(this._element));
           }
           this.lt = this.vertical ? 'top' : 'left';
           // Ensure before closest() call
           this.relative = this.list().css('position') === 'relative';
           // Force list and items reload
           this._list  = null;
           this._items = null;
           var item = this.index(this._target) >= 0 ?
                          this._target :
                          this.closest();
           // _prepare() needs this here
           this.circular  = this.options('wrap') === 'circular';
           this.underflow = false;
           var props = {'left': 0, 'top': 0};
           if (item.length > 0) {
               this._prepare(item);
               this.list().find('[data-jcarousel-clone]').remove();
               // Force items reload
               this._items = null;
               this.underflow = this._fullyvisible.length >= this.items().length;
               this.circular  = this.circular && !this.underflow;
               props[this.lt] = this._position(item) + 'px';
           }
           this.move(props);
           return this;
       },
       list: function() {
           if (this._list === null) {
               var option = this.options('list');
               this._list = $.isFunction(option) ? option.call(this) : this._element.find(option);
           }
           return this._list;
       },
       items: function() {
           if (this._items === null) {
               var option = this.options('items');
               this._items = ($.isFunction(option) ? option.call(this) : this.list().find(option)).not('[data-jcarousel-clone]');
           }
           return this._items;
       },
       index: function(item) {
           return this.items().index(item);
       },
       closest: function() {
           var self    = this,
               pos     = this.list().position()[this.lt],
               closest = $(), // Ensure we're returning a jQuery instance
               stop    = false,
               lrb     = this.vertical ? 'bottom' : (this.rtl && !this.relative ? 'left' : 'right'),
               width;
           if (this.rtl && this.relative && !this.vertical) {
               pos += this.list().width() - this.clipping();
           }
           this.items().each(function() {
               closest = $(this);
               if (stop) {
                   return false;
               }
               var dim = self.dimension(closest);
               pos += dim;
               if (pos >= 0) {
                   width = dim - toFloat(closest.css('margin-' + lrb));
                   if ((Math.abs(pos) - dim + (width / 2)) <= 0) {
                       stop = true;
                   } else {
                       return false;
                   }
               }
           });


           return closest;
       },
       target: function() {
           return this._target;
       },
       first: function() {
           return this._first;
       },
       last: function() {
           return this._last;
       },
       visible: function() {
           return this._visible;
       },
       fullyvisible: function() {
           return this._fullyvisible;
       },
       hasNext: function() {
           if (false === this._trigger('hasnext')) {
               return true;
           }
           var wrap = this.options('wrap'),
               end = this.items().length - 1,
               check = this.options('center') ? this._target : this._last;
           return end >= 0 && !this.underflow &&
               ((wrap && wrap !== 'first') ||
                   (this.index(check) < end) ||
                   (this.tail && !this.inTail)) ? true : false;
       },
       hasPrev: function() {
           if (false === this._trigger('hasprev')) {
               return true;
           }
           var wrap = this.options('wrap');
           return this.items().length > 0 && !this.underflow &&
               ((wrap && wrap !== 'last') ||
                   (this.index(this._first) > 0) ||
                   (this.tail && this.inTail)) ? true : false;
       },
       clipping: function() {
           return this._element['inner' + (this.vertical ? 'Height' : 'Width')]();
       },
       dimension: function(element) {
           return element['outer' + (this.vertical ? 'Height' : 'Width')](true);
       },
       scroll: function(target, animate, callback) {
           if (this.animating) {
               return this;
           }
           if (false === this._trigger('scroll', null, [target, animate])) {
               return this;
           }
           if ($.isFunction(animate)) {
               callback = animate;
               animate  = true;
           }
           var parsed = $.jCarousel.parseTarget(target);
           if (parsed.relative) {
               var end    = this.items().length - 1,
                   scroll = Math.abs(parsed.target),
                   wrap   = this.options('wrap'),
                   current,
                   first,
                   index,
                   start,
                   curr,
                   isVisible,
                   props,
                   i;
               if (parsed.target > 0) {
                   var last = this.index(this._last);
                   if (last >= end && this.tail) {
                       if (!this.inTail) {
                           this._scrollTail(animate, callback);
                       } else {
                           if (wrap === 'both' || wrap === 'last') {
                               this._scroll(0, animate, callback);
                           } else {
                               if ($.isFunction(callback)) {
                                   callback.call(this, false);
                               }
                           }
                       }
                   } else {
                       current = this.index(this._target);
                       if ((this.underflow && current === end && (wrap === 'circular' || wrap === 'both' || wrap === 'last')) ||
                           (!this.underflow && last === end && (wrap === 'both' || wrap === 'last'))) {
                           this._scroll(0, animate, callback);
                       } else {
                           index = current + scroll;
                           if (this.circular && index > end) {
                               i = end;
                               curr = this.items().get(-1);
                               while (i++ < index) {
                                   curr = this.items().eq(0);
                                   isVisible = this._visible.index(curr) >= 0;
                                   if (isVisible) {
                                       curr.after(curr.clone(true).attr('data-jcarousel-clone', true));
                                   }
                                   this.list().append(curr);
                                   if (!isVisible) {
                                       props = {};
                                       props[this.lt] = this.dimension(curr);
                                       this.moveBy(props);
                                   }
                                   // Force items reload
                                   this._items = null;
                               }
                               this._scroll(curr, animate, callback);
                           } else {
                               this._scroll(Math.min(index, end), animate, callback);
                           }
                       }
                   }
               } else {
                   if (this.inTail) {
                       this._scroll(Math.max((this.index(this._first) - scroll) + 1, 0), animate, callback);
                   } else {
                       first  = this.index(this._first);
                       current = this.index(this._target);
                       start  = this.underflow ? current : first;
                       index  = start - scroll;
                       if (start <= 0 && ((this.underflow && wrap === 'circular') || wrap === 'both' || wrap === 'first')) {
                           this._scroll(end, animate, callback);
                       } else {
                           if (this.circular && index < 0) {
                               i    = index;
                               curr = this.items().get(0);
                               while (i++ < 0) {
                                   curr = this.items().eq(-1);
                                   isVisible = this._visible.index(curr) >= 0;
                                   if (isVisible) {
                                       curr.after(curr.clone(true).attr('data-jcarousel-clone', true));
                                   }
                                   this.list().prepend(curr);
                                   // Force items reload
                                   this._items = null;
                                   var dim = this.dimension(curr);
                                   props = {};
                                   props[this.lt] = -dim;
                                   this.moveBy(props);
                               }
                               this._scroll(curr, animate, callback);
                           } else {
                               this._scroll(Math.max(index, 0), animate, callback);
                           }
                       }
                   }
               }
           } else {
               this._scroll(parsed.target, animate, callback);
           }
           this._trigger('scrollend');
           return this;
       },
       moveBy: function(properties, opts) {
           var position = this.list().position(),
               multiplier = 1,
               correction = 0;
           if (this.rtl && !this.vertical) {
               multiplier = -1;
               if (this.relative) {
                   correction = this.list().width() - this.clipping();
               }
           }
           if (properties.left) {
               properties.left = (position.left + correction + toFloat(properties.left) * multiplier) + 'px';
           }
           if (properties.top) {
               properties.top = (position.top + correction + toFloat(properties.top) * multiplier) + 'px';
           }
           return this.move(properties, opts);
       },
       move: function(properties, opts) {
           opts = opts || {};
           var option       = this.options('transitions'),
               transitions  = !!option,
               transforms   = !!option.transforms,
               transforms3d = !!option.transforms3d,
               duration     = opts.duration || 0,
               list         = this.list();
           if (!transitions && duration > 0) {
               list.animate(properties, opts);
               return;
           }
           var complete = opts.complete || $.noop,
               css = {};
           if (transitions) {
               var backup = {
                       transitionDuration: list.css('transitionDuration'),
                       transitionTimingFunction: list.css('transitionTimingFunction'),
                       transitionProperty: list.css('transitionProperty')
                   },
                   oldComplete = complete;
               complete = function() {
                   $(this).css(backup);
                   oldComplete.call(this);
               };
               css = {
                   transitionDuration: (duration > 0 ? duration / 1000 : 0) + 's',
                   transitionTimingFunction: option.easing || opts.easing,
                   transitionProperty: duration > 0 ? (function() {
                       if (transforms || transforms3d) {
                           // We have to use 'all' because jQuery doesn't prefix
                           // css values, like transition-property: transform;
                           return 'all';
                       }
                       return properties.left ? 'left' : 'top';
                   })() : 'none',
                   transform: 'none'
               };
           }
           if (transforms3d) {
               css.transform = 'translate3d(' + (properties.left || 0) + ',' + (properties.top || 0) + ',0)';
           } else if (transforms) {
               css.transform = 'translate(' + (properties.left || 0) + ',' + (properties.top || 0) + ')';
           } else {
               $.extend(css, properties);
           }
           if (transitions && duration > 0) {
               list.one('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', complete);
           }
           list.css(css);
           if (duration <= 0) {
               list.each(function() {
                   complete.call(this);
               });
           }
       },
       _scroll: function(item, animate, callback) {
           if (this.animating) {
               if ($.isFunction(callback)) {
                   callback.call(this, false);
               }
               return this;
           }
           if (typeof item !== 'object') {
               item = this.items().eq(item);
           } else if (typeof item.jquery === 'undefined') {
               item = $(item);
           }
           if (item.length === 0) {
               if ($.isFunction(callback)) {
                   callback.call(this, false);
               }
               return this;
           }
           this.inTail = false;
           this._prepare(item);
           var pos     = this._position(item),
               currPos = this.list().position()[this.lt];
           if (pos === currPos) {
               if ($.isFunction(callback)) {
                   callback.call(this, false);
               }
               return this;
           }
           var properties = {};
           properties[this.lt] = pos + 'px';
           this._animate(properties, animate, callback);
           return this;
       },
       _scrollTail: function(animate, callback) {
           if (this.animating || !this.tail) {
               if ($.isFunction(callback)) {
                   callback.call(this, false);
               }
               return this;
           }
           var pos = this.list().position()[this.lt];
           if (this.rtl && this.relative && !this.vertical) {
               pos += this.list().width() - this.clipping();
           }
           if (this.rtl && !this.vertical) {
               pos += this.tail;
           } else {
               pos -= this.tail;
           }
           this.inTail = true;
           var properties = {};
           properties[this.lt] = pos + 'px';
           this._update({
               target:       this._target.next(),
               fullyvisible: this._fullyvisible.slice(1).add(this._visible.last())
           });
           this._animate(properties, animate, callback);
           return this;
       },
       _animate: function(properties, animate, callback) {
           callback = callback || $.noop;
           if (false === this._trigger('animate')) {
               callback.call(this, false);
               return this;
           }
           this.animating = true;
           var animation = this.options('animation'),
               complete  = $.proxy(function() {
                   this.animating = false;
                   var c = this.list().find('[data-jcarousel-clone]');
                   if (c.length > 0) {
                       c.remove();
                       this._reload();
                   }
                   this._trigger('animateend');
                   callback.call(this, true);
               }, this);
           var opts = typeof animation === 'object' ?
                          $.extend({}, animation) :
                          {duration: animation},
               oldComplete = opts.complete || $.noop;
           if (animate === false) {
               opts.duration = 0;
           } else if (typeof $.fx.speeds[opts.duration] !== 'undefined') {
               opts.duration = $.fx.speeds[opts.duration];
           }
           opts.complete = function() {
               complete();
               oldComplete.call(this);
           };
           this.move(properties, opts);
           return this;
       },
       _prepare: function(item) {
           var index  = this.index(item),
               idx    = index,
               wh     = this.dimension(item),
               clip   = this.clipping(),
               lrb    = this.vertical ? 'bottom' : (this.rtl ? 'left'  : 'right'),
               center = this.options('center'),
               update = {
                   target:       item,
                   first:        item,
                   last:         item,
                   visible:      item,
                   fullyvisible: wh <= clip ? item : $()
               },
               curr,
               isVisible,
               margin,
               dim;
           if (center) {
               wh /= 2;
               clip /= 2;
           }
           if (wh < clip) {
               while (true) {
                   curr = this.items().eq(++idx);
                   if (curr.length === 0) {
                       if (!this.circular) {
                           break;
                       }
                       curr = this.items().eq(0);
                       if (item.get(0) === curr.get(0)) {
                           break;
                       }
                       isVisible = this._visible.index(curr) >= 0;
                       if (isVisible) {
                           curr.after(curr.clone(true).attr('data-jcarousel-clone', true));
                       }
                       this.list().append(curr);
                       if (!isVisible) {
                           var props = {};
                           props[this.lt] = this.dimension(curr);
                           this.moveBy(props);
                       }
                       // Force items reload
                       this._items = null;
                   }
                   dim = this.dimension(curr);
                   if (dim === 0) {
                       break;
                   }
                   wh += dim;
                   update.last    = curr;
                   update.visible = update.visible.add(curr);
                   // Remove right/bottom margin from total width
                   margin = toFloat(curr.css('margin-' + lrb));
                   if ((wh - margin) <= clip) {
                       update.fullyvisible = update.fullyvisible.add(curr);
                   }
                   if (wh >= clip) {
                       break;
                   }
               }
           }
           if (!this.circular && !center && wh < clip) {
               idx = index;
               while (true) {
                   if (--idx < 0) {
                       break;
                   }
                   curr = this.items().eq(idx);
                   if (curr.length === 0) {
                       break;
                   }
                   dim = this.dimension(curr);
                   if (dim === 0) {
                       break;
                   }
                   wh += dim;
                   update.first   = curr;
                   update.visible = update.visible.add(curr);
                   // Remove right/bottom margin from total width
                   margin = toFloat(curr.css('margin-' + lrb));
                   if ((wh - margin) <= clip) {
                       update.fullyvisible = update.fullyvisible.add(curr);
                   }
                   if (wh >= clip) {
                       break;
                   }
               }
           }
           this._update(update);
           this.tail = 0;
           if (!center &&
               this.options('wrap') !== 'circular' &&
               this.options('wrap') !== 'custom' &&
               this.index(update.last) === (this.items().length - 1)) {
               // Remove right/bottom margin from total width
               wh -= toFloat(update.last.css('margin-' + lrb));
               if (wh > clip) {
                   this.tail = wh - clip;
               }
           }
           return this;
       },
       _position: function(item) {
           var first  = this._first,
               pos    = first.position()[this.lt],
               center = this.options('center'),
               centerOffset = center ? (this.clipping() / 2) - (this.dimension(first) / 2) : 0;
           if (this.rtl && !this.vertical) {
               if (this.relative) {
                   pos -= this.list().width() - this.dimension(first);
               } else {
                   pos -= this.clipping() - this.dimension(first);
               }
               pos += centerOffset;
           } else {
               pos -= centerOffset;
           }
           if (!center &&
               (this.index(item) > this.index(first) || this.inTail) &&
               this.tail) {
               pos = this.rtl && !this.vertical ? pos - this.tail : pos + this.tail;
               this.inTail = true;
           } else {
               this.inTail = false;
           }
           return -pos;
       },
       _update: function(update) {
           var self = this,
               current = {
                   target:       this._target,
                   first:        this._first,
                   last:         this._last,
                   visible:      this._visible,
                   fullyvisible: this._fullyvisible
               },
               back = this.index(update.first || current.first) < this.index(current.first),
               key,
               doUpdate = function(key) {
                   var elIn  = [],
                       elOut = [];
                   update[key].each(function() {
                       if (current[key].index(this) < 0) {
                           elIn.push(this);
                       }
                   });
                   current[key].each(function() {
                       if (update[key].index(this) < 0) {
                           elOut.push(this);
                       }
                   });
                   if (back) {
                       elIn = elIn.reverse();
                   } else {
                       elOut = elOut.reverse();
                   }
                   self._trigger(key + 'in', $(elIn));
                   self._trigger(key + 'out', $(elOut));
                   self['_' + key] = update[key];
               };
           for (key in update) {
               doUpdate(key);
           }
           return this;
       }
   });

}(jQuery, window));

(function($) {

   'use strict';
   $.jcarousel.fn.scrollIntoView = function(target, animate, callback) {
       var parsed = $.jCarousel.parseTarget(target),
           first  = this.index(this._fullyvisible.first()),
           last   = this.index(this._fullyvisible.last()),
           index;
       if (parsed.relative) {
           index = parsed.target < 0 ? Math.max(0, first + parsed.target) : last + parsed.target;
       } else {
           index = typeof parsed.target !== 'object' ? parsed.target : this.index(parsed.target);
       }
       if (index < first) {
           return this.scroll(index, animate, callback);
       }
       if (index >= first && index <= last) {
           if ($.isFunction(callback)) {
               callback.call(this, false);
           }
           return this;
       }
       var items = this.items(),
           clip = this.clipping(),
           lrb  = this.vertical ? 'bottom' : (this.rtl ? 'left'  : 'right'),
           wh   = 0,
           curr;
       while (true) {
           curr = items.eq(index);
           if (curr.length === 0) {
               break;
           }
           wh += this.dimension(curr);
           if (wh >= clip) {
               var margin = parseFloat(curr.css('margin-' + lrb)) || 0;
               if ((wh - margin) !== clip) {
                   index++;
               }
               break;
           }
           if (index <= 0) {
               break;
           }
           index--;
       }
       return this.scroll(index, animate, callback);
   };

}(jQuery));

(function($) {

   'use strict';
   $.jCarousel.plugin('jcarouselControl', {
       _options: {
           target: '+=1',
           event:  'click',
           method: 'scroll'
       },
       _active: null,
       _init: function() {
           this.onDestroy = $.proxy(function() {
               this._destroy();
               this.carousel()
                   .one('jcarousel:createend', $.proxy(this._create, this));
           }, this);
           this.onReload = $.proxy(this._reload, this);
           this.onEvent = $.proxy(function(e) {
               e.preventDefault();
               var method = this.options('method');
               if ($.isFunction(method)) {
                   method.call(this);
               } else {
                   this.carousel()
                       .jcarousel(this.options('method'), this.options('target'));
               }
           }, this);
       },
       _create: function() {
           this.carousel()
               .one('jcarousel:destroy', this.onDestroy)
               .on('jcarousel:reloadend jcarousel:scrollend', this.onReload);
           this._element
               .on(this.options('event') + '.jcarouselcontrol', this.onEvent);
           this._reload();
       },
       _destroy: function() {
           this._element
               .off('.jcarouselcontrol', this.onEvent);
           this.carousel()
               .off('jcarousel:destroy', this.onDestroy)
               .off('jcarousel:reloadend jcarousel:scrollend', this.onReload);
       },
       _reload: function() {
           var parsed   = $.jCarousel.parseTarget(this.options('target')),
               carousel = this.carousel(),
               active;
           if (parsed.relative) {
               active = carousel
                   .jcarousel(parsed.target > 0 ? 'hasNext' : 'hasPrev');
           } else {
               var target = typeof parsed.target !== 'object' ?
                               carousel.jcarousel('items').eq(parsed.target) :
                               parsed.target;
               active = carousel.jcarousel('target').index(target) >= 0;
           }
           if (this._active !== active) {
               this._trigger(active ? 'active' : 'inactive');
               this._active = active;
           }
           return this;
       }
   });

}(jQuery));

(function($) {

   'use strict';
   $.jCarousel.plugin('jcarouselPagination', {
       _options: {
           perPage: null,
           item: function(page) {
               return '<a href="#' + page + '">' + page + '</a>';
           },
           event:  'click',
           method: 'scroll'
       },
       _carouselItems: null,
       _pages: {},
       _items: {},
       _currentPage: null,
       _init: function() {
           this.onDestroy = $.proxy(function() {
               this._destroy();
               this.carousel()
                   .one('jcarousel:createend', $.proxy(this._create, this));
           }, this);
           this.onReload = $.proxy(this._reload, this);
           this.onScroll = $.proxy(this._update, this);
       },
       _create: function() {
           this.carousel()
               .one('jcarousel:destroy', this.onDestroy)
               .on('jcarousel:reloadend', this.onReload)
               .on('jcarousel:scrollend', this.onScroll);
           this._reload();
       },
       _destroy: function() {
           this._clear();
           this.carousel()
               .off('jcarousel:destroy', this.onDestroy)
               .off('jcarousel:reloadend', this.onReload)
               .off('jcarousel:scrollend', this.onScroll);
           this._carouselItems = null;
       },
       _reload: function() {
           var perPage = this.options('perPage');
           this._pages = {};
           this._items = {};
           // Calculate pages
           if ($.isFunction(perPage)) {
               perPage = perPage.call(this);
           }
           if (perPage == null) {
               this._pages = this._calculatePages();
           } else {
               var pp    = parseInt(perPage, 10) || 0,
                   items = this._getCarouselItems(),
                   page  = 1,
                   i     = 0,
                   curr;
               while (true) {
                   curr = items.eq(i++);
                   if (curr.length === 0) {
                       break;
                   }
                   if (!this._pages[page]) {
                       this._pages[page] = curr;
                   } else {
                       this._pages[page] = this._pages[page].add(curr);
                   }
                   if (i % pp === 0) {
                       page++;
                   }
               }
           }
           this._clear();
           var self     = this,
               carousel = this.carousel().data('jcarousel'),
               element  = this._element,
               item     = this.options('item'),
               numCarouselItems = this._getCarouselItems().length;
           $.each(this._pages, function(page, carouselItems) {
               var currItem = self._items[page] = $(item.call(self, page, carouselItems));
               currItem.on(self.options('event') + '.jcarouselpagination', $.proxy(function() {
                   var target = carouselItems.eq(0);
                   // If circular wrapping enabled, ensure correct scrolling direction
                   if (carousel.circular) {
                       var currentIndex = carousel.index(carousel.target()),
                           newIndex     = carousel.index(target);
                       if (parseFloat(page) > parseFloat(self._currentPage)) {
                           if (newIndex < currentIndex) {
                               target = '+=' + (numCarouselItems - currentIndex + newIndex);
                           }
                       } else {
                           if (newIndex > currentIndex) {
                               target = '-=' + (currentIndex + (numCarouselItems - newIndex));
                           }
                       }
                   }
                   carousel[this.options('method')](target);
               }, self));
               element.append(currItem);
           });
           this._update();
       },
       _update: function() {
           var target = this.carousel().jcarousel('target'),
               currentPage;
           $.each(this._pages, function(page, carouselItems) {
               carouselItems.each(function() {
                   if (target.is(this)) {
                       currentPage = page;
                       return false;
                   }
               });
               if (currentPage) {
                   return false;
               }
           });
           if (this._currentPage !== currentPage) {
               this._trigger('inactive', this._items[this._currentPage]);
               this._trigger('active', this._items[currentPage]);
           }
           this._currentPage = currentPage;
       },
       items: function() {
           return this._items;
       },
       reloadCarouselItems: function() {
           this._carouselItems = null;
           return this;
       },
       _clear: function() {
           this._element.empty();
           this._currentPage = null;
       },
       _calculatePages: function() {
           var carousel = this.carousel().data('jcarousel'),
               items    = this._getCarouselItems(),
               clip     = carousel.clipping(),
               wh       = 0,
               idx      = 0,
               page     = 1,
               pages    = {},
               curr,
               dim;
           while (true) {
               curr = items.eq(idx++);
               if (curr.length === 0) {
                   break;
               }
               dim = carousel.dimension(curr);
               if ((wh + dim) > clip) {
                   page++;
                   wh = 0;
               }
               wh += dim;
               if (!pages[page]) {
                   pages[page] = curr;
               } else {
                   pages[page] = pages[page].add(curr);
               }
           }
           return pages;
       },
       _getCarouselItems: function() {
           if (!this._carouselItems) {
               this._carouselItems = this.carousel().jcarousel('items');
           }
           return this._carouselItems;
       }
   });

}(jQuery));

(function($, document) {

   'use strict';
   var hiddenProp,
       visibilityChangeEvent,
       visibilityChangeEventNames = {
           hidden: 'visibilitychange',
           mozHidden: 'mozvisibilitychange',
           msHidden: 'msvisibilitychange',
           webkitHidden: 'webkitvisibilitychange'
       }
   ;
   $.each(visibilityChangeEventNames, function(key, val) {
       if (typeof document[key] !== 'undefined') {
           hiddenProp = key;
           visibilityChangeEvent = val;
           return false;
       }
   });
   $.jCarousel.plugin('jcarouselAutoscroll', {
       _options: {
           target:    '+=1',
           interval:  3000,
           autostart: true
       },
       _timer: null,
       _started: false,
       _init: function () {
           this.onDestroy = $.proxy(function() {
               this._destroy();
               this.carousel()
                   .one('jcarousel:createend', $.proxy(this._create, this));
           }, this);
           this.onAnimateEnd = $.proxy(this._start, this);
           this.onVisibilityChange = $.proxy(function() {
               if (document[hiddenProp]) {
                   this._stop();
               } else {
                   this._start();
               }
           }, this);
       },
       _create: function() {
           this.carousel()
               .one('jcarousel:destroy', this.onDestroy);
           $(document)
               .on(visibilityChangeEvent, this.onVisibilityChange);
           if (this.options('autostart')) {
               this.start();
           }
       },
       _destroy: function() {
           this._stop();
           this.carousel()
               .off('jcarousel:destroy', this.onDestroy);
           $(document)
               .off(visibilityChangeEvent, this.onVisibilityChange);
       },
       _start: function() {
           this._stop();
           if (!this._started) {
               return;
           }
           this.carousel()
               .one('jcarousel:animateend', this.onAnimateEnd);
           this._timer = setTimeout($.proxy(function() {
               this.carousel().jcarousel('scroll', this.options('target'));
           }, this), this.options('interval'));
           return this;
       },
       _stop: function() {
           if (this._timer) {
               this._timer = clearTimeout(this._timer);
           }
           this.carousel()
               .off('jcarousel:animateend', this.onAnimateEnd);
           return this;
       },
       start: function() {
           this._started = true;
           this._start();
           return this;
       },
       stop: function() {
           this._started = false;
           this._stop();
           return this;
       }
   });

}(jQuery, document));