vendor/assets/javascripts/fotorama.js in fotoramajs-4.5.0 vs vendor/assets/javascripts/fotorama.js in fotoramajs-4.5.2

- old
+ new

@@ -1,7 +1,7 @@ /*! - * Fotorama 4.5.0 | http://fotorama.io/license/ + * Fotorama 4.5.2 | http://fotorama.io/license/ */ (function (window, document, location, $, undefined) { "use strict"; var _fotoramaClass = 'fotorama', _fullscreenClass = 'fullscreen', @@ -15,10 +15,12 @@ wrapNoControlsClass = wrapClass + '--no-controls', wrapNoShadowsClass = wrapClass + '--no-shadows', wrapPanYClass = wrapClass + '--pan-y', wrapRtlClass = wrapClass + '--rtl', wrapOnlyActiveClass = wrapClass + '--only-active', + wrapNoCaptionsClass = wrapClass + '--no-captions', + wrapToggleArrowsClass = wrapClass + '--toggle-arrows', stageClass = _fotoramaClass + '__stage', stageFrameClass = stageClass + '__frame', stageFrameVideoClass = stageFrameClass + '--video', stageShaftClass = stageClass + '__shaft', @@ -80,11 +82,13 @@ videoCloseClass = videoClass + '-close', captionClass = _fotoramaClass + '__caption', captionWrapClass = _fotoramaClass + '__caption__wrap', - spinnerClass = _fotoramaClass + '__spinner'; + spinnerClass = _fotoramaClass + '__spinner', + + buttonAttributes = '" tabindex="0" role="button'; var JQUERY_VERSION = $ && $.fn.jquery.split('.'); if (!JQUERY_VERSION || JQUERY_VERSION[0] < 1 || (JQUERY_VERSION[0] == 1 && JQUERY_VERSION[1] < 8)) { @@ -359,12 +363,11 @@ } }; return Modernizr; })(window, document); -var - fullScreenApi = { +var fullScreenApi = { ok: false, is: function () { return false; }, request: function () { @@ -844,12 +847,10 @@ FULLSCREEN = fullScreenApi.ok, MOBILE = navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i), SLOW = !CSS3 || MOBILE, - ADD_EVENT_LISTENER = 'addEventListener', - MS_POINTER = navigator.msPointerEnabled, WHEEL = "onwheel" in document.createElement("div") ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll", TOUCH_TIMEOUT = 250, @@ -866,11 +867,84 @@ STAGE_FRAME_KEY = '$stageFrame', NAV_DOT_FRAME_KEY = '$navDotFrame', NAV_THUMB_FRAME_KEY = '$navThumbFrame', - BEZIER = bez([.1, 0, .25, 1]); + AUTO = 'auto', + + BEZIER = bez([.1, 0, .25, 1]), + + MAX_WIDTH = 99999, + + OPTIONS = { + // dimensions + width: null, // 500 || '100%' + minwidth: null, + maxwidth: '100%', // '100%' + height: null, + minheight: null, + maxheight: null, + + ratio: null, // '16/9' || 500/333 || 1.5 + + margin: MARGIN, + glimpse: 0, + + fit: 'contain', // 'cover' || 'scaledown' || 'none' + + // navigation, thumbs + nav: 'dots', // 'thumbs' || false + navposition: 'bottom', // 'top' + navwidth: null, + thumbwidth: THUMB_SIZE, + thumbheight: THUMB_SIZE, + thumbmargin: MARGIN, + thumbborderwidth: MARGIN, + thumbfit: 'cover', // 'contain' || 'scaledown' || 'none' + + allowfullscreen: false, // true || 'native' + + transition: 'slide', // 'crossfade' || 'dissolve' + clicktransition: null, + transitionduration: TRANSITION_DURATION, + + captions: true, + + hash: false, + startindex: 0, + + loop: false, + + autoplay: false, + stopautoplayontouch: true, + + keyboard: false, + + arrows: true, + click: true, + swipe: true, + trackpad: false, + + controlsonstart: true, + + shuffle: false, + + direction: 'ltr', // 'rtl' + + shadows: true, + spinner: null + }, + + KEYBOARD_OPTIONS = { + left: true, + right: true, + down: false, + up: false, + space: false, + home: false, + end: false + }; function noop () {} function minMaxLimit (value, min, max) { return Math.max(isNaN(min) ? -Infinity : min, Math.min(isNaN(max) ? Infinity : max, value)); } @@ -885,14 +959,14 @@ } else { return +$el.css('left').replace('px', ''); } } -function getTranslate (pos, _001) { +function getTranslate (pos/*, _001*/) { var obj = {}; if (CSS3) { - obj.transform = 'translate3d(' + (pos + (_001 ? 0.001 : 0)) + 'px,0,0)'; // 0.001 to remove Retina artifacts + obj.transform = 'translate3d(' + (pos/* + (_001 ? 0.001 : 0)*/) + 'px,0,0)'; // 0.001 to remove Retina artifacts } else { obj.left = pos; } return obj; } @@ -916,10 +990,13 @@ function measureIsValid (value) { return (!!numberFromMeasure(value) || !!numberFromMeasure(value, '%')) && value; } function getPosByIndex (index, side, margin, baseIndex) { + //console.log('getPosByIndex', index, side, margin, baseIndex); + //console.log((index - (baseIndex || 0)) * (side + (margin || 0))); + return (index - (baseIndex || 0)) * (side + (margin || 0)); } function getIndexByPos (pos, side, margin, baseIndex) { return -Math.round(pos / (side + (margin || 0)) - (baseIndex || 0)); @@ -936,13 +1013,13 @@ MozTransition: 'transitionend', OTransition: 'oTransitionEnd otransitionend', msTransition: 'MSTransitionEnd', transition: 'transitionend' }; - el.addEventListener(transitionEndEvent[Modernizr.prefixed('transition')], function (e) { + addEvent(el, transitionEndEvent[Modernizr.prefixed('transition')], function (e) { elData.tProp && e.propertyName.match(elData.tProp) && elData.onEndFn(); - }, false); + }); elData.tEnd = true; } function afterTransition ($el, property, fn, time) { var ok, @@ -966,11 +1043,11 @@ bindTransitionEnd($el); } } -function stop ($el, left, _001) { +function stop ($el, left/*, _001*/) { if ($el.length) { var elData = $el.data(); if (CSS3) { $el.css(getDuration(0)); elData.onEndFn = noop; @@ -980,11 +1057,11 @@ } var lockedLeft = getNumber(left, function () { return readPosition($el); }); - $el.css(getTranslate(lockedLeft, _001));//.width(); // `.width()` for reflow + $el.css(getTranslate(lockedLeft/*, _001*/));//.width(); // `.width()` for reflow return lockedLeft; } } function getNumber () { @@ -1042,11 +1119,11 @@ if ((!id || !type) && forceVideo) { id = href.href; type = 'custom'; } - return id ? {id: id, type: type, s: href.search.replace(/^\?/, '')} : false; + return id ? {id: id, type: type, s: href.search.replace(/^\?/, ''), p: getProtocol()} : false; } function getVideoThumbs (dataFrame, data, fotorama) { var img, thumb, video = dataFrame.video; if (video.type === 'youtube') { @@ -1203,12 +1280,12 @@ } $el.css({ width: Math.ceil(width), height: Math.ceil(height), - marginLeft: Math.floor(-width / 2), - marginTop: Math.floor(-height / 2) + left: Math.floor(measuresToFit.w / 2 - width / 2), + top: Math.floor(measuresToFit.h / 2 - height / 2) }); elData.l = { W: measures.width, H: measures.height, @@ -1308,14 +1385,14 @@ && $.map(array, function (frame) { return $.extend({}, frame); }); } -function lockScroll (left, top) { - $WINDOW - .scrollLeft(left) - .scrollTop(top); +function lockScroll ($el, left, top) { + $el + .scrollLeft(left || 0) + .scrollTop(top || 0); } function optionsToLowerCase (options) { if (options) { var opts = {}; @@ -1336,12 +1413,37 @@ ratio = _ratio.split('/'); return +ratio[0] / +ratio[1] || undefined; } } +function addEvent (el, e, fn, bool) { + if (!e) return; + el.addEventListener ? el.addEventListener(e, fn, !!bool) : el.attachEvent('on'+e, fn); +} + +function elIsDisabled (el) { + return !!el.getAttribute('disabled'); +} + +function disableAttr (FLAG) { + return {tabindex: FLAG * -1 + '', disabled: FLAG}; +} + +function addEnterUp (el, fn) { + addEvent(el, 'keyup', function (e) { + elIsDisabled(el) || e.keyCode == 13 && fn.call(el, e); + }); +} + +function addFocus (el, fn) { + addEvent(el, 'focus', el.onfocusin = function (e) { + fn.call(el, e); + }, true); +} + function stopEvent (e, stopPropagation) { - e.preventDefault(); + e.preventDefault ? e.preventDefault() : (e.returnValue = false); stopPropagation && e.stopPropagation(); } function getDirectionSign (forward) { return forward ? '>' : '<'; @@ -1361,11 +1463,11 @@ slide($el, $.extend({}, options, {overPos: options.pos, time: Math.max(TRANSITION_DURATION, options.time / 2)})) }; } //console.time('var translate = $.extend'); - var translate = $.extend(getTranslate(elPos, options._001), options.width && {width: options.width}); + var translate = $.extend(getTranslate(elPos/*, options._001*/), options.width && {width: options.width}); //console.timeEnd('var translate = $.extend'); elData.sliding = true; if (CSS3) { @@ -1550,30 +1652,28 @@ tail.flow = false; }, TOUCH_TIMEOUT); } if (MS_POINTER) { - el[ADD_EVENT_LISTENER]('MSPointerDown', onStart, false); - document[ADD_EVENT_LISTENER]('MSPointerMove', onMove, false); - document[ADD_EVENT_LISTENER]('MSPointerCancel', onEnd, false); - document[ADD_EVENT_LISTENER]('MSPointerUp', onEnd, false); + addEvent(el, 'MSPointerDown', onStart); + addEvent(document, 'MSPointerMove', onMove); + addEvent(document,'MSPointerCancel', onEnd); + addEvent(document, 'MSPointerUp', onEnd); } else { - if (el[ADD_EVENT_LISTENER]) { - el[ADD_EVENT_LISTENER]('touchstart', onStart, false); - el[ADD_EVENT_LISTENER]('touchmove', onMove, false); - el[ADD_EVENT_LISTENER]('touchend', onEnd, false); + addEvent(el, 'touchstart', onStart); + addEvent(el, 'touchmove', onMove); + addEvent(el, 'touchend', onEnd); - document[ADD_EVENT_LISTENER]('touchstart', onOtherStart, false); - document[ADD_EVENT_LISTENER]('touchend', onOtherEnd, false); - document[ADD_EVENT_LISTENER]('touchcancel', onOtherEnd, false); - window[ADD_EVENT_LISTENER]('scroll', onOtherEnd, false); - } + addEvent(document, 'touchstart', onOtherStart); + addEvent(document, 'touchend', onOtherEnd); + addEvent(document, 'touchcancel', onOtherEnd); - $el.on('mousedown', onStart); - $DOCUMENT - .on('mousemove', onMove) - .on('mouseup', onEnd); + addEvent(window, 'scroll', onOtherEnd); + + addEvent(el, 'mousedown', onStart); + addEvent(document, 'mousemove', onMove); + addEvent(document, 'mouseup', onEnd); } $el.on('click', 'a', function (e) { tail.checked && stopEvent(e); }); @@ -1608,11 +1708,11 @@ moveTrack = [ [startTime, startCoo] ]; - startElPos = moveElPos = tail.noMove || noStop ? 0 : stop($el, (options.getPos || noop)(), options._001); + startElPos = moveElPos = tail.noMove || noStop ? 0 : stop($el, (options.getPos || noop)()/*, options._001*/); (options.onStart || noop).call(el, e); } function onStart (e, result) { @@ -1649,11 +1749,11 @@ } else if (moveElPos >= max) { moveElPos = edgeResistance(moveElPos, max); } if (!tail.noMove) { - $el.css(getTranslate(moveElPos, options._001)); + $el.css(getTranslate(moveElPos/*, options._001*/)); if (!moved) { moved = true; // only for mouse result.touch || MS_POINTER || $el.addClass(grabbingClass); } @@ -1739,17 +1839,15 @@ time *= slowFLAG ? 10 : 1; (options.onEnd || noop).call(el, $.extend(result, {moved: result.moved || longTouchFLAG && snap, pos: moveElPos, newPos: newPos, overPos: overPos, time: time})); } - tail = $.extend(touch(options.$wrap, { + tail = $.extend(touch(options.$wrap, $.extend({}, options, { onStart: onStart, onMove: onMove, - onTouchEnd: options.onTouchEnd, - onEnd: onEnd, - select: options.select - }), tail); + onEnd: onEnd + })), tail); return tail; } function wheel ($el, options) { var el = $el[0], @@ -1758,14 +1856,14 @@ lastNow, tail = { prevent: {} }; - el[ADD_EVENT_LISTENER] && el[ADD_EVENT_LISTENER](WHEEL, function (e) { + addEvent(el, WHEEL, function (e) { var yDelta = e.wheelDeltaY || -1 * e.deltaY || 0, xDelta = e.wheelDeltaX || -1 * e.deltaX || 0, - xWin = Math.abs(xDelta) > Math.abs(yDelta), + xWin = Math.abs(xDelta) && !Math.abs(yDelta), direction = getDirectionSign(xDelta < 0), sameDirection = lastDirection === direction, now = $.now(), tooFast = now - lastNow < TOUCH_TIMEOUT; @@ -1789,17 +1887,17 @@ }, SCROLL_LOCK_TIMEOUT); } (options.onEnd || noop)(e, options.shift ? direction : xDelta); - }, false); + }); return tail; } jQuery.Fotorama = function ($fotorama, opts) { - $HTML = $HTML || $('html'); - $BODY = $BODY || $('body'); + $HTML = $('html'); + $BODY = $('body'); var that = this, stamp = $.now(), stampClass = _fotoramaClass + stamp, fotorama = $fotorama[0], @@ -1815,12 +1913,12 @@ $stage = $(div(stageClass)).appendTo($wrap), stage = $stage[0], $stageShaft = $(div(stageShaftClass)).appendTo($stage), $stageFrame = $(), - $arrPrev = $(div(arrClass + ' ' + arrPrevClass/*, div(arrArrClass)*/)), - $arrNext = $(div(arrClass + ' ' + arrNextClass/*, div(arrArrClass)*/)), + $arrPrev = $(div(arrClass + ' ' + arrPrevClass + buttonAttributes)), + $arrNext = $(div(arrClass + ' ' + arrNextClass + buttonAttributes)), $arrs = $arrPrev.add($arrNext).appendTo($stage), $navWrap = $(div(navWrapClass)), $nav = $(div(navClass)).appendTo($navWrap), $navShaft = $(div(navShaftClass)).appendTo($nav), $navFrame, @@ -1830,11 +1928,11 @@ stageShaftData = $stageShaft.data(), navShaftData = $navShaft.data(), $thumbBorder = $(div(thumbBorderClass)).appendTo($navShaft), - $fullscreenIcon = $(div(fullscreenIconClass)), + $fullscreenIcon = $(div(fullscreenIconClass + buttonAttributes)), fullscreenIcon = $fullscreenIcon[0], $videoPlay = $(div(videoPlayClass)), $videoClose = $(div(videoCloseClass)).appendTo($stage), videoClose = $videoClose[0], @@ -1864,10 +1962,11 @@ o_thumbSide2, o_transitionDuration, o_transition, o_shadows, o_rtl, + o_keyboard, lastOptions = {}, measures = {}, measuresSetFLAG, @@ -1896,19 +1995,21 @@ stageLeft = 0, fadeStack = []; $wrap[STAGE_FRAME_KEY] = $(div(stageFrameClass)); - $wrap[NAV_THUMB_FRAME_KEY] = $(div(navFrameClass + ' ' + navFrameThumbClass, div(thumbClass))); - $wrap[NAV_DOT_FRAME_KEY] = $(div(navFrameClass + ' ' + navFrameDotClass, div(dotClass))); + $wrap[NAV_THUMB_FRAME_KEY] = $(div(navFrameClass + ' ' + navFrameThumbClass + buttonAttributes, div(thumbClass))); + $wrap[NAV_DOT_FRAME_KEY] = $(div(navFrameClass + ' ' + navFrameDotClass + buttonAttributes, div(dotClass))); toDeactivate[STAGE_FRAME_KEY] = []; toDeactivate[NAV_THUMB_FRAME_KEY] = []; toDeactivate[NAV_DOT_FRAME_KEY] = []; toDetach[STAGE_FRAME_KEY] = {}; - $wrap.addClass(CSS3 ? wrapCss3Class : wrapCss2Class); + $wrap + .addClass(CSS3 ? wrapCss3Class : wrapCss2Class) + .toggleClass(wrapNoControlsClass, !opts.controlsonstart); fotoramaData.fotorama = this; function checkForVideo () { $.each(data, function (i, dataFrame) { @@ -1927,33 +2028,46 @@ } } }); } + function allowKey (key) { + return o_keyboard[key] || that.fullScreen; + } + function bindGlobalEvents (FLAG) { var keydownCommon = 'keydown.' + _fotoramaClass, - keydownLocal = 'keydown.' + _fotoramaClass + stamp, - resizeLocal = 'resize.' + _fotoramaClass + stamp; + localStamp = _fotoramaClass + stamp, + keydownLocal = 'keydown.' + localStamp, + resizeLocal = 'resize.' + localStamp + ' ' + 'orientationchange.' + localStamp; if (FLAG) { $DOCUMENT .on(keydownLocal, function (e) { + var catched, + index; + if ($videoPlaying && e.keyCode === 27) { - stopEvent(e); + catched = true; unloadVideo($videoPlaying, true, true); } else if (that.fullScreen || (opts.keyboard && !that.index)) { if (e.keyCode === 27) { - stopEvent(e); + catched = true; that.cancelFullScreen(); - } else if (e.keyCode === 39 || (e.keyCode === 40 && that.fullScreen)) { - stopEvent(e); - that.show({index: '>', slow: e.altKey, user: true}); - } else if (e.keyCode === 37 || (e.keyCode === 38 && that.fullScreen)) { - stopEvent(e); - that.show({index: '<', slow: e.altKey, user: true}); + } else if ((e.shiftKey && e.keyCode === 32 && allowKey('space')) || (e.keyCode === 37 && allowKey('left')) || (e.keyCode === 38 && allowKey('up'))) { + index = '<'; + } else if ((e.keyCode === 32 && allowKey('space')) || (e.keyCode === 39 && allowKey('right')) || (e.keyCode === 40 && allowKey('down'))) { + index = '>'; + } else if (e.keyCode === 36 && allowKey('home')) { + index = '<<'; + } else if (e.keyCode === 35 && allowKey('end')) { + index = '>>'; } } + + (catched || index) && stopEvent(e); + index && that.show({index: index, slow: e.altKey, user: true}); }); if (!that.index) { $DOCUMENT .off(keydownCommon) @@ -2012,45 +2126,47 @@ function stageNoMove () { var _noMove = size < 2 || $videoPlaying; stageShaftTouchTail.noMove = _noMove || o_fade; stageShaftTouchTail.noSwipe = _noMove || !opts.swipe; - !o_transition && $stageShaft.toggleClass(grabClass, !stageShaftTouchTail.noMove && !stageShaftTouchTail.noSwipe); + !o_transition && $stageShaft.toggleClass(grabClass, !opts.click && !stageShaftTouchTail.noMove && !stageShaftTouchTail.noSwipe); MS_POINTER && $wrap.toggleClass(wrapPanYClass, !stageShaftTouchTail.noSwipe); } function setAutoplayInterval (interval) { if (interval === true) interval = ''; opts.autoplay = Math.max(+interval || AUTOPLAY_INTERVAL, o_transitionDuration * 1.5); } - function addOrRemove (FLAG) { - return FLAG ? 'add' : 'remove'; - } - /** * Options on the fly * */ function setOptions () { that.options = opts = optionsToLowerCase(opts); - o_fade = opts.transition === 'crossfade' || opts.transition === 'dissolve'; + o_fade = (opts.transition === 'crossfade' || opts.transition === 'dissolve'); - o_loop = opts.loop && (size > 2 || o_fade); + o_loop = opts.loop && (size > 2 || (o_fade && (!o_transition || o_transition !== 'slide'))); o_transitionDuration = +opts.transitionduration || TRANSITION_DURATION; o_rtl = opts.direction === 'rtl'; + o_keyboard = $.extend({}, opts.keyboard && KEYBOARD_OPTIONS, opts.keyboard); + var classes = {add: [], remove: []}; + function addOrRemoveClass (FLAG, value) { + classes[FLAG ? 'add' : 'remove'].push(value); + } + if (size > 1) { o_nav = opts.nav; o_navTop = opts.navposition === 'top'; classes.remove.push(selectClass); - $arrs.toggle(opts.arrows); + $arrs.toggle(!!opts.arrows); } else { o_nav = false; $arrs.hide(); } @@ -2067,11 +2183,11 @@ stageWheelTail.ok = navWheelTail.ok = opts.trackpad && !SLOW; stageNoMove(); - extendMeasures(opts, true); + extendMeasures(opts, [measures]); o_navThumbs = o_nav === 'thumbs'; if (o_navThumbs) { frameDraw(size, 'navThumb'); @@ -2109,24 +2225,25 @@ } o_allowFullScreen = opts.allowfullscreen; if (o_allowFullScreen) { - $fullscreenIcon.appendTo($stage); + $fullscreenIcon.prependTo($stage); o_nativeFullScreen = FULLSCREEN && o_allowFullScreen === 'native'; } else { $fullscreenIcon.detach(); o_nativeFullScreen = false; } - classes[addOrRemove(o_fade)].push(wrapFadeClass); - classes[addOrRemove(!o_fade)].push(wrapSlideClass); + addOrRemoveClass(o_fade, wrapFadeClass); + addOrRemoveClass(!o_fade, wrapSlideClass); + addOrRemoveClass(!opts.captions, wrapNoCaptionsClass); + addOrRemoveClass(o_rtl, wrapRtlClass); + addOrRemoveClass(opts.arrows !== 'always', wrapToggleArrowsClass); - classes[addOrRemove(o_rtl)].push(wrapRtlClass); - o_shadows = opts.shadows && !SLOW; - classes[addOrRemove(!o_shadows)].push(wrapNoShadowsClass); + addOrRemoveClass(!o_shadows, wrapNoShadowsClass); $wrap .addClass(classes.add.join(' ')) .removeClass(classes.remove.join(' ')); @@ -2186,16 +2303,19 @@ }); } function setMeasures (width, height, ratio, index) { if (!measuresSetFLAG || (measuresSetFLAG === '*' && index === startIndex)) { + + //console.log('setMeasures', index, opts.width, opts.height); + width = measureIsValid(opts.width) || measureIsValid(width) || WIDTH; height = measureIsValid(opts.height) || measureIsValid(height) || HEIGHT; that.resize({ width: width, ratio: opts.ratio || ratio || width / height - }, 0, index === startIndex ? true : '*'); + }, 0, index !== startIndex && '*'); } } function loadImg (indexes, type, specialMeasures, specialFit, again) { eachIndex(indexes, type, function (i, index, dataFrame, $frame, key, frameData) { @@ -2290,12 +2410,16 @@ .removeClass(loadingClass + ' ' + errorClass) .addClass(loadedClass + ' ' + (fullFLAG ? loadedFullClass : loadedImgClass)); if (type === 'stage') { triggerTriggerEvent('load'); + } else if (dataFrame.thumbratio === AUTO || !dataFrame.thumbratio && opts.thumbratio === AUTO) { + // danger! reflow for all thumbnails + dataFrame.thumbratio = imgData.measures.ratio; + reset(); } - }, 5); + }, 0); } if (!src) { error(); return; @@ -2342,28 +2466,40 @@ $spinner.detach(); spinner && spinner.stop(); } function updateFotoramaState () { - var $frame = that.activeFrame[STAGE_FRAME_KEY]; + var $frame = activeFrame[STAGE_FRAME_KEY]; if ($frame && !$frame.data().state) { spinnerSpin($frame); $frame.on('f:load f:error', function () { $frame.off('f:load f:error'); spinnerStop(); }); } } + function addNavFrameEvents (frame) { + addEnterUp(frame, onNavFrameClick); + addFocus(frame, function () { + + setTimeout(function () { + lockScroll($nav); + }, 0); + slideNavShaft({time: o_transitionDuration, guessIndex: $(this).data().eq, minMax: navShaftTouchTail}); + }); + } + function frameDraw (indexes, type) { eachIndex(indexes, type, function (i, index, dataFrame, $frame, key, frameData) { if ($frame) return; $frame = dataFrame[key] = $wrap[key].clone(); frameData = $frame.data(); frameData.data = dataFrame; + var frame = $frame[0]; if (type === 'stage') { if (dataFrame.html) { $('<div class="' + htmlClass + '"></div>') @@ -2374,22 +2510,30 @@ : dataFrame.html ) .appendTo($frame); } - if (opts.captions && dataFrame.caption) { - $(div(captionClass, div(captionWrapClass, dataFrame.caption))).appendTo($frame); - } + dataFrame.caption && $(div(captionClass, div(captionWrapClass, dataFrame.caption))).appendTo($frame); dataFrame.video && $frame .addClass(stageFrameVideoClass) .append($videoPlay.clone()); + // This solves tabbing problems + addFocus(frame, function () { + setTimeout(function () { + lockScroll($stage); + }, 0); + clickToShow({index: frameData.eq, user: true}); + }); + $stageFrame = $stageFrame.add($frame); } else if (type === 'navDot') { + addNavFrameEvents(frame); $navDotFrame = $navDotFrame.add($frame); } else if (type === 'navThumb') { + addNavFrameEvents(frame); frameData.$wrap = $frame.children(':first'); $navThumbFrame = $navThumbFrame.add($frame); if (dataFrame.video) { $frame.append($videoPlay.clone()); } @@ -2403,12 +2547,15 @@ function stageFramePosition (indexes) { eachIndex(indexes, 'stage', function (i, index, dataFrame, $frame, key, frameData) { if (!$frame) return; - toDetach[STAGE_FRAME_KEY][normalizeIndex(index)] = $frame.css($.extend({left: o_fade ? 0 : getPosByIndex(index, measures.w, opts.margin, repositionIndex)}, o_fade && getDuration(0))); + var normalizedIndex = normalizeIndex(index); + frameData.eq = normalizedIndex; + toDetach[STAGE_FRAME_KEY][normalizedIndex] = $frame.css($.extend({left: o_fade ? 0 : getPosByIndex(index, measures.w, opts.margin, repositionIndex)}, o_fade && getDuration(0))); + if (isDetached($frame[0])) { $frame.appendTo($stageShaft); unloadVideo(dataFrame.$video); } @@ -2428,11 +2575,11 @@ $navThumbFrame.each(function () { var $this = $(this), thisData = $this.data(), eq = thisData.eq, specialMeasures = {h: o_thumbSide2}, - specialFit = 'cover'; + specialFit = (data[eq] || {}).thumbfit || opts.thumbfit; specialMeasures.w = thisData.w; if (thisData.l + thisData.w < leftLimit || thisData.l > rightLimit @@ -2494,18 +2641,18 @@ function disableDirrection (i) { return !o_loop && (!(activeIndex + i) || !(activeIndex - size + i)) && !$videoPlaying; } function arrsUpdate () { - $arrPrev.toggleClass( - arrDisabledClass, - disableDirrection(0) - ); - $arrNext.toggleClass( - arrDisabledClass, - disableDirrection(1) - ); + var disablePrev = disableDirrection(0), + disableNext = disableDirrection(1); + $arrPrev + .toggleClass(arrDisabledClass, disablePrev) + .attr(disableAttr(disablePrev)); + $arrNext + .toggleClass(arrDisabledClass, disableNext) + .attr(disableAttr(disableNext)); } function stageWheelUpdate () { if (stageWheelTail.ok) { stageWheelTail.prevent = {'<': disableDirrection(0), '>': disableDirrection(1)}; @@ -2531,27 +2678,27 @@ max: -left + measures.w - width - opts.thumbmargin * 10 }; } function slideThumbBorder (time) { - var navFrameData = that.activeFrame[navFrameKey].data(); + var navFrameData = activeFrame[navFrameKey].data(); slide($thumbBorder, { - time: time * .9, + time: time * 1.2, pos: navFrameData.l, width: navFrameData.w - opts.thumbborderwidth * 2 }); } function slideNavShaft (options) { - //console.log('slideNavShaft'); + //console.log('slideNavShaft', options.guessIndex, options.keep, slideNavShaft.l); var $guessNavFrame = data[options.guessIndex][navFrameKey]; if ($guessNavFrame) { var overflowFLAG = navShaftTouchTail.min !== navShaftTouchTail.max, - activeNavFrameBounds = overflowFLAG && getNavFrameBounds(that.activeFrame[navFrameKey]), - l = overflowFLAG && (options.keep && slideNavShaft.l ? slideNavShaft.l : minMaxLimit((options.coo || measures.nw / 2) - getNavFrameBounds($guessNavFrame).c, activeNavFrameBounds.min, activeNavFrameBounds.max)), + minMax = options.minMax || overflowFLAG && getNavFrameBounds(activeFrame[navFrameKey]), + l = overflowFLAG && (options.keep && slideNavShaft.l ? slideNavShaft.l : minMaxLimit((options.coo || measures.nw / 2) - getNavFrameBounds($guessNavFrame).c, minMax.min, minMax.max)), pos = overflowFLAG && minMaxLimit(l, navShaftTouchTail.min, navShaftTouchTail.max), - time = options.time * .9; + time = options.time * 1.1; slide($navShaft, { time: time, pos: pos || 0, onEnd: function () { @@ -2566,11 +2713,11 @@ } } function navUpdate () { deactivateFrames(navFrameKey); - toDeactivate[navFrameKey].push(that.activeFrame[navFrameKey].addClass(activeClass)); + toDeactivate[navFrameKey].push(activeFrame[navFrameKey].addClass(activeClass)); } function deactivateFrames (key) { var _toDeactivate = toDeactivate[key]; @@ -2598,12 +2745,11 @@ function stageShaftReposition (skipOnEnd) { repositionIndex = dirtyIndex = activeIndex; - var dataFrame = that.activeFrame, - $frame = dataFrame[STAGE_FRAME_KEY]; + var $frame = activeFrame[STAGE_FRAME_KEY]; if ($frame) { deactivateFrames(STAGE_FRAME_KEY); toDeactivate[STAGE_FRAME_KEY].push($frame.addClass(activeClass)); @@ -2615,28 +2761,25 @@ setStageShaftMinmaxAndSnap(); setNavShaftMinMax(); } } - function extendMeasures (options, optsLeave) { - options && $.extend(measures, { - width: options.width || measures.width, - height: options.height, - minwidth: options.minwidth, - maxwidth: options.maxwidth, - minheight: options.minheight, - maxheight: options.maxheight, - ratio: getRatio(options.ratio) - }) - && !optsLeave && $.extend(opts, { - width: measures.width, - height: measures.height, - minwidth: measures.minwidth, - maxwidth: measures.maxwidth, - minheight: measures.minheight, - maxheight: measures.maxheight, - ratio: measures.ratio + function extendMeasures (options, measuresArray) { + if (!options) return; + + $.each(measuresArray, function (i, measures) { + if (!measures) return; + + $.extend(measures, { + width: options.width || measures.width, + height: options.height, + minwidth: options.minwidth, + maxwidth: options.maxwidth, + minheight: options.minheight, + maxheight: options.maxheight, + ratio: getRatio(options.ratio) + }) }); } function triggerEvent (event, extra) { $fotorama.trigger(_fotoramaClass + ':' + event, [that, extra]); @@ -2687,11 +2830,11 @@ } var _activeIndex = activeIndex; - var frameData = that.activeFrame[STAGE_FRAME_KEY].data(); + var frameData = activeFrame[STAGE_FRAME_KEY].data(); waitFor(function () { return frameData.state || _activeIndex !== activeIndex; }, function () { changeAutoplay.t = setTimeout(function () { if (pausedAutoplayFLAG || _activeIndex !== activeIndex) return; @@ -2747,13 +2890,16 @@ }), overPos = options.overPos; if (options.slow) time *= 10; + var _activeFrame = activeFrame; that.activeFrame = activeFrame = data[activeIndex]; ////console.timeEnd('that.show prepare'); + var silent = _activeFrame === activeFrame; + //setTimeout(function () { ////console.time('unloadVideo'); unloadVideo($videoPlaying, activeFrame.i !== data[normalizeIndex(repositionIndex)].i); ////console.timeEnd('unloadVideo'); ////console.time('frameDraw'); @@ -2764,11 +2910,12 @@ ////console.timeEnd('stageFramePosition'); ////console.time('updateTouchTails'); updateTouchTails('go', true); ////console.timeEnd('updateTouchTails'); ////console.time('triggerEvent'); - options.reset || triggerEvent('show', { + + silent || triggerEvent('show', { user: options.user, time: time }); ////console.timeEnd('triggerEvent'); //}, 0); @@ -2781,13 +2928,11 @@ if (onEnd.ok) return; onEnd.ok = true; skipReposition || stageShaftReposition(true); - //console.log('options.reset', options.reset); - - if (!options.reset) { + if (!silent) { triggerEvent('showend', { user: options.user }); //console.log('o_transition', o_transition); @@ -2816,12 +2961,12 @@ ////console.time('slide'); slide($stageShaft, { pos: -getPosByIndex(dirtyIndex, measures.w, opts.margin, repositionIndex), overPos: overPos, time: time, - onEnd: onEnd, - _001: true + onEnd: onEnd/*, + _001: true*/ }); ////console.timeEnd('slide'); } else { var $activeFrame = activeFrame[STAGE_FRAME_KEY], $prevActiveFrame = activeIndex !== lastActiveIndex ? data[lastActiveIndex][STAGE_FRAME_KEY] : null; @@ -2842,11 +2987,11 @@ navUpdate(); ////console.timeEnd('navUpdate'); ////console.time('slideNavShaft'); var guessIndex = limitIndex(activeIndex + minMaxLimit(dirtyIndex - lastActiveIndex, -1, 1)); - slideNavShaft({time: time, coo: guessIndex !== activeIndex && options.coo, guessIndex: typeof options.coo !== 'undefined' ? guessIndex : activeIndex, keep: options.reset}); + slideNavShaft({time: time, coo: guessIndex !== activeIndex && options.coo, guessIndex: typeof options.coo !== 'undefined' ? guessIndex : activeIndex, keep: silent}); ////console.timeEnd('slideNavShaft'); ////console.time('slideThumbBorder'); if (o_navThumbs) slideThumbBorder(time); ////console.timeEnd('slideThumbBorder'); @@ -2866,11 +3011,11 @@ that.requestFullScreen = function () { if (o_allowFullScreen && !that.fullScreen) { scrollTop = $WINDOW.scrollTop(); scrollLeft = $WINDOW.scrollLeft(); - lockScroll(0, 0); + lockScroll($WINDOW); updateTouchTails('x', true); measuresStash = $.extend({}, measures); @@ -2920,11 +3065,11 @@ updateTouchTails('x', false); that.resize(); loadImg(activeIndexes, 'stage'); - lockScroll(scrollLeft, scrollTop); + lockScroll($WINDOW, scrollLeft, scrollTop); triggerEvent('fullscreenexit'); } } @@ -2936,34 +3081,37 @@ } return this; }; - if (document.addEventListener) { - document.addEventListener(fullScreenApi.event, function () { - if (data && !fullScreenApi.is() && !$videoPlaying) { - cancelFullScreen(); - } - }, false); - } + that.toggleFullScreen = function () { + return that[(that.fullScreen ? 'cancel' : 'request') + 'FullScreen'](); + }; + addEvent(document, fullScreenApi.event, function () { + if (data && !fullScreenApi.is() && !$videoPlaying) { + cancelFullScreen(); + } + }); + that.resize = function (options) { if (!data) return this; - extendMeasures(!that.fullScreen ? optionsToLowerCase(options) : {width: '100%', maxwidth: null, minwidth: null, height: '100%', maxheight: null, minheight: null}, that.fullScreen); - var time = arguments[1] || 0, - setFLAG = arguments[2], - width = measures.width, + setFLAG = arguments[2]; + + extendMeasures(!that.fullScreen ? optionsToLowerCase(options) : {width: '100%', maxwidth: null, minwidth: null, height: '100%', maxheight: null, minheight: null}, [measures, setFLAG || that.fullScreen || opts]); + + var width = measures.width, height = measures.height, ratio = measures.ratio, windowHeight = $WINDOW.height() - (o_nav ? $nav.height() : 0); if (measureIsValid(width)) { $wrap .addClass(wrapOnlyActiveClass) - .css({width: width, minWidth: measures.minwidth, maxWidth: measures.maxwidth}); + .css({width: width, minWidth: measures.minwidth || 0, maxWidth: measures.maxwidth || MAX_WIDTH}); width = measures.W = measures.w = $wrap.width(); measures.nw = o_nav && numberFromWhatever(opts.navwidth, width) || width; if (opts.glimpse) { @@ -3041,15 +3189,17 @@ appendElements(); activeIndexes = []; detachFrames(STAGE_FRAME_KEY); + reset.ok = false; + return this; }; that.playVideo = function () { - var dataFrame = that.activeFrame, + var dataFrame = activeFrame, video = dataFrame.video, _activeIndex = activeIndex; if (typeof video === 'object' && dataFrame.videoReady) { o_nativeFullScreen && that.fullScreen && that.cancelFullScreen(); @@ -3064,10 +3214,13 @@ $wrap.addClass(wrapVideoClass); $videoPlaying = dataFrame.$video; stageNoMove(); + $arrs.blur(); + $fullscreenIcon.blur(); + triggerEvent('loadvideo'); } }); } @@ -3107,11 +3260,10 @@ var x = e ? e.pageX : stageCursor.x, pointerFLAG = x && !disableDirrection(getDirection(x)) && opts.click; if (stageCursor.p !== pointerFLAG - && (o_fade || !opts.swipe) && $stage.toggleClass(pointerClass, pointerFLAG)) { stageCursor.p = pointerFLAG; stageCursor.x = x; } } @@ -3141,11 +3293,11 @@ $target = $(target); if ($target.hasClass(videoPlayClass)) { that.playVideo(); } else if (target === fullscreenIcon) { - that[(that.fullScreen ? 'cancel' : 'request') + 'FullScreen'](); + that.toggleFullScreen(); } else if ($videoPlaying) { target === videoClose && unloadVideo($videoPlaying, true, true); } else { if (toggleControlsFLAG) { toggleControlsClass(); @@ -3171,11 +3323,11 @@ ////console.time('stageShaftTouchTail.onEnd'); setShadow($stage); ////console.log('result', result); - var toggleControlsFLAG = (MS_POINTER && !hoverFLAG || result.touch) && opts.arrows; + var toggleControlsFLAG = (MS_POINTER && !hoverFLAG || result.touch) && opts.arrows && opts.arrows !== 'always'; if (result.moved || (toggleControlsFLAG && result.pos !== result.newPos && !result.control)) { var index = getIndexByPos(result.newPos, measures.w, opts.margin, repositionIndex); that.show({ index: index, @@ -3189,11 +3341,11 @@ ////console.timeEnd('stageShaftTouchTail.onEnd'); }, // getPos: function () { // return -getPosByIndex(dirtyIndex, measures.w, opts.margin, repositionIndex); // }, - _001: true, + //_001: true, timeLow: 1, timeHigh: 1, friction: 2, select: '.' + selectClass + ', .' + selectClass + ' *', $wrap: $stage @@ -3256,58 +3408,83 @@ $navShaft.css(getTranslate(minMaxLimit(newPos, navShaftTouchTail.min, navShaftTouchTail.max))); o_shadows && setShadow($nav, findShadowEdge(newPos, navShaftTouchTail.min, navShaftTouchTail.max)); navWheelTail.prevent = {'<': newPos >= navShaftTouchTail.max, '>': newPos <= navShaftTouchTail.min}; clearTimeout(navWheelTail.t); navWheelTail.t = setTimeout(function () { + slideNavShaft.l = newPos; thumbsDraw(newPos, true) }, TOUCH_TIMEOUT); thumbsDraw(newPos); } }); $wrap.hover( function () { setTimeout(function () { if (touchedFLAG) return; - hoverFLAG = true; - toggleControlsClass(!hoverFLAG); + toggleControlsClass(!(hoverFLAG = true)); }, 0); }, function () { if (!hoverFLAG) return; - hoverFLAG = false; - toggleControlsClass(!hoverFLAG); + toggleControlsClass(!(hoverFLAG = false)); } ); - function onNavFrameClick (e, time) { + function onNavFrameClick (e) { var index = $(this).data().eq; - clickToShow({index: index, slow: e.altKey, user: true, coo: e._x - $nav.offset().left, time: time}); + clickToShow({index: index, slow: e.altKey, user: true, coo: e._x - $nav.offset().left}); } + function onArrClick (e) { + clickToShow({index: $arrs.index(this) ? '>' : '<', slow: e.altKey, user: true}); + } + smartClick($arrs, function (e) { stopEvent(e); - clickToShow({index: $arrs.index(this) ? '>' : '<', slow: e.altKey, user: true}); + onArrClick.call(this, e); }, { onStart: function () { onTouchStart(); stageShaftTouchTail.control = true; }, onTouchEnd: onTouchEnd }); + function addFocusOnControls (el) { + addFocus(el, function () { + lockScroll($stage); + setTimeout(function () { + lockScroll($stage); + }, 0); + toggleControlsClass(false); + }); + } + + $arrs.each(function () { + addEnterUp(this, function (e) { + onArrClick.call(this, e); + }); + addFocusOnControls(this); + }); + + addEnterUp(fullscreenIcon, that.toggleFullScreen); + addFocusOnControls(fullscreenIcon); + function reset () { + var ok = reset.ok; + setData(); setOptions(); if (!reset.i) { reset.i = true; // Only once var _startindex = opts.startindex; if (_startindex || opts.hash && location.hash) { startIndex = getIndexFromHash(_startindex || location.hash.replace(/^#/, ''), data, that.index === 0 || _startindex, _startindex); } - activeIndex = repositionIndex = dirtyIndex = lastActiveIndex = startIndex = edgeIndex(startIndex) || 0;/*(o_rtl ? size - 1 : 0)*/; + activeIndex = repositionIndex = dirtyIndex = lastActiveIndex = startIndex = edgeIndex(startIndex) || 0;/*(o_rtl ? size - 1 : 0)*///; } if (size) { if (changeToRtl()) return; @@ -3316,17 +3493,17 @@ } activeIndexes = []; detachFrames(STAGE_FRAME_KEY); - that.show({index: activeIndex, time: 0, reset: reset.ok}); + reset.ok = true; + + that.show({index: activeIndex, time: 0}); that.resize(); } else { that.destroy(); } - - reset.ok = true; } function changeToRtl () { ////console.log('changeToRtl'); if (!changeToRtl.f === o_rtl) { @@ -3380,73 +3557,19 @@ * 1. <div data-loop="true"></div> * 2. $('div').fotorama({loop: false}) * 3. Defaults */ $.extend( {}, - { - // dimensions - width: null, // 500 || '100%' - minwidth: null, - maxwidth: '100%', // '100%' - height: null, - minheight: null, - maxheight: null, - - ratio: null, // '16/9' || 500/333 || 1.5 - - margin: MARGIN, - glimpse: 0, - - // navigation, thumbs - nav: 'dots', // 'thumbs' || false - navposition: 'bottom', // 'top' - navwidth: null, - thumbwidth: THUMB_SIZE, - thumbheight: THUMB_SIZE, - thumbmargin: MARGIN, - thumbborderwidth: MARGIN, - - allowfullscreen: false, // true || 'native' - - fit: 'contain', // 'cover' || 'scaledown' || 'none' - - transition: 'slide', // 'crossfade' || 'dissolve' - clicktransition: null, - transitionduration: TRANSITION_DURATION, - - captions: true, - - hash: false, - startindex: 0, - - loop: false, - - autoplay: false, - stopautoplayontouch: true, - - keyboard: false, - - arrows: true, - click: true, - swipe: true, - trackpad: true, - - shuffle: false, - - direction: 'ltr', // 'rtl' - - shadows: true, - spinner: null - }, + OPTIONS, window.fotoramaDefaults, opts, fotoramaData ) ); }); } else { - fotorama.setOptions(opts); + fotorama.setOptions(opts, true); } }); }; $.Fotorama.instances = []; @@ -3493,11 +3616,11 @@ $.Fotorama.jst.video = function(v) { var __t, __p = '', __e = _.escape, __j = Array.prototype.join; function print() { __p += __j.call(arguments, '') } __p += '<div class="fotorama__video"><iframe src="'; - print((v.type == 'youtube' ? 'http://youtube.com/embed/' + v.id +'?autoplay=1' : v.type == 'vimeo' ? 'http://player.vimeo.com/video/' + v.id + '?autoplay=1&badge=0' : v.id) + (v.s && v.type != 'custom' ? '&' + v.s : '')) ; -__p += '" frameborder="0" allowfullscreen></iframe></div>'; + print((v.type == 'youtube' ? v.p + 'youtube.com/embed/' + v.id +'?autoplay=1' : v.type == 'vimeo' ? v.p + 'player.vimeo.com/video/' + v.id + '?autoplay=1&badge=0' : v.id) + (v.s && v.type != 'custom' ? '&' + v.s : '')) ; +__p += '" frameborder="0" allowfullscreen></iframe></div>\n'; return __p }; $(function () { $('.' + _fotoramaClass + ':not([data-auto="false"])').fotorama(); });