123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- define([
- 'jquery',
- 'fotorama/fotorama',
- 'underscore',
- 'matchMedia',
- 'mage/template',
- 'text!mage/gallery/gallery.html',
- 'uiClass',
- 'mage/translate'
- ], function ($, fotorama, _, mediaCheck, template, galleryTpl, Class, $t) {
- 'use strict';
- /**
- * Retrieves index if the main item.
- * @param {Array.<Object>} data - Set of gallery items.
- */
- var getMainImageIndex = function (data) {
- var mainIndex;
- if (_.every(data, function (item) {
- return _.isObject(item);
- })
- ) {
- mainIndex = _.findIndex(data, function (item) {
- return item.isMain;
- });
- }
- return mainIndex > 0 ? mainIndex : 0;
- },
- /**
- * Helper for parse translate property
- *
- * @param {Element} el - el that to parse
- * @returns {Array} - array of properties.
- */
- getTranslate = function (el) {
- var slideTransform = $(el).attr('style').split(';');
- slideTransform = $.map(slideTransform, function (style) {
- style = style.trim();
- if (style.startsWith('transform: translate3d')) {
- return style.match(/transform: translate3d\((.+)px,(.+)px,(.+)px\)/);
- }
- return false;
- });
- return slideTransform.filter(Boolean);
- },
- /**
- * @param {*} str
- * @return {*}
- * @private
- */
- _toNumber = function (str) {
- var type = typeof str;
- if (type === 'string') {
- return parseInt(str); //eslint-disable-line radix
- }
- return str;
- };
- return Class.extend({
- defaults: {
- settings: {},
- config: {},
- startConfig: {}
- },
- /**
- * Checks if device has touch interface.
- * @return {Boolean} The result of searching touch events on device.
- */
- isTouchEnabled: (function () {
- return 'ontouchstart' in document.documentElement;
- })(),
- /**
- * Initializes gallery.
- * @param {Object} config - Gallery configuration.
- * @param {String} element - String selector of gallery DOM element.
- */
- initialize: function (config, element) {
- var self = this;
- this._super();
- _.bindAll(this,
- '_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;
- this.settings = {
- $element: $(element),
- $pageWrapper: $('body>.page-wrapper'),
- currentConfig: config,
- defaultConfig: _.clone(config),
- fullscreenConfig: _.clone(config.fullscreen),
- breakpoints: config.breakpoints,
- activeBreakpoint: {},
- fotoramaApi: null,
- isFullscreen: false,
- api: null,
- data: _.clone(config.data)
- };
- config.options.ratio = config.options.width / config.options.height;
- config.options.height = null;
- $.extend(true, this.startConfig, config);
- this.initGallery();
- this.initApi();
- this.setupBreakpoints();
- this.initFullscreenSettings();
- this.settings.$element.on('mouseup', '.fotorama__stage__frame', function () {
- if (
- !$(this).parents('.fotorama__shadows--left, .fotorama__shadows--right').length &&
- !$(this).hasClass('fotorama-video-container')
- ) {
- self.openFullScreen();
- }
- });
- if (this.isTouchEnabled && this.settings.isFullscreen) {
- this.settings.$element.on('tap', '.fotorama__stage__frame', function () {
- var translate = getTranslate($(this).parents('.fotorama__stage__shaft'));
- if (translate[1] === '0' && !$(this).hasClass('fotorama-video-container')) {
- self.openFullScreen();
- self.settings.$pageWrapper.hide();
- }
- });
- }
- },
- /**
- * Open gallery fullscreen
- */
- openFullScreen: function () {
- this.settings.api.fotorama.requestFullScreen();
- this.settings.$fullscreenIcon.css({
- opacity: 1,
- visibility: 'visible',
- display: 'block'
- });
- },
- /**
- * Gallery fullscreen settings.
- */
- initFullscreenSettings: function () {
- var settings = this.settings,
- self = this;
- settings.$gallery = this.settings.$element.find('[data-gallery-role="gallery"]');
- settings.$fullscreenIcon = this.settings.$element.find('[data-gallery-role="fotorama__fullscreen-icon"]');
- settings.focusableStart = this.settings.$element.find('[data-gallery-role="fotorama__focusable-start"]');
- settings.focusableEnd = this.settings.$element.find('[data-gallery-role="fotorama__focusable-end"]');
- settings.closeIcon = this.settings.$element.find('[data-gallery-role="fotorama__fullscreen-icon"]');
- settings.fullscreenConfig.swipe = true;
- settings.$gallery.on('fotorama:fullscreenenter', function () {
- 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, {}) && settings.breakpoints) {
- settings.api.updateOptions(settings.activeBreakpoint.options, true);
- }
- settings.isFullscreen = true;
- });
- settings.$gallery.on('fotorama:fullscreenexit', function () {
- 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, {}) && settings.breakpoints) {
- settings.api.updateOptions(settings.activeBreakpoint.options, true);
- }
- settings.isFullscreen = false;
- settings.$element.data('gallery').updateOptions({
- swipe: true
- });
- });
- },
- /**
- * Switcher focus.
- */
- _focusSwitcher: function (e) {
- var target = $(e.target),
- settings = this.settings;
- if (target.is(settings.focusableStart)) {
- this._setFocus('start');
- } else if (target.is(settings.focusableEnd)) {
- this._setFocus('end');
- }
- },
- /**
- * Set focus to element.
- * @param {String} position - can be "start" and "end"
- * positions.
- * If position is "end" - sets focus to first
- * focusable element in modal window scope.
- * If position is "start" - sets focus to last
- * focusable element in modal window scope
- */
- _setFocus: function (position) {
- var settings = this.settings,
- focusableElements,
- infelicity;
- if (position === 'end') {
- settings.$gallery.find(settings.closeIcon).focus();
- } else if (position === 'start') {
- infelicity = 3; //Constant for find last focusable element
- focusableElements = settings.$gallery.find(':focusable');
- focusableElements.eq(focusableElements.length - infelicity).focus();
- }
- },
- /**
- * Initializes gallery with configuration options.
- */
- initGallery: function () {
- var breakpoints = {},
- settings = this.settings,
- config = this.config,
- tpl = template(galleryTpl, {
- next: $t('Next'),
- previous: $t('Previous')
- }),
- mainImageIndex;
- if (settings.breakpoints) {
- _.each(_.values(settings.breakpoints), function (breakpoint) {
- var conditions;
- _.each(_.pairs(breakpoint.conditions), function (pair) {
- conditions = conditions ? conditions + ' and (' + pair[0] + ': ' + pair[1] + ')' :
- '(' + pair[0] + ': ' + pair[1] + ')';
- });
- breakpoints[conditions] = breakpoint.options;
- });
- settings.breakpoints = breakpoints;
- }
- _.extend(config, config.options);
- config.options = undefined;
- config.click = false;
- config.breakpoints = null;
- settings.currentConfig = config;
- settings.$element.html(tpl);
- settings.$element.removeClass('_block-content-loading');
- settings.$elementF = $(settings.$element.children()[0]);
- settings.$elementF.fotorama(config);
- settings.fotoramaApi = settings.$elementF.data('fotorama');
- $.extend(true, config, this.startConfig);
- mainImageIndex = getMainImageIndex(config.data);
- if (mainImageIndex) {
- this.settings.fotoramaApi.show({
- index: mainImageIndex,
- time: 0
- });
- }
- },
- /**
- * Creates breakpoints for gallery.
- */
- setupBreakpoints: function () {
- var pairs,
- settings = this.settings,
- config = this.config,
- startConfig = this.startConfig,
- isTouchEnabled = this.isTouchEnabled;
- if (_.isObject(settings.breakpoints)) {
- pairs = _.pairs(settings.breakpoints);
- _.each(pairs, function (pair) {
- mediaCheck({
- media: pair[0],
- /**
- * Is triggered when breakpoint enties.
- */
- entry: function () {
- $.extend(true, config, _.clone(startConfig));
- settings.api.updateOptions(settings.defaultConfig.options, true);
- 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]];
- },
- /**
- * Is triggered when breakpoint exits.
- */
- exit: function () {
- $.extend(true, config, _.clone(startConfig));
- settings.api.updateOptions(settings.defaultConfig.options, true);
- if (settings.isFullscreen) {
- settings.api.updateOptions(settings.fullscreenConfig, true);
- }
- settings.activeBreakpoint = {};
- }
- });
- });
- }
- },
- /**
- * Creates gallery's API.
- */
- initApi: function () {
- var settings = this.settings,
- config = this.config,
- api = {
- /**
- * Contains fotorama's API methods.
- */
- fotorama: settings.fotoramaApi,
- /**
- * Displays the last image on preview.
- */
- last: function () {
- settings.fotoramaApi.show('>>');
- },
- /**
- * Displays the first image on preview.
- */
- first: function () {
- settings.fotoramaApi.show('<<');
- },
- /**
- * Displays previous element on preview.
- */
- prev: function () {
- settings.fotoramaApi.show('<');
- },
- /**
- * Displays next element on preview.
- */
- next: function () {
- settings.fotoramaApi.show('>');
- },
- /**
- * Displays image with appropriate count number on preview.
- * @param {Number} index - Number of image that should be displayed.
- */
- seek: function (index) {
- if (_.isNumber(index) && index !== 0) {
- if (index > 0) {
- index -= 1;
- }
- settings.fotoramaApi.show(index);
- }
- },
- /**
- * Updates gallery with new set of options.
- * @param {Object} configuration - Standart gallery configuration object.
- * @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'),
- $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;
- }
- configuration.click = false;
- configuration.breakpoints = null;
- if (!isInternal) {
- !_.isEqual(settings.activeBreakpoint, {} && settings.brekpoints) ?
- $.extend(true, settings.activeBreakpoint.options, configuration) :
- settings.isFullscreen ?
- $.extend(true, settings.fullscreenConfig, configuration) :
- $.extend(true, settings.defaultConfig.options, configuration);
- }
- $.extend(true, settings.currentConfig.options, configuration);
- settings.fotoramaApi.setOptions(settings.currentConfig.options);
- if (_.isNumber(index)) {
- $selectable.eq(index).focus();
- }
- }
- },
- /**
- * Updates gallery with specific set of items.
- * @param {Array.<Object>} data - Set of gallery items to update.
- */
- updateData: function (data) {
- var mainImageIndex;
- if (_.isArray(data)) {
- settings.fotoramaApi.load(data);
- mainImageIndex = getMainImageIndex(data);
- if (mainImageIndex) {
- settings.fotoramaApi.show({
- index: mainImageIndex,
- time: 0
- });
- }
- $.extend(false, settings, {
- data: data,
- defaultConfig: data
- });
- $.extend(false, config, {
- data: data
- });
- }
- },
- /**
- * Returns current images list
- *
- * @returns {Array}
- */
- returnCurrentImages: function () {
- var images = [];
- _.each(this.fotorama.data, function (item) {
- 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);
- }
- };
- settings.$element.data('gallery', api);
- settings.api = settings.$element.data('gallery');
- settings.$element.trigger('gallery:loaded');
- }
- });
- });
|