PageSourceSearch

https://www.bread.com.tw/js/varien/product.js

js bread.com.tw collected 2026-10-02 06:33:46 UTC 17,838 bytes, 524 lines download raw bytes

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.