; (function ($, window) {
var debug = false;
var diag = function (message) {
if (debug && window.console) {
console.log('[CarouselWidget] - ' + message);
}
};
var constants =
{
Fade: 'fade',
Slide: 'slide',
Automatic: 'automatically',
Manual: 'manual'
}
// Defaults
var defaults = {
transition: constants.Fade, //[fade or slide]
transitionTiming: 1,
groupAdvance: constants.Automatic, //[automatically or manual]
groupTiming: 5,
showArrows: true,
showPaging: true,
showDots: true,
sliderSelector: 'div.widgetCarousel-slider',
groupSelector: 'div.widgetCarousel-group',
itemsSelector: 'div.widgetCarousel-item',
forceHeight: false
};
var pageMarkup = '
{0}';
var separatorMarkup = '...';
var maxPageNumbers = 10;
//Constructor
window.CarouselWidget = function (options, element) {
var self = this;
//private vars/methods
self.element = element;
self.$carousel = $(self.element);
self.$prev = self.$carousel.find('.arrow.prev');
self.$next = self.$carousel.find('.arrow.next');
self.$pager = self.$carousel.find('.semanticList.pager');
self.$arrowSpans = self.$next.children('span').add(self.$prev.children('span'));
self.autoTransition = null;
self.initPaging = function () {
var appendPage = function (number) {
var $li = $(pageMarkup.replace(/\{0\}/g, number));
$li.children('a').unbind('click').click(function (e) {
e.preventDefault();
if (!$(this).parent().hasClass('disabled')) {
self.stopTransition();
self.show($(this).data('index'));
}
});
self.$pager.append($li);
};
var appendSeparator = function () {
var $li = $(separatorMarkup);
self.$pager.append($li);
};
var appendRange = function (start, end) {
for (var number = start; number <= end; number++) {
appendPage(number);
}
};
self.$pager.empty();
if (self.settings.showDots || self.$slides.length <= maxPageNumbers) {
for (var i = 0; i < self.$slides.length; i++) {
appendPage(i + 1);
}
diag('Paging initialized with ' + (self.settings.showDots ? 'dots' : 'numbers'));
} else {
if (self.currentSlide <= 3) {
appendRange(1, 4);
appendSeparator();
appendPage(self.$slides.length);
} else if (self.$slides.length - self.currentSlide < 3) {
appendPage(1);
appendSeparator();
appendRange(self.$slides.length - 3, self.$slides.length);
} else {
appendPage(1);
appendSeparator();
appendRange(self.currentSlide - 1, self.currentSlide + 1);
appendSeparator();
appendPage(self.$slides.length);
}
diag('Paging initialized with optimized numbers');
}
self.$pager.show();
};
self.updatePaging = function () {
if (self.$pager.is(':visible')) {
if (!self.settings.showDots && self.$slides.length > maxPageNumbers) {
self.initPaging();
}
self.$pager.find('.active').removeClass('active');
self.$pager.find('[data-index=' + self.currentSlide + '].pagingItems').parent().addClass('active');
}
self.updateArrowsHeight();
};
self.updateArrowsHeight = function () {
if (self.settings.showArrows) {
var slide = self.currentSlide > self.$slides.length
? 1
: (self.currentSlide < 1
? self.$slides.length
: self.currentSlide);
var top = $(self.$slides[slide - 1]).height() / 2;
if (top < 15) top = 15;
var centerCss = 'translateY(' + top + 'px)';
self.$arrowSpans.css({
'-webkit-transform': centerCss,
'-ms-transform': centerCss,
'-o-transform': centerCss,
'transform': centerCss
});
}
};
self.initArrows = function () {
self.$prev.unbind('click').click(function (e) {
e.preventDefault();
if (!$(this).hasClass('disabled')) {
self.$prev.addClass('disabled');
if (!self.$next.hasClass('disabled')) {
self.$next.addClass('disabled');
setTimeout(function() {
self.$next.removeClass('disabled');
}, self.settings.transitionTiming * 1000);
}
self.stopTransition();
self.movePrev();
if (document.activeElement !== document.body) document.activeElement.blur();
setTimeout(function() {
self.$prev.removeClass('disabled');
}, self.settings.transitionTiming * 1000);
}
});
self.$next.unbind('click').click(function (e) {
e.preventDefault();
if (!$(this).hasClass('disabled')) {
self.stopTransition();
self.moveNext();
if (document.activeElement !== document.body) document.activeElement.blur();
}
});
//Disabled arrows only if there is one slide. Otherwise, carousel is always circular
self.$prev.show()[(self.$slides.length <= 1) ? 'addClass' : 'removeClass']("disabled");
self.$next.show()[(self.$slides.length <= 1) ? 'addClass' : 'removeClass']("disabled");
};
self.startTransition = function () {
self.stopTransition();
var loopTransition = function (force) {
force = force || false;
if (force || self.autoTransition != null) {
self.autoTransition = window.setTimeout(function () {
self.moveNext(loopTransition);
}, self.settings.groupTiming * 1000);
}
};
loopTransition(true);
};
self.stopTransition = function () {
if (self.autoTransition != null) {
window.clearTimeout(self.autoTransition);
self.autoTransition = null;
}
};
self.setupTransition = function () {
var i,
m = self.$groups.length,
n = self.$items.length;
if (!self.slideByItems) {
//by groups => wide view
diag('Setup transition by groups. m=' + m + ', effect=' + self.settings.transition);
if (self.settings.transition === constants.Slide) {
self.$slider.css('left', '0');
self.$slider.css("margin-left", "100%").css("margin-right", "100%");
//adjust internally new groups
self.$groups = self.$carousel.find(self.settings.groupSelector);
m = self.$groups.length;
if (m > 1) {
self.$slider.css("transition", "left " + self.settings.transitionTiming + "s ease");
}
} else {
for (i = 0; i < m; i++) {
$(self.$groups[i]).css('left', (i * 100 * -1 / m) + '%').css('z-index', 1);
}
}
self.$slider.css('width', (m * 100) + '%');
self.$groups.css('width', (100 * 1 / m) + '%');
} else {
//by items => narrow view
diag('Setup transition by items. m=' + m + ', n=' + n + ', effect=' + self.settings.transition);
var $groupItems;
var j;
if (self.settings.transition === constants.Slide) {
self.$slider.css('left', '0');
self.$items.css('opacity', 1);
self.$slider.css("margin-left", "100%").css("margin-right", "100%");
//adjust internally new groups and items
self.$groups = self.$carousel.find(self.settings.groupSelector);
self.$items = self.$carousel.find(self.settings.itemsSelector);
m = self.$groups.length;
n = self.$items.length;
if (n > 1) {
self.$slider.css("transition", "left " + self.settings.transitionTiming + "s ease");
}
for (i = 0; i < m; i++) {
$groupItems = $(self.$groups[i]).find(self.settings.itemsSelector);
$(self.$groups[i])
.css('width', (100 * $groupItems.length / n) + '%');
for (j = 0; j < $groupItems.length; j++) {
$($groupItems[j]).css('width', (1 / $groupItems.length) * 100 + '%');
}
}
} else {
for (i = 0; i < m; i++) {
var itemsLeft = 0;
$groupItems = $(self.$groups[i]).find(self.settings.itemsSelector);
if (i > 0) {
for (j = 0; j < i; j++) {
itemsLeft += $(self.$groups[j]).find(self.settings.itemsSelector).length;
}
}
$(self.$groups[i])
.css('width', (100 * $groupItems.length / n) + '%')
.css('left', (-100 * itemsLeft / n) + '%').css('z-index', 1);
for (j = 0; j < $groupItems.length; j++) {
$($groupItems[j]).css('width', (1 / $groupItems.length) * 100 + '%')
.css('left', -j / $groupItems.length * 100 + '%');
}
}
}
self.$slider.css('width', (n * 100) + '%');
}
};
self.init(options);
//Adding global onresize handlers
var onResize = function () {
self.onResize();
};
window.Pages.onResizeHandlers = window.Pages.onResizeHandlers || [];
window.Pages.onResizeHandlers.push(onResize);
};
//public methods
window.CarouselWidget.prototype = {
init: function (options) {
var self = this;
self.settings = $.extend({}, defaults, options);
self.$slider = self.$carousel.find(self.settings.sliderSelector);
self.$groups = self.$carousel.find(self.settings.groupSelector);
self.$items = self.$carousel.find(self.settings.itemsSelector);
self.slideByItems = self.settings.itemsSelector != null && self.settings.itemsSelector.length > 0;
self.$slides = self.slideByItems ? self.$items : self.$groups;
self.currentSlide = 1;
diag('Initing carouselId: ' + self.$carousel.attr('id'));
diag('# of slides: ' + self.$slides.length);
//Display and init arrows/paging if needed
self.$pager.hide();
self.$prev.hide();
self.$next.hide();
self.settings.showPaging && self.initPaging();
self.settings.showArrows && self.initArrows();
// Find play and pause buttons and attach event handlers
self.$pause = self.$carousel.find('.pause-btn');
self.$play = self.$carousel.find('.play-btn');
// Initially display pause button and hide play button
if (self.$play.length>0)
self.$play.hide();
if (self.$pause.length > 0) {
self.$pause.click(function () {
self.stopTransition();
$(this).hide();
self.$play.show();
});
}
if (self.$play.length > 0) {
self.$play.click(function () {
self.startTransition();
$(this).hide();
self.$pause.show();
});
}
self.setupTransition();
//Adjust height and show only first slide.
self.adjustHeight();
self.show(1);
// Set the z-index so group 1 is front
if (self.slideByItems && self.settings.transition === constants.Fade) {
$(self.$slides[0]).parent().css('z-index', 2);
$(self.$slides[0]).parent().siblings().css('z-index', 1);
}
if (self.settings.groupAdvance === constants.Automatic && self.$slides.length > 1)
self.startTransition();
},
show: function (slide, callback) {
var self = this;
if (slide >= 1 && slide <= self.$slides.length) {
diag('Moving to slide #: ' + slide);
var originalSlide = self.currentSlide;
self.currentSlide = slide;
//Hide previous and display new one using transitions
switch (self.settings.transition) {
case constants.Fade:
if (originalSlide === self.currentSlide) {
//Hide all and display slide no effect.
self.$slides.css('opacity', 0).css('z-index', 1);
$(self.$slides[self.currentSlide - 1]).css('opacity', 1).css('z-index', 2);
} else {
// If slide by items, use to change the z-index of groups
if (self.slideByItems) {
$(self.$slides[self.currentSlide - 1]).parent().css('z-index',2);
$(self.$slides[self.currentSlide - 1]).parent().siblings().css('z-index', 1);
}
//Fade effect
$(self.$slides[originalSlide - 1]).animate({ opacity: 0 }, self.settings.transitionTiming * 1000, function () {
$(this).css('z-index', 1);
});
$(self.$slides[self.currentSlide - 1]).animate({ opacity: 1 }, self.settings.transitionTiming * 1000, function () {
$(this).css('z-index', 2);
if (typeof callback === 'function') {
callback();
}
});
}
break;
case constants.Slide:
if (originalSlide === self.currentSlide) {
//display slide no effect.
$(self.$slider.css('left', ((self.currentSlide) * -100) + '%'));
} else {
//slide effect
self.$slider.css("left", ((self.currentSlide) * -100) + '%');
setTimeout(function() {
if (typeof callback === 'function') {
callback();
}
}, self.settings.transitionTiming * 1000);
}
break;
}
//https://civicplus.tpondemand.com/entity/55058-pages-carousel-widget-does-not-show
window.setTimeout(function () {
self.updatePaging();
}, 500);
} else {
diag('Cannot move to slide #: ' + slide);
}
},
moveNext: function (callback) {
var self = this;
if (!self.$next.hasClass('disabled')) {
self.$next.addClass('disabled');
setTimeout(function() {
self.$next.removeClass('disabled');
}, self.settings.transitionTiming * 1000 + 50);
}
if (!self.$prev.hasClass('disabled')) {
self.$prev.addClass('disabled');
setTimeout(function() {
self.$prev.removeClass('disabled');
}, self.settings.transitionTiming * 1000 + 50);
}
var next = self.currentSlide === self.$slides.length ? 1 : self.currentSlide + 1;
if (next === 1 && self.settings.transition === constants.Slide) {
//Slide from Last to First
self.currentSlide = next;
var leftOffset = ((self.$slides.length + 1) * -100); //Last to phantom Last and then to actual First slide
self.$slider.css("left", leftOffset + '%');
self.$slides.first().css("transform","translateX(" + self.$slides.length * 100 + "%)");
setTimeout(function() {
self.$slider.css("transition", "none");
self.$slider.css('left', ((self.currentSlide) * -100) + '%');
setTimeout(function() { self.$slider.css("transition", "left " + self.settings.transitionTiming + "s ease"); }, 50);
self.$slides.first().css("transform","none");
if (typeof callback === 'function') {
callback();
}
}, self.settings.transitionTiming * 1000);
self.updatePaging();
} else
self.show(next, callback);
},
movePrev: function () {
var self = this;
if (!self.$next.hasClass('disabled')) {
self.$next.addClass('disabled');
setTimeout(function() {
self.$next.removeClass('disabled');
}, self.settings.transitionTiming * 1000 + 50);
}
if (!self.$prev.hasClass('disabled')) {
self.$prev.addClass('disabled');
setTimeout(function() {
self.$prev.removeClass('disabled');
}, self.settings.transitionTiming * 1000 + 50);
}
var prev = self.currentSlide === 1 ? self.$slides.length : self.currentSlide - 1;
if (prev === self.$slides.length && self.settings.transition === constants.Slide) {
//Slide from First to Last
self.currentSlide = prev;
var leftOffset = 0; //First to phantom First and then to actual Last slide
self.$slider.css("left", leftOffset + '%');
self.$slides.last().css("transform","translateX(-" + self.$slides.length * 100 + "%)");
setTimeout(function() {
self.$slider.css("transition", "none");
self.$slider.css('left', ((self.currentSlide) * -100) + '%');
setTimeout(function() { self.$slider.css("transition", "left " + self.settings.transitionTiming + "s ease"); }, 50);
self.$slides.last().css("transform","none");
if (typeof callback === 'function') {
callback();
}
}, self.settings.transitionTiming * 1000);
self.updatePaging();
} else
self.show(prev);
},
onResize: function () {
var self = this;
self.adjustHeight();
},
adjustHeight: function () {
var self = this;
if (self.settings.forceHeight) {
var maxHeight = 0;
for (var i = 0; i < self.$slides.length; i++) {
var slideHeight = $(self.$slides[i]).outerHeight(true);
if (slideHeight > maxHeight)
maxHeight = slideHeight;
}
if (self.settings.showPaging)
maxHeight += self.$pager.outerHeight(true);
self.$carousel.css('height', maxHeight + 'px');
diag('height adjusted to ' + maxHeight + 'px');
}
},
destroy: function () {
var self = this;
self.$pager.empty().hide();
self.$prev.unbind('click').hide();
self.$next.unbind('click').hide();
self.stopTransition();
self.$carousel.css('height', '');
self.$slider.css('width', '').css('left', '');
self.$groups.css('width', '').css('left', '').css('z-index', '').css('opacity', '');
self.$items.css('width', '').css('left', '').css('z-index', '').css('opacity', '');
}
}
/* jQuery Plugin Support */
$.fn.carouselWidget = function (options) {
if (typeof options === 'string') {
var args = Array.prototype.slice.call(arguments, 1);
this.each(function () {
var instance = $.data(this, 'carouselWidget');
if (!instance) {
diag("cannot call methods on carouselWidget prior to initialization; " +
"attempted to call method '" + options + "'");
return;
}
if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {
diag("no such method '" + options + "' for carouselWidget instance");
return;
}
instance[options].apply(instance, args);
});
}
else {
this.each(function () {
var instance = $.data(this, 'carouselWidget');
if (instance) {
instance.init(options);
}
else {
$.data(this, 'carouselWidget', new window.CarouselWidget(options, this));
}
});
}
return this;
};
})(jQuery, window);