diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml index 86af618c38900..600902bec5d19 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml @@ -20,6 +20,24 @@ + + diff --git a/app/code/Magento/Swatches/view/frontend/web/css/swatches.css b/app/code/Magento/Swatches/view/frontend/web/css/swatches.css index 321a57c605300..8204fc7fc8f63 100644 --- a/app/code/Magento/Swatches/view/frontend/web/css/swatches.css +++ b/app/code/Magento/Swatches/view/frontend/web/css/swatches.css @@ -269,7 +269,7 @@ } /* Bugfix for Add To Cart button */ -div[class^="swatch-opt-"] { +.swatch-opt-listing { margin-bottom: 10px; } diff --git a/app/code/Magento/Swatches/view/frontend/web/js/SwatchRenderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js similarity index 94% rename from app/code/Magento/Swatches/view/frontend/web/js/SwatchRenderer.js rename to app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js index da59d840c204c..169da58a35ccb 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/SwatchRenderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js @@ -19,7 +19,7 @@ define([ * - option-tooltip-thumb * - option-tooltip-value */ - $.widget('custom.SwatchRendererTooltip', { + $.widget('mage.SwatchRendererTooltip', { options: { delay: 200, //how much ms before tooltip to show tooltipClass: 'swatch-option-tooltip' //configurable, but remember about css @@ -141,7 +141,7 @@ define([ * - selectorProduct (selector for product container) * - selectorProductPrice (selector for change price) */ - $.widget('custom.SwatchRenderer', { + $.widget('mage.SwatchRenderer', { options: { classes: { attributeClass: 'swatch-attribute', @@ -166,6 +166,9 @@ define([ // selector of price wrapper (need to know where set price) selectorProductPrice: '[data-role=priceBox]', + //selector of product images gallery wrapper + mediaGallerySelector: '[data-gallery-role=gallery-placeholder]', + // number of controls to show (false or zero = show all) numberToShow: false, @@ -182,7 +185,10 @@ define([ mediaCallback: '', // Cache for BaseProduct images. Needed when option unset - mediaGalleryInitial: [{}] + mediaGalleryInitial: [{}], + + // + onlyMainImg: false }, /** @@ -814,7 +820,8 @@ define([ images.push({ full: response.large, img: response.medium, - thumb: response.small + thumb: response.small, + isMain: true }); if (response.hasOwnProperty('gallery')) { @@ -834,6 +841,24 @@ define([ this.updateBaseImage(images, $main, isProductViewExist); }, + /** + * Check if images to update are initial and set their type + * @param {Array} images + */ + _setImageType: function (images) { + var initial = this.options.mediaGalleryInitial[0].img; + + if (images[0].img === initial) { + images = $.extend(true, [], this.options.mediaGalleryInitial); + } else { + images.map(function (img) { + img.type = 'image'; + }); + } + + return images; + }, + /** * Update [gallery-placeholder] or [product-image-photo] * @param {Array} images @@ -841,13 +866,29 @@ define([ * @param {Boolean} isProductViewExist */ updateBaseImage: function (images, context, isProductViewExist) { - var justAnImage = images[0]; + var justAnImage = images[0], + updateImg, + imagesToUpdate, + gallery = context.find(this.options.mediaGallerySelector).data('gallery'), + item; + + if (images) { + imagesToUpdate = this._setImageType($.extend(true, [], images)); + } if (isProductViewExist) { - context - .find('[data-gallery-role=gallery-placeholder]') - .data('gallery') - .updateData(images); + if (this.options.onlyMainImg) { + updateImg = imagesToUpdate.filter(function (img) { + return img.isMain; + }); + item = updateImg.length ? updateImg[0] : imagesToUpdate[0]; + gallery.updateDataByIndex(0, item); + + gallery.seek(1); + } else { + gallery.updateData(imagesToUpdate); + $(this.options.mediaGallerySelector).AddFotoramaVideoEvents(); + } } else if (justAnImage && justAnImage.img) { context.find('.product-image-photo').attr('src', justAnImage.img); } @@ -901,4 +942,6 @@ define([ return selectedAttributes; } }); + + return $.mage.SwatchRenderer; }); diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less index 2a72c5d9aef2c..c7c21d23585a7 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less @@ -71,6 +71,7 @@ bottom: 0; left: 0; margin: auto; + max-height: 100%; max-width: 100%; position: absolute; right: 0; diff --git a/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less index ca30dbabe31b0..39ea21884a389 100644 --- a/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less @@ -76,15 +76,6 @@ and (orientation : landscape) { } } -.fotorama__arr.hidden-video { - z-index: -1 !important; -} - -.fotorama__video-close { - bottom: 89%; - top: auto; -} - .fotorama__stage__shaft:focus .fotorama__stage__frame.fotorama__active:after { bottom: 0; content: ''; diff --git a/app/design/frontend/Magento/blank/etc/view.xml b/app/design/frontend/Magento/blank/etc/view.xml index f8383a602341b..90dc921d7674f 100644 --- a/app/design/frontend/Magento/blank/etc/view.xml +++ b/app/design/frontend/Magento/blank/etc/view.xml @@ -190,7 +190,7 @@ false true horizontal - true + true slides slide @@ -199,23 +199,19 @@ thumbs true - true - false - false - horizontal - 150 - 150 - true + false + false + horizontal + slides dissolve 500 - true - 5 + 20 diff --git a/app/design/frontend/Magento/luma/etc/view.xml b/app/design/frontend/Magento/luma/etc/view.xml index cbb6b24680943..41d513f3bb894 100644 --- a/app/design/frontend/Magento/luma/etc/view.xml +++ b/app/design/frontend/Magento/luma/etc/view.xml @@ -194,7 +194,7 @@ false true horizontal - true + true slides slide @@ -203,23 +203,20 @@ thumbs true - true - false - false - horizontal - 150 - 150 - true + true + false + horizontal + false + slides - dissolve + slide 500 - true - 5 + 20 @@ -254,6 +251,14 @@ 58 + + + true + + + true + + 1MB diff --git a/lib/web/fotorama/fotorama.js b/lib/web/fotorama/fotorama.js index bd91a76807915..f92fa7209abfe 100644 --- a/lib/web/fotorama/fotorama.js +++ b/lib/web/fotorama/fotorama.js @@ -86,10 +86,11 @@ fotoramaVersion = '4.6.4'; videoPlayClass = videoClass + '-play', videoCloseClass = videoClass + '-close', - spinnerClass = _fotoramaClass + '__spinner', horizontalImageClass = _fotoramaClass + '_horizontal_ratio', - verticalImageClass = _fotoramaClass + '_vertical_ratio'; + verticalImageClass = _fotoramaClass + '_vertical_ratio', + fotoramaSpinnerClass = _fotoramaClass + '__spinner', + spinnerShowClass = fotoramaSpinnerClass + '--show'; var JQUERY_VERSION = $ && $.fn.jquery.split('.'); if (!JQUERY_VERSION @@ -436,390 +437,6 @@ fotoramaVersion = '4.6.4'; return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen'](); }; } -//fgnass.github.com/spin.js#v1.3.2 - - /** - * Copyright (c) 2011-2013 Felix Gnass - * Licensed under the MIT license - */ - - var Spinner, - spinnerDefaults = { - lines: 12, // The number of lines to draw - length: 5, // The length of each line - width: 2, // The line thickness - radius: 7, // The radius of the inner circle - corners: 1, // Corner roundness (0..1) - rotate: 15, // The rotation offset - color: 'rgba(128, 128, 128, .75)', - hwaccel: true - }, - spinnerOverride = { - top: 'auto', - left: 'auto', - className: '' - }; - - (function (root, factory) { - - /* CommonJS */ - //if (typeof exports == 'object') module.exports = factory() - - /* AMD module */ - //else if (typeof define == 'function' && define.amd) define(factory) - - /* Browser global */ - //else root.Spinner = factory() - - Spinner = factory(); - } - (this, function () { - "use strict"; - - var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */ - , animations = {} /* Animation rules keyed by their name */ - , useCssAnimations - /* Whether to use CSS animations or setTimeout */ - - /** - * Utility function to create elements. If no tag name is given, - * a DIV is created. Optionally properties can be passed. - */ - function createEl(tag, prop) { - var el = document.createElement(tag || 'div') - , n - - for (n in prop) el[n] = prop[n] - return el - } - - /** - * Appends children and returns the parent. - */ - function ins(parent /* child1, child2, ...*/) { - for (var i = 1, n = arguments.length; i < n; i++) - parent.appendChild(arguments[i]) - - return parent - } - - /** - * Insert a new stylesheet to hold the @keyframe or VML rules. - */ - var sheet = (function () { - var el = createEl('style', {type: 'text/css'}) - ins(document.getElementsByTagName('head')[0], el) - return el.sheet || el.styleSheet - }()) - - /** - * Creates an opacity keyframe animation rule and returns its name. - * Since most mobile Webkits have timing issues with animation-delay, - * we create separate rules for each line/segment. - */ - function addAnimation(alpha, trail, i, lines) { - var name = ['opacity', trail, ~~(alpha * 100), i, lines].join('-') - , start = 0.01 + i / lines * 100 - , z = Math.max(1 - (1 - alpha) / trail * (100 - start), alpha) - , prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase() - , pre = prefix && '-' + prefix + '-' || '' - - if (!animations[name]) { - sheet.insertRule( - '@' + pre + 'keyframes ' + name + '{' + - '0%{opacity:' + z + '}' + - start + '%{opacity:' + alpha + '}' + - (start + 0.01) + '%{opacity:1}' + - (start + trail) % 100 + '%{opacity:' + alpha + '}' + - '100%{opacity:' + z + '}' + - '}', sheet.cssRules.length) - - animations[name] = 1 - } - - return name - } - - /** - * Tries various vendor prefixes and returns the first supported property. - */ - function vendor(el, prop) { - var s = el.style - , pp - , i - - prop = prop.charAt(0).toUpperCase() + prop.slice(1) - for (i = 0; i < prefixes.length; i++) { - pp = prefixes[i] + prop - if (s[pp] !== undefined) return pp - } - if (s[prop] !== undefined) return prop - } - - /** - * Sets multiple style properties at once. - */ - function css(el, prop) { - for (var n in prop) - el.style[vendor(el, n) || n] = prop[n] - - return el - } - - /** - * Fills in default values. - */ - function merge(obj) { - for (var i = 1; i < arguments.length; i++) { - var def = arguments[i] - for (var n in def) - if (obj[n] === undefined) obj[n] = def[n] - } - return obj - } - - /** - * Returns the absolute page-offset of the given element. - */ - function pos(el) { - var o = {x: el.offsetLeft, y: el.offsetTop} - while ((el = el.offsetParent)) - o.x += el.offsetLeft, o.y += el.offsetTop - - return o - } - - /** - * Returns the line color from the given string or array. - */ - function getColor(color, idx) { - return typeof color == 'string' ? color : color[idx % color.length] - } - - // Built-in defaults - - var defaults = { - lines: 12, // The number of lines to draw - length: 7, // The length of each line - width: 5, // The line thickness - radius: 10, // The radius of the inner circle - rotate: 0, // Rotation offset - corners: 1, // Roundness (0..1) - color: '#000', // #rgb or #rrggbb - direction: 1, // 1: clockwise, -1: counterclockwise - speed: 1, // Rounds per second - trail: 100, // Afterglow percentage - opacity: 1 / 4, // Opacity of the lines - fps: 20, // Frames per second when using setTimeout() - zIndex: 2e9, // Use a high z-index by default - className: 'spinner', // CSS class to assign to the element - top: 'auto', // center vertically - left: 'auto', // center horizontally - position: 'relative' // element position - } - - /** The constructor */ - function Spinner(o) { - if (typeof this == 'undefined') return new Spinner(o) - this.opts = merge(o || {}, Spinner.defaults, defaults) - } - - // Global defaults that override the built-ins: - Spinner.defaults = {} - - merge(Spinner.prototype, { - - /** - * Adds the spinner to the given target element. If this instance is already - * spinning, it is automatically removed from its previous target b calling - * stop() internally. - */ - spin: function (target) { - this.stop() - - var self = this - , o = self.opts - , el = self.el = css(createEl(0, {className: o.className}), { - position: o.position, - width: 0, - zIndex: o.zIndex - }) - , mid = o.radius + o.length + o.width - , ep // element position - , tp // target position - - if (target) { - target.insertBefore(el, target.firstChild || null) - tp = pos(target) - ep = pos(el) - css(el, { - left: (o.left == 'auto' ? tp.x - ep.x + (target.offsetWidth >> 1) : parseInt(o.left, 10) + mid) + 'px', - top: (o.top == 'auto' ? tp.y - ep.y + (target.offsetHeight >> 1) : parseInt(o.top, 10) + mid) + 'px' - }) - } - - el.setAttribute('role', 'progressbar') - self.lines(el, self.opts) - - if (!useCssAnimations) { - // No CSS animation support, use setTimeout() instead - var i = 0 - , start = (o.lines - 1) * (1 - o.direction) / 2 - , alpha - , fps = o.fps - , f = fps / o.speed - , ostep = (1 - o.opacity) / (f * o.trail / 100) - , astep = f / o.lines - - ; - (function anim() { - i++; - for (var j = 0; j < o.lines; j++) { - alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity) - - self.opacity(el, j * o.direction + start, alpha, o) - } - self.timeout = self.el && setTimeout(anim, ~~(1000 / fps)) - })() - } - return self - }, - - /** - * Stops and removes the Spinner. - */ - stop: function () { - var el = this.el - if (el) { - clearTimeout(this.timeout) - if (el.parentNode) el.parentNode.removeChild(el) - this.el = undefined - } - return this - }, - - /** - * Internal method that draws the individual lines. Will be overwritten - * in VML fallback mode below. - */ - lines: function (el, o) { - var i = 0 - , start = (o.lines - 1) * (1 - o.direction) / 2 - , seg - - function fill(color, shadow) { - return css(createEl(), { - position: 'absolute', - width: (o.length + o.width) + 'px', - height: o.width + 'px', - background: color, - boxShadow: shadow, - transformOrigin: 'left', - transform: 'rotate(' + ~~(360 / o.lines * i + o.rotate) + 'deg) translate(' + o.radius + 'px' + ',0)', - borderRadius: (o.corners * o.width >> 1) + 'px' - }) - } - - for (; i < o.lines; i++) { - seg = css(createEl(), { - position: 'absolute', - top: 1 + ~(o.width / 2) + 'px', - transform: o.hwaccel ? 'translate3d(0,0,0)' : '', - opacity: o.opacity, - animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1 / o.speed + 's linear infinite' - }) - - if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2 + 'px'})) - ins(el, ins(seg, fill(getColor(o.color, i), '0 0 1px rgba(0,0,0,.1)'))) - } - return el - }, - - /** - * Internal method that adjusts the opacity of a single line. - * Will be overwritten in VML fallback mode below. - */ - opacity: function (el, i, val) { - if (i < el.childNodes.length) el.childNodes[i].style.opacity = val - } - - }) - - - function initVML() { - - /* Utility function to create a VML tag */ - function vml(tag, attr) { - return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr) - } - - // No CSS transforms but VML support, add a CSS rule for VML elements: - sheet.addRule('.spin-vml', 'behavior:url(#default#VML)') - - Spinner.prototype.lines = function (el, o) { - var r = o.length + o.width - , s = 2 * r - - function grp() { - return css( - vml('group', { - coordsize: s + ' ' + s, - coordorigin: -r + ' ' + -r - }), - {width: s, height: s} - ) - } - - var margin = -(o.width + o.length) * 2 + 'px' - , g = css(grp(), {position: 'absolute', top: margin, left: margin}) - , i - - function seg(i, dx, filter) { - ins(g, - ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}), - ins(css(vml('roundrect', {arcsize: o.corners}), { - width: r, - height: o.width, - left: o.radius, - top: -o.width >> 1, - filter: filter - }), - vml('fill', {color: getColor(o.color, i), opacity: o.opacity}), - vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change - ) - ) - ) - } - - if (o.shadow) - for (i = 1; i <= o.lines; i++) - seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)') - - for (i = 1; i <= o.lines; i++) seg(i) - return ins(el, g) - } - - Spinner.prototype.opacity = function (el, i, val, o) { - var c = el.firstChild - o = o.shadow && o.lines || 0 - if (c && i + o < c.childNodes.length) { - c = c.childNodes[i + o]; - c = c && c.firstChild; - c = c && c.firstChild - if (c) c.opacity = val - } - } - } - - var probe = css(createEl('group'), {behavior: 'url(#default#VML)'}) - - if (!vendor(probe, 'transform') && probe.adj) initVML() - else useCssAnimations = vendor(probe, 'animation') - - return Spinner - - })); - /* Bez v1.0.10-g5ae0136 * http://github.com/rdallasgray/bez * @@ -1000,7 +617,7 @@ fotoramaVersion = '4.6.4'; direction: 'ltr', // 'rtl' shadows: true, - spinner: null, + showcaption: true, /** @@ -1023,8 +640,8 @@ fotoramaVersion = '4.6.4'; KEYBOARD_OPTIONS = { left: true, right: true, - down: false, - up: false, + down: true, + up: true, space: false, home: false, end: false @@ -1574,8 +1191,13 @@ fotoramaVersion = '4.6.4'; return !!el.getAttribute('disabled'); } - function disableAttr(FLAG) { - return {tabindex: FLAG * -1 + '', disabled: FLAG}; + function disableAttr(FLAG, disable) { + if (disable) { + return {disabled: FLAG}; + } else { + return {tabindex: FLAG * -1 + '', disabled: FLAG}; + + } } function addEnterUp(el, fn) { @@ -1746,8 +1368,8 @@ fotoramaVersion = '4.6.4'; function extendEvent(e) { var touch = (e.touches || [])[0] || e; - e._x = touch.pageX; - e._y = touch.clientY; + e._x = touch.pageX || touch.originalEvent.pageX; + e._y = touch.clientY || touch.originalEvent.clientY; e._now = $.now(); } @@ -1811,14 +1433,8 @@ fotoramaVersion = '4.6.4'; xWin = (tail.go || tail.x || xyDiff >= 0) && !tail.noSwipe, yWin = xyDiff < 0; - if (touchFLAG && !tail.checked) { - if (touchEnabledFLAG = xWin) { - stopEvent(e); - } - } else { - stopEvent(e); - (options.onMove || noop).call(el, e, {touch: touchFLAG}); - } + stopEvent(e); + (options.onMove || noop).call(el, e, {touch: touchFLAG}); if (!moved && Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) > tolerance) { moved = true; @@ -1859,16 +1475,12 @@ fotoramaVersion = '4.6.4'; function onOtherStart() { if (tail.flow) return; - setTimeout(function () { - tail.flow = true; - }, 10); + tail.flow = true; } function onOtherEnd() { if (!tail.flow) return; - setTimeout(function () { - tail.flow = false; - }, TOUCH_TIMEOUT); + tail.flow = false; } if (MS_POINTER) { @@ -1887,10 +1499,10 @@ fotoramaVersion = '4.6.4'; $WINDOW.on('scroll', onOtherEnd); - $el.on('mousedown', onStart); + $el.on('mousedown pointerdown', onStart); $DOCUMENT - .on('mousemove', onMove) - .on('mouseup', onEnd); + .on('mousemove pointermove', onMove) + .on('mouseup pointerup', onEnd); } if (Modernizr.touch) { dragDomEl = 'a'; @@ -2169,8 +1781,7 @@ fotoramaVersion = '4.6.4'; $videoClose = $fotorama.find(cls(videoCloseClass)), videoClose = $videoClose[0], - spinner, - $spinner = $(div(spinnerClass)), + $spinner = $fotorama.find(cls(fotoramaSpinnerClass)), $videoPlaying, @@ -2267,7 +1878,7 @@ fotoramaVersion = '4.6.4'; } function allowKey(key) { - return o_keyboard[key] || that.fullScreen; + return o_keyboard[key]; } function setStagePosition() { @@ -2312,10 +1923,10 @@ fotoramaVersion = '4.6.4'; if (e.keyCode === 27) { catched = true; that.cancelFullScreen(); - } else if ((e.shiftKey && e.keyCode === 32 && allowKey('space')) || (e.keyCode === 37 && allowKey('left')) || (e.keyCode === 38 && allowKey('up'))) { + } else if ((e.shiftKey && e.keyCode === 32 && allowKey('space')) || (e.keyCode === 37 && allowKey('left')) || (e.keyCode === 38 && allowKey('up') && $(':focus').attr('data-gallery-role'))) { that.longPress.progress(); index = '<'; - } else if ((e.keyCode === 32 && allowKey('space')) || (e.keyCode === 39 && allowKey('right')) || (e.keyCode === 40 && allowKey('down'))) { + } else if ((e.keyCode === 32 && allowKey('space')) || (e.keyCode === 39 && allowKey('right')) || (e.keyCode === 40 && allowKey('down') && $(':focus').attr('data-gallery-role'))) { that.longPress.progress(); index = '>'; } else if (e.keyCode === 36 && allowKey('home')) { @@ -2338,7 +1949,7 @@ fotoramaVersion = '4.6.4'; $DOCUMENT .on(keyupLocal, function (e) { if (that.longPress.inProgress) { - that.showEndLongPress({user:true}); + that.showEndLongPress({user: true}); } that.longPress.reset(); }); @@ -2465,9 +2076,6 @@ fotoramaVersion = '4.6.4'; $arrs.hide(); } - spinnerStop(); - spinner = new Spinner($.extend(spinnerDefaults, opts.spinner, spinnerOverride, {direction: o_rtl ? -1 : 1})); - arrsUpdate(); stageWheelUpdate(); thumbArrUpdate(); @@ -2545,7 +2153,7 @@ fotoramaVersion = '4.6.4'; addOrRemoveClass(!o_fade, wrapSlideClass); addOrRemoveClass(!opts.captions, wrapNoCaptionsClass); addOrRemoveClass(o_rtl, wrapRtlClass); - addOrRemoveClass(opts.arrows !== 'always', wrapToggleArrowsClass); + addOrRemoveClass(opts.arrows, wrapToggleArrowsClass); o_shadows = opts.shadows && !SLOW; addOrRemoveClass(!o_shadows, wrapNoShadowsClass); @@ -2628,11 +2236,12 @@ fotoramaVersion = '4.6.4'; } function loadImg(indexes, type, specialMeasures, again) { + eachIndex(indexes, type, function (i, index, dataFrame, $frame, key, frameData) { if (!$frame) return; - var fullFLAG = that.fullScreen && dataFrame.full && dataFrame.full !== dataFrame.img && !frameData.$full && type === 'stage'; + var fullFLAG = that.fullScreen && !frameData.$full && type === 'stage'; if (frameData.$img && !again && !fullFLAG) return; @@ -2644,7 +2253,7 @@ fotoramaVersion = '4.6.4'; var srcKey = type === 'stage' ? (fullFLAG ? 'full' : 'img') : 'thumb', src = dataFrame[srcKey], - dummy = fullFLAG ? null : dataFrame[type === 'stage' ? 'thumb' : 'img']; + dummy = fullFLAG ? dataFrame['img'] : dataFrame[type === 'stage' ? 'thumb' : 'img']; if (type === 'navThumb') $frame = frameData.$wrap; @@ -2664,6 +2273,7 @@ fotoramaVersion = '4.6.4'; if ((!dataFrame.html || type !== 'stage') && dummy && dummy !== src) { dataFrame[srcKey] = src = dummy; + frameData.$full = null; loadImg([index], type, specialMeasures, true); } else { if (src && !dataFrame.html && !fullFLAG) { @@ -2703,7 +2313,8 @@ fotoramaVersion = '4.6.4'; $img .off('load error') - .addClass(imgClass + (fullFLAG ? ' ' + imgFullClass : '')) + .addClass('' + (fullFLAG ? imgFullClass: imgClass)) + .attr('aria-hidden', 'false') .prependTo($frame); if ($frame.hasClass(stageFrameClass) && !$frame.hasClass(videoContainerClass)) { @@ -2770,29 +2381,24 @@ fotoramaVersion = '4.6.4'; img.alt = frameData.data.caption || ""; } + if (frameData.data.full) { + $(img).data('original', frameData.data.full); + } + if (UTIL.isExpectedCaption(dataFrame, opts.showcaption)) { $(img).attr('aria-labelledby', dataFrame.labelledby); } }); } - function spinnerSpin($el) { - $spinner.append(spinner.spin().el).appendTo($el); - } - - function spinnerStop() { - $spinner.detach(); - spinner && spinner.stop(); - } - function updateFotoramaState() { var $frame = activeFrame[STAGE_FRAME_KEY]; if ($frame && !$frame.data().state) { - spinnerSpin($frame); + $spinner.addClass(spinnerShowClass); $frame.on('f:load f:error', function () { $frame.off('f:load f:error'); - spinnerStop(); + $spinner.removeClass(spinnerShowClass); }); } } @@ -3004,10 +2610,10 @@ fotoramaVersion = '4.6.4'; disableNext = disableDirrection(1); $arrPrev .toggleClass(arrDisabledClass, disablePrev) - .attr(disableAttr(disablePrev)); + .attr(disableAttr(disablePrev, false)); $arrNext .toggleClass(arrDisabledClass, disableNext) - .attr(disableAttr(disableNext)); + .attr(disableAttr(disableNext, false)); } function thumbArrUpdate() { @@ -3024,10 +2630,10 @@ fotoramaVersion = '4.6.4'; } $thumbArrLeft .toggleClass(arrDisabledClass, isLeftDisable) - .attr(disableAttr(isLeftDisable)); + .attr(disableAttr(isLeftDisable, true)); $thumbArrRight .toggleClass(arrDisabledClass, isRightDisable) - .attr(disableAttr(isRightDisable)); + .attr(disableAttr(isRightDisable, true)); } function stageWheelUpdate() { @@ -3183,7 +2789,7 @@ fotoramaVersion = '4.6.4'; addEnterUp($stageShaft[0], function () { if (!$fotorama.hasClass(fullscreenClass)) { that.requestFullScreen(); - $(fullscreenIcon).trigger('focus'); + $fullscreenIcon.focus(); } }); } @@ -3325,14 +2931,13 @@ fotoramaVersion = '4.6.4'; }; that.showWhileLongPress = function (options) { - if (that.longPress.singlePressInProgress) - { + if (that.longPress.singlePressInProgress) { return; } var index = calcActiveIndex(options); calcGlobalIndexes(index); - var time = calcTime(options)/50; + var time = calcTime(options) / 50; var _activeFrame = activeFrame; that.activeFrame = activeFrame = data[activeIndex]; var silent = _activeFrame === activeFrame && !options.user; @@ -3343,14 +2948,13 @@ fotoramaVersion = '4.6.4'; }; that.showEndLongPress = function (options) { - if (that.longPress.singlePressInProgress) - { + if (that.longPress.singlePressInProgress) { return; } var index = calcActiveIndex(options); calcGlobalIndexes(index); - var time = calcTime(options)/50; + var time = calcTime(options) / 50; var _activeFrame = activeFrame; that.activeFrame = activeFrame = data[activeIndex]; @@ -3444,6 +3048,14 @@ fotoramaVersion = '4.6.4'; stageCursor(); releaseAutoplay(); changeAutoplay(); + + if (that.fullScreen) { + activeFrame[STAGE_FRAME_KEY].find('.' + imgFullClass).attr('aria-hidden', false); + activeFrame[STAGE_FRAME_KEY].find('.' + imgClass).attr('aria-hidden', true) + } else { + activeFrame[STAGE_FRAME_KEY].find('.' + imgFullClass).attr('aria-hidden', true); + activeFrame[STAGE_FRAME_KEY].find('.' + imgClass).attr('aria-hidden', false) + } }; if (!o_fade) { @@ -3539,8 +3151,11 @@ fotoramaVersion = '4.6.4'; that.resize(); loadImg(activeIndexes, 'stage'); updateFotoramaState(); - triggerEvent('fullscreenenter'); + + if (!('ontouchstart' in window)) { + $fullscreenIcon.focus(); + } } return this; @@ -3590,12 +3205,6 @@ fotoramaVersion = '4.6.4'; 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; @@ -3622,13 +3231,15 @@ fotoramaVersion = '4.6.4'; $wrap.css({height: ''}); $stage.css({width: ''}); $stage.css({height: ''}); - $stage.css({'line-height': ''}); $stageShaft.css({width: ''}); $stageShaft.css({height: ''}); $nav.css({width: ''}); $nav.css({height: ''}); $wrap.css({minWidth: measures.minwidth || 0, maxWidth: measures.maxwidth || MAX_WIDTH}); + if (o_nav === 'dots') { + $navWrap.hide(); + } width = measures.W = measures.w = $wrap.width(); measures.nw = o_nav && numberFromWhatever(opts.navwidth, width) || width; @@ -3641,7 +3252,7 @@ fotoramaVersion = '4.6.4'; if (height) { width = Math.round(width); height = measures.h = Math.round(minMaxLimit(height, numberFromWhatever(measures.minheight, windowHeight), numberFromWhatever(measures.maxheight, windowHeight))); - $stage.css({'width': width, 'height': height, 'line-height': height + 'px'}); + $stage.css({'width': width, 'height': height}); if (opts.navdir === 'vertical' && !that.fullscreen) { $nav.width(opts.thumbwidth + opts.thumbmargin * 2); @@ -3651,12 +3262,18 @@ fotoramaVersion = '4.6.4'; $nav.height(opts.thumbheight + opts.thumbmargin * 2); } + if (o_nav === 'dots') { + $nav.width(width) + .height('auto'); + $navWrap.show(); + } + if (opts.navdir === 'vertical' && that.fullScreen) { - $stage.css('height', $(window).height()); + $stage.css('height', $WINDOW.height()); } if (opts.navdir === 'horizontal' && that.fullScreen) { - $stage.css('height', $(window).height() - (opts.thumbheight + opts.thumbmargin * 2)); + $stage.css('height', $WINDOW.height() - $nav.height()); } if (o_nav) { @@ -3799,6 +3416,18 @@ fotoramaVersion = '4.6.4'; return this; }; + that.spliceByIndex = function (index, newImgObj) { + newImgObj.i = index + 1; + newImgObj.img && $.ajax({ + url: newImgObj.img, + type: 'HEAD', + success: function () { + data.splice(index, 1, newImgObj); + reset(); + } + }); + }; + function unloadVideo($video, unloadActiveFLAG, releaseAutoplayFLAG) { if (unloadActiveFLAG) { $wrap.removeClass(wrapVideoClass); @@ -3867,17 +3496,8 @@ fotoramaVersion = '4.6.4'; that.toggleFullScreen(); } else if ($videoPlaying) { target === videoClose && unloadVideo($videoPlaying, true, true); - } else { - if (toggleControlsFLAG) { - toggleControlsClass(); - } else if (opts.click) { - - clickToShow({ - index: e.shiftKey || getDirectionSign(getDirection(e._x)), - slow: e.altKey, - user: true - }); - } + } else if (!$fotorama.hasClass(fullscreenClass)) { + that.requestFullScreen(); } } @@ -3896,11 +3516,11 @@ fotoramaVersion = '4.6.4'; setShadow($stage); toggleControlsFLAG = (MS_POINTER && !hoverFLAG || result.touch) && - opts.arrows && opts.arrows !== 'always'; + opts.arrows; if ((result.moved || (toggleControlsFLAG && result.pos !== result.newPos && !result.control)) && result.$target[0] !== $fullscreenIcon[0]) { var index = getIndexByPos(result.newPos, measures.w, opts.margin, repositionIndex); - + that.show({ index: index, time: o_fade ? o_transitionDuration : result.time, @@ -4063,8 +3683,14 @@ fotoramaVersion = '4.6.4'; }); addEnterUp(fullscreenIcon, function () { - that.toggleFullScreen(); - $(fullscreenIcon).trigger('focus'); + if ($fotorama.hasClass(fullscreenClass)) { + that.cancelFullScreen(); + $stageShaft.focus(); + } else { + that.requestFullScreen(); + $fullscreenIcon.focus(); + } + }); addFocusOnControls(fullscreenIcon); @@ -4225,3 +3851,4 @@ fotoramaVersion = '4.6.4'; return __p }; })(window, document, location, typeof jQuery !== 'undefined' && jQuery); + diff --git a/lib/web/mage/gallery/gallery.html b/lib/web/mage/gallery/gallery.html index 005d75efaa5ea..73f7533d56f01 100644 --- a/lib/web/mage/gallery/gallery.html +++ b/lib/web/mage/gallery/gallery.html @@ -4,38 +4,39 @@ * See COPYING.txt for license details. */ --> -
-
+
+
-
-
-
+
+
+
-
+ aria-label="Next" data-gallery-role="arrow"> +
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
+
diff --git a/lib/web/mage/gallery/gallery.js b/lib/web/mage/gallery/gallery.js index 7e3a1e0259b22..deea19a4b5109 100644 --- a/lib/web/mage/gallery/gallery.js +++ b/lib/web/mage/gallery/gallery.js @@ -59,6 +59,17 @@ define([ }); return slideTransform.filter(Boolean); + }, + + _toNumber = function (str) { + + var type = typeof(str); + + if (type === 'string') { + return parseInt(str); + } else { + return str; + } }; return Class.extend({ @@ -91,6 +102,20 @@ define([ '_focusSwitcher' ); + /*turn off arrows for touch devices*/ + if (this.isTouchEnabled) { + config.options.arrows = false; + + if (config.fullscreen) { + config.fullscreen.arrows = false; + } + } + + config.options.width = _toNumber(config.options.width); + config.options.height = _toNumber(config.options.height); + config.options.thumbwidth = _toNumber(config.options.thumbwidth); + config.options.thumbheight = _toNumber(config.options.thumbheight); + config.options.swipe = true; this.config = config; @@ -165,29 +190,36 @@ define([ settings.fullscreenConfig.swipe = true; settings.$gallery.on('fotorama:fullscreenenter', function () { - settings.$gallery.focus(); + settings.closeIcon.show(); + settings.focusableStart.attr('tabindex', '0'); + settings.focusableEnd.attr('tabindex', '0'); settings.focusableStart.bind('focusin', self._focusSwitcher); settings.focusableEnd.bind('focusin', self._focusSwitcher); settings.api.updateOptions(settings.defaultConfig.options, true); settings.api.updateOptions(settings.fullscreenConfig, true); - if (!_.isEqual(settings.activeBreakpoint, {})) { + if (!_.isEqual(settings.activeBreakpoint, {}) && settings.breakpoints) { settings.api.updateOptions(settings.activeBreakpoint.options, true); } settings.isFullscreen = true; }); settings.$gallery.on('fotorama:fullscreenexit', function () { - settings.$pageWrapper.show(); + settings.closeIcon.hide(); + settings.focusableStart.attr('tabindex', '-1'); + settings.focusableEnd.attr('tabindex', '-1'); settings.api.updateOptions(settings.defaultConfig.options, true); settings.focusableStart.unbind('focusin', this._focusSwitcher); settings.focusableEnd.unbind('focusin', this._focusSwitcher); + settings.closeIcon.hide(); - if (!_.isEqual(settings.activeBreakpoint, {})) { + if (!_.isEqual(settings.activeBreakpoint, {}) && settings.breakpoints) { settings.api.updateOptions(settings.activeBreakpoint.options, true); } settings.isFullscreen = false; - settings.$fullscreenIcon.hide(); + settings.$element.data('gallery').updateOptions({ + swipe: true + }); }); }, @@ -222,7 +254,7 @@ define([ if (position === 'end') { settings.$gallery.find(settings.closeIcon).focus(); } else if (position === 'start') { - infelicity = 2; //Constant for find last focusable element + infelicity = 3; //Constant for find last focusable element focusableElements = settings.$gallery.find(':focusable'); focusableElements.eq(focusableElements.length - infelicity).focus(); } @@ -256,10 +288,6 @@ define([ _.extend(config, config.options); config.options = undefined; - if (this.isTouchEnabled) { - config.arrows = false; - } - config.click = false; config.breakpoints = null; settings.currentConfig = config; @@ -278,7 +306,9 @@ define([ var pairs, settings = this.settings, config = this.config, - startConfig = this.startConfig; + startConfig = this.startConfig, + triggeredBreakpoints = 0, + isTouchEnabled = this.isTouchEnabled; if (_.isObject(settings.breakpoints)) { pairs = _.pairs(settings.breakpoints); @@ -297,6 +327,14 @@ define([ if (settings.isFullscreen) { settings.api.updateOptions(settings.fullscreenConfig, true); } + + if (isTouchEnabled) { + settings.breakpoints[pair[0]].options.arrows = false; + if (settings.breakpoints[pair[0]].options.fullscreen) { + settings.breakpoints[pair[0]].options.fullscreen.arrows = false; + } + } + settings.api.updateOptions(settings.breakpoints[pair[0]].options, true); $.extend(true, config, settings.breakpoints[pair[0]]); settings.activeBreakpoint = settings.breakpoints[pair[0]]; @@ -380,7 +418,24 @@ define([ * @param {Boolean} isInternal - Is this function called via breakpoints. */ updateOptions: function (configuration, isInternal) { + + var $selectable = + $('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]') + .not('[tabindex=-1], [disabled], :hidden'), + fotorama = settings.fotoramaApi, + $focus = $(':focus'), + index; + if (_.isObject(configuration)) { + + //Saves index of focus + $selectable.each(function (number) { + + if ($(this).is($focus)) { + index = number; + } + }); + if (this.isTouchEnabled) { configuration.arrows = false; } @@ -388,7 +443,7 @@ define([ configuration.breakpoints = null; if (!isInternal) { - !_.isEqual(settings.activeBreakpoint, {}) ? + !_.isEqual(settings.activeBreakpoint, {} && settings.brekpoints) ? $.extend(true, settings.activeBreakpoint.options, configuration) : settings.isFullscreen ? @@ -398,6 +453,10 @@ define([ } $.extend(true, settings.currentConfig.options, configuration); settings.fotoramaApi.setOptions(settings.currentConfig.options); + + if (_.isNumber(index)) { + $selectable.eq(index).focus(); + } } }, @@ -429,10 +488,19 @@ define([ var images = []; _.each(this.fotorama.data, function (item) { - images.push(_.omit(item, '$navThumbFrame', '$navDotFrame', '$stageFrame')); + images.push(_.omit(item, '$navThumbFrame', '$navDotFrame', '$stageFrame', 'labelledby')); }); return images; + }, + /** + * Updates gallery data partially by index + * @param {Number} index - Index of image in data array to be updated. + * @param {Object} item - Standart gallery image object. + * + */ + updateDataByIndex: function(index, item){ + settings.fotoramaApi.spliceByIndex(index, item); } }; diff --git a/lib/web/mage/gallery/gallery.less b/lib/web/mage/gallery/gallery.less index 351bcc707454d..4b7f3a62d028a 100644 --- a/lib/web/mage/gallery/gallery.less +++ b/lib/web/mage/gallery/gallery.less @@ -3,309 +3,26 @@ // * See COPYING.txt for license details. // */ -@fotorama-duration-time: 0.3s; -@fotorama-arw-size: 95px; -@fotorama_close_size: 30px; -@size-fotorama-block: 50px; -@fotorama-thumb-arrow: 30px; - +@import 'module/_variables.less'; //Default gallery variables @import '../../css/source/lib/_lib.less'; // Global lib @import '../../css/source/_theme.less'; // Theme overrides @import '../../css/source/_variables.less'; // Local theme variables @import '../../css/source/lib/_responsive.less'; - - -.fotorama-translate3d(@x; @y; @z) { - -webkit-transform: translate3d(@x, @y, @z); - transform: translate3d(@x, @y, @z); -} - -.fotorama-rotate (@deg) { - -webkit-transform: rotate(@deg); - -ms-transform: rotate(@deg); - transform: rotate(@deg); -} - -.translateX(@value) { - -webkit-transform: translateX(@value); - -ms-transform: translateX(@value); - -o-transform: translateX(@value); - transform: translateX(@value); -} - -.translateY(@value) { - -webkit-transform: translateY(@value); - -ms-transform: translateY(@value); - -o-transform: translateY(@value); - transform: translateY(@value); -} - -.fotorama-shadow-gradient(@x, @y) { - background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.2) 25%, rgba(0, 0, 0, 0.3) 75%, transparent), radial-gradient(farthest-side at @x @y, rgba(0, 0, 0, 0.4), transparent); -} - -.fotorama-arrow-gradient(@d){ - background-image: -webkit-linear-gradient(@d, rgba(255, 255, 255, .7), rgba(255, 255, 255, 0)); - background-image: -ms-linear-gradient(@d, rgba(255, 255, 255, .7), rgba(255, 255, 255, 0)); - background-image: linear-gradient(@d, rgba(255, 255, 255, .7), rgba(255, 255, 255, 0)); -} - -.fotorama-inline-block(@va: middle) { - *display: inline; - *zoom: 1; - -moz-box-orient: vertical; - display: -moz-inline-box; - display: inline-block; - vertical-align: @va; -} - -.fotorama__zoom-in, -.fotorama__zoom-out { - display: none; -} - -.fotorama__fullscreen { - .fotorama__zoom-in, - .fotorama__zoom-out { - display: block; - height: 50px; - margin-left: 20px; - position: absolute; - width: 50px; - z-index: 1000; - } - - .fotorama__zoom-out { - top: 51px; - &:extend(.fotorama-sprite); - - background-position: 0 (-@size-fotorama-block) !important; - } - - .fotorama__zoom-in { - top: 0; - &:extend(.fotorama-sprite); - background-position: 0 0 !important; - } -} - -.fotorama__zoom-in, -.fotorama__zoom-out { - display: none; -} -.fotorama__fullscreen { - .fotorama__zoom-in, - .fotorama__zoom-out { - cursor: pointer; - display: block; - height: 50px; - margin-left: 20px; - position: absolute; - width: 50px; - } - .fotorama__zoom-out { - top: 51px; - &:extend(.fotorama-sprite); - background-position: 0 (-@size-fotorama-block) !important; - } - - .fotorama__zoom-in { - top: 0; - &:extend(.fotorama-sprite); - background-position: 0 0 !important; - } -} +@import 'module/_mixins.less'; //Mixins in gallery +@import 'module/_extends.less'; +@import 'module/_focus.less'; +@import 'module/_fullscreen.less'; .fotorama__zoom-in, .fotorama__zoom-out { display: none; } -.fotorama__fullscreen { - .fotorama__zoom-in, - .fotorama__zoom-out { - cursor: pointer; - display: block; - height: 50px; - margin-left: 20px; - position: absolute; - width: 50px; - } - .fotorama__zoom-out { - top: 51px; - &:extend(.fotorama-sprite); - background-position: 0 (-@size-fotorama-block) !important; - } - - .fotorama__zoom-in { - top: 0; - &:extend(.fotorama-sprite); - background-position: 0 0 !important; - } -} - -.fotorama-stretch { - bottom: 0; - height: 100%; - left: 0; - position: absolute; - right: 0; - top: 0; - width: 100%; -} - -.fotorama-grab-cursor { - cursor: move; - cursor: -webkit-grab; - cursor: -moz-grab; - cursor: -o-grab; - cursor: -ms-grab; - cursor: grab; -} - -.fotorama-grabbing-cursor { - cursor: move; - cursor: -webkit-grabbing; - cursor: -moz-grabbing; - cursor: -o-grabbing; - cursor: -ms-grabbing; - cursor: grabbing; -} - -.fotorama-gpu { - transform: translateZ(0); -} - -.fotorama-focus { - outline: 0; -} - -.fotorama-focus-overlay { - &:after { - &:extend(.fotorama-stretch); - background-color: @color-blue2; - border-radius: inherit; - content: ''; - } -} - -.fotorama__arr:focus:after, -.fotorama__fullscreen-icon:focus:after, -.fotorama__nav__frame:focus .fotorama__dot:after, -.fotorama__nav__frame:focus .fotorama__thumb:after, -.fotorama__stage__shaft:focus .fotorama__stage__frame.fotorama__active:after { - background-color: rgba(0, 175, 234, .5); - border-radius: inherit; - content: ''; - height: 100%; - position: absolute; - left:0; - width: 100%; -} - -.fotorama-transform-disabled { - transform: none !important; -} - -.fotorama-transition-for-slide { - transition-duration: 0ms; - transition-property: transform, width; - transition-timing-function: cubic-bezier(0.1, 0, 0.25, 1); -} - -.fotorama-no-select { - user-select: none; -} - -.fotorama-select { - user-select: text; -} - -.fotorama-empty-bg { - background: url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=); -} - -.fotorama-auto-margin { - margin: auto; - padding: 0; -} - -.fotorama-inline-block { - .fotorama-inline-block(); -} - -.fotorama-content-box { - box-sizing: content-box; -} - -.fotorama-border-box { - box-sizing: border-box; -} - -.fotorama-hidden { - left: -99999px; - position: absolute; - top: -99999px; - z-index: -@z-index-10; -} - -.fotorama-visible { - left: auto; - opacity: 1; - position: relative; - top: auto; - z-index: auto; -} - -.fotorama-no-tap { - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -.transitionDuration { - transition-duration: 333ms; -} - -.transitionDurationZero { - transition-duration: 0ms; -} - -.fotorama-sprite { - &:extend(.fotorama-print-background); - background: url('gallery.png') no-repeat; - //@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 2dppx) { - // background: url('fotorama@2x.png') no-repeat; - //} -} - -.fotorama-print-background { - @media print { - background: none !important; - } -} - .fotorama { min-width: 1px; overflow: hidden; } -.fotorama--fullscreen { - background: @color-white; - bottom: 0 !important; - float: none !important; - height: 100% !important; - left: 0 !important; - margin: 0 !important; - position: absolute !important; - right: 0 !important; - top: 0 !important; - width: 100% !important; - z-index: @z-index-10 !important; - - .fotorama__wrap { - max-width: 100% !important; - } -} - .fotorama__wrap { &:extend(.fotorama-no-select); -webkit-text-size-adjust: 100%; @@ -361,7 +78,6 @@ &:extend(.fotorama-no-tap); &:extend(.fotorama-stretch); overflow: hidden; - &.fotorama__active { z-index: 8; } @@ -371,7 +87,6 @@ .fotorama__stage__frame { display: none; } - .fotorama__stage__frame.fotorama__active, .fotorama__fade-front, .fotorama__fade-rear { @@ -379,19 +94,15 @@ left: 0; top: 0; } - .fotorama__fade-front { z-index: 8; } - .fotorama__fade-rear { z-index: 7; - &.fotorama__active { z-index: 9; } } - .fotorama__stage .fotorama__shadow { display: none; } @@ -401,7 +112,6 @@ border: none !important; max-width: inherit; opacity: 0; - .fotorama__loaded &, .fotorama__error & { opacity: 1; @@ -412,16 +122,6 @@ display: none; } -.fotorama--fullscreen .fotorama__loaded--full { - .fotorama__img { - display: none; - } - - .fotorama__img--full { - display: block; - } -} - .fotorama__html { &:extend(.fotorama-stretch); } @@ -457,12 +157,10 @@ .fotorama__nav--dots { display: block; text-align: center; - .fotorama__nav__frame { height: 30px; width: 18px; } - .fotorama__nav__frame--thumb, .fotorama__thumb-border { display: none; @@ -471,15 +169,12 @@ .fotorama__nav--thumbs { display: block; - .fotorama__nav__frame { padding-left: 0 !important; - &:last-child { padding-right: 0 !important; } } - .fotorama__nav__frame--dot { display: none; } @@ -497,7 +192,6 @@ border-width: 3px; height: 0; width: 0; - &:after { left: -3px; padding: 3px; @@ -509,11 +203,10 @@ .fotorama__nav__frame:focus & { &:extend(.fotorama-focus-overlay); box-shadow: none; - &:after { - top: -1px; left: -1px; padding: 1px; + top: -1px; } } @@ -534,8 +227,6 @@ overflow: hidden; position: relative; width: 100%; - cursor: pointer; - .fotorama__nav__frame:focus & { &:extend(.fotorama-focus-overlay); z-index: 2; @@ -564,16 +255,14 @@ position: absolute; right: 0; z-index: 12; - a { border-bottom: 1px solid; border-color: fade(@color-black, 0.5); color: @color-black; text-decoration: none; - &:hover { - color: @color-black; border-color: fade(@color-black, 0.5); + color: @color-black; } } @@ -618,18 +307,15 @@ .fotorama__thumb-border { &:extend(.fotorama-transition-for-slide); } - .fotorama__spinner { &:extend(.fotorama-gpu); animation: spinner 24s infinite linear; } - .fotorama__stage, .fotorama__nav, .fotorama__stage__frame { &:extend(.fotorama-gpu); } - .fotorama__html { &:extend(.fotorama-gpu); transition-duration: @fotorama-duration-time; @@ -644,7 +330,6 @@ .fotorama__stage__frame--video { &:extend(.fotorama-transform-disabled); } - .fotorama__stage__frame--video { .fotorama__img, .fotorama__html { @@ -674,7 +359,6 @@ right: 0; top: 32px; z-index: 10; - iframe { &:extend(.fotorama-stretch); } @@ -700,6 +384,8 @@ } .fotorama__fullscreen-icon, +.fotorama__zoom-out, +.fotorama__zoom-in, .fotorama__video-close { z-index: @z-index-10; } @@ -707,11 +393,9 @@ .fotorama__arr { &:extend(.fotorama-border-box); bottom: 0; - margin-top: -(@fotorama-arw-size / 2); position: absolute; - top: 47px; + top: 0; width: @fotorama-arw-size; - .fotorama__arr__arr { &:extend(.fotorama-sprite); .fotorama-abs-center(); @@ -726,7 +410,6 @@ .fotorama__arr--prev { left: 0; - .fotorama__arr__arr { background-position: -@size-fotorama-block -@size-fotorama-block; } @@ -734,7 +417,6 @@ .fotorama__arr--next { right: 0; - .fotorama__arr__arr { background-position: (-@size-fotorama-block*2) (-@size-fotorama-block); } @@ -750,27 +432,32 @@ .fotorama__fullscreen-icon { &:extend(.fotorama-sprite); background-position: 0 0; + display: none; height: @size-fotorama-block; - right: 2px; - top: 2px; + right: 0; + top: 0; width: @size-fotorama-block; z-index: @z-index-10; - display: none; } -.fotorama__fullscreen-icon { - //display: none; +.fotorama--fullscreen-icons { + .fotorama__fullscreen-icon { + display: none; + } +} + +.fotorama__fullscreen-icon, +.fotorama__zoom-out, +.fotorama__zoom-in { &:focus { &:extend(.fotorama-focus); - border-radius: 50%; - } } .fotorama--fullscreen { .fotorama__fullscreen-icon { - //display: inline-block; background-position: (-@size-fotorama-block) 0; + display: inline-block; } } @@ -800,41 +487,10 @@ } } -.fotorama__video-close { - &:extend(.fotorama-sprite); - background-position: -60px -9px; - height: @fotorama_close_size; - opacity: 0; - right: 0; - top: 0; - width: @fotorama_close_size; - z-index: 19; - - .fotorama__wrap--css2 & { - display: none; - } - - .fotorama__wrap--css3 & { - .fotorama-translate3d(@fotorama-arw-size, -@fotorama-arw-size, 0); - } - - .fotorama__wrap--video & { - display: block; - opacity: 1; - } - - .fotorama__wrap--css3 { - &.fotorama__wrap--video & { - transform: translate3d(0, 0, 0); - } - } -} - .fotorama__wrap--no-controls.fotorama__wrap--toggle-arrows { .fotorama__arr, .fotorama__fullscreen-icon { opacity: 0; - &:focus { opacity: 1; } @@ -852,9 +508,9 @@ .fotorama__wrap--toggle-arrows { &.fotorama__wrap--video { .fotorama__video-close { - top: 97px; - right: 93px; opacity: 1; + right: 93px; + top: 97px; } } } @@ -870,9 +526,9 @@ .fotorama__wrap--toggle-arrows { &.fotorama__wrap--video { .fotorama__video-close { - top: 97px; - right: 93px; opacity: 1; + right: 93px; + top: 97px; } } } @@ -888,9 +544,9 @@ .fotorama__wrap--toggle-arrows { &.fotorama__wrap--video { .fotorama__video-close { - top: 97px; - right: 93px; opacity: 1; + right: 93px; + top: 97px; } } } @@ -907,7 +563,6 @@ .fotorama__arr, .fotorama__fullscreen-icon { display: none; - &:focus { display: block; } @@ -952,7 +607,7 @@ .fotorama__video-play:not(:focus), .fotorama__video-close:not(:focus) { transition-duration: @fotorama-duration-time; - transition-property: transform, opacity; + transition-property: transform, opacity, background-color; } } @@ -969,35 +624,30 @@ text-decoration: none; z-index: 10; } - &:before { left: -10px; top: -10px; } - &:after { right: -10px; bottom: -10px; } - &.fotorama__shadows--left:before, &.fotorama__shadows--right:after { - top: 0; - bottom: 0; background-size: 1px 100%, 5px 100%; + bottom: 0; height: auto; + top: 0; width: 10px; } - &.fotorama__shadows--top:before, &.fotorama__shadows--bottom:after { - left: 0; - right: 0; background-size: 100% 1px, 100% 5px ; height:10px; + left: 0; + right:0; width:auto; } - &.fotorama__shadows--left:before { .fotorama-shadow-gradient(0, 50%); background-position: 0 0, 0 0; @@ -1009,13 +659,12 @@ background-position: 100% 0, 100% 0; right: 0; } - &.fotorama__shadows--top:before { .fotorama-shadow-gradient(50%, 0); background-position: 0 0, 0 0; - top: 0; - } + top:0; + } &.fotorama__shadows--bottom:after { .fotorama-shadow-gradient(50%, 100%); background-position: 0 100%, 0 100%; @@ -1051,7 +700,6 @@ width: 100%; } } - .fotorama_horizontal_ratio { .fotorama__img { .translateX(-50%); @@ -1107,11 +755,9 @@ padding: 0; position: absolute; top: 215px; - &:not(.hidden) { background-color: @color-white; } - img { left: 0; max-width: inherit; @@ -1122,11 +768,16 @@ .fotorama__stage__frame { text-align: center; - .fotorama__img { height: auto; + left: 50%; max-height: 100%; max-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); + transition-duration: @fotorama-fullscreen-zoom-time; + transition-property: width, height, top, left; vertical-align: middle; width: auto; } @@ -1151,7 +802,6 @@ .fotorama__nav__shaft { background-color: white; width: 100%; - .fotorama__nav__frame--thumb { display: block; padding-bottom: inherit !important; @@ -1162,6 +812,10 @@ .fotorama--fullscreen { .fotorama__stage__frame { .fotorama__img { + display: none; + } + .fotorama__img, + .fotorama__img--full { bottom: 0; left: 0; margin: auto; @@ -1171,6 +825,34 @@ right: 0; top: 0; } + .fotorama__img--full { + cursor: default; + display: block; + height: auto; + left: 0; + margin: auto; + max-height: 100%; + max-width: 100%; + top: 0; + transition: @fotorama-fullscreen-zoom-time linear; + vertical-align: middle; + width: auto; + &:extend(.fotorama-gpu); + &.fotorama__img--zoommable { + cursor: pointer; + max-height: none; + max-width: none; + transition-property: width, height, bottom, right, top, left; + } + &.fotorama__img--draggable { + cursor: move; + transition-property: none; + } + } + iframe { + left: @fotorama-arw-size; + width: calc(~'100% - @{fotorama-arw-size} * 2'); + } } } @@ -1183,8 +865,7 @@ top: 0; width: @fotorama-thumb-arrow; z-index: @z-index-10; - - .fotorama__thumb__arr { + .fotorama__thumb--icon { .fotorama-abs-center(); width: 100%; @@ -1193,25 +874,13 @@ } } } - .fotorama__thumb__arr--left { - .fotorama-arrow-gradient(left); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#00ffffff', GradientType=1); left: 0; - - .fotorama__thumb__arr { - background-position: (-@fotorama-thumb-arrow) (-@fotorama-thumb-arrow); - } } - .fotorama__thumb__arr--right { - .fotorama-arrow-gradient(right); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffffff', endColorstr='#ffffff', GradientType=1); right: 0; - .fotorama__thumb__arr { - background-position: (-@fotorama-thumb-arrow*2) (-@fotorama-thumb-arrow); - } + } } @@ -1224,30 +893,17 @@ position: absolute; right: 0; z-index: @z-index-10; - - .fotorama__thumb__arr { + .fotorama__thumb--icon { .fotorama-rotate(90deg); margin: auto; width: @fotorama-thumb-arrow; } } - .fotorama__thumb__arr--left { - .fotorama-arrow-gradient(top); top: 0; - - .fotorama__thumb__arr { - background-position: (-@fotorama-thumb-arrow) (-@fotorama-thumb-arrow); - } } - .fotorama__thumb__arr--right { - .fotorama-arrow-gradient(bottom); bottom: 0; - - .fotorama__thumb__arr { - background-position: (-@fotorama-thumb-arrow*2) (-@fotorama-thumb-arrow); - } } } @@ -1256,48 +912,111 @@ .fotorama__nav { max-width: 99999px !important; } - .fotorama__stage__frame { visibility: hidden; } - .fotorama__stage__frame.fotorama__active { visibility: visible; } } -.fotorama__thumb__arr { +.fotorama__thumb--icon { &:extend(.fotorama-sprite); - background-size: 300%; font-size: 0.001px; padding-bottom: @fotorama-thumb-arrow; } +.fotorama__thumb__arr--left { + .fotorama__thumb--icon { + background-position: -25px -265px; + } +} + +.fotorama__thumb__arr--right { + .fotorama__thumb--icon { + background-position: -25px -350px; + } +} + .magnify-fullimage { display: none; } +.fotorama__arr, +.fotorama__thumb__arr { + .fotorama-button-background(); +} + +.fotorama__wrap:not(.fotorama__wrap--toggle-arrows) { + .fotorama__fullscreen-icon, + .fotorama__zoom-out, + .fotorama__zoom-in{ + .fotorama-button-background(); + } +} + +.fotorama__video-close { + &:extend(.fotorama-sprite); + background-position: (-@fotorama_close_button) 0; + height: @fotorama_close_button; + opacity: 0; + right: 0; + top: 0; + transform: translate3d((@fotorama_close_button), (-@fotorama_close_button), 0); + transition: opacity 0.3s ease-in-out; + width: @fotorama_close_button; + @media all and (max-width: 768px) { + background-position: -100px -20px; + top: 10px; + height: 40px; + width: 40px; + } + &.fotorama-show-control { + opacity: 1; + transform: translate3d(0, -10px, 0); + } +} + +// While first time init .gallery-placeholder { .loading-mask { padding: 0 0 50%; - position: absolute; + position: static; } - .loader img { - position: absolute; + position: absolute; } } -body.fotorama__fullscreen { - overflow-y: hidden; +// Styles for spinner in gallery. +.fotorama__spinner { + background-image: url('@{baseDir}../images/loader-1.gif'); + bottom: 0; + display: none; + height: @fotorama-spinner-size; + left: 0; + margin: auto; + position: absolute; + right: 0; + top: 0; + width: @fotorama-spinner-size; + z-index: @z-index-1; + &.fotorama__spinner--show { + display: block; + } +} +.fotorama__product-video--loaded { + .fotorama__img, .fotorama__img--full { + display: none !important; + } +} - .magnify-fullimage { - display: inline-block; +.fotorama__stage { + .fotorama__arr--shown { + display: block !important; } - .fotorama__stage__shaft { - //.fotorama__img { - // display: none; - //} + .fotorama__arr--hidden { + display: none !important; } } diff --git a/lib/web/mage/gallery/gallery.png b/lib/web/mage/gallery/gallery.png index 8fa060478295e..a5077dd7cd7f7 100644 Binary files a/lib/web/mage/gallery/gallery.png and b/lib/web/mage/gallery/gallery.png differ diff --git a/lib/web/mage/gallery/module/_extends.less b/lib/web/mage/gallery/module/_extends.less new file mode 100644 index 0000000000000..32226fa540274 --- /dev/null +++ b/lib/web/mage/gallery/module/_extends.less @@ -0,0 +1,127 @@ +// /** +// * Copyright © 2016 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +.fotorama-stretch { + bottom: 0; + height: 100%; + left: 0; + position: absolute; + right: 0; + top: 0; + width: 100%; +} + +.fotorama-grab-cursor { + cursor: move; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: -o-grab; + cursor: -ms-grab; + cursor: grab; +} + +.fotorama-grabbing-cursor { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: -o-grabbing; + cursor: -ms-grabbing; + cursor: grabbing; +} + +.fotorama-gpu { + transform: translateZ(0); +} + +.fotorama-focus { + outline: 0; +} + +.fotorama-focus-overlay { + &:after { + &:extend(.fotorama-stretch); + background-color: @color-blue2; + border-radius: inherit; + content: ''; + } +} + +.fotorama-transform-disabled { + transform: none !important; +} + +.fotorama-transition-for-slide { + transition-duration: 0ms; + transition-property: transform, width; + transition-timing-function: cubic-bezier(0.1, 0, 0.25, 1); +} + +.fotorama-no-select { + user-select: none; +} + +.fotorama-select { + user-select: text; +} + +.fotorama-empty-bg { + background: url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=); +} + +.fotorama-auto-margin { + margin: auto; + padding: 0; +} + +.fotorama-inline-block { + .fotorama-inline-block(); +} + +.fotorama-content-box { + box-sizing: content-box; +} + +.fotorama-border-box { + box-sizing: border-box; +} + +.fotorama-hidden { + left: -99999px; + position: absolute; + top: -99999px; + z-index: -@z-index-10; +} + +.fotorama-visible { + left: auto; + opacity: 1; + position: relative; + top: auto; + z-index: auto; +} + +.fotorama-no-tap { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.transitionDuration { + transition-duration: 333ms; +} + +.transitionDurationZero { + transition-duration: 0ms; +} + +.fotorama-sprite { + &:extend(.fotorama-print-background); + background-image: url('gallery.png'); + background-repeat: no-repeat; +} + +.fotorama-print-background { + @media print { + background: none !important; + } +} diff --git a/lib/web/mage/gallery/module/_focus.less b/lib/web/mage/gallery/module/_focus.less new file mode 100644 index 0000000000000..20b02a0b2e031 --- /dev/null +++ b/lib/web/mage/gallery/module/_focus.less @@ -0,0 +1,66 @@ +// /** +// * Copyright © 2016 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +.fotorama__fullscreen-icon:focus, +.fotorama__zoom-out:focus, +.fotorama__zoom-in:focus, +.fotorama__arr:focus, +.fotorama__stage__shaft:focus, +.fotorama__nav__frame--thumb:focus .fotorama__thumb, +.fotorama__nav__frame--dot:focus .fotorama__dot { + box-shadow: none; + &:after { + border-radius: inherit; + bottom: @fotorama-inner-box-shadow; + box-shadow: @focus__box-shadow; + content: ''; + left: @fotorama-inner-box-shadow; + position: absolute; + right: @fotorama-inner-box-shadow; + top: @fotorama-inner-box-shadow; + z-index: @z-index-10; + } +} + +.fotorama__nav__frame--thumb:focus, +.fotorama__nav__frame--dot:focus { + .fotorama__thumb:after, + .fotorama__dot:after{ + bottom: 0; + left: 0; + right: 0; + top: 0; + } + .fotorama__thumb.fotorama_vertical_ratio:after { + left: 2px; + right: 2px; + } + .fotorama__thumb { + overflow: inherit; + } +} + +.fotorama__nav__frame:nth-child(2):focus { + .fotorama__thumb:after{ + left: 1px; + } + .fotorama__thumb.fotorama_vertical_ratio:after{ + top: 1px; + } +} + +.fotorama__nav__frame:last-child:focus { + .fotorama__thumb:after{ + right: 1px; + } + .fotorama__thumb.fotorama_vertical_ratio:after{ + bottom: 1px; + } +} + +.fotorama__thumb__arr { + box-shadow: none; +} + diff --git a/lib/web/mage/gallery/module/_fullscreen.less b/lib/web/mage/gallery/module/_fullscreen.less new file mode 100644 index 0000000000000..68cef2055d0a1 --- /dev/null +++ b/lib/web/mage/gallery/module/_fullscreen.less @@ -0,0 +1,64 @@ +// /** +// * Copyright © 2016 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +.fotorama--fullscreen { + background: @color-white; + bottom: 0 !important; + float: none !important; + left: 0 !important; + margin: 0 !important; + position: fixed !important; + right: 0 !important; + top: 0 !important; + width: 100% !important; + z-index: @z-index-10 !important; + &:extend(.fotorama-gpu); + .fotorama__wrap { + max-width: 100% !important; + } +} + +.fotorama__fullscreen { + overflow: hidden; + position: relative; + .fotorama__zoom-in, + .fotorama__zoom-out { + cursor: pointer; + display: block; + height: @size-fotorama-block; + overflow: hidden; + position: absolute; + width: @size-fotorama-block; + + } + .fotorama__zoom-out { + &:extend(.fotorama-sprite); + background-position: 0 (-@size-fotorama-block) !important; + top: 80px; + &.fotorama__zoom-out--disabled { + display: none; + } + } + .fotorama__zoom-in { + &:extend(.fotorama-sprite); + background-position: 0 0 !important; + top: 0; + &.fotorama__zoom-in--disabled { + display: none; + } + } + .fotorama__video-close { + display: none; + } +} + +.fotorama--fullscreen .fotorama__loaded--full { + .fotorama__img { + display: none; + } + .fotorama__img--full { + display: block; + } +} \ No newline at end of file diff --git a/lib/web/mage/gallery/module/_mixins.less b/lib/web/mage/gallery/module/_mixins.less new file mode 100644 index 0000000000000..1c9c613fcdc60 --- /dev/null +++ b/lib/web/mage/gallery/module/_mixins.less @@ -0,0 +1,53 @@ +// /** +// * Copyright © 2016 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +.fotorama-translate3d(@x; @y; @z) { + -webkit-transform: translate3d(@x, @y, @z); + transform: translate3d(@x, @y, @z); +} + +.fotorama-rotate (@deg) { + -webkit-transform: rotate(@deg); + -ms-transform: rotate(@deg); + transform: rotate(@deg); +} + +.translateX(@value) { + -webkit-transform: translateX(@value); + -ms-transform: translateX(@value); + -o-transform: translateX(@value); + transform: translateX(@value); +} + +.translateY(@value) { + -webkit-transform: translateY(@value); + -ms-transform: translateY(@value); + -o-transform: translateY(@value); + transform: translateY(@value); +} + +.fotorama-shadow-gradient(@x, @y) { + background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.2) 25%, rgba(0, 0, 0, 0.3) 75%, transparent), radial-gradient(farthest-side at @x @y, rgba(0, 0, 0, 0.4), transparent); +} + +.fotorama-inline-block(@va: middle) { + *display: inline; + *zoom: 1; + -moz-box-orient: vertical; + display: -moz-inline-box; + display: inline-block; + vertical-align: @va; +} + +.fotorama-button-background() { + background-color: rgba(255, 255, 255, 0.3); + transition: background-color @fotorama-duration-time ease-in-out; + &:hover { + background-color: rgba(255, 255, 255, 0.5); + } + &:active { + background-color: rgba(213, 213, 213, 0.5); + } +} \ No newline at end of file diff --git a/lib/web/mage/gallery/module/_variables.less b/lib/web/mage/gallery/module/_variables.less new file mode 100644 index 0000000000000..70e05bf6060a7 --- /dev/null +++ b/lib/web/mage/gallery/module/_variables.less @@ -0,0 +1,12 @@ +// * Copyright © 2016 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ +// /** +@fotorama-arw-size: 80px; +@fotorama-duration-time: 0.3s; +@fotorama-fullscreen-zoom-time: 0.3s; +@fotorama-inner-box-shadow: 3px; +@fotorama-spinner-size: 64px; +@fotorama-thumb-arrow: 30px; +@fotorama_close_button: 80px; +@size-fotorama-block: 80px; diff --git a/lib/web/magnifier/magnifier.js b/lib/web/magnifier/magnifier.js index e0b8ba111b8c3..bf09a32d3da02 100644 --- a/lib/web/magnifier/magnifier.js +++ b/lib/web/magnifier/magnifier.js @@ -4,12 +4,6 @@ */ ;(function ($) { - var onWheelCallback, - zoomWidthStep = 0, - zoomHeightStep = 0, - isDraggable = false, - isZoomActive = false; - $.fn.magnify = function (options) { 'use strict'; @@ -30,9 +24,8 @@ $thumb, that = this, largeWrapper = options.largeWrapper || ".magnifier-preview", - $largeWrapper = $(largeWrapper), - zoomShown = false, - curThumb = null, + $largeWrapper = $(largeWrapper); + curThumb = null, currentOpts = { x: 0, y: 0, @@ -160,7 +153,7 @@ lens.addClass(MagnifyCls.magnifyHidden); lens.html(""); large.id = idx + '-large'; - large.style.width = Math.round(data[idx].largeW * rate) + 'px'; + large.style.width = data[idx].largeW * rate + 'px'; large.style.height = data[idx].largeH + 'px'; large.className = 'magnifier-large magnify-hidden'; @@ -172,10 +165,16 @@ } data[idx].lensH = data[idx].lensH > $thumb.height() ? $thumb.height() : data[idx].lensH; - lens.css({ - width: data[idx].lensW + 1 + 'px', - height: data[idx].lensH + 0.5 + 'px' - }); + + if (Math.round(data[idx].lensW) === 0) { + lens.css('display', 'none'); + } else { + lens.css({ + width: data[idx].lensW + 1 + 'px', + height: data[idx].lensH - 1 + 'px', + display: '' + }); + } } function getMousePos() { @@ -186,8 +185,8 @@ inBounds = ( xPos < 0 || yPos < 0 || xPos > currentOpts.w || yPos > currentOpts.h ) ? false : true; - l = xPos - Math.round(currentOpts.lensW / 2); - t = yPos - Math.round(currentOpts.lensH / 2); + l = xPos - currentOpts.lensW / 2; + t = yPos - currentOpts.lensH / 2; if (currentOpts.mode !== 'inside') { if (xPos < currentOpts.lensW / 2) { @@ -203,21 +202,21 @@ } if (yPos - currentOpts.h + Math.ceil(currentOpts.lensH / 2) > 0) { - t = currentOpts.h - Math.ceil(currentOpts.lensH + 2); + t = currentOpts.h - Math.ceil(currentOpts.lensH); } - pos.l = Math.round(l); - pos.t = Math.round(t); + pos.l = l; + pos.t = t; - currentOpts.lensBgX = pos.l + 1; - currentOpts.lensBgY = pos.t + 1; + currentOpts.lensBgX = pos.l; + currentOpts.lensBgY = pos.t; if (currentOpts.mode === 'inside') { - currentOpts.largeL = Math.round(xPos * (currentOpts.zoom - (currentOpts.lensW / currentOpts.w))); - currentOpts.largeT = Math.round(yPos * (currentOpts.zoom - (currentOpts.lensH / currentOpts.h))); + currentOpts.largeL = xPos * (currentOpts.zoom - (currentOpts.lensW / currentOpts.w)); + currentOpts.largeT = yPos * (currentOpts.zoom - (currentOpts.lensH / currentOpts.h)); } else { - currentOpts.largeL = Math.round(currentOpts.lensBgX * currentOpts.zoom * (currentOpts.largeWrapperW / currentOpts.w) * rate); - currentOpts.largeT = Math.round(currentOpts.lensBgY * currentOpts.zoom * (currentOpts.largeWrapperH / currentOpts.h)); + currentOpts.largeL = currentOpts.lensBgX * currentOpts.zoom * (currentOpts.largeWrapperW / currentOpts.w) * rate; + currentOpts.largeT = currentOpts.lensBgY * currentOpts.zoom * (currentOpts.largeWrapperH / currentOpts.h); } } } @@ -284,12 +283,9 @@ } pos.t = pos.t <= 0 ? 0 : pos.t; - pos.t = pos.t > 0 ? pos.t: pos.t; - pos.l = pos.l <= 0 ? 0 : pos.l; - //pos.l = pos.l > 0 ? pos.l : pos.l; curLens.css({ left: pos.l + paddingX +'px', - top: pos.t + paddingY + 1.75 + 'px' + top: pos.t + 1 + paddingY + 'px' }); if (lensbg) { @@ -325,8 +321,8 @@ thumbData.x = thumbBounds.left; thumbData.y = thumbBounds.top; - thumbData.w = Math.round(thumbBounds.right - thumbData.x); - thumbData.h = Math.round(thumbBounds.bottom - thumbData.y); + thumbData.w = thumbBounds.right - thumbData.x; + thumbData.h = thumbBounds.bottom - thumbData.y; if (thumbData.mode === 'inside') { w = thumbData.w; @@ -336,8 +332,8 @@ h = thumbData.largeWrapperH; } - thumbData.largeW = Math.round(thumbData.zoom * w); - thumbData.largeH = Math.round(thumbData.zoom * h); + thumbData.largeW = thumbData.zoom * w; + thumbData.largeH = thumbData.zoom * h; thumbData.lensW = (thumbData.w / thumbData.zoom) / rate; thumbData.lensH = thumbData.h / thumbData.zoom; @@ -468,7 +464,7 @@ ? options.onthumbmove : currentOpts.onthumbmove; - largeUrl = gOptions.full || $thumb.attr('src'); + largeUrl = $thumb.data("original") || gOptions.full || $thumb.attr('src'); if (thumb.id === '') { idx = thumb.id = 'magnifier-item-' + gId; @@ -571,162 +567,6 @@ } } - function toggleZoomButtons($image) { - var path = $image.attr('src'), - isVideo = $image.parent().hasClass('fotorama-video-container'), - imgSize; - - if (path && !isVideo) { - imgSize = getImageSize(path); - if ((imgSize.rh > $image.parent().height()) || (imgSize.rw > $image.parent().width())) { - $('.fotorama__zoom-in').show(); - $('.fotorama__zoom-out').show(); - zoomShown = true; - } else { - $('.fotorama__zoom-in').hide(); - $('.fotorama__zoom-out').hide(); - zoomShown = false; - } - } else { - $('.fotorama__zoom-in').hide(); - $('.fotorama__zoom-out').hide(); - zoomShown = false; - } - } - - function magnifierFullscreen () { - var isDragActive = false, - startX, - startY, - imagePosX, - imagePosY, - touch, - isTouchEnabled = 'ontouchstart' in document.documentElement; - - $('[data-gallery-role="gallery"]').on('fotorama:fullscreenenter fotorama:showend fotorama:load', function () { - var $preview = $('[data-gallery-role="stage-shaft"] [data-active="true"] img'), - $image = $('[data-gallery-role="stage-shaft"] [data-active="true"] .fotorama__img--full'), - $imageContainer = $preview.parent(), - gallery = $('[data-gallery-role="gallery"]'); - - gallery.on('fotorama:fullscreenexit', function () { - $thumb.css({ - 'top': '', - 'left': '' - }); - }); - - if (gallery.data('fotorama').fullScreen) { - toggleZoomButtons($image); - resetVars($('[data-gallery-role="stage-shaft"] .fotorama__img--full')); - - $('.fotorama__stage__frame .fotorama__img--full').each(function () { - var path = $(this).attr("src"), - imgSize; - if (path) { - imgSize = getImageSize(path); - - if ((imgSize.rh > $(this).parent().height()) || (imgSize.rw > $(this).parent().width())) { - - if (imgSize.rh / imgSize.rw < $(this).parent().height() / $(this).parent().width()) { - $(this).width($(this).parent().width()); - $(this).height('auto'); - } else { - $(this).height($(this).parent().height()); - $(this).width('auto'); - } - - $(this).css({ - 'top': '', - 'left': '' - }); - } - } - }); - } - $image - .off(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown') - .on(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown', function (e) { - if (gallery.data('fotorama').fullScreen && isDraggable) { - e.preventDefault(); - $image.css('cursor', 'move'); - imagePosY = $image.offset().top; - imagePosX = $image.offset().left; - - startX = e.clientX || e.originalEvent.clientX; - startY = e.clientY || e.originalEvent.clientY; - if (isTouchEnabled) { - touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; - startX = touch.pageX; - startY = touch.pageY; - } - isDragActive = true; - } - }); - - - - $image - .off(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove') - .on(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove', function (e) { - if (gallery.data('fotorama').fullScreen && isDragActive && isDraggable) { - var top, - left, - startOffset = $image.offset(), - clientX = e.clientX || e.originalEvent.clientX, - clientY = e.clientY || e.originalEvent.clientY; - - - e.preventDefault(); - - if (isTouchEnabled && !isZoomActive) { - touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; - clientX = touch.pageX; - clientY = touch.pageY; - } - top = +imagePosY + (clientY - startY); - left = +imagePosX + (clientX - startX); - - if ($image.height() > $imageContainer.height()) { - - if (($imageContainer.offset().top + $imageContainer.height()) > (top + $image.height())) { - top = $imageContainer.offset().top + $imageContainer.height() - $image.height(); - } else { - top = ($imageContainer.offset().top < top) ? 0 : top; - } - $image.offset({ - 'top': top - }); - } - - if ($image.width() > $imageContainer.width()) { - - if (($imageContainer.offset().left + $imageContainer.width()) > (left + $image.width())) { - left = $imageContainer.offset().left + $imageContainer.width() - $image.width(); - } else { - left = ($imageContainer.offset().left < left) ? $imageContainer.offset().left : left; - } - $image.offset({ - 'left': left - }); - } - return false; - } - }); - - $image - .off(isTouchEnabled ? 'touchend' : 'mouseup pointerup MSPointerUp') - .on(isTouchEnabled ? 'touchend' : 'mouseup pointerup MSPointerUp', function (e) { - if (gallery.data('fotorama').fullScreen && isDragActive && isDraggable) { - isDragActive = false; - $image.css('cursor', 'pointer'); - - return false; - } - }); - }); - } - function onScroll() { if (curThumb !== null) { @@ -734,280 +574,14 @@ } } - if ($('.fotorama-item').data('fotorama').fullScreen) { - $('.fotorama__stage__frame .fotorama__img--full').each(function () { - var image = new Image(); - image.src = $(this).attr("src"); - - if ( (image.height > $(this).parent().height()) || (image.width > $(this).parent().width()) ) { - - if (image.height / image.width < $(this).parent().height() / $(this).parent().width()) { - $(this).width($(this).parent().width()); - $(this).height(''); - } else { - $(this).height($(this).parent().height()); - $(this).width(''); - } - } - }); - } $(window).on('scroll', onScroll); $(window).resize(function() { - - if ($('.fotorama-item').data('fotorama').fullScreen) { - - $('.fotorama__stage__frame .fotorama__img--full').each(function () { - var image = new Image(); - image.src = $(this).attr("src"); - - if ( (image.height > $(this).parent().height()) || (image.width > $(this).parent().width()) ) { - - if (image.height / image.width < $(this).parent().height() / $(this).parent().width()) { - $(this).width($(this).parent().width()); - $(this).height(''); - } else { - $(this).height($(this).parent().height()); - $(this).width(''); - } - } - }); - - toggleZoomButtons($('[data-gallery-role="stage-shaft"] [data-active="true"] .fotorama__img--full')); - } - - _init($box, gOptions); - }); - function resetVars($image) { - zoomWidthStep = 0; - zoomHeightStep = 0; - isDraggable = false; - $image.css({ - top: 0, - left: 0, - right: 0, - bottom: 0, - cursor: '' - }); - } - - function checkFullscreenImagePosition(widthStep, heightStep) { - var $preview, $image, $imageContainer, gallery, top, left; - - if ($('[data-gallery-role="gallery"]').data('fotorama').fullScreen) { - - $preview = $('[data-gallery-role="stage-shaft"] [data-active="true"] img'); - $image = $('[data-gallery-role="stage-shaft"] [data-active="true"] .fotorama__img--full'); - $imageContainer = $preview.parent(); - gallery = $('[data-gallery-role="gallery"]'); - top = $image.position().top; - left = $image.position().left; - - if ($imageContainer.width() < $image.width() - widthStep && $imageContainer.width() > $image.width()) { - left = ($imageContainer.width() - $image.width()) / 2; - } - - if ($imageContainer.height() < $image.height() - heightStep && $imageContainer.height() > $image.height()) { - top = ($imageContainer.height() - $image.height()) / 2; - } - - if ($image.height() - heightStep > $imageContainer.height()) { - if (Math.abs(top + heightStep / 2) > $image.height() - $imageContainer.height() - heightStep) { - top = $imageContainer.height() - $image.height() + heightStep; - } else if (top + heightStep / 2 >= 0) { - top = 0; - } else { - top += heightStep / 2; - } - $image.css({ - top: top, - bottom: 'auto' - }); - } else { - $image.css({ - top: 0, - bottom: 0 - }); - } - - if ($image.width() - widthStep > $imageContainer.width()) { - if (Math.abs(left + widthStep / 2) > $image.width() - $imageContainer.width() - widthStep) { - left = $imageContainer.width() - $image.width() + widthStep; - } else if (left + widthStep / 2 >= 0) { - left = 0; - } else { - left += widthStep / 2; - } - $image.css({ - left: left, - right: 'auto' - }); - } else { - $image.css({ - left: 0, - right: 0 - }); - } - } - } - - function zoomIn(e) { - if (zoomShown) { - var $image = $('[data-gallery-role="stage-shaft"] [data-active="true"] .fotorama__img--full'), - imgOriginalSize = $image.length ? getImageSize($image[0].src) : '', - widthResult, - heightResult; - - if (!zoomWidthStep) { - zoomWidthStep = Math.ceil((imgOriginalSize.rw - $image.width())/parseFloat(options.fullscreenzoom)); - zoomHeightStep = Math.ceil((imgOriginalSize.rh - $image.height())/parseFloat(options.fullscreenzoom)); - } - widthResult = $image.width() + zoomWidthStep; - heightResult = $image.height() + zoomHeightStep; - - if (widthResult >= imgOriginalSize.rw) { - widthResult = imgOriginalSize.rw; - } - if (heightResult >= imgOriginalSize.rh) { - heightResult = imgOriginalSize.rh; - } - - if ( zoomShown ) { - isDraggable = true; - } - - if ($image.width() >= $image.height() && $image.width() !== imgOriginalSize.rw) { - checkFullscreenImagePosition(-zoomWidthStep, -zoomHeightStep); - $image.css({ - width: widthResult, - height: 'auto' - }); - } else if ($image.width() < $image.height() && $image.height() !== imgOriginalSize.rh) { - checkFullscreenImagePosition(-zoomWidthStep, -zoomHeightStep); - $image.css({ - width: 'auto', - height: heightResult - }); - } - } - - return false; - } - - function zoomOut(e) { - if (zoomShown) { - var $image = $('[data-gallery-role="stage-shaft"] [data-active="true"] .fotorama__img--full'), - setedResult = $image.width() - zoomWidthStep, - widthCheck = $image.width() - zoomWidthStep <= $image.parent().width(), - heightCheck = $image.height() - zoomHeightStep <= $image.parent().height(); - - e.preventDefault(); - - if (widthCheck && heightCheck) { - if ($image.width() >= $image.height()) { - $image.trigger('fotorama:load'); - - return false; - } else if ($image.width() < $image.height()) { - $image.trigger('fotorama:load'); - - return false; - } - } - checkFullscreenImagePosition(zoomWidthStep, zoomHeightStep); - $image.css({'width': setedResult, height: 'auto'}); - } - - return false; - } - - /** - * Return width and height of original image - * @param src path for original image - * @returns {{rw: number, rh: number}} - */ - function getImageSize(src) { - var img = new Image(), - imgSize = { - rw: 0, - rh: 0 - }; - img.src = src; - imgSize.rw = img.width; - imgSize.rh = img.height; - return imgSize; - } - - - function setEventOnce() { - $('.fotorama__zoom-in') - .off('mouseup') - .on('mouseup', zoomIn); - $('.fotorama__zoom-out') - .off('mouseup') - .on('mouseup', zoomOut); - $('.fotorama__zoom-in') - .off('touchend') - .on('touchend', zoomIn); - $('.fotorama__zoom-out') - .off('touchend') - .on('touchend', zoomOut); - } - $(document).on('mousemove', onMousemove); _init($box, gOptions); - setEventOnce(); - magnifierFullscreen(); - - if (!onWheelCallback) { - onWheelCallback = function onWheel(e) { - var delta; - - if ($('[data-gallery-role="gallery"]').data('fotorama').fullScreen) { - e = e || window.event; - delta = e.deltaY || e.detail || e.wheelDelta; - - if (delta > 0 || (e.scale && e.scale < 1.0)) { - zoomOut(e); - } else if (delta < 0 || (e.scale && e.scale > 1.0)) { - zoomIn(e); - } - - e.preventDefault ? e.preventDefault() : (e.returnValue = false); - } - }; - } - $('.fotorama-item').on('fotorama:load', function () { - document.querySelector('.fotorama__stage').removeEventListener("gesturechange", onWheelCallback); - document.querySelector('.fotorama__stage').addEventListener("gesturechange", onWheelCallback); - document.querySelector('.fotorama__stage').addEventListener("gesturestart", function () { - isZoomActive = true; - }); - document.querySelector('.fotorama__stage').addEventListener("gestureend", function () { - isZoomActive = false; - }); - - if (document.querySelector('.fotorama__stage').addEventListener) { - if ('onwheel' in document) { - // IE9+, FF17+, Ch31+ - document.querySelector('.fotorama__stage').removeEventListener("wheel", onWheelCallback); - document.querySelector('.fotorama__stage').addEventListener("wheel", onWheelCallback); - } else if ('onmousewheel' in document) { - document.querySelector('.fotorama__stage').removeEventListener("mousewheel", onWheelCallback); - document.querySelector('.fotorama__stage').addEventListener("mousewheel", onWheelCallback); - } else { - // Firefox < 17 - document.querySelector('.fotorama__stage').removeEventListener("MozMousePixelScroll", onWheelCallback); - document.querySelector('.fotorama__stage').addEventListener("MozMousePixelScroll", onWheelCallback); - } - } else { // IE8- - document.querySelector('.fotorama__stage').detachEvent("onmousewheel", onWheelCallback); - document.querySelector('.fotorama__stage').attachEvent("onmousewheel", onWheelCallback); - } - }); } }(jQuery)); diff --git a/lib/web/magnifier/magnify.js b/lib/web/magnifier/magnify.js index f41130c7c089b..d4548a949ab81 100644 --- a/lib/web/magnifier/magnify.js +++ b/lib/web/magnifier/magnify.js @@ -4,8 +4,9 @@ */ define([ 'jquery', + 'underscore', 'magnifier/magnifier' -], function ($) { +], function ($, _) { 'use strict'; return function (config, element) { @@ -14,9 +15,24 @@ define([ gallerySelector = '[data-gallery-role="gallery"]', magnifierSelector = '[data-gallery-role="magnifier"]', magnifierZoomSelector = '[data-gallery-role="magnifier-zoom"]', - fullScreenIcon = '[data-gallery-role="fotorama__fullscreen-icon"]', + zoomInButtonSelector = '[data-gallery-role="fotorama__zoom-in"]', + zoomOutButtonSelector = '[data-gallery-role="fotorama__zoom-out"]', + fullscreenImageSelector = '[data-gallery-role="stage-shaft"] [data-active="true"] .fotorama__img--full', + imageDraggableClass = 'fotorama__img--draggable', + imageZoommable = 'fotorama__img--zoommable', + zoomInLoaded = 'zoom-in-loaded', + zoomOutLoaded = 'zoom-out-loaded', + zoomInDisabled = 'fotorama__zoom-in--disabled', + zoomOutDisabled = 'fotorama__zoom-out--disabled', + keyboardNavigation, + videoContainerClass = 'fotorama-video-container', hideMagnifier, - behaveOnHover; + dragFlag, + endX, + transitionActive = false, + tapFlag = 0, + allowZoomOut = false, + allowZoomIn = true; if (isTouchEnabled) { $(element).on('fotorama:showend fotorama:load', function () { @@ -25,6 +41,774 @@ define([ }); } + /** + * Return width and height of original image + * @param src path for original image + * @returns {{rw: number, rh: number}} + */ + function getImageSize(src) { + var img = new Image(), + imgSize = { + rw: 0, + rh: 0 + }; + + img.src = src; + imgSize.rw = img.width; + imgSize.rh = img.height; + + return imgSize; + } + + /** + * Sets min-height and min-width for image to avoid transition bug + * @param $image - fullscreen image + */ + function calculateMinSize($image) { + + var minHeight, + minWidth, + height = $image.height(), + width = $image.width(), + parentHeight = $image.parent().height(), + parentWidth = $image.parent().width(); + + if (width > parentWidth || height > parentHeight) { + + if (width / height < parentWidth / parentHeight) { + minHeight = parentHeight; + minWidth = width * (parentHeight / height); + } else { + minWidth = parentWidth; + minHeight = height * parentWidth / width; + } + $image.css({ + 'min-width': minWidth, + 'min-height': minHeight + }); + } + } + + function toggleZoomable($image, flag) { + if (flag) { + $image.css({ + 'min-width': $image.width(), + 'min-height': $image.height(), + 'width': $image.width(), + 'height': $image.height() + }).addClass(imageZoommable); + } else { + $image.css({ + width: '', + height: '', + top: '', + left: '', + right: '', + bottom: '' + }).removeClass(imageZoommable); + calculateMinSize($image); + } + } + + function resetVars($image) { + allowZoomIn = true; + allowZoomOut = dragFlag = transitionActive = false; + $image.hasClass(imageDraggableClass) && $image.removeClass(imageDraggableClass); + toggleZoomable($image, false); + } + + /** + * Set state for zoom controls. + * If state is true, zoom controls will be visible. + * IF state is false, zoom controls will be hidden. + * @param isHide + */ + function hideZoomControls(isHide) { + if (isHide) { + $(zoomInButtonSelector).addClass(zoomInDisabled); + $(zoomOutButtonSelector).addClass(zoomOutDisabled); + } else { + $(zoomInButtonSelector).removeClass(zoomInDisabled); + $(zoomOutButtonSelector).removeClass(zoomOutDisabled); + } + } + + /** + * Control visibility of zoom buttons. + * If image bigger than her wrapper. Zoom controls must visible. + * Zoom controls must be invisible for video content and touch devices. + * On touch devices active pinchIn/pinchOut. + * @param $image + * @param isTouchScreen - true for touch devices + * @param isVideoActiveFrame - true for active video frame + */ + function toggleZoomButtons($image, isTouchScreen, isVideoActiveFrame) { + var path = $image.attr('src'), + imgSize; + + if (path && !isTouchScreen && !isVideoActiveFrame) { + imgSize = getImageSize(path); + + imgSize.rh > $image.parent().height() || imgSize.rw > $image.parent().width() ? + hideZoomControls(false) : hideZoomControls(true); + } else { + hideZoomControls(true); + } + } + + function getTopValue($image, topProp, step, height, containerHeight) { + var top; + + if (parseInt($image.css('marginTop')) || parseInt($image.css('marginLeft'))) { + top = dragFlag ? topProp - step / 4 : 0; + top = top < containerHeight - height ? containerHeight - height : top; + top = top > height - containerHeight ? height - containerHeight : top; + } else { + top = topProp + step / 2; + top = top < containerHeight - height ? containerHeight - height : top; + top = top > 0 ? 0 : top; + + if (!dragFlag && step < 0) { + top = top < (containerHeight - height) / 2 ? (containerHeight - height) / 2 : top; + } + } + + return top; + } + + function getLeftValue(leftProp, step, width, containerWidth) { + var left; + + left = leftProp + step / 2; + left = left < containerWidth - width ? containerWidth - width : left; + left = left > 0 ? 0 : left; + + if (!dragFlag && step < 0) { + left = left < (containerWidth - width) / 2 ? (containerWidth - width) / 2 : left; + } + + return left; + } + + function checkFullscreenImagePosition($image, dimentions, widthStep, heightStep) { + var $imageContainer, + containerWidth, + containerHeight, + settings, + top, + left, + right, + bottom, + ratio; + + if ($(gallerySelector).data('fotorama').fullScreen) { + transitionActive = true; + $imageContainer = $image.parent(); + containerWidth = $imageContainer.width(); + containerHeight = $imageContainer.height(); + top = $image.position().top; + left = $image.position().left; + ratio = $image.width() / $image.height(); + dimentions.height = isNaN(dimentions.height) ? dimentions.width / ratio : dimentions.height; + dimentions.width = isNaN(dimentions.width) ? dimentions.height * ratio : dimentions.width; + + top = dimentions.height >= containerHeight ? + getTopValue($image, top, heightStep, dimentions.height, containerHeight) : 0; + + left = dimentions.width >= containerWidth ? + getLeftValue(left, widthStep, dimentions.width, containerWidth) : 0; + + right = dragFlag && left < (containerWidth - dimentions.width) / 2 ? 0 : left; + bottom = dragFlag ? 0 : top; + + settings = $.extend(dimentions, { + top: top, + bottom: bottom, + left: left, + right: right + }); + + $image.css(settings); + } + } + + /** + * Toggles fotorama's keyboard and mouse/touch navigation. + */ + function toggleStandartNavigation() { + var $selectable = + $('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]') + .not('[tabindex=-1], [disabled], :hidden'), + fotorama = $(gallerySelector).data('fotorama'), + $focus = $(':focus'), + index; + + if (fotorama.fullScreen) { + + $selectable.each(function (number) { + + if ($(this).is($focus)) { + index = number; + } + }); + + fotorama.setOptions({ + swipe: !allowZoomOut, + keyboard: !allowZoomOut + }); + + if (_.isNumber(index)) { + $selectable.eq(index).focus(); + } + } + } + + function zoomIn(e, xStep, yStep) { + var $image, + imgOriginalSize, + imageWidth, + imageHeight, + zoomWidthStep, + zoomHeightStep, + widthResult, + heightResult, + ratio, + dimentions = {}; + + if (allowZoomIn && !transitionActive && (isTouchEnabled || + !$(zoomInButtonSelector).hasClass(zoomInDisabled))) { + $image = $(fullscreenImageSelector); + imgOriginalSize = getImageSize($image[0].src); + imageWidth = $image.width(); + imageHeight = $image.height(); + ratio = imageWidth / imageHeight; + allowZoomOut = true; + toggleStandartNavigation(); + + if (!$image.hasClass(imageZoommable)) { + toggleZoomable($image, true); + } + + e.preventDefault(); + + if (imageWidth >= imageHeight) { + zoomWidthStep = xStep || Math.ceil(imageWidth * parseFloat(config.magnifierOpts.fullscreenzoom) / 100); + widthResult = imageWidth + zoomWidthStep; + + if (widthResult >= imgOriginalSize.rw) { + widthResult = imgOriginalSize.rw; + zoomWidthStep = xStep || widthResult - imageWidth; + allowZoomIn = false; + } + heightResult = widthResult / ratio; + zoomHeightStep = yStep || heightResult - imageHeight; + } else { + zoomHeightStep = yStep || Math.ceil(imageHeight * parseFloat(config.magnifierOpts.fullscreenzoom) / 100); + heightResult = imageHeight + zoomHeightStep; + + if (heightResult >= imgOriginalSize.rh) { + heightResult = imgOriginalSize.rh; + zoomHeightStep = yStep || heightResult - imageHeight; + allowZoomIn = false; + } + widthResult = heightResult * ratio; + zoomWidthStep = xStep || widthResult - imageWidth; + } + + if (imageWidth >= imageHeight && imageWidth !== imgOriginalSize.rw) { + dimentions = $.extend(dimentions, { + width: widthResult, + height: 'auto' + }); + checkFullscreenImagePosition($image, dimentions, -zoomWidthStep, -zoomHeightStep); + + } else if (imageWidth < imageHeight && imageHeight !== imgOriginalSize.rh) { + dimentions = $.extend(dimentions, { + width: 'auto', + height: heightResult + }); + checkFullscreenImagePosition($image, dimentions, -zoomWidthStep, -zoomHeightStep); + } + } + + return false; + } + + function zoomOut(e, xStep, yStep) { + var $image, + widthResult, + heightResult, + dimentions, + parentWidth, + parentHeight, + imageWidth, + imageHeight, + zoomWidthStep, + zoomHeightStep, + ratio, + fitIntoParent; + + if (allowZoomOut && !transitionActive && (isTouchEnabled || + !$(zoomOutButtonSelector).hasClass(zoomOutDisabled))) { + allowZoomIn = true; + $image = $(fullscreenImageSelector); + parentWidth = $image.parent().width(); + parentHeight = $image.parent().height(); + imageWidth = $image.width(); + imageHeight = $image.height(); + ratio = imageWidth / imageHeight; + + e.preventDefault(); + + if (imageWidth >= imageHeight) { + zoomWidthStep = xStep || Math.ceil(imageWidth * parseFloat(config.magnifierOpts.fullscreenzoom) / 100); + widthResult = imageWidth - zoomWidthStep; + heightResult = widthResult / ratio; + zoomHeightStep = yStep || imageHeight - heightResult; + } else { + zoomHeightStep = yStep || Math.ceil(imageHeight * parseFloat(config.magnifierOpts.fullscreenzoom) / 100); + heightResult = imageHeight - zoomHeightStep; + widthResult = heightResult * ratio; + zoomWidthStep = xStep || imageWidth - widthResult; + } + + fitIntoParent = function () { + if (ratio > parentWidth / parentHeight) { + widthResult = parentWidth; + zoomWidthStep = imageWidth - widthResult; + heightResult = widthResult / ratio; + zoomHeightStep = imageHeight - heightResult; + dimentions = { + width: widthResult, + height: 'auto' + }; + } else { + heightResult = parentHeight; + zoomHeightStep = imageHeight - heightResult; + widthResult = heightResult * ratio; + zoomWidthStep = imageWidth - widthResult; + dimentions = { + width: 'auto', + height: heightResult + }; + } + checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep); + }; + + if (imageWidth >= imageHeight) { + if (widthResult > parentWidth) { + dimentions = { + width: widthResult, + height: 'auto' + }; + checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep); + } else { + if (heightResult > parentHeight) { + dimentions = { + width: widthResult, + height: 'auto' + }; + checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep); + } else { + allowZoomOut = dragFlag = false; + toggleStandartNavigation(); + fitIntoParent(); + } + } + } else { + if (heightResult > parentHeight) { + dimentions = { + width: 'auto', + height: heightResult + }; + checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep); + } else { + if (widthResult > parentWidth) { + dimentions = { + width: 'auto', + height: heightResult + }; + checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep); + } else { + allowZoomOut = dragFlag = false; + toggleStandartNavigation(); + fitIntoParent(); + } + } + } + } + + return false; + } + + /** + * Bind event on scroll on active item in fotorama + * @param e + * @param fotorama - object of fotorama + */ + function mousewheel(e, fotorama, element) { + var $fotoramaStage = fotorama.activeFrame.$stageFrame, + fotoramaStage = $fotoramaStage.get(0); + + function onWheel(e) { + var delta = e.deltaY || e.wheelDelta, + ev = e || window.event; + + if ($(gallerySelector).data('fotorama').fullScreen) { + + if (e.deltaY) { + if (delta > 0) { + zoomOut(ev); + } else { + zoomIn(ev); + } + } else { + if (delta > 0) { + zoomIn(ev); + } else { + zoomOut(ev); + } + } + + e.preventDefault ? e.preventDefault() : e.returnValue = false; + } + } + + if (!$fotoramaStage.hasClass('magnify-wheel-loaded')) { + if (fotoramaStage && fotoramaStage.addEventListener) { + if ('onwheel' in document) { + fotoramaStage.addEventListener('wheel', onWheel); + } else if ('onmousewheel' in document) { + fotoramaStage.addEventListener('mousewheel', onWheel); + } else { + fotoramaStage.addEventListener('MozMousePixelScroll', onWheel); + } + $fotoramaStage.addClass('magnify-wheel-loaded'); + } + } + } + + /** + * Method which makes draggable picture. Also work on touch devices. + */ + function magnifierFullscreen(fotorama) { + var isDragActive = false, + startX, + startY, + imagePosX, + imagePosY, + touch, + swipeSlide, + $gallery = $(gallerySelector), + $image = $(fullscreenImageSelector, $gallery), + $imageContainer = $('[data-gallery-role="stage-shaft"] [data-active="true"]'), + gallery = $gallery.data('fotorama'), + pinchDimention; + + swipeSlide = _.throttle(function (direction) { + $(gallerySelector).data('fotorama').show(direction); + }, 500, { + trailing: false + }); + + function shiftImage(dx, dy, e) { + var top = +imagePosY + dy, + left = +imagePosX + dx, + swipeCondition = $image.width() / 10 + 20; + + dragFlag = true; + + if (($image.offset().left === $imageContainer.offset().left + $imageContainer.width() - $image.width() && e.keyCode === 39) || + (endX - 1 < $imageContainer.offset().left + $imageContainer.width() - $image.width() && dx < 0 && + _.isNumber(endX) && + (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove'))) { + endX = null; + swipeSlide('>'); + return; + } + + if (($image.offset().left === $imageContainer.offset().left && dx !== 0 && e.keyCode === 37) || + (endX === $imageContainer.offset().left && dx > 0 && + (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove'))) { + endX = null; + swipeSlide('<'); + + return; + } + + if ($image.height() > $imageContainer.height()) { + + if ($imageContainer.offset().top + $imageContainer.height() > top + $image.height()) { + top = $imageContainer.offset().top + $imageContainer.height() - $image.height(); + } else { + top = $imageContainer.offset().top < top ? 0 : top; + } + $image.offset({ + 'top': top + }); + $image.css('bottom', ''); + } + + if ($image.width() > $imageContainer.width()) { + + if ($imageContainer.offset().left + $imageContainer.width() > left + $image.width()) { + left = $imageContainer.offset().left + $imageContainer.width() - $image.width(); + } else { + left = $imageContainer.offset().left < left ? $imageContainer.offset().left : left; + } + $image.offset({ + 'left': left + }); + $image.css('right', ''); + } else if (Math.abs(dy) < 1 && allowZoomOut && + !(e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove')) { + dx < 0 ? $(gallerySelector).data('fotorama').show('>') : $(gallerySelector).data('fotorama').show('<'); + } + + if ($image.width() <= $imageContainer.width() && allowZoomOut && + (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove') && + Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > swipeCondition) { + dx < 0 ? swipeSlide('>') : swipeSlide('<'); + } + } + + /** + * Sets image size to original or fit in parent block + * @param e - event object + */ + function dblClickHandler(e) { + var imgOriginalSize = getImageSize($image[0].src), + proportions; + + if (imgOriginalSize.rh < $image.parent().height() && imgOriginalSize.rw < $image.parent().width()) { + return; + } + + proportions = imgOriginalSize.rw / imgOriginalSize.rh; + + if (allowZoomIn) { + zoomIn(e, imgOriginalSize.rw - $image.width(), imgOriginalSize.rh - $image.height()); + } else { + if (proportions > $imageContainer.width() / $imageContainer.height()) { + zoomOut(e, imgOriginalSize.rw - $imageContainer.width(), imgOriginalSize.rw / proportions); + } else { + zoomOut(e, imgOriginalSize.rw * proportions, imgOriginalSize.rh - $imageContainer.height()); + } + } + } + + function detectDoubleTap(e) { + var now = new Date().getTime(), + timesince = now - tapFlag; + + if (timesince < 400 && timesince > 0) { + transitionActive = false; + tapFlag = 0; + dblClickHandler(e); + } else { + tapFlag = new Date().getTime(); + } + } + + if (isTouchEnabled) { + $image.off('tap'); + $image.on('tap', function (e) { + if (e.originalEvent.originalEvent.touches.length === 0) { + detectDoubleTap(e); + } + }); + } else { + $image.unbind('dblclick'); + $image.dblclick(dblClickHandler); + } + + if (gallery.fullScreen) { + toggleZoomButtons($image, isTouchEnabled, checkForVideo(fotorama.activeFrame.$stageFrame)); + } + + function getDimention(event) { + return Math.sqrt( + (event.touches[0].clientX - event.touches[1].clientX) * (event.touches[0].clientX - event.touches[1].clientX) + + (event.touches[0].clientY - event.touches[1].clientY) * (event.touches[0].clientY - event.touches[1].clientY)); + } + + $image.off(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown'); + $image.on(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown', function (e) { + if (e && e.originalEvent.touches && e.originalEvent.touches.length >= 2) { + e.preventDefault(); + pinchDimention = getDimention(e.originalEvent); + isDragActive = false; + + if ($image.hasClass(imageDraggableClass)) { + $image.removeClass(imageDraggableClass); + } + } else { + if (gallery.fullScreen) { + e.preventDefault(); + + imagePosY = $image.offset().top; + imagePosX = $image.offset().left; + + if (isTouchEnabled) { + touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; + e.clientX = touch.pageX; + e.clientY = touch.pageY; + } + startX = e.clientX || e.originalEvent.clientX; + startY = e.clientY || e.originalEvent.clientY; + isDragActive = true; + } + } + + if ($image.offset() && ($image.width() > $imageContainer.width())) { + endX = $image.offset().left; + } + }); + + $image.off(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove'); + $image.on(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove', function (e) { + if (e && e.originalEvent.touches && e.originalEvent.touches.length >= 2) { + e.preventDefault(); + var currentDimention = getDimention(e.originalEvent); + + if ($image.hasClass(imageDraggableClass)) { + $image.removeClass(imageDraggableClass); + } + if (currentDimention < pinchDimention) { + zoomOut(e); + pinchDimention = currentDimention; + } else if (currentDimention > pinchDimention) { + zoomIn(e); + pinchDimention = currentDimention; + } + } else { + var clientX, + clientY; + + if (gallery.fullScreen && isDragActive) { + + if (allowZoomOut && !$image.hasClass(imageDraggableClass)) { + $image.addClass(imageDraggableClass); + } + clientX = e.clientX || e.originalEvent.clientX; + clientY = e.clientY || e.originalEvent.clientY; + + e.preventDefault(); + + if (isTouchEnabled) { + touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; + clientX = touch.pageX; + clientY = touch.pageY; + } + + shiftImage(clientX - startX, clientY - startY, e); + } + } + }); + + $image.off('transitionend webkitTransitionEnd'); + $image.on('transitionend webkitTransitionEnd', function () { + transitionActive = false; + }); + + if (keyboardNavigation) { + $(document).unbind('keydown', keyboardNavigation); + } + + /** + * Replaces original navigations with better one + * @param e - event object + */ + keyboardNavigation = function (e) { + var step = 40, + $focus = $(':focus'), + isFullScreen = $(gallerySelector).data('fotorama').fullScreen, + initVars = function () { + imagePosX = $(fullscreenImageSelector, $gallery).offset().left; + imagePosY = $(fullscreenImageSelector, $gallery).offset().top; + }; + + if (($focus.attr('data-gallery-role') || !$focus.length) && allowZoomOut) { + if (isFullScreen) { + imagePosX = $(fullscreenImageSelector, $(gallerySelector)).offset().left; + imagePosY = $(fullscreenImageSelector, $(gallerySelector)).offset().top; + } + + if (e.keyCode === 39) { + + if (isFullScreen) { + initVars(); + shiftImage(-step, 0, e); + } + } + + if (e.keyCode === 38) { + + if (isFullScreen) { + initVars(); + shiftImage(0, step, e); + } + } + + if (e.keyCode === 37) { + + if (isFullScreen) { + initVars(); + shiftImage(step, 0, e); + } + } + + if (e.keyCode === 40) { + + if (isFullScreen) { + e.preventDefault(); + initVars(); + shiftImage(0, -step, e); + } + } + } + + if (e.keyCode === 27 && isFullScreen && allowZoomOut) { + $(gallerySelector).data('fotorama').cancelFullScreen(); + } + }; + + /** + * @todo keyboard navigation through Fotorama Api. + */ + $(document).keydown(keyboardNavigation); + + $(document).on(isTouchEnabled ? 'touchend' : 'mouseup pointerup MSPointerUp', function (e) { + if (gallery.fullScreen) { + + if ($image.offset() && $image.width() > $imageContainer.width()) { + endX = $image.offset().left; + } + + isDragActive = false; + $image.removeClass(imageDraggableClass); + } + }); + + $(window).resize(function () { + var imageSize = getImageSize($(fullscreenImageSelector)[0].src), + isImageSmall = + $(fullscreenImageSelector).parent().width() >= imageSize.rw && + $(fullscreenImageSelector).parent().height() >= imageSize.rh; + + toggleZoomButtons($image, isTouchEnabled, checkForVideo(fotorama.activeFrame.$stageFrame)); + calculateMinSize($image); + + if ($image.hasClass(imageZoommable) && !allowZoomOut || isImageSmall) { + resetVars($image); + } + + if (!isImageSmall) { + toggleStandartNavigation(); + } + }); + } + /** * Hides magnifier preview and zoom blocks. */ @@ -33,26 +817,36 @@ define([ $(magnifierZoomSelector).remove(); }; + /** + * Check is active frame in gallery include video content. + * If true activeFrame contain video. + * @param $stageFrame - active frame in gallery + * @returns {*|Boolean} + */ + function checkForVideo($stageFrame) { + return $stageFrame.hasClass(videoContainerClass); + } + /** * Hides magnifier on drag and while arrow click. */ - behaveOnHover = function (e, initPos) { + function behaveOnDrag(e, initPos) { var pos = [e.pageX, e.pageY], isArrow = $(e.target).data('gallery-role') === 'arrow', - isClick = initPos[0] === pos[0] && initPos[1] === pos[1]; - if (isArrow || !isClick) { + isClick = initPos[0] === pos[0] && initPos[1] === pos[1], + isImg = $(e.target).parent().data('active'); + + if (isArrow || isImg && !isClick) { hideMagnifier(); } - }; + } - if (config.magnifierOpts.eventType === 'click') { - config.options.swipe = false; - } else if (config.magnifierOpts.eventType === 'hover') { + if (config.magnifierOpts.enabled) { $(element).on('pointerdown mousedown MSPointerDown', function (e) { var pos = [e.pageX, e.pageY]; $(element).on('mousemove pointermove MSPointerMove', function (ev) { - navigator.msPointerEnabled ? hideMagnifier() : behaveOnHover(ev, pos); + navigator.msPointerEnabled ? hideMagnifier() : behaveOnDrag(ev, pos); }); $(document).on('mouseup pointerup MSPointerUp', function () { $(element).off('mousemove pointermove MSPointerMove'); @@ -62,7 +856,7 @@ define([ $.extend(config.magnifierOpts, { zoomable: false, - thumb: '.fotorama__img:not(".fotorama__img--full")', + thumb: '.fotorama__img', largeWrapper: '[data-gallery-role="magnifier"]', height: config.magnifierOpts.height || function () { return $('[data-active="true"]').height(); @@ -80,16 +874,109 @@ define([ } }); - $(element).on('fotorama:showend fotorama:load fotorama:fullscreenexit fotorama:ready', function (e, fotorama) { - hideMagnifier(); - config.magnifierOpts.large = $(gallerySelector).data('fotorama').activeFrame.img; - config.magnifierOpts.full = fotorama.data[fotorama.activeIndex].full; - $($(gallerySelector).data('fotorama').activeFrame.$stageFrame).magnify(config.magnifierOpts); - }); - $(element).on('gallery:loaded', function () { - $(element).find(gallerySelector).on('fotorama:show fotorama:fullscreenenter ', function () { + $(element).on('fotorama:load fotorama:showend fotorama:fullscreenexit fotorama:ready', function (e, fotorama) { + var $activeStageFrame = $(gallerySelector).data('fotorama').activeFrame.$stageFrame; + + if (!$activeStageFrame.find(magnifierZoomSelector).length) { hideMagnifier(); - }); + + if (config.magnifierOpts) { + config.magnifierOpts.large = $(gallerySelector).data('fotorama').activeFrame.img; + config.magnifierOpts.full = fotorama.data[fotorama.activeIndex].original; + !checkForVideo($activeStageFrame) && $($activeStageFrame).magnify(config.magnifierOpts); + } + } + }); + + $(element).on('gallery:loaded', function (e) { + var $prevImage; + + $(element).find(gallerySelector) + .on('fotorama:ready', function (e, fotorama) { + var $zoomIn = $(zoomInButtonSelector), + $zoomOut = $(zoomOutButtonSelector); + + if (!$zoomIn.hasClass(zoomInLoaded)) { + $zoomIn.on('click touchstart', zoomIn); + $zoomIn.on('mousedown', function(e) { + e.stopPropagation(); + }); + + $zoomIn.keyup(function (e) { + + if (e.keyCode === 13) { + zoomIn(e); + } + }); + + $(window).keyup(function (e) { + + if (e.keyCode === 107 || fotorama.fullscreen) { + zoomIn(e); + } + }); + + $zoomIn.addClass(zoomInLoaded); + } + + if (!$zoomOut.hasClass(zoomOutLoaded)) { + $zoomOut.on('click touchstart', zoomOut); + $zoomOut.on('mousedown', function(e) { + e.stopPropagation(); + }); + + $zoomOut.keyup(function (e) { + + if (e.keyCode === 13) { + zoomOut(e); + } + }); + + $(window).keyup(function (e) { + + if (e.keyCode === 109 || fotorama.fullscreen) { + zoomOut(e); + } + }); + + $zoomOut.addClass(zoomOutLoaded); + } + }) + .on('fotorama:fullscreenenter fotorama:showend', function (e, fotorama) { + hideMagnifier(); + + if (!$(fullscreenImageSelector).is($prevImage)) { + resetVars($(fullscreenImageSelector)); + } + magnifierFullscreen(fotorama); + mousewheel(e, fotorama, element); + + if ($prevImage) { + calculateMinSize($prevImage); + + if (!$(fullscreenImageSelector).is($prevImage)) { + resetVars($prevImage); + } + } + + toggleStandartNavigation(); + }) + .on('fotorama:load', function (e, fotorama) { + if ($(gallerySelector).data('fotorama').fullScreen) { + toggleZoomButtons($(fullscreenImageSelector), isTouchEnabled, + checkForVideo(fotorama.activeFrame.$stageFrame)); + } + magnifierFullscreen(fotorama); + }) + .on('fotorama:show', function (e, fotorama) { + $prevImage = _.clone($(fullscreenImageSelector)); + hideMagnifier(); + }) + .on('fotorama:fullscreenexit', function (e, fotorama) { + resetVars($(fullscreenImageSelector)); + hideMagnifier(); + hideZoomControls(true); + }); }); return config;