/*!
* Liquid Slider
* Copyright 2012 Kevin Batdorf
* http://liquidslider.com
* MIT license
*/
// Utility for creating objects in older browsers
if (typeof Object.create !== 'function') {
Object.create = function(obj) {
'use strict';
function F() {}
F.prototype = obj;
return new F();
};
}
;(function($, window, document, undefined) {
'use strict';
$.fn.liquidSlider = function(options) {
return this.each(function() {
var slider = Object.create(LiquidSlider);
slider.init(options, this);
$.data(this, 'liquidSlider', slider);
});
};
$.fn.liquidSlider.options = {
autoHeight: false,
minHeight: 0,
heightEaseDuration: 500,
heightEaseFunction: 'easeInOutExpo',
slideEaseDuration: 500,
slideEaseFunction: 'easeInOutExpo',
slideEaseFunctionFallback: 'swing',
animateIn: 'bounceInRight',
animateOut: 'bounceOutRight',
continuous: true,
fadeInDuration: 500,
fadeOutDuration: 500,
autoSlide: false,
autoSlideDirection: 'right',
autoSlideInterval: 6000,
forceAutoSlide: false,
pauseOnHover: false,
dynamicArrows: false,
dynamicArrowsGraphical: true,
dynamicArrowLeftText: '« left',
dynamicArrowRightText: 'right »',
hideSideArrows: true,
hideSideArrowsDuration: 750,
hoverArrows: false,
hoverArrowDuration: 250,
dynamicTabs: false,
dynamicTabsHtml: true,
includeTitle: true,
panelTitleSelector: '.title',
dynamicTabsAlign: 'left',
dynamicTabsPosition: 'top',
navElementTag: 'div',
firstPanelToLoad: 1,
hashLinking: false,
hashTitleSelector: '.title',
keyboardNavigation: false,
leftKey: 39,
rightKey: 37,
panelKeys: {
1: 49,
2: 50,
3: 51,
4: 52
},
responsive: true,
mobileNavigation: true,
mobileNavDefaultText: 'Menu',
mobileUIThreshold: 0,
hideArrowsWhenMobile: true,
hideArrowsThreshold: 0,
useCSSMaxWidth: 3000,
preload: function() {
var _this = this;
jQuery(window).bind('load', function() {
_this.finalize();
});
},
onload: function() {},
pretransition: function() {
this.transition();
},
callback: function() {},
preloader: false,
swipe: true,
swipeArgs: undefined
};
})(jQuery, window, document);
// Create the Liquid Slider Object
var LiquidSlider = {};
LiquidSlider.init = function(options, elem) {
var _this = this;
// Cache the element
_this.elem = elem;
_this.$elem = jQuery(elem);
jQuery('.no-js').removeClass('no-js');
// Cache the ID and class. This allows for multiple instances with any ID name supplied
_this.sliderId = '#' + (_this.$elem).attr('id');
_this.$sliderId = jQuery(_this.sliderId);
// Set the options
_this.options = jQuery.extend({}, jQuery.fn.liquidSlider.options, options);
// Variable for the % sign if needed (responsive), otherwise px
_this.pSign = (_this.options.responsive) ? '%' : 'px';
// jQuery or CSS3 ?
_this.determineAnimationType();
// Disable some stuff when not responsive
if (!_this.options.responsive) {
_this.options.mobileNavigation = false;
_this.options.hideArrowsWhenMobile = false;
}
// If using animate.css, add the class here and disable other options.
if (_this.options.slideEaseFunction === 'animate.css') {
if (!_this.useCSS) {
_this.options.slideEaseFunction = _this.options.slideEaseFunctionFallback;
} else {
_this.options.continuous = false;
_this.animateCSS = true;
}
}
// Build the tabs and navigation
_this.build();
// Register events
_this.events();
// Fix width
if (!_this.options.responsive && _this.options.dynamicArrows)
_this.$sliderWrap.width(_this.$sliderId.outerWidth(true) +
_this.leftArrow.outerWidth(true) +
_this.rightArrow.outerWidth(true));
// Set the slider as loaded (almost)
_this.loaded = true;
_this.options.preload.call(_this);
};
LiquidSlider.build = function() {
var _this = this,
isAbsolute;
// Wrap the entire slider unless it exists already
if ((_this.$sliderId).parent().attr('class') !== 'ls-wrapper') {
(_this.$sliderId).wrap('
');
}
// Cache the wrapper
_this.$sliderWrap = jQuery(_this.sliderId + '-wrapper');
// Add the preloader
_this.options.preloader && _this.addPreloader();
// Add the .panel class to the individual panels
jQuery(_this.sliderId).children().addClass((_this.$elem).attr('id') + '-panel ls-panel');
_this.panelClass = _this.sliderId + ' .' + (_this.$elem).attr('id') + '-panel:not(.clone)';
_this.$panelClass = jQuery(_this.panelClass);
// Wrap all panels in a div, and wrap inner content in a div
(_this.$panelClass).wrapAll('');
(_this.$panelClass).wrapInner('');
_this.panelContainer = (_this.$panelClass).parent();
_this.$panelContainer = _this.panelContainer;
// Build hash links
_this.options.hashLinking && _this.buildHashTags();
// If using fade transition, add the class here and disable other options.
if (_this.options.slideEaseFunction === 'fade') {
(_this.$panelClass).addClass('fade');
_this.options.continuous = false;
_this.fade = true;
}
// Build navigation tabs
if (_this.options.dynamicTabs) {
_this.addNavigation();
} else {
_this.options.mobileNavigation = false;
}
// Build navigation arrows or disable features
if (_this.options.dynamicArrows) {
_this.addArrows();
} else {
_this.options.hoverArrows = false;
_this.options.hideSideArrows = false;
_this.options.hideArrowsWhenMobile = false;
}
/**
* Create a container width to allow for a smooth float right.
* Won't calculate arrows if positioned absolute
*/
isAbsolute = ((_this.$leftArrow) && (_this.$leftArrow).css('position') === 'absolute') ? 0 : 1;
// Set slider width
_this.totalSliderWidth = (_this.$sliderId).outerWidth(true) +
(jQuery(_this.$leftArrow).outerWidth(true)) * isAbsolute +
(jQuery(_this.$rightArrow).outerWidth(true)) * isAbsolute;
jQuery((_this.$sliderWrap)).css('width', _this.totalSliderWidth);
// Align navigation tabs
_this.options.dynamicTabs && _this.alignNavigation();
/*
* There is no need to use continuous if arrow navigation is hidden on sides.
* If you want to use autoslide and still want hideSideArrows, use the API
*/
_this.options.hideSideArrows && (_this.options.continuous = false);
// Clone panels if continuous is enabled
if (_this.options.continuous) {
(_this.$panelContainer).prepend((_this.$panelContainer).children().last().clone().addClass('clone'));
(_this.$panelContainer).append((_this.$panelContainer).children().eq(1).clone().addClass('clone'));
}
var clonedCount = (_this.options.continuous) ? 2 : 0;
// Count the number of panels and get the combined width
_this.panelCount = jQuery(_this.panelClass).length;
_this.panelCountTotal = (_this.fade) ? 1 : _this.panelCount + clonedCount;
_this.panelWidth = jQuery(_this.panelClass).outerWidth();
_this.totalWidth = _this.panelCountTotal * _this.panelWidth;
// Apply the width to the panel container
jQuery(_this.sliderId + ' .panel-container').css('width', _this.totalWidth);
// How far should we slide?
_this.slideDistance = (_this.options.responsive) ? 100 : jQuery(_this.sliderId).outerWidth();
if (_this.useCSS && _this.options.responsive) {
_this.totalWidth = 100 * _this.panelCountTotal;
_this.slideDistance = 100 / _this.panelCountTotal;
}
// Make responsive
_this.options.responsive && _this.makeResponsive();
// Apply starting position
_this.prepareTransition(_this.getFirstPanel(), true);
// Update the class
_this.updateClass();
};
LiquidSlider.determineAnimationType = function() {
var _this = this,
animationstring = 'animation',
keyframeprefix = '',
domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
pfx = '',
i = 0;
/* Decide whether or not to use CSS transitions or jQuery.
* Code taken from:
* https://developer.mozilla.org/en-US/docs/CSS/CSS_animations/Detecting_CSS_animation_support
*/
_this.useCSS = false;
if (_this.elem.style.animationName) _this.useCSS = true;
if (_this.useCSS === false) {
for (i = 0; i < domPrefixes.length; i++) {
if (_this.elem.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
pfx = domPrefixes[i];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
_this.useCSS = true;
break;
}
}
}
(document.documentElement.clientWidth > _this.options.useCSSMaxWidth) && (_this.useCSS = false);
};
LiquidSlider.configureCSSTransitions = function(slide, height) {
var _this = this,
slideTransition,
heightTransition,
sFunction,
hFunction;
// Penner equations in attempt to match jQuery Easing
_this.easing = {
easeOutCubic: 'cubic-bezier(.215,.61,.355,1)',
easeInOutCubic: 'cubic-bezier(.645,.045,.355,1)',
easeInCirc: 'cubic-bezier(.6,.04,.98,.335)',
easeOutCirc: 'cubic-bezier(.075,.82,.165,1)',
easeInOutCirc: 'cubic-bezier(.785,.135,.15,.86)',
easeInExpo: 'cubic-bezier(.95,.05,.795,.035)',
easeOutExpo: 'cubic-bezier(.19,1,.22,1)',
easeInOutExpo: 'cubic-bezier(1,0,0,1)',
easeInQuad: 'cubic-bezier(.55,.085,.68,.53)',
easeOutQuad: 'cubic-bezier(.25,.46,.45,.94)',
easeInOutQuad: 'cubic-bezier(.455,.03,.515,.955)',
easeInQuart: 'cubic-bezier(.895,.03,.685,.22)',
easeOutQuart: 'cubic-bezier(.165,.84,.44,1)',
easeInOutQuart: 'cubic-bezier(.77,0,.175,1)',
easeInQuint: 'cubic-bezier(.755,.05,.855,.06)',
easeOutQuint: 'cubic-bezier(.23,1,.32,1)',
easeInOutQuint: 'cubic-bezier(.86,0,.07,1)',
easeInSine: 'cubic-bezier(.47,0,.745,.715)',
easeOutSine: 'cubic-bezier(.39,.575,.565,1)',
easeInOutSine: 'cubic-bezier(.445,.05,.55,.95)',
easeInBack: 'cubic-bezier(.6,-.28,.735,.045)',
easeOutBack: 'cubic-bezier(.175,.885,.32,1.275)',
easeInOutBack: 'cubic-bezier(.68,-.55,.265,1.55)'
};
// Set some defaults
sFunction = _this.easing[_this.options.slideEaseFunction] || _this.options.slideEaseFunction;
hFunction = _this.easing[_this.options.heightEaseFunction] || _this.options.heightEaseFunction;
// Build a CSS class depending on the type of transition
if (_this.useCSS) {
slideTransition = 'all ' + (slide || _this.options.slideEaseDuration) + 'ms ' + sFunction;
heightTransition = 'all ' + (height || _this.options.heightEaseDuration) + 'ms ' + hFunction;
// Build the width transition rules
jQuery(_this.panelContainer).css({
'-webkit-transition': slideTransition,
'-moz-transition': slideTransition,
'-ms-transition': slideTransition,
'-o-transition': slideTransition,
'transition': slideTransition
});
// Build the height transition rules
if (_this.options.autoHeight) {
(_this.$sliderId).css({
'-webkit-transition': heightTransition,
'-moz-transition': heightTransition,
'-ms-transition': heightTransition,
'-o-transition': heightTransition,
'transition': heightTransition
});
}
}
};
LiquidSlider.transitionFade = function() {
var _this = this;
jQuery(_this.panelClass).eq(_this.nextPanel)
.fadeTo(_this.options.fadeInDuration, 1.0).css('z-index', 1);
jQuery(_this.panelClass).eq(_this.prevPanel)
.fadeTo(_this.options.fadeOutDuration, 0).css('z-index', 0);
_this.callback(_this.options.callback, true);
};
LiquidSlider.hover = function() {
var _this = this;
(_this.$sliderWrap).hover(
function() {
_this.options.hoverArrows && _this.hideShowArrows(_this.options.fadeInDuration, true, true, false);
_this.options.pauseOnHover && clearTimeout(_this.autoSlideTimeout);
},
function() {
_this.options.hoverArrows && _this.hideShowArrows(_this.options.fadeOutnDuration, true, false, true);
(_this.options.pauseOnHover && _this.options.autoSlide) && _this.startAutoSlide(true);
}
);
};
LiquidSlider.events = function() {
var _this = this;
// Set events for all types of navigation
_this.options.dynamicArrows && _this.registerArrows();
_this.options.dynamicTabs && _this.registerNav();
_this.options.swipe && _this.registerTouch();
_this.options.keyboardNavigation && _this.registerKeyboard();
// Click to stop autoSlider
(_this.$sliderWrap).find('*').on('click', function() {
if (_this.options.forceAutoSlide) {
_this.startAutoSlide(true);
} else if (_this.options.autoSlide) {
_this.stopAutoSlide();
}
});
_this.hover();
};
LiquidSlider.setNextPanel = function(direction) {
var _this = this;
if (direction === _this.nextPanel) return;
_this.prevPanel = _this.nextPanel;
if (_this.loaded) {
if (typeof direction === 'number') {
_this.nextPanel = direction;
} else {
// Clicking to a cloned panel
// case clickable || ((_this.nextPanel === _this.panelCount) || (_this.nextPanel === -1)):
if(direction === 'right'){
if((_this.nextPanel + 1) >= _this.panelCount){
_this.nextPanel = (_this.panelCount - 1);
}else{
_this.nextPanel += (~~(direction === 'right') || -1);
}
}
if(direction === 'left'){
if((_this.nextPanel) == 0){
_this.nextPanel = 0;
}else{
_this.nextPanel += (~~(direction === 'right') || -1);
}
}
if((_this.nextPanel + 1) >= _this.panelCount){
$(".total-panel").addClass("panel-active");
}else{
$(".total-panel").removeClass("panel-active");
}
// If not continuous, slide back at the last or first panel
_this.options.continuous ||
(_this.nextPanel = (_this.nextPanel < 0) ? _this.panelCount - 1 : (_this.nextPanel % _this.panelCount));
}
if (_this.fade || _this.animateCSS) {
_this.prepareTransition(_this.nextPanel);
} else {
_this.verifyPanel();
}
}
};
LiquidSlider.getFirstPanel = function() {
var _this = this,
output;
// is there a hash tag?
if (_this.options.hashLinking) {
output = jQuery.inArray(_this.convertRegex(window.location.hash), _this.hashLinks);
// Default to panel 1 if mistyped
if (output === -1) output = 0;
}
return (output) ? output : _this.options.firstPanelToLoad - 1;
};
/**
* Searches for the title class and returns the formatted hashtag
*
* @param searchTerm
* @param input
* @return
*/
LiquidSlider.getFromPanel = function(searchTerm, panelNumber) {
var _this = this;
return _this.convertRegex(_this.$panelClass.find(searchTerm).eq(panelNumber).text());
};
/**
* Removes unwanted characters for browser hash
*
* @param input
* @return
*/
LiquidSlider.convertRegex = function(input) {
return jQuery.trim(input)
.replace(/[^\w -]+/g,'')
.replace(/ +/g,'-')
.toLowerCase();
};
/**
* Updates all classes for current nav and panels
*
* @param