/* This file is part of JonDesign's SmoothGallery v2.0. 3.2.0 JonDesign's SmoothGallery is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. JonDesign's SmoothGallery is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JonDesign's SmoothGallery; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/) Contributed code by: - Christian Ehret (bugfix) - Nitrix (bugfix) - Valerio from Mad4Milk for his great help with the carousel scrolling and many other things. - Archie Cowan for helping me find a bugfix on carousel inner width problem. - Tomocchino from #mootools for the preloader class Many thanks to: - The mootools team for the great mootools lib, and it's help and support throughout the project. */ // declaring the class var gallery = { initialize: function (element, options) { this.setOptions({ showArrows: true, showCarousel: true, showInfopane: true, embedLinks: true, fadeDuration: 500, timed: false, delay: 14000, preloader: true, preloaderImage: true, preloaderErrorImage: true, /* Data retrieval */ manualData: [], populateFrom: false, populateData: true, destroyAfterPopulate: true, elementSelector: "div.imageElement", titleSelector: "h2", subtitleSelector: "p", linkSelector: "a.open", imageSelector: "img.full", thumbnailSelector: "img.thumbnail", defaultTransition: 'fade', /* InfoPane options */ slideInfoZoneOpacity: 0.7, slideInfoZoneSlide: true, /* Carousel options */ carouselMinimizedOpacity: 0.4, carouselMinimizedHeight: 20, carouselMaximizedOpacity: 0.9, thumbHeight: 75, thumbWidth: 100, thumbSpacing: 10, thumbIdleOpacity: 0.6, textShowCarousel: 'Más noticias', showCarouselLabel: true, thumbCloseCarousel: true, useThumbGenerator: false, thumbGenerator: 'resizer.php', useExternalCarousel: false, carouselElement: false, carouselHorizontal: true, activateCarouselScroller: true, carouselPreloader: true, textPreloadingCarousel: 'Loading...', /* CSS Classes */ baseClass: 'jdGallery', withArrowsClass: 'withArrows', /* Plugins: HistoryManager */ useHistoryManager: false, customHistoryKey: false }, options); this.fireEvent('onInit'); this.currentIter = 0; this.lastIter = 0; this.maxIter = 0; this.galleryElement = element; this.galleryData = this.options.manualData; this.galleryInit = 1; this.galleryElements = Array(); this.thumbnailElements = Array(); this.galleryElement.addClass(this.options.baseClass); this.populateFrom = element; if (this.options.populateFrom) this.populateFrom = this.options.populateFrom; if (this.options.populateData) this.populateData(); element.style.display = "block"; if (this.options.useHistoryManager) this.initHistory(); if (this.options.embedLinks) { this.currentLink = new Element('a').addClass('open').setProperties({ href: '#', title: '' }).injectInside(element); if ((!this.options.showArrows) && (!this.options.showCarousel)) this.galleryElement = element = this.currentLink; else this.currentLink.setStyle('display', 'none'); } this.constructElements(); if ((this.galleryData.length > 1) && (this.options.showArrows)) { var leftArrow = new Element('a').addClass('left').addEvent( 'click', this.prevItem.bind(this) ).injectInside(element); var rightArrow = new Element('a').addClass('right').addEvent( 'click', this.nextItem.bind(this) ).injectInside(element); this.galleryElement.addClass(this.options.withArrowsClass); } this.loadingElement = new Element('div').addClass('loadingElement').injectInside(element); if (this.options.showInfopane) this.initInfoSlideshow(); if (this.options.showCarousel) this.initCarousel(); this.doSlideShow(1); }, populateData: function () { currentArrayPlace = this.galleryData.length; options = this.options; var data = $A(this.galleryData); data.extend(this.populateGallery(this.populateFrom, currentArrayPlace)); this.galleryData = data; this.fireEvent('onPopulated'); }, populateGallery: function (element, startNumber) { var data = []; options = this.options; currentArrayPlace = startNumber; element.getElements(options.elementSelector).each(function (el) { elementDict = { image: el.getElement(options.imageSelector).getProperty('src'), number: currentArrayPlace, transition: this.options.defaultTransition }; elementDict.extend = $extend; if ((options.showInfopane) | (options.showCarousel)) elementDict.extend({ title: el.getElement(options.titleSelector).innerHTML, description: el.getElement(options.subtitleSelector).innerHTML }); if (options.embedLinks) elementDict.extend({ link: el.getElement(options.linkSelector).href || false, linkTitle: el.getElement(options.linkSelector).title || false, linkTarget: el.getElement(options.linkSelector).getProperty('target') || false }); if ((!options.useThumbGenerator) && (options.showCarousel)) elementDict.extend({ thumbnail: el.getElement(options.thumbnailSelector).getProperty('src') }); else if (options.useThumbGenerator) elementDict.extend({ thumbnail: options.thumbGenerator + '?imgfile=' + elementDict.image + '&max_width=' + options.thumbWidth + '&max_height=' + options.thumbHeight }); data.extend([elementDict]); currentArrayPlace++; if (this.options.destroyAfterPopulate) el.remove(); }); return data; }, constructElements: function () { el = this.galleryElement; this.maxIter = this.galleryData.length; var currentImg; for (i = 0; i < this.galleryData.length; i++) { var currentImg = new Fx.Styles( new Element('div').addClass('slideElement').setStyles({ 'position': 'absolute', 'left': '0px', 'right': '0px', 'margin': '0px', 'padding': '0px', 'backgroundPosition': "center center", 'opacity': '0' }).injectInside(el), 'opacity', {duration: this.options.fadeDuration} ); if (this.options.preloader) { currentImg.source = this.galleryData[i].image; currentImg.loaded = false; currentImg.load = function (imageStyle) { if (!imageStyle.loaded) { new Asset.image(imageStyle.source, { 'onload': function (img) { img.element.setStyle( 'backgroundImage', "url('" + img.source + "')") img.loaded = true; }.bind(this, imageStyle) }); } }.pass(currentImg, this); } else { currentImg.element.setStyle('backgroundImage', "url('" + this.galleryData[i].image + "')"); } this.galleryElements[parseInt(i)] = currentImg; } }, destroySlideShow: function (element) { var myClassName = element.className; var newElement = new Element('div').addClass('myClassName'); element.parentNode.replaceChild(newElement, element); }, startSlideShow: function () { this.fireEvent('onStart'); this.loadingElement.style.display = "none"; this.lastIter = this.maxIter - 1; this.currentIter = 0; this.galleryInit = 0; this.galleryElements[parseInt(this.currentIter)].set({opacity: 1}); if (this.options.showInfopane) this.showInfoSlideShow.delay(1000, this); var textShowCarousel = formatString(this.options.textShowCarousel, this.currentIter + 1, this.maxIter); if (this.options.showCarousel && (!this.options.carouselPreloader)) this.carouselBtn.setHTML(textShowCarousel).setProperty('title', textShowCarousel); this.prepareTimer(); if (this.options.embedLinks) this.makeLink(this.currentIter); }, nextItem: function () { this.fireEvent('onNextCalled'); this.nextIter = this.currentIter + 1; if (this.nextIter >= this.maxIter) this.nextIter = 0; this.galleryInit = 0; this.goTo(this.nextIter); }, prevItem: function () { this.fireEvent('onPreviousCalled'); this.nextIter = this.currentIter - 1; if (this.nextIter <= -1) this.nextIter = this.maxIter - 1; this.galleryInit = 0; this.goTo(this.nextIter); }, goTo: function (num) { this.clearTimer(); if (this.options.preloader) { this.galleryElements[num].load(); if (num == 0) this.galleryElements[this.maxIter - 1].load(); else this.galleryElements[num - 1].load(); if (num == (this.maxIter - 1)) this.galleryElements[0].load(); else this.galleryElements[num + 1].load(); } if (this.options.embedLinks) this.clearLink(); if (this.options.showInfopane) { this.slideInfoZone.clearChain(); this.hideInfoSlideShow().chain(this.changeItem.pass(num, this)); } else this.currentChangeDelay = this.changeItem.delay(500, this, num); if (this.options.embedLinks) this.makeLink(num); this.prepareTimer(); /*if (this.options.showCarousel) this.clearThumbnailsHighlights();*/ }, changeItem: function (num) { this.fireEvent('onStartChanging'); this.galleryInit = 0; if (this.currentIter != num) { for (i = 0; i < this.maxIter; i++) { if ((i != this.currentIter)) this.galleryElements[i].set({opacity: 0}); } gallery.Transitions[this.galleryData[num].transition].pass([ this.galleryElements[this.currentIter], this.galleryElements[num], this.currentIter, num], this)(); this.currentIter = num; } var textShowCarousel = formatString(this.options.textShowCarousel, num + 1, this.maxIter); if (this.options.showCarousel) this.carouselBtn.setHTML(textShowCarousel).setProperty('title', textShowCarousel); this.doSlideShow.bind(this)(); this.fireEvent('onChanged'); }, clearTimer: function () { if (this.options.timed) $clear(this.timer); }, prepareTimer: function () { if (this.options.timed) this.timer = this.nextItem.delay(this.options.delay, this); }, doSlideShow: function (position) { if (this.galleryInit == 1) { imgPreloader = new Image(); imgPreloader.onload = function () { this.startSlideShow.delay(10, this); }.bind(this); imgPreloader.src = this.galleryData[0].image; if (this.options.preloader) this.galleryElements[0].load(); } else { if (this.options.showInfopane) { if (this.options.showInfopane) { this.showInfoSlideShow.delay((500 + this.options.fadeDuration), this); } else if ((this.options.showCarousel) && (this.options.activateCarouselScroller)) this.centerCarouselOn(position); } } }, createCarousel: function () { var carouselElement; if (!this.options.useExternalCarousel) { var carouselContainerElement = new Element('div').addClass('carouselContainer').injectInside(this.galleryElement); this.carouselContainer = new Fx.Styles(carouselContainerElement, {transition: Fx.Transitions.expoOut}); this.carouselContainer.normalHeight = carouselContainerElement.offsetHeight; this.carouselContainer.set({ 'opacity': this.options.carouselMinimizedOpacity, 'top': (this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight) }); this.carouselBtn = new Element('a').addClass('carouselBtn').setProperties({ title: this.options.textShowCarousel }).injectInside(carouselContainerElement); if (this.options.carouselPreloader) this.carouselBtn.setHTML(this.options.textPreloadingCarousel); else this.carouselBtn.setHTML(this.options.textShowCarousel); this.carouselBtn.addEvent( 'click', function () { this.carouselContainer.clearTimer(); this.toggleCarousel(); }.bind(this) ); this.carouselActive = false; carouselElement = new Element('div').addClass('carousel').injectInside(carouselContainerElement); this.carousel = new Fx.Styles(carouselElement); } else { carouselElement = $(this.options.carouselElement).addClass('jdExtCarousel'); } this.carouselElement = new Fx.Styles(carouselElement, {transition: Fx.Transitions.expoOut}); this.carouselElement.normalHeight = carouselElement.offsetHeight; if (this.options.showCarouselLabel) this.carouselLabel = new Element('p').addClass('label').injectInside(carouselElement); carouselWrapper = new Element('div').addClass('carouselWrapper').injectInside(carouselElement); this.carouselWrapper = new Fx.Styles(carouselWrapper, {transition: Fx.Transitions.expoOut}); this.carouselWrapper.normalHeight = carouselWrapper.offsetHeight; this.carouselInner = new Element('div').addClass('carouselInner').injectInside(carouselWrapper); if (this.options.activateCarouselScroller) { this.carouselWrapper.scroller = new Scroller(carouselWrapper, { area: 100, velocity: 0.2 }) this.carouselWrapper.elementScroller = new Fx.Scroll(carouselWrapper, { duration: 400, onStart: this.carouselWrapper.scroller.stop.bind(this.carouselWrapper.scroller), onComplete: this.carouselWrapper.scroller.start.bind(this.carouselWrapper.scroller) }); } }, fillCarousel: function () { this.constructThumbnails(); this.carouselInner.normalWidth = ((this.maxIter * (this.options.thumbWidth + this.options.thumbSpacing + 2)) + this.options.thumbSpacing) + "px"; this.carouselInner.style.width = this.carouselInner.normalWidth; }, initCarousel: function () { this.createCarousel(); this.fillCarousel(); if (this.options.carouselPreloader) this.preloadThumbnails(); }, flushCarousel: function () { this.thumbnailElements.each(function (myFx) { myFx.element.remove(); myFx = myFx.element = null; }); this.thumbnailElements = []; }, toggleCarousel: function () { if (this.carouselActive) this.hideCarousel(); else this.showCarousel(); }, showCarousel: function () { this.fireEvent('onShowCarousel'); this.carouselContainer.start({ 'opacity': this.options.carouselMaximizedOpacity, 'top': 0 }).chain(function () { this.carouselActive = true; this.carouselWrapper.scroller.start(); this.fireEvent('onCarouselShown'); this.carouselContainer.options.onComplete = null; }.bind(this)); }, hideCarousel: function () { this.fireEvent('onHideCarousel'); var targetTop = this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight; this.carouselContainer.start({ 'opacity': this.options.carouselMinimizedOpacity, 'top': targetTop }).chain(function () { this.carouselActive = false; this.carouselWrapper.scroller.stop(); this.fireEvent('onCarouselHidden'); this.carouselContainer.options.onComplete = null; }.bind(this)); }, constructThumbnails: function () { element = this.carouselInner; for (i = 0; i < this.galleryData.length; i++) { var currentImg = new Fx.Style(new Element('div').addClass("thumbnail").setStyles({ backgroundImage: "url('" + this.galleryData[i].thumbnail + "')", backgroundPosition: "center center", backgroundRepeat: 'no-repeat', marginLeft: this.options.thumbSpacing + "px", width: this.options.thumbWidth + "px", height: this.options.thumbHeight + "px" }).injectInside(element), "opacity", {duration: 200}).set(this.options.thumbIdleOpacity); currentImg.element.addEvents({ 'mouseover': function (myself) { myself.clearTimer(); myself.start(0.99); if (this.options.showCarouselLabel) $(this.carouselLabel).setHTML('' + (myself.relatedImage.number + 1) + "/" + this.maxIter + ": " + myself.relatedImage.title); }.pass(currentImg, this), 'mouseout': function (myself) { myself.clearTimer(); myself.start(this.options.thumbIdleOpacity); }.pass(currentImg, this), 'click': function (myself) { this.goTo(myself.relatedImage.number); if (this.options.thumbCloseCarousel) this.hideCarousel(); }.pass(currentImg, this) }); currentImg.relatedImage = this.galleryData[i]; this.thumbnailElements[parseInt(i)] = currentImg; } }, log: function (value) { if (console.log) console.log(value); }, preloadThumbnails: function () { var thumbnails = []; for (i = 0; i < this.galleryData.length; i++) { thumbnails[parseInt(i)] = this.galleryData[i].thumbnail; } this.thumbnailPreloader = new Preloader(); this.thumbnailPreloader.addEvent('onComplete', function () { var textShowCarousel = formatString(this.options.textShowCarousel, this.currentIter + 1, this.maxIter); this.carouselBtn.setHTML(textShowCarousel).setProperty('title', textShowCarousel); }.bind(this)); this.thumbnailPreloader.load(thumbnails); }, clearThumbnailsHighlights: function () { for (i = 0; i < this.galleryData.length; i++) { this.thumbnailElements[i].clearTimer(); this.thumbnailElements[i].start(0.2); } }, changeThumbnailsSize: function (width, height) { for (i = 0; i < this.galleryData.length; i++) { this.thumbnailElements[i].clearTimer(); this.thumbnailElements[i].element.setStyles({ 'width': width + "px", 'height': height + "px" }); } }, centerCarouselOn: function (num) { if (!this.carouselWallMode) { var carouselElement = this.thumbnailElements[num]; var position = carouselElement.element.offsetLeft + (carouselElement.element.offsetWidth / 2); var carouselWidth = this.carouselWrapper.element.offsetWidth; var carouselInnerWidth = this.carouselInner.offsetWidth; var diffWidth = carouselWidth / 2; var scrollPos = position - diffWidth; try { this.carouselWrapper.elementScroller.scrollTo(scrollPos, 0); } catch (e) { this.carouselWrapper.elementScroller.scrollTo = (scrollPos, 0); } } }, initInfoSlideshow: function () { /*if (this.slideInfoZone.element) this.slideInfoZone.element.remove();*/ this.slideInfoZone = new Fx.Styles(new Element('div').addClass('slideInfoZone').injectInside($(this.galleryElement))).set({'opacity': 0}); var slideInfoZoneTitle = new Element('h2').injectInside(this.slideInfoZone.element); var slideInfoZoneDescription = new Element('p').injectInside(this.slideInfoZone.element); this.slideInfoZone.normalHeight = this.slideInfoZone.element.offsetHeight; this.slideInfoZone.element.setStyle('opacity', 0); }, changeInfoSlideShow: function () { this.hideInfoSlideShow.delay(10, this); this.showInfoSlideShow.delay(500, this); }, showInfoSlideShow: function () { this.fireEvent('onShowInfopane'); this.slideInfoZone.clearTimer(); element = this.slideInfoZone.element; element.getElement('h2').setHTML(this.galleryData[this.currentIter].title); element.getElement('p').setHTML(this.galleryData[this.currentIter].description); if (this.options.slideInfoZoneSlide) this.slideInfoZone.start({ 'opacity': [0, this.options.slideInfoZoneOpacity], 'height': [0, this.slideInfoZone.normalHeight] }); else this.slideInfoZone.start({'opacity': [0, this.options.slideInfoZoneOpacity]}); if (this.options.showCarousel) this.slideInfoZone.chain(this.centerCarouselOn.pass(this.currentIter, this)); return this.slideInfoZone; }, hideInfoSlideShow: function () { this.fireEvent('onHideInfopane'); this.slideInfoZone.clearTimer(); if (this.options.slideInfoZoneSlide) this.slideInfoZone.start({'opacity': 0, 'height': 0}); else this.slideInfoZone.start({'opacity': 0}); return this.slideInfoZone; }, makeLink: function (num) { this.currentLink.setProperties({ href: this.galleryData[num].link, title: this.galleryData[num].linkTitle }) if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) this.currentLink.setStyle('display', 'block'); }, clearLink: function () { this.currentLink.setProperties({href: '', title: ''}); if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) this.currentLink.setStyle('display', 'none'); }, /* To change the gallery data, those two functions : */ flushGallery: function () { this.galleryElements.each(function (myFx) { myFx.element.remove(); myFx = myFx.element = null; }); this.galleryElements = []; }, changeData: function (data) { this.galleryData = data; this.clearTimer(); this.flushGallery(); if (this.options.showCarousel) this.flushCarousel(); this.constructElements(); if (this.options.showCarousel) this.fillCarousel(); if (this.options.showInfopane) this.hideInfoSlideShow(); this.galleryInit = 1; this.lastIter = 0; this.currentIter = 0; this.doSlideShow(1); }, /* Plugins: HistoryManager */ initHistory: function () { this.fireEvent('onHistoryInit'); this.historyKey = this.galleryElement.id + '-picture'; if (this.options.customHistoryKey) this.historyKey = this.options.customHistoryKey(); this.history = HistoryManager.register( this.historyKey, [1], function (values) { if (parseInt(values[0]) - 1 < this.maxIter) this.goTo(parseInt(values[0]) - 1); }.bind(this), function (values) { return [this.historyKey, '(', values[0], ')'].join(''); }.bind(this), this.historyKey + '\\((\\d+)\\)'); this.addEvent('onChanged', function () { this.history.setValue(0, this.currentIter + 1); }.bind(this)); this.fireEvent('onHistoryInited'); } }; gallery = new Class(gallery); gallery.implement(new Events); gallery.implement(new Options); gallery.Transitions = new Abstract({ fade: function (oldFx, newFx, oldPos, newPos) { oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration; if (newPos > oldPos) newFx.start({opacity: 1}); else { newFx.set({opacity: 1}); oldFx.start({opacity: 0}); } }, crossfade: function (oldFx, newFx, oldPos, newPos) { oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration; newFx.start({opacity: 1}); oldFx.start({opacity: 0}); }, fadebg: function (oldFx, newFx, oldPos, newPos) { oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration / 2; oldFx.start({opacity: 0}).chain(newFx.start.pass([{opacity: 1}], newFx)); } }); /* All code copyright 2007 Jonathan Schemoul */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Follows: Preloader (class) * Simple class for preloading images with support for progress reporting * Copyright 2007 Tomocchino. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var Preloader = new Class({ Implements: [Events, Options], options: { root: '', period: 100 }, initialize: function (options) { this.setOptions(options); }, load: function (sources) { this.index = 0; this.images = []; this.sources = this.temps = sources; this.total = this.sources.length; this.fireEvent('onStart', [this.index, this.total]); this.timer = this.progress.periodical(this.options.period, this); this.sources.each(function (source, index) { this.images[index] = new Asset.image(this.options.root + source, { 'onload': function () { this.index++; if (this.images[index]) this.fireEvent('onLoad', [this.images[index], index, source]); }.bind(this), 'onerror': function () { this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this), 'onabort': function () { this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this) }); }, this); }, progress: function () { this.fireEvent('onProgress', [Math.min(this.index, this.total), this.total]); if (this.index >= this.total) this.complete(); }, complete: function () { $clear(this.timer); this.fireEvent('onComplete', [this.images]); }, cancel: function () { $clear(this.timer); } }); Preloader.implement(new Events, new Options); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Follows: formatString (function) * Original name: Yahoo.Tools.printf * Copyright Yahoo. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ function formatString() { var num = arguments.length; var oStr = arguments[0]; for (var i = 1; i < num; i++) { var pattern = "\\{" + (i - 1) + "\\}"; var re = new RegExp(pattern, "g"); oStr = oStr.replace(re, arguments[i]); } return oStr; }