﻿(function ($) { var undef, window = this, doc = window.document, $doc = $(doc), $win = $(window), VERSION = 1.25, DEBUG = true, TIMEOUT = 30000, DUMMY = false, NAV = navigator.userAgent.toLowerCase(), HASH = window.location.hash.replace(/#\//, ''), IE = (function () { var v = 3, div = doc.createElement('div'), all = div.getElementsByTagName('i'); do { div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->' } while (all[0]); return v > 4 ? v : undef } ()), DOM = function () { return { html: doc.documentElement, body: doc.body, head: doc.getElementsByTagName('head')[0], title: doc.title} }, _eventlist = 'data ready thumbnail loadstart loadfinish image play pause progress ' + 'fullscreen_enter fullscreen_exit idle_enter idle_exit rescale ' + 'lightbox_open lightbox_close lightbox_image', _events = (function () { var evs = []; $.each(_eventlist.split(' '), function (i, ev) { evs.push(ev); if (/_/.test(ev)) { evs.push(ev.replace(/_/g, '')) } }); return evs } ()), _legacyOptions = function (options) { var n; if (typeof options !== 'object') { return options } $.each(options, function (key, value) { if (/^[a-z]+_/.test(key)) { n = ''; $.each(key.split('_'), function (i, k) { n += i > 0 ? k.substr(0, 1).toUpperCase() + k.substr(1) : k }); options[n] = value; delete options[key] } }); return options }, _patchEvent = function (type) { if ($.inArray(type, _events) > -1) { return Galleria[type.toUpperCase()] } return type }, _timeouts = { trunk: {}, add: function (id, fn, delay, loop) { loop = loop || false; this.clear(id); if (loop) { var old = fn; fn = function () { old(); _timeouts.add(id, fn, delay) } } this.trunk[id] = window.setTimeout(fn, delay) }, clear: function (id) { var del = function (i) { window.clearTimeout(this.trunk[i]); delete this.trunk[i] }, i; if (!!id && id in this.trunk) { del.call(_timeouts, id) } else if (typeof id === 'undefined') { for (i in this.trunk) { if (this.trunk.hasOwnProperty(i)) { del.call(_timeouts, i) } } } } }, _galleries = [], _instances = [], _hasError = false, _canvas = false, _pool = [], _themeLoad = function (theme) { Galleria.theme = theme; $.each(_pool, function (i, instance) { instance._init.call(instance) }) }, Utils = (function () { return { array: function (obj) { return Array.prototype.slice.call(obj, 0) }, create: function (className, nodeName) { nodeName = nodeName || 'div'; var elem = doc.createElement(nodeName); elem.className = className; return elem }, getScriptPath: function (src) { src = src || $('script:last').attr('src'); var slices = src.split('/'); if (slices.length == 1) { return '' } slices.pop(); return slices.join('/') + '/' }, animate: (function () { var transition = (function (style) { var props = 'transition WebkitTransition MozTransition OTransition'.split(' '), i; if (window.opera) { return false } for (i = 0; props[i]; i++) { if (typeof style[props[i]] !== 'undefined') { return props[i] } } return false } ((doc.body || doc.documentElement).style)); var endEvent = { MozTransition: 'transitionend', OTransition: 'oTransitionEnd', WebkitTransition: 'webkitTransitionEnd', transition: 'transitionend'}[transition]; var easings = { _default: [0.25, 0.1, 0.25, 1], galleria: [0.645, 0.045, 0.355, 1], galleriaIn: [0.55, 0.085, 0.68, 0.53], galleriaOut: [0.25, 0.46, 0.45, 0.94], ease: [0.25, 0, 0.25, 1], linear: [0.25, 0.25, 0.75, 0.75], 'ease-in': [0.42, 0, 1, 1], 'ease-out': [0, 0, 0.58, 1], 'ease-in-out': [0.42, 0, 0.58, 1] }; var setStyle = function (elem, value, suffix) { var css = {}; suffix = suffix || 'transition'; $.each('webkit moz ms o'.split(' '), function () { css['-' + this + '-' + suffix] = value }); elem.css(css) }; var clearStyle = function (elem) { setStyle(elem, 'none', 'transition'); if (Galleria.WEBKIT && Galleria.TOUCH) { setStyle(elem, 'translate3d(0,0,0)', 'transform'); if (elem.data('revert')) { elem.css(elem.data('revert')); elem.data('revert', null) } } }; var change, strings, easing, syntax, revert, form, css; return function (elem, to, options) { options = $.extend({ duration: 400, complete: function () { }, stop: false }, options); elem = $(elem); if (!options.duration) { elem.css(to); options.complete.call(elem[0]); return } if (!transition) { elem.animate(to, options); return } if (options.stop) { elem.unbind(endEvent); clearStyle(elem) } change = false; $.each(to, function (key, val) { css = elem.css(key); if (Utils.parseValue(css) != Utils.parseValue(val)) { change = true } elem.css(key, css) }); if (!change) { window.setTimeout(function () { options.complete.call(elem[0]) }, options.duration); return } strings = []; easing = options.easing in easings ? easings[options.easing] : easings._default; syntax = ' ' + options.duration + 'ms' + ' cubic-bezier(' + easing.join(',') + ')'; window.setTimeout(function () { elem.one(endEvent, (function (elem) { return function () { clearStyle(elem); options.complete.call(elem[0]) } } (elem))); if (Galleria.WEBKIT && Galleria.TOUCH) { revert = {}; form = [0, 0, 0]; $.each(['left', 'top'], function (i, m) { if (m in to) { form[i] = (Utils.parseValue(to[m]) - Utils.parseValue(elem.css(m))) + 'px'; revert[m] = to[m]; delete to[m] } }); if (form[0] || form[1]) { elem.data('revert', revert); strings.push('-webkit-transform' + syntax); setStyle(elem, 'translate3d(' + form.join(',') + ')', 'transform') } } $.each(to, function (p, val) { strings.push(p + syntax) }); setStyle(elem, strings.join(',')); elem.css(to) }, 1) } } ()), removeAlpha: function (elem) { if (IE < 9 && elem) { var style = elem.style, currentStyle = elem.currentStyle, filter = currentStyle && currentStyle.filter || style.filter || ""; if (/alpha/.test(filter)) { style.filter = filter.replace(/alpha\([^)]*\)/i, '') } } }, forceStyles: function (elem, styles) { elem = $(elem); if (elem.attr('style')) { elem.data('styles', elem.attr('style')).removeAttr('style') } elem.css(styles) }, revertStyles: function () { $.each(Utils.array(arguments), function (i, elem) { elem = $(elem); elem.removeAttr('style'); elem.attr('style', ''); if (elem.data('styles')) { elem.attr('style', elem.data('styles')).data('styles', null) } }) }, moveOut: function (elem) { Utils.forceStyles(elem, { position: 'absolute', left: -10000 }) }, moveIn: function () { Utils.revertStyles.apply(Utils, Utils.array(arguments)) }, elem: function (elem) { if (elem instanceof $) { return { $: elem, dom: elem[0]} } else { return { $: $(elem), dom: elem} } }, hide: function (elem, speed, callback) { callback = callback || function () { }; var el = Utils.elem(elem), $elem = el.$; elem = el.dom; if (!$elem.data('opacity')) { $elem.data('opacity', $elem.css('opacity')) } var style = { opacity: 0 }; if (speed) { var complete = IE < 9 && elem ? function () { Utils.removeAlpha(elem); elem.style.visibility = 'hidden'; callback.call(elem) } : callback; Utils.animate(elem, style, { duration: speed, complete: complete, stop: true }) } else { if (IE < 9 && elem) { Utils.removeAlpha(elem); elem.style.visibility = 'hidden' } else { $elem.css(style) } } }, show: function (elem, speed, callback) { callback = callback || function () { }; var el = Utils.elem(elem), $elem = el.$; elem = el.dom; var saved = parseFloat($elem.data('opacity')) || 1, style = { opacity: saved }; if (speed) { if (IE < 9) { $elem.css('opacity', 0); elem.style.visibility = 'visible' } var complete = IE < 9 && elem ? function () { if (style.opacity == 1) { Utils.removeAlpha(elem) } callback.call(elem) } : callback; Utils.animate(elem, style, { duration: speed, complete: complete, stop: true }) } else { if (IE < 9 && style.opacity == 1 && elem) { Utils.removeAlpha(elem); elem.style.visibility = 'visible' } else { $elem.css(style) } } }, optimizeTouch: (function () { var node, evs, fakes, travel, evt = {}, handler = function (e) { e.preventDefault(); evt = $.extend({}, e, true) }, attach = function () { this.evt = evt }, fake = function () { this.handler.call(node, this.evt) }; return function (elem) { $(elem).bind('touchend', function (e) { node = e.target; travel = true; while (node.parentNode && node != e.currentTarget && travel) { evs = $(node).data('events'); fakes = $(node).data('fakes'); if (evs && 'click' in evs) { travel = false; e.preventDefault(); $(node).click(handler).click(); evs.click.pop(); $.each(evs.click, attach); $(node).data('fakes', evs.click); delete evs.click } else if (fakes) { travel = false; e.preventDefault(); $.each(fakes, fake) } node = node.parentNode } }) } } ()), addTimer: function () { _timeouts.add.apply(_timeouts, Utils.array(arguments)); return this }, clearTimer: function () { _timeouts.clear.apply(_timeouts, Utils.array(arguments)); return this }, wait: function (options) { options = $.extend({ until: function () { return false }, success: function () { }, error: function () { Galleria.raise('Could not complete wait function.') }, timeout: 3000 }, options); var start = Utils.timestamp(), elapsed, now, fn = function () { now = Utils.timestamp(); elapsed = now - start; if (options.until(elapsed)) { options.success(); return false } if (now >= start + options.timeout) { options.error(); return false } window.setTimeout(fn, 10) }; window.setTimeout(fn, 10) }, toggleQuality: function (img, force) { if ((IE !== 7 && IE !== 8) || !img) { return } if (typeof force === 'undefined') { force = img.style.msInterpolationMode === 'nearest-neighbor' } img.style.msInterpolationMode = force ? 'bicubic' : 'nearest-neighbor' }, insertStyleTag: function (styles) { var style = doc.createElement('style'); DOM().head.appendChild(style); if (style.styleSheet) { style.styleSheet.cssText = styles } else { var cssText = doc.createTextNode(styles); style.appendChild(cssText) } }, loadScript: function (url, callback) { var done = false, script = $('<scr' + 'ipt>').attr({ src: url, async: true }).get(0); script.onload = script.onreadystatechange = function () { if (!done && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) { done = true; script.onload = script.onreadystatechange = null; if (typeof callback === 'function') { callback.call(this, this) } } }; DOM().head.appendChild(script) }, parseValue: function (val) { if (typeof val === 'number') { return val } else if (typeof val === 'string') { var arr = val.match(/\-?\d|\./g); return arr && arr.constructor === Array ? arr.join('') * 1 : 0 } else { return 0 } }, timestamp: function () { return new Date().getTime() }, loadCSS: function (href, id, callback) { var link, ready = false, length; $('link[rel=stylesheet]').each(function () { if (new RegExp(href).test(this.href)) { link = this; return false } }); if (typeof id === 'function') { callback = id; id = undef } callback = callback || function () { }; if (link) { callback.call(link, link); return link } length = doc.styleSheets.length; if (DEBUG) { href += '?' + Utils.timestamp() } if ($('#' + id).length) { $('#' + id).attr('href', href); length--; ready = true } else { link = $('<link>').attr({ rel: 'stylesheet', href: href, id: id }).get(0); window.setTimeout(function () { var styles = $('link[rel="stylesheet"], style'); if (styles.length) { styles.get(0).parentNode.insertBefore(link, styles[0]) } else { DOM().head.appendChild(link) } if (IE) { if (length >= 31) { Galleria.raise('You have reached the browser stylesheet limit (31)', true); return } link.onreadystatechange = function (e) { if (!ready && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) { ready = true } } } else { if (!(new RegExp('file://', 'i').test(href))) { $.ajax({ url: href, success: function () { ready = true }, error: function (e) { if (e.isRejected() && Galleria.WEBKIT) { ready = true } } }) } else { ready = true } } }, 10) } if (typeof callback === 'function') { Utils.wait({ until: function () { return ready && doc.styleSheets.length > length }, success: function () { window.setTimeout(function () { callback.call(link, link) }, 100) }, error: function () { Galleria.raise('Theme CSS could not load', true) }, timeout: 10000 }) } return link } } } ()), _transitions = (function () { var _slide = function (params, complete, fade, door) { var easing = this.getOptions('easing'), distance = this.getStageWidth(), from = { left: distance * (params.rewind ? -1 : 1) }, to = { left: 0 }; if (fade) { from.opacity = 0; to.opacity = 1 } $(params.next).css(from); Utils.animate(params.next, to, { duration: params.speed, complete: (function (elems) { return function () { complete(); elems.css({ left: 0 }) } } ($(params.next).add(params.prev))), queue: false, easing: easing }); if (door) { params.rewind = !params.rewind } if (params.prev) { from = { left: 0 }; to = { left: distance * (params.rewind ? 1 : -1) }; if (fade) { from.opacity = 1; to.opacity = 0 } $(params.prev).css(from); Utils.animate(params.prev, to, { duration: params.speed, queue: false, easing: easing, complete: function () { $(this).css('opacity', 0) } }) } }; return { fade: function (params, complete) { $(params.next).css('opacity', 0).show(); Utils.animate(params.next, { opacity: 1 }, { duration: params.speed, complete: complete }); if (params.prev) { $(params.prev).css('opacity', 1).show(); Utils.animate(params.prev, { opacity: 0 }, { duration: params.speed }) } }, flash: function (params, complete) { $(params.next).css('opacity', 0); if (params.prev) { Utils.animate(params.prev, { opacity: 0 }, { duration: params.speed / 2, complete: function () { Utils.animate(params.next, { opacity: 1 }, { duration: params.speed, complete: complete }) } }) } else { Utils.animate(params.next, { opacity: 1 }, { duration: params.speed, complete: complete }) } }, pulse: function (params, complete) { if (params.prev) { $(params.prev).hide() } $(params.next).css('opacity', 0).show(); Utils.animate(params.next, { opacity: 1 }, { duration: params.speed, complete: complete }) }, slide: function (params, complete) { _slide.apply(this, Utils.array(arguments)) }, fadeslide: function (params, complete) { _slide.apply(this, Utils.array(arguments).concat([true])) }, doorslide: function (params, complete) { _slide.apply(this, Utils.array(arguments).concat([false, true])) } } } ()); Galleria = function () { var self = this; this._theme = undef; this._options = {}; this._playing = false; this._playtime = 5000; this._active = null; this._queue = { length: 0 }; this._data = []; this._dom = {}; this._thumbnails = []; this._layers = []; this._initialized = false; this._firstrun = false; this._stageWidth = 0; this._stageHeight = 0; this._target = undef; this._id = Math.random(); var divs = 'container stage images image-nav image-nav-left image-nav-right ' + 'info info-text info-title info-description ' + 'thumbnails thumbnails-list thumbnails-container thumb-nav-left thumb-nav-right ' + 'loader counter tooltip', spans = 'current total'; $.each(divs.split(' '), function (i, elemId) { self._dom[elemId] = Utils.create('galleria-' + elemId) }); $.each(spans.split(' '), function (i, elemId) { self._dom[elemId] = Utils.create('galleria-' + elemId, 'span') }); var keyboard = this._keyboard = { keys: { 'UP': 38, 'DOWN': 40, 'LEFT': 37, 'RIGHT': 39, 'RETURN': 13, 'ESCAPE': 27, 'BACKSPACE': 8, 'SPACE': 32 }, map: {}, bound: false, press: function (e) { var key = e.keyCode || e.which; if (key in keyboard.map && typeof keyboard.map[key] === 'function') { keyboard.map[key].call(self, e) } }, attach: function (map) { var key, up; for (key in map) { if (map.hasOwnProperty(key)) { up = key.toUpperCase(); if (up in keyboard.keys) { keyboard.map[keyboard.keys[up]] = map[key] } else { keyboard.map[up] = map[key] } } } if (!keyboard.bound) { keyboard.bound = true; $doc.bind('keydown', keyboard.press) } }, detach: function () { keyboard.bound = false; keyboard.map = {}; $doc.unbind('keydown', keyboard.press) } }; var controls = this._controls = { 0: undef, 1: undef, active: 0, swap: function () { controls.active = controls.active ? 0 : 1 }, getActive: function () { return controls[controls.active] }, getNext: function () { return controls[1 - controls.active] } }; var carousel = this._carousel = { next: self.$('thumb-nav-right'), prev: self.$('thumb-nav-left'), width: 0, current: 0, max: 0, hooks: [], update: function () { var w = 0, h = 0, hooks = [0]; $.each(self._thumbnails, function (i, thumb) { if (thumb.ready) { w += thumb.outerWidth || $(thumb.container).outerWidth(true); hooks[i + 1] = w; h = Math.max(h, thumb.outerHeight || $(thumb.container).outerHeight(true)) } }); self.$('thumbnails').css({ width: w, height: h }); carousel.max = w; carousel.hooks = hooks; carousel.width = self.$('thumbnails-list').width(); carousel.setClasses(); self.$('thumbnails-container').toggleClass('galleria-carousel', w > carousel.width); carousel.width = self.$('thumbnails-list').width() }, bindControls: function () { var i; carousel.next.bind('click', function (e) { e.preventDefault(); if (self._options.carouselSteps === 'auto') { for (i = carousel.current; i < carousel.hooks.length; i++) { if (carousel.hooks[i] - carousel.hooks[carousel.current] > carousel.width) { carousel.set(i - 2); break } } } else { carousel.set(carousel.current + self._options.carouselSteps) } }); carousel.prev.bind('click', function (e) { e.preventDefault(); if (self._options.carouselSteps === 'auto') { for (i = carousel.current; i >= 0; i--) { if (carousel.hooks[carousel.current] - carousel.hooks[i] > carousel.width) { carousel.set(i + 2); break } else if (i === 0) { carousel.set(0); break } } } else { carousel.set(carousel.current - self._options.carouselSteps) } }) }, set: function (i) { i = Math.max(i, 0); while (carousel.hooks[i - 1] + carousel.width >= carousel.max && i >= 0) { i-- } carousel.current = i; carousel.animate() }, getLast: function (i) { return (i || carousel.current) - 1 }, follow: function (i) { if (i === 0 || i === carousel.hooks.length - 2) { carousel.set(i); return } var last = carousel.current; while (carousel.hooks[last] - carousel.hooks[carousel.current] < carousel.width && last <= carousel.hooks.length) { last++ } if (i - 1 < carousel.current) { carousel.set(i - 1) } else if (i + 2 > last) { carousel.set(i - last + carousel.current + 2) } }, setClasses: function () { carousel.prev.toggleClass('disabled', !carousel.current); carousel.next.toggleClass('disabled', carousel.hooks[carousel.current] + carousel.width >= carousel.max) }, animate: function (to) { carousel.setClasses(); var num = carousel.hooks[carousel.current] * -1; if (isNaN(num)) { return } Utils.animate(self.get('thumbnails'), { left: num }, { duration: self._options.carouselSpeed, easing: self._options.easing, queue: false }) } }; var tooltip = this._tooltip = { initialized: false, open: false, init: function () { tooltip.initialized = true; var css = '.galleria-tooltip{padding:3px 8px;max-width:50%;background:#ffe;color:#000;z-index:3;position:absolute;font-size:11px;line-height:1.3' + 'opacity:0;box-shadow:0 0 2px rgba(0,0,0,.4);-moz-box-shadow:0 0 2px rgba(0,0,0,.4);-webkit-box-shadow:0 0 2px rgba(0,0,0,.4);}'; Utils.insertStyleTag(css); self.$('tooltip').css('opacity', 0.8); Utils.hide(self.get('tooltip')) }, move: function (e) { var mouseX = self.getMousePosition(e).x, mouseY = self.getMousePosition(e).y, $elem = self.$('tooltip'), x = mouseX, y = mouseY, height = $elem.outerHeight(true) + 1, width = $elem.outerWidth(true), limitY = height + 15; var maxX = self.$('container').width() - width - 2, maxY = self.$('container').height() - height - 2; if (!isNaN(x) && !isNaN(y)) { x += 10; y -= 30; x = Math.max(0, Math.min(maxX, x)); y = Math.max(0, Math.min(maxY, y)); if (mouseY < limitY) { y = limitY } $elem.css({ left: x, top: y }) } }, bind: function (elem, value) { if (Galleria.TOUCH) { return } if (!tooltip.initialized) { tooltip.init() } var hover = function (elem, value) { tooltip.define(elem, value); $(elem).hover(function () { Utils.clearTimer('switch_tooltip'); self.$('container').unbind('mousemove', tooltip.move).bind('mousemove', tooltip.move).trigger('mousemove'); tooltip.show(elem); Galleria.utils.addTimer('tooltip', function () { self.$('tooltip').stop().show().animate({ opacity: 1 }); tooltip.open = true }, tooltip.open ? 0 : 500) }, function () { self.$('container').unbind('mousemove', tooltip.move); Utils.clearTimer('tooltip'); self.$('tooltip').stop().animate({ opacity: 0 }, 200, function () { self.$('tooltip').hide(); Utils.addTimer('switch_tooltip', function () { tooltip.open = false }, 1000) }) }) }; if (typeof value === 'string') { hover((elem in self._dom ? self.get(elem) : elem), value) } else { $.each(elem, function (elemID, val) { hover(self.get(elemID), val) }) } }, show: function (elem) { elem = $(elem in self._dom ? self.get(elem) : elem); var text = elem.data('tt'), mouseup = function (e) { window.setTimeout((function (ev) { return function () { tooltip.move(ev) } } (e)), 10); elem.unbind('mouseup', mouseup) }; text = typeof text === 'function' ? text() : text; if (!text) { return } self.$('tooltip').html(text.replace(/\s/, '&nbsp;')); elem.bind('mouseup', mouseup) }, define: function (elem, value) { if (typeof value !== 'function') { var s = value; value = function () { return s } } elem = $(elem in self._dom ? self.get(elem) : elem).data('tt', value); tooltip.show(elem) } }; var fullscreen = this._fullscreen = { scrolled: 0, crop: self._options.imageCrop, active: false, keymap: self._keyboard.map, enter: function (callback) { fullscreen.active = true; Utils.hide(self.getActiveImage()); self.$('container').addClass('fullscreen'); fullscreen.scrolled = $win.scrollTop(); Utils.forceStyles(self.get('container'), { position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', zIndex: 10000 }); var htmlbody = { height: '100%', overflow: 'hidden', margin: 0, padding: 0 }, data = self.getData(); Utils.forceStyles(DOM().html, htmlbody); Utils.forceStyles(DOM().body, htmlbody); fullscreen.keymap = $.extend({}, self._keyboard.map); self.attachKeyboard({ escape: self.exitFullscreen, right: self.next, left: self.prev }); if (self._options.fullscreenCrop !== undef) { self._options.imageCrop = self._options.fullscreenCrop } if (data && data.big && data.image !== data.big) { var big = new Galleria.Picture(), cached = big.isCached(data.big), index = self.getIndex(), thumb = self._thumbnails[index]; self.trigger({ type: Galleria.LOADSTART, cached: cached, rewind: false, index: index, imageTarget: self.getActiveImage(), thumbTarget: thumb }); big.load(data.big, function (big) { self._scaleImage(big, { complete: function (big) { self.trigger({ type: Galleria.LOADFINISH, cached: cached, index: index, rewind: false, imageTarget: big.image, thumbTarget: thumb }); var image = self._controls.getActive().image; if (image) { $(image).width(big.image.width).height(big.image.height).attr('style', $(big.image).attr('style')).attr('src', big.image.src) } } }) }) } self.rescale(function () { Utils.addTimer('fullscreen_enter', function () { Utils.show(self.getActiveImage()); if (typeof callback === 'function') { callback.call(self) } }, 100); self.trigger(Galleria.FULLSCREEN_ENTER) }); $win.resize(function () { fullscreen.scale() }) }, scale: function () { self.rescale() }, exit: function (callback) { fullscreen.active = false; Utils.hide(self.getActiveImage()); self.$('container').removeClass('fullscreen'); Utils.revertStyles(self.get('container'), DOM().html, DOM().body); window.scrollTo(0, fullscreen.scrolled); self.detachKeyboard(); self.attachKeyboard(fullscreen.keymap); if (self._options.fullscreenCrop !== undef) { self._options.imageCrop = fullscreen.crop } self.rescale(function () { Utils.addTimer('fullscreen_exit', function () { Utils.show(self.getActiveImage()); if (typeof callback === 'function') { callback.call(self) } }, 50); self.trigger(Galleria.FULLSCREEN_EXIT) }); $win.unbind('resize', fullscreen.scale) } }; var idle = this._idle = { trunk: [], bound: false, add: function (elem, to) { if (!elem) { return } if (!idle.bound) { idle.addEvent() } elem = $(elem); var from = {}, style; for (style in to) { if (to.hasOwnProperty(style)) { from[style] = elem.css(style) } } elem.data('idle', { from: from, to: to, complete: true, busy: false }); idle.addTimer(); idle.trunk.push(elem) }, remove: function (elem) { elem = jQuery(elem); $.each(idle.trunk, function (i, el) { if (el.length && !el.not(elem).length) { self._idle.show(elem); self._idle.trunk.splice(i, 1) } }); if (!idle.trunk.length) { idle.removeEvent(); Utils.clearTimer('idle') } }, addEvent: function () { idle.bound = true; self.$('container').bind('mousemove click', idle.showAll) }, removeEvent: function () { idle.bound = false; self.$('container').unbind('mousemove click', idle.showAll) }, addTimer: function () { Utils.addTimer('idle', function () { self._idle.hide() }, self._options.idleTime) }, hide: function () { if (!self._options.idleMode) { return } self.trigger(Galleria.IDLE_ENTER); $.each(idle.trunk, function (i, elem) { var data = elem.data('idle'); if (!data) { return } elem.data('idle').complete = false; Utils.animate(elem, data.to, { duration: self._options.idleSpeed }) }) }, showAll: function () { Utils.clearTimer('idle'); $.each(self._idle.trunk, function (i, elem) { self._idle.show(elem) }) }, show: function (elem) { var data = elem.data('idle'); if (!data.busy && !data.complete) { data.busy = true; self.trigger(Galleria.IDLE_EXIT); Utils.clearTimer('idle'); Utils.animate(elem, data.from, { duration: self._options.idleSpeed / 2, complete: function () { $(this).data('idle').busy = false; $(this).data('idle').complete = true } }) } idle.addTimer() } }; var lightbox = this._lightbox = { width: 0, height: 0, initialized: false, active: null, image: null, elems: {}, keymap: false, init: function () { self.trigger(Galleria.LIGHTBOX_OPEN); if (lightbox.initialized) { return } lightbox.initialized = true; var elems = 'overlay box content shadow title info close prevholder prev nextholder next counter image', el = {}, op = self._options, css = '', abs = 'position:absolute;', prefix = 'lightbox-', cssMap = { overlay: 'position:fixed;display:none;opacity:' + op.overlayOpacity + ';filter:alpha(opacity=' + (op.overlayOpacity * 100) + ');top:0;left:0;width:100%;height:100%;background:' + op.overlayBackground + ';z-index:99990', box: 'position:fixed;display:none;width:400px;height:400px;top:50%;left:50%;margin-top:-200px;margin-left:-200px;z-index:99991', shadow: abs + 'background:#000;width:100%;height:100%;', content: abs + 'background-color:#fff;top:10px;left:10px;right:10px;bottom:10px;overflow:hidden', info: abs + 'bottom:10px;left:10px;right:10px;color:#444;font:11px/13px arial,sans-serif;height:13px', close: abs + 'top:10px;right:10px;height:20px;width:20px;background:#fff;text-align:center;cursor:pointer;color:#444;font:16px/22px arial,sans-serif;z-index:99999', image: abs + 'top:10px;left:10px;right:10px;bottom:30px;overflow:hidden;display:block;', prevholder: abs + 'width:50%;top:0;bottom:40px;cursor:pointer;', nextholder: abs + 'width:50%;top:0;bottom:40px;right:-1px;cursor:pointer;', prev: abs + 'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;left:20px;display:none;text-align:center;color:#000;font:bold 16px/36px arial,sans-serif', next: abs + 'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;right:20px;left:auto;display:none;font:bold 16px/36px arial,sans-serif;text-align:center;color:#000', title: 'float:left', counter: 'float:right;margin-left:8px;' }, hover = function (elem) { return elem.hover(function () { $(this).css('color', '#bbb') }, function () { $(this).css('color', '#444') }) }, appends = {}; if (IE === 8) { cssMap.nextholder += 'background:#000;filter:alpha(opacity=0);'; cssMap.prevholder += 'background:#000;filter:alpha(opacity=0);' } $.each(cssMap, function (key, value) { css += '.galleria-' + prefix + key + '{' + value + '}' }); Utils.insertStyleTag(css); $.each(elems.split(' '), function (i, elemId) { self.addElement('lightbox-' + elemId); el[elemId] = lightbox.elems[elemId] = self.get('lightbox-' + elemId) }); lightbox.image = new Galleria.Picture(); $.each({ box: 'shadow content close prevholder nextholder', info: 'title counter', content: 'info image', prevholder: 'prev', nextholder: 'next' }, function (key, val) { var arr = []; $.each(val.split(' '), function (i, prop) { arr.push(prefix + prop) }); appends[prefix + key] = arr }); self.append(appends); $(el.image).append(lightbox.image.container); $(DOM().body).append(el.overlay, el.box); Utils.optimizeTouch(el.box); hover($(el.close).bind('click', lightbox.hide).html('&#215;')); $.each(['Prev', 'Next'], function (i, dir) { var $d = $(el[dir.toLowerCase()]).html(/v/.test(dir) ? '&#8249;&nbsp;' : '&nbsp;&#8250;'), $e = $(el[dir.toLowerCase() + 'holder']); $e.bind('click', function () { lightbox['show' + dir]() }); if (IE < 8 || Galleria.TOUCH) { $d.show(); return } $e.hover(function () { $d.show() }, function (e) { $d.stop().fadeOut(200) }) }); $(el.overlay).bind('click', lightbox.hide); if (Galleria.IPAD) { self._options.lightboxTransitionSpeed = 0 } }, rescale: function (event) { var width = Math.min($win.width() - 40, lightbox.width), height = Math.min($win.height() - 60, lightbox.height), ratio = Math.min(width / lightbox.width, height / lightbox.height), destWidth = Math.round(lightbox.width * ratio) + 40, destHeight = Math.round(lightbox.height * ratio) + 60, to = { width: destWidth, height: destHeight, 'margin-top': Math.ceil(destHeight / 2) * -1, 'margin-left': Math.ceil(destWidth / 2) * -1 }; if (event) { $(lightbox.elems.box).css(to) } else { $(lightbox.elems.box).animate(to, { duration: self._options.lightboxTransitionSpeed, easing: self._options.easing, complete: function () { var image = lightbox.image, speed = self._options.lightboxFadeSpeed; self.trigger({ type: Galleria.LIGHTBOX_IMAGE, imageTarget: image.image }); $(image.container).show(); Utils.show(image.image, speed); Utils.show(lightbox.elems.info, speed) } }) } }, hide: function () { lightbox.image.image = null; $win.unbind('resize', lightbox.rescale); $(lightbox.elems.box).hide(); Utils.hide(lightbox.elems.info); self.detachKeyboard(); self.attachKeyboard(lightbox.keymap); lightbox.keymap = false; Utils.hide(lightbox.elems.overlay, 200, function () { $(this).hide().css('opacity', self._options.overlayOpacity); self.trigger(Galleria.LIGHTBOX_CLOSE) }) }, showNext: function () { lightbox.show(self.getNext(lightbox.active)) }, showPrev: function () { lightbox.show(self.getPrev(lightbox.active)) }, show: function (index) { lightbox.active = index = typeof index === 'number' ? index : self.getIndex(); if (!lightbox.initialized) { lightbox.init() } if (!lightbox.keymap) { lightbox.keymap = $.extend({}, self._keyboard.map); self.attachKeyboard({ escape: lightbox.hide, right: lightbox.showNext, left: lightbox.showPrev }) } $win.unbind('resize', lightbox.rescale); var data = self.getData(index), total = self.getDataLength(); if (total == 1) { $(".galleria-lightbox-prevholder").hide(); $(".galleria-lightbox-nextholder").hide() } Utils.hide(lightbox.elems.info); lightbox.image.load(data.big || data.image, function (image) { lightbox.width = image.original.width; lightbox.height = image.original.height; $(image.image).css({ width: '100.5%', height: '100.5%', top: 0, zIndex: 99998 }); Utils.hide(image.image); lightbox.elems.title.innerHTML = data.title || ''; lightbox.elems.counter.innerHTML = (index + 1) + ' / ' + total; $win.resize(lightbox.rescale); lightbox.rescale() }); $(lightbox.elems.overlay).show(); $(lightbox.elems.box).show() } }; return this }; Galleria.prototype = { constructor: Galleria, init: function (target, options) { var self = this; options = _legacyOptions(options); this._original = { target: target, options: options, data: null }; this._target = this._dom.target = target.nodeName ? target : $(target).get(0); _instances.push(this); if (!this._target) { Galleria.raise('Target not found.', true); return } this._options = { autoplay: false, carousel: true, carouselFollow: true, carouselSpeed: 400, carouselSteps: 'auto', clicknext: false, dataConfig: function (elem) { return {} }, dataSelector: 'img', dataSource: this._target, debug: undef, dummy: undef, easing: 'galleria', extend: function (options) { }, fullscreenCrop: undef, fullscreenDoubleTap: true, fullscreenTransition: undef, height: 'auto', idleMode: true, idleTime: 3000, idleSpeed: 200, imageCrop: false, imageMargin: 0, imagePan: false, imagePanSmoothness: 12, imagePosition: '50%', imageTimeout: undef, initialTransition: undef, keepSource: false, layerFollow: true, lightbox: false, lightboxFadeSpeed: 200, lightboxTransitionSpeed: 200, linkSourceImages: true, maxScaleRatio: undef, minScaleRatio: undef, overlayOpacity: 0.85, overlayBackground: '#0b0b0b', pauseOnInteraction: true, popupLinks: false, preload: 2, queue: true, show: 0, showInfo: true, showCounter: true, showImagenav: true, swipe: true, thumbCrop: true, thumbEventType: 'click', thumbFit: true, thumbMargin: 0, thumbQuality: 'auto', thumbnails: true, touchTransition: undef, transition: 'fade', transitionInitial: undef, transitionSpeed: 400, useCanvas: false, width: 'auto' }; this._options.initialTransition = this._options.initialTransition || this._options.transitionInitial; if (options && options.debug === false) { DEBUG = false } if (options && typeof options.imageTimeout === 'number') { TIMEOUT = options.imageTimeout } if (options && typeof options.dummy === 'string') { DUMMY = options.dummy } $(this._target).children().hide(); if (typeof Galleria.theme === 'object') { this._init() } else { _pool.push(this) } return this }, _init: function () { var self = this; if (this._initialized) { Galleria.raise('Init failed: Gallery instance already initialized.'); return this } this._initialized = true; if (!Galleria.theme) { Galleria.raise('Init failed: No theme found.'); return this } $.extend(true, this._options, Galleria.theme.defaults, this._original.options); (function (can) { if (!('getContext' in can)) { can = null; return } _canvas = _canvas || { elem: can, context: can.getContext('2d'), cache: {}, length: 0} } (doc.createElement('canvas'))); this.bind(Galleria.DATA, function () { this._original.data = this._data; this.get('total').innerHTML = this.getDataLength(); var $container = this.$('container'); var num = { width: 0, height: 0 }; var testHeight = function () { return self.$('stage').height() }; Utils.wait({ until: function () { $.each(['width', 'height'], function (i, m) { if (self._options[m] && typeof self._options[m] === 'number') { num[m] = self._options[m] } else { num[m] = Math.max(Utils.parseValue($container.css(m)), Utils.parseValue(self.$('target').css(m)), $container[m](), self.$('target')[m]()) } $container[m](num[m]) }); return testHeight() && num.width && num.height > 10 }, success: function () { if (Galleria.WEBKIT) { window.setTimeout(function () { self._run() }, 1) } else { self._run() } }, error: function () { if (testHeight()) { Galleria.raise('Could not extract sufficient width/height of the gallery container. Traced measures: width:' + num.width + 'px, height: ' + num.height + 'px.', true) } else { Galleria.raise('Could not extract a stage height from the CSS. Traced height: ' + testHeight() + 'px.', true) } }, timeout: 2000 }) }); this.append({ 'info-text': ['info-title', 'info-description'], 'info': ['info-text'], 'image-nav': ['image-nav-right', 'image-nav-left'], 'stage': ['images', 'loader', 'counter', 'image-nav'], 'thumbnails-list': ['thumbnails'], 'thumbnails-container': ['thumb-nav-left', 'thumbnails-list', 'thumb-nav-right'], 'container': ['stage', 'thumbnails-container', 'info', 'tooltip'] }); Utils.hide(this.$('counter').append(this.get('current'), ' / ', this.get('total'))); this.setCounter('&#8211;'); Utils.hide(self.get('tooltip')); this.$('container').addClass(Galleria.TOUCH ? 'touch' : 'notouch'); $.each(new Array(2), function (i) { var image = new Galleria.Picture(); $(image.container).css({ position: 'absolute', top: 0, left: 0 }).prepend(self._layers[i] = $(Utils.create('galleria-layer')).css({ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 2 })[0]); self.$('images').append(image.container); self._controls[i] = image }); this.$('images').css({ position: 'relative', top: 0, left: 0, width: '100%', height: '100%' }); this.$('thumbnails, thumbnails-list').css({ overflow: 'hidden', position: 'relative' }); this.$('image-nav-right, image-nav-left').bind('click', function (e) { if (self._options.clicknext) { e.stopPropagation() } if (self._options.pauseOnInteraction) { self.pause() } var fn = /right/.test(this.className) ? 'next' : 'prev'; self[fn]() }); $.each(['info', 'counter', 'image-nav'], function (i, el) { if (self._options['show' + el.substr(0, 1).toUpperCase() + el.substr(1).replace(/-/, '')] === false) { Utils.moveOut(self.get(el.toLowerCase())) } }); this.load(); if (!this._options.keep_source && !IE) { this._target.innerHTML = '' } if (this.get('errors')) { this.appendChild('target', 'errors') } this.appendChild('target', 'container'); if (this._options.carousel) { var count = 0, show = this._options.show; this.bind(Galleria.THUMBNAIL, function () { this.updateCarousel(); if (++count == this.getDataLength() && typeof show == 'number' && show > 0) { this._carousel.follow(show) } }) } if (this._options.swipe) { (function (images) { var swipeStart = [0, 0], swipeStop = [0, 0], limitX = 30, limitY = 100, multi = false, tid = 0, data, ev = { start: 'touchstart', move: 'touchmove', stop: 'touchend' }, getData = function (e) { return e.originalEvent.touches ? e.originalEvent.touches[0] : e }, moveHandler = function (e) { if (e.originalEvent.touches && e.originalEvent.touches.length > 1) { return } data = getData(e); swipeStop = [data.pageX, data.pageY]; if (!swipeStart[0]) { swipeStart = swipeStop } if (Math.abs(swipeStart[0] - swipeStop[0]) > 10) { e.preventDefault() } }, upHandler = function (e) { images.unbind(ev.move, moveHandler); if ((e.originalEvent.touches && e.originalEvent.touches.length) || multi) { multi = !multi; return } if (Utils.timestamp() - tid < 1000 && Math.abs(swipeStart[0] - swipeStop[0]) > limitX && Math.abs(swipeStart[1] - swipeStop[1]) < limitY) { e.preventDefault(); self[swipeStart[0] > swipeStop[0] ? 'next' : 'prev']() } swipeStart = swipeStop = [0, 0] }; images.bind(ev.start, function (e) { if (e.originalEvent.touches && e.originalEvent.touches.length > 1) { return } data = getData(e); tid = Utils.timestamp(); swipeStart = swipeStop = [data.pageX, data.pageY]; images.bind(ev.move, moveHandler).one(ev.stop, upHandler) }) } (self.$('images'))); if (this._options.fullscreenDoubleTap) { this.$('stage').bind('touchstart', (function () { var last, cx, cy, lx, ly, now, getData = function (e) { return e.originalEvent.touches ? e.originalEvent.touches[0] : e }; return function (e) { now = Galleria.utils.timestamp(); cx = getData(e).pageX; cy = getData(e).pageY; if ((now - last < 500) && (cx - lx < 20) && (cy - ly < 20)) { self.toggleFullscreen(); e.preventDefault(); self.$('stage').unbind('touchend', arguments.callee); return } last = now; lx = cx; ly = cy } } ())) } } Utils.optimizeTouch(this.get('container')); return this }, _createThumbnails: function () { this.get('total').innerHTML = this.getDataLength(); var i, src, thumb, data, $container, self = this, o = this._options, active = (function () { var a = self.$('thumbnails').find('.active'); if (!a.length) { return false } return a.find('img').attr('src') } ()), optval = typeof o.thumbnails === 'string' ? o.thumbnails.toLowerCase() : null, getStyle = function (prop) { return doc.defaultView && doc.defaultView.getComputedStyle ? doc.defaultView.getComputedStyle(thumb.container, null)[prop] : $container.css(prop) }, fake = function (image, index, container) { return function () { $(container).append(image); self.trigger({ type: Galleria.THUMBNAIL, thumbTarget: image, index: index }) } }, onThumbEvent = function (e) { if (o.pauseOnInteraction) { self.pause() } var index = $(e.currentTarget).data('index'); if (self.getIndex() !== index) { self.show(index) } var needlightBox = $('#galleria-alt'); if (needlightBox[0] != null) { self.openLightbox() } e.preventDefault() }, onThumbLoad = function (thumb) { thumb.scale({ width: thumb.data.width, height: thumb.data.height, crop: o.thumbCrop, margin: o.thumbMargin, canvas: o.useCanvas, complete: function (thumb) { var top = ['left', 'top'], arr = ['Width', 'Height'], m, css; $.each(arr, function (i, measure) { m = measure.toLowerCase(); if ((o.thumbCrop !== true || o.thumbCrop === m) && o.thumbFit) { css = {}; css[m] = thumb[m]; $(thumb.container).css(css); css = {}; css[top[i]] = 0; $(thumb.image).css(css) } thumb['outer' + measure] = $(thumb.container)['outer' + measure](true) }); Utils.toggleQuality(thumb.image, o.thumbQuality === true || (o.thumbQuality === 'auto' && thumb.original.width < thumb.width * 3)); self.trigger({ type: Galleria.THUMBNAIL, thumbTarget: thumb.image, index: thumb.data.order }) } }) }; this._thumbnails = []; this.$('thumbnails').empty(); for (i = 0; this._data[i]; i++) { data = this._data[i]; if (o.thumbnails === true) { thumb = new Galleria.Picture(i); src = data.thumb || data.image; this.$('thumbnails').append(thumb.container); $container = $(thumb.container); thumb.data = { width: Utils.parseValue(getStyle('width')), height: Utils.parseValue(getStyle('height')), order: i }; if (o.thumbFit && o.thumbCrop !== true) { $container.css({ width: 0, height: 0 }) } else { $container.css({ width: thumb.data.width, height: thumb.data.height }) } thumb.load(src, onThumbLoad); if (o.preload === 'all') { thumb.preload(data.image) } } else if (optval === 'empty' || optval === 'numbers') { thumb = { container: Utils.create('galleria-image'), image: Utils.create('img', 'span'), ready: true }; if (optval === 'numbers') { $(thumb.image).text(i + 1) } this.$('thumbnails').append(thumb.container); window.setTimeout((fake)(thumb.image, i, thumb.container), 50 + (i * 20)) } else { thumb = { container: null, image: null} } $(thumb.container).add(o.keepSource && o.linkSourceImages ? data.original : null).data('index', i).bind(o.thumbEventType, onThumbEvent); if (active === src) { $(thumb.container).addClass('active') } this._thumbnails.push(thumb) } }, _run: function () { var self = this; self._createThumbnails(); Utils.wait({ until: function () { if (Galleria.OPERA) { self.$('stage').css('display', 'inline-block') } self._stageWidth = self.$('stage').width(); self._stageHeight = self.$('stage').height(); return (self._stageWidth && self._stageHeight > 50) }, success: function () { _galleries.push(self); Utils.show(self.get('counter')); if (self._options.carousel) { self._carousel.bindControls() } if (self._options.autoplay) { self.pause(); if (typeof self._options.autoplay === 'number') { self._playtime = self._options.autoplay } self.trigger(Galleria.PLAY); self._playing = true } if (self._firstrun) { if (typeof self._options.show === 'number') { self.show(self._options.show) } return } self._firstrun = true; if (self._options.clicknext && !Galleria.TOUCH) { $.each(self._data, function (i, data) { delete data.link }); self.$('stage').css({ cursor: 'pointer' }).bind('click', function (e) { if (self._options.pauseOnInteraction) { self.pause() } self.next() }) } if (Galleria.History) { Galleria.History.change(function (value) { if (isNaN(value)) { window.history.go(-1) } else { self.show(value, undef, true) } }) } $.each(Galleria.ready.callbacks, function () { this.call(self, self._options) }); self.trigger(Galleria.READY); Galleria.theme.init.call(self, self._options); self._options.extend.call(self, self._options); if (/^[0-9]{1,4}$/.test(HASH) && Galleria.History) { self.show(HASH, undef, true) } else if (self._data[self._options.show]) { self.show(self._options.show) } }, error: function () { Galleria.raise('Stage width or height is too small to show the gallery. Traced measures: width:' + self._stageWidth + 'px, height: ' + self._stageHeight + 'px.', true) } }) }, load: function (source, selector, config) { var self = this; this._data = []; this._thumbnails = []; this.$('thumbnails').empty(); if (typeof selector === 'function') { config = selector; selector = null } source = source || this._options.dataSource; selector = selector || this._options.dataSelector; config = config || this._options.dataConfig; if (/^function Object/.test(source.constructor)) { source = [source] } if (source.constructor === Array) { if (this.validate(source)) { this._data = source; this._parseData().trigger(Galleria.DATA) } else { Galleria.raise('Load failed: JSON Array not valid.') } return this } $(source).find(selector).each(function (i, img) { img = $(img); var data = {}, parent = img.parent(), href = parent.attr('href'), rel = parent.attr('rel'); if (href) { data.image = data.big = href } if (rel) { data.big = rel } self._data.push($.extend({ title: img.attr('title') || '', thumb: img.attr('src'), image: img.attr('src'), big: img.attr('src'), description: img.attr('alt') || '', link: img.attr('longdesc'), original: img.get(0) }, data, config(img))) }); if (this.getDataLength()) { this.trigger(Galleria.DATA) } else { Galleria.raise('Load failed: no data found.') } return this }, _parseData: function () { var self = this; $.each(this._data, function (i, data) { if ('thumb' in data === false) { self._data[i].thumb = data.image } if (!'big' in data) { self._data[i].big = data.image } }); return this }, splice: function () { Array.prototype.splice.apply(this._data, Utils.array(arguments)); return this._parseData()._createThumbnails() }, push: function () { Array.prototype.push.apply(this._data, Utils.array(arguments)); return this._parseData()._createThumbnails() }, _getActive: function () { return this._controls.getActive() }, validate: function (data) { return true }, bind: function (type, fn) { type = _patchEvent(type); this.$('container').bind(type, this.proxy(fn)); return this }, unbind: function (type) { type = _patchEvent(type); this.$('container').unbind(type); return this }, trigger: function (type) { type = typeof type === 'object' ? $.extend(type, { scope: this }) : { type: _patchEvent(type), scope: this }; this.$('container').trigger(type); return this }, addIdleState: function (elem, styles) { this._idle.add.apply(this._idle, Utils.array(arguments)); return this }, removeIdleState: function (elem) { this._idle.remove.apply(this._idle, Utils.array(arguments)); return this }, enterIdleMode: function () { this._idle.hide(); return this }, exitIdleMode: function () { this._idle.showAll(); return this }, enterFullscreen: function (callback) { this._fullscreen.enter.apply(this, Utils.array(arguments)); return this }, exitFullscreen: function (callback) { this._fullscreen.exit.apply(this, Utils.array(arguments)); return this }, toggleFullscreen: function (callback) { this._fullscreen[this.isFullscreen() ? 'exit' : 'enter'].apply(this, Utils.array(arguments)); return this }, bindTooltip: function (elem, value) { this._tooltip.bind.apply(this._tooltip, Utils.array(arguments)); return this }, defineTooltip: function (elem, value) { this._tooltip.define.apply(this._tooltip, Utils.array(arguments)); return this }, refreshTooltip: function (elem) { this._tooltip.show.apply(this._tooltip, Utils.array(arguments)); return this }, openLightbox: function () { this._lightbox.show.apply(this._lightbox, Utils.array(arguments)); return this }, closeLightbox: function () { this._lightbox.hide.apply(this._lightbox, Utils.array(arguments)); return this }, getActiveImage: function () { return this._getActive().image || undef }, getActiveThumb: function () { return this._thumbnails[this._active].image || undef }, getMousePosition: function (e) { return { x: e.pageX - this.$('container').offset().left, y: e.pageY - this.$('container').offset().top} }, addPan: function (img) { if (this._options.imageCrop === false) { return } img = $(img || this.getActiveImage()); var self = this, x = img.width() / 2, y = img.height() / 2, destX = parseInt(img.css('left'), 10), destY = parseInt(img.css('top'), 10), curX = destX || 0, curY = destY || 0, distX = 0, distY = 0, active = false, ts = Utils.timestamp(), cache = 0, move = 0, position = function (dist, cur, pos) { if (dist > 0) { move = Math.round(Math.max(dist * -1, Math.min(0, cur))); if (cache !== move) { cache = move; if (IE === 8) { img.parent()['scroll' + pos](move * -1) } else { var css = {}; css[pos.toLowerCase()] = move; img.css(css) } } } }, calculate = function (e) { if (Utils.timestamp() - ts < 50) { return } active = true; x = self.getMousePosition(e).x; y = self.getMousePosition(e).y }, loop = function (e) { if (!active) { return } distX = img.width() - self._stageWidth; distY = img.height() - self._stageHeight; destX = x / self._stageWidth * distX * -1; destY = y / self._stageHeight * distY * -1; curX += (destX - curX) / self._options.imagePanSmoothness; curY += (destY - curY) / self._options.imagePanSmoothness; position(distY, curY, 'Top'); position(distX, curX, 'Left') }; if (IE === 8) { img.parent().scrollTop(curY * -1).scrollLeft(curX * -1); img.css({ top: 0, left: 0 }) } this.$('stage').unbind('mousemove', calculate).bind('mousemove', calculate); Utils.addTimer('pan', loop, 50, true); return this }, proxy: function (fn, scope) { if (typeof fn !== 'function') { return function () { } } scope = scope || this; return function () { return fn.apply(scope, Utils.array(arguments)) } }, removePan: function () { this.$('stage').unbind('mousemove'); Utils.clearTimer('pan'); return this }, addElement: function (id) { var dom = this._dom; $.each(Utils.array(arguments), function (i, blueprint) { dom[blueprint] = Utils.create('galleria-' + blueprint) }); return this }, attachKeyboard: function (map) { this._keyboard.attach.apply(this._keyboard, Utils.array(arguments)); return this }, detachKeyboard: function () { this._keyboard.detach.apply(this._keyboard, Utils.array(arguments)); return this }, appendChild: function (parentID, childID) { this.$(parentID).append(this.get(childID) || childID); return this }, prependChild: function (parentID, childID) { this.$(parentID).prepend(this.get(childID) || childID); return this }, remove: function (elemID) { this.$(Utils.array(arguments).join(',')).remove(); return this }, append: function (data) { var i, j; for (i in data) { if (data.hasOwnProperty(i)) { if (data[i].constructor === Array) { for (j = 0; data[i][j]; j++) { this.appendChild(i, data[i][j]) } } else { this.appendChild(i, data[i]) } } } return this }, _scaleImage: function (image, options) { image = image || this._controls.getActive(); var self = this, complete, scaleLayer = function (img) { $(img.container).children(':first').css({ top: Math.max(0, Utils.parseValue(img.image.style.top)), left: Math.max(0, Utils.parseValue(img.image.style.left)), width: Utils.parseValue(img.image.width), height: Utils.parseValue(img.image.height) }) }; options = $.extend({ width: this._stageWidth, height: this._stageHeight, crop: this._options.imageCrop, max: this._options.maxScaleRatio, min: this._options.minScaleRatio, margin: this._options.imageMargin, position: this._options.imagePosition }, options); if (this._options.layerFollow && this._options.imageCrop !== true) { if (typeof options.complete == 'function') { complete = options.complete; options.complete = function () { complete.call(image, image); scaleLayer(image) } } else { options.complete = scaleLayer } } else { $(image.container).children(':first').css({ top: 0, left: 0 }) } image.scale(options); return this }, updateCarousel: function () { this._carousel.update(); return this }, rescale: function (width, height, complete) { var self = this; if (typeof width === 'function') { complete = width; width = undef } var scale = function () { self._stageWidth = width || self.$('stage').width(); self._stageHeight = height || self.$('stage').height(); self._scaleImage(); if (self._options.carousel) { self.updateCarousel() } self.trigger(Galleria.RESCALE); if (typeof complete === 'function') { complete.call(self) } }; if (Galleria.WEBKIT && !width && !height) { Utils.addTimer('scale', scale, 10) } else { scale.call(self) } return this }, refreshImage: function () { this._scaleImage(); if (this._options.imagePan) { this.addPan() } return this }, show: function (index, rewind, _history) { if (index === false || (!this._options.queue && this._queue.stalled)) { return } index = Math.max(0, Math.min(parseInt(index, 10), this.getDataLength() - 1)); rewind = typeof rewind !== 'undefined' ? !!rewind : index < this.getIndex(); _history = _history || false; if (!_history && Galleria.History) { Galleria.History.set(index.toString()); return } this._active = index; Array.prototype.push.call(this._queue, { index: index, rewind: rewind }); if (!this._queue.stalled) { this._show() } return this }, _show: function () { var self = this, queue = this._queue[0], data = this.getData(queue.index); if (!data) { return } var src = this.isFullscreen() && 'big' in data ? data.big : data.image, active = this._controls.getActive(), next = this._controls.getNext(), cached = next.isCached(src), thumb = this._thumbnails[queue.index]; var complete = (function (data, next, active, queue, thumb) { return function () { var win; self._queue.stalled = false; Utils.toggleQuality(next.image, self._options.imageQuality); self._layers[self._controls.active].innerHTML = ''; $(active.container).css({ zIndex: 0, opacity: 0 }).show(); $(next.container).css({ zIndex: 1 }).show(); self._controls.swap(); if (self._options.imagePan) { self.addPan(next.image) } if (data.link || self._options.lightbox) { $(next.image).css({ cursor: 'pointer' }).bind('mouseup', function () { if (data.link) { if (self._options.popupLinks) { win = window.open(data.link, '_blank') } else { window.location.href = data.link } return } self.openLightbox() }) } Array.prototype.shift.call(self._queue); if (self._queue.length) { self._show() } self._playCheck(); self.trigger({ type: Galleria.IMAGE, index: queue.index, imageTarget: next.image, thumbTarget: thumb.image }) } } (data, next, active, queue, thumb)); if (this._options.carousel && this._options.carouselFollow) { this._carousel.follow(queue.index) } if (this._options.preload) { var p, i, n = this.getNext(), ndata; try { for (i = this._options.preload; i > 0; i--) { p = new Galleria.Picture(); ndata = self.getData(n); p.preload(this.isFullscreen() && 'big' in ndata ? ndata.big : ndata.image); n = self.getNext(n) } } catch (e) { } } Utils.show(next.container); $(self._thumbnails[queue.index].container).addClass('active').siblings('.active').removeClass('active'); self.trigger({ type: Galleria.LOADSTART, cached: cached, index: queue.index, rewind: queue.rewind, imageTarget: next.image, thumbTarget: thumb.image }); next.load(src, function (next) { $(self._layers[1 - self._controls.active]).html(data.layer || '').hide(); self._scaleImage(next, { complete: function (next) { if ('image' in active) { Utils.toggleQuality(active.image, false) } Utils.toggleQuality(next.image, false); self._queue.stalled = true; self.removePan(); self.setInfo(queue.index); self.setCounter(queue.index); if (data.layer) { $(self._layers[1 - self._controls.active]).show() } self.trigger({ type: Galleria.LOADFINISH, cached: cached, index: queue.index, rewind: queue.rewind, imageTarget: next.image, thumbTarget: self._thumbnails[queue.index].image }); var transition = self._options.transition; $.each({ initial: active.image === null, touch: Galleria.TOUCH, fullscreen: self.isFullscreen() }, function (type, arg) { if (arg && self._options[type + 'Transition'] !== undef) { transition = self._options[type + 'Transition']; return false } }); if (transition in _transitions === false) { complete() } else { var params = { prev: active.container, next: next.container, rewind: queue.rewind, speed: self._options.transitionSpeed || 400 }; _transitions[transition].call(self, params, complete) } } }) }) }, getNext: function (base) { base = typeof base === 'number' ? base : this.getIndex(); return base === this.getDataLength() - 1 ? 0 : base + 1 }, getPrev: function (base) { base = typeof base === 'number' ? base : this.getIndex(); return base === 0 ? this.getDataLength() - 1 : base - 1 }, next: function () { if (this.getDataLength() > 1) { this.show(this.getNext(), false) } return this }, prev: function () { if (this.getDataLength() > 1) { this.show(this.getPrev(), true) } return this }, get: function (elemId) { return elemId in this._dom ? this._dom[elemId] : null }, getData: function (index) { return index in this._data ? this._data[index] : this._data[this._active] }, getDataLength: function () { return this._data.length }, getIndex: function () { return typeof this._active === 'number' ? this._active : false }, getStageHeight: function () { return this._stageHeight }, getStageWidth: function () { return this._stageWidth }, getOptions: function (key) { return typeof key === 'undefined' ? this._options : this._options[key] }, setOptions: function (key, value) { if (typeof key === 'object') { $.extend(this._options, key) } else { this._options[key] = value } return this }, play: function (delay) { this._playing = true; this._playtime = delay || this._playtime; this._playCheck(); this.trigger(Galleria.PLAY); return this }, pause: function () { this._playing = false; this.trigger(Galleria.PAUSE); return this }, playToggle: function (delay) { return (this._playing) ? this.pause() : this.play(delay) }, isPlaying: function () { return this._playing }, isFullscreen: function () { return this._fullscreen.active }, _playCheck: function () { var self = this, played = 0, interval = 20, now = Utils.timestamp(), timer_id = 'play' + this._id; if (this._playing) { Utils.clearTimer(timer_id); var fn = function () { played = Utils.timestamp() - now; if (played >= self._playtime && self._playing) { Utils.clearTimer(timer_id); self.next(); return } if (self._playing) { self.trigger({ type: Galleria.PROGRESS, percent: Math.ceil(played / self._playtime * 100), seconds: Math.floor(played / 1000), milliseconds: played }); Utils.addTimer(timer_id, fn, interval) } }; Utils.addTimer(timer_id, fn, interval) } }, setPlaytime: function (delay) { this._playtime = delay; return this }, setIndex: function (val) { this._active = val; return this }, setCounter: function (index) { if (typeof index === 'number') { index++ } else if (typeof index === 'undefined') { index = this.getIndex() + 1 } this.get('current').innerHTML = index; if (IE) { var count = this.$('counter'), opacity = count.css('opacity'); if (parseInt(opacity, 10) === 1) { Utils.removeAlpha(count[0]) } else { this.$('counter').css('opacity', opacity) } } return this }, setInfo: function (index) { var self = this, data = this.getData(index); $.each(['title', 'description'], function (i, type) { var elem = self.$('info-' + type); if (!!data[type]) { elem[data[type].length ? 'show' : 'hide']().html(data[type]) } else { elem.empty().hide() } }); return this }, hasInfo: function (index) { var check = 'title description'.split(' '), i; for (i = 0; check[i]; i++) { if (!!this.getData(index)[check[i]]) { return true } } return false }, jQuery: function (str) { var self = this, ret = []; $.each(str.split(','), function (i, elemId) { elemId = $.trim(elemId); if (self.get(elemId)) { ret.push(elemId) } }); var jQ = $(self.get(ret.shift())); $.each(ret, function (i, elemId) { jQ = jQ.add(self.get(elemId)) }); return jQ }, $: function (str) { return this.jQuery.apply(this, Utils.array(arguments)) } }; $.each(_events, function (i, ev) { var type = /_/.test(ev) ? ev.replace(/_/g, '') : ev; Galleria[ev.toUpperCase()] = 'galleria.' + type }); $.extend(Galleria, { IE9: IE === 9, IE8: IE === 8, IE7: IE === 7, IE6: IE === 6, IE: IE, WEBKIT: /webkit/.test(NAV), SAFARI: /safari/.test(NAV), CHROME: /chrome/.test(NAV), QUIRK: (IE && doc.compatMode && doc.compatMode === "BackCompat"), MAC: /mac/.test(navigator.platform.toLowerCase()), OPERA: !!window.opera, IPHONE: /iphone/.test(NAV), IPAD: /ipad/.test(NAV), ANDROID: /android/.test(NAV), TOUCH: ('ontouchstart' in doc) }); Galleria.addTheme = function (theme) { if (!theme.name) { Galleria.raise('No theme name specified') } if (typeof theme.defaults !== 'object') { theme.defaults = {} } else { theme.defaults = _legacyOptions(theme.defaults) } var css = false, reg; if (typeof theme.css === 'string') { $('link').each(function (i, link) { reg = new RegExp(theme.css); if (reg.test(link.href)) { css = true; _themeLoad(theme); return false } }); if (!css) { $('script').each(function (i, script) { reg = new RegExp('galleria\\.' + theme.name.toLowerCase() + '\\.'); if (reg.test(script.src)) { css = script.src.replace(/[^\/]*$/, '') + theme.css; Utils.addTimer("css", function () { Utils.loadCSS(css, 'galleria-theme', function () { _themeLoad(theme) }) }, 1) } }) } if (!css) { Galleria.raise('No theme CSS loaded') } } else { _themeLoad(theme) } return theme }; Galleria.loadTheme = function (src, options) { var loaded = false, length = _galleries.length, err = window.setTimeout(function () { Galleria.raise("Theme at " + src + " could not load, check theme path.", true) }, 5000); Galleria.theme = undef; Utils.loadScript(src, function () { window.clearTimeout(err); if (length) { var refreshed = []; $.each(Galleria.get(), function (i, instance) { var op = $.extend(instance._original.options, { data_source: instance._data }, options); instance.$('container').remove(); var g = new Galleria(); g._id = instance._id; g.init(instance._original.target, op); refreshed.push(g) }); _galleries = refreshed } }) }; Galleria.get = function (index) { if (!!_instances[index]) { return _instances[index] } else if (typeof index !== 'number') { return _instances } else { Galleria.raise('Gallery index ' + index + ' not found') } }; Galleria.addTransition = function (name, fn) { _transitions[name] = fn }; Galleria.utils = Utils; Galleria.log = (function () { if ('console' in window && 'log' in window.console) { return window.console.log } else { return function () { window.alert(Utils.array(arguments).join(', ')) } } } ()); Galleria.ready = function (fn) { $.each(_galleries, function (i, gallery) { fn.call(gallery, gallery._options) }); Galleria.ready.callbacks.push(fn) }; Galleria.ready.callbacks = []; Galleria.raise = function (msg, fatal) { var type = fatal ? 'Fatal error' : 'Error', self = this, echo = function (msg) { var html = '<div style="padding:4px;margin:0 0 2px;background:#' + (fatal ? '811' : '222') + '";>' + (fatal ? '<strong>' + type + ': </strong>' : '') + msg + '</div>'; $.each(_instances, function () { var cont = this.$('errors'), target = this.$('target'); if (!cont.length) { target.css('position', 'relative'); cont = this.addElement('errors').appendChild('target', 'errors').$('errors').css({ color: '#fff', position: 'absolute', top: 0, left: 0, zIndex: 100000 }) } cont.append(html) }) }; if (DEBUG) { echo(msg); if (fatal) { throw new Error(type + ': ' + msg); } } else if (fatal) { if (_hasError) { return } _hasError = true; fatal = false; echo('Image gallery could not load.') } }; Galleria.version = VERSION; Galleria.requires = function (version, msg) { msg = msg || 'You need to upgrade Galleria to version ' + version + ' to use one or more components.'; if (Galleria.version < version) { Galleria.raise(msg, true) } }; Galleria.Picture = function (id) { this.id = id || null; this.image = null; this.container = Utils.create('galleria-image'); $(this.container).css({ overflow: 'hidden', position: 'relative' }); this.original = { width: 0, height: 0 }; this.ready = false; this.tid = null }; Galleria.Picture.prototype = { cache: {}, show: function () { Utils.show(this.image) }, hide: function () { Utils.moveOut(this.image) }, clear: function () { this.image = null }, isCached: function (src) { return !!this.cache[src] }, preload: function (src) { $(new Image()).load((function (src, cache) { return function () { cache[src] = src } } (src, this.cache))).attr('src', src) }, load: function (src, callback) { this.tid = window.setTimeout((function (src) { return function () { Galleria.raise('Image not loaded in ' + Math.round(TIMEOUT / 1000) + ' seconds: ' + src) } } (src)), TIMEOUT); this.image = new Image(); var i = 0, reload = false, $container = $(this.container), $image = $(this.image), onload = (function (self, callback, src) { return function () { var complete = function () { self.original = { height: this.height, width: this.width }; self.cache[src] = src; window.clearTimeout(self.tid); if (typeof callback == 'function') { window.setTimeout(function () { callback.call(self, self) }, 1) } }; if ((!this.width || !this.height)) { window.setTimeout((function (img) { return function () { if (img.width && img.height) { complete.call(img) } else { Galleria.raise('Could not extract width/height from image: ' + img.src + '. Traced measures: width:' + img.width + 'px, height: ' + img.height + 'px.') } } } (this)), 2) } else { complete.call(this) } } } (this, callback, src)); $container.find('img').remove(); $image.css('display', 'block').appendTo(this.container); Utils.hide(this.image); if (this.cache[src]) { this.image.src = src; onload.call(this.image); return this.container } $(this.image).load(onload).error(function () { if (!reload) { reload = true; window.setTimeout((function (image, src) { return function () { image.attr('src', src + '?' + Utils.timestamp()) } } ($(this), src)), 50) } else { if (DUMMY) { $(this).attr('src', DUMMY) } else { Galleria.raise('Image not found: ' + src) } } }).attr('src', src); return this.container }, scale: function (options) { options = $.extend({ width: 0, height: 0, min: undef, max: undef, margin: 0, complete: function () { }, position: 'center', crop: false, canvas: false }, options); if (!this.image) { return this.container } var width, height, self = this, $container = $(self.container), data; Utils.wait({ until: function () { width = options.width || $container.width() || Utils.parseValue($container.css('width')); height = options.height || $container.height() || Utils.parseValue($container.css('height')); return width && height }, success: function () { var newWidth = (width - options.margin * 2) / self.original.width, newHeight = (height - options.margin * 2) / self.original.height, cropMap = { 'true': Math.max(newWidth, newHeight), 'width': newWidth, 'height': newHeight, 'false': Math.min(newWidth, newHeight) }, ratio = cropMap[options.crop.toString()], canvasKey = ''; if (options.max) { ratio = Math.min(options.max, ratio) } if (options.min) { ratio = Math.max(options.min, ratio) } $.each(['width', 'height'], function (i, m) { $(self.image)[m](self[m] = self.image[m] = Math.round(self.original[m] * ratio)) }); $(self.container).width(width).height(height); if (options.canvas && _canvas) { _canvas.elem.width = self.width; _canvas.elem.height = self.height; canvasKey = self.image.src + ':' + self.width + 'x' + self.height; self.image.src = _canvas.cache[canvasKey] || (function (key) { _canvas.context.drawImage(self.image, 0, 0, self.original.width * ratio, self.original.height * ratio); try { data = _canvas.elem.toDataURL(); _canvas.length += data.length; _canvas.cache[key] = data; return data } catch (e) { return self.image.src } } (canvasKey)) } var pos = {}, mix = {}, getPosition = function (value, measure, margin) { var result = 0; if (/\%/.test(value)) { var flt = parseInt(value, 10) / 100, m = self.image[measure] || $(self.image)[measure](); result = Math.ceil(m * -1 * flt + margin * flt) } else { result = Utils.parseValue(value) } return result }, positionMap = { 'top': { top: 0 }, 'left': { left: 0 }, 'right': { left: '100%' }, 'bottom': { top: '100%'} }; $.each(options.position.toLowerCase().split(' '), function (i, value) { if (value === 'center') { value = '50%' } pos[i ? 'top' : 'left'] = value }); $.each(pos, function (i, value) { if (positionMap.hasOwnProperty(value)) { $.extend(mix, positionMap[value]) } }); pos = pos.top ? $.extend(pos, mix) : mix; pos = $.extend({ top: '50%', left: '50%' }, pos); $(self.image).css({ position: 'absolute', top: getPosition(pos.top, 'height', height), left: getPosition(pos.left, 'width', width) }); self.show(); self.ready = true; options.complete.call(self, self) }, error: function () { Galleria.raise('Could not scale image: ' + self.image.src) }, timeout: 1000 }); return this } }; $.extend($.easing, { galleria: function (_, t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t + b } return c / 2 * ((t -= 2) * t * t + 2) + b }, galleriaIn: function (_, t, b, c, d) { return c * (t /= d) * t + b }, galleriaOut: function (_, t, b, c, d) { return -c * (t /= d) * (t - 2) + b } }); $.fn.galleria = function (options) { return this.each(function () { $(this).data('galleria', new Galleria().init(this, options)) }) } } (jQuery));

