PageSourceSearch

https://www.quiltsourcecanada.ca/application/modules/core/Catalog/Assets/Js/product_preview.js

js quiltsourcecanada.ca collected 2026-09-27 04:44:54 UTC 23,328 bytes, 680 lines download raw bytes

1window.catalog = window.catalog || {};
2catalog.alternateParts = catalog.alternateParts || [];
3
4window.catalog.ProductPreview = function (data) {
5    var self = this;
6
7    self.exists = data.exists;
8    self.warehouseId = data.warehouse_id;
9    self.warehouseForUrl = data.warehouse_for_url;
10    self.partNumber = data.part_number;
11    self.customerPartNumber = ko.observable(data.customerPartNumber);
12    self.newCustomerPartNumber = ko.observable("");
13    self.slug = data.slug;
14    self.cartComments = data.cartComments;
15    self.partIdForUrl = data.part_id_for_url;
16    self.url = data.url;
17    self.upc = data.upc;
18    self.title = data.title;
19    self.salesDept = data.salesDept;
20    self.isNew = data.new_status && data.new_status.start && data.new_status.start !== "";
21    self.newAsOf = self.isNew ? data.new_status.start : "";
22    self.shortDescription = data.short_description;
23    self.longDescription = data.long_description;
24    self.HTMLDescription = data.HTML_description;
25    self.descriptionForUrl = data.description_for_url;
26    self.thumbnails = data.thumbnails;
27    self.defaultCategory = data.default_category;
28    self.manufacturer = data.manufacturer;
29    self.customFields = data.custom_fields;
30    self.stock = data.stock;
31    self.statuses = data.statuses;
32    self.isOnSale = false;
33    self.onSaleStatuses = [];
34    self.price = parseFloat(data.price);
35    self.priceText = "$" + data.price;
36    self.list_price = parseFloat(data.list_price);
37    self.listPriceText = "$" + data.list_price;
38    self.qty = $('#grid-list-view-toggle-container div.list-view img.list-view-on').is(':visible') && $('div.add-all-to-cart').is(':visible') ? ko.observable("") : ko.observable(1);
39    self.qtyFieldId = "qty_" + data.warehouse_id + "_" + data.part_number;
40    self.qtyFieldName = "shopping_cart[add][" + data.warehouse_id + "][" + data.part_number + "][quantity]";
41    self.uoms = data.uoms;
42    self.defaultUom = ko.observable(data.default_uom);
43    self.uomFieldName = "shopping_cart[add][" + data.warehouse_id + "][" + data.part_number + "][uom]";
44    self.is_quote_only = data.is_quote_only;
45    self.showAddToCartForQuotableProducts = Quote.showAddToCartForQuotableProducts;
46    self.selectedUOM = ko.observable(data.default_uom);
47    self.isSelectedForCompare = data.isSelectedForCompare;
48    self.addons = data.addons;
49    self.isDigitalProduct = data.isDigitalProduct;
50    self.partDiagrams = data.partDiagrams;
51    self.hasPartDiagrams = data.partDiagrams.length > 0 ? 1 : 0;
52    self.packSize = data.packSize;
53    self.isPriceVisible = data.isPriceVisible;
54    self.isAddToCartVisible = data.isAddToCartVisible;
55    self.isKittedProduct = data.isKittedProduct;
56    self.reorderPoint = data.reorderPoint;
57    self.minimumOrderQty = data.minimumOrderQty;
58    self.promotion = data.promotion;
59    self.isTrainingCourse = data.isTrainingCourse;
60    self.trainingCourses = data.trainingCourses;
61    self.yearToDateGrossSales = data.yearToDateGrossSales;
62    self.images = data.images;
63    self.orderTemplates = ko.observable();
64    self.alternateParts = !_.isUndefined(data.alternate_parts) ? data.alternate_parts : [];
65    self.preOrderPricing = data.preOrderPricing;
66    self.displayDefaultUomOnly = window.displayDefaultUomOnly;
67    self.productUomDisplaySetting = window.productUomDisplaySetting;
68    self.favouriteData = data.favouriteData;
69    self.preloadedFavourite = !_.isUndefined(data.favouriteData) && data.favouriteData.isPreloaded === "1";
70    self.productSelectorGroup = data.productSelectorGroup;
71    self.productSelectorGroupData = data.productSelectorGroupData;
72    self.onlyDisplayAlternates = onlyDisplayAlternates;
73    self.displayAlternateField = displayAlternateField;
74    self.isOnSaleNotification = ko.observable(false);
75    self.isInStockNotification = ko.observable(false);
76    self.relatedFiles = _.values(data.related_files);
77    self.isPurchasable = data.isPurchasable;
78    self.isFavourite = data.isFavourite;
79    self.equipmentRegistryDetails = !_.isUndefined(data.equipmentRegistryDetails) ? data.equipmentRegistryDetails : [];
80    self.differentActiveWarehouse = !_.isUndefined(data.differentActiveWarehouse) ? data.differentActiveWarehouse : false;
81    self.inlineProductAssociations = data.inlineProductAssociations;
82
83    self.hasDiscount = function () {
84        var listPrice = parseFloat(data.list_price.replace(/,/g, ""));
85        var price = parseFloat(data.price.replace(/,/g, ""));
86
87        return (listPrice > price) ? true : false;
88    };
89
90    self.outputProductStatusClasses = function () {
91        var productStatus = "";
92        _.forEach(self.statuses, function (status) {
93            if (status.name === "on_sale") {
94                productStatus = prepProductStatusClass(status.name);
95            } else if (productStatus === "") {
96                productStatus = prepProductStatusClass(status.name);
97            }
98        });
99
100        return productStatus;
101    };
102
103    var prepProductStatusClass = function (status) {
104        var classes = "product_status_icon ";
105        var string = String(status).replace(/,/g, " ");
106
107        return classes + string;
108    };
109
110    self.outputProductStatusImage = function () {
111        var statusImage = "";
112        _.forEach(self.statuses, function (status) {
113            if (status.name === "on_sale") {
114                statusImage = status.image;
115            } else if (statusImage === "") {
116                statusImage = status.image;
117            }
118        });
119
120        return statusImage;
121    };
122
123    self.hasStatus = function (name) {
124        return _.some(self.statuses, function(status) {
125            return (name == status.name);
126        });
127    };
128
129    self.hasManufacturer = function () {
130        return self.manufacturer.id > 0;
131    };
132
133    self.hasCustomField = function (name) {
134        return _.some(self.customFields, function(field) {
135            return (name == field.name);
136        });
137    };
138
139    self.getCustomField = function (name) {
140        var customField;
141        _.forEach(self.customFields, function (field) {
142            if (name == field.name) {
143                customField = field;
144            }
145        });
146
147        return customField;
148    };
149
150    self.selectedUomObj = ko.computed(function () {
151        var selectedUOM = self.selectedUOM();
152        var found = null;
153        $.each(self.uoms, function (k, uom) {
154            if (uom.code == selectedUOM) {
155                found = uom;
156            }
157        });
158
159        return found;
160    });
161
162    self.showQuoteButton = ko.computed(function () {
163        return _.result(_.find(self.uoms, function (uom) {
164            return uom.code == self.selectedUOM();
165        }), "is_quote_only");
166    });
167
168    self.showPrice = ko.computed(function () {
169        return self.isPriceVisible &&
170        (!self.showQuoteButton() || self.showAddToCartForQuotableProducts) &&
171        self.selectedUomObj() && self.selectedUomObj().price != 0;
172    });
173
174    self.canAddToCart = function () {
175        var visible = self.isAddToCartVisible ? true : false;
176
177        if (visible && self.isPriceVisible && self.selectedUomObj().price === 0) {
178            visible = false;
179        }
180
181        return visible;
182    };
183
184    self.hasUomWithPrice = function () {
185        return _.find(self.uoms, function (uom) { return uom.price != 0; }) ? true : false;
186    };
187
188    self.isQuotable = function () {
189        return _.find(self.uoms, 'is_quote_only') ? true : false;
190    };
191
192    self.showUomAndQty = function () {
193        if ((self.isAddToCartVisible && self.isPriceVisible && self.hasUomWithPrice()) || self.isQuotable()) {
194            return true;
195        }
196
197        return false;
198    };
199
200    self.prep_alternate_parts = function (product) {
201        if (product.alternate_parts !== undefined && product.alternate_parts !== null) {
202            var alternateParts = product.alternate_parts;
203
204            if (alternateParts.alts !== undefined && alternateParts.alts !== null && alternateParts.alts.length > 0) {
205                catalog.alternateParts[product.slug] = alternateParts;
206            }
207        }
208    };
209
210    self.prep_alternate_parts(data);
211
212    self.prepUnitsOfMeasure = function (defaultUom) {
213        var unitsOfMeasure = [];
214        var defaultUnitOfMeasure = null;
215
216        _.forEach(self.uoms, function (uom) {
217            if (uom.code === defaultUom) {
218                uom.is_default = true;
219                defaultUnitOfMeasure = uom;
220            } else if (uom.isSellUom) {
221                uom.is_default = false;
222                unitsOfMeasure.push(uom);
223            }
224        });
225
226        if (defaultUnitOfMeasure !== null) {
227            unitsOfMeasure.unshift(defaultUnitOfMeasure);
228        }
229
230        self.uoms = unitsOfMeasure;
231    };
232
233    self.prepUnitsOfMeasure(data.default_uom);
234
235    self.getImage = function (key, size) {
236        return data.images[key][size];
237    };
238
239    self.defaultImage = ko.observable(self.getImage(0, "medium"));
240
241    var defaultAltText = data.images[0].altText ? data.images[0].altText : data.title;
242    self.defaultImage.width = ko.observable(data.images[0].medium.width);
243    self.defaultImage.height = ko.observable(data.images[0].medium.height);
244    self.defaultImage.src = ko.observable(data.images[0].medium.src);
245    self.defaultImage.srcSet = ko.observable(data.images[0].medium.srcSet);
246    self.defaultImage.sizes = ko.observable(data.images[0].medium.sizes);
247    self.defaultImage.altText = ko.observable(defaultAltText);
248    self.enlargeImage = ko.observable(self.getImage(0, "large"));
249
250    self.setDetailsImage = function (index, image) {
251        self.defaultImage(image);
252        self.defaultImage.width(data.images[index].medium.width);
253        self.defaultImage.height(data.images[index].medium.height);
254        self.defaultImage.src(data.images[index].medium.src);
255        self.defaultImage.srcSet(data.images[index].medium.srcSet);
256        self.defaultImage.sizes(data.images[index].medium.sizes);
257        self.defaultImage.altText(data.images[index].altText);
258        self.enlargeImage(self.getImage(index, "large"));
259    };
260
261    self.humanize = function (value) {
262        temp = $.trim(value).toLowerCase();
263        temp = temp.replace(/[_-]+/g, ' ');
264
265        return temp.charAt(0).toUpperCase() + temp.slice(1);
266    };
267
268    self.machinize = function (value) {
269        temp = $.trim(value).toLowerCase();
270
271        return temp.replace(/\s+/g, '_');
272    };
273
274    self.buildProductRatings = function (rating) {
275        var self = this;
276        var fullStarsArray = [];
277        var halfStarsArray = [];
278        var emptyStarsArray = [];
279
280        if (!_.isUndefined(rating) && rating != null) {
281            var i = 0;
282
283            for (i = 0; i < rating.full_stars; i++) {
284                fullStarsArray[i] = i;
285            }
286
287            for (i = 0; i < rating.half_stars; i++) {
288                halfStarsArray[i] = i;
289            }
290
291            for (i = 0; i < rating.empty_stars; i++) {
292                emptyStarsArray[i] = i;
293            }
294
295            self.rating = {
296                "averageRating": rating.average_rating,
297                "reviewCount": rating.review_count,
298                "maxReviewRating": rating.max_review_rating,
299                "fullStars": fullStarsArray,
300                "halfStars": halfStarsArray,
301                "emptyStars": emptyStarsArray
302            };
303        }
304    };
305
306    self.buildProductRatings(data.rating);
307
308    self.buildQuantityBreaks = function (quantityBreaks) {
309        var availableRanges = [];
310        var qbcount = self.findQuantityBreakCount(quantityBreaks);
311        $.each(quantityBreaks, function (uom, quantityBreak) {
312            var length = _.size(quantityBreak);
313            var ranges = [];
314            var liClass = "li_" + uom + " ";
315            var divClass = "qb_" + uom + " quantity_break_container ";
316
317            liClass += (self.defaultUom() == uom || qbcount == 1) ? "selected" : "";
318            divClass += (self.defaultUom() == uom || qbcount == 1) ? " show" : " hide";
319
320            $.each(quantityBreak, function (range, value) {
321                var thisRange = {
322                    "lowerBound": value.lowerBound,
323                    "rangeName": range,
324                    "actualPrice": value.formatted_actual_price
325                };
326
327                ranges.push(thisRange);
328            });
329
330            var thisUom = {
331                "liClass": liClass,
332                "divClass": divClass,
333                "name": uom,
334                "ranges": ranges
335            };
336
337            availableRanges.push(thisUom);
338        });
339
340        self.quantityBreaks = {
341            "availableRanges": availableRanges,
342            "quantityBreaksAvailable": (availableRanges.length > 0) ? true : false
343        };
344    };
345
346    self.findQuantityBreakCount = function (qbs) {
347        var count = 0;
348        for (var k in qbs) {
349            if (qbs.hasOwnProperty(k)) {
350                count++;
351            }
352        }
353        return count;
354    };
355
356    self.doesUomHaveQuantityBreaks = function() {
357        return _.find(self.quantityBreaks.availableRanges, {name: self.selectedUOM()});
358    };
359
360    self.getCartCommentForUom = function () {
361        return (self.selectedUOM() in self.cartComments) ? self.cartComments[self.selectedUOM()] : "";
362    };
363
364    self.buildQuantityBreaks(data.quantity_breaks);
365
366    self.displayQuickViewModal = function () {
367        $("#quick-view-modal-" + self.slug).modal("show");
368    };
369
370    self.getTrainingCourseLocation = function () {
371        return self.trainingCourses[0].location;
372    };
373
374    self.loadOrderTemplates = function (data) {
375        slug = data.product.slug;
376        orderTemplates.loadOrderTemplates(slug, data.product.selectedUOM()).done(function (data) {
377            self.orderTemplates(data);
378            $("#order-template-modal-" + slug).modal();
379        });
380    };
381
382    self.getTitleForOrderTemplateModal = function () {
383        if (hidePartNumber) {
384            return self.title;
385        }
386
387        return self.partNumber + ' - ' + self.title;
388    };
389
390    self.removeFavourite = function(id, e) {
391        if (confirmFavouriteDelete()) {
392            $(".ajax-load-overlay").show();
393
394            $.ajax({
395                url: base_index_url + "my_account/favourites/delete",
396                type: "POST",
397                data: {
398                    id: id
399                },
400                success: function( data ) {
401                    $(e).closest(".product_preview").fadeOut(100, function() {
402                        $(this).parent().remove();
403
404                        if ($(".product_preview").length === 0) {
405                            $("#favourites-products").remove();
406                            $(".no-favourites").show();
407                        }
408                    });
409
410                    Notifications.success(data);
411                },
412                error: function(jqXHR, textStatus, errorThrown) {
413                    Notifications.fail(jqXHR.responseText);
414                },
415                complete: function(data) {
416                    $(".ajax-load-overlay").hide();
417                }
418            });
419        }
420    };
421
422    self.getProductsArray = function (data) {
423        return [{"product": data}];
424    };
425
426    self.displayAlternatesModal = function () {
427        $("#alternate-products-modal-" + self.slug).modal();
428    };
429
430    self.hasAlternatesForDisplay = function () {
431        if (self.onlyDisplayAlternates === "1" && doesProductHaveAlternateCustomField()) {
432            return true;
433        }
434
435        return false;
436    };
437
438    var doesProductHaveAlternateCustomField = function () {
439        var hasField = false;
440        _.forEach(self.customFields, function (field) {
441            if (field.name === self.displayAlternateField) {
442                hasField = true;
443            }
444        });
445
446        return hasField;
447    };
448
449    var extractAlternatePartNums = function (data) {
450        return _.map(data.alts, "pn");
451    };
452
453    self.getAlternates = function (data) {
454        $.ajax({
455            url: base_index_url + "alternate-parts",
456            data: {
457                "alternatePartNumbers": extractAlternatePartNums(data.alternateParts),
458            },
459            dataType: "json",
460            type: "POST",
461            success: function (data) {
462                _.forEach(data, function (preview) {
463                    var detailProduct = new window.catalog.ProductPreview(preview);
464                    var element = document.getElementById("product-preview-modal-" + detailProduct.slug);
465
466                    ko.cleanNode(element);
467                    ko.applyBindings(detailProduct, element);
468                });
469            }
470        });
471
472    };
473
474    self.checkIsGridView = function () {
475        return true;
476    };
477
478    self.displayPreOrderPricing = function () {
479        $(".pre-order-pricing-button").popover({
480            container: "body",
481            html: true,
482            content: function() {
483                popoverContent = $(this).parent().find(".pre-order-pricing").html();
484                return popoverContent;
485            }
486        })
487        .on('shown.bs.popover',function(e){
488            $(".popover").css("min-width","600px");
489        });
490    };
491
492    self.hasPreOrderPricing = function () {
493        return self.preOrderPricing.length > 0;
494    };
495
496    self.showCustomerPartNumberModal = function (data) {
497        self.showModal("#customer-part-number-modal-" + self.slug);
498    };
499
500    self.showModal = function (id) {
501        $(id).modal();
502    };
503
504    self.hideModal = function (id) {
505        $(id).modal("hide");
506    };
507
508    self.hasCustomerPartNumber = ko.computed(function () {
509        return !_.isEmpty(self.customerPartNumber());
510    });
511
512    self.saveCustomerPartNumber = function () {
513        var customerPartNumberError = $("#customer-part-number-error");
514
515        customerPartNumberError.addClass("hide");
516
517        if (!isAlphanumericDashUnderscore(self.newCustomerPartNumber())) {
518            customerPartNumberError.removeClass("hide");
519        } else {
520            $.ajax({
521                url: base_index_url + "customer-part-number",
522                type: "POST",
523                data: {
524                    partNum: self.partNumber,
525                    customerPartNumber: self.newCustomerPartNumber()
526                },
527                dataType: "json",
528                success: function(response) {
529                    self.updateCustomerPartNumber(self.newCustomerPartNumber());
530                    self.hideModal("#customer-part-number-modal-" + self.slug);
531
532                    Notifications.success(response.message);
533                },
534                error: function(jqXHR, textStatus, errorThrown) {
535                    Notifications.fail(jqXHR.responseText);
536                }
537            });
538        }
539    };
540
541    self.deleteCustomerPartNumber = function () {
542        $.ajax({
543            url: base_index_url + "customer-part-number/delete",
544            type: "POST",
545            data: {
546                partNum: self.partNumber,
547            },
548            dataType: "json",
549            success: function(response) {
550                self.updateCustomerPartNumber("");
551                self.hideModal("#customer-part-number-modal-" + self.slug);
552
553                Notifications.success(response.message);
554            },
555            error: function(jqXHR, textStatus, errorThrown) {
556                Notifications.fail(jqXHR.responseText);
557            }
558        });
559    };
560
561    self.updateCustomerPartNumber = function (value) {
562        self.customerPartNumber(value);
563        self.newCustomerPartNumber("");
564    };
565
566    self.loadNotifyMeTemplates = function (vm, data, email) {
567        if (email) {
568            $.ajax({
569                url: base_index_url + "notify-me",
570                type: "POST",
571                data: {
572                    partNum: self.partNumber,
573                    warehouse: self.warehouseId,
574                    email: email
575                },
576                dataType: "json",
577                success: function(response) {
578                    self.isOnSaleNotification(_.includes(response,"OnSale"));
579                    self.isInStockNotification(_.includes(response,"BackInStock"));
580                },
581                error: function(jqXHR, textStatus, errorThrown) {
582                    Notifications.fail(jqXHR.responseText);
583                }
584            });
585        }
586
587        self.showModal("#notify-me-template-modal-" + self.slug);
588    };
589
590    self.updateNotifications = function () {
591        var email = $("#notify-email-" + self.slug).val();
592
593        $.ajax({
594            url: base_index_url + "notify-me/create",
595            type: "POST",
596            data: {
597                partNum: self.partNumber,
598                warehouse: self.warehouseId,
599                email: email,
600                conditions : {
601                    OnSale : self.isOnSaleNotification,
602                    BackInStock : self.isInStockNotification
603                }
604            },
605            dataType: "json",
606            success: function(response) {
607                Notifications.success(response.message);
608            },
609            error: function(jqXHR, textStatus, errorThrown) {
610                Notifications.fail(jqXHR.responseText);
611            }
612        });
613
614        self.hideModal("#notify-me-template-modal-" + self.slug);
615    };
616
617    self.showSelectedUomOnSaleEndDate = function (uom, price) {
618        var roundedSaleprice = roundPrice(price);
619        var roundedPrice = roundPrice(self.price);
620
621        return uom == self.selectedUOM() && roundedSaleprice > roundedPrice;
622    };
623
624    self.formatDate = function (date, format)
625    {
626        return moment(date).format(format);
627    };
628
629    self.hasEquipmentRegistryDetails = function () {
630        return !_.isEmpty(self.equipmentRegistryDetails);
631    };
632
633    self.equipmentRegistryId = function() {
634        return self.hasEquipmentRegistryDetails() ? self.equipmentRegistryDetails.equipmentRegistryId : "";
635    };
636
637    self.showPartDiagramsCondensed = function () {
638        return self.hasPartDiagrams && self.partDiagrams.length > 5;
639    };
640
641    self.showPartDiagram = function () {
642        if (!_.isEmpty(self.chosenDiagram)) {
643            window.location = self.chosenDiagram.url;
644        }
645    };
646
647    self.hasRelatedFiles = function () {
648        return self.relatedFiles.length > 0;
649    };
650
651    self.hasInlineProductAssociations = function () {
652        return self.inlineProductAssociations.length > 0 ? true : false;
653    };
654
655    var roundPrice = function (price) {
656        return Math.round((price + Number.EPSILON) * 100) / 100;
657    };
658
659    (function () {
660        _.forEach(self.statuses, function (status) {
661            if (status.name === "on_sale") {
662                self.onSaleStatuses.push(status);
663            }
664        });
665
666        _.forEach(self.statuses, function (status) {
667            if (status.name === "on_sale") {
668                self.isOnSale = true;
669            }
670        });
671    })();
672
673    $("#search-container").on("mouseenter", ".product_list .product_preview, .product_list .product_preview_list", function() {
674        $(this).find(".quick-view-trigger").fadeIn("fast");
675    });
676
677    $("#search-container").on("mouseleave", ".product_list .product_preview, .product_list .product_preview_list", function() {
678        $(this).find(".quick-view-trigger").fadeOut("fast");
679    });
680};

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.