/** * Magento * * NOTICE OF LICENSE * * This source file is subject to the Academic Free License (AFL 3.0) * that is bundled with this package in the file LICENSE_AFL.txt. * It is also available through the world-wide-web at this URL: * http://opensource.org/licenses/afl-3.0.php * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@magentocommerce.com so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade Magento to newer * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * * @category Varien * @package js * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ if(typeof Product=='undefined') { var Product = {}; } /********************* IMAGE ZOOMER ***********************/ Product.Zoom = Class.create(); /** * Image zoom control * * @author Magento Core Team */ Product.Zoom.prototype = { initialize: function(imageEl, trackEl, handleEl, zoomInEl, zoomOutEl, hintEl){ this.containerEl = $(imageEl).parentNode; this.imageEl = $(imageEl); this.handleEl = $(handleEl); this.trackEl = $(trackEl); this.hintEl = $(hintEl); this.containerDim = Element.getDimensions(this.containerEl); this.imageDim = Element.getDimensions(this.imageEl); this.imageDim.ratio = this.imageDim.width/this.imageDim.height; this.floorZoom = 1; if (this.imageDim.width > this.imageDim.height) { this.ceilingZoom = this.imageDim.width / this.containerDim.width; } else { this.ceilingZoom = this.imageDim.height / this.containerDim.height; } if (this.imageDim.width <= this.containerDim.width && this.imageDim.height <= this.containerDim.height) { this.trackEl.up().hide(); this.hintEl.hide(); this.containerEl.removeClassName('product-image-zoom'); return; } this.imageX = 0; this.imageY = 0; this.imageZoom = 1; this.sliderSpeed = 0; this.sliderAccel = 0; this.zoomBtnPressed = false; this.showFull = false; this.selects = document.getElementsByTagName('select'); this.draggable = new Draggable(imageEl, { starteffect:false, reverteffect:false, endeffect:false, snap:this.contain.bind(this) }); this.slider = new Control.Slider(handleEl, trackEl, { axis:'horizontal', minimum:0, maximum:Element.getDimensions(this.trackEl).width, alignX:0, increment:1, sliderValue:0, onSlide:this.scale.bind(this), onChange:this.scale.bind(this) }); this.scale(0); Event.observe(this.imageEl, 'dblclick', this.toggleFull.bind(this)); Event.observe($(zoomInEl), 'mousedown', this.startZoomIn.bind(this)); Event.observe($(zoomInEl), 'mouseup', this.stopZooming.bind(this)); Event.observe($(zoomInEl), 'mouseout', this.stopZooming.bind(this)); Event.observe($(zoomOutEl), 'mousedown', this.startZoomOut.bind(this)); Event.observe($(zoomOutEl), 'mouseup', this.stopZooming.bind(this)); Event.observe($(zoomOutEl), 'mouseout', this.stopZooming.bind(this)); }, toggleFull: function () { this.showFull = !this.showFull; //Hide selects for IE6 only if (typeof document.body.style.maxHeight == "undefined") { for (i=0; i this.containerDim.width && this.imageDim.height > this.containerDim.height); this.imageZoom = this.floorZoom+(v*(this.ceilingZoom-this.floorZoom)); if (overSize) { if (this.imageDim.width > this.containerDim.width) { this.imageEl.style.width = (this.imageZoom*this.containerDim.width)+'px'; } if(this.containerDim.ratio){ this.imageEl.style.height = (this.imageZoom*this.containerDim.width*this.containerDim.ratio)+'px'; // for safari } } else { this.slider.setDisabled(); } this.imageX = this.containerDim.width*(1-this.imageZoom)/2-centerX*this.imageZoom; this.imageY = this.containerDim.height*(1-this.imageZoom)/2-centerY*this.imageZoom; this.contain(this.imageX, this.imageY, this.draggable); return true; }, startZoomIn: function() { if (!this.slider.disabled) { this.zoomBtnPressed = true; this.sliderAccel = .002; this.periodicalZoom(); this.zoomer = new PeriodicalExecuter(this.periodicalZoom.bind(this), .05); } return this; }, startZoomOut: function() { if (!this.slider.disabled) { this.zoomBtnPressed = true; this.sliderAccel = -.002; this.periodicalZoom(); this.zoomer = new PeriodicalExecuter(this.periodicalZoom.bind(this), .05); } return this; }, stopZooming: function() { if (!this.zoomer || this.sliderSpeed==0) { return; } this.zoomBtnPressed = false; this.sliderAccel = 0; }, periodicalZoom: function() { if (!this.zoomer) { return this; } if (this.zoomBtnPressed) { this.sliderSpeed += this.sliderAccel; } else { this.sliderSpeed /= 1.5; if (Math.abs(this.sliderSpeed)<.001) { this.sliderSpeed = 0; this.zoomer.stop(); this.zoomer = null; } } this.slider.value += this.sliderSpeed; this.slider.setValue(this.slider.value); this.scale(this.slider.value); return this; }, contain: function (x,y,draggable) { var dim = Element.getDimensions(draggable.element); var xMin = 0, xMax = this.containerDim.width-dim.width; var yMin = 0, yMax = this.containerDim.height-dim.height; x = x>xMin ? xMin : x; x = xyMin ? yMin : y; y = y dim.width) { x = (this.containerDim.width/2) - (dim.width/2); } if (this.containerDim.height > dim.height) { y = (this.containerDim.height/2) - (dim.height/2); } this.imageX = x; this.imageY = y; this.imageEl.style.left = this.imageX+'px'; this.imageEl.style.top = this.imageY+'px'; return [x,y]; } } /**************************** CONFIGURABLE PRODUCT **************************/ Product.Config = Class.create(); Product.Config.prototype = { initialize: function(config){ this.config = config; this.taxConfig = this.config.taxConfig; this.settings = $$('.super-attribute-select'); this.state = new Hash(); this.priceTemplate = new Template(this.config.template); this.prices = config.prices; this.settings.each(function(element){ Event.observe(element, 'change', this.configure.bind(this)) }.bind(this)); // fill state this.settings.each(function(element){ var attributeId = element.id.replace(/[a-z]*/, ''); if(attributeId && this.config.attributes[attributeId]) { element.config = this.config.attributes[attributeId]; element.attributeId = attributeId; this.state[attributeId] = false; } }.bind(this)) // Init settings dropdown var childSettings = []; for(var i=this.settings.length-1;i>=0;i--){ var prevSetting = this.settings[i-1] ? this.settings[i-1] : false; var nextSetting = this.settings[i+1] ? this.settings[i+1] : false; if(i==0){ this.fillSelect(this.settings[i]) } else { this.settings[i].disabled=true; } $(this.settings[i]).childSettings = childSettings.clone(); $(this.settings[i]).prevSetting = prevSetting; $(this.settings[i]).nextSetting = nextSetting; childSettings.push(this.settings[i]); } // try retireve options from url var separatorIndex = window.location.href.indexOf('#'); if (separatorIndex!=-1) { var paramsStr = window.location.href.substr(separatorIndex+1); this.values = paramsStr.toQueryParams(); this.settings.each(function(element){ var attributeId = element.attributeId; element.value = (typeof(this.values[attributeId]) == 'undefined')? '' : this.values[attributeId]; this.configureElement(element); }.bind(this)); } }, configure: function(event){ var element = Event.element(event); this.configureElement(element); }, configureElement : function(element) { this.reloadOptionLabels(element); if(element.value){ this.state[element.config.id] = element.value; if(element.nextSetting){ element.nextSetting.disabled = false; this.fillSelect(element.nextSetting); this.resetChildren(element.nextSetting); } } else { this.resetChildren(element); } this.reloadPrice(); // Calculator.updatePrice(); }, reloadOptionLabels: function(element){ var selectedPrice; if(element.options[element.selectedIndex].config){ selectedPrice = parseFloat(element.options[element.selectedIndex].config.price) } else{ selectedPrice = 0; } for(var i=0;i-1){ allowedProducts.push(options[i].products[j]); } } } else { allowedProducts = options[i].products.clone(); } if(allowedProducts.size()>0){ options[i].allowedProducts = allowedProducts; element.options[index] = new Option(this.getOptionLabel(options[i], options[i].price), options[i].id); element.options[index].config = options[i]; index++; } } } }, getOptionLabel: function(option, price){ var price = parseFloat(price); if (this.taxConfig.includeTax) { var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax; var excl = price - tax; var incl = excl*(1+(this.taxConfig.currentTax/100)); } else { var tax = price * (this.taxConfig.currentTax / 100); var excl = price; var incl = excl + tax; } if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) { price = incl; } else { price = excl; } var str = option.label; if(price){ if (this.taxConfig.showBothPrices) { str+= ' ' + this.formatPrice(excl, true) + ' (' + this.formatPrice(price, true) + ' ' + this.taxConfig.inclTaxTitle + ')'; } else { str+= ' ' + this.formatPrice(price, true); } } return str; }, formatPrice: function(price, showSign){ var str = ''; price = parseFloat(price); if(showSign){ if(price<0){ str+= '-'; price = -price; } else{ str+= '+'; } } var roundedPrice = (Math.round(price*100)/100).toString(); if (this.prices && this.prices[roundedPrice]) { str+= this.prices[roundedPrice]; } else { str+= this.priceTemplate.evaluate({price:price.toFixed(2)}); } return str; }, clearSelect: function(element){ for(var i=element.options.length-1;i>=0;i--){ element.remove(i); } }, getAttributeOptions: function(attributeId){ if(this.config.attributes[attributeId]){ return this.config.attributes[attributeId].options; } }, reloadPrice: function(){ var price = 0; for(var i=this.settings.length-1;i>=0;i--){ var selected = this.settings[i].options[this.settings[i].selectedIndex]; if(selected.config){ price += parseFloat(selected.config.price); } } optionsPrice.changePrice('config', price); optionsPrice.reload(); return price; if($('product-price-'+this.config.productId)){ $('product-price-'+this.config.productId).innerHTML = price; } this.reloadOldPrice(); }, reloadOldPrice: function(){ if ($('old-price-'+this.config.productId)) { var price = parseFloat(this.config.oldPrice); for(var i=this.settings.length-1;i>=0;i--){ var selected = this.settings[i].options[this.settings[i].selectedIndex]; if(selected.config){ price+= parseFloat(selected.config.price); } } if (price < 0) price = 0; price = this.formatPrice(price); if($('old-price-'+this.config.productId)){ $('old-price-'+this.config.productId).innerHTML = price; } } } } /**************************** SUPER PRODUCTS ********************************/ Product.Super = {}; Product.Super.Configurable = Class.create(); Product.Super.Configurable.prototype = { initialize: function(container, observeCss, updateUrl, updatePriceUrl, priceContainerId) { this.container = $(container); this.observeCss = observeCss; this.updateUrl = updateUrl; this.updatePriceUrl = updatePriceUrl; this.priceContainerId = priceContainerId; this.registerObservers(); }, registerObservers: function() { var elements = this.container.getElementsByClassName(this.observeCss); elements.each(function(element){ Event.observe(element, 'change', this.update.bindAsEventListener(this)); }.bind(this)); return this; }, update: function(event) { var elements = this.container.getElementsByClassName(this.observeCss); var parameters = Form.serializeElements(elements, true); new Ajax.Updater(this.container, this.updateUrl + '?ajax=1', { parameters:parameters, onComplete:this.registerObservers.bind(this) }); var priceContainer = $(this.priceContainerId); if(priceContainer) { new Ajax.Updater(priceContainer, this.updatePriceUrl + '?ajax=1', { parameters:parameters }); } } } /**************************** PRICE RELOADER ********************************/ Product.OptionsPrice = Class.create(); Product.OptionsPrice.prototype = { initialize: function(config) { this.productId = config.productId; this.priceFormat = config.priceFormat; this.includeTax = config.includeTax; this.defaultTax = config.defaultTax; this.currentTax = config.currentTax; this.productPrice = config.productPrice; this.showIncludeTax = config.showIncludeTax; this.showBothPrices = config.showBothPrices; this.productPrice = config.productPrice; this.productOldPrice = config.productOldPrice; this.skipCalculate = config.skipCalculate; this.duplicateIdSuffix = config.idSuffix; this.oldPlusDisposition = config.oldPlusDisposition; this.plusDisposition = config.plusDisposition; this.oldMinusDisposition = config.oldMinusDisposition; this.minusDisposition = config.minusDisposition; this.optionPrices = {}; this.containers = {}; this.displayZeroPrice = true; this.initPrices(); }, setDuplicateIdSuffix: function(idSuffix) { this.duplicateIdSuffix = idSuffix; }, initPrices: function() { this.containers[0] = 'product-price-' + this.productId; this.containers[1] = 'bundle-price-' + this.productId; this.containers[2] = 'price-including-tax-' + this.productId; this.containers[3] = 'price-excluding-tax-' + this.productId; this.containers[4] = 'old-price-' + this.productId; }, changePrice: function(key, price) { this.optionPrices[key] = parseFloat(price); }, getOptionPrices: function() { var result = 0; var nonTaxable = 0; $H(this.optionPrices).each(function(pair) { if (pair.key == 'nontaxable') { nonTaxable = pair.value; } else { result += pair.value; } }); var r = new Array(result, nonTaxable); return r; }, reload: function() { var price; var formattedPrice; var optionPrices = this.getOptionPrices(); var nonTaxable = optionPrices[1]; optionPrices = optionPrices[0]; $H(this.containers).each(function(pair) { var _productPrice; var _plusDisposition; var _minusDisposition; if ($(pair.value)) { if (pair.value == 'old-price-'+this.productId && this.productOldPrice != this.productPrice) { _productPrice = this.productOldPrice; _plusDisposition = this.oldPlusDisposition; _minusDisposition = this.oldMinusDisposition; } else { _productPrice = this.productPrice; _plusDisposition = this.plusDisposition; _minusDisposition = this.minusDisposition; } var price = optionPrices+parseFloat(_productPrice) if (this.includeTax == 'true') { // tax = tax included into product price by admin var tax = price / (100 + this.defaultTax) * this.defaultTax; var excl = price - tax; var incl = excl*(1+(this.currentTax/100)); } else { var tax = price * (this.currentTax / 100); var excl = price; var incl = excl + tax; } excl += parseFloat(_plusDisposition); incl += parseFloat(_plusDisposition); excl -= parseFloat(_minusDisposition); incl -= parseFloat(_minusDisposition); //adding nontaxlable part of options excl += parseFloat(nonTaxable); incl += parseFloat(nonTaxable); if (pair.value == 'price-including-tax-'+this.productId) { price = incl; } else if (pair.value == 'old-price-'+this.productId) { if (this.showIncludeTax || this.showBothPrices) { price = incl; } else { price = excl; } } else { if (this.showIncludeTax) { price = incl; } else { if (!this.skipCalculate || _productPrice == 0) { price = excl; } else { price = optionPrices+parseFloat(_productPrice); } } } if (price < 0) price = 0; if (price > 0 || this.displayZeroPrice) { formattedPrice = this.formatPrice(price); } else { formattedPrice = ''; } if ($(pair.value).select('.price')[0]) { $(pair.value).select('.price')[0].innerHTML = formattedPrice; if ($(pair.value+this.duplicateIdSuffix) && $(pair.value+this.duplicateIdSuffix).select('.price')[0]) { $(pair.value+this.duplicateIdSuffix).select('.price')[0].innerHTML = formattedPrice; } } else { $(pair.value).innerHTML = formattedPrice; if ($(pair.value+this.duplicateIdSuffix)) { $(pair.value+this.duplicateIdSuffix).innerHTML = formattedPrice; } } }; }.bind(this)); }, formatPrice: function(price) { return formatCurrency(price, this.priceFormat); } }