1/** 2 * OpenMage 3 * 4 * This source file is subject to the Academic Free License (AFL 3.0) 5 * that is bundled with this package in the file LICENSE_AFL.txt. 6 * It is also available at https://opensource.org/license/afl-3-0-php 7 * 8 * @category Varien 9 * @package js 10 * @copyright Copyright (c) 2006-2020 Magento, Inc. (https://www.magento.com) 11 * @copyright Copyright (c) 2017-2023 The OpenMage Contributors (https://www.openmage.org) 12 * @license https://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) 13 */ 14if(typeof Product=='undefined') { 15 var Product = {}; 16} 17 18/********************* IMAGE ZOOMER ***********************/ 19 20Product.Zoom = Class.create(); 21Product.Zoom.prototype = { 22 initialize: function(imageEl, trackEl, handleEl, zoomInEl, zoomOutEl, hintEl){ 23 this.containerEl = $(imageEl).parentNode; 24 this.imageEl = $(imageEl); 25 this.handleEl = $(handleEl); 26 this.trackEl = $(trackEl); 27 this.hintEl = $(hintEl); 28 29 this.containerDim = Element.getDimensions(this.containerEl); 30 this.imageDim = Element.getDimensions(this.imageEl); 31 32 this.imageDim.ratio = this.imageDim.width/this.imageDim.height; 33 34 this.floorZoom = 1; 35 36 if (this.imageDim.width > this.imageDim.height) { 37 this.ceilingZoom = this.imageDim.width / this.containerDim.width; 38 } else { 39 this.ceilingZoom = this.imageDim.height / this.containerDim.height; 40 } 41 42 if (this.imageDim.width <= this.containerDim.width 43 && this.imageDim.height <= this.containerDim.height) { 44 this.trackEl.up().hide(); 45 this.hintEl.hide(); 46 this.containerEl.removeClassName('product-image-zoom'); 47 return; 48 } 49 50 this.imageX = 0; 51 this.imageY = 0; 52 this.imageZoom = 1; 53 54 this.sliderSpeed = 0; 55 this.sliderAccel = 0; 56 this.zoomBtnPressed = false; 57 58 this.showFull = false; 59 60 this.selects = document.getElementsByTagName('select'); 61 62 this.draggable = new Draggable(imageEl, { 63 starteffect:false, 64 reverteffect:false, 65 endeffect:false, 66 snap:this.contain.bind(this) 67 }); 68 69 this.slider = new Control.Slider(handleEl, trackEl, { 70 axis:'horizontal', 71 minimum:0, 72 maximum:Element.getDimensions(this.trackEl).width, 73 alignX:0, 74 increment:1, 75 sliderValue:0, 76 onSlide:this.scale.bind(this), 77 onChange:this.scale.bind(this) 78 }); 79 80 this.scale(0); 81 82 Event.observe(this.imageEl, 'dblclick', this.toggleFull.bind(this)); 83 84 Event.observe($(zoomInEl), 'mousedown', this.startZoomIn.bind(this)); 85 Event.observe($(zoomInEl), 'mouseup', this.stopZooming.bind(this)); 86 Event.observe($(zoomInEl), 'mouseout', this.stopZooming.bind(this)); 87 88 Event.observe($(zoomOutEl), 'mousedown', this.startZoomOut.bind(this)); 89 Event.observe($(zoomOutEl), 'mouseup', this.stopZooming.bind(this)); 90 Event.observe($(zoomOutEl), 'mouseout', this.stopZooming.bind(this)); 91 }, 92 93 toggleFull: function () { 94 this.showFull = !this.showFull; 95 96 val_scale = !this.showFull ? this.slider.value : 1; 97 this.scale(val_scale); 98 99 this.trackEl.style.visibility = this.showFull ? 'hidden' : 'visible'; 100 this.containerEl.style.overflow = this.showFull ? 'visible' : 'hidden'; 101 this.containerEl.style.zIndex = this.showFull ? '1000' : '9'; 102 103 return this; 104 }, 105 106 scale: function (v) { 107 var centerX = (this.containerDim.width*(1-this.imageZoom)/2-this.imageX)/this.imageZoom; 108 var centerY = (this.containerDim.height*(1-this.imageZoom)/2-this.imageY)/this.imageZoom; 109 var overSize = (this.imageDim.width > this.containerDim.width || this.imageDim.height > this.containerDim.height); 110 111 this.imageZoom = this.floorZoom+(v*(this.ceilingZoom-this.floorZoom)); 112 113 if (overSize) { 114 if (this.imageDim.width > this.imageDim.height) { 115 this.imageEl.style.width = (this.imageZoom*this.containerDim.width)+'px'; 116 } else { 117 this.imageEl.style.height = (this.imageZoom*this.containerDim.height)+'px'; 118 } 119 if (this.containerDim.ratio) { 120 if (this.imageDim.width > this.imageDim.height) { 121 this.imageEl.style.height = (this.imageZoom*this.containerDim.width*this.containerDim.ratio)+'px'; // for safari 122 } else { 123 this.imageEl.style.width = (this.imageZoom*this.containerDim.height*this.containerDim.ratio)+'px'; // for safari 124 } 125 } 126 } else { 127 this.slider.setDisabled(); 128 } 129 130 this.imageX = this.containerDim.width*(1-this.imageZoom)/2-centerX*this.imageZoom; 131 this.imageY = this.containerDim.height*(1-this.imageZoom)/2-centerY*this.imageZoom; 132 133 this.contain(this.imageX, this.imageY, this.draggable); 134 135 return true; 136 }, 137 138 startZoomIn: function() 139 { 140 if (!this.slider.disabled) { 141 this.zoomBtnPressed = true; 142 this.sliderAccel = .002; 143 this.periodicalZoom();
144 this.zoomer = new PeriodicalExecuter(this.periodicalZoom.bind(this), .05); 145 } 146 return this; 147 }, 148 149 startZoomOut: function() 150 { 151 if (!this.slider.disabled) { 152 this.zoomBtnPressed = true; 153 this.sliderAccel = -.002; 154 this.periodicalZoom(); 155 this.zoomer = new PeriodicalExecuter(this.periodicalZoom.bind(this), .05); 156 } 157 return this; 158 }, 159 160 stopZooming: function() 161 { 162 if (!this.zoomer || this.sliderSpeed==0) { 163 return; 164 } 165 this.zoomBtnPressed = false; 166 this.sliderAccel = 0; 167 }, 168 169 periodicalZoom: function() 170 { 171 if (!this.zoomer) { 172 return this; 173 } 174 175 if (this.zoomBtnPressed) { 176 this.sliderSpeed += this.sliderAccel; 177 } else { 178 this.sliderSpeed /= 1.5; 179 if (Math.abs(this.sliderSpeed)<.001) { 180 this.sliderSpeed = 0; 181 this.zoomer.stop(); 182 this.zoomer = null; 183 } 184 } 185 this.slider.value += this.sliderSpeed; 186 187 this.slider.setValue(this.slider.value); 188 this.scale(this.slider.value); 189 190 return this; 191 }, 192 193 contain: function (x,y,draggable) { 194 195 var dim = Element.getDimensions(draggable.element); 196 197 var xMin = 0, xMax = this.containerDim.width-dim.width; 198 var yMin = 0, yMax = this.containerDim.height-dim.height; 199 200 x = x>xMin ? xMin : x; 201 x = x<xMax ? xMax : x; 202 y = y>yMin ? yMin : y; 203 y = y<yMax ? yMax : y; 204 205 if (this.containerDim.width > dim.width) { 206 x = (this.containerDim.width/2) - (dim.width/2); 207 } 208 209 if (this.containerDim.height > dim.height) { 210 y = (this.containerDim.height/2) - (dim.height/2); 211 } 212 213 this.imageX = x; 214 this.imageY = y; 215 216 this.imageEl.style.left = this.imageX+'px'; 217 this.imageEl.style.top = this.imageY+'px'; 218 219 return [x,y]; 220 } 221}; 222 223/**************************** CONFIGURABLE PRODUCT **************************/ 224Product.Config = Class.create(); 225Product.Config.prototype = { 226 initialize: function(config){ 227 this.config = config; 228 this.taxConfig = this.config.taxConfig; 229 this.settings = $$('.super-attribute-select'); 230 this.state = new Hash(); 231 this.priceTemplate = new Template(this.config.template); 232 this.prices = config.prices; 233 234 this.settings.each(function(element){ 235 Event.observe(element, 'change', this.configure.bind(this)); 236 }.bind(this)); 237 238 // fill state 239 this.settings.each(function(element){ 240 var attributeId = element.id.replace(/[a-z]*/, ''); 241 if(attributeId && this.config.attributes[attributeId]) { 242 element.config = this.config.attributes[attributeId]; 243 element.attributeId = attributeId; 244 this.state[attributeId] = false; 245 } 246 }.bind(this)); 247 248 // Init settings dropdown 249 var childSettings = []; 250 for(var i=this.settings.length-1;i>=0;i--){ 251 var prevSetting = this.settings[i-1] ? this.settings[i-1] : false; 252 var nextSetting = this.settings[i+1] ? this.settings[i+1] : false; 253 if(i==0){ 254 this.fillSelect(this.settings[i]); 255 } 256 else { 257 this.settings[i].disabled=true; 258 } 259 $(this.settings[i]).childSettings = childSettings.clone(); 260 $(this.settings[i]).prevSetting = prevSetting; 261 $(this.settings[i]).nextSetting = nextSetting; 262 childSettings.push(this.settings[i]); 263 } 264 265 // Set default values - from config and overwrite them by url values 266 if (config.defaultValues) { 267 this.values = config.defaultValues; 268 } 269 270 var separatorIndex = window.location.href.indexOf('#'); 271 if (separatorIndex != -1) { 272 var paramsStr = window.location.href.substr(separatorIndex+1); 273 var urlValues = paramsStr.toQueryParams(); 274 if (!this.values) { 275 this.values = {}; 276 } 277 for (var i in urlValues) { 278 this.values[i] = urlValues[i]; 279 } 280 } 281 282 this.configureForValues(); 283 document.observe("dom:loaded", this.configureForValues.bind(this)); 284 }, 285 286 configureForValues: function () { 287 if (this.values) { 288 this.settings.each(function(element){ 289 var attributeId = element.attributeId; 290 element.value = (typeof(this.values[attributeId]) == 'undefined')? '' : this.values[attributeId]; 291 this.configureElement(element); 292 }.bind(this)); 293 } 294 }, 295 296 configure: function(event){ 297 var element = Event.element(event); 298 this.configureElement(element); 299 }, 300 301 configureElement : function(element) { 302 this.reloadOptionLabels(element); 303 if(element.value){ 304 this.state[element.config.id] = element.value; 305 if(element.nextSetting){ 306 element.nextSetting.disabled = false;
307 this.fillSelect(element.nextSetting); 308 this.resetChildren(element.nextSetting); 309 } 310 } 311 else { 312 this.resetChildren(element); 313 } 314 this.reloadPrice(); 315// Calculator.updatePrice(); 316 }, 317 318 reloadOptionLabels: function(element){ 319 var selectedPrice; 320 if(element.options[element.selectedIndex].config){ 321 selectedPrice = parseFloat(element.options[element.selectedIndex].config.price); 322 } 323 else{ 324 selectedPrice = 0; 325 } 326 for(var i=0;i<element.options.length;i++){ 327 if(element.options[i].config){ 328 element.options[i].text = this.getOptionLabel(element.options[i].config, element.options[i].config.price-selectedPrice); 329 } 330 } 331 }, 332 333 resetChildren : function(element){ 334 if(element.childSettings) { 335 for(var i=0;i<element.childSettings.length;i++){ 336 element.childSettings[i].selectedIndex = 0; 337 element.childSettings[i].disabled = true; 338 if(element.config){ 339 this.state[element.config.id] = false; 340 } 341 } 342 } 343 }, 344 345 fillSelect: function(element){ 346 var attributeId = element.id.replace(/[a-z]*/, ''); 347 var options = this.getAttributeOptions(attributeId); 348 this.clearSelect(element); 349 element.options[0] = new Option('', ''); 350 element.options[0].innerHTML = this.config.chooseText; 351 352 var prevConfig = false; 353 if(element.prevSetting){ 354 prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex]; 355 } 356 357 if(options) { 358 var index = 1; 359 for(var i=0;i<options.length;i++){ 360 var allowedProducts = []; 361 if(prevConfig) { 362 for(var j=0;j<options[i].products.length;j++){ 363 if(prevConfig.config.allowedProducts 364 && prevConfig.config.allowedProducts.indexOf(options[i].products[j])>-1){ 365 allowedProducts.push(options[i].products[j]); 366 } 367 } 368 } else { 369 allowedProducts = options[i].products.clone(); 370 } 371 372 if(allowedProducts.size()>0){ 373 options[i].allowedProducts = allowedProducts; 374 element.options[index] = new Option(this.getOptionLabel(options[i], options[i].price), options[i].id); 375 element.options[index].config = options[i]; 376 index++; 377 } 378 } 379 } 380 }, 381 382 getOptionLabel: function(option, price){ 383 var price = parseFloat(price); 384 if (this.taxConfig.includeTax) { 385 var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax; 386 var excl = price - tax; 387 var incl = excl*(1+(this.taxConfig.currentTax/100)); 388 } else { 389 var tax = price * (this.taxConfig.currentTax / 100); 390 var excl = price; 391 var incl = excl + tax; 392 } 393 394 if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) { 395 price = incl; 396 } else { 397 price = excl; 398 } 399 400 var str = option.label; 401 if(price){ 402 if (this.taxConfig.showBothPrices) { 403 str+= ' ' + this.formatPrice(excl, true) + ' (' + this.formatPrice(price, true) + ' ' + this.taxConfig.inclTaxTitle + ')'; 404 } else { 405 str+= ' ' + this.formatPrice(price, true); 406 } 407 } 408 return str; 409 }, 410 411 formatPrice: function(price, showSign){ 412 var str = ''; 413 price = parseFloat(price); 414 if(showSign){ 415 if(price<0){ 416 str+= '-'; 417 price = -price; 418 } 419 else{ 420 str+= '+'; 421 } 422 } 423 424 var roundedPrice = (Math.round(price*100)/100).toString(); 425 426 if (this.prices && this.prices[roundedPrice]) { 427 str+= this.prices[roundedPrice]; 428 } 429 else { 430 str+= this.priceTemplate.evaluate({price:price.toFixed(2)}); 431 } 432 return str; 433 }, 434 435 clearSelect: function(element){ 436 for(var i=element.options.length-1;i>=0;i--){ 437 element.remove(i); 438 } 439 }, 440 441 getAttributeOptions: function(attributeId){ 442 if(this.config.attributes[attributeId]){ 443 return this.config.attributes[attributeId].options; 444 } 445 }, 446 447 reloadPrice: function(){ 448 var price = 0; 449 var oldPrice = 0; 450 for(var i=this.settings.length-1;i>=0;i--){ 451 var selected = this.settings[i].options[this.settings[i].selectedIndex]; 452 if(selected.config){ 453 price += parseFloat(selected.config.price); 454 oldPrice += parseFloat(selected.config.oldPrice); 455 } 456 } 457 458 optionsPrice.changePrice('config', {'price': price, 'oldPrice': oldPrice}); 459 optionsPrice.reload(); 460 461 return price; 462 }, 463 464 reloadOldPrice: function(){ 465 if ($('old-price-'+this.config.productId)) { 466 467 var price = parseFloat(this.config.oldPrice); 468 for(var i=this.settings.length-1;i>=0;i--){ 469 var selected = this.settings[i].options[this.settings[i].selectedIndex]; 470 if(selected.config){ 471 var parsedOldPrice = parseFloat(selected.config.oldPrice); 472 price += isNaN(parsedOldPrice) ? 0 : parsedOldPrice; 473 } 474 } 475 if (price < 0) 476 price = 0; 477 price = this.formatPrice(price); 478 479 if($('old-price-'+this.config.productId)){ 480 $('old-price-'+this.config.productId).innerHTML = price; 481 } 482 483 } 484 } 485}; 486 487 488/**************************** SUPER PRODUCTS ********************************/ 489 490Product.Super = {}; 491Product.Super.Configurable = Class.create(); 492 493Product.Super.Configurable.prototype = { 494 initialize: function(container, observeCss, updateUrl, updatePriceUrl, priceContainerId) { 495 this.container = $(container); 496 this.observeCss = observeCss; 497 this.updateUrl = updateUrl; 498 this.updatePriceUrl = updatePriceUrl; 499 this.priceContainerId = priceContainerId; 500 this.registerObservers(); 501 }, 502 registerObservers: function() { 503 var elements = this.container.getElementsByClassName(this.observeCss); 504 elements.each(function(element){ 505 Event.observe(element, 'change', this.update.bindAsEventListener(this)); 506 }.bind(this)); 507 return this; 508 }, 509 update: function(event) { 510 var elements = this.container.getElementsByClassName(this.observeCss); 511 var parameters = Form.serializeElements(elements, true); 512 513 new Ajax.Updater(this.container, this.updateUrl + '?ajax=1', { 514 parameters:parameters, 515 onComplete:this.registerObservers.bind(this) 516 }); 517 var priceContainer = $(this.priceContainerId); 518 if(priceContainer) { 519 new Ajax.Updater(priceContainer, this.updatePriceUrl + '?ajax=1', { 520 parameters:parameters 521 }); 522 } 523 } 524};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.