; (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);