/** * jQuery (a)Slideshow plugin * * Copyright (c) 2009 Anton Shevchuk * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * * @author Anton Shevchuk AntonShevchuk@gmail.com * @version 0.8.0 */ ;(function($) { defaults = { width:313, // width in px height:170, // height in px index:0, // start from frame number N time:2000, // time out beetwen slides history:false, // change/check location hash title:false, // show title titleshow:false,// always show title callback:null, // callback function - call when slide changed - receive index and label panel:false, // show controls panel play:true, // play slideshow loop:true, effect:'fade', // aviable fade, scrollUp/Down/Left/Right, zoom, zoomFade, growX, growY effecttime:3000,// aviable fast,slow,normal and any valid fx speed value filter:false, // remove
, empty
,

and other stuff nextclick:false, // bind content click next slide playclick:false, // bind content click play/stop playhover:false, // bind content hover play/stop playhoverr:false, // bind content hover stop/play (reverse of playhover) playframe:false, // show frame "Play Now!" loadframe:false, // show frame with "loading" fullscreen:false, // in full window size imgresize:false, // resize image to slideshow window imgzoom:false, // zoom image to slideshow window (for smaller side) imgcenter:false, // set image to center imgajax:false, // load images from links imglink:false, // go to external link by click linkajax:false, // load html from links controls :{ // show/hide controls elements 'hide':true, // show controls bar on mouse hover 'first':true, // goto first frame 'prev':true, // goto previouse frame (if it first go to last) 'play':true, // play slideshow 'next':true, // goto next frame (if it last go to first) 'last':true, // goto last frame 'help':true, // show help message 'counter':true // show slide counter } }; /** * Create a new instance of slideshow. * * @classDescription This class creates a new slideshow and manipulate it * * @return {Object} Returns a new slideshow object. * @constructor */ $.fn.slideshow = function(settings) { var _slideshow = this; /* * Construct */ this.each(function(){ var ext = $(this); this.playId = null; this.playFlag = false; this.playFrame = false; this.goToFlag = false; this.length = 0; this.inited = new Array(); this.titles = new Array(); /** * Build Html * @method */ this.build = function () { var _self = this; ext.wrapInner('

'); ext = ext.find('.aslideshow'); // filter content if (this.options.filter) { ext.find('.aslideshow-content > br').remove(); ext.find('.aslideshow-content > p:empty').remove(); ext.find('.aslideshow-content > div:empty').remove(); } // fullscreen if (this.options.fullscreen) { $('body').css({overflow:'hidden', padding:0}); this.options.width = $(window).width(); this.options.height = ($(window).height()>$(document).height())?$(window).height():$(document).height(); ext.addClass('slideshow-fullscreen'); } this.length = ext.find('.aslideshow-content > *').length; // build title if (this.options.title) { ext.prepend('
'); if (!this.options.titleshow) { ext.find('.aslideshow-label-place').hover(function(){ $(this).find('.aslideshow-label').fadeIn(); }, function() { $(this).find('.aslideshow-label').fadeOut(); }); ext.find('.aslideshow-label').hide(); } ext.find('.aslideshow-label-place').css('width', this.options.width); } // build panel if (this.options.panel) { ext.append('
'); panel = ext.find('.aslideshow-panel'); if (this.options.controls.first) panel.append('First'); if (this.options.controls.prev) panel.append(''); if (this.options.controls.play) panel.append('Play'); if (this.options.controls.next) panel.append(''); if (this.options.controls.last) panel.append('Last'); if (this.options.controls.help) { panel.append('Help'); panel.prepend('
'+this.options.help+'
'); } if (this.options.controls.counter) { panel.append(''+(this.options.index+1)+' / '+this.length+''); } if (this.options.controls.hide) { ext.find('.aslideshow-panel-place').hover(function(){ $(this).find('.aslideshow-panel').fadeIn(); }, function() { $(this).find('.aslideshow-panel').fadeOut(); }); panel.hide(); } ext.find('.aslideshow-panel-place').css('width', this.options.width); } /** * Set Size Options */ ext.css({width:this.options.width,height:this.options.height}); var content = ext.find('.aslideshow-content'); content.css({width:this.options.width,height:this.options.height}); // add playframe if (this.options.playframe) { this.playFrame = true; ext.append('
'); } // add loadframe if (this.options.loadframe) { ext.append('
'); } ext.find('.aslideshow-shadow').css({width:this.options.width,height:this.options.height}); // bind all events this.events(); // wrap children ext.find('.aslideshow-content > *').each(function(){ $(this).wrap('
'); }); // check play option if (this.options.play) { this.play(); } // init slide (replace by ajax etc) this.init(this.options.index); // show slide ext.find('.aslideshow-slide:eq('+this.options.index+')').show(); // update label this._label(); // init checker if (this.options.history) { setInterval(function(){ _self._check() }, 300); } return true; }; /** * Init N-slide * @method * @param {Integer} index * @param {Boolean} next */ this.init = function (index) { // initialize only ones for (var i = 0, loopCnt = this.inited.length; i < loopCnt; i++) { if (this.inited[i] === index) { return true; } } // index to inited stack this.inited.push(index); // current slide slide = ext.find('.aslideshow-slide:eq('+index+')'); var _self = this; var title = ''; var link = false; var name = slide.contents().attr('name'); if (name != '') { var rename = new RegExp("^((https?|ftp):\/\/)", "i"); if (rename.test(name)) { link = name; } } /** * Replace A to content from HREF */ if (slide.contents().is('a')) { var href = slide.contents().attr('href'); var domain = document.domain; domain = domain.replace(/\./i,"\."); // for strong check domain name var reimage = new RegExp("\.(png|gif|jpg|jpeg|svg)$", "i"); var relocal = new RegExp("^((https?:\/\/"+domain+")|(?!http:\/\/))", "i"); title = slide.contents().attr('title'); if (title.length == 0) title = slide.contents().html(); title = title.replace(/\"/i,'\''); // if you use single quotes for tag attribs if (this.options.imgajax && reimage.test(href)) { var img = new Image(); img.alt = title; this._load($(img), href, index); slide.contents().replaceWith(img); } else if (this.options.linkajax && relocal.test(href)) { $.get(href, function(data){ _self.goToSlide(index); slide.contents().replaceWith('
'+data+'
'); }); } else { this.goToSlide(index); // why? } } else { if (slide.contents().is("img")) { if ($.browser.msie) { var img = new Image(); img.alt = slide.contents().attr("alt"); this._load($(img), slide.contents().attr("src"), index); slide.contents().replaceWith(img); } else { this._load(slide.contents(), slide.contents().attr("src"), index); } } else { this.goToSlide(index); } if (slide.contents().attr('alt')) { title = slide.contents().attr('alt'); } else if (slide.contents().attr('title')) { title = slide.contents().attr('title'); } else if (slide.find('label:first').length>0) { slide.find('label:first').hide(); title = slide.find('label:first').html(); } } if (link) title = ''+title+''; this.titles[index] = title; /** * Go to external link by click */ if (this.options.imglink && link) { $(slide).css({cursor:'pointer'}) .click(function(){ document.location = link; return false; }); } /** * Play/stop on content click (like image and other) */ if (this.options.playclick) $(slide).css({cursor:'pointer'}) .click(function(){ if (_self.playId) { _self.stop(); } else { _self.play(); } return false; }); return false; }; /** * Load Image * * @param {Jquery} img * @param {String} src * @param {Integer} index * @return {Jquery} img */ this._load = function (img, src, index) { // console.log('Load image '+img); var _load = ext.find('.aslideshow-load').show(); var _self = this; img.load(function(){ _self._zoom(img); _self._resize(img); _self._center(img); _self.goToSlide(index); _load.hide(); }).error(function(){ // TODO: notify the user that the image could not be loaded _load.hide(); }) .attr('src', src); // fix for stupid browsers if (img.get(0).complete) { _self._zoom(img); _self._resize(img); _self._center(img); _self.goToSlide(index); _load.hide(); } return img; }; /** * Resize Image * @param {Jquery} el * @return {Jquery} el */ this._resize = function (el) { if (!this.options.imgresize && !this.options.fullscreen) return false; el.get(0).width = this.options.width; el.get(0).height = this.options.height; el.css({width:this.options.width,height:this.options.height}); return el; }; /** * Zoom Image * @param {Jquery} el * @return {Jquery} el */ this._zoom = function (el) { if (!this.options.imgzoom) return false; var nWidth = el.get(0).width; var nHeight = el.get(0).height; var Kw = this.options.width / nWidth; var Kh = this.options.height / nHeight; var K = (Kh > Kw) ? Kh : Kw; nWidth = nWidth * K; nHeight = nHeight * K; el.css({width:nWidth,height:nHeight}); el.get(0).width = nWidth; el.get(0).height = nHeight; return el; }; /** * Center Image * @param {Jquery} el * @return {Jquery} el */ this._center = function (el){ if (!this.options.imgcenter) return false; var nWidth = el.get(0).width ? el.get(0).width : el.get(0).offsetWidth; var nHeight = el.get(0).height ? el.get(0).height : el.get(0).offsetHeight; var nLeft = 0; var nTop = 0; if (nWidth != this.options.width) { nLeft = (Math.ceil((this.options.width - nWidth) / 2)) + 'px'; } // Now make sure it isn't taller if (nHeight != this.options.height) { nTop = (Math.ceil((this.options.height - nHeight) / 2)) + 'px'; } el.css({left:nLeft,top:nTop,position:'relative'}); return el; }; /** * Bind Events */ this.events = function() { var _self = this; /** * Go to next slide on content click (optional) */ if (_self.options.nextclick) ext.find('.aslideshow-content').click(function(){ _self.stop(); _self.next(); return false; }); /** * Goto first slide button */ if (this.options.controls.first) ext.find('a.first').click(function(){ _self.stop(); _self.goToSlide(0); return false; }); /** * Goto previouse slide button */ if (this.options.controls.prev) ext.find('a.prev').click(function(){ _self.stop(); _self.prev(); return false; }); /** * Play slideshow button */ if (this.options.controls.play) ext.find('a.play').click(function(){ if (_self.playId) { _self.stop(); } else { _self.play(); } return false; }); /** * Goto next slide button */ if (this.options.controls.next) ext.find('a.next').click(function(){ _self.stop(); _self.next(); return false; }); /** * Goto last slide button */ if (this.options.controls.last) ext.find('a.last').click(function(){ _self.stop(); _self.goToSlide(_self.length-1); return false; }); /** * Show help message */ if (this.options.controls.help) ext.find('a.help').click(function(){ _self.stop(); ext.find('.aslideshow-help').slideToggle(); return false; }); /** * Show playframe */ if (this.options.playframe) ext.find('.aslideshow-frame').click(function(){ ext.find('.aslideshow-frame').remove(); if (_self.options.playclick) setTimeout(function(){ _self.play() }, _self.options.time); return false; }); /** * Play/stop on slideshow hover */ if (this.options.playhover) ext.hover(function(){ if (!_self.playId) { _self.play(); } }, function(){ if (_self.playId) { _self.stop(); } }); /** * Stop/Play on slideshow hover */ if (this.options.playhoverr) ext.hover(function(){ if (_self.playId) { _self.stop(); } }, function(){ if (!_self.playId) { _self.play(); } }); }; /** * Update label of slide * @method */ this._label = function () { var title = this.getTitle(); if (this.options.callback) { this.options.callback (this.options.index, title); } // always load label of slide if (!this.options.title) return false; ext.find('.aslideshow-label').html(title); }; /** * Update page anchor * @method */ this._hash = function () { if (this.options.history) { document.location.hash = 'slide-' + (this.options.index + 1); } }; /** * Interval callback function * need for history navigation */ this._check = function () { // when animation in progress if (this.goToFlag) { return false; } // otherwise, check for location.hash var hash = document.location.hash; hash = hash.length?hash.substr(1):''; /* - check current url hash - is empty - goToSlide(0) - is exist - goToSlide(index) */ if (hash.length == 0) { this.goToSlide(0); } else { var tester = new RegExp('slide-([0-9]+)', 'i'); if (!tester.test(hash)) { // is not slideshow anchor return false; } var index = tester.exec(hash); if (index) { index = parseInt(index[1])-1; if (index >= 0 && index < this.length && index != this.options.index ) { // remove play frame if (this.playFrame) { $(this).find('.aslideshow-frame').remove(); } this.stop(); this.goToSlide(index); } } } }; /** * Return title of current slide * @method */ this.getTitle = function () { return this.titles[this.options.index]; }; /** * Goto previous slide * @method */ this.prev = function () { if (this.options.index == 0) { i = (this.length-1); } else { i = this.options.index - 1; } this.goToSlide(i); }; /** * Play Slideshow * @method */ this.play = function () { var _self = this; this.playFlag = true; this.playId = setTimeout(function(){ _self.next() }, this.options.time); ext.find('a.play').addClass('stop'); }; /** * Play Slideshow * @private * @method */ this._play = function () { var _self = this; // if it last frame if (this.options.index == (this.length-1) ) { this.stop(); // should be restart slideshow if ( this.options.loop ) { this.play(); } return false; } this.playId = setTimeout(function(){ _self.next(); }, this.options.time); return true; }; /** * Stop Slideshow * @method */ this.stop = function () { this.playFlag = false; ext.find('a.play').removeClass('stop'); clearTimeout(this.playId); this.playId = null; }; /** * Goto next slide * @method */ this.next = function () { if (this.options.index == (this.length-1)) { i = 0; } else { i = this.options.index + 1; } this.goToSlide(i); }; /** * Goto N-slide * @method * @param {Integer} n */ this.goToSlide = function(n) { switch (true) { case (this.options.index == n): case (!this.init(n, true)): return false; default: this.goToFlag = true; this._goToSlide(n); return true; } }; /** * Goto N-slide * @method * @param {Integer} n */ this._goToSlide = function(n) { var next = ext.find('.aslideshow-content > *:eq('+n+')'); var prev = ext.find('.aslideshow-content > *:eq('+this.options.index+')'); // restore next slide after all effects, set z-index = 0 for prev slide prev.css({zIndex:0}); next.css({zIndex:1, top: 0, left: 0, opacity: 1, width: this.options.width, height: this.options.height}); this.options.index = n; if (this.options.effect == 'random' ) { var r = Math.random(); r = Math.floor(r*12); } else { r = -1; } // effect between slides switch (true) { case (r == 0 || this.options.effect == 'scrollUp'): prev.css({width:'100%'}); next.css({top:0, height:0}); prevAni = {height: 0, top:this.options.height}; break; case (r == 1 || this.options.effect == 'scrollDown'): prev.css({width:'100%'}); next.css({top:this.options.height,height:0}); prevAni = {height: 0, top:0}; break; case (r == 2 || this.options.effect == 'scrollRight'): prev.css({right:0,left:'',height:'100%'}); next.css({right:'',left:0,height:'100%',width:'0%'}); prevAni = {width: 0}; break; case (r == 3 || this.options.effect == 'scrollLeft'): prev.css({right:'',left:0,height:'100%'}); next.css({right:0,left:'',height:'100%',width:'0%'}); prevAni = {width: 0}; break; case (r == 4 || this.options.effect == 'growX'): next.css({zIndex:2,opacity: 1,left: this.options.width/2, width: '0%', height:'100%'}); prevAni = {opacity: 0.8}; break; case (r == 5 || this.options.effect == 'growY'): next.css({opacity: 1,top: this.options.height/2, width:'100%', height: '0%'}); prevAni = {opacity: 0.8}; break; case (r == 6 || this.options.effect == 'zoom'): next.css({width: 0, height: 0, top: this.options.height/2, left: this.options.width/2}); prevAni = {width: 0, height: 0, top: this.options.height/2, left: this.options.width/2}; break; case (r == 7 || this.options.effect == 'zoomFade'): next.css({zIndex:1, opacity: 0,width: 0, height: 0, top: this.options.height/2, left: this.options.width/2}); prevAni = {opacity: 0, width: 0, height: 0, top: this.options.height/2, left: this.options.width/2}; break; case (r == 8 || this.options.effect == 'zoomTL'): next.css({zIndex:1, opacity: 0,width: this.options.width/2, height: this.options.height/2, top:0, left: 0}); prevAni = {opacity: 0, width: 0, height: 0, top: this.options.height, left: this.options.width}; break; case (r == 9 || this.options.effect == 'zoomBR'): next.css({zIndex:1, opacity: 0,width: this.options.width/2, height: this.options.height/2, top: this.options.height/2, left: this.options.width/2}); prevAni = {opacity: 0, width: 0, height: 0, top: 0, left: 0}; break; case (r == 10 || this.options.effect == 'fade'): default: prev.css({zIndex:0, opacity: 1}); next.css({zIndex:1, opacity: 0}); prevAni = {opacity: 0}; break; } var _self = this; prev.animate(prevAni,this.options.effecttime); // play next slide animation, hide prev slide, update label, update counter next.show().animate({top: 0, left: 0,opacity: 1, width: this.options.width, height: this.options.height}, this.options.effecttime, function () { prev.hide(); if (_self.playFlag) _self._play(); _self._label(); _self._counter(); _self._hash(); _self.goToFlag = false; }); }; /** * Update counter data * @method */ this._counter = function () { if (this.options.controls.counter) ext.find('.aslideshow-panel span.counter').html((this.options.index+1) + ' / ' + this.length); }; // Now initialize the slideshow this.options = $.extend({}, defaults, settings); if (typeof(settings) != 'undefined') { if (typeof(settings.controls) != 'undefined') this.options.controls = $.extend({}, defaults.controls, settings.controls); } this.build(); /** * Show slideshow */ ext.show(); return ext; }); /** * external functions - append to $ */ _slideshow.playSlide = function(){ _slideshow.each(function () { this.play(); }) }; _slideshow.stopSlide = function(){ _slideshow.each(function () { this.stop(); }) }; _slideshow.nextSlide = function(){ _slideshow.each(function () { this.next(); }) }; _slideshow.prevSlide = function(){ _slideshow.each(function () { this.prev(); }) }; _slideshow.getTitle = function(){ _slideshow.each(function () { this.getTitle(); }) }; _slideshow.goToSlide = function(n){ _slideshow.each(function () { this.goToSlide(n); }) }; return this; } })(jQuery);