PageSourceSearch

https://www.havencityhall.org/1767619478/c/cart/cart.js

js havencityhall.org collected 2026-09-25 10:58:20 UTC 79,559 bytes, 2,293 lines download raw bytes

1/* Shopping Cart (2017 version) */
2
3Array.prototype.remove = function(from, to) {
4    var rest = this.slice((to || from) + 1 || this.length);
5    this.length = from < 0 ? this.length + from : from;
6    return this.push.apply(this, rest);
7};
8
9if (!window.domesticCountry) {
10    window.domesticCountry = 'United States';
11}
12
13var linkStyles = 'color: #fff !important; text-decoration:underline !important; font-family: Arial !important; font-size: 12px !important; font-weight: normal !important;';
14var checkoutUrl = window.CheckoutUrl;
15if (checkoutUrl.indexOf('?') < 0) {
16    checkoutUrl += "?1";
17}
18var editcartUrl = window.EditCartUrl;
19if (editcartUrl.indexOf('?') < 0) {
20    editcartUrl += "?1";
21}
22
23//module to make cart requests synchronous
24var requestModule = (function() {
25    var instance;
26    var readyForNext = true;
27
28    var addItemToCart = function(postData) {
29        return new Promise(function (resolve) {
30            var intervalId = setInterval(function() {
31                if (readyForNext === true) {
32                    var cartUuid = getCartUuidFromCookie();
33
34                    resolve(sendCartItem(cartUuid, postData));
35
36                    clearInterval(intervalId);
37                }
38            }, 100);
39        });
40    }
41
42    var sendCartItem = function(cartUuid, postData) {
43        readyForNext = false;
44        var axios = getAxiosInstance();
45
46        return axios.post("/api/cart/" + cartUuid + "/item", postData).then(function(response) {
47            if (response && response.data && response.data.success) {
48                if (response.data.uuid) {
49                    setCartUuidCookie(response.data.uuid);
50                }
51                if (response.data.data) {
52                    CreateCartArray(response.data.data);
53                    ShowCart(true);
54                }
55            } else {
56                alert('There was an error adding this item to your cart.');
57            }
58        })
59            .catch(function (error) {
60                var errorMessage = error.response && error.response.data && error.response.data.error;
61
62                alert(errorMessage || 'There was an error adding this item to your cart.');
63            })
64            .finally(function() {
65                readyForNext = true;
66            });
67    }
68
69    var createInstance = function() {
70        return {
71            addItemToCart: addItemToCart
72        }
73    }
74
75    return {
76        getInstance: function() {
77            return instance || (instance = createInstance());
78        }
79    }
80}());
81
82function Set_Cart_Cookie_Cookie(name, value, expires, path, domain, secure) {
83    var today = new Date();
84    today.setTime(today.getTime());
85
86    if (expires) {
87        expires = expires * 1000 * 60 * 60 * 24;
88    }
89    var expires_date = new Date(today.getTime() + (expires));
90
91    if (domain == '') {
92        domain = document.domain.split('.');
93        if (domain[domain.length - 1].toLowerCase() == 'au' || domain[domain.length - 1].toLowerCase() == 'uk' || domain[domain.length - 1].toLowerCase() == 'nz' || domain[domain.length - 1].toLowerCase() == 'za') {
94            domain = domain[domain.length - 3] + '.' + domain[domain.length - 2] + '.' + domain[domain.length - 1];
95        } else {
96            domain = domain[domain.length - 2] + '.' + domain[domain.length - 1];
97        }
98    }
99
100    while (value.substring(0, 4) == 'null') {
101        value = value.substring(4);
102    }
103
104    value = escape(value);
105    var count = 0;
106    var lastIndex = 0;
107
108    while (value.length > lastIndex) {
109
110        var segment = value.substring(lastIndex, lastIndex + 4000);
111        if (value.length > lastIndex + 4000) {
112            var lastPos = segment.lastIndexOf('%');
113            if (lastPos > 0) {
114                segment = segment.substring(0, lastPos);
115                lastIndex = lastIndex + lastPos;
116            }
117            else {
118                lastIndex = lastIndex + 4000;
119            }
120        }
121        else {
122            lastIndex = lastIndex + 4000;
123        }
124
125        document.cookie = name + (count > 0 ? count : '') + "=" + segment +
126            ( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) +
127            ( ( path ) ? ";path=" + path : "" ) +
128            ( ( domain ) ? ";domain=" + domain : "" ) +
129            ( ( secure ) ? ";secure" : "" );
130
131        count++;
132    }
133
134    if (count > 0) {
135        // Delete any leftover cookies if the amount to be stored is shrinking (they are removing items from the shopping cart)
136        document.cookie = name + (count > 0 ? count : '') + "=" +
137            ( ( path ) ? ";path=" + path : "") +
138            ( ( domain ) ? ";domain=" + domain : "" ) +
139            ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
140    }
141}
142
143function trimUuid(uuid) {
144    var trimmed = '';
145    if(typeof uuid === 'string') {
146        trimmed = uuid.substr(0,36);
147    }
148    return trimmed;
149}
150
151function setCartUuidCookie(uuid) {
152    uuid = trimUuid(uuid);
153    var name = 'cart_id';
154    var days = 31;
155    var expires = "";
156    var date = new Date();
157    date.setTime(date.getTime() + (days*24*60*60*1000));
158    expires = "; expires=" + date.toUTCString();
159    document.cookie = name + "=" + (uuid || "")  + expires + "; path=/";
160}
161function getCartUuidFromCookie() {
162    var name = 'cart_id';
163    var nameEQ = name + "=";
164    var ca = document.cookie.split(';');
165    for(var i=0;i < ca.length;i++) {
166        var c = ca[i];
167        while (c.charAt(0)==' ') {
168            c = c.substring(1,c.length);
169        }
170        if (c.indexOf(nameEQ) == 0) {
171            var uuid = c.substring(nameEQ.length,c.length);
172            return trimUuid(uuid);
173        }
174    }
175    return null;
176}
177
178function getAxiosInstance() {
179    if (window.knobby && window.knobby.module_website_vue_use_one_lib_for_all_places) {
180        const config = {};
181        if (this.cartJWT) {
182            config.headers = {
183                Authorization: 'Bearer ' + window.cartJWT,
184            };
185        }
186        return axios.create(config);
187    } else {
188        let instance = axios.create();
189        if (window.cartJWT) {
190            instance.defaults.headers.common['Authorization'] = 'Bearer ' + window.cartJWT;
191        }
192        return instance;
193    }
194}
195
196
197function addItemToCartData(data, classPackageData) {
198    var postData = {
199        'item_data': encodeURIComponent(data)
200    };
201
202    // Pass Class packageData with the class to avoid async race conditions
203    if (classPackageData && Array.isArray(classPackageData) && classPackageData.length > 0){
204        postData['class_package_data'] = classPackageData;
205    }
206
207    return requestModule.getInstance().addItemToCart(postData);
208}
209
210function Set_Cart_Cookie_Db(name, value, expires, path, domain, secure) {
211    var cartUuid = getCartUuidFromCookie(); // may be null, server will return one
212
213    var axios = getAxiosInstance();
214    var data = {};
215    data.uuid = cartUuid;
216    data.cart_contents = value;
217
218    axios.post("/api/cart/data", data).then(function(response) {
219        if(response && response.data && response.data.uuid) {
220            setCartUuidCookie(response.data.uuid);
221        }
222    });
223
224    // TODO - handle the unhappy cases
225    // TODO - no, really do it.
226}
227
228// Cart
229function Set_Cart_Cookie(name, value, expires, path, domain, secure) {
230    if(name == 'cart') {
231        Set_Cart_Cookie_Db(name, value, expires, path, domain, secure);
232        CreateCartArray(value);
233    } else {
234        Set_Cart_Cookie_Cookie(name, value, expires, path, domain, secure);
235    }
236}
237
238function Get_Cart_Cookie_Cookie(check_name) {
239    var a_all_cookies = document.cookie.split(';');
240    var a_temp_cookie = '';
241    var cookie_name = '';
242    var cookie_value = '';
243    var b_cookie_found = false;
244    var retVal = null;
245    var count = 0;
246
247    do {
248
249        b_cookie_found = false;
250
251        for (i = 0; i < a_all_cookies.length; i++) {
252            a_temp_cookie = a_all_cookies[i].split('=');
253
254            cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
255
256            if (cookie_name == check_name + (count > 0 ? count : '')) {
257                b_cookie_found = true;
258
259                if (a_temp_cookie.length > 1) {
260                    cookie_value = unescape(a_temp_cookie[1].replace(/^\s+|\s+$/g, ''));
261                }
262
263                retVal = (retVal === null ? '' : retVal) + cookie_value;
264                break;
265            }
266            a_temp_cookie = null;
267            cookie_name = '';
268        }
269
270        count++;
271
272    } while (b_cookie_found == true);
273
274    return retVal;
275}
276
277// Cart
278function Get_Cart_Cookie(check_name) {
279    if(check_name == 'cart') {
280        return BuildCookieFromArray();
281    } else {
282        return Get_Cart_Cookie_Cookie(check_name);
283    }
284}
285
286function Delete_Cart_Cookie(name, path, domain) {
287    var count = 0;
288    while (Get_Cart_Cookie(name + (count > 0 ? count : ''))) {
289
290        if (domain == '') {
291            domain = document.domain.split('.');
292            if (domain[domain.length - 1].toLowerCase() == 'au' || domain[domain.length - 1].toLowerCase() == 'uk' || domain[domain.length - 1].toLowerCase() == 'nz' || domain[domain.length - 1].toLowerCase() == 'za') {
293                domain = domain[domain.length - 3] + '.' + domain[domain.length - 2] + '.' + domain[domain.length - 1];
294            } else {
295                domain = domain[domain.length - 2] + '.' + domain[domain.length - 1];
296            }
297        }
298
299        document.cookie = name + (count > 0 ? count : '') + "=" +
300            ( ( path ) ? ";path=" + path : "") +
301            ( ( domain ) ? ";domain=" + domain : "" ) +
302            ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
303
304        count++;
305    }
306
307}
308
309// Item Page?
310function showAddToWaitlistDialog(id, title, storeId, type) {
311
312    window.storeId = storeId;
313
314    if (type === "PSLR") {
315
316        var key = '';
317        var titleAddOn = ' ';
318        for (var i = 0; i < window['numAttributes' + id]; i++) {
319            key += (key.length > 0 ? '-' : '') + $('#attribute_' + id + '_' + i).val();
320            titleAddOn += (titleAddOn.length > 0 ? ' - ' : '') + window['attributeValues' + id][i][$('#attribute_' + id + '_' + i).val()];
321        }
322
323        title += titleAddOn;
324
325        if (key == '') {
326            key = '0';
327        }
328
329        window.currentProductId = id;
330        window.selected_wait_list_item_id = window['prices' + id][key]['pslrId'];
331        window.selected_wait_list_type_id = 1;
332    } else if (type === "EVENT") {
333
334        window.currentProductId = id;
335        window.selected_wait_list_item_id = id;
336        window.selected_wait_list_type_id = 2;
337    } else {
338
339        return;
340    }
341
342    $("#wait_list_added_span").html("");
343    $("#overlayWaitListForm").replaceWith('');
344
345    var markup = getWaitListDialogMarkup(title);
346
347    $(document.body).append(markup);
348
349    populateWaitListFormWithCookie();
350
351    showWaitListSaveButton();
352
353    $("#wait_list_contact_email").change(function() {
354
355        var email = $("#wait_list_contact_email").val();
356        var collection = new WaitListCollection(window.storeId);
357        collection.getExistingContactInfoByEmail(window.selected_wait_list_item_id, email, function(data) {
358
359            populateWaitListFormWithData(data);
360            showWaitListSaveButton(email);
361        });
362    });
363
364    $("#wait_list_contact_first_name").change(function() {
365
366        showWaitListSaveButton();
367    });
368
369    $("#wait_list_contact_last_name").change(function() {
370
371        showWaitListSaveButton();
372    });
373
374    $("#overlayWaitListForm").dialog({width: 300, dialogClass: 'dlgWaitList'});
375
376    // For some reason the close button is removed with responsive websites.  We'll put it back here.
377    $(".dlgWaitList > .ui-dialog-titlebar > .ui-dialog-titlebar-close").html('<span class="ui-button-icon-primary ui-icon ui-icon-closethick"></span>');
378}
379
380function getWaitListDialogMarkup(title) {
381
382    var appendString = '';
383
384    appendString += '<div id="overlayWaitListForm" title="ADD TO WAIT LIST" class="wait-list-container">';
385
386    appendString += '<div class="form-container">';
387    appendString += '<div class="form-row">';
388    appendString += '<div class="product-name">';
389    appendString += title;
390    appendString += '</div>';
391    appendString += '</div>';
392
393    appendString += '<div class="form-row">';
394    appendString += '<div class="form-title">';
395    appendString += 'Email Address:';
396    appendString += '</div><input class="form-input" placeholder="" id="wait_list_contact_email">';
397    appendString += '</div>';
398
399    appendString += '<div class="form-row">';
400    appendString += '<div class="form-title">';
401    appendString += 'First Name:';
402    appendString += '</div><input class="form-input" placeholder="" id="wait_list_contact_first_name">';
403    appendString += '</div>';
404
405    appendString += '<div class="form-row">';
406    appendString += '<div class="form-title">';
407    appendString += 'Last Name:';
408    appendString += '</div><input class="form-input" placeholder="" id="wait_list_contact_last_name">';
409    appendString += '</div>';
410
411    appendString += '<div class="form-row">';
412    appendString += '<div class="form-title">';
413    appendString += 'Phone:';
414    appendString += '</div><input class="form-input" placeholder="" id="wait_list_contact_phone">';
415    appendString += '</div>';
416
417    appendString += '<div class="form-row">';
418    appendString += '<div class="form-title">';
419    appendString += 'Quantity:';
420    appendString += '</div><input class="form-input" value="1" id="wait_list_quantity">';
421    appendString += '</div>';
422
423    appendString += '<button class="wait-list-btn" onClick="javascript:SaveToWaitList()" id="wait_list_save_button">Add to Wait List</button>'
424    appendString += '</div>';
425    appendString += '</div>';
426    return appendString;
427}
428
429function populateWaitListFormWithCookie() {
430
431    var waitlist_data = Get_Cart_Cookie('waitlist');
432    if (waitlist_data !== null) {
433
434        var contact = JSON.parse(waitlist_data);
435        populateWaitListFormWithData(contact);
436    }
437}
438
439function populateWaitListFormWithData(contact) {
440
441    if (contact === null) {
442
443        $("#wait_list_contact_first_name").val("");
444        $("#wait_list_contact_last_name").val("");
445        $("#wait_list_contact_phone").val("");
446        window.selected_wait_list_id = null;
447        window.selected_wait_list_contact_rel_id = null;
448        window.selected_pos_customer_id = null;
449    }
450    else {
451        if (contact.email !== null) {
452
453            $("#wait_list_contact_email").val(contact.email);
454        }
455        if (contact.first_name !== undefined && contact.first_name !== null) {
456
457            $("#wait_list_contact_first_name").val(contact.first_name);
458        }
459        if (contact.last_name !== undefined && contact.last_name !== null) {
460
461            $("#wait_list_contact_last_name").val(contact.last_name);
462        }
463        if (contact.phone !== undefined && contact.phone !== null) {
464
465            $("#wait_list_contact_phone").val(contact.phone);
466        }
467        if (contact.wait_list_id !== undefined && contact.wait_list_id !== null) {
468
469            window.selected_wait_list_id = contact.wait_list_id;
470        }
471        if (contact.wait_list_contact_rel_id !== undefined && contact.wait_list_contact_rel_id !== null) {
472
473            window.selected_wait_list_contact_rel_id = contact.wait_list_contact_rel_id;
474        }
475        if (contact.pos_customer_id !== undefined && contact.pos_customer_id !== null) {
476
477            window.selected_pos_customer_id = contact.pos_customer_id;
478        }
479    }
480}
481
482function showWaitListSaveButton(email) {
483
484    if (email === undefined) {
485
486        email = $("#wait_list_contact_email").val();
487    }
488
489    var first_name = $("#wait_list_contact_first_name").val();
490    var last_name = $("#wait_list_contact_last_name").val();
491
492    if (isEmailValid(email) && first_name.length > 0 && last_name.length > 0) {
493
494        $("#wait_list_save_button").show();
495        return true;
496    }
497    else {
498
499        $("#wait_list_save_button").hide();
500        return false;
501    }
502}
503
504function isEmailValid(email) {
505
506    if (email !== undefined && email.length > 0) {
507
508        var reg = /^([A-Za-z0-9_\-\.\+])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
509        return (reg.test(email));
510    } else {
511
512        return false;
513    }
514}
515
516function SaveToWaitList() {
517
518    var wait_list = new WaitList();
519    var contact = new WaitListContact();
520    contact.email = $("#wait_list_contact_email").val();
521    contact.first_name = $("#wait_list_contact_first_name").val();
522    contact.last_name = $("#wait_list_contact_last_name").val();
523    contact.phone = $("#wait_list_contact_phone").val();
524    contact.quantity = $("#wait_list_quantity").val();
525    if (window.selected_pos_customer_id !== undefined) {
526        contact.pos_customer_id = window.selected_pos_customer_id;
527    }
528    if (window.selected_wait_list_contact_rel_id !== undefined) {
529        contact.wait_list_contact_rel_id = window.selected_wait_list_contact_rel_id;
530    }
531    if (window.selected_wait_list_id !== undefined) {
532        contact.wait_list_id = window.selected_wait_list_id;
533    }
534    wait_list.contacts.push(contact);
535    wait_list.store_id = window.storeId;
536    wait_list.item_id = window.selected_wait_list_item_id;
537    wait_list.item_type_id = window.selected_wait_list_type_id;
538    wait_list.save(function(response) {
539
540        if (response.contact !== undefined && response.contact !== null) {
541
542            Set_Cart_Cookie('waitlist', JSON.stringify(response.contact), '', '/', '', '');
543            $("#wait_list_added_span_" + window.currentProductId).html(' ' + contact.quantity + ' added to wait list');
544        }
545    });
546
547    closeWaitListModal();
548}
549
550// Class
551function closeWaitListModal() {
552
553    $("#overlayWaitListForm").dialog("close");
554}
555
556// Class
557function SaveWaitListContact(contact) {
558
559    var wait_list = new WaitList();
560    wait_list.contacts.push(contact);
561    wait_list.store_id = contact.store_id;
562    wait_list.item_id = contact.item_id;
563    wait_list.item_type_id = contact.item_type_id;
564    wait_list.save(function (response) {
565
566        if (response.contact !== undefined && response.contact !== null) {
567
568            Set_Cart_Cookie('waitlist', JSON.stringify(response.contact), '', '/', '', '');
569            $("#wait_list_added_span_" + contact.item_id).html(' ' + contact.quantity + ' added to wait list');
570        }
571    });
572}
573
574// Cart
575function CreateCartArray(cart) {
576    tuples = cart.split(";;");
577    window.cartArray = new Array();
578    for (i = 0; i < tuples.length; i++) {
579        parts = tuples[i].split("##");
580        window.cartArray[i] = parts;
581    }
582}
583
584// Cart - Makes cart visible and shows actual cart
585function ShowCart(forceExpand) {
586    var oldCart = window.cartVersion != 2017;
587    var cartDiv = $("#cartDiv");
588    var cartDivMobile = $("#cartDivMobile");
589
590    if (window.cartMode === undefined || window.cartMode == false) {
591        window.cartMode = 'normal';
592    }
593
594    if (window.cartMode == 'hidden') {
595        cartDiv.hide();
596        cartDivMobile.hide();
597    } else {
598        if (oldCart) {
599          var cart = '';
600          if (Get_Cart_Cookie('cart')) {
601              cart = Get_Cart_Cookie('cart');
602          }
603
604          if (window.cartMode == 'wide') {
605              CreateCartArray(cart);
606              cartDiv.hide();
607              cartDivMobile.hide();
608              WideCart();
609          } else if (window.cartMode == 'mobile') {
610              CreateCartArray(cart);
611              cartDiv.hide();
612              cartDivMobile.hide();
613              MobileCart(forceExpand);
614          } else {
615              if (cart.length > 0) {
616                  CreateCartArray(cart);
617                  var toShow = true;
618                  if (GetCartArrayValueByKey('mode') == 'collapsed' && forceExpand != true) {
619                      CollapseCart();
620                  } else {
621                      toShow = ExpandCart();
622                  }
623
624                  if (toShow !== false) {
625                      cartDiv.fadeIn();
626                      cartDivMobile.fadeIn();
627                  }
628
629                  return;
630              } else {
631                  cartDiv.hide();
632                  cartDivMobile.hide();
633              }
634          }
635        } else {
636          var cart = Get_Cart_Cookie('cart');
637          if (cart && cart.length > 0) {
638              CreateCartArray(cart);
639              toShow = ExpandCart();
640              if (toShow !== false) {
641                  cartDiv.fadeIn();
642              }
643          } else {
644              cartDiv.hide();
645              cartDivMobile.hide();
646          }
647        }
648    }
649}
650
651// Cart
652function BuildCookieFromArray() {
653    var newCart = '';
654    for (var i = 0; i < window.cartArray.length; i++) {
655        if (i > 0) {
656            newCart += ';;';
657        }
658        newCart += window.cartArray[i].join("##");
659    }
660    return newCart;
661}
662
663function dataToCookieString(productId,productTitle,productPrice,productC
663ount,productWeight,productCountType,productSku,requiresDownloadEmailAddress,minQuantity,maxQuantity,notes
664    ,isTimed,holdingId,in_shipping,in_taxes,in_productType,pslrId,in_hasAttendees,isDiscountEligible,productImagePath,productImageStyle,class_attendees
665    ,deptId,categoryIdList,displayPrice,unitType,soldInIncrements,wishlistItemId, rto_items) {
666
667    //delimiter is ## so if this string ends with # we need to change it so I just add a space to the end of the string
668
669    if (
670        isNaN(productCount)
671        || isNaN(minQuantity)
672        || isNaN(minQuantity)
673    ) {
674        return '';
675    }
676    productCount = parseFloat(productCount);
677    minQuantity = parseFloat(minQuantity);
678    maxQuantity = parseFloat(maxQuantity);
679
680    if (productTitle.length > 0 && productTitle.charAt(productTitle.length - 1) == '#') {
681        productTitle = productTitle + " ";
682    }
683    if (productCount < minQuantity) {
684        var humanQuantity = minQuantity;
685        if (!!window.measurementUnit && window.measurementUnit == 'Yard') {
686
687            if (humanQuantity === '0.25') {
688                humanQuantity = '1/4';
689            } else if (humanQuantity === '0.5') {
690                humanQuantity = '1/2';
691            } else if (humanQuantity === '0.75') {
692                humanQuantity = '3/4';
693            }
694
695        }
696
697        alert('Please select a quantity greater than ' + humanQuantity);
698        return '';
699    }
700    if (productCount > maxQuantity) {
701        alert('Please select a quantity less than ' + maxQuantity);
702        return '';
703    }
704
705
706
707
708    var cookieData = ';;product##' + productId +
709        '##' + productTitle +
710        '##' + productPrice +
711        '##' + productCount +
712        '##' + productWeight +
713        '##' + productCountType +
714        '##' + productSku +
715        '##' + requiresDownloadEmailAddress +
716        '##' + minQuantity +
717        '##' + maxQuantity +
718        '##' + notes +
719        '##' + isTimed +
720        '##' + holdingId +
721        '##' + in_shipping +
722        '##' + in_taxes +
723        '##' + in_productType +
724        '##' + pslrId +
725        '##' + in_hasAttendees +
726        '##' + isDiscountEligible +
727        '##' + productImagePath +
728        '##' + productImageStyle +
729        '##' + class_attendees +
730        '##' + deptId +
731        '##' + categoryIdList +
732        '##' + displayPrice +
733        '##' + unitType +
734        '##' + soldInIncrements +
735        '##' + wishlistItemId;
736
737    if (rto_items !== undefined) {
738        cookieData += '##' + rto_items;
739    }
740    return cookieData;
741
742}
743
744// Cart - This is what renders the expanded version of the cart in the upper corner
745/** @return {boolean} */
746function ExpandCart() {
747    var oldCart = window.cartVersion != 2017;
748    var cartDiv = $("#cartDiv");
749    var cartDivMobile = $("#cartDivMobile");
750
751    var products = '';
752    var subtotal = 0;
753    var subtotal_to_discount = 0;
754    var giftCardSubtotal = 0;
755    var totalItems = 0;
756    var numProducts = 0;
757    var numGiftCards = 0;
758
759    if (oldCart) {
760        UpdateCouponsInCartArrayAndCookie();
761    }
762
763    // Item totals
764    for (var i = window.cartArray.length - 1; i >= 0; i--) {
765        var row = window.cartArray[i];
766        if (row[0] == 'product') {
767            if (row[1].indexOf('PITEM') > -1) {
768                continue;
769            }
770            totalItems += Number(row[4]);
771            var displayPrice = 0;
772            if (row[25]) {
773                displayPrice = row[25];
774            } else {
775                displayPrice = row[3];
776            }
777
778            var amount = Math.round(fractionalMultiplication(parseFloat(displayPrice), row[4]) * 100) / 100;
779
780            if (row.length > 16 && row[16] == 'GC') {
781                giftCardSubtotal += amount;
782                numGiftCards++;
783            } else {
784                numProducts++;
785                subtotal += amount;
786
787                // 19 - discount_eligible
788                if (row[19] === "true") {
789                    subtotal_to_discount += amount;
790                }
791            }
792
793            if (oldCart) {
794                var replaceTitle = window.cartArray[i][2].replace(/\+/g, ' ');
795                try {
796                    replaceTitle = JSON.parse(replaceTitle);
797                } catch (e) {}
798
799                products +=
800                    '<div style="font-size: 12px !important; line-height: 20px; border-bottom: 1px solid #999; padding-bottom:5px; margin-bottom: 10px;">' +
801                    '<div style="line-height: 14px; font-size: 11px !important; margin-bottom:4px;">' +
802                    replaceTitle +
803                    '</div>' +
804                    '<div><b>' + formatCurrency(displayPrice) + '</b></div>' +
805                    '<span style="font-size: 10px; color: #999;">quantity: ' + row[4] + '</span><br><br>' +
806                    '</div>';
807            }
808        }
809    }
810
811    // Don't show cart div if there are no items
812    if (numProducts == 0 && giftCardSubtotal == 0) {
813        return false;
814    }
815
816    // Calculate discounts
817    // This version of the cart should not require calculating the coupon as it only intends to show quantity of items
818    // however, I've kept it as the mobile version still shows a total amount
819    for (var i = window.cartArray.length - 1; i >= 0; i--) {
820        if (window.cartArray[i][0] == 'coupon' || window.cartArray[i][0] == 'couponV2') {
821            if (oldCart) {
822                var couponInfo = GetCouponInfo(window.cartArray[i]);
823                var discount = Math.round(CalculateDiscount(subtotal_to_discount, i) * 100) / 100;
824                if (discount > 0) {
825                    subtotal -= discount;
826                    products +=
827                        '<div style="font-size: 12px !important; line-height: 20px; border-bottom: 1px solid #999; padding-bottom:5px; margin-bottom: 10px;">' +
828                        '<div style="line-height: 14px; font-size: 11px !important; margin-bottom:4px;">' +
829                        couponInfo.title.replace(/\+/g, ' ') +
830                        '</div>' +
831                        '<div><b>- ' + formatCurrency(discount) + '</b></div>' +
832                        '</div>';
833                }
834
835            }
836        }
837    }
838
839    // Update subtotal
840    subtotal += giftCardSubtotal;
841    subtotal = Math.round(subtotal * 100) / 100;
842
843    if (oldCart) {
844        // Gift Card Payments
845        var giftCardPayments = 0;
846        for (var i = window.cartArray.length - 1; i >= 0; i--) {
847            if (window.cartArray[i][0] == 'giftcard') {
848                giftCardPayments += Math.round(window.cartArray[i][3] * 100) / 100;
849            }
850        }
851
852        var giftCardRows = '';
853        if (giftCardPayments > 0) {
854            if (subtotal < giftCardPayments) {
855                giftCardPayments = subtotal;
856            }
857            giftCardRows = '<span style="color: #ccc; font-size: 14px;"><b>Gift Cards = ' + formatCurrency(giftCardPayments) + '</b></span><br>';
858            subtotal -= giftCardPayments;
859        }
860
861    }
862
863    // Mobile bottom div
864    cartDivMobile.html(
865        '<div style="padding:10px;" onclick="location=\'' + editcartUrl + '\'">' +
866        '<table width="100%"><tr>' +
867        '<td style="text-align: left; cursor: pointer; color: #fff;">' +
868        '<img style="width:23px; height:18px; vertical-align:middle; margin-bottom: 4px;" src="https://images.rainpos.com/view-cart.png">&nbsp;&nbsp;&nbsp;Cart - ' + (totalItems) + ' items' +
869        '</td>' +
870        '<td style="text-align: right; cursor: pointer; color: #fff;">' + formatCurrency(subtotal) + '</td>' +
871        '</tr></table></div>'
872    );
873
874    if (!oldCart || window.ABCart == 'B') {
875        // Full page upper corner bullet
876        cartDiv.attr('style', 'display:none; top: 10px; right: 10px; padding: 0px; width: 150px; background: none;');
877        cartDiv.html(
878            '<div class="btnViewCart" onclick="location=\'' + editcartUrl + '\'" >' +
879            '<img style="width:23px; height:18px; vertical-align:middle; margin-bottom: 4px;" src="https://images.rainpos.com/view-cart.png">' +
880            ' &nbsp;' + (totalItems) + ' Item' + (totalItems != 1 ? 's' : '') +
881            '</div>'
882        );
883    } else {
884        cartDiv.html(
885            '<div style="display:table; height:28px; text-align:right; width:100%;">' +
886            '  <span style="display:table-cell; width:20px;"></span>' +
887            '  <span style="vertical-align:middle; text-align:center; display:table-cell; color: #ccc; font-family: Arial; font-size: 12px !important;">' +
888            '    <a href="' + editcartUrl + '" style="' + linkStyles + '">View Cart</a>' +
889            '  </span>' +
890            '  <span style="vertical-align:middle; width:20px; display:table-cell; color: #ccc; font-family: Arial; font-size: 12px !important;">' +
891            '    <a href="javascript:CollapseCart();"><img border=0 width=16 height=11 src="https://images.rainpos.com/btn-collapse.png"></a>' +
892            '  </span>' +
893            '</div>' +
894
895            '<div style="width: 100%; top: 30px; right: 0px; border-top: 1px solid #888; margin-bottom:10px;"></div>' +
896            '<div class="btnViewCart" onclick="ProceedToCheckout(\'no\');" style="font-size:14px; font-family: Arial !important;">Proceed to Checkout &raquo;</div>' +
897            '<div style="text-align:left; margin-top:10px; margin-bottom:10px; padding: 10px; color: #fff; height: 200px; overflow:auto; background: url(https://images.rainpos.com/cart-bg-2a.png) repeat;">' +
898            products +
899            '</div>' +
900            giftCardRows +
901            '<div style="color: #ddd; font-size: 14px !important; padding:4px;">Subtotal = ' + formatCurrency(subtotal) + '</div>' +
902            '<div style="line-height:20px;">' +
903            '<a href="' + editcartUrl + '&enterCoupon=true" style="' + linkStyles + '">Enter Coupon</a><br>' +
904            (window.paymentProcessor === undefined || window.paymentProcessor == false || window.paymentProcessor == 'paypal' ? '' : '<a href="' + editcartUrl + '&enterGiftcard=true" style="' + linkStyles + '">Enter Gift Card</a><br>') +
905            '<a href="' + editcartUrl + '" style="' + linkStyles + '">View Cart</a>' +
906            '</div>' +
907            '<div class="btnViewCart" onclick="ProceedToCheckout(\'no\');" style="font-size:14px; font-family: Arial !important; margin-bottom: 10px; margin-top: 5px;">Proceed to Checkout &raquo;</div>' +
908            MakeCartForm() +
909            '');
910    }
911
912    return true;
913}
914
915/** @return {string} */
916function ProductAttributeKeyGet(in_productId, in_attributeIndex) {
917    // Get the key
918    var key = '';
919    for (var i = 0; i < window['numAttributes' + in_productId]; i++) {
920        key += (key.length > 0 ? '-' : '') + $('#attribute_' + in_productId + '_' + i).val();
921    }
922
923    if (key == '') {
924        key = '0';
925    }
926
927    return key;
928}
929
930// Used by the product page - probably does not belong in this file
931function handleProductOptionChanged(in_productId, in_attributeIndex) {
932    var newPrice = '';
933    var isSale;
934    var integer = $("#integer" + in_productId);
935    var fraction = $("#fraction" + in_productId);
936    var currentIntegerVal = parseInt(integer.val());
937    var currentFractionVal = parseFloat(fraction.val());
938    var minFraction = window.siteMinimumFraction;
939
940    // Get the key
941    var key = ProductAttributeKeyGet(in_productId, in_attributeIndex);
942    var pslrId = parseInt(window['prices' + in_productId][key]['pslrId']);
943
944     // Show propper Custom fields and hide others
945    $('#product-details-pricing-table .custom-fields').hide();
946    $('#product-details-pricing-table .custom-fields-' + pslrId).show();
947
948    // Set font colors to black for attributes that are available for the just-selected attribute, and gray for those that aren't available
949
950    var reserve = 0;
951    var outOfStock = false;
952
953    if (window['prices' + in_productId][key]) {
954        var temp = window['prices' + in_productId][key]['salePrice'];
955        // Is the selected product option on sale?
956        isSale = (parseFloat(window['prices' + in_productId][key]['salePrice']) > 0.0 ? true : false);
957
958        // Set price label
959        $('#spanPriceLabel' + in_productId).html((isSale == true ? 'SALE:' : 'Price:'));
960
961        // Set price value
962        if (isSale == true) {
963            newPrice = '<strike>' + formatCurrency(window['prices' + in_productId][key]['price']) + '</strike> &nbsp;<b><span style="color:#ff0000;">' + formatCurrency(window['prices' + in_productId][key]['salePrice']) + '</span></b>';
964        } else {
965            newPrice = formatCurrency(window['prices' + in_productId][key]['finalDisplayPrice']);
966        }
967        $('#spanPrice' + in_productId).html(newPrice);
968
969        // Set quantity dropdowns
970
971        // Integer
972        var maxInteger = Math.floor(parseFloat(window['prices' + in_productId][key]['quantity']));
973        if (currentIntegerVal > maxInteger) {
974            currentIntegerVal = maxInteger;
975        }
976        var startInteger = (window['isFabric' + in_productId] == true ? 0 : 1);
977        var soldInIncrements = window['soldInIncrements' + in_productId];
978        integer.html("");
979        for (var i = startInteger; i <= maxInteger; i++) {
980                if ((i === 0) && ((minFraction === 1) || (minFraction === '1'))) {
981                    continue;
982                }
983
984
985            if ((i % soldInIncrements) > 0) {
986                continue;
987            }
988            integer.append("<option value=\'" + i + "\' " + (currentIntegerVal == i ? 'selected' : '') + ">" + i + "</option>");
989        }
990        $('#maxInteger' + in_productId).val(maxInteger);
991
992        if(maxInteger <= 0 && (typeof maxFraction === 'undefined' && !window['isFabric' + in_productId])) {
993            outOfStock = true;
994        }
995
996        // Fraction
997        if (window['isFabric' + in_productId] == true) {
998            var increment = (window.measurementUnit == 'Meter' ? 10 : 25);
999            var maxFraction = Math.floor(parseFloat(window['prices' + in_productId][key]['quantity']) * 100) % 100;
1000            maxFraction = (maxFraction - (maxFraction % increment)) / 100;
1001            if (currentIntegerVal == 0 && currentFractionVal == 0) {
1002                currentFractionVal = maxFraction;
1003            } else if (currentIntegerVal == maxInteger && currentFractionVal > maxFraction) {
1004                currentFractionVal = maxFraction;
1005            }
1006            $('#maxFraction' + in_productId).val(maxFraction);
1007
1008            fraction.html("");
1009            var startVal = 0;
1010            if (currentIntegerVal == 0) {
1011                if (minFraction && (minFraction > 0) && (minFraction < 1)) {
1012                    startVal = Math.floor(window.siteMinimumFraction * 100);
1013                } else {
1014                    startVal = (window.measurementUnit === 'Meter') ? 10 : 25;
1015                }
1016
1017            }
1018            for (var i = startVal; i < 100; i += increment) {
1019                var decimal = (i / 100);
1020                if (maxInteger == currentIntegerVal && maxFraction < decimal) {
1021                    break;
1022                }
1023                var appendStr = '';
1024                if (window.measurementUnit == 'Meter' && currentIntegerVal == 0 && decimal == .3 && window.siteMinimumFraction == 'fat quarter') {
1025                    appendStr += "<option value=\'0.25\' " + (currentFractionVal == 0.25 ? 'selected' : '') + ">Fat Quarter</option>";
1026                }
1027                appendStr += "<option value=\'" + decimal + "\' " + (currentFractionVal == decimal ? 'selected' : '') + ">";
1028                if (window.measurementUnit == 'Meter') {
1029                    appendStr += decimal;
1030                } else {
1031                    appendStr += (decimal == 0.25 ? (currentIntegerVal == 0 && window.siteMinimumFraction == 'fat quarter' ? 'Fat Quarter' : '1/4') : (decimal == 0.5 ? '1/2' : (decimal == 0.75 ? '3/4' : decimal)));
1032                }
1033                appendStr += "</option>";
1034                fraction.append(appendStr);
1035            }
1036        }
1037
1038        // WishList
1039        if (typeof wishlistApp != 'undefined' && wishlistApp) {
1040
1041            var qtyInteger = $("#integer" + in_productId);
1042            var qtyFraction = $("#fraction" + in_productId);
1043            var qtyIntegerVal = parseInt(qtyInteger.val());
1044            var qtyFractionVal = parseFloat(qtyFraction.val());
1045
1046            // Handle NaN
1047            if (!qtyIntegerVal) {
1048                qtyIntegerVal = 0;
1049                if ((minFraction === 1) || (minFraction === '1')) {
1050                    qtyIntegerVal = 1;
1051                }
1052            }
1053            if (!qtyFractionVal) {
1054                qtyFractionVal = 0;
1055            }
1056
1057            wishlistApp.$root.$emit('update_pslr_qty', {pslr_id: pslrId, qty: (qtyIntegerVal + qtyFractionVal)});
1058        }
1059    } else {
1060        outOfStock = true
1061    }
1062
1063    if (window['isFabric' + in_productId] === true && window['prices' + in_productId][key]['quantity'] < minimumQuantity) {
1064        outOfStock = true;
1065    }
1066
1067    var newPriceNumber = Number(newPrice.replace(/[^0-9\.-]+/g,""));
1068    var freeProductNotAllowed =
1069        newPriceNumber <= 0 &&
1070        (typeof window['freeProductsAllowed'] !== 'undefined' && window['freeProductsAllowed'] === false);
1071
1072    if (freeProductNotAllowed) {
1073        $('[id^=add-to-cart-btn-' + in_productId + ']').attr('disabled','disabled');
1074        $('[id^=add-to-cart-btn-' + in_productId + ']').html('Product Unavailable');
1075    } else {
1076        $('[id^=add-to-cart-btn-' + in_productId + ']').removeAttr("disabled");
1077        $('[id^=add-to-cart-btn-' + in_productId + ']').html('Add to Cart');
1078    }
1079
1080    if (outOfStock || (reserve > 0 && maxInteger == 0 && (window['isFabric' + in_productId] != true || maxFraction == 0))) {
1081        $('[id^=integer' + in_productId + ']').hide();
1082        $('[id^=fraction' + in_productId + ']').hide();
1083        $('[id^=add-to-cart-btn-' + in_productId + ']').hide();
1084        $('[id^=reserve' + in_productId + ']').html('<span style="color:#f00;">Out of Stock</span>').show();
1085    } else {
1086        $('[id^=integer' + in_productId + ']').show();
1087        $('[id^=fraction' + in_productId + ']').show();
1088        $('[id^=add-to-cart-btn-' + in_productId + ']').show();
1089        $('[id^=reserve' + in_productId + ']').hide();
1090    }
1091
1092    var conditionalSelect = $('#conditional-select');
1093    if (!conditionalSelect) {
1094        return;
1095    }
1096
1097    var conditionOptions = window['prices' + in_productId][key]['conditional_option']
1098
1099    if (conditionOptions) {
1100        $.each(conditionOptions, function (i, item) {
1101            conditionalSelect.append($('<option>', {
1102                value: item.value,
1103                text : item.label,
1104                selected: i === 0.
1105            }));
1106        });
1107        conditionalSelect.attr('data-key', key);
1108        conditionalSelect.trigger('change');
1109    } else {
1110        conditionalSelect.parent().parent().css('display','none');
1111    }
1112}
1113
1114// Cart
1115function formatCurrency(num) {
1116    num = num.toString().replace(/\$|\,/g, '');
1117    if (isNaN(num)) {
1118        num = "0";
1119    }
1120    sign = (num == (num = Math.abs(num)));
1121    num = Math.floor(num * 100 + 0.50000000001);
1122    cents = num % 100;
1123    num = Math.floor(num / 100).toString();
1124    if (cents < 10) {
1125        cents = "0" + cents;
1126    }
1127    for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++) {
1128        num = num.substring(0, num.length - (4 * i + 3)) + ',' +
1129            num.substring(num.length - (4 * i + 3));
1130    }
1131    return (((sign) ? '' : '-') + window.displayCurrencySymbol + num + '.' + cents + ' ' + window.displayCurrency);
1132}
1133
1134// Rental Cart (Outdoor)
1135function addRentalToCart(rentalDataId, price) {
1136    if (isRentalInCart(rentalDataId)) {
1137        updateRentalPrice(rentalDataId, price);
1138    } else {
1139        AddProductToCart('', 'sale', rentalDataId, 'Rental', price, 0, 'integer', '', 'no', 1, 1, 0, '', '', 0, '', 'RENTAL', '', 'false', '', '');
1140    }
1141}
1142
1143function isRentalInCart(rentalDataId) {
1144    var cart = Get_Cart_Cookie('cart');
1145    if (cart && cart.length > 0 && window.cartArray) {
1146        for (var i = 0; i < window.cartArray.length; i++) {
1147            if (window.cartArray[i][1] == 'RENTAL' + rentalDataId) {
1148                return true;
1149            }
1150        }
1151    }
1152    return false;
1153}
1154
1155function updateRentalPrice(rentalDataId, price) {
1156    var cart = Get_Cart_Cookie('cart');
1157    if (cart && cart.length > 0 && window.cartArray) {
1158        for (var i = 0; i < window.cartArray.length; i++) {
1159            if (window.cartArray[i][1] == 'RENTAL' + rentalDataId) {
1160                window.cartArray[i][3] = price;
1161                updateCart();
1162                return;
1163            }
1164        }
1165    }
1166}
1167
1168function updateCart() {
1169    Set_Cart_Cookie('cart', BuildCookieFromArray(), '', '/', '', '');
1170}
1171
1172function addWishlistProductToCart(item, qty, maxQty, unitType) {
1173
1174    var productId = item.product_id;
1175    var pslrId = item.item_id;
1176
1177    var prices = item.prices;
1178    var price = prices['price'];
1179    if(prices['sale_price'] > 0 && prices['sale_price'] < price) {
1180        price = prices['sale_price'];
1181    }
1182
1183    var notes = '';
1184    console.log('add '+ qty +'product ' + productId + ' pslr ' + pslrId);
1185
1186    var min = 0;
1187    if(item.qty_on_hand > 0 || item.unlimitedWebInventory === 1) {
1188        min = 1;
1189    }
1190    var discountEligibility = item.discount_eligible;
1191
1192    // (in_businessEmail, in_paymentAction, productId, productTitle, productPrice, productWeight, productCountType, productSku, requiresDownloadEmailAddress, minQuantity, maxQuantity, isTimed, in_notes, in_shipping, in_taxes, inlineAddToCartBtn, in_productType, in_hasAttendees, isDiscountEligible, productImagePath, productImageStyle, requireClassAttendees,
1193    // pslrId, packageData, holdingId, deptId, categoryIdList, displayPrice, unitType, soldInIncrements,qty, wishlist_id
1194    AddProductToCart(
1195        '',
1196        'sale',
1197        productId,
1198        item.title,
1199        price,
1200        item.weight,
1201        item.productCountType,
1202        item.sku,
1203        'no',
1204        min,
1205        maxQty,
1206        0,
1207        notes,
1208        '',
1209        item.bitmap_tax,
1210        '',
1211        'PSLR',
1212        '',
1213        discountEligibility,
1214        item.thumbnail,
1215        '',
1216        false,
1217        pslrId,
1218        null,
1219        null,
1220        item.department_id,
1221        JSON.parse(item.category_ids),
1222        null,
1223        unitType,
1224        null,
1225        qty,
1226        item.wishlist_item_id
1227    );
1228}
1229
1230
1231// RTO Cart (Music)
1232function addRtoToCartWithCondition(token, pslrId, conditionId, schoolDistrictId, schoolId, studentName, selectedMaintenance, selectedProtection, conditionPiiId) {
1233    conditionPiiId = (conditionPiiId === undefined) ? null : conditionPiiId;
1234    var request = {
1235        pslr_id: pslrId,
1236        condition_id: conditionId,
1237        school_district_id: schoolDistrictId,
1238        school_id: schoolId,
1239        student_name: studentName,
1240        selected_maintenance: selectedMaintenance,
1241        selected_protection: selectedProtection,
1242        condition_pii_id: conditionPiiId
1243    };
1244
1245    $.ajax({
1246        url: '/api/rto/online/contract',
1247        type: 'POST',
1248        dataType: 'json',
1249        contentType: 'application/json',
1250        data: JSON.stringify(request),
1251        headers: {
1252            Authorization: 'Bearer ' + token
1253        },
1254        success: function(result) {
1255            if (result.result != 'success') {
1256                alert('There was an error adding your rental to the cart.');
1257            } else {
1258                var notes = '';
1259                if (result.taxable_amount) {
1260                    notes = JSON.stringify({taxable_amount:result.taxable_amount});
1261                }
1262
1263                var rto_items = null;
1264                if (result.rto_items !== undefined) {
1265                    rto_items = JSON.stringify({
1266                        rto_principle_payment: result.rto_items.rto_principle_payment,
1267                        rto_down_payment: result.rto_items.rto_down_payment,
1268                        rto_product_tax_bitmap: result.rto_items.rto_product_tax_bitmap,
1269                        rto_maintenance_payment: result.rto_items.rto_maintenance_payment,
1270                        rto_maintenance_tax_bitmap: result.rto_items.rto_maintenance_tax_bitmap,
1271                        rto_insurance_payment: result.rto_items.rto_insurance_payment,
1272                        rto_insurance_tax_bitmap: result.rto_items.rto_insurance_tax_bitmap,
1273                        rto_security_deposit: result.rto_items.rto_security_deposit,
1274                        rto_initial_payments: result.rto_items.rto_initial_payments,
1275                        rto_interest_rate: result.rto_items.rto_interest_rate,
1276                        rto_interest_tax_bitmap: result.rto_items.rto_interest_tax_bitmap,
1277                    });
1278                }
1279                AddProductToCart('', 'sale', result.rto_id, result.title + ' - Rental', result.due, result.weight, 'integer', '', 'no', 1, 1, 0, notes, '', 0, '', 'RTO', '', 'false', '', '', false, pslrId, null, conditionId, null, null, null, null, null, null, null, rto_items);
1280            }
1281        }
1282    });
1283}
1284
1285function createAndAddOsrToCart(token, rentalId, variationId, conditionId, maintenance, protection, student, customerInfo, image, addons) {
1286    var config = {
1287        headers: {
1288            Authorization: 'Bearer ' + token,
1289        }
1290    };
1291
1292    var data = {
1293        rentalId: rentalId,
1294        variationId: variationId,
1295        conditionId: conditionId,
1296        maintenance: maintenance,
1297        protection: protection,
1298        student: student,
1299        customerInfo: customerInfo,
1300        addons: addons,
1301    };
1302
1303    return axios.post('/api/online-school-rentals/cart-contract', data, config)
1304        .then(function (response) {
1305            var data = response.data;
1306
1307            if (!data || !data.rto_id) {
1308                return Promise.reject(new Error('Error on contract creation'));
1309            }
1310
1311            var rtoItems = data.rto_items ? {
1312                rto_principle_payment: data.rto_items.rto_principle_payment,
1313                rto_down_payment: data.rto_items.rto_down_payment,
1314                rto_product_tax_bitmap: data.rto_items.rto_product_tax_bitmap,
1315                rto_maintenance_payment: data.rto_items.rto_maintenance_payment,
1316                rto_maintenance_tax_bitmap: data.rto_items.rto_maintenance_tax_bitmap,
1317                rto_insurance_payment: data.rto_items.rto_insurance_payment,
1318                rto_insurance_tax_bitmap: data.rto_items.rto_insurance_tax_bitmap,
1319                rto_security_deposit: data.rto_items.rto_security_deposit,
1320                rto_initial_payments: data.rto_items.rto_initial_payments,
1321                rto_interest_rate: data.rto_items.rto_interest_rate,
1322                rto_interest_tax_bitmap: data.rto_items.rto_interest_tax_bitmap,
1323            } : null;
1324
1325            return AddOsrToCart(
1326                data.rto_id,
1327                data.title,
1328                data.due,
1329                data.weight,
1330                {taxable_amount: data.taxable_amount},
1331                image,
1332                data.pslr_id,
1333                conditionId,
1334                rtoItems
1335            );
1336        });
1337}
1338
1339function AddOsrToCart(productId, productTitle, productPrice, productWeight, notes, productImagePath, pslrId, holdingId, rtoItems) {
1340    // Get custom fields & notes
1341    productId = 'RTO' + productId;
1342    notes = notes ? JSON.stringify(notes) : '';
1343    rtoItems = rtoItems ? JSON.stringify(rtoItems) : null;
1344
1345    var cookieData = dataToCookieString(
1346        productId, productTitle, productPrice, 1, productWeight, 'integer', '',
1347        'no', 1, 1, notes, 0, holdingId, '',
1348        0, 'OSR', pslrId || '', '', 'false', productImagePath, '',
1349        '', null, JSON.stringify(null), productPrice, 'each', 1, null, rtoItems
1350    );
1351
1352    if (cookieData === '') {
1353        return Promise.reject(new Error('Wrong cart item data'));
1354    }
1355
1356    var promise = addItemToCartData(cookieData);
1357
1358    if (window.facebookPixelId) {
1359        fbq('track', 'AddToCart', {
1360            currency: window.currency,
1361            value: productPrice,
1362            content_name: productTitle,
1363            content_ids: [productId],
1364            content_type: 'product',
1365            contents: [{
1366                'id': productId,
1367                'quantity': 1
1368            }]
1369        });
1370    }
1371
1372    addGAEvent(productId, productTitle, productPrice, 1);
1373
1374    return promise;
1375}
1376
1377// Cart
1378
1379
1380function yardLoop(maxFractionVal, siteMinimumFraction, fraction, currFractionVal, intVal, maxIntVal){
1381    //we could probably be clever and do something cool like the meter loop...but not enough values to make it worth it
1382    fraction.html("");
1383    if(currFractionVal > maxFractionVal && intVal >= maxIntVal){
1384        currFractionVal = maxFractionVal;
1385    }
1386    if (intVal === 0) {
1387        if (window.siteMinimumFraction === 'fat quarter') {
1388            fraction.append("<option " + (currFractionVal < 0.5 ? "selected" : "") + " value=\'0.25\'>Fat Quarter</option>");
1389        }
1390        if (window.siteMinimumFraction === '0.25' || window.siteMinimumFraction === '') {
1391            fraction.append("<option " + (currFractionVal < 0.5 ? "selected" : "") + " value=\'0.25\'>1/4</option>");
1392        }
1393    } else {
1394        fraction.append("<option value=\'0\'>0</option>");
1395        if (intVal < maxIntVal || maxFractionVal >= 0.25) {
1396            fraction.append("<option " + (currFractionVal === 0.25 ? "selected" : "") + " value=\'0.25\'>1/4</option>");
1397        }
1398    }
1399    if (intVal < maxIntVal || maxFractionVal >= 0.5) {
1400        fraction.append("<option " + (currFractionVal === 0.5 ? "selected" : "") + " value=\'0.5\'>1/2</option>");
1401    }
1402    if (intVal < maxIntVal || maxFractionVal >= 0.75) {
1403        fraction.append("<option " + (currFractionVal === 0.75 ? "selected" : "") + " value=\'0.75\'>3/4</option>");
1404    }
1405}
1406
1407function meterLoop(startingFraction, currentFraction, fraction, maxFractionValue, intVal, maxIntVal){
1408
1409    var i = parseFloat(startingFraction);
1410    if(intVal<maxIntVal){
1411        maxFractionValue = .9
1412    }
1413    if(currentFraction < i ){
1414        currentFraction = i;
1415    }
1416    if(currentFraction > maxFractionValue && intVal >= maxIntVal){
1417        currentFraction = maxFractionValue;
1418    }
1419    if (startingFraction === .25 ){
1420        fraction.append("<option " + (currentFraction === .25  ? "selected" : "") + " value=\'0.25\'>Fat Quarter</option>");
1421        i = parseFloat(.3);
1422    }
1423    for(i; i <= maxFractionValue ; i += .1 ){
1424        var count = i.toFixed(1);
1425        fraction.append("<option " + (currentFraction == count ? "selected" : "") + " value=\'"+ count +"\'>"+ count.replace(/^0+/,"")+"</option>");
1426        if (i === .2 && intVal === 0 ){
1427            fraction.append("<option " + (currentFraction === .25  ? "selected" : "") + " value=\'0.25\'>Fat Quarter</option>");
1428        }
1429    }
1430    return fraction;
1431}
1432
1433// TODO - This function is a little better, but still messy, and needs additional refactoring and automated tests
1434function checkFabricMinimum(id, maxQuantity)
1435{
1436    var minFraction = window.siteMinimumFraction;
1437    var minFractionVal = (minFraction === 'fat quarter') ? 0.25 : minFraction;
1438
1439    var intVal = parseInt($("#integer" + id).val());
1440    var fraction = $("#fraction" + id);
1441    var currFractionVal = parseFloat(fraction.val());
1442
1443    var maxIntVal;
1444    var maxFractionVal;
1445
1446    if (typeof maxQuantity === 'undefined') {
1447        maxIntVal = parseInt($("#maxInteger" + id).val());
1448        maxFractionVal = parseFloat($("#maxFraction" + id).val());
1449    } else {
1450        maxQuantity = parseFloat(maxQuantity);
1451        maxIntVal = Math.floor(maxQuantity);
1452        maxFractionVal = Math.floor((maxQuantity * 100) % 100) / 100;
1453    }
1454
1455    // WishList
1456
1457    if ((typeof wishlistApp !== 'undefined') && wishlistApp) {
1458        var key = ProductAttributeKeyGet(id, 0);
1459        var pslrId = parseInt(window['prices' + id][key]['pslrId']);
1460
1461        wishlistApp.$root.$emit('update_pslr_qty', {pslr_id: pslrId, qty: (intVal + currFractionVal)});
1462    }
1463
1464    // Fractional handling
1465
1466    if (window.measurementUnit === 'Meter') {
1467        fraction.html("");
1468        if (intVal === 0) {
1469            meterLoop(minFractionVal, currFractionVal, fraction, maxFractionVal, intVal, maxIntVal);
1470        } else {
1471            meterLoop('0', currFractionVal, fraction, maxFractionVal, intVal, maxIntVal);
1472        }
1473
1474    } else {
1475            yardLoop(maxFractionVal, siteMinimumFraction, fraction, currFractionVal, intVal, maxIntVal);
1476    }
1477}
1478
1479function getPslrIdFromUI(productId)
1480{
1481    // Find which PSLR is selected
1482    var key = '';
1483    for (var i = 0; i < window['numAttributes' + productId]; i++) {
1484        key += (key.length > 0 ? '-' : '') + $('#attribute_' + productId + '_' + i).val();
1485    }
1486    if (key == '') {
1487        key = '0';
1488    }
1489    pslrId = window['prices' + productId][key]['pslrId'];
1490    return pslrId;
1491}
1492
1493function getQuantityFromUI(productId)
1494{
1495    quantity = 1;
1496    if (typeof inlineAddToCartBtn !== 'undefined') {
1497        quantity = parseInt(document.getElementById('inlineInteger' + productId).value) + parseFloat(document.getElementById('inlineFraction' + productId).value);
1498    } else {
1499        var element = document.getElementById('integer' + productId);
1500        var element2 = document.getElementById('fraction' + productId);
1501        quantity = 0;
1502        if (element) {
1503            quantity += parseInt(element.value);
1504        }
1505        if (element2) {
1506            quantity += parseFloat(element2.value);
1507        }
1508    }
1509    return quantity;
1510}
1511
1512function getNotesFromUI(productId) {
1513    var notes = '';
1514    var noteObjects = $(".class" + productId);
1515    noteObjects.each(function(i) {
1516        if (notes === 'return') {
1517            return;
1518        }
1519        var noteName = $(this).attr('name');
1520        var noteValue = '';
1521
1522        if ($(this).is(':checkbox')) {
1523            noteValue = ($(this).is(":checked") ? 'checked' : 'not checked');
1524        }
1525        else {
1526            noteValue = $.trim($(this).val());
1527        }
1528
1529        if ($(this).attr('required') == true && noteValue == '') {
1530            alert(noteName + ' is a required field.');
1531            notes = 'return';
1532            return;
1533        }
1534
1535        if (notes == '') {
1536            notes = {};
1537        }
1538        notes[noteName] = noteValue;
1539    });
1540
1541    if (notes == 'return') {
1542        return;
1543    }
1544    return notes;
1545}
1546
1547function createItem(productId, productTitle, productPrice, productWeight, productCountType, productSku, requiresDownloadEmailAddress, minQuantity, maxQuantity, isTimed, in_notes, in_shipping, in_taxes, inlineAddToCartBtn, in_productType, in_hasAttendees, isDiscountEligible, productImagePath, productImageStyle, requireClassAttendees, pslrId, packageData, holdingId, deptId, categoryIdList, displayPrice, unitType, soldInIncrements, quantity, wishlistItemId, rto_items, conditionId, conditions, addonId) {
1548    if (in_productType === 'PSLR') {
1549        if (!pslrId) {
1550            pslrId = getPslrIdFromUI(productId);
1551        }
1552
1553        // Get Quantity
1554        if (!quantity) {
1555            quantity = getQuantityFromUI(productId);
1556        }
1557
1558        var notes = in_notes;
1559        if (!notes) {
1560            notes = getNotesFromUI(productId);
1561        }
1562
1563        var pslr = {
1564            type: in_productType,
1565            pslr_id: pslrId,
1566            product_id: productId,
1567            quantity: quantity,
1568            notes: notes,
1569            wishlistItemId: wishlistItemId || 0,
1570            title: productTitle,
1571        };
1572
1573        if (conditionId) {
1574            pslr['condition'] = conditionId;
1575        } else {
1576            var condition = getConditional(productId);
1577            if (condition) {
1578                pslr['condition'] = condition.id;
1579            }
1580        }
1581
1582        if (conditions) {
1583            pslr['conditions'] = conditions;
1584        }
1585
1586        if (window.knobby && window.knobby['module_comment_sold']) {
1587            pslr.sku = productSku;
1588            pslr.price = productPrice;
1589        }
1590        if (addonId) {
1591            pslr['addon_id'] = addonId;
1592        }
1593
1594        return pslr;
1595    }
1596    return null;
1597}
1598
1599function getConditional(productId) {
1600    if (!document.getElementById('conditional-select')) {
1601        return null;
1602    }
1603
1604    if (document.getElementById('conditional-select') === null) {
1605        return null;
1606    }
1607
1608    var key = ProductAttributeKeyGet(productId, 0);
1609
1610    var value = document.getElementById('conditional-select').value;
1611
1612    var conditional = window['prices' + productId][key]['conditional'];
1613
1614    if (!conditional) {
1615        return null;
1616    }
1617
1618    return conditional.find(function (v) {
1619        return parseInt(v.item_condition_id) === parseInt(value);
1620    });
1621}
1622
1623function getConditionQuantity(productId, conditionId, key = null) {
1624    key = key === null ? ProductAttributeKeyGet(productId, 0) : key;
1625
1626    var conditionQuantity = window['prices' + productId][key]['conditional_quantity'].find(function (v) {
1627        return parseInt(v.condition_id) === parseInt(conditionId);
1628    });
1629
1630    return conditionQuantity ? parseInt(conditionQuantity.quantity) : 0;
1631}
1632
1633function addClassToCart(classId, eventId, requireAttendees, packageData, class_id_str) {
1634    if (requireAttendees) {
1635        var result = verifyClassAttendees('CLASS' + eventId);
1636        if (!result) {
1637            return;
1638        }
1639    }
1640
1641    var selectedComponents = [];
1642    var packageId = null;
1643    if (packageData && packageData.available && packageData.option === 'classAndPackage') {
1644        packageId = packageData.packageId;
1645        if (packageData.components) {
1646            packageData.components.forEach(function(c) {
1647                selectedComponents.push(c.selectedItem);
1648            });
1649        }
1650    }
1651
1652    var item = {
1653        type: 'CLASS',
1654        event_id: eventId,
1655        class_id: classId,
1656        package_id: packageId,
1657        components: selectedComponents,
1658        class_attendees: getClassAttendees('CLASS' + eventId),
1659    }
1660    addItemToCart(item);
1661}
1662
1663function addItemToCart(item, productId) {
1664    if (!isValidConditionQuantityInCart(item, productId)) {
1665        if (!item.hasOwnProperty('conditions')) {
1666            decreaseActualConditionQuantity(productId, item.condition);
1667        }
1668
1669        alert('There was an error adding this item to your cart.');
1670        return Promise.resolve();
1671    }
1672
1673    var promise = requestModule.getInstance().addItemToCart({
1674        item: item,
1675    });
1676
1677    // Google Analytics
1678    if (item.type === 'PSLR') {
1679        if (item.quantity > 0) {
1680            addGAEvent(item.product_id, item.title, item.price, item.quantity);
1681        }
1682    }
1683
1684    if (window.knobby && window.knobby['module_comment_sold']) {
1685        if (typeof item.type !== 'undefined' && item.type.toLowerCase() === 'pslr') {
1686            //we want to fire event only for pslr items
1687            var data = {
1688                product: {
1689                    sku: item.pslr_id || item.sku,
1690                    price: parseFloat(item.price),
1691                    currency: window.currency || 'USD',
1692                    quantity: item.quantity,
1693                }
1694            }
1695            try {
1696                videeoCommand('addToCart', data);
1697            } catch (e) {
1698                console.warn(e);
1699            }
1700        }
1701    }
1702
1703    return promise;
1704}
1705
1706/**
1707 * Adds a product to the cart (pre-2017 version).
1708 * When adding parameters, make sure to also add them for GetAttendees()
1709 */
1710function AddProductToCart(in_businessEmail, in_paymentAction, productId, productTitle, productPrice, productWeight, productC
1710ountType, productSku, requiresDownloadEmailAddress, minQuantity, maxQuantity, isTimed, in_notes, in_shipping, in_taxes, inlineAddToCartBtn, in_productType, in_hasAttendees, isDiscountEligible, productImagePath, productImageStyle, requireClassAttendees, pslrId, packageData, holdingId, deptId, categoryIdList, displayPrice, unitType, soldInIncrements, quantity, wishlistItemId, rto_items, conditionId, conditions) {
1711    if (window.location.search.indexOf('ie') == -1) { // IE still can't use the new product page.
1712        if (requireClassAttendees) {
1713            var result = verifyClassAttendees(productId);
1714            if (!result) {
1715                return;
1716            }
1717        }
1718
1719        var item = createItem(productId, productTitle, productPrice, productWeight, productCountType, productSku, requiresDownloadEmailAddress, minQuantity, maxQuantity, isTimed, in_notes, in_shipping, in_taxes, inlineAddToCartBtn, in_productType, in_hasAttendees, isDiscountEligible, productImagePath, productImageStyle, requireClassAttendees, pslrId, packageData, holdingId, deptId, categoryIdList, displayPrice, unitType, soldInIncrements, quantity, wishlistItemId, rto_items, conditionId, conditions);
1720        if (item) {
1721            addItemToCart(item, productId);
1722            return;
1723        }
1724    }
1725
1726    unitType = unitType || 'each';
1727    soldInIncrements = soldInIncrements || 1;
1728
1729    if (in_businessEmail !== null) {
1730        window.businessEmail = in_businessEmail;
1731    }
1732
1733    if(typeof deptId === 'undefined') {
1734        deptId = null;
1735    }
1736    if(typeof categoryIdList === 'undefined') {
1737        categoryIdList = [];
1738    }
1739
1740    // Class Package Items
1741    var classPackage = false;
1742    var classPackageData = [];
1743    if (productId.indexOf('CLASS') > -1) {
1744        // Overloading here - it's just too much work to add new fields and we want to redo all this anyway
1745        var classUid = new Date().getTime();
1746        productSku = classUid;
1747        if (packageData && packageData.available) {
1748            classPackage = true;
1749            if (packageData.option == 'classAndPackage') {
1750                in_productType = 'PACKAGE';
1751                pslrId = packageData.packageId;
1752                productWeight = packageData.class_price;
1753                if (packageData.components) {
1754                    packageData.components.forEach(function(c) {
1755                        var s = c.selectedItem;
1756                        var packageItemData = AddProductToCart(null, null, 'PITEM' + packageData.packageId, s.title, s.price, 0, null, '', 'no', 1, 1, 0, null, 0, 0, false, 'PSLR', '', false, '', '', '', s.pslrId, null, classUid);
1757                        if (packageItemData) {
1758                            classPackageData.push(packageItemData);
1759                        }
1760                    });
1761                }
1762            }
1763        }
1764    }
1765
1766    categoryIdList = JSON.stringify(categoryIdList);
1767
1768    var class_attendees = "";
1769    if (requireClassAttendees) {
1770
1771        class_attendees = getClassAttendees(productId);
1772        if (class_attendees.no_value != undefined) {
1773
1774            alert("Attendee Name Required");
1775            $("#" + class_attendees.input_id).focus();
1776            return;
1777        }
1778    }
1779
1780    // Set defaults
1781    if (!pslrId) {
1782        pslrId = '';
1783    }
1784
1785    if (!requiresDownloadEmailAddress || requiresDownloadEmailAddress == 'undefined') {
1786        requiresDownloadEmailAddress = "no";
1787    }
1788
1789    if (!minQuantity || minQuantity == 'undefined') {
1790        if (productCountType == 'fraction') {
1791            minQuantity = 0.25;
1792        } else {
1793            minQuantity = 1;
1794        }
1795    }
1796
1797    if (!maxQuantity || maxQuantity == 'undefined') {
1798        maxQuantity = 100;
1799    }
1800
1801    if (!isTimed || isTimed == 'undefined') {
1802        isTimed = 0;
1803    }
1804
1805    if ((!in_shipping || in_shipping == 'undefined') && in_shipping !== 0) {
1806        in_shipping = '';
1807    }
1808
1809    if ((!in_taxes || in_taxes == 'undefined') && in_taxes !== 0) {
1810        in_taxes = '';
1811    }
1812
1813    // Get current cart
1814    var cart = '';
1815    if (Get_Cart_Cookie('cart')) {
1816        cart = Get_Cart_Cookie('cart');
1817    }
1818
1819    var productCount = null;
1820    if (quantity > 0) {
1821        productCount = quantity;
1822    } else if (productCountType !== null) {
1823        if (in_productType == 'RENTAL' || in_productType == 'RTO') {
1824            productCount = 1;
1825        } else if (inlineAddToCartBtn) {
1826            productCount = parseInt(document.getElementById('inlineInteger' + productId).value) + parseFloat(document.getElementById('inlineFraction' + productId).value);
1827        } else {
1828            var element = document.getElementById('integer' + productId);
1829            var element2 = document.getElementById('fraction' + productId);
1830            productCount = 0;
1831            if (element) {
1832                productCount += parseInt(element.value);
1833            }
1834            if (element2) {
1835                productCount += parseFloat(element2.value);
1836            }
1837        }
1838    } else {
1839        productCount = 1;
1840    }
1841
1842    // Get custom fields & notes
1843    var notes = '';
1844    if (in_notes != 'undefined' && in_notes != '') {
1845        notes = in_notes;
1846    } else {
1847        var noteObjects = $(".class" + productId);
1848        noteObjects.each(function(i) {
1849            if (notes == 'return') {
1850                return;
1851            }
1852            var noteName = $(this).attr('name');
1853            var noteValue = '';
1854
1855            if ($(this).is(':checkbox')) {
1856                noteValue = ($(this).is(":checked") ? 'checked' : 'not checked');
1857            }
1858            else {
1859                noteValue = $.trim($(this).val());
1860            }
1861            if ($(this).attr('requiredField') == 'true' && noteValue == '') {
1862                noteName = noteName.replace(/_/g, ' ');
1863                alert(noteName + ' is a required field.');
1864                notes = 'return';
1865                return;
1866            }
1867
1868
1869            if (notes == '') {
1870                notes = {};
1871            }
1872            notes[noteName] = noteValue;
1873        });
1874
1875        if (notes == 'return') {
1876            return;
1877        }
1878        if (notes != '') {
1879            notes = JSON.stringify(notes);
1880        }
1881    }
1882
1883    // Product ID is modified here, so make sure it goes after anything that relies on the Product ID.
1884    // Handle PSLR information
1885    if (in_productType == 'PSLR') {
1886        // Find selected PSLR
1887        var key = '';
1888        var titleAddOn = '';
1889        for (var i = 0; i < window['numAttributes' + productId]; i++) {
1890            key += (key.length > 0 ? '-' : '') + $('#attribute_' + productId + '_' + i).val();
1891            titleAddOn += (titleAddOn.length > 0 ? ' - ' : '') + window['attributeValues' + productId][i][$('#attribute_' + productId + '_' + i).val()];
1892        }
1893        if (key == '') {
1894            key = '0';
1895        }
1896
1897        // Fix data
1898        productTitle += (titleAddOn.length > 0 ? ': ' : '') + titleAddOn;
1899        if (window['prices' + productId]) {
1900            productWeight = window['prices' + productId][key]['weight'];
1901            productPrice = window['prices' + productId][key]['finalPrice'];
1902            displayPrice = window['prices' + productId][key]['finalDisplayPrice'];
1903            productSku = window['prices' + productId][key]['sku'];
1904            maxQuantity = window['prices' + productId][key]['quantity'];
1905            pslrId = window['prices' + productId][key]['pslrId'];
1906        }
1907
1908        // Get the option image if no image specified
1909        if (!productImagePath && $('#productImage' + productId).length) {
1910            var optionImage = $('#productImage' + productId).attr('src');
1911            if (optionImage && optionImage.length > 0) {
1912                productImagePath = optionImage;
1913            }
1914        }
1915    }
1916    // Gift Cards
1917    else if (in_productType == 'GC') {
1918        productPrice = $("#GCValue").val();
1919        displayPrice = productPrice;
1920        productId += Math.floor(Math.random() * 1000);
1921    } else if (in_productType == 'RENTAL') {
1922        productId = 'RENTAL' + productId;
1923    } else if (in_productType == 'RTO') {
1924        productId = 'RTO' + productId;
1925    } else if (in_productType == 'SUBSCRIPTION') {
1926        productId = 'SUBSCRIPTION' + productId;
1927    }
1928
1929    if (!displayPrice) {
1930        displayPrice = productPrice;
1931    }
1932
1933    // create path for timed inventory ajax calls
1934    if (isTimed == 1) {
1935        var cartUrl = '/module/product.htm?timed=1';
1936        if (isAdminUrl(location.host)) {
1937            cartUrl = location.pathname.substring(0, location.pathname.indexOf('/', 2)) + cartUrl;
1938        }
1939    }
1940    if (!holdingId) {
1941        holdingId = ''; // timed inventory variable
1942    }
1943
1944    var cookieData = dataToCookieString(productId,productTitle,productPrice,productC
1944ount,productWeight,productCountType,productSku,requiresDownloadEmailAddress,minQuantity,maxQuantity,notes
1945        ,isTimed,holdingId,in_shipping,in_taxes,in_productType,pslrId,in_hasAttendees,isDiscountEligible,productImagePath,productImageStyle,class_attendees
1946        ,deptId,categoryIdList,displayPrice,unitType,soldInIncrements,wishlistItemId, rto_items);
1947
1948    // For packageData, we add it as part of the class
1949    if (productId.indexOf('PITEM') > -1) {
1950        return encodeURIComponent(cookieData);
1951    }
1952
1953    if (cookieData === '') {
1954        return ;
1955    }
1956    addItemToCartData(cookieData, classPackageData);
1957
1958    var contentId = productSku ? productSku : productId;
1959    if (window.facebookPixelId) {
1960        fbq('track', 'AddToCart', {
1961            currency: window.currency,
1962            value: productPrice,
1963            content_name: productTitle,
1964            content_ids: [contentId],
1965            content_type: 'product',
1966            contents: [{
1967                'id': contentId,
1968                'quantity': productCount
1969            }]
1970        });
1971    }
1972
1973    addGAEvent(contentId, productTitle, productPrice, productCount);
1974}
1975
1976function verifyClassAttendees(productId) {
1977    var classAttendees = getClassAttendees(productId);
1978    if (classAttendees.no_value !== undefined) {
1979        // TODO: No alerts
1980        alert("Attendee Name Required");
1981        $("#" + classAttendees.input_id).focus();
1982        return false;
1983    }
1984    return true;
1985}
1986
1987function getClassAttendees(class_id_str) {
1988
1989    var return_value = "";
1990    var classToken = "CLASS";
1991    var pos = class_id_str.indexOf(classToken);
1992    if (pos > -1) {
1993
1994        var event_id = class_id_str.substr(pos + classToken.length);
1995        return_value = getAttendeesJson(event_id);
1996    }
1997    return return_value;
1998}
1999
2000function getAttendeesJson(in_event_id) {
2001
2002    var jsn = "";
2003    var attendees = $(".attendee");
2004    if (attendees) {
2005
2006        var names = [];
2007
2008        for (var i = 0; i < attendees.length; i++) {
2009
2010            var ele = attendees[i];
2011            var event_id = ele.attributes["eventid"].value;
2012
2013            if (in_event_id == event_id && ele.value.length > 0) {
2014
2015                names.push(ele.value);
2016            }
2017        }
2018        if (names.length === 0) {
2019
2020            jsn = {no_value: 1, input_id: "event_" + in_event_id + "_attendee_1", numberOfAttendees: parseInt($('#qty').val())};
2021        } else {
2022
2023            jsn = JSON.stringify(names);
2024        }
2025    }
2026    return jsn;
2027}
2028
2029function CalculateDiscount(subtotal, i) {
2030    var discount = 0;
2031    if (window.cartArray[i][0] == 'coupon' || window.cartArray[i][0] == 'couponV2') {
2032        var couponInfo = GetCouponInfo(window.cartArray[i]);
2033        if (couponInfo.couponType == 'dollar_off') {
2034            // Calculate discount
2035            if (subtotal > couponInfo.minDollarAmount) {
2036                discount = couponInfo.dollarOffAmount;
2037            }
2038            discount = Math.round(discount * 100) / 100;
2039        }
2040        else if (couponInfo.couponType == 'percent_off') {
2041            if (subtotal > couponInfo.minDollarAmount) {
2042                discount = Number(subtotal) * (Number(couponInfo.percentOff) / 100);
2043                discount = Math.round(discount * 100) / 100;
2044            }
2045
2046        }
2047        if(couponInfo.maxDiscount && couponInfo.maxDiscount < discount) {
2048            discount = couponInfo.maxDiscount;
2049        }
2050    }
2051
2052    if (discount + 0.01 > subtotal) {
2053        discount = subtotal - 0.01;
2054    }
2055
2056    return discount;
2057}
2058
2059function GetCouponInfo(row) {
2060    if (!row) {
2061        return null;
2062    }
2063
2064    var couponInfo = {};
2065    couponInfo['version'] = row[0];
2066    couponInfo['couponType'] = row[1];
2067    couponInfo['title'] = row[2];
2068    if (couponInfo.version == 'couponV2') {
2069        couponInfo['number'] = row[3];
2070        couponInfo['couponId'] = row[4];
2071        if (couponInfo.couponType == 'dollar_off') {
2072            couponInfo['minDollarAmount'] = row[5];
2073            couponInfo['dollarOffAmount'] = row[6];
2074        } else if (couponInfo.couponType == 'percent_off') {
2075            couponInfo['percentOff'] = row[5];
2076        }
2077    } else {
2078        if (couponInfo.couponType == 'dollar_off') {
2079            couponInfo['minDollarAmount'] = row[3];
2080            couponInfo['dollarOffAmount'] = row[4];
2081            couponInfo['maxDiscount'] = row[5];
2082        }
2083
2084        if (couponInfo.couponType == 'percent_off') {
2085            couponInfo['percentOff'] = row[3];
2086            couponInfo['minDollarAmount'] = row[4];
2087            couponInfo['maxDiscount'] = row[5];
2088        }
2089
2090        if (row.length >= 7) {
2091            couponInfo['number'] = row[6]; // coupon_id
2092        }
2093        if (row.length >= 8) {
2094            couponInfo['start_date'] = row[7];
2095        }
2096        if (row.length >= 9) {
2097            couponInfo['end_date'] = row[8];
2098        }
2099    }
2100    return couponInfo;
2101}
2102
2103function isAdminUrl(url) {
2104    if (typeof adminUrls != 'undefined') {
2105        var length = adminUrls.length;
2106        for (var i = 0; i < length; i++) {
2107            if (adminUrls[i] == url || 'www.' + adminUrls[i] == url || 'my-' + adminUrls[i] == url || 'www.my-' 
2107+ adminUrls[i] == url) {
2108                return true;
2109            }
2110        }
2111    }
2112    return false;
2113}
2114
2115function onChangeConditionalSelect(productId) {
2116    changeConditional(productId);
2117    window.vueEventHub.$eventHub.$emit('product-style-variant-changed');
2118}
2119
2120function changeConditional(productId) {
2121    var condition = getConditional(productId);
2122
2123    if (!condition) {
2124        return;
2125    }
2126
2127    if (window.knobby && window.knobby['module_improved_waitlist']) {
2128        var conditionSelect = $('#conditional-select');
2129        conditionSelect.attr('selected-id', condition.id);
2130        conditionSelect.attr('selected-name', condition.name);
2131    }
2132
2133    var price = condition.hasOwnProperty('display_price') ? condition.display_price.price : 0;
2134
2135    var priceHtml = formatCurrency(price);
2136
2137    var sale = condition.hasOwnProperty('display_price') ? condition.display_price.sale_price : 0;
2138
2139    if (+sale > 0) {
2140        priceHtml = '<strike>' + formatCurrency(price) + '</strike>&nbsp;<b><span style="color: #ff0000">' + formatCurrency(sale) + '</span></b>'
2141    }
2142
2143    document.getElementById('spanPrice' + productId).innerHTML = priceHtml;
2144    changQuantity(productId, condition.id);
2145}
2146
2147function changQuantity(productId, conditionId) {
2148    var isUnlimited = +$('#maxInteger' + productId).val() === 1000;
2149
2150    var quantity = isUnlimited === true ? 1000 : getConditionQuantity(productId, conditionId);
2151
2152    var quantitySelect = $('#integer' + productId);
2153    quantitySelect.find('option').remove()
2154
2155    var reserve = $('#reserve' + productId);
2156    var addBtn = $('#add-to-cart-btn-' + productId);
2157    var addToWaitlistBtn = $('#waitlist-wrapper');
2158
2159    if (quantity === 0) {
2160        reserve.css('display', 'block');
2161        quantitySelect.css('display', 'none')
2162        addBtn.css('display', 'none');
2163        addToWaitlistBtn.css('display', 'inline-block');
2164
2165        return;
2166    }
2167    reserve.css('display', 'none');
2168    quantitySelect.css('display', 'block');
2169    addToWaitlistBtn.css('display', 'none');
2170    addBtn.css('display', 'inline-block');
2171
2172    for(var i = 0; i < quantity; i++) {
2173        quantitySelect.append($('<option>', {
2174            value: i + 1,
2175            text : i + 1,
2176        }));
2177    }
2178}
2179function findCartItemsByProductId(productId) {
2180    return window.cartArray.filter(function (item) {
2181        if (item[0] !== 'product'){
2182            return false;
2183        }
2184
2185        return parseInt(item[1].replace('PSLR', '')) === parseInt(productId);
2186    });
2187}
2188function isValidConditionQuantityInCart(item, currentProductId) {
2189    if (!window.cartArray.length) {
2190        return true;
2191    }
2192
2193    var cart = findCartItemsByProductId(currentProductId);
2194
2195    if (!cart.length) {
2196        return true;
2197    }
2198
2199    var isValidConditionQuantity = function (condition, inCartQuantity) {
2200        var quantity = getConditionQuantity(currentProductId, condition);
2201
2202        return quantity >= inCartQuantity;
2203    };
2204
2205    var CONDITION_INDEX = 30;
2206    var QUANTITY_INDEX = 4;
2207
2208    for (var i = 0; i < cart.length; i++) {
2209        var cartItem = cart[i];
2210
2211        var condition = +cartItem[CONDITION_INDEX];
2212        var quantity = +cartItem[QUANTITY_INDEX];
2213
2214        if (item.conditions) {
2215            for (var j = 0; j < item.conditions; j++) {
2216                if (!isValidConditionQuantity(item.conditions[j].condition, quantity) && +item.conditions[j].condition === condition) {
2217                    return false;
2218                }
2219            }
2220
2221            return true;
2222        }
2223
2224        if (condition !== +item.condition) {
2225            continue;
2226        }
2227
2228        if (!isValidConditionQuantity(condition, quantity)) {
2229            return false;
2230        }
2231    }
2232
2233    return true;
2234}
2235
2236function getInCartQuantity(productId, conditionId, defaultQuantity = 1) {
2237    var cart = findCartItemsByProductId(productId);
2238
2239    if (!cart) {
2240        return defaultQuantity;
2241    }
2242
2243    var CONDITION_INDEX = 30;
2244    var QUANTITY_INDEX = 4;
2245
2246    for (var i = 0; i < cart.length; i++) {
2247        var cartItem = cart[i];
2248        if (+cartItem[CONDITION_INDEX] === +conditionId) {
2249            return +cartItem[QUANTITY_INDEX];
2250        }
2251    }
2252
2253    return defaultQuantity;
2254}
2255
2256function decreaseActualConditionQuantity(productId, conditionId, key = null) {
2257    key = key === null ? ProductAttributeKeyGet(productId, 0) : key;
2258
2259    var conditionQuantity = window['prices' + productId][key]['conditional_quantity'].find(function (v) {
2260        return parseInt(v.condition_id) === parseInt(conditionId);
2261    });
2262
2263    conditionQuantity.quantity = conditionQuantity.quantity - getInCartQuantity(productId, conditionId);
2264}
2265
2266function addGAEvent(productId, productTitle, productPrice, productC
2266ount) {
2267    if (window.knobby && window.knobby['module_flag_google_analytics_v4']) {
2268        if (window.googleAnalyticsId) {
2269            gtag('event', 'add_to_cart', {
2270                currency: window.currency || 'USD',
2271                value: parseFloat(productPrice),
2272                items: [{
2273                    item_id: productId,
2274                    item_name: productTitle,
2275                    quantity: productCount,
2276                    price: productPrice,
2277                }]
2278            });
2279        }
2280    } else {
2281        if (window.googleAnalyticsId) {
2282            gtag('event', 'add_to_cart', {
2283                "items": [{
2284                    id: productId,
2285                    name: productTitle,
2286                    quantity: productCount,
2287                    price: productPrice,
2288                    currency: window.currency,
2289                }]
2290            });
2291        }
2292    }
2293}

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.