magesuite / theme-creativeshop

Open Software License 3.0
38 stars 24 forks source link

Product thumbnails on grid view transition badly for swatch products if tile gallery is on #91

Open jtomaszewski opened 2 years ago

jtomaszewski commented 2 years ago

Not sure if it's a regression caused by https://github.com/magesuite/theme-creativeshop/commit/b9be48ed6274d025772984e8d4798adb7c0a7c4c, but currently if on product list in grid view, if you have products with swatches, that have their own images per swatch, then:

Video of this behaviour: https://www.dropbox.com/s/zf6g6c7ejunioxi/Screen%20Recording%202021-09-14%20at%2015.02.47.mov?dl=0

jtomaszewski commented 2 years ago

We have fixed this in the following manner:

Video of how it works after the fixes: https://www.dropbox.com/s/nc35mheuzmbkwpe/Screen%20Recording%202021-09-14%20at%2015.43.39.mov?dl=0

In case you'd like to use it, code of our swatch-renderer-gs-ext.js file that decorates the swatch-renderer-ext.js from theme-creativeshop:

define(['jquery', 'underscore', 'mage/translate'], function($, _, $t) {
    'use strict';

    return function(swatchRenderer) {
        $.widget('mage.SwatchRenderer', swatchRenderer, {
            _init: function() {
                if (this.element.attr('data-rendered')) {
                    return;
                }

                this.options.classes.productTileImageClass =
                    'cs-product-tile__image';
                this.options.classes.productTileClass = 'cs-product-tile';
                this.options.classes.galleryClass = 'cs-tile-gallery';
                this.options.classes.galleryItemClass = 'cs-tile-gallery__item';
                this.options.classes.activeGalleryItemClass =
                    'cs-tile-gallery__item--active';

                this._super();
            },
            updateBaseImage: function(images, context, isInProductView) {
                var justAnImage = images[0];

                if (isInProductView) {
                    return this._super(images, context, isInProductView);
                }

                if (justAnImage && justAnImage.img) {
                    this._findOrCreateImage(justAnImage.img).then($image => {
                        this._setActiveImage($image);
                        this._toggleGallery(false);
                    });
                } else {
                    const activeGalleryItemIndex = this._getActiveGalleryItemIndex();
                    const $image = this.element
                        .parents(this.options.selectorProductTile)
                        .find(`.${this.options.classes.productTileImageClass}`)
                        .eq(activeGalleryItemIndex);
                    this._setActiveImage($image, activeGalleryItemIndex);
                    this._toggleGallery(true);
                }
            },
            _setActiveImage: function($image, activeGalleryItemIndex) {
                $image
                    .addClass(
                        `${this.options.classes.productTileImageClass}--animate`
                    )
                    .siblings()
                    .removeClass(
                        `${this.options.classes.productTileImageClass}--animate`
                    );

                const galleryItems = this.element
                    .parents(this.options.selectorProductTile)
                    .find(`.${this.options.classes.galleryItemClass}`);
                galleryItems.removeClass(
                    this.options.classes.activeGalleryItemClass
                );
                if (activeGalleryItemIndex != null) {
                    galleryItems
                        .eq(activeGalleryItemIndex)
                        .addClass(this.options.classes.activeGalleryItemClass);
                }
            },
            _toggleGallery: function(visible) {
                this.element
                    .parents(this.options.selectorProductTile)
                    .find(`.${this.options.classes.galleryClass}`)
                    .toggleClass('active', visible);
            },
            _getActiveGalleryItemIndex: function() {
                const index = this.element
                    .parents(this.options.selectorProductTile)
                    .find(`.${this.options.classes.galleryItemClass}`)
                    .toArray()
                    .findIndex(el =>
                        el.classList.contains(
                            this.options.classes.activeGalleryItemClass
                        )
                    );
                return index === -1 ? 0 : undefined;
            },
            _findOrCreateImage: function(imgSrc) {
                const existingImage = this.element
                    .parents(this.options.selectorProductTile)
                    .find(`.${this.options.classes.productTileImageClass}`)
                    .toArray()
                    .find(element => element.src === imgSrc);
                if (existingImage) {
                    return Promise.resolve($(existingImage));
                }
                return this._createImage(imgSrc);
            },
            _createImage: function(imgSrc) {
                return new Promise((resolve, reject) => {
                    const img = new Image();
                    img.onload = () => {
                        this._getImageParent().append(img);
                        requestAnimationFrame(() => {
                            resolve($(img));
                        });
                    };
                    img.onerror = reject;
                    img.src = imgSrc;
                    img.className = `${this.options.classes.productTileImageClass} ${this.options.classes.productTileImageClass}--animatable`;
                });
            },
            _getImageParent: function() {
                return this.element
                    .parents(this.options.selectorProductTile)
                    .find(`.${this.options.classes.productTileImageClass}`)
                    .first()
                    .parent();
            },
        });

        return $.mage.SwatchRenderer;
    };
});

If you like this, feel free to copy that, or we can submit a PR.