Move PDP Image gallery to the extension.

Jira Code: IBT-38, 39

This extension overrides the default view (child view) of image gallery in PDP page, it includes images as well as videos for the item. The video module is custom created.

// EXTENSION: ENTRY POINT

define(
	'JJ.PDPImageGallery.PDPImgGallery'
,   [
		'Product.ImageGallery'
	]
,   function (
		PDPImgGalleryView
	)
{
	'use strict';

	return  {
		mountToApp: function mountToApp (container)
		{ 
			var pdp = container.getComponent('PDP');
			var model;
			if(pdp)
			{
				pdp.addToViewContextDefinition('ProductDetails.Full.View', 'test123', 'string', function(context) {
                        model = context.model;
                        var item = model.item;
                        var keyFeatures = "";
                        return keyFeatures;
                    });

				// pdp.addChildView('Product.ImgVideosGallery', function() { 
				// 	return new PDPImgGalleryView({ application: container,model: new Backbone.Model(model) });
				// });


				pdp.addChildViews(
                        pdp.PDP_FULL_VIEW, {
                            'Product.ImageGallery': {
                                'Product.ImageGallery': {
                                    childViewIndex: 10,
                                    childViewConstructor: function() {
                                        return new PDPImgGalleryView({ application: container,model: new Backbone.Model(model) });
                                    }
                                }
                            }
                        }
                    );

				pdp.addChildViews(
                        pdp.PDP_QUICK_VIEW , {
                            'Product.ImageGallery': {
                                'Product.ImageGallery': {
                                    childViewIndex: 10,
                                    childViewConstructor: function() {
                                        return new PDPImgGalleryView({ application: container,model: new Backbone.Model(model) });
                                    }
                                }
                            }
                        }
                    );
			}

		}
	};
});
//IMAGE GALLERY VIEW
// @module JJ.PDPImageGallery.PDPImgGallery
define('Product.ImageGallery', [
    'jj_pdpimagegallery_pdpimggallery.tpl', 'Backbone.CompositeView', 'Utilities.ResizeImage', 'Utils', 'Backbone', 'jQuery', 'underscore'
], function(
    jj_pdpimagegallery_pdpimggallery_tpl, BackboneCompositeView, resizeImage, Utils, Backbone, jQuery, _
) {
    'use strict';
    // @class JJ.PDPImageGallery.PDPImgGallery.View @extends Backbone.View
    return Backbone.View.extend({

        template: jj_pdpimagegallery_pdpimggallery_tpl

            ,
        initialize: function(options) {

                var self = this;
                Backbone.View.prototype.initialize.apply(self, arguments);
                BackboneCompositeView.add(self);
                self.model = options.model;
                self.application = self.options.application;

                self.images = self.model.get('item').keyMapping_images;

                var itemid = self.model.get('item').internalid;

                var service_url = Utils.getAbsoluteUrl(getExtensionAssetsPath('services/ProductVideos.Service.ss'));
                this.loadScript('https://cdnjs.cloudflare.com/ajax/libs/fitvids/1.2.0/jquery.fitvids.min.js', function() {
                    jQuery.get(service_url, { itemid: itemid })
                        .then((result) => {
                            self.productVideos = result;
                            self.images = self.getImages();
                            self.render();
                        });
                    //this.application.getLayout().on('afterAppendView', this.initSliderZoom, this);
                    self.on('afterViewRender', function() {
                        self.initSlider();
                        self.initZoom();

                    });
                });


            }

            ,
        initSliderZoom: function initSliderZoom() {
            this.initSlider();
            this.initZoom();
        },
        loadScript: function(url, callback) {
                var script = document.createElement("script")
                script.type = "text/javascript";
                if (script.readyState) { // only required for IE <9
                    script.onreadystatechange = function() {
                        if (script.readyState === "loaded" || script.readyState === "complete") {
                            script.onreadystatechange = null;
                            callback();
                        }
                    };
                } else { //Others
                    script.onload = function() {
                        callback();
                    };
                }

                script.src = url;
                document.getElementsByTagName("head")[0].appendChild(script);
            }
            // @method destroy
            // @returns {Void}
            ,
        destroy: function destroy() {
                this.model.off('change', this.render, this);
                this.application.getLayout().off('afterAppendView', this.initSliderZoom, this);
                this._destroy();
            }

            // @method initSlider Initialize the bxSlider
            // @return {Void}
            ,
        initSlider: function initSlider() {
                var self = this;

                if (self.images.length > 1) {
                    self.$slider = Utils.initBxSlider(self.$('[data-slider]'), {
                        buildPager: _.bind(self.buildSliderPager, self),
                        startSlide: 0,
                        adaptiveHeight: true,
                        touchEnabled: true,
                        nextText: '<a class="product-details-image-gallery-next-icon" data-action="next-image"></a>',
                        prevText: '<a class="product-details-image-gallery-prev-icon" data-action="prev-image"></a>',
                        controls: true,
                        video: true
                    });

                    self.$('[data-action="next-image"]').off();
                    self.$('[data-action="prev-image"]').off();

                    self.$('[data-action="next-image"]').click(_.bind(self.nextImageEventHandler, self));
                    self.$('[data-action="prev-image"]').click(_.bind(self.previousImageEventHandler, self));
                }
            }

            //@method previousImageEventHandler Handle the clicking over the previous button to show the previous main image. It does it by triggering a cancelable event.
            //@return {Void}
            ,
        previousImageEventHandler: function previousImageEventHandler() {
                var self = this,
                    current_index = self.$slider.getCurrentSlide(),
                    next_index = current_index === 0 ? self.$slider.getSlideCount() - 1 : current_index - 1;

                //IMPORTANT This event is used to notify the ProductDetails.Component that the images have changed
                //@event {ProductDetails.ImageGallery.ChangeEvent} 'afterChangeImage
                self.model.cancelableTrigger('beforeChangeImage', { currentIndex: current_index, nextIndex: next_index })
                    .then(function() {
                        self.$slider.goToPrevSlide();
                        self.model.cancelableTrigger('afterChangeImage', next_index);
                    });
            }

            //@method nextImageEventHandler Handle the clicking over the next button to show the next main image. It does it by triggering a cancelable event
            //@return {Void}
            ,
        nextImageEventHandler: function nextImageEventHandler() {
                var self = this,
                    current_index = self.$slider.getCurrentSlide(),
                    next_index = current_index === (self.$slider.getSlideCount() - 1) ? 0 : current_index + 1;

                //IMPORTANT This event is used to notify the ProductDetails.Component that the images have changed
                //@event {ProductDetails.ImageGallery.ChangeEvent} beforeChangeImage
                self.model.cancelableTrigger('beforeChangeImage'
                        //@class ProductDetails.ImageGallery.ChangeEvent Image change event information container
                        , {
                            //@property {Number} currentIndex
                            currentIndex: current_index
                                //@property {Number} nextIndex
                                ,
                            nextIndex: next_index
                        }
                        // @class ProductDetails.ImageGallery.View
                    )
                    .then(function() {
                        self.$slider.goToNextSlide();
                        self.model.cancelableTrigger('afterChangeImage', next_index);
                    });
            }

            // @method initZoom
            // @return {Void}
            ,
        initZoom: function() {
                if (!SC.ENVIRONMENT.isTouchEnabled) {
                    var images = this.images,
                        self = this;

                    this.$('[data-zoom]:not(.bx-clone)').each(function(slide_index) {
                        self.$(this).zoom({
                            url: resizeImage(images[slide_index].url, 'zoom'),
                            callback: function() {
                                var $this = self.$(this);

                                if ($this.width() <= $this.closest('[data-view="Product.ImageGallery"]').width()) {
                                    $this.remove();
                                }

                                return this;
                            }
                        });
                    });
                }
            }

            ,
        getImages: function() {
                var newImages;

                newImages = jQuery.extend(true, [], this.model.get('item').keyMapping_images);
                if (!!this.productVideos) {
                    _.each(this.productVideos, function each(video) {
                        var name, url;

                        name = video.name;
                        url = video.url;

                        newImages.push({
                            altimagetext: name,
                            url: url,
                            isVideo: true
                        })
                    })
                }

                return newImages;
            }

            ,
        buildSliderPager: function(slide_index) {
                var image, imgEl;

                image = this.images[slide_index];

                if (image.isVideo) {
                    var videoIdRegExp, videoId, thumbUrl, isYoutubeThumbnail;

                    isYoutubeThumbnail = false;

                    videoIdRegExp = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
                    videoId = image.url && image.url.match(videoIdRegExp);

                    if (videoId && videoId[2].length === 11) {
                        thumbUrl = '//img.youtube.com/vi/' + videoId[2] + '/0.jpg';
                        isYoutubeThumbnail = true;
                    } else {
                        thumbUrl = Utils.getAbsoluteUrlOfNonManagedResources('img/play-icon.png')
                    }

                    imgEl = '<img class="product-details-image-gallery-video-thumb' + (isYoutubeThumbnail ? ' youtube-thumb"' : '"') + ' src="' + resizeImage(thumbUrl, 'tinythumb') + '" alt="' + (image.altimagetext || '') + '">';
                } else {
                    imgEl = '<img src="' + resizeImage(image.url, 'tinythumb') + '" alt="' + (image.altimagetext || '') + '">';
                }

                return imgEl;
            }

            //@method getContext @return JJ.PDPImageGallery.PDPImgGallery.View.Context
            ,
        getContext: function getContext() {
            // @class ProductDetails.ImageGallery.View.Context
            return {
                // @property {String} imageResizeId
                imageResizeId: Utils.getViewportWidth() < 768 ? 'thumbnail' : 'main'
                    //@property {Array<ImageContainer>} images
                    ,
                images: this.images || []
                    //@property {ImageContainer} firstImage
                    ,
                firstImage: this.images[0] || {}
                    // @property {Boolean} showImages
                    ,
                showImages: this.images.length > 0
                    // @property {Boolean} showImageSlider
                    ,
                showImageSlider: this.images.length > 1
            };
            // @class ProductDetails.ImageGallery.View
        }
    });
});
//TEMPLATE
<div class="product-details-image-gallery">
	{{#if showImages}}
		{{#if showImageSlider}}
			<ul class="bxslider" data-slider>
				{{#each images}}
                    {{#if isVideo}}
                        <li>
                            <iframe src="{{url}}" class="product-details-image-gallery-video" width="560" height="315" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
                        </li>
                    {{else}}
                        <li data-zoom class="product-details-image-gallery-container">
                            <img
                                src="{{resizeImage url ../imageResizeId}}"
                                alt="{{altimagetext}}"
                                itemprop="image"
                                data-loader="false">
                        </li>
                    {{/if}}
				{{/each}}
			</ul>
		{{else}}
			{{#with firstImage}}
                {{#if isVideo}}
                    <li>
                        <iframe src="{{url}}" class="product-details-image-gallery-video" width="560" height="315" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
                    </li>
                {{else}}
                    <div class="product-details-image-gallery-detailed-image" data-zoom>
                        <img
                            class="center-block"
                            src="{{resizeImage url ../imageResizeId}}"
                            alt="{{altimagetext}}"
                            itemprop="image"
                            data-loader="false">
                    </div>
                {{/if}}
			{{/with}}

		{{/if}}
	{{/if}}
	<div data-view="SocialSharing.Flyout.Hover"></div>
</div>
//PRODUCT VIDEOS CUSTOM MODULES
define(
    'ProductVideos.Collection'
,   [
        'ProductVideos.Model'
    ,   'Backbone.CachedCollection'
    ,	'underscore'
    ,	'Utils'
    ]
,   function ProductVideosCollection (
        ProductVideosModel
    ,   BackboneCachedCollection
    ,	_
    ,	Utils
    )
{
	'use strict';

    return BackboneCachedCollection.extend({
        url: function url () {
            return Utils.getAbsoluteUrl(getExtensionAssetsPath('services/ProductVideos.Service.ss'));
        }

    ,   model: ProductVideosModel
    });

});
define(
    'ProductVideos.Model'
,   [
        'Backbone'
    ,   'underscore'
    ,   'Utils'
    ]
,   function ProductVideosModel (
        Backbone
    ,   _
    ,   Utils
    )
{
    'use strict';

    return Backbone.Model.extend({
        urlRoot: function urlRoot () {
            return Utils.getAbsoluteUrl(getExtensionAssetsPath('services/ProductVideos.Service.ss'));
        }
    });
});
define(
    'JJ.PDPImageGallery.ProductVideos.ServiceController'
,	[
        'ServiceController'
    ,	'ProductVideos.Models'
    ]
,	function ProductVideosServiceController (
        ServiceController
    ,	ProductVideosModel
    )
{
    'use strict';

    return ServiceController.extend({
        name:'JJ.PDPImageGallery.ProductVideos.ServiceController'

    ,	get: function get () {
            var itemid
            ,   results;

            try {
                itemid = this.request.getParameter('itemid');

                if (itemid) {
                    results = ProductVideosModel.get(itemid);
                } else {
                    results = [];
                }

                this.sendContent(results, { cache: response.CACHE_DURATION_LONG });

            } catch (e) {
                console.warn('ProductVideos.Service.ss::' + e.name, e);
                this.sendError(e);
            }
        }
    });
});
define(
    'ProductVideos.Models'
,	[
        'SC.Model'
    ,   'Application'
    ,   'JJ.PDPImageGallery.ProductVideos.ServiceController'
    ,   'underscore'
    ]
,	function ProductVideosModel (
        SCModel
    ,   Application
    ,   ProductVideosServiceController
    ,   _
    )
{
    'use strict';

    return SCModel.extend({
        name: 'ItemVideos'
    ,   record: {
            type: 'customrecord_item_video'
        ,   fieldsets: {
                list: {
                    name: 'custrecord_item_video_name'
                ,   url: 'custrecord_item_video_url'
                }
            ,   all: {
                    name: 'custrecord_item_video_name'
                ,   url: 'custrecord_item_video_url'
                ,   item: 'custrecord_item_video_item'
                ,   isinactive: 'isinactive'
                }
            }
        }

    ,	get: function (itemId) {
            var itemVideosSearchResults
            ,   filters
            ,   results;

            filters = [
                new nlobjSearchFilter(this.record.fieldsets.all.isinactive, null, 'is', 'F')
            ,   new nlobjSearchFilter(this.record.fieldsets.all.item, null, 'is', itemId)
            ];

            itemVideosSearchResults = Application.getAllSearchResults(this.record.type, filters, this._getColumnsArray(this.record.fieldsets.list));

            results = [];

            if (!itemVideosSearchResults || !itemVideosSearchResults.length) {
                return results;
            }

            _.each(itemVideosSearchResults, function each (itemVideosSearchResult){
                var name
                ,   url;

                name = itemVideosSearchResult.getValue(this.record.fieldsets.list.name);
                url = itemVideosSearchResult.getValue(this.record.fieldsets.list.url);

                if (name && url) {
                    results.push({
                        name: name
                    ,   url : url
                    });
                }
            }, this);

            return results;
        }

    ,   _getColumnsArray: function _getColumnsArray (fieldset) {
            var columns;

            columns = [];

            _.each(_.keys(fieldset), function each (key) {
                columns.push(new nlobjSearchColumn(fieldset[key]));
            }, this);

            return columns;
        }
    });
});

Leave a comment

Your email address will not be published. Required fields are marked *