/**
* Event listener
*
* @private
*/
_EventListener: function () {
var $widget = this;
$widget.element.on('click', '.' + this.options.classes.optionClass, function () {
return $widget._OnClick($(this), $widget);
});
$widget.element.on('change', '.' + this.options.classes.selectClass, function () {
return $widget._OnChange($(this), $widget);
});
$widget.element.on('click', '.' + this.options.classes.moreButton, function (e) {
e.preventDefault();
return $widget._OnMoreClick($(this));
});
},
/**
* Event for swatch options
*
* @param $this
* @param $widget
* @private
*/
_OnClick: function ($this, $widget) {
var $parent = $this.parents('.' + $widget.options.classes.attributeClass),
$label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass),
$input = $parent.find('.' + $widget.options.classes.attributeInput);
if ($this.hasClass('disabled')) {
return;
}
if ($this.hasClass('selected')) {
$parent.removeAttr('option-selected').find('.selected').removeClass('selected');
$input.val('');
$label.text('');
} else {
$parent.attr('option-selected', $this.attr('option-id')).find('.selected').removeClass('selected');
$label.text($this.attr('option-label'));
$input.val($this.attr('option-id'));
$this.addClass('selected');
}
$widget._Rebuild();
if ($widget.element.parents($widget.options.selectorProduct)
.find(this.options.selectorProductPrice).is(':data(mage-priceBox)')
) {
$widget._UpdatePrice();
}
$widget._LoadProductMedia();
},
/**
* Event for select
*
* @param $this
* @param $widget
* @private
*/
_OnChange: function ($this, $widget) {
var $parent = $this.parents('.' + $widget.options.classes.attributeClass),
$input = $parent.find('.' + $widget.options.classes.attributeInput);
if ($this.val() > 0) {
$parent.attr('option-selected', $this.val());
$input.val($this.val());
} else {
$parent.removeAttr('option-selected');
$input.val('');
}
$widget._Rebuild();
$widget._UpdatePrice();
$widget._LoadProductMedia();
},
/**
* Event for more switcher
*
* @param $this
* @private
*/
_OnMoreClick: function ($this) {
$this.nextAll().show();
$this.blur().remove();
},
/**
* Rewind options for controls
*
* @private
*/
_Rewind: function (controls) {
controls.find('div[option-id], option[option-id]').removeClass('disabled').removeAttr('disabled');
controls.find('div[option-empty], option[option-empty]').attr('disabled', true).addClass('disabled');
},
/**
* Rebuild container
*
* @private
*/
_Rebuild: function () {
var $widget = this,
controls = $widget.element.find('.' + $widget.options.classes.attributeClass + '[attribute-id]'),
selected = controls.filter('[option-selected]');
// Enable all options
$widget._Rewind(controls);
// done if nothing selected
if (selected.size() <= 0) {
return;
}
// Disable not available options
controls.each(function () {
var $this = $(this),
id = $this.attr('attribute-id'),
products = $widget._CalcProducts(id);
if (selected.size() == 1 && selected.first().attr('attribute-id') == id) {
return;
}
$this.find('[option-id]').each(function () {
var $this = $(this),
option = $this.attr('option-id');
if (!$widget.optionsMap.hasOwnProperty(id) || !$widget.optionsMap[id].hasOwnProperty(option) ||
$this.hasClass('selected') ||
$this.is(':selected')) {
return;
}
if (_.intersection(products, $widget.optionsMap[id][option].products).length <= 0) {
$this.attr('disabled', true).addClass('disabled');
}
});
});
},
/**
* Get selected product list
*
* @returns {Array}
* @private
*/
_CalcProducts: function ($skipAttributeId) {
var $widget = this,
products = [];
// Generate intersection of products
$widget.element.find('.' + $widget.options.classes.attributeClass + '[option-selected]').each(function () {
var id = $(this).attr('attribute-id');
var option = $(this).attr('option-selected');
if ($skipAttributeId != undefined && $skipAttributeId == id) {
return;
}
if (!$widget.optionsMap.hasOwnProperty(id) || !$widget.optionsMap[id].hasOwnProperty(option)) {
return;
}
if (products.length == 0) {
products = $widget.optionsMap[id][option].products;
} else {
products = _.intersection(products, $widget.optionsMap[id][option].products);
}
});
return products;
},
/**
* Update total price
*
* @private
*/
_UpdatePrice: function () {
var $widget = this,
$product = $widget.element.parents($widget.options.selectorProduct),
$productPrice = $product.find(this.options.selectorProductPrice),
options = _.object(_.keys($widget.optionsMap), {}),
result;
$widget.element.find('.' + $widget.options.classes.attributeClass + '[option-selected]').each(function () {
var attributeId = $(this).attr('attribute-id'),
selectedOptionId = $(this).attr('option-selected');
options[attributeId] = selectedOptionId;
});
result = $widget.options.jsonConfig.optionPrices[_.findKey($widget.options.jsonConfig.index, options)];
$productPrice.trigger(
'updatePrice',
{
'prices': $widget._getPrices(result, $productPrice.priceBox('option').prices)
}
);
},
/**
* Get prices
* @param {Object} newPrices
* @returns {Object}
* @private
*/
_getPrices: function (newPrices, displayPrices) {
var $widget = this;
if (_.isEmpty(newPrices)) {
newPrices = $widget.options.jsonConfig.prices;
}
_.each(displayPrices, function (price, code) {
if (newPrices[code]) {
displayPrices[code].amount = newPrices[code].amount - displayPrices[code].amount;
}
});
return displayPrices;
},
/**
* Gets all product media and change current to the needed one
*
* @private
*/
_LoadProductMedia: function () {
var $widget = this,
$this = $widget.element,
attributes = {},
productId = 0;
if (!$widget.options.mediaCallback) {
return;
}
$this.find('[option-selected]').each(function () {
var $selected = $(this);
attributes[$selected.attr('attribute-code')] = $selected.attr('option-selected');
});
if ($('body.catalog-product-view').size() > 0) {
//Product Page
productId = document.getElementsByName('product')[0].value;
} else {
//Category View
productId = $this.parents('.product.details.product-item-details')
.find('.price-box.price-final_price').attr('data-product-id');
}
var additional = $.parseParams(window.location.search.substring(1));
$widget._XhrKiller();
$widget._EnableProductMediaLoader($this);
$widget.xhr = $.post(
$widget.options.mediaCallback,
{product_id: productId, attributes: attributes, isAjax: true, additional: additional},
function (data) {
$widget._ProductMediaCallback($this, data);
$widget._DisableProductMediaLoader($this);
},
'json'
).done(function () {
$widget._XhrKiller();
});
},
/**
* Enable loader
*
* @param $this
* @private
*/
_EnableProductMediaLoader: function ($this) {
var $widget = this;
if ($('body.catalog-product-view').size() > 0) {
$this.parents('.column.main').find('.photo.image')
.addClass($widget.options.classes.loader);
} else {
//Category View
$this.parents('.product-item-info').find('.product-image-photo')
.addClass($widget.options.classes.loader);
}
},
/**
* Disable loader
*
* @param $this
* @private
*/
_DisableProductMediaLoader: function ($this) {
var $widget = this;
if ($('body.catalog-product-view').size() > 0) {
$this.parents('.column.main').find('.photo.image')
.removeClass($widget.options.classes.loader);
} else {
//Category View
$this.parents('.product-item-info').find('.product-image-photo')
.removeClass($widget.options.classes.loader);
}
},
/**
* Callback for product media
*
* @param $this
* @param response
* @private
*/
_ProductMediaCallback: function ($this, response) {
var isProductViewExist = $('body.catalog-product-view').size() > 0,
$main = isProductViewExist
? $this.parents('.column.main')
: $this.parents('.product-item-info'),
$widget = this,
images = [],
support = function (e) {
return e.hasOwnProperty('large') && e.hasOwnProperty('medium') && e.hasOwnProperty('small');
};
if ($widget._ObjectLength(response) < 1) {
this.updateBaseImage(this.options.mediaGalleryInitial, $main, isProductViewExist);
return;
}
if (support(response)) {
images.push({
full: response.large,
img: response.medium,
thumb: response.small
});
if (response.hasOwnProperty('gallery')) {
$.each(response.gallery, function () {
if (!support(this) || response.large === this.large) {
return;
}
images.push({
full: this.large,
img: this.medium,
thumb: this.small
});
});
}
}
this.updateBaseImage(images, $main, isProductViewExist);
},
/**
* Update [gallery-placeholder] or [product-image-photo]
* @param {Array} images
* @param {jQuery} context
* @param {Boolean} isProductViewExist
*/
updateBaseImage: function (images, context, isProductViewExist) {
var justAnImage = images[0];
if (isProductViewExist) {
context
.find('[data-gallery-role=gallery-placeholder]')
.data('gallery')
.updateData(images);
} else if (justAnImage && justAnImage.img) {
context.find('.product-image-photo').attr('src', justAnImage.img);
}
},
/**
* Kill doubled AJAX requests
*
* @private
*/
_XhrKiller: function () {
var $widget = this;
if ($widget.xhr !== undefined && $widget.xhr !== null) {
$widget.xhr.abort();
$widget.xhr = null;
}
},
/**
* Emulate mouse click on all swatches that should be selected
*
* @private
*/
_EmulateSelected: function () {
var $widget = this,
$this = $widget.element,
request = $.parseParams(window.location.search.substring(1));
$.each(request, function (key, value) {
$this.find('.' + $widget.options.classes.attributeClass
+ '[attribute-code="' + key + '"] [option-id="' + value + '"]').trigger('click');
});
},
/**
* Returns an array/object's length
* @param obj
* @returns {number}
* @private
*/
_ObjectLength: function (obj) {
var size = 0,
key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
}