/** * Copyright (c) 2010 Anders Ekdahl (http://coffeescripter.com/) * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. * * Version: 1.2.4 * * Demo and documentation: http://coffeescripter.com/code/ad-gallery/ */ (function($) { $.fn.adGallery = function(options) { var defaults = { loader_image: '/img/redigo_loader.gif', link_prefix: '/photo', start_at_index: 0, description_wrapper: false, thumb_opacity: 0.7, animate_first_image: false, animation_speed: 400, width: false, height: false, display_next_and_prev: true, display_back_and_forward: true, scroll_jump: 0, // If 0, it jumps the width of the container slideshow: { enable: true, autostart: false, speed: 3000, start_label: 'Запустить слайд-шоу', stop_label: 'Остановить слайд-шоу', stop_on_scroll: true, countdown_prefix: ':0', countdown_sufix: '', onStart: false, onStop: false }, effect: 'slide-hori', // or 'slide-vert', 'fade', or 'resize', 'none' enable_keyboard_move: true, cycle: true, callbacks: { init: false, afterImageVisible: function() { if ("pushState" in history) { var loc = window.location.href; var ps = loc.lastIndexOf(defaults.link_prefix); var imgIndex = loc.substring(ps, loc.length); var index = parseInt($('.ad-thumb' + this.current_index).parent('li').data('position')); if (isNaN(index)) { index = 1; } else { index += 1; } if(loc.indexOf(defaults.link_prefix) != -1 && imgIndex.length > 0) loc = loc.replace(imgIndex, defaults.link_prefix + '/' + index); else loc += defaults.link_prefix + '/' + index; history.pushState("", document.title, loc); } else { document.location.hash = '#' + (this.current_index + 1); } }, beforeImageVisible: false } }; var settings = $.extend(false, defaults, options); if (options && options.slideshow) { settings.slideshow = $.extend(false, defaults.slideshow, options.slideshow); } if (!settings.slideshow.enable) { settings.slideshow.autostart = false; } var galleries = []; $(this).each(function() { var gallery = new AdGallery(this, settings); galleries[galleries.length] = gallery; }); // Sorry, breaking the jQuery chain because the gallery instances // are returned so you can fiddle with them return galleries; }; function VerticalSlideAnimation(img_container, direction, desc) { var current_top = parseInt(img_container.css('top'), 10); if (direction == 'left') { var old_image_top = '-' + this.image_wrapper_height + 'px'; img_container.css('top', this.image_wrapper_height + 'px'); } else { var old_image_top = this.image_wrapper_height + 'px'; img_container.css('top', '-' + this.image_wrapper_height + 'px'); } if (desc) { desc.css('bottom', '-' + desc[0].offsetHeight + 'px'); desc.animate({bottom: 0}, this.settings.animation_speed * 2); } if (this.current_description) { this.current_description.animate({bottom: '-' + this.current_description[0].offsetHeight + 'px'}, this.settings.animation_speed * 2); } return {old_image: {top: old_image_top}, new_image: {top: current_top}}; } function HorizontalSlideAnimation(img_container, direction, desc) { var current_left = parseInt(img_container.css('left'), 10); //var current_left = 0; if (direction == 'left') { var old_image_left = '-' + this.image_wrapper_width + 'px'; img_container.css('left', this.image_wrapper_width + 'px'); } else { var old_image_left = this.image_wrapper_width + 'px'; img_container.css('left', '-' + this.image_wrapper_width + 'px'); } // if (desc) { // desc.css('bottom', '-' + desc[0].offsetHeight + 'px'); // desc.animate({bottom: 0}, this.settings.animation_speed * 2); // } if (this.current_description) { this.current_description.animate({bottom: '-' + this.current_description[0].offsetHeight + 'px'}, this.settings.animation_speed * 2); } return {old_image: {left: old_image_left}, new_image: {left: current_left}}; } function ResizeAnimation(img_container, direction, desc) { var image_width = img_container.width(); var image_height = img_container.height(); var current_left = parseInt(img_container.css('left'), 10); var current_top = parseInt(img_container.css('top'), 10); img_container.css({width: 0, height: 0, top: this.image_wrapper_height / 2, left: this.image_wrapper_width / 2}); return {old_image: {width: 0, height: 0, top: this.image_wrapper_height / 2, left: this.image_wrapper_width / 2}, new_image: {width: image_width, height: image_height, top: current_top, left: current_left}}; } function FadeAnimation(img_container, direction, desc) { img_container.css('opacity', 0); return {old_image: {opacity: 0}, new_image: {opacity: 1}}; } // Sort of a hack, will clean this up... eventually function NoneAnimation(img_container, direction, desc) { img_container.css('opacity', 0); return {old_image: {opacity: 0}, new_image: {opacity: 1}, speed: 0}; } function AdGallery(wrapper, settings) { this.init(wrapper, settings); } AdGallery.prototype = { // Elements wrapper: false, image_wrapper: false, author_wrapper: '', gallery_info: false, descShow: true, mainDesc: '', nav: false, loader: false, preloads: false, thumbs_wrapper: false, scroll_back: false, scroll_forward: false, next_link: false, prev_link: false, slideshow: false, image_wrapper_width: 0, image_wrapper_height: 0, current_index: 0, current_image: false, current_description: '', nav_display_width: 0, settings: false, images: false, in_transition: false, animations: false, link_prefix: '/photo', init: function(wrapper, settings) { var context = this; this.wrapper = $(wrapper); this.settings = settings; this.setupElements(); this.setupAnimations(); if (this.settings.width) { this.image_wrapper_width = this.settings.width; this.image_wrapper.width(this.settings.width); this.wrapper.width(this.settings.width); } else { this.image_wrapper_width = this.image_wrapper.width(); } if (this.settings.height) { this.image_wrapper_height = this.settings.height; this.image_wrapper.height(this.settings.height); } else { this.image_wrapper_height = this.image_wrapper.height(); } this.nav_display_width = this.nav.width(); this.current_index = 0; this.current_image = false; this.current_description = ''; this.in_transition = false; this.findImages(); if (this.settings.display_next_and_prev) { this.initNextAndPrev(); } // The slideshow needs a callback to trigger the next image to be shown // but we don't want to give it access to the whole gallery instance var nextimage_callback = function(callback) { return context.nextImage(callback); }; this.slideshow = new AdGallerySlideshow(nextimage_callback, this.settings.slideshow); //this.slideshow.create().insertBefore(this.controls.find('.ad-info')); this.controls.append(this.slideshow.create()); if (this.settings.slideshow.enable) { this.slideshow.enable(); } else { this.slideshow.disable(); } if (this.settings.display_back_and_forward && this.images.length > 4) { this.initBackAndForward(); } if (this.settings.enable_keyboard_move) { this.initKeyEvents(); } var start_at = parseInt(this.settings.start_at_index, 10); if ("pushState" in history){ var ps = window.location.href.lastIndexOf('/'); var imgIndex = window.location.href.substring(ps + 1, window.location.href.length); if(imgIndex.length > 0) { start_at = parseInt(imgIndex.replace(/[^0-9]+/g, '')); if ((start_at * 1) != start_at) { start_at = this.settings.start_at_index; } else start_at = (start_at - 1 < 0) ? 0 : (start_at - 1); } } else { if (window.location.hash && window.location.hash.indexOf('#img') === 0) { start_at = parseInt(window.location.hash.replace(/[^0-9]+/g, '')); // Check if it's a number if ((start_at * 1) != start_at) { start_at = this.settings.start_at_index; } else start_at = (start_at - 1 < 0) ? 0 : (start_at - 1); } } this.loading(true); this.showImage(start_at, function() { // We don't want to start the slideshow before the image has been // displayed if (context.settings.slideshow.autostart) { context.preloadImage(start_at + 1); context.slideshow.start(); } } ); this.fireCallback(this.settings.callbacks.init); $(window).resize(function(){ var h = Math.round(context.image_wrapper.width() * 2 / 3), current_img = context.images[context.current_index], vertical = (current_img.size.width < current_img.size.height) ? true : false, desc_h = 0; if(context.current_description) desc_h = context.current_description.height(); context.image_wrapper.css('height', h + 'px'); context.image_wrapper_height = h; context.image_wrapper_width = context.image_wrapper.width(); if(context.next_link && context.prev_link){ context.next_link.css('height', (h - desc_h) + 'px'); context.prev_link.css('height', (h - desc_h) + 'px'); } var size = context._getContainedImageSize(current_img.size.width, current_img.size.height); if(vertical) context.current_image.css({height: h + 'px', width: size.width + 'px'}); else if(size.height >= context.image_wrapper_height) context.current_image.css('height', h + 'px'); context._centerImage(context.current_image, size.width, size.height); if(context.current_index == 0) context.mainDesc.css({ height: context.current_image.css('height'), top: context.current_image.css('top') }); }) }, setupAnimations: function() { this.animations = { 'slide-vert': VerticalSlideAnimation, 'slide-hori': HorizontalSlideAnimation, 'resize': ResizeAnimation, 'fade': FadeAnimation, 'none': NoneAnimation }; }, setImgLocation: function(imgId) { if ("pushState" in history) { var loc = window.location.href; var ps = loc.lastIndexOf(this.link_prefix); var imgIndex = loc.substring(ps, loc.length); var index = parseInt($('.ad-thumb' + this.current_index).parent('li').data('position')) + 1; if(loc.indexOf(this.link_prefix) != -1 && imgIndex.length > 0) loc = loc.replace(imgIndex, this.link_prefix + '/' + index); else loc += this.link_prefix + '/' + index; history.pushState("", document.title, loc); } else { document.location.hash = '#' + imgId; } }, setupElements: function() { var context = this; this.mainDesc = this.wrapper.find('.ad-description'); this.controls = this.wrapper.find('.ad-controls'); var descShowHideLink = this.controls.find('.toggle_description'); if(descShowHideLink){ descShowHideLink.click(function(){ if($(this).hasClass('hide_desc')){ $(this).removeClass('hide_desc').addClass('show_desc').html('Показать описание'); if(context.current_description) context.current_description.hide(); context.descShow = false; }else{ $(this).removeClass('show_desc').addClass('hide_desc').html('Спрятать описание'); if(context.current_description) context.current_description.show(); context.descShow = true; } }) } this.gallery_info = $('.photos_number'); this.author_wrapper = this.wrapper.find('.ad-author'); this.image_wrapper = this.wrapper.find('.ad-image-wrapper'); var h = Math.round(this.image_wrapper.width() * 2 / 3) - 15; this.image_wrapper.css('height', h + 'px'); this.nav = this.wrapper.find('.ad-nav'); this.thumbs_wrapper = this.nav.find('.ad-thumbs'); this.preloads = $('
'); this.loader = $(''); this.image_wrapper.append(this.loader); this.loader.hide(); $(document.body).append(this.preloads); }, loading: function(bool) { if (bool) { this.loader.show(); } else { this.loader.hide(); } }, addAnimation: function(name, fn) { if ($.isFunction(fn)) { this.animations[name] = fn; } }, findImages: function() { var context = this; this.images = []; var thumb_wrapper_width = 0; var thumbs_loaded = 0; var thumbs = this.thumbs_wrapper.find('a.path'); var thumb_count = thumbs.length; thumbs.each( function(i) { var link = $(this); var image_src = link.attr('href'), thumb = link.find('img'), type = link.find('img').data('type'), parent = link.parents('li'), author = parent.find('.author').html(); // Check if the thumb has already loaded if (!context.isImageLoaded(thumb[0])) { thumb.load( function() { thumb_wrapper_width += this.parentNode.parentNode.offsetWidth; thumbs_loaded++; } ); } else { thumb_wrapper_width += thumb[0].parentNode.parentNode.offsetWidth; thumbs_loaded++; } link.addClass('ad-thumb' + i); link.click( function() { $(document).trigger('ajax.reload'); context.showImage(i); context.slideshow.stop(); return false; }) var link = false; if (thumb.data('ad-link')) { link = thumb.data('ad-link'); } else if (thumb.attr('longdesc') && thumb.attr('longdesc').length) { link = thumb.attr('longdesc'); } var desc = ''; if (thumb.data('ad-desc')) { desc = thumb.data('ad-desc'); } var title = false; if (parent.find('.ad-title')) { title = parent.find('.ad-title'); } else if (thumb.attr('title') && thumb.attr('title').length) { title = thumb.attr('title'); } context.images[i] = { thumb: thumb.attr('src'), image: image_src, error: false, preloaded: false, desc: desc, title: title, size: false, link: link, type: type, author: author }; } ); // Wait until all thumbs are loaded, and then set the width of the ul var inter = setInterval( function() { if (thumb_count == thumbs_loaded) { thumb_wrapper_width -= 100; var list = context.nav.find('.ad-thumb-list'); list.css('width', thumb_wrapper_width + 'px'); var i = 1; var last_height = list.height(); while (i < 201) { list.css('width', (thumb_wrapper_width + i) + 'px'); if (last_height != list.height()) { break; } last_height = list.height(); i++; } clearInterval(inter); } }, 100 ); }, initKeyEvents: function() { var context = this; $(document).keydown(function(e) { if($(e.target).parents('form').size() > 0) return; if (e.keyCode == 39) { // right arrow context.nextImage(); context.slideshow.stop(); } else if (e.keyCode == 37) { // left arrow context.prevImage(); context.slideshow.stop(); } }); }, initNextAndPrev: function() { this.next_link = $(''); this.prev_link = $(''); this.image_wrapper.append(this.next_link); this.image_wrapper.append(this.prev_link); var context = this; this.prev_link.add(this.next_link).mouseover( function(e) { var desc_h = 0; if(context.current_description) desc_h = context.current_description.height(); // IE 6 hides the wrapper div, so we have to set it's width $(this).css('height', (context.image_wrapper_height - desc_h) + 'px'); $(this).find('i').show(); } ).mouseout( function(e) { $(this).find('i').hide(); } ).click( function() { if ($(this).is('.ad-next')) context.nextImage(); else context.prevImage(); context.slideshow.stop(); } ) //.find('div').css('opacity', 0.7); }, initBackAndForward: function() { var context = this; this.scroll_forward = $(''); this.scroll_back = $(''); this.nav.append(this.scroll_forward); this.nav.prepend(this.scroll_back); var has_scrolled = 0; var thumbs_scroll_interval = false; $(this.scroll_back).add(this.scroll_forward).click( function() { // We don't want to jump the whole width, since an image // might be cut at the edge var width = context.nav_display_width - 50; if (context.settings.scroll_jump > 0) { var width = context.settings.scroll_jump; } if ($(this).is('.ad-forward')) { var left = context.thumbs_wrapper.scrollLeft() + width; } else { var left = context.thumbs_wrapper.scrollLeft() - width; } if (context.settings.slideshow.stop_on_scroll) { context.slideshow.stop(); } context.thumbs_wrapper.animate({scrollLeft: left + 'px'}); return false; } ).css('opacity', 0.6).hover( function() { var direction = 'left'; if ($(this).is('.ad-forward')) { direction = 'right'; } thumbs_scroll_interval = setInterval( function() { has_scrolled++; // Don't want to stop the slideshow just because we scrolled a pixel or two if (has_scrolled > 30 && context.settings.slideshow.stop_on_scroll) { context.slideshow.stop(); } var left = context.thumbs_wrapper.scrollLeft() + 1; if (direction == 'left') { left = context.thumbs_wrapper.scrollLeft() - 1; } context.thumbs_wrapper.scrollLeft(left); }, 10 ); $(this).css('opacity', 1); }, function() { has_scrolled = 0; clearInterval(thumbs_scroll_interval); $(this).css('opacity', 0.6); } ); }, _afterShow: function() { this.gallery_info.html((this.current_index + 1) + ' / ' + this.images.length); if (this.current_index == (this.images.length - 1)) { $(this.next_link).addClass('ad-repeat'); this.slideshow.stop(); }else if($(this.next_link).hasClass('ad-repeat')) $(this.next_link).removeClass('ad-repeat'); if (!this.settings.cycle && this.images.length > 1) { // Needed for IE this.prev_link.show().css('height', this.image_wrapper_height); this.next_link.show().css('height', this.image_wrapper_height); if (this.current_index == (this.images.length - 1)) { this.next_link.hide(); } if (this.current_index == 0) { this.prev_link.hide(); } } if(this.current_index == 0){ this.mainDesc.css({ height: this.current_image.css('height'), top: this.current_image.css('top') }); } this.fireCallback(this.settings.callbacks.afterImageVisible); }, /** * Checks if the image is small enough to fit inside the container * If it's not, shrink it proportionally */ _getContainedImageSize: function(image_width, image_height) { if (image_height > this.image_wrapper_height) { var ratio = image_width / image_height; image_height = this.image_wrapper_height; image_width = this.image_wrapper_height * ratio; } if (image_width > this.image_wrapper_width) { var ratio = image_height / image_width; image_width = this.image_wrapper_width; image_height = Math.round(this.image_wrapper_width * ratio); } return {width: image_width, height: image_height}; }, /** * If the image dimensions are smaller than the wrapper, we position * it in the middle anyway */ _centerImage: function(img_container, image_width, image_height) { img_container.css('top', '0px'); if(image_width > image_height){ if (img_container.height() > 0 && img_container.height() < this.image_wrapper_height) { var dif = this.image_wrapper_height - img_container.height(); img_container.css('top', Math.round(dif / 2) + 'px'); }else{ var real_img = img_container.find('img'), real_img_h = real_img.height(); var dif = img_container.height() - real_img_h; real_img.css('margin-top', Math.round(dif / 2) + 'px'); } } //if (img_container.width() < this.image_wrapper_width && image_width < image_height) { if (img_container.width() < this.image_wrapper_width) { var dif = this.image_wrapper_width - img_container.width(); img_container.css('left', Math.round(dif / 2) + 'px'); } }, _getDescription: function(image) { //var desc = ''; console.log(image); console.log(image.title); if (image.desc.length || image.title.length) { var title = image.title.length ? image.title.html() : '', desc = image.desc.length ? image.desc : ''; desc = $('