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;
}
});
});