您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

1007 行
39 KiB

  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. define([
  6. 'jquery',
  7. 'underscore',
  8. 'magnifier/magnifier'
  9. ], function ($, _) {
  10. 'use strict';
  11. return function (config, element) {
  12. var isTouchEnabled = 'ontouchstart' in document.documentElement,
  13. gallerySelector = '[data-gallery-role="gallery"]',
  14. magnifierSelector = '[data-gallery-role="magnifier"]',
  15. magnifierZoomSelector = '[data-gallery-role="magnifier-zoom"]',
  16. zoomInButtonSelector = '[data-gallery-role="fotorama__zoom-in"]',
  17. zoomOutButtonSelector = '[data-gallery-role="fotorama__zoom-out"]',
  18. fullscreenImageSelector = '[data-gallery-role="stage-shaft"] [data-active="true"] .fotorama__img--full',
  19. imageDraggableClass = 'fotorama__img--draggable',
  20. imageZoommable = 'fotorama__img--zoommable',
  21. zoomInLoaded = 'zoom-in-loaded',
  22. zoomOutLoaded = 'zoom-out-loaded',
  23. zoomInDisabled = 'fotorama__zoom-in--disabled',
  24. zoomOutDisabled = 'fotorama__zoom-out--disabled',
  25. keyboardNavigation,
  26. videoContainerClass = 'fotorama-video-container',
  27. hideMagnifier,
  28. dragFlag,
  29. endX,
  30. transitionEnabled,
  31. transitionActive = false,
  32. tapFlag = 0,
  33. allowZoomOut = false,
  34. allowZoomIn = true;
  35. transitionEnabled = document.documentElement.style.transition !== undefined ||
  36. document.documentElement.style.WebkitTransition !== undefined ||
  37. document.documentElement.style.MozTransition !== undefined ||
  38. document.documentElement.style.MsTransition !== undefined ||
  39. document.documentElement.style.OTransition !== undefined;
  40. /**
  41. * Return width and height of original image
  42. * @param img original image node
  43. * @returns {{rw: number, rh: number}}
  44. */
  45. function getImageSize(img) {
  46. return {
  47. rw: img.naturalWidth,
  48. rh: img.naturalHeight
  49. };
  50. }
  51. /**
  52. * Sets min-height and min-width for image to avoid transition bug
  53. * @param $image - fullscreen image
  54. */
  55. function calculateMinSize($image) {
  56. var minHeight,
  57. minWidth,
  58. height = $image.height(),
  59. width = $image.width(),
  60. parentHeight = $image.parent().height(),
  61. parentWidth = $image.parent().width();
  62. if (width > parentWidth || height > parentHeight) {
  63. if (width / height < parentWidth / parentHeight) {
  64. minHeight = parentHeight;
  65. minWidth = width * (parentHeight / height);
  66. } else {
  67. minWidth = parentWidth;
  68. minHeight = height * parentWidth / width;
  69. }
  70. $image.css({
  71. 'min-width': minWidth,
  72. 'min-height': minHeight
  73. });
  74. }
  75. }
  76. function toggleZoomable($image, flag) {
  77. if (flag) {
  78. $image.css({
  79. 'min-width': $image.width(),
  80. 'min-height': $image.height(),
  81. 'width': $image.width(),
  82. 'height': $image.height()
  83. }).addClass(imageZoommable);
  84. } else {
  85. $image.css({
  86. width: '',
  87. height: '',
  88. top: '',
  89. left: '',
  90. right: '',
  91. bottom: ''
  92. }).removeClass(imageZoommable);
  93. calculateMinSize($image);
  94. }
  95. }
  96. function resetVars($image) {
  97. allowZoomIn = true;
  98. allowZoomOut = dragFlag = transitionActive = false;
  99. $image.hasClass(imageDraggableClass) && $image.removeClass(imageDraggableClass);
  100. toggleZoomable($image, false);
  101. }
  102. /**
  103. * Set state for zoom controls.
  104. * If state is true, zoom controls will be visible.
  105. * IF state is false, zoom controls will be hidden.
  106. * @param isHide
  107. */
  108. function hideZoomControls(isHide) {
  109. if (isHide) {
  110. $(zoomInButtonSelector).addClass(zoomInDisabled);
  111. $(zoomOutButtonSelector).addClass(zoomOutDisabled);
  112. } else {
  113. $(zoomInButtonSelector).removeClass(zoomInDisabled);
  114. $(zoomOutButtonSelector).removeClass(zoomOutDisabled);
  115. }
  116. }
  117. /**
  118. * Asynchronus control visibility of zoom buttons.
  119. * If image bigger than her wrapper. Zoom controls must visible.
  120. * @param path - image source path
  121. * @param $image
  122. */
  123. function asyncToggleZoomButtons(path, $image) {
  124. var img = new Image();
  125. img.onload = function () {
  126. this.height > $image.parent().height() || this.width > $image.parent().width() ?
  127. hideZoomControls(false) : hideZoomControls(true);
  128. };
  129. img.src = path;
  130. }
  131. /**
  132. * Control visibility of zoom buttons.
  133. * Zoom controls must be invisible for video content and touch devices.
  134. * On touch devices active pinchIn/pinchOut.
  135. * @param $image
  136. * @param isTouchScreen - true for touch devices
  137. * @param isVideoActiveFrame - true for active video frame
  138. */
  139. function toggleZoomButtons($image, isTouchScreen, isVideoActiveFrame) {
  140. var path = $image.attr('src');
  141. if (path && !isTouchScreen && !isVideoActiveFrame) {
  142. asyncToggleZoomButtons(path, $image);
  143. } else {
  144. hideZoomControls(true);
  145. }
  146. }
  147. /**
  148. * Handle resize event in fullscreen.
  149. * @param $image - Fullscreen image.
  150. * @param e - Event.
  151. */
  152. function resizeHandler(e, $image) {
  153. var imageSize,
  154. parentWidth,
  155. parentHeight,
  156. isImageSmall,
  157. isImageFit;
  158. if (!e.data.$image || !e.data.$image.length)
  159. return;
  160. imageSize = getImageSize($(fullscreenImageSelector)[0]);
  161. parentWidth = e.data.$image.parent().width();
  162. parentHeight = e.data.$image.parent().height();
  163. isImageSmall = parentWidth >= imageSize.rw && parentHeight >= imageSize.rh;
  164. isImageFit = parentWidth > e.data.$image.width() && parentHeight > e.data.$image.height();
  165. toggleZoomButtons(e.data.$image, isTouchEnabled, checkForVideo(e.data.fotorama.activeFrame.$stageFrame));
  166. calculateMinSize(e.data.$image);
  167. if (e.data.$image.hasClass(imageZoommable) && !allowZoomOut || isImageSmall || isImageFit) {
  168. resetVars(e.data.$image);
  169. }
  170. if (!isImageSmall) {
  171. toggleStandartNavigation();
  172. }
  173. }
  174. function getTopValue($image, topProp, step, height, containerHeight) {
  175. var top;
  176. if (parseInt($image.css('marginTop')) || parseInt($image.css('marginLeft'))) {
  177. top = dragFlag ? topProp - step / 4 : 0;
  178. top = top < containerHeight - height ? containerHeight - height : top;
  179. top = top > height - containerHeight ? height - containerHeight : top;
  180. } else {
  181. top = topProp + step / 2;
  182. top = top < containerHeight - height ? containerHeight - height : top;
  183. top = top > 0 ? 0 : top;
  184. if (!dragFlag && step < 0) {
  185. top = top < (containerHeight - height) / 2 ? (containerHeight - height) / 2 : top;
  186. }
  187. }
  188. return top;
  189. }
  190. function getLeftValue(leftProp, step, width, containerWidth) {
  191. var left;
  192. left = leftProp + step / 2;
  193. left = left < containerWidth - width ? containerWidth - width : left;
  194. left = left > 0 ? 0 : left;
  195. if (!dragFlag && step < 0) {
  196. left = left < (containerWidth - width) / 2 ? (containerWidth - width) / 2 : left;
  197. }
  198. return left;
  199. }
  200. function checkFullscreenImagePosition($image, dimentions, widthStep, heightStep) {
  201. var $imageContainer,
  202. containerWidth,
  203. containerHeight,
  204. settings,
  205. top,
  206. left,
  207. right,
  208. bottom,
  209. ratio;
  210. if ($(gallerySelector).data('fotorama').fullScreen) {
  211. transitionActive = true;
  212. $imageContainer = $image.parent();
  213. containerWidth = $imageContainer.width();
  214. containerHeight = $imageContainer.height();
  215. top = $image.position().top;
  216. left = $image.position().left;
  217. ratio = $image.width() / $image.height();
  218. dimentions.height = isNaN(dimentions.height) ? dimentions.width / ratio : dimentions.height;
  219. dimentions.width = isNaN(dimentions.width) ? dimentions.height * ratio : dimentions.width;
  220. top = dimentions.height >= containerHeight ?
  221. getTopValue($image, top, heightStep, dimentions.height, containerHeight) : 0;
  222. left = dimentions.width >= containerWidth ?
  223. getLeftValue(left, widthStep, dimentions.width, containerWidth) : 0;
  224. right = dragFlag && left < (containerWidth - dimentions.width) / 2 ? 0 : left;
  225. bottom = dragFlag ? 0 : top;
  226. settings = $.extend(dimentions, {
  227. top: top,
  228. left: left,
  229. right: right
  230. });
  231. $image.css(settings);
  232. }
  233. }
  234. /**
  235. * Toggles fotorama's keyboard and mouse/touch navigation.
  236. */
  237. function toggleStandartNavigation() {
  238. var $selectable =
  239. $('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]')
  240. .not('[tabindex=-1], [disabled], :hidden'),
  241. fotorama = $(gallerySelector).data('fotorama'),
  242. $focus = $(':focus'),
  243. index;
  244. if (fotorama.fullScreen) {
  245. $selectable.each(function (number) {
  246. if ($(this).is($focus)) {
  247. index = number;
  248. }
  249. });
  250. fotorama.setOptions({
  251. swipe: !allowZoomOut,
  252. keyboard: !allowZoomOut
  253. });
  254. if (_.isNumber(index)) {
  255. $selectable.eq(index).trigger('focus');
  256. }
  257. }
  258. }
  259. function zoomIn(e, xStep, yStep) {
  260. var $image,
  261. imgOriginalSize,
  262. imageWidth,
  263. imageHeight,
  264. zoomWidthStep,
  265. zoomHeightStep,
  266. widthResult,
  267. heightResult,
  268. ratio,
  269. dimentions = {};
  270. if (allowZoomIn && (!transitionEnabled || !transitionActive) && (isTouchEnabled ||
  271. !$(zoomInButtonSelector).hasClass(zoomInDisabled))) {
  272. $image = $(fullscreenImageSelector);
  273. imgOriginalSize = getImageSize($image[0]);
  274. imageWidth = $image.width();
  275. imageHeight = $image.height();
  276. ratio = imageWidth / imageHeight;
  277. allowZoomOut = true;
  278. toggleStandartNavigation();
  279. if (!$image.hasClass(imageZoommable)) {
  280. toggleZoomable($image, true);
  281. }
  282. e.preventDefault();
  283. if (imageWidth >= imageHeight) {
  284. zoomWidthStep = xStep || Math.ceil(imageWidth * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);
  285. widthResult = imageWidth + zoomWidthStep;
  286. if (widthResult >= imgOriginalSize.rw) {
  287. widthResult = imgOriginalSize.rw;
  288. zoomWidthStep = xStep || widthResult - imageWidth;
  289. allowZoomIn = false;
  290. }
  291. heightResult = widthResult / ratio;
  292. zoomHeightStep = yStep || heightResult - imageHeight;
  293. } else {
  294. zoomHeightStep = yStep || Math.ceil(imageHeight * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);
  295. heightResult = imageHeight + zoomHeightStep;
  296. if (heightResult >= imgOriginalSize.rh) {
  297. heightResult = imgOriginalSize.rh;
  298. zoomHeightStep = yStep || heightResult - imageHeight;
  299. allowZoomIn = false;
  300. }
  301. widthResult = heightResult * ratio;
  302. zoomWidthStep = xStep || widthResult - imageWidth;
  303. }
  304. if (imageWidth >= imageHeight && imageWidth !== imgOriginalSize.rw) {
  305. dimentions = $.extend(dimentions, {
  306. width: widthResult,
  307. height: 'auto'
  308. });
  309. checkFullscreenImagePosition($image, dimentions, -zoomWidthStep, -zoomHeightStep);
  310. } else if (imageWidth < imageHeight && imageHeight !== imgOriginalSize.rh) {
  311. dimentions = $.extend(dimentions, {
  312. width: 'auto',
  313. height: heightResult
  314. });
  315. checkFullscreenImagePosition($image, dimentions, -zoomWidthStep, -zoomHeightStep);
  316. }
  317. }
  318. return false;
  319. }
  320. function zoomOut(e, xStep, yStep) {
  321. var $image,
  322. widthResult,
  323. heightResult,
  324. dimentions,
  325. parentWidth,
  326. parentHeight,
  327. imageWidth,
  328. imageHeight,
  329. zoomWidthStep,
  330. zoomHeightStep,
  331. ratio,
  332. fitIntoParent;
  333. if (allowZoomOut && (!transitionEnabled || !transitionActive) && (isTouchEnabled ||
  334. !$(zoomOutButtonSelector).hasClass(zoomOutDisabled))) {
  335. allowZoomIn = true;
  336. $image = $(fullscreenImageSelector);
  337. parentWidth = $image.parent().width();
  338. parentHeight = $image.parent().height();
  339. imageWidth = $image.width();
  340. imageHeight = $image.height();
  341. ratio = imageWidth / imageHeight;
  342. e.preventDefault();
  343. if (imageWidth >= imageHeight) {
  344. zoomWidthStep = xStep || Math.ceil(imageWidth * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);
  345. widthResult = imageWidth - zoomWidthStep;
  346. heightResult = widthResult / ratio;
  347. zoomHeightStep = yStep || imageHeight - heightResult;
  348. } else {
  349. zoomHeightStep = yStep || Math.ceil(imageHeight * parseFloat(config.magnifierOpts.fullscreenzoom) / 100);
  350. heightResult = imageHeight - zoomHeightStep;
  351. widthResult = heightResult * ratio;
  352. zoomWidthStep = xStep || imageWidth - widthResult;
  353. }
  354. fitIntoParent = function () {
  355. if (ratio > parentWidth / parentHeight) {
  356. widthResult = parentWidth;
  357. zoomWidthStep = imageWidth - widthResult;
  358. heightResult = widthResult / ratio;
  359. zoomHeightStep = imageHeight - heightResult;
  360. dimentions = {
  361. width: widthResult,
  362. height: 'auto'
  363. };
  364. } else {
  365. heightResult = parentHeight;
  366. zoomHeightStep = imageHeight - heightResult;
  367. widthResult = heightResult * ratio;
  368. zoomWidthStep = imageWidth - widthResult;
  369. dimentions = {
  370. width: 'auto',
  371. height: heightResult
  372. };
  373. }
  374. checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);
  375. };
  376. if (imageWidth >= imageHeight) {
  377. if (widthResult > parentWidth) {
  378. dimentions = {
  379. width: widthResult,
  380. height: 'auto'
  381. };
  382. checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);
  383. } else if (heightResult > parentHeight) {
  384. dimentions = {
  385. width: widthResult,
  386. height: 'auto'
  387. };
  388. checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);
  389. } else {
  390. allowZoomOut = dragFlag = false;
  391. toggleStandartNavigation();
  392. fitIntoParent();
  393. }
  394. } else if (heightResult > parentHeight) {
  395. dimentions = {
  396. width: 'auto',
  397. height: heightResult
  398. };
  399. checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);
  400. } else if (widthResult > parentWidth) {
  401. dimentions = {
  402. width: 'auto',
  403. height: heightResult
  404. };
  405. checkFullscreenImagePosition($image, dimentions, zoomWidthStep, zoomHeightStep);
  406. } else {
  407. allowZoomOut = dragFlag = false;
  408. toggleStandartNavigation();
  409. fitIntoParent();
  410. }
  411. }
  412. return false;
  413. }
  414. /**
  415. * Bind event on scroll on active item in fotorama
  416. * @param e
  417. * @param fotorama - object of fotorama
  418. */
  419. function mousewheel(e, fotorama, element) {
  420. var $fotoramaStage = fotorama.activeFrame.$stageFrame,
  421. fotoramaStage = $fotoramaStage.get(0);
  422. function onWheel(e) {
  423. var delta = e.deltaY || e.wheelDelta,
  424. ev = e || window.event;
  425. if ($(gallerySelector).data('fotorama').fullScreen) {
  426. if (e.deltaY) {
  427. if (delta > 0) {
  428. zoomOut(ev);
  429. } else {
  430. zoomIn(ev);
  431. }
  432. } else if (delta > 0) {
  433. zoomIn(ev);
  434. } else {
  435. zoomOut(ev);
  436. }
  437. e.preventDefault ? e.preventDefault() : e.returnValue = false;
  438. }
  439. }
  440. if (!$fotoramaStage.hasClass('magnify-wheel-loaded')) {
  441. if (fotoramaStage && fotoramaStage.addEventListener) {
  442. if ('onwheel' in document) {
  443. fotoramaStage.addEventListener('wheel', onWheel, { passive: true });
  444. } else if ('onmousewheel' in document) {
  445. fotoramaStage.addEventListener('mousewheel', onWheel);
  446. } else {
  447. fotoramaStage.addEventListener('MozMousePixelScroll', onWheel);
  448. }
  449. $fotoramaStage.addClass('magnify-wheel-loaded');
  450. }
  451. }
  452. }
  453. /**
  454. * Method which makes draggable picture. Also work on touch devices.
  455. */
  456. function magnifierFullscreen(fotorama) {
  457. var isDragActive = false,
  458. startX,
  459. startY,
  460. imagePosX,
  461. imagePosY,
  462. touch,
  463. swipeSlide,
  464. $gallery = $(gallerySelector),
  465. $image = $(fullscreenImageSelector, $gallery),
  466. $imageContainer = $('[data-gallery-role="stage-shaft"] [data-active="true"]'),
  467. gallery = $gallery.data('fotorama'),
  468. pinchDimention;
  469. swipeSlide = _.throttle(function (direction) {
  470. $(gallerySelector).data('fotorama').show(direction);
  471. }, 500, {
  472. trailing: false
  473. });
  474. /**
  475. * Returns top position value for passed jQuery object.
  476. *
  477. * @param $el
  478. * @return {number}
  479. */
  480. function getTop($el) {
  481. return parseInt($el.get(0).style.top);
  482. }
  483. function shiftImage(dx, dy, e) {
  484. var top = +imagePosY + dy,
  485. left = +imagePosX + dx,
  486. swipeCondition = $image.width() / 10 + 20;
  487. dragFlag = true;
  488. if ($image.offset().left === $imageContainer.offset().left + $imageContainer.width() - $image.width() && e.keyCode === 39 ||
  489. endX - 1 < $imageContainer.offset().left + $imageContainer.width() - $image.width() && dx < 0 &&
  490. _.isNumber(endX) &&
  491. (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove')) {
  492. endX = null;
  493. swipeSlide('>');
  494. return;
  495. }
  496. if ($image.offset().left === $imageContainer.offset().left && dx !== 0 && e.keyCode === 37 ||
  497. endX === $imageContainer.offset().left && dx > 0 &&
  498. (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove')) {
  499. endX = null;
  500. swipeSlide('<');
  501. return;
  502. }
  503. if ($image.height() > $imageContainer.height()) {
  504. if ($imageContainer.height() > $image.height() + top) {
  505. $image.css('top', $imageContainer.height() - $image.height());
  506. } else {
  507. top = $image.height() - getTop($image) - $imageContainer.height();
  508. dy = dy < top ? dy : top;
  509. $image.css('top', getTop($image) + dy);
  510. }
  511. }
  512. if ($image.width() > $imageContainer.width()) {
  513. if ($imageContainer.offset().left + $imageContainer.width() > left + $image.width()) {
  514. left = $imageContainer.offset().left + $imageContainer.width() - $image.width();
  515. } else {
  516. left = $imageContainer.offset().left < left ? $imageContainer.offset().left : left;
  517. }
  518. $image.offset({
  519. 'left': left
  520. });
  521. $image.css('right', '');
  522. } else if (Math.abs(dy) < 1 && allowZoomOut &&
  523. !(e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove')) {
  524. dx < 0 ? $(gallerySelector).data('fotorama').show('>') : $(gallerySelector).data('fotorama').show('<');
  525. }
  526. if ($image.width() <= $imageContainer.width() && allowZoomOut &&
  527. (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'pointermove' || e.type === 'MSPointerMove') &&
  528. Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > swipeCondition) {
  529. dx < 0 ? swipeSlide('>') : swipeSlide('<');
  530. }
  531. }
  532. /**
  533. * Sets image size to original or fit in parent block
  534. * @param e - event object
  535. */
  536. function dblClickHandler(e) {
  537. var imgOriginalSize = getImageSize($image[0]),
  538. proportions;
  539. if (imgOriginalSize.rh < $image.parent().height() && imgOriginalSize.rw < $image.parent().width()) {
  540. return;
  541. }
  542. proportions = imgOriginalSize.rw / imgOriginalSize.rh;
  543. if (allowZoomIn) {
  544. zoomIn(e, imgOriginalSize.rw - $image.width(), imgOriginalSize.rh - $image.height());
  545. } else if (proportions > $imageContainer.width() / $imageContainer.height()) {
  546. zoomOut(e, imgOriginalSize.rw - $imageContainer.width(), imgOriginalSize.rw / proportions);
  547. } else {
  548. zoomOut(e, imgOriginalSize.rw * proportions, imgOriginalSize.rh - $imageContainer.height());
  549. }
  550. }
  551. function detectDoubleTap(e) {
  552. var now = new Date().getTime(),
  553. timesince = now - tapFlag;
  554. if (timesince < 400 && timesince > 0) {
  555. transitionActive = false;
  556. tapFlag = 0;
  557. dblClickHandler(e);
  558. } else {
  559. tapFlag = new Date().getTime();
  560. }
  561. }
  562. if (isTouchEnabled) {
  563. $image.off('tap');
  564. $image.on('tap', function (e) {
  565. if (e.originalEvent.originalEvent.touches.length === 0) {
  566. detectDoubleTap(e);
  567. }
  568. });
  569. } else {
  570. $image.off('dblclick');
  571. $image.on('dblclick', dblClickHandler);
  572. }
  573. if (gallery.fullScreen) {
  574. toggleZoomButtons($image, isTouchEnabled, checkForVideo(fotorama.activeFrame.$stageFrame));
  575. }
  576. function getDimention(event) {
  577. return Math.sqrt(
  578. (event.touches[0].clientX - event.touches[1].clientX) * (event.touches[0].clientX - event.touches[1].clientX) +
  579. (event.touches[0].clientY - event.touches[1].clientY) * (event.touches[0].clientY - event.touches[1].clientY));
  580. }
  581. $image.off(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown');
  582. $image.on(isTouchEnabled ? 'touchstart' : 'pointerdown mousedown MSPointerDown', function (e) {
  583. if (e && e.originalEvent.touches && e.originalEvent.touches.length >= 2) {
  584. e.preventDefault();
  585. pinchDimention = getDimention(e.originalEvent);
  586. isDragActive = false;
  587. if ($image.hasClass(imageDraggableClass)) {
  588. $image.removeClass(imageDraggableClass);
  589. }
  590. } else if (gallery.fullScreen && (!transitionEnabled || !transitionActive)) {
  591. imagePosY = getTop($image);
  592. imagePosX = $image.offset().left;
  593. if (isTouchEnabled) {
  594. touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
  595. e.clientX = touch.pageX;
  596. e.clientY = touch.pageY;
  597. }
  598. startX = e.clientX || e.originalEvent.clientX;
  599. startY = e.clientY || e.originalEvent.clientY;
  600. isDragActive = true;
  601. }
  602. if ($image.offset() && $image.width() > $imageContainer.width()) {
  603. endX = $image.offset().left;
  604. }
  605. });
  606. $image.off(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove');
  607. $image.on(isTouchEnabled ? 'touchmove' : 'mousemove pointermove MSPointerMove', function (e) {
  608. if (e && e.originalEvent.touches && e.originalEvent.touches.length >= 2) {
  609. e.preventDefault();
  610. var currentDimention = getDimention(e.originalEvent);
  611. if ($image.hasClass(imageDraggableClass)) {
  612. $image.removeClass(imageDraggableClass);
  613. }
  614. if (currentDimention < pinchDimention) {
  615. zoomOut(e);
  616. pinchDimention = currentDimention;
  617. } else if (currentDimention > pinchDimention) {
  618. zoomIn(e);
  619. pinchDimention = currentDimention;
  620. }
  621. } else {
  622. var clientX,
  623. clientY;
  624. if (gallery.fullScreen && isDragActive && (!transitionEnabled || !transitionActive)) {
  625. if (allowZoomOut && !$image.hasClass(imageDraggableClass)) {
  626. $image.addClass(imageDraggableClass);
  627. }
  628. clientX = e.clientX || e.originalEvent.clientX;
  629. clientY = e.clientY || e.originalEvent.clientY;
  630. e.preventDefault();
  631. if (isTouchEnabled) {
  632. touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
  633. clientX = touch.pageX;
  634. clientY = touch.pageY;
  635. }
  636. if (allowZoomOut) {
  637. imagePosY = getTop($(fullscreenImageSelector, $gallery));
  638. shiftImage(clientX - startX, clientY - startY, e);
  639. }
  640. }
  641. }
  642. });
  643. $image.off('transitionend webkitTransitionEnd mozTransitionEnd msTransitionEnd ');
  644. $image.on('transitionend webkitTransitionEnd mozTransitionEnd msTransitionEnd', function () {
  645. transitionActive = false;
  646. });
  647. if (keyboardNavigation) {
  648. $(document).off('keydown', keyboardNavigation);
  649. }
  650. /**
  651. * Replaces original navigations with better one
  652. * @param e - event object
  653. */
  654. keyboardNavigation = function (e) {
  655. var step = 40,
  656. $focus = $(':focus'),
  657. isFullScreen = $(gallerySelector).data('fotorama').fullScreen,
  658. initVars = function () {
  659. imagePosX = $(fullscreenImageSelector, $gallery).offset().left;
  660. imagePosY = getTop($(fullscreenImageSelector, $gallery));
  661. };
  662. if (($focus.attr('data-gallery-role') || !$focus.length) && allowZoomOut) {
  663. if (isFullScreen) {
  664. imagePosX = $(fullscreenImageSelector, $(gallerySelector)).offset().left;
  665. imagePosY = getTop($(fullscreenImageSelector, $(gallerySelector)));
  666. }
  667. if (e.keyCode === 39) {
  668. if (isFullScreen) {
  669. initVars();
  670. shiftImage(-step, 0, e);
  671. }
  672. }
  673. if (e.keyCode === 38) {
  674. if (isFullScreen) {
  675. initVars();
  676. shiftImage(0, step, e);
  677. }
  678. }
  679. if (e.keyCode === 37) {
  680. if (isFullScreen) {
  681. initVars();
  682. shiftImage(step, 0, e);
  683. }
  684. }
  685. if (e.keyCode === 40) {
  686. if (isFullScreen) {
  687. e.preventDefault();
  688. initVars();
  689. shiftImage(0, -step, e);
  690. }
  691. }
  692. }
  693. if (e.keyCode === 27 && isFullScreen && allowZoomOut) {
  694. $(gallerySelector).data('fotorama').cancelFullScreen();
  695. }
  696. };
  697. /**
  698. * @todo keyboard navigation through Fotorama Api.
  699. */
  700. $(document).on('keydown', keyboardNavigation);
  701. $(document).on(isTouchEnabled ? 'touchend' : 'mouseup pointerup MSPointerUp', function (e) {
  702. if (gallery.fullScreen) {
  703. if ($image.offset() && $image.width() > $imageContainer.width()) {
  704. endX = $image.offset().left;
  705. }
  706. isDragActive = false;
  707. $image.removeClass(imageDraggableClass);
  708. }
  709. });
  710. $(window).off('resize', resizeHandler);
  711. $(window).on('resize', {
  712. $image: $image,
  713. fotorama: fotorama
  714. }, resizeHandler);
  715. }
  716. /**
  717. * Hides magnifier preview and zoom blocks.
  718. */
  719. hideMagnifier = function () {
  720. $(magnifierSelector).empty().hide();
  721. $(magnifierZoomSelector).remove();
  722. };
  723. /**
  724. * Check is active frame in gallery include video content.
  725. * If true activeFrame contain video.
  726. * @param $stageFrame - active frame in gallery
  727. * @returns {*|Boolean}
  728. */
  729. function checkForVideo($stageFrame) {
  730. return $stageFrame.hasClass(videoContainerClass);
  731. }
  732. /**
  733. * Hides magnifier on drag and while arrow click.
  734. */
  735. function behaveOnDrag(e, initPos) {
  736. var pos = [e.pageX, e.pageY],
  737. isArrow = $(e.target).data('gallery-role') === 'arrow',
  738. isClick = initPos[0] === pos[0] && initPos[1] === pos[1],
  739. isImg = $(e.target).parent().data('active');
  740. if (isArrow || isImg && !isClick) {
  741. hideMagnifier();
  742. }
  743. }
  744. if (config.magnifierOpts.enabled) {
  745. $(element).on('pointerdown mousedown MSPointerDown', function (e) {
  746. var pos = [e.pageX, e.pageY];
  747. $(element).on('mousemove pointermove MSPointerMove', function (ev) {
  748. navigator.msPointerEnabled ? hideMagnifier() : behaveOnDrag(ev, pos);
  749. });
  750. $(document).on('mouseup pointerup MSPointerUp', function () {
  751. $(element).off('mousemove pointermove MSPointerMove');
  752. });
  753. });
  754. }
  755. $.extend(config.magnifierOpts, {
  756. zoomable: false,
  757. thumb: '.fotorama__img',
  758. largeWrapper: '[data-gallery-role="magnifier"]',
  759. height: config.magnifierOpts.height || function () {
  760. return $('[data-active="true"]').height();
  761. },
  762. width: config.magnifierOpts.width || function () {
  763. var productMedia = $(gallerySelector).parent().parent();
  764. return productMedia.parent().width() - productMedia.width() - 20;
  765. },
  766. left: config.magnifierOpts.left || function () {
  767. return $(gallerySelector).offset().left + $(gallerySelector).width() + 20;
  768. },
  769. top: config.magnifierOpts.top || function () {
  770. return $(gallerySelector).offset().top;
  771. }
  772. });
  773. $(element).on('fotorama:load fotorama:showend fotorama:fullscreenexit fotorama:ready', function (e, fotorama) {
  774. var $activeStageFrame = $(gallerySelector).data('fotorama').activeFrame.$stageFrame;
  775. if (!$activeStageFrame.find(magnifierZoomSelector).length) {
  776. hideMagnifier();
  777. if (config.magnifierOpts) {
  778. config.magnifierOpts.large = $(gallerySelector).data('fotorama').activeFrame.img;
  779. config.magnifierOpts.full = fotorama.data[fotorama.activeIndex].original;
  780. !checkForVideo($activeStageFrame) && $($activeStageFrame).magnify(config.magnifierOpts);
  781. }
  782. }
  783. });
  784. $(element).on('gallery:loaded', function (e) {
  785. var $prevImage;
  786. $(element).find(gallerySelector)
  787. .on('fotorama:ready', function (e, fotorama) {
  788. var $zoomIn = $(zoomInButtonSelector),
  789. $zoomOut = $(zoomOutButtonSelector);
  790. if (!$zoomIn.hasClass(zoomInLoaded)) {
  791. $zoomIn.on('click touchstart', zoomIn);
  792. $zoomIn.on('mousedown', function (e) {
  793. e.stopPropagation();
  794. });
  795. $zoomIn.on('keyup', function (e) {
  796. if (e.keyCode === 13) {
  797. zoomIn(e);
  798. }
  799. });
  800. $(window).on('keyup', function (e) {
  801. if (e.keyCode === 107 || fotorama.fullscreen) {
  802. zoomIn(e);
  803. }
  804. });
  805. $zoomIn.addClass(zoomInLoaded);
  806. }
  807. if (!$zoomOut.hasClass(zoomOutLoaded)) {
  808. $zoomOut.on('click touchstart', zoomOut);
  809. $zoomOut.on('mousedown', function (e) {
  810. e.stopPropagation();
  811. });
  812. $zoomOut.on('keyup', function (e) {
  813. if (e.keyCode === 13) {
  814. zoomOut(e);
  815. }
  816. });
  817. $(window).on('keyup', function (e) {
  818. if (e.keyCode === 109 || fotorama.fullscreen) {
  819. zoomOut(e);
  820. }
  821. });
  822. $zoomOut.addClass(zoomOutLoaded);
  823. }
  824. })
  825. .on('fotorama:fullscreenenter fotorama:showend', function (e, fotorama) {
  826. hideMagnifier();
  827. if (!$(fullscreenImageSelector).is($prevImage)) {
  828. resetVars($(fullscreenImageSelector));
  829. }
  830. magnifierFullscreen(fotorama);
  831. mousewheel(e, fotorama, element);
  832. if ($prevImage) {
  833. calculateMinSize($prevImage);
  834. if (!$(fullscreenImageSelector).is($prevImage)) {
  835. resetVars($prevImage);
  836. }
  837. }
  838. toggleStandartNavigation();
  839. })
  840. .on('fotorama:load', function (e, fotorama) {
  841. if ($(gallerySelector).data('fotorama').fullScreen) {
  842. toggleZoomButtons($(fullscreenImageSelector), isTouchEnabled,
  843. checkForVideo(fotorama.activeFrame.$stageFrame));
  844. }
  845. magnifierFullscreen(fotorama);
  846. })
  847. .on('fotorama:show', function (e, fotorama) {
  848. $prevImage = _.clone($(fullscreenImageSelector));
  849. hideMagnifier();
  850. })
  851. .on('fotorama:fullscreenexit', function (e, fotorama) {
  852. resetVars($(fullscreenImageSelector));
  853. hideMagnifier();
  854. hideZoomControls(true);
  855. });
  856. });
  857. return config;
  858. };
  859. });