Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jtomaszewski opened this issue Sep 14, 2021 · 1 comment

Comments

@jtomaszewski
Copy link
Contributor

Not sure if it's a regression caused by b9be48e, but currently if on product list in grid view, if you have products with swatches, that have their own images per swatch, then:

  • if you select a swatch, it'll replace the image of all gallery thumbnails but the first one
  • even if you deselect the swatch, the swatch image stays, and some gallery thumbnails can't be accessed
  • also, the swatch image is not covering the whole width and height of the previous image, and so both images can be seen at the same time.

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

@jtomaszewski
Copy link
Contributor Author

jtomaszewski commented Sep 14, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant