PageSourceSearch

https://www.playbaseball.com/bundles/project.js?v=AanFj90-CzRyDr2lJ2hZJS3sWzRIwXJpRrxlTz8UtsE1

js playbaseball.com collected 2026-10-08 22:57:31 UTC 270,205 bytes, 6,608 lines download raw bytes

1/* Minification failed. Returning unminified contents.
2(6534,16-17): run-time error JS1195: Expected expression: .
3(6534,21-22): run-time error JS1003: Expected ':': )
4(6539,9-11): run-time error JS1010: Expected identifier: if
5(6539,13-14): run-time error JS1010: Expected identifier: !
6(6539,13-14): run-time error JS1326: Expected binding syntax: !
7(6539,13-14): run-time error JS1193: Expected ',' or ')': !
8(6539,13-14): run-time error JS1006: Expected ')': !
9(6539,13-14): run-time error JS1008: Expected '{': !
10(6539,38): run-time error JS1004: Expected ';'
11(6539,38-39): run-time error JS1195: Expected expression: )
12(6566,5-12): run-time error JS1009: Expected '}': console
13(6566,5-12): run-time error JS1006: Expected ')': console
14(6539,9,6564,6): run-time error JS1314: Implicit property name must be identifier: if (!dataObject.tealium_event) {
15            console.error("No tealium_event defined for the link call. Please define a tealium_event key-value pair.");
16            return;
17        }
18
19        //Force everything to be strings
20        var objString = Object.fromEntries(
21            Object.entries(dataObject).map(([key, value]) => {
22                if (typeof value === 'object' && value !== null) {
23                    if (Array.isArray(value)) {
24                        var newValue = [];
25                        for (var i = 0; i < value.length; i++) {
26                            newValue[i] = String(value[i]);
27                        }
28                        return [key, newValue];
29                    }
30                    console.log('Tealium link() calls do not accept any objects outside of arrays and strings, ommitting object from data set.');
31                    return [key, ''];
32                }
33                return [key, String(value)];
34            })
35        );
36
37        window.utag.link(objString);
38        return;
39    }
40 */
41!function ($) {
42
43    $.validator.addMethod("postalCode", function (value, element) {
44        return this.optional(element) || /^[a-zA-Z][0-9][a-zA-Z] *[0-9][a-zA-Z][0-9]$/.test(value);
45    }, "Please enter a valid postal code.");
46
47    /**
48     * Default Validation Settings
49     */
50    $.validator.setDefaults({
51        invalidHandler: function (form, validator) {
52            var errors = validator.numberOfInvalids();
53            if (errors) {
54                setTimeout(function () {
55                    validator.errorList[0].element.focus();
56                }, 100);
57            }
58        },
59        errorPlacement: function (error, element) {
60            var $parent = element.parent();
61            if ($parent.hasClass("style-radio")) {
62                error.prependTo($parent.parents(".form-list"));
63            } else if ($parent.hasClass("style-checkbox")) {
64                error.appendTo($parent.parent().siblings("label[class='label-jqv-error']"));
65            } else {
66                error.appendTo(element.parent());
67            }
68        },
69        highlight: function (element, errorClass, validClass) {
70            if (element.type === "radio") {
71                this.findByName(element.name).addClass(errorClass).removeClass(validClass);
72            } else {
73                $(element).addClass(errorClass).removeClass(validClass);
74                $(element.form).find("label[for=" + element.id + "]").addClass('label-' + errorClass);
75                if (($select = $(element).parent('.select-wrap')).length) {
76                    $select.addClass(errorClass).removeClass(validClass)
77                }
78            }
79        },
80        unhighlight: function (element, errorClass, validClass) {
81            if (element.type === "radio") {
82                this.findByName(element.name).removeClass(errorClass).addClass(validClass);
83            } else {
84                $(element).removeClass(errorClass).addClass(validClass);
85                $(element.form).find("label[for=" + element.id + "]").removeClass('label-' + errorClass);
86                if (($select = $(element).parent('.select-wrap')).length) {
87                    $select.removeClass(errorClass).addClass(validClass)
88                }
89            }
90        },
91        ignoreTitle: true,
92        onkeyup: false,
93        errorElement: "p",
94        errorClass: "jqv-error"
95    });
96
97
98    $('#product-form').validate();
99
100    // generic form validation
101    $('.validate-form').each(function (i, v) {
102        $(this).validate();
103    });
104
105    // ads instant credit form validation
106    $('.validate-ads-form').each(function (i, v) {
107        $(this).validate({
108            groups: {
109                SSN: "SS1 SS2 SS3",
110                DateOfBirth: "DOBYear DOBMonth DOBDay",
111                PhoneNumber: "PhoneNum1 PhoneNum2 PhoneNum3",
112                AlternatePhoneNumber: "AltNum1 AltNum2 AltNum3"
113            },
114            errorPlacement: function (error, element) {
115                if (element.attr("name") == "SS1" || element.attr("name") == "SS2" || element.attr("name") == "SS3") {
116                    error.insertAfter("#SSN");
117                }
118                else if (element.attr("name") == "PhoneNum1" || element.attr("name") == "PhoneNum2" || element.attr("name") == "PhoneNum3") {
119                    error.insertAfter("#PhoneNumber");
120                }
121                else if (element.attr("name") == "AltNum1" || element.attr("name") == "AltNum2" || element.attr("name") == "AltNum3") {
122                    error.insertAfter("#AlternateNumber");
123                }
124                else if (element.attr("name") == "DOBYear" || element.attr("name") == "DOBMonth" || element.attr("name") == "DOBDay") {
125                    error.insertAfter("#DOB");
126                }
127                else if (element.attr("name") == "UserAgreementAcceptance") {
128                    //only turn the text red... dont display any extra messages
129                }
130                else {
131                    error.insertAfter(element);
132                }
133            },
134            focusInvalid: false,
135            invalidHandler: function(form, validator) {
136                if (!validator.numberOfInvalids())
137                    return;
138
139                $('html, body').animate({
140                    scrollTop: $(validator.errorList[0].element).offset().top
141                }, 1);
142            }
143        })
144    });
145
146
147    /**
148     * handling country changes - need to change  validation requirements
149     * based on country selected.
150     * 	- set state as optional/required and hide/show
151     * 	-
152     */
153    $(document).on('change.country', 'select.country-select', function (e) {
154        var $this = $(this),
155            $form = $this.parents('form'),
156            validator = $form.data('validator'),
157            $stateField = $this.parents('.form-list').find('select.state'),
158            $zipField = $this.parents('.form-list').find('input.zip'),
159            $phoneField = $this.parents('.form-list').find('input.phone'),
160            option = $this.val();
161
162        if (option == "") {
163            return;
164        }
165
166        if (option == "US" || option == "CA") {
167
168            $stateField.addClass('required').parents('li').show();
169            $zipField.addClass('required');
170            $phoneField.removeClass('phoneNonUS').addClass('phoneUS');
171
172            // Logic for state/province swap
173            var previousValue = $stateField.val();
174            $stateField.find('option').eq(0).siblings().remove();
175
176            if (option == "CA")
177                $zipField.removeClass('zipUS').addClass('zipCA');
178            else if (option == "US") 
179                $zipField.removeClass('zipCA').addClass('zipUS');
180
181            return AjaxJsonPostWrapper.ajaxRouteNonAsync('Product', 'GetStateList', { country: option },
182                function (result) {
183                    $(result).each(function () {
184                        $('<option/>', {
185                            value: this.Value,
186                            text: this.Text
187                        }).appendTo($stateField);
188                    });
189                },
190                null,
191                function () {
192                    // Reset state field value
193                    $stateField.find('option').each(function () {
194                        if ($(this).val() === previousValue) {
195                            $(this).prop('selected', true);
196                        }
197                    })
198                    $stateField.customSelect('updateText');
199                }
200            );
201
202        } else {
203            $stateField.empty();
204            $stateField.removeClass('required').parents('li').hide();
205            $zipField.removeClass('zipCA').removeClass('zipUS');
206            $phoneField.removeClass('phoneUS').addClass('phoneNonUS');
207        }
208    });
209    /**
210     * Update day select opts based on selected month
211     */
212    $(document).on('change.month', 'select.month-select', function (e) {
213        var $this = $(this),//month select
214            $form = $this.parents('form'), //parent form
215            $day = $form.find('.day-select'), //date select
216            today = new Date(), //get todays date
217            month = parseInt($this.val()),//get month
218            year = $form.find('.year-select').val() == "" ? today.getFullYear() : parseInt($form.find('.year-select').val()),//get year, if no year is set use current year
219            daysInMonth = new Date(year, month, 0).getDate(), //get the last day of the month by setting the day to zero
220            lastDay = $day.children('option').length - 1; //get the current last day in the select
221
222
223        //remove days
224        for (var i = lastDay; i >= 0; i--) {
225            if (i > daysInMonth) {
226                $day.children('option').eq(i).remove();
227            }
228        }
229
230        //add days
231        for (i = lastDay + 1; i <= daysInMonth; i++) {
232            $day.append('<option value="' + i + '">' + i + '</option>');
233        }
234
235        $day.customSelect('updateText'); //update select display
236
237    });
238
239    $(document).on('change.year', 'select.year-select', function (e) {
240        var $this = $(this);//year select
241        var $form = $this.parents('form'); //parent form
242        var $month = $form.find('.month-select');
243        if ($month.val() != "") {
244            var $day = $form.find('.day-select'), //date select
245                month = parseInt($month.val()),//get month
246                year = $this.val() == "" ? today.getFullYear() : parseInt($this.val()),//get year, if no year is set use current year
247                daysInMonth = new Date(year, month, 0).getDate(), //get the last day of the month by setting the day to zero
248                lastDay = $day.children('option').length - 1; //get the current last day in the select
249
250
251            //remove days
252            for (var i = lastDay; i >= 0; i--) {
253                if (i > daysInMonth) {
254                    $day.children('option').eq(i).remove();
255                }
256            }
257
258            //add days
259            for (i = lastDay + 1; i <= daysInMonth; i++) {
260                $day.append('<option value="' + i + '">' + i + '</option>');
261            }
262
263            $day.customSelect('updateText'); //update select display
264        }
265    });
266
267}(window.jQuery);;;;
268/**
269 * Ajax add to cart functionality
270 *
271 * Usage using the data api add to the trigger element data-ajax="true" or $('myElement').AjaxCart(options);
272 *
273 * SEARCHING FOR THESE? #btnAddItemToCart  .btn-cart
274 */
275!function ($) {
276    var _root = this,
277		_namespace = 'AjaxCart';
278
279    var AjaxCart = this.AjaxCart = function (element, options) {
280        this.$element = $(element);
281        this.$element.data(this.namespace, this);
282        this.options = $.extend({}, this.defaults, options);
283        this.prepare();
284    };
285
286    AjaxCart.prototype = {
287        namespace: _namespace,
288
289        defaults: {
290            miniCartContainer: '#cartSummary',
291            onBeforeSubmitCallback: null,
292            onSuccessCallback: null,
293            onFailureCallback: null
294        },
295
296        prepare: function () {
297            var url = '',
298                data = null,
299                instance = this;
300
301            if (($form = this.$element.parents('form')).length) {
302                //check if form valdiation is initalized and validated
303                var options = $form.find(".product-options").length;
304                var ColorCode = $form.find("#ColorCode").val();
305                var SizeCode = $form.find("#SizeCode").val();
306
307                if ($form.data('validator')) {
308                    if ($form.valid()) {
309
310                        if (options > 0) {
311                            if (ColorCode == 000) {
312                                $form.data('validator').focusInvalid();
313                                return false;
314                            }
315                            if (SizeCode == 000) {
316                                $form.data('validator').focusInvalid();
317                                return false;
318                            }
319                        }
320
321                        if ($form.find("#hdnFreightZip").length && $form.find("#hdnFreightAmount").length) {
322                            if (!this.validateFreightFields($form)) {
323                                return false;
324                            }
325                        }
326
327                        //todo validate the options are interacted with if there are any in ProductOptionsController.js
328
329                        url = $form.prop('action');
330                        data = $form.serialize();
331                        this.setButtonState(false);
332
333                        if ($form.find('#companion-products').length) {
334                            var scope = angular.element($form.find('#companion-products')).scope();
335                            let companions = [];
336                            scope.vm.forEach(function (product) {
337                                if (product.addToCart) {
338                                    let companion = {};
339                                    product.Quantity = $form.find("#quantity").val();
340                                    if (!product.ColorCode) product.ColorCode = '000';
341                                    if (!product.SizeCode) product.SizeCode = '000';
342                                    companion.AdId = product.AdId;
343                                    companion.ID = product.ID;
344                                    companion.PromoCode = product.PromoCode;
345                                    companion.SizeCode = product.SizeCode;
346                                    companion.ColorCode = product.ColorCode;
347                                    companion.Quantity = parseInt(product.Quantity);
348                                    companions.push(companion);
349                                }
350                            });
351                            if (companions.length) data += '&Companions=' + JSON.stringify(companions);
352                        } 
353
354                        this.submit(url, data);
355
356                        if (typeof this.options.onBeforeSubmitCallback === 'function') {
357                            this.options.onBeforeSubmitCallback(this);
358                        }
359                    } else {
360                        $form.data('validator').focusInvalid();
361                    }
362                }
363            }
364        },
365
366        //freight fields are required in cart post for truck items, but they are hidden
367        validateFreightFields: function($form) {
368            var zip = $form.find("#hdnFreightZip").val();
369            var amount = $form.find("#hdnFreightAmount").val();
370            var status = $form.find("#hdnFreightStatus").val();
371            var validator = $form.validate();
372            if (zip == null || zip === "" || amount == null || amount === "" || amount === 0) {
373                validator.showErrors({
374                    "freightZipInput": "You must have a freight rate set to purchase this item."
375                });
376                $form.data('validator').focusInvalid();
377                return false;
378            }
379
380            if (status !== "200") {
381                return false;
382            }
383
384            return true;
385        },
386
387        setButtonState: function (state) {
388            state ? this.$element.prop('disabled', false).removeClass('disabled') : this.$element.prop('disabled', true).addClass('disabled')
389        },
390
391        submit: function (url, data) {
392            var that = this;
393
394            Gorilla.util.messages.clearMessages();
395
396            $.ajax({
397                type: 'POST',
398                url: url.toLowerCase(),
399                data: data,
400                dataType: 'json'
401            })
402            .done(function (data) {
403                that.handleSuccess(data);
404            })
405            .fail(function (xhr, ajaxOptions, thrownError) {
406                that.handleFailure(thrownError);
407            }).always(function () {
408                that.setButtonState(true);
409            })
410        },
411
412        handleSuccess: function (response) {
413            if (response.success) {
414                if (response.message != null && response.message != '') {
415                    Gorilla.util.messages.addMessages(response.messages, 'success');
416                }
417
418                populateTealiumAjaxScript(response.tealium);
419                if (response.certona) {
420                    var certonaDiv = $('#certonaAjax');
421                    if (typeof certonaDiv !== 'undefined') {
422                        certonaDiv.empty();
423                        certonaDiv.append(response.certona);
424                    }
425                }
426
427                if (window.location.href.indexOf('cart/viewcart')) {
428                    var scope = angular.element(document.getElementById('ViewCartController')).scope();
429                    if (scope != undefined) scope.getCart();
430                }
431            } else {
432                //set messages
433                if (response.messages) {
434                    Gorilla.util.messages.addMessages(response.messages, 'error');
435                }
436            }
437
438            if (typeof this.options.onSuccessCallback === 'function') {
439                this.options.onSuccessCallback(this, response);
440            }
441
442            var scope = angular.element(document.getElementById('CartWishListHomepageController')).scope();
443            if (scope != undefined) scope.addedToCart();
444        },
445
446        handleFailure: function (thrownError) {
447            alert('An error occurred while processing your request. Please try again shortly.');
448
449            if (typeof this.options.onFailureCallback === 'function') {
450                this.options.onFailureCallback(this, thrownError);
451            }
452        },
453
454        /**
455		 * Resets the plugin state back to init state
456		 */
457        reset: function () {
458
459        },
460
461        /**
462		 * Unsets all events and settings back to init state
463		 */
464        unset: function () {
465            $(document).off('click.ajaxCart');
466        }
467
468
469    };
470
471    $.fn[_namespace] = function (options) {
472        var args = arguments;
473        if (options === undefined) {
474            options = {};
475        }
476
477        if (typeof options === "object") {
478            return this.each(function () {
479                new AjaxCart(this, options);
480            });
481        } else {
482            if (typeof options === 'string' && AjaxCart.prototype[options]) {
483                var obj = $(this).data(_namespace);
484                obj[options].apply(obj, Array.prototype.slice.call(args, 1));
485            } else {
486                console.error('Method ' + options + ' does not exist in ' + _namespace);
487            }
488        }
489    };
490
491    $(document).on('click.ajaxCart', '[data-ajax="true"]', function (e) {
492        e.preventDefault();
493        $(this).AjaxCart();
494    });
495
496
497    /**
498     * Ajax AddCart - Handles successful responses
499     * @param obj
500     * @param response
501     */
502    AjaxCart.prototype.defaults.onSuccessCallback = function (obj, response) {
503        if (response.cartMax == true)
504            $("#cart-limit-modal-trigger").moby({
505                'modalClass': 'cart-limit-modal gradient-gray',
506                'ariaLabelText': 'Full Cart',
507                'onCompleteCallback': function () {
508                    $(".moby-close").on('click', function (event) {
509                        event.preventDefault();
510                        $("#cart-limit-modal-trigger").moby('hide');
511                    });
512                }
513            }).moby('show', '#cart-limit-modal');
514        else {
515
516            if (response.miniCartHtml && response.miniCartHtml !== "") {
517                //update mini cart html
518                var prevItemCount = $("#cart-mmenu .products-grid li").length;
519                setCartQuantityText();
520                var showCart = response.freeGiftHtml == "" &&
521                    response.personalizeHtml == "";
522
523                if (Gorilla.util.getCookie("ab-cart") === "Experiment" && showCart) {
524                    //this is bad practice, but a necessary evil until we are fully angular on the rest of the site
525                    var scope = angular.element(document.getElementById('ItemAddedDialogController')).scope();
526                    scope.showDialog();
527                } else {
528                    updateShowMiniCart(response.miniCartHtml, true);
529                    //$(obj.options.miniCartContainer).html(response.miniCartHtml);
530                    if ($("#cart-mmenu .products-grid li").length > prevItemCount)
531                        popFadeProduct("cart-mmenu");
532                }
533            }
534            
535        }
536
537        //determine if we are in a modal and close it, dont close if there are errors 
538        if (response.success) {
539            if (obj.$element && ($moby = obj.$element.parents('.moby-container')).length) {
540                $moby.find('.moby-close').trigger('click').off('click'); //close the actual window that triggered this....normal path
541            }
542        }
543        else {
544            Gorilla.util.messages.addMessages(response.messages, 'error');
545        }
546        
547        //this has to go after the modal close above otherwise the page data is changed and the modal will not close.
548        if (response.cartHtml) {
549            $('#cartContainer').html(response.cartHtml);
550            $('#cartContainer').find($("img.lazy")).lazy();
551        }
552    }
553
554
555}(jQuery);
556
557
558function populateTealiumAjaxScript(script) {
559    var div = $('#tealiumAjax');
560    if (typeof div !== 'undefined') {
561        div.empty();
562        div.append(script);
563    }
564}
565
566function addItemToCartFamilyGroup(itemId, promoCode, color, size, qty, fgItem, fgPromo, fgOfferID, fromTable) {
567    var cartItem = { ID: itemId, PromoCode: promoCode, ColorCode: color, SizeCode: size, Quantity: qty, FreeGiftItemId: fgItem, FreeGiftPromoCode: fgPromo, FreeGiftOfferID: fgOfferID, FromTable: fromTable };
568    return AjaxJsonPostWrapper.ajaxRoute('cart', 'addtocart', { data: cartItem }, function (result) {
569        if (result.cartMax == true) {
570            $("#cart-limit-modal-trigger").moby({
571                'modalClass': 'cart-limit-modal gradient-gray',
572                'ariaLabelText': 'Full Cart',
573                'onCompleteCallback': function () {
574                    $(".moby-close").on('click', function (event) {
575                        event.preventDefault();
576                        $("#cart-limit-modal-trigger").moby('hide');
577                    });
578                }
579            }).moby('show', '#cart-limit-modal');
580        }
581        else {
582            updateShowMiniCart(result.miniCartHtml, true);
583            populateTealiumAjaxScript(result.tealium);
584            if (result.freeGiftHtml) {
585                if (($giftTrigger = $('#freegift-trigger')).length && ($giftModal = $('#freegift-modal')).length) {
586                    //init the modal and set the Html from the response, since Moby requires an anchor we're triggering a click on the hidden anchor
587                    $giftModal.html(result.freeGiftHtml);
588                    $giftTrigger.moby({
589                        'modalClass': 'free-gift',
590                        'ariaLabelText': 'Free Gift',
591                        'bodyClose': false,
592                        'keyActions': false,
593                        'onCompleteCallback': function () {
594                            Gorilla.util.initForms();
595                            $(".moby-close").hide();
596                            $('#free-gift').validate();
597                        }
598                    }).moby('show', '#freegift-modal');
599                }
600            }
601        }
602
603    });
604}
605;
606var AjaxJsonPostWrapper = (function () {
607   
608    var my = {};
609
610    my.async = true;
611    
612    my.getBaseUrl = function () {
613        var pathArray = window.location.pathname.split('/');
614        return window.location.protocol + "//" + window.location.host;
615    };
616
617    my.getUrl = function (controller, action) {
618        return my.getBaseUrl() + '/' + controller + '/' + action;
619    };
620
621    my.getFormData = function (form) {
622        // there is an improved version of this function in the admin tool...
623        var data = $(form).serializeArray();
624        var formData = {};
625        for (var i = 0; i < data.length; i++) {
626            formData[data[i].name] = data[i].value;
627        }
628        return formData;
629    };
630
631    my.ajaxUrl = function (url, data, success, error, complete, type) {
632        var ajaxType = 'POST'; 
633
634        if (type != undefined) {
635            ajaxType = type;
636        }
637        return $.ajax({
638            type: ajaxType,
639            url: url.toLowerCase(),
640            async: my.async,
641            data: JSON.stringify(data),
642            contentType: 'application/json',
643            traditional: true,
644            beforeSend: function () {
645            },
646            success: function (result) {
647                if (success != undefined) {
648                    success(result);
649                }
650            },
651            complete: function () {
652                if (complete != undefined) {
653                    complete();
654                }
655            },
656            error: function (XMLHttpRequest, textStatus, errorThrown) {
657                var errId = XMLHttpRequest.getResponseHeader("System-Error-ID");
658                var errIdMsg = "";
659                if (errId != null) {
660                //    var newUrl = AjaxJsonPostWrapper.getBaseUrl() + '/error/error?errId=' + errId;
661                //    window.location.replace(newUrl);
662                    errIdMsg = " [" + errId + "]"
663                }
664                console.log("An error occurred during ajax operation" + errIdMsg + ".") // mimics what has been "good enough" since redesign, circa 2014.  we don't really know what to do but probably don't want to interrupt the user
665
666                if (error != undefined) {
667                    error(errorThrown);
668                }
669                else
670                {
671                    Gorilla.util.messages.addMessage('Sorry, there was an error with your request. Please try again shortly.', 'error');
672                }
673            }
674        })
675		.done(function (data) {
676		    if (data.errors) {
677		        onDataError(data);
678		    }
679		});
680    };
681
682    my.ajaxRoute = function (controller, action, data, success, error, complete, type) {
683        my.async = true;
684        var url = my.getUrl(controller.toLowerCase(), action.toLowerCase());
685        return my.ajaxUrl(url, data, success, error, complete, type);
686    };
687
688    my.ajaxRouteNonAsync = function (controller, action, data, success, error, complete, type) {
689        my.async = false;
690        var url = my.getUrl(controller.toLowerCase(), action.toLowerCase());
691        return my.ajaxUrl(url, data, success, error, complete, type);
692    };
693
694    return my;
695}());;
696var moveToWishlistIndex = 0;
697
698!function ($) {
699
700    // Readied
701    $(function () {
702        //test for csscalc support
703        Modernizr.addTest('csscalc', function () {
704            var prop = 'width:';
705            var value = 'calc(10px);';
706            var el = document.createElement('div');
707
708            el.style.cssText = prop + Modernizr._prefixes.join(value + prop);
709
710            return !!el.style.length;
711        });
712        if (!Modernizr.csscalc) {
713            $("html").addClass("no-csscalc");
714        }
715
716        //fix for keyboard open and position fixed elements with iOS
717        if (Modernizr.touch) {
718            var $body = $('body'); 
719            
720            $(document).on('focus', 'input:not(#searchMobile), textarea, select, md-select-menu', function () {
721                $body.addClass('ios-kb-fix');
722            }).on('blur', 'input, textarea, select, md-select-menu', function () {
723                $body.removeClass('ios-kb-fix');
724            });
725        }
726
727        var fnSkipToContent = function () {
728            focusOnFirstEl($("#main[role='main']"));
729        }
730
731        $("#skipToContent > a").on("click", fnSkipToContent);
732        $("#skipToContent > a").on('keypress', function (e) {
733            if (e.which == 13) { fnSkipToContent(); }
734        });
735
736        //init custom form elements
737        Gorilla.util.initForms();
738
739        if (($modalTrigger = $('.trigger-modal')).length) {
740            $modalTrigger.moby({
741                'modalClass': 'generic'
742            });
743        }
744
745        initToolTips();
746
747        //restrictions accordion in quickview
748        $(document).on("click", ".moby-container .restrictions-note legend", function () {
749            var restrictionsText = $(this).parent().find("#restrictions-text");
750
751            if (restrictionsText.is(":visible")) {
752                $(this).find("#plus-minus").text("+");
753                restrictionsText.fadeOut('fast');
754            } else {
755                $(this).find("#plus-minus").text("-");
756                restrictionsText.fadeIn('slow');
757            }
758        });
759
760        if (($lazyImg = $('.lazy')).length) {
761            $lazyImg.lazy();
762        }
763 
764        //Init default sliders, use data api to set items count and margins
765        if (($slider = $('.default-slider .products-grid')).length) {
766            if (!$slider.hasClass('slick-initialized')) {
767                $slider.slick({
768                    dots: false,
769                    arrows: true,
770                    slidesToShow: 4,
771                    slidesToScroll: 4,
772                    infinite: false,
773                    lazyLoad: 'ondemand',
774                    prevArrow: '<span class="sg-slick-prev" role="button" aria-label="Previous" tabindex="0"> &lsaquo; </span>',
775                    nextArrow: '<span class="sg-slick-next" role="button" aria-label="Next" tabindex="0"> &rsaquo; </span>',
776                    responsive: [
777                        {
778                            breakpoint: 1060,
779                            settings: {
780                                slidesToShow: 3,
781                                slidesToScroll: 3,
782                                arrows: true,
783                                dots: true
784                            }
785                        },
786                        {
787                            breakpoint: 768,
788                            settings: {
789                                slidesToShow: 2,
790                                slidesToScroll: 2,
791                                arrows: true,
792                                dots: true
793                            }
794                        },
795                        {
796                            breakpoint: 480,
797                            settings: {
798                                slidesToShow: 1,
799                                slidesToScroll: 1,
800                                arrows: true,
801                                dots: true
802                            }
803                        }
804                    ]
805                });
806                numSlickProductSliders += $('.default-slider .products-grid').length;
807                $slider.on("breakpoint", function (event, slick, breakpoint) {
808                    event.preventDefault();
809                    processSlickProductSliders();
810                });
811            }
812        }
813
814        //brands carousel slider
815        if (($brandslider = $('.slick-brands-carousel')).length) {
816            if (!$brandslider.hasClass('slick-initialized')) {
817                $brandslider.slick({
818                    dots: false,
819                    infinite: true,
820                    respondTo: 'slider',
821                    slidesToShow: 8,
822                    slidesToScroll: 8,
823                    prevArrow: '<span class="sg-slick-prev" role="button" aria-label="Previous" tabindex="0"> &lsaquo; </span>',/*Needs styles*/
824                    nextArrow: '<span class="sg-slick-next" role="button" aria-label="Next" tabindex="0"> &rsaquo; </span>',
825                    responsive: [
826                        {
827                            breakpoint: 1400,
828                            settings: {
829                                slidesToShow: 7,
830                                slidesToScroll: 7
831                            }
832                        },
833                        {
834                            breakpoint: 1200,
835                            settings: {
836                                slidesToShow: 6,
837                                slidesToScroll: 6
838                            }
839                        },
840                        {
841                            breakpoint: 1060,
842                            settings: {
843                                slidesToShow: 5,
844                                slidesToScroll: 5
845                            }
846                        },
847                        {
848                            breakpoint: 960,
849                            settings: {
850                                slidesToShow: 4,
851                                slidesToScroll: 4
852                            }
853                        },
854                        {
855                            breakpoint: 680,
856                            settings: {
857                                slidesToShow: 3,
858                                slidesToScroll: 3
859                            }
860                        },
861                        {
862                            breakpoint: 480,
863                            settings: {
864                                slidesToShow: 2,
865                                slidesToScroll: 2
866                            }
867                        },
868                        {
869                            breakpoint: 320,
870                            settings: {
871                                slidesToShow: 1,
872                                slidesToScroll: 1,
873                                variableWidth: true,
874                                centerMode: true,
875                                arrows: false
876                            }
877                        }
878                    ]
879                });
880                $brandslider.find('img').show();
881            }
882        }
883
884        //callout slider
885        if (($calloutSlider = $('.techDetailsCarousel-container .slick-slider')).length) {
886            if (!$calloutSlider.hasClass('slick-initialized')) {
887                $calloutSlider.slick({
888                    dots: false,
889                    arrows: true,
890                    slidesToShow: 1,
891                    slidesToScroll: 1,
892                    lazyLoad: 'ondemand',
893                    fade: true,
894                    cssEase: 'linear'
895                });
896
897                $calloutSlider.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
898                    $(".techDetailsCarousel-container ul.callout-thumbs li").removeClass("selected");
899                    $(".techDetailsCarousel-container ul.callout-thumbs").find("li:eq(" + nextSlide + ")").addClass("selected");
900                });
901
902                $("ul.callout-thumbs li").on("click", function () {
903                    $calloutSlider.slick('slickGoTo', $(this).index());
904                });
905            }
906        }
907
908        if (($navslider = $('.navigation-carousel .bcwp-widgets-wrapper')).length) {
909            if (!$navslider.hasClass('slick-initialized')) {
910                $navslider.slick({
911                    dots: false,
912                    infinite: true,
913                    respondTo: 'slider',
914                    slidesToShow: 6,
915                    slidesToScroll: 6,
916                    prevArrow: '<span class="sg-slick-prev-gray" role="button" aria-label="Previous" tabindex="0"></span>',/*Needs styles*/
917                    nextArrow: '<span class="sg-slick-next-gray" role="button" aria-label="Next" tabindex="0"></span>',
918                    responsive: [
919                        {
920                            breakpoint: 1400,
921                            settings: {
922                                slidesToShow: 6,
923                                slidesToScroll: 6
924                            }
925                        },
926                        {
927                            breakpoint: 1060,
928                            settings: {
929                                slidesToShow: 5,
930                                slidesToScroll: 5
931                            }
932                        },
933                        {
934                            breakpoint: 960,
935                            settings: {
936                                slidesToShow: 4,
937                                slidesToScroll: 4
938                            }
939                        },
940                        {
941                            breakpoint: 680,
942                            settings: {
943                                slidesToShow: 3,
944                                slidesToScroll: 3
945                            }
946                        }
947                    ]
948                });
949            }
950        }
951
952        /**
953         * Ajax AddCart - Handles successful responses
954         * @param obj
955         * @param response
956         */
957        AjaxCart.prototype.defaults.onSuccessCallback = function (obj, response) {
958            if (response.cartMax == true)
959                $("#cart-limit-modal-trigger").moby({
960                    'modalClass': 'cart-limit-modal gradient-gray',
961                    'ariaLabelText': 'Full Cart',
962                    'onCompleteCallback': function () {
963                        $(".moby-close").on('click', function (event) {
964                            event.preventDefault();
965                            $("#cart-limit-modal-trigger").moby('hide');
966                        });
967                    }
968                }).moby('show', '#cart-limit-modal');
969            else {
970
971                if (response.miniCartHtml && response.miniCartHtml !== "") {
972                    //update mini cart html
973                    var prevItemCount = $("#cart-mmenu .products-grid li").length;
974                    setCartQuantityText();
975                    var showCart = response.freeGiftHtml == "" &&
976                        response.personalizeHtml == "";
977
978                    if (Gorilla.util.getCookie("ab-cart") === "Experiment" && showCart) {
979                        //this is bad practice, but a necessary evil until we are fully angular on the rest of the site
980                        var scope = angular.element(document.getElementById('ItemAddedDialogController')).scope();
981                        scope.showDialog();
982                    } else {
983                        updateShowMiniCart(response.miniCartHtml, showCart);
984                        $(obj.options.miniCartContainer).html(response.miniCartHtml);
985
986                        if ($("#cart-mmenu .products-grid li").length > prevItemCount)
987                            popFadeProduct("cart-mmenu");
988                    }
989                }
990
991                //handle freegift modal
992                if (response.freeGiftHtml) {
993                    if (($giftTrigger = $('#freegift-trigger')).length && ($giftModal = $('#freegift-modal')).length) {
994                        //init the modal and set the Html from the response, since Moby requires an anchor we're triggering a click on the hidden anchor
995                        $giftModal.html(response.freeGiftHtml);
996                        $giftTrigger.moby({
997                            'modalClass': 'free-gift',
998                            'ariaLabelText': 'Free Gift',
999                            'bodyClose': false,
1000                            'keyActions': false,
1001                            'onCompleteCallback': function () {
1002
1003                                if (($selects = $("#free-gift select")).length) {
1004                                    $selects.first().prop("selectedIndex", 0).customSelect("updateText");
1005                                }
1006
1007                                Gorilla.util.initForms();
1008                                $(".moby-close").hide();
1009                                $('#free-gift').validate();
1010                            }
1011                        }).moby('show', '#freegift-modal');
1012                    }
1013                }
1014                
1015            }
1016            //determine if we are in a modal and close it, dont close if there are errors 
1017            if (response.success) {
1018                if (obj.$element && ($moby = obj.$element.parents('.moby-container')).length) {
1019                    $moby.find('.moby-close').trigger('click').off('click'); //close the actual window that triggered this....normal path
1020                }
1021            }
1022            else {
1023                Gorilla.util.messages.addMessages(response.messages, 'error');
1024            }
1025            
1026            //this has to go after the modal close above otherwise the page data is changed and the modal will not close.
1027            if (response.cartHtml) {
1028                $('#cartContainer').html(response.cartHtml);
1029                $('#cartContainer').find($("img.lazy")).lazy();
1030            }
1031        }
1032
1033        //Canada/International Shopping Modal
1034        $(document).on("click", "a.international", function () {
1035            var $intlMoby = $(this).moby({
1036                'modalClass': 'generic intl-shopping-modal',
1037                'ariaLabelText': 'International options',
1038                'onCompleteCallback': function () {
1039                    Gorilla.util.initForms();
1040                    $('#intl-shopping-form').validate();
1041                    $("#intl-shopping").find(".close-link").on("click", function (e) {
1042                        e.preventDefault();
1043                        $intlMoby.off('click.moby');
1044                        $intlMoby.moby('remove');
1045                    });
1046                    $(".intl-shopping-modal .moby-close").on("click", function() {
1047                        $(this).parent().find('.close-link').click();
1048                    });
1049                }
1050            }).moby('show', '#intl-shopping');
1051        });
1052
1053        //Tracking Infomration Modal
1054        var $trackingInfoModal = $(".tracking-info-trigger").moby({
1055            'modalClass': 'tracking-info-modal',
1056            'ariaLabelText': 'Tracking information',
1057            'onCompleteCallback': function () {
1058                Gorilla.util.initForms();
1059
1060                // not going to have this Close link in _OrderTrackng.cshtml for the time-being
1061                //  it may (or may not) have been causing infrequent "immediate close" when opening...
1062                //$("#tracking-info").find(".close-link").click(function (e) {
1063                //    e.preventDefault();
1064                //    $trackingInfoModal.moby('hide');
1065                //});
1066            }
1067        });
1068
1069        //Audio modal
1070        var $divAudioTrigger = $("#div-audio-trigger").moby({
1071            'modalClass': 'audio-modal',
1072            'ariaLabelText': 'Audio sample',
1073            'onCompleteCallback': function () {
1074                Gorilla.util.initForms();
1075            },
1076            'onCloseCallback': function () {
1077                $("#audioPlayer")[0].pause();
1078            }
1079        });
1080
1081        //Share Wish List Link Modal
1082        if (($sharewishlist = $(".sharewishlist-trigger")).length) {
1083            $(document).on("click", ".sharewishlist-trigger", function (e) {
1084                e.preventDefault();
1085                $(".sharewishlist-trigger").moby({
1086                    'modalClass': 'generic sharewishlist-modal',
1087                    'ariaLabelText': 'Share Wish List',
1088                    'onBeforeCloseCallback': function () {
1089                        $("#email-wishlist-form").trigger("reset"); // reset the form...
1090                        var validator = $("#email-wishlist-form").validate();
1091                        validator.resetForm();
1092                        $("#email-wishlist-form label").removeClass("label-error");
1093                        $('#message-block').fadeOut("slow");
1094                        $('#message-block').html("");
1095                    },
1096                    'onCompleteCallback': function () {
1097                        Gorilla.util.initForms();
1098
1099                        $("#sharewishlist-modal").find(".close-link, .moby-close").click(function (e) {
1100                            e.preventDefault();
1101                            $(".sharewishlist-trigger").moby('hide');
1102                        });
1103                    }
1104                }).moby('show', '#sharewishlist-modal');
1105            });
1106        }
1107
1108        // Message (Move to Wish List from Cart) Modal
1109        var $messageModal = $("#wishlistmessage-trigger").moby({
1110            'modalClass': 'generic wishlistmessage-modal',
1111            'ariaLabelText': 'Wishlist Success',
1112            'onCloseCallback': function () {
1113                //ADA return focus to cart table after modal is closed
1114                setTimeout(function () {
1115                    var $trs = $("#cartContainer tbody tr:not(.restrictions-row)");
1116                    if (moveToWishlistIndex > $trs.length) {
1117                        $trs.last().find('.product-name a').focus();
1118                    } else {
1119                        $("#cartContainer tbody tr:not(.restrictions-row):nth-child(" + moveToWishlistIndex + ")").find('.product-name a').focus();
1120                    }
1121                }, 250);
1122            }
1123        });
1124
1125        //Edit Exp (cc) Link Modal done in checkout.js
1126
1127        //Cancel Club Modal
1128        $(document).on("click", "#cancel-membership", function () {
1129            $("#cancel-membership-trigger").moby({
1130                'modalClass': 'club-accept-modal',
1131                'ariaLabelText': 'Cancel club',
1132                'onCompleteCallback': function () {
1133                    Gorilla.util.initForms();
1134                    $('#cancel-membership-form').validate();
1135                }
1136            }).moby('show', '#cancel-membership-modal');
1137        });
1138
1139        //cancel club confirmation
1140        $(document).on("submit", "#cancel-membership-form", function () {
1141            var postedData = AjaxJsonPostWrapper.getFormData(this);
1142            var firstLast = $(".customer-firstlast").text();
1143            return AjaxJsonPostWrapper.ajaxRoute('club', 'cancelmembership',
1144                { customerNumber: postedData.CustomerNumber, cancelReason: postedData.CancelReason, name: firstLast },
1145            function(result) {
1146                if (result.Success === true) {
1147                    $("#cancel-membership-modal").html(result.Message);
1148                    $(".club-dashboard > .spiff-container").replaceWith(result.DashboardSpiffHtml);
1149                    $(".club-dashboard > .spiff-container").find($("img.lazy")).lazy();
1150                } else {
1151                    Gorilla.util.messages.addMessage('Sorry, an error has occurred. Please try again shortly.',
1152                        'error');
1153                }
1154            });
1155        });
1156
1157        //selection groups will refresh the lightbox on quickview
1158        $(document).on("click", ".quickview-form ul.selection-group li a.selection-link", function (event) {
1159            event.preventDefault();
1160            var adId = getParameterByName("a", $(this).attr('href'));
1161            var data = { "AdId": adId };
1162            return AjaxJsonPostWrapper.ajaxRoute("product", "getproductcartdata", data, function (result) {
1163                $(".moby-container.quickview .quickview-form").replaceWith(result);
1164                validateAndInitQuickViewForm($(".moby-container.quickview .quickview-form"));
1165            });
1166        });
1167
1168        //Gift Card Balance Form
1169        var $giftCardBalanceForm = $("#card-balance-form");
1170        if ($giftCardBalanceForm.length) {
1171            var $balanceMessageHolder = $("#balance-message");
1172
1173            $giftCardBalanceForm.validate({
1174                submitHandler: function (form) {
1175                    var $loader = $(form).find(".ajax-loader");
1176                    var url = $(form).prop("action");
1177
1178                    $balanceMessageHolder.text('');
1179                    $loader.show();
1180
1181                    $.post(url, $(form).serialize(), function (response) {
1182                        $balanceMessageHolder.text(response.message)
1183                        if (response.success) {
1184                            $balanceMessageHolder.addClass("success");
1185                        } else {
1186                            $balanceMessageHolder.addClass("error");
1187                        }
1188
1189                        $loader.hide();
1190                    });
1191                }
1192            });
1193        }
1194
1195        //gift card lookup on my account/shopping resources
1196        if ($(".gift-card-balance").length) {
1197            $(document).on("click", "#gc-balance-btn", function () {
1198                if ($("#ReferenceNumber").val().trim() == "" ||
1199                    !$('#card-balance-form').valid()) {
1200                    return;
1201                }
1202
1203                var data = AjaxJsonPostWrapper.getFormData($('#card-balance-form'));
1204                AjaxJsonPostWrapper.ajaxRoute("giftcard", "giftcardlookup", { giftCard: data },
1205                    function (result) {
1206                        $("#gift-card-lookup-tables").html(result.giftCardLookupHtml);
1207                    });
1208            });
1209        }
1210
1211        /**
1212         * keep body from scrolling when nav menu is open in iOS
1213         */
1214        $(document).on('touchmove', function (e) {
1215            if ($('body').hasClass('nav-showing')) {
1216                var $target = $(e.target);
1217                if ($target.is('#nav-wrapper') || $target.parents('#nav-wrapper')) {
1218                    e.stopPropagation();
1219                }
1220            }
1221        });
1222
1223        //dimension accordion init
1224        if (($accordion = $('#dimensions').find('.dim-accordion')).length) {
1225            $accordion.gorillaAccordion({
1226                trigger: 'a.trigger',
1227                container: '.content',
1228                containerInner: '> ul'
1229            });
1230        }
1231
1232        // a simple pair of classes was addded to truncate top and bottom abstracts with "..." on mobile
1233        //  this allows user to expand and read the whole section if desired.
1234        $(document).on("click", ".single-line-ellipsis-trigger", function () {
1235            $(this).toggleClass("single-line-ellipsis");
1236        });
1237
1238        //Accordion spiff from web page images template
1239        if (($spiffAccordion = $('.spiff-accordion')).length) {
1240            $spiffAccordion.gorillaAccordion({
1241                trigger: '.category-hero',
1242                container: '.accordion-content',
1243                containerInner: '> div'
1244            });
1245        }
1246
1247        //peelback spiff from web page images template
1248        if (($peelBackSpiff = $(".peelback-container")).length) {
1249            $peelBackSpiff.on("mouseover", function () {
1250                $(this).find("div.before").css("width", 0);
1251            });
1252        }
1253
1254        $(document).on("click", ".cfs-offerdetails-trigger", function (e) { // variation on the sg-accordion-header concept
1255            e.preventDefault();
1256            $(this).next().slideToggle(250, function () { // the very next element had better be the content...
1257            }); 
1258        });
1259
1260        // deal with container padding: first, last, multiple containers of the same type are in a row
1261        if ((bcwpContainers = $("div.base-container")).length) {
1262            for (var i = 0; i < bcwpContainers.length; i++) {
1263                var $elem = $(bcwpContainers[i]);
1264
1265                // see if we're the first one of multiple of this type
1266                if (i == 0 || (i > 0 && $elem.data("containertype") != $(bcwpContainers[i - 1]).data("c
1266ontainertype")) &&
1267                    i < bcwpContainers.length - 1 &&
1268                    $elem.data("containertype") == $(bcwpContainers[i + 1]).data("containertype")) {
1269
1270                    $elem.addClass("firstOfType");
1271                }
1272
1273                // look back to see if the one before this was the same type
1274                if (i > 0 && $elem.data("containertype") === $(bcwpContainers[i - 1]).data("containertype")) {
1275                    $elem.addClass("nthOfType");
1276
1277                    // see if we're also the last of our type...
1278                    if (i === bcwpContainers.length - 1 || $elem.data("containertype") != $(bcwpContainers[i + 1]).data("containertype")) {
1279                        $elem.addClass("lastOfType");
1280                    }
1281                }
1282
1283                // tag the very first base-container
1284                if (i === 0) {
1285                    $elem.addClass("firstBaseContainer")
1286                }
1287
1288                // tag the very last base-container
1289                if (i === bcwpContainers.length - 1) {
1290                    $elem.addClass("lastBaseContainer")
1291                }
1292            }
1293        }
1294
1295        $(document).on("click", "button.tool-tip", function (e) {
1296            if (e.target.tagName.toLowerCase() === 'a') // let nested links work
1297                return true;
1298            
1299            e.preventDefault();
1300            e.stopPropagation();
1301        });
1302
1303        $(document).on("keypress", ".pdp2019-quantityAdjustment #quantity", function (e) {
1304            var keyCode = e.which;
1305            if (keyCode == 13 && $(this).valid()) {
1306                $('#btnAddItemToCart').click();
1307                return false;
1308            }
1309            return textInputDigitsOnly(keyCode);
1310        });
1311
1312        $(document).on("blur", ".pdp2019-quantityAdjustment #quantity", function () {
1313            $this = $(this);
1314            var curVal = Number($.trim($this.val()));
1315            if (isNaN(curVal) || curVal <= 0 || !Number.isInteger(curVal)) {
1316                $this.val(1);
1317            }
1318        });
1319
1320    });  // **** END Readied ****
1321
1322    // lots of trial club pages need a huge block of text, we wanted an "accordian" style flyout when the "link" is clicked
1323    $(".show-buyers-club-benefits").on("click", function () {
1324        $('#buyers-club-benefits').fadeIn('slow');
1325        $(this).html('');
1326    });
1327
1328    //promo banner "tool tips"
1329    $(document).on("click", ".promo-trigger", function () {
1330        var message = $(this).next("hdncontent");
1331        $("#site-promo-modal").html(message.text());
1332
1333        $("#site-promo-modal-trigger").moby({
1334            //'modalClass': 'cart-limit-modal gradient-gray',
1335            'ariaLabelText': 'Promotion',
1336            'onCompleteCallback': function () {
1337                $(".moby-close").on('click', function (event) {
1338                    event.preventDefault();
1339                    $("#site-promo-modal-trigger").moby('hide');
1340                });
1341            }
1342        }).moby('show', '#site-promo-modal');
1343    });
1344
1345    //new product tiles.. since we cant put an anchor inside an anchor we have to show the quickview using javascript :(
1346    if ($(".product-tile").length) {
1347        $(document).on("mouseenter mouseleave", ".product-tile .product-image, .product-tile .btn-quickview", function (e) {
1348            if (e.type === "mouseenter") {
1349                $(this).closest(".product-tile").find(".btn-quickview").addClass("show");
1350            } else {
1351                $(this).closest(".product-tile").find(".btn-quickview").removeClass("show");
1352            }
1353        });
1354    }
1355
1356    //animate labels to shrink and anchor to left corner to solve the placeholder texts always being visible ADA issue
1357    if (($anchorLabel = $(".input-wrapper .anchor-label")).length) {
1358        $anchorLabel.each(function() {
1359            var $input = $("#" + $(this).attr("for"));
1360            if ($input.length) {
1361                $input.on('focusin', function () {
1362                    $(this).closest(".input-wrapper").addClass("anchored");
1363                }).on('focusout', function () {
1364                    if (!$(this).val()) {
1365                        $(this).closest(".input-wrapper").removeClass("anchored");
1366                    }
1367                });
1368            }
1369        });
1370    }
1371
1372    $(document).on("click", "#auto-renew-container .auto-renew-link-no-si", function (e) {
1373        e.preventDefault();
1374
1375        $link = $(this);
1376        $link.attr('disabled', 'disabled');
1377
1378        var cust = $('#custnum').val();
1379        return AjaxJsonPostWrapper.ajaxRoute('account', 'toggleautorenewjsonnosi', { ar: $link.data("target"), cust: cust },
1380            function (result) { // success (ajax, business logic could still indicate issues)
1381                $("#auto-renew-container").html(result.html);
1382                $(".auto-renew-link").focus();
1383            },
1384            function () { // error (ajax)
1385                // console.log("error");
1386            },
1387            function () { // complete (ajax)
1388                $link.removeAttr('disabled');
1389            }
1390        );
1391    });
1392
1393    $(document).on("click", "#auto-renew-container .auto-renew-link", function (e) {
1394        e.preventDefault();
1395
1396        $link = $(this);
1397        $link.attr('disabled', 'disabled');
1398
1399        return AjaxJsonPostWrapper.ajaxRoute('account', 'toggleautorenewjson', { ar: $link.data("target") },
1400            function (result) { // success (ajax, business logic could still indicate issues)
1401                $("#auto-renew-container").html(result.html);
1402                $(".auto-renew-link").focus();
1403            },
1404            function () { // error (ajax)
1405                // console.log("error");
1406            },
1407            function () { // complete (ajax)
1408                $link.removeAttr('disabled');
1409            }
1410        );
1411    });
1412
1413    $(document).on("focus", ".styled-select", function (e) {
1414        $(this).closest(".select-wrap").find("span.customStyleSelectBox").first().addClass("psuedo-focus");
1415    });
1416
1417    $(document).on("blur", ".styled-select", function (e) {
1418        $(this).closest(".select-wrap").find("span.customStyleSelectBox").first().removeClass("psuedo-focus");
1419    });
1420
1421}(window.jQuery);
1422
1423//this function completely replaces tag names
1424(function ($) {
1425    $.fn.replaceTagName = function(replaceWith) {
1426        var tags =[],
1427            i    = this.length;
1428            while (i--) {
1429                var newElement = document.createElement(replaceWith),
1430                    thisi      = this[i],
1431                thisia     = thisi.attributes;
1432                for (var a = thisia.length -1; a >= 0; a--) {
1433                var attrib = thisia[a];
1434                newElement.setAttribute(attrib.name, attrib.value);
1435                };
1436            newElement.innerHTML = thisi.innerHTML;
1437            $(thisi).after(newElement).remove();
1438            tags[i]= newElement;
1439                }
1440        return $(tags);
1441    };
1442}) (window.jQuery);
1443
1444function updateNotifyMeEamil(address) {
1445    var boxes = [];
1446    $("input:checkbox[name=notifyMeBox]:checked").each(function () {
1447        boxes.push($(this).val());
1448    });
1449
1450    return AjaxJsonPostWrapper.ajaxRouteNonAsync('email', 'updatenotifymepreferences', { emailAddress: address, notifyMeBox: boxes }, function (result) {
1451        if(result != "") {
1452            $('#preferencesDiv').replaceWith(result.preferencesHtml);
1453            Gorilla.util.initForms();
1454            $('#notifyme-emails-modal-trigger').moby({
1455                'modalClass': 'email-preferences-modal',
1456                'ariaLabelText': 'Notify Me',
1457                'onCompleteCallback': function () {
1458                    $(".moby-close, .button.close").on('click', function (event) {
1459                        event.preventDefault();
1460                        $('#notifyme-emails-modal-trigger').moby('hide');
1461                    });
1462                }
1463            }).moby('show', '#notifyme-emails-modal');
1464        }
1465    });
1466}
1467/****************************** Wish List *******************************************/
1468function addToWishListFamily(id, promo, isSignedIn, colorCode, sizeCode) {
1469    // color code, size code, promo code, id, quantity
1470    var cartItem = { ID: id, PromoCode: promo, ColorCode: colorCode, SizeCode: sizeCode, Quantity: 1 };
1471
1472
1473    if (!isSignedIn) {
1474        Gorilla.util.setCookie('_wishlist-product-data', btoa(JSON.stringify(cartItem)));
1475        // if not signed in, send them off to sign-in/create account with their wish list as the final landing page (wish list will add the item from the cookie and trigger personalization if needed)
1476        window.location = "/authenticate/accountlogin?returnUrl=/wishlist/index"
1477    }
1478    else {
1479        // send them to their wish list (wish list will add the item from the cookie and trigger personalization if needed)
1480        window.location = "/wishlist/index";
1481    }
1482}
1483
1484function showClubBucksDialog(buck) {
1485    var scope = angular.element(document.getElementById('MyAccountClubBucksDialogController')).scope();
1486    scope.showDialog(buck);
1487}
1488
1489function setWishlistQuantityText() {
1490    var cookieValue = "0";
1491    var cookieData =
1492        decodeURIComponent(document.cookie
1493            .replace(new RegExp("(?:(?:^|.*;)\\s*" +
1494                encodeURIComponent("wlQty").replace(/[\-\.\+\*]/g, "\\$&") +
1495                "\\s*\\=\\s*([^;]*).*$)|^.*$"),
1496                "$1")) || null;
1497
1498    if (cookieData != null)
1499        cookieValue = cookieData;
1500
1501    $('#wishlistQtyText').text(cookieValue);
1502    if (cookieValue != null && cookieValue != "0") {
1503        $('#wishlistQtyText').show();
1504        $('#wishlistQtyLbl').show();
1505    } else {
1506        $('#wishlistQtyText').hide();
1507        $('#wishlistQtyLbl').hide();
1508    }
1509        
1510}
1511
1512function editPersonalization(entryId, isPersonalized) {
1513    AjaxJsonPostWrapper.ajaxRoute('wishlist', 'editpersonalization', { entryId: entryId, isPersonalized: isPersonalized }, function (result) {
1514        //handle personalize modal
1515        if (result.personalizeHtml) {
1516            if (result.personalizeHtml.substr(0, 10) == "embroidery") {
1517                document.location.href = "/wishlist/" + result.personalizeHtml;
1518            }
1519            else if (($personalizeTrigger = $('#personalize-trigger')).length &&
1520                     ($personalizeModal = $('#personalize-modal')).length) {
1521
1522                $personalizeModal.html(result.personalizeHtml);
1523                $personalizeTrigger.moby({
1524                    'modalClass': 'personalize-mod',
1525                    'ariaLabelText': 'Customize Item',
1526                    'onCompleteCallback': function () {
1527                        Gorilla.util.initForms();
1528                        $('#personalize-mod').validate();
1529                    }
1530                }).moby('show', '#personalize-modal');
1531            }
1532        }
1533    });
1534};
1535
1536function checkQtyLimit($form) {
1537    var limit = $form.find("#hdnPurchaseQtyLimit").val();
1538    if (limit === "0" || limit === "99") return false;
1539    setTimeout(function () {
1540        $form.find('#quantity').attr('type', 'number').attr('max', limit);
1541    }, 1000);
1542    if ($form.find("#ammoQtyLimit").length) {
1543        $form.find("#ammoQtyLimit").text(limit);
1544    } else {
1545        $form.find('.pdp-title-flex-container').first().after(
1546            '<div class="bold-text" style="color:#54565a;">* THIS ITEM HAS A LIMIT OF <span id="ammoQtyLimit">' +
1547                limit + '</span> PER ORDER.</div>');
1548    }
1549}
1550
1551function CartMoveToWishListAfterLogin(cartEntryId, inCheckout) {
1552
1553    // save form data to cookie 
1554    Gorilla.util.setCookie('_wishlist-ceid', btoa(JSON.stringify(cartEntryId)));
1555
1556    var returnUrl = inCheckout ? "/checkout" : "/cart/viewcart";
1557
1558    // if not signed in, send them off to sign-in/create account with their wish list as the final landing page (wish list will move the item from their cart to their now-available wishlist)
1559    window.location = "/authenticate/accountlogin?returnUrl=" + returnUrl;
1560    
1561}
1562
1563function CartMoveToWishListAsync(el, cartEntryId, inCheckout, inQuickOrder) {
1564
1565    var maxLimitReached = false;
1566    var success = false;
1567    moveToWishlistIndex = $(el).closest('tr:not(.restrictions-row)').prevAll().length + 1;
1568
1569    if (cartEntryId == null)
1570        return false;
1571
1572    $('.loading').show();
1573    AjaxJsonPostWrapper.ajaxRouteNonAsync('wishlist', 'movetowishlist', { entryId: cartEntryId }, function (response) {
1574        $('.loading').hide();
1575        // don't need to update main wish list display
1576        maxLimitReached = response.maxLimitReached;
1577        success = response.success;
1578        if (maxLimitReached) {
1579            $("#wish-limit-modal-trigger").moby({
1580                'modalClass': 'wish-limit-modal gradient-gray',
1581                'ariaLabelText': 'Full Wish List',
1582                'onCompleteCallback': function () {
1583                    $(".moby-close, .button.close").on('click', function (event) {
1584                        event.preventDefault();
1585                        $("#wish-limit-modal-trigger").moby('hide');
1586                    });
1587                }
1588            }).moby('show', '#wish-limit-modal');
1589        }
1590    });
1591
1592    if (!maxLimitReached && success) {
1593        // remove item from cart
1594        var action = inCheckout ? "updateqtyincheckout" : "updateqty";
1595        $('.loading').show();
1596        AjaxJsonPostWrapper.ajaxRouteNonAsync('cart', action, { entryId: cartEntryId, qty: 0, cqo: inQuickOrder }, function (result) {
1597            $('.loading').hide();
1598            if (inQuickOrder && result.cartQty < 1) {
1599                window.location.assign("/cart/catalogquickorder");
1600            }
1601            //update the main cart display
1602            else if (result.cartQty > 0) {
1603                if (result.cartHtml && result.cartHtml != "") {
1604                    $('#cartContainer').html(result.cartHtml);
1605                    $('#cartContainer').find($("img.lazy")).lazy();
1606                    $('#cartModifiedBtn').click();
1607                    Gorilla.util.initForms();
1608
1609                    if (!inCheckout) {
1610                        setCartQuantityText();
1611                    }
1612
1613                    // show message in modal
1614                    $("#wishlistmessage-modal").html("Item moved to Wish List");
1615                    $("#wishlistmessage-trigger").click();
1616
1617                }
1618            }
1619            else
1620                window.location.replace("/cart/viewcart");
1621        });
1622    }
1623    else if(!success) {
1624        $("#wishlistmessage-modal").html("Email address error. Please sign out and sign back in.");
1625        $("#wishlistmessage-trigger").click();
1626    }
1627}
1628
1629// the HandleCartMoveToWishListLogin needs to be called from "returnUrl" client-side script,
1630//  thus far it is just the Cart and the Payment pages that use this
1631function HandleCartMoveToWishListAfterLogin(inCheckout) {
1632    var cookie = Gorilla.util.getCookie("_wishlist-ceid");
1633    if (cookie != null) {
1634        $('.loading').show();
1635        AjaxJsonPostWrapper.ajaxRouteNonAsync('authenticate', 'issignedin', {}, function (response) {
1636            $('.loading').hide();
1637            //only move the item if they are signed in, if the didnt actually sign in and the come back to the cart page then just delete the cookie
1638            if (response.signedIn) { 
1639                var decodedData = atob(cookie);
1640                var data = JSON.parse(decodedData);
1641                Gorilla.util.deleteCookie("_wishlist-ceid");
1642
1643                CartMoveToWishListAsync(this, data, inCheckout, false);
1644            } else {
1645                Gorilla.util.deleteCookie("_wishlist-ceid");
1646            }
1647        });
1648    }  
1649
1650}
1651
1652
1653//ALL cart refreshes before checkout need to use this!!!
1654function updateShowMiniCart(html, showSlide) {
1655    if (html && html !== "") {
1656        setCartQuantityText();
1657        var $cartSummary = $("#cartSummary");
1658        setTimeout(function () {
1659            $cartSummary.empty().append(html);
1660            $("#mini-totals").empty().append($cartSummary.find(".mini-totals-container").detach());
1661
1662            var itemCount = $cartSummary.find(".items-in-cart").detach().text();
1663            var cartTotal = $("#mini-cart-total-preview").html();
1664            var cls = $("#mini-cart-total-preview").attr('class');
1665            $("#cart-mmenu").removeClass("mm-nomap").removeClass("mm-map").removeClass("mm-unset").removeClass("mm-noSavings");
1666            if (itemCount.length) {
1667                $("#cart-mmenu").addClass(cls);
1668                $("#mini-cart-total").html(cartTotal).show();
1669                $("#mini-count").empty().append(itemCount);
1670                $("#mini-cart-actions").show();
1671                $("#cart-mmenu .mm-navbars_top .mm-navbar").css("height", "");
1672                $("#cart-mmenu.mm-menu_navbar_top-1 .mm-panels").css("top", "");
1673            } else {
1674                $("#mini-cart-actions").hide();
1675                $("#cart-mmenu").addClass("mm-unset");
1676                $("#mini-count").text("0 items in your cart");
1677                $("#mini-cart-total").hide();
1678            }
1679        }, 500);
1680
1681        if (showSlide) {
1682            dropMiniCart();
1683        }
1684    }
1685}
1686
1687//ALL updates to the view cart container need to use this!!!
1688function updateCartContainer(html) {
1689    $('#cartContainer').replaceWith(html);
1690    $('#cartContainer').find($("img.lazy")).lazy();
1691    Gorilla.util.initForms();
1692    //need to refresh dynamic data on teh club spiff...
1693    //TODO since that no longer show/hides based on the cart or membership... this should be fixed to be static
1694    AjaxJsonPostWrapper.ajaxRoute('dynamicdata', 'getdata', { page: 'viewcart' }, function (result) {
1695        var $clubDd = $("club-dynamic-data");
1696        if (result.clubDd && $clubDd.length) {
1697            $("club-dynamic-data").replaceWith(result.clubDd);
1698        }
1699    });
1700}
1701
1702/****************************** Search SuggestAhead *******************************************/
1703function getSuggestAheadTerms(request, response) {
1704    var term = $('<div/>').text(request.term).html();
1705    $.ajax({
1706        type: "POST",
1707        url: window.location.protocol + "//" +window.location.host + "/main/suggestaheadsearchterms",
1708        async: true,
1709        data : JSON.stringify({ term: term }),
1710        contentType: 'application/json',
1711        traditional: true,
1712            success: function (result) {
1713            var fullTerms = result.suggestions.split('|');
1714            var uniqueKeys =[];
1715            $.each(fullTerms, function (i, el) {
1716                var str = el.trim();
1717                if ($.inArray(str, uniqueKeys) == -1) uniqueKeys.push(str);
1718            });
1719            $('#searchProducts').html(result.html);
1720            $itemContainer = $('#product-listing-container');
1721            $itemContainer.find("img.lazy").lazy({ delay: 0 });
1722            response(uniqueKeys);
1723        },
1724        error: function (XMLHttpRequest, textStatus, errorThrown) {
1725            var errId = XMLHttpRequest.getResponseHeader("System-Error-ID");
1726            var errIdMsg = "";
1727            if (errId != null) {
1728                errIdMsg = " [" + errId + "]"
1729            }
1730            console.log("An error occurred during ajax operation" + errIdMsg + ".") // mimics what has been "good enough" since redesign, circa 2014.  we don't really know what to do but probably don't want to interrupt the user
1731
1732            //if (error != undefined) {
1733            //    error(errorThrown);
1734            //}
1735            //else {
1736            //    Gorilla.util.messages.addMessage('Sorry, there was an error with your request. Please try again shortly.', 'error');
1737            //}
1738        }
1739    })
1740    .done(function (data) {
1741        if (data.errors) {
1742            onDataError(data);
1743        }
1744    });
1745}
1746
1747function getSuggestAheadTermsFocusCall(term) {
1748    var suggestions = term;
1749    $('#searchProducts').html("");
1750    AjaxJsonPostWrapper.ajaxRoute('main', 'suggestaheadsearchterms', { term: term }, function (result) {
1751        $('#searchProducts').html(result.html);
1752        $itemContainer = $('#product-listing-container');
1753        $itemContainer.find("img.lazy").lazy({ delay: 0 });
1754    });
1755    return suggestions;
1756}
1757
1758function myGetStackTrace() {
1759    var stackTrace = (function () {
1760        var ret = new Error("").stack; // doesn't seem to work in IE but faster in Chrome and FF
1761        if (ret == undefined || ret == "") // use the throw catch technique when needed
1762            try {
1763                throw new Error("");
1764            } catch (ex) {
1765                ret = ex.stack;
1766            }
1767        return ret;
1768    })();
1769
1770    var messages = stackTrace ? stackTrace.split("\n") : "";
1771    messages.splice(0, messages[0] == 'Error' ? 3 : 2); // removed the first 3 or 2 lines (FF doesn't start w/ "Error" line)
1772
1773    return messages.join("\n");
1774}
1775
1776// when an item in the suggested terms dropdown gets the focus/hover, call out and get products for that term
1777function getSuggestAheadTermsFocus(liID, label) {
1778    if ($("#" + liID).hasClass('ui-state-active')) { // used to be ui-state-focus in older version of jQuery
1779        getSuggestAheadTermsFocusCall(label);
1780    }
1781}
1782
1783// setup a custom override of the jquery-ui's _renderMenu function
1784$.widget("ui.autocomplete", $.ui.autocomplete, {
1785    options: {
1786        maxItems: 9999 // adds this maxItems property to the object and default to 9999, usually overridden during specific .autocomplete({ inits
1787    },
1788    _renderMenu: function (ul, items) { // override jQuery-Ui's _renderMenu so we can make use of the maxItems as needed
1789        var that = this;
1790        $.each(items, function (index, item) { // google says this goes in order that they appear in the DOM
1791            if (index < that.options.maxItems) {
1792                that._renderItemData(ul, item);
1793            }
1794        });
1795    }
1796});
1797
1798function validateEU(input) {
1799    return !/(\.(ad|at|be|bg|hr|cy|cz|dk|ee|fi|fr|de|gr|gp|va|hu|ie|im|it|lv|lt|lu|mt|mq|mc|nl|pl|pt|ro|sk|si|es|bl|mf|se|gb|uk|eu))$/i.test(input);
1800}
1801
1802/****************************** Truncate ad copy*******************************************/
1803
1804function truncateQuickViewAdCopy(quickViewForm) {
1805    var overflowMaxHeight = 400;
1806    var productDesc = quickViewForm.find('.product-description'),
1807        productMore = quickViewForm.find('#quickViewMoreDetails');
1808    truncateElementTextToHeight(productDesc, overflowMaxHeight);
1809    productMore.detach().appendTo(productDesc.children().last());
1810}
1811
1812function truncateElementTextToHeight(elem, overflowMaxHeight) {
1813    if (elem.height() > overflowMaxHeight) {
1814        do {
1815            var lastChild = elem.children().last();
1816            if ((lastChild.is('ul')) && (lastChild.children().length > 0)) {
1817                lastChild.children().last().remove();
1818                if (lastChild.children().length == 0) {
1819                    lastChild.remove();
1820                }
1821            }
1822            else {
1823                var text = elem.html();
1824                text = text.slice(0, text.lastIndexOf(" "));
1825                elem.html(text);
1826            }
1827        } while (elem.height() > overflowMaxHeight);
1828    }
1829}
1830
1831/****************************** Bloomreach Related Product Quick View Image Swap *******************************************/
1832
1833function swapBRRelProdImage(anchor) {
1834    var $id = anchor.href.substr(anchor.href.lastIndexOf('#')+1);
1835    var $div = $("div[id=" + $id + "]");
1836    var $img = $div.find('img.brRelProd');
1837    if ($img.length) {
1838        $img.attr("src", $img.attr("data-br-src").replace("/m/", "/e/"));
1839    }
1840    $div.find("#alternate-images img").each(function () {
1841        $(this).attr("src", $(this).attr("data-br-src").replace("/m/", "/e/"));
1842    });
1843}
1844
1845/* This function will report if an element is in the current viewport */
1846function isElementInViewport(el) {
1847    if (typeof jQuery === "function" && el instanceof jQuery) {
1848        el = el[0];
1849    }
1850
1851    var rect = el.getBoundingClientRect();
1852
1853    return (
1854        rect.top >= 0 &&
1855        rect.left >= 0 &&
1856        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
1857        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
1858    );
1859}
1860
1861/* This function will find the largest height and width of a set of elements and resize them accordingly */
1862function resizeElms(els) {
1863    var $els = $(els);
1864    if ($els.length) {
1865        var height = getMaxHeight($els);
1866        var width = getMaxWidth($els);
1867        $els.each(function () {
1868            $(this).height(height);
1869            $(this).width(width);
1870        });
1871    }
1872}
1873function resizeSelectionGroup(els) {
1874    var $els = $(els);
1875    var height = getMaxHeight($els);
1876    var width = getMaxWidth($els);
1877    $els.each(function () {
1878        $(this).width(width);
1879        $(this).height(height);
1880        $(this).css('line-height', height + 'px');
1881    });
1882}
1883function getMaxWidth(els) {
1884    return Math.max.apply(Math,
1885        $(els).map(function () {
1886         return $(this).width();
1887    }).get());
1888}
1889function getMaxHeight(els) {
1890    return Math.max.apply(Math,
1891        $(els).map(function () {
1892            return $(this).height();
1893        }).get());
1894}
1895
1896//equivalent to IsNullOrWhiteSpace server side
1897function isNullOrWhiteSpace(input) {
1898    if (typeof input === 'undefined' || input == null) return true;
1899    return input.replace(/\s/g, '').length < 1;
1900}
1901
1902// get query string parameter by name
1903function getParameterByName(name, url) {
1904    if (!url) {
1905        url = window.location.href;
1906    }
1907    name = name.replace(/[\[\]]/g, "\\$&");
1908    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
1909        results = regex.exec(url);
1910    if (!results) return null;
1911    if (!results[2]) return '';
1912    return decodeURIComponent(results[2].replace(/\+/g, " "));
1913}
1914
1915function dropMiniCart() {
1916    //close the quickview slideout if its open
1917    if ($("#quickview-mmenu").length && $("#quickview-mmenu").hasClass("mm-menu_opened")) {
1918        $("#quickview-mmenu").data("mmenu").close();
1919        if (lastFocus) {
1920            lastFocus.focus();
1921        }
1922    }
1923    
1924    $quickorderAdd = $("#quickorder-add");
1925    if (!$quickorderAdd.length)
1926        setTimeout(function() {
1927            $("#cart-mmenu").data("mmenu").open();
1928            trapFocus($("#cart-mmenu"));
1929            $("#cart-mmenu").on("click", ".mm-navbars_top", function (e) {
1930                $("#cart-mmenu").data("mmenu").close();
1931            });
1932        }, 500);
1933}
1934
1935
1936
1937// validates social security number
1938// method looks for SS1, SS2 and SS3
1939// SSN cannot be all the same digit or 123456789
1940function adsICSSNValidation() {
1941    if ($('#SS1').val() && $('#SS2').val() && $('#SS3').val())
1942    {
1943        var SSN = $('#SS1').val() + $('#SS2').val() + $('#SS3').val();
1944        return /^(?!\b(\d)\1+\b)(?!123456789|012345678)\d{9}$/.test(SSN);
1945
1946    }
1947    return true;
1948}
1949
1950// validates age, must be at least 18 years of age
1951// method looks for DOBDay, DOBMonth and DOBYear
1952function adsICDOBValidation() {
1953    if ($('#DOBDay').val() && $('#DOBMonth').val() && $('#DOBYear').val()) {
1954        var day = $('#DOBDay').val();
1955        var month = $('#DOBMonth').val();
1956        var year = $('#DOBYear').val();
1957        var requiredAge = 18;
1958
1959        var dob = new Date(year, month - 1, day);
1960        var today = new Date();
1961        var mindob = new Date(today.getFullYear() - 18, today.getMonth(), today.getDate());
1962        return mindob >= dob;
1963    }
1964    return true;
1965}
1966
1967// validates phone number, must be 10 digits long
1968// method looks for PhoneNumber1, PhoneNumber2, PhoneNumber3
1969// phone number cannot be all the same digit or incrementing numbers, and must be 10 digits
1970function adsICPhoneValidation() {
1971    if ($('#PhoneNum1').val() && $('#PhoneNum2').val() && $('#PhoneNum3').val()) {
1972        var phone = $('#PhoneNum1').val() + $('#PhoneNum2').val() + $('#PhoneNum3').val();
1973        return /^(?!\b(\d)\1+\b)(?!1234567890|0123456789)\d{10}$/.test(phone);
1974    }
1975    return true;
1976}
1977function adsICPhoneAltValidation() {
1978    if ($('#AltNum1').val() || $('#AltNum2').val() || $('#AltNum3').val()) {
1979        var phone = $('#AltNum1').val() + $('#AltNum2').val() + $('#AltNum3').val();
1980        return /^(?!\b(\d)\1+\b)(?!1234567890|0123456789)\d{10}$/.test(phone);
1981    }
1982    return true;
1983}
1984
1985// checkout payment - validate if a customer can use their new ADS credit card
1986// or are they over their credit limit?
1987function adsCanUseCard(creditlimit) {
1988    if ($('#CCType').val() == "L" && creditlimit != 0 && $('#GrandTotal').val() != 0 && (Number(creditlimit) < Number($('#GrandTotal').val())))
1989    {
1990        return false;
1991    }
1992    return true;
1993}
1994
1995function populateTealiumAjaxScript(script) {
1996    var div = $('#tealiumAjax');
1997    div.empty();
1998    div.append(script);
1999}
2000
2001function addItemToCartFamilyGroup(itemId, promoCode, color, size, qty, fgItem, fgPromo, fgOfferID, fromTable) {
2002    var cartItem = { ID: itemId, PromoCode: promoCode, ColorCode: color, SizeCode: size, Quantity: qty, FreeGiftItemId: fgItem, FreeGiftPromoCode: fgPromo, FreeGiftOfferID: fgOfferID, FromTable: fromTable };
2003    return AjaxJsonPostWrapper.ajaxRoute('cart', 'addtocart', { data: cartItem }, function (result) {
2004        if (result.cartMax == true) {
2005            $("#cart-limit-modal-trigger").moby({
2006                'modalClass': 'cart-limit-modal gradient-gray',
2007                'ariaLabelText': 'Full Cart',
2008                'onCompleteCallback': function () {
2009                    $(".moby-close").on('click', function (event) {
2010                        event.preventDefault();
2011                        $("#cart-limit-modal-trigger").moby('hide');
2012                    });
2013                }
2014            }).moby('show', '#cart-limit-modal');
2015        }
2016        else {
2017            updateShowMiniCart(result.miniCartHtml, true);
2018            populateTealiumAjaxScript(result.tealium);
2019            if (result.freeGiftHtml) {
2020                if (($giftTrigger = $('#freegift-trigger')).length && ($giftModal = $('#freegift-modal')).length) {
2021                //init the modal and set the Html from the response, since Moby requires an anchor we're triggering a click on the hidden anchor
2022                    $giftModal.html(result.freeGiftHtml);
2023                    $giftTrigger.moby({
2024                        'modalClass': 'free-gift',
2025                        'ariaLabelText': 'Free Gift',
2026                        'bodyClose': false,
2027                        'keyActions': false,
2028                        'onCompleteCallback': function () {
2029                            Gorilla.util.initForms();
2030                            $(".moby-close").hide();
2031                            $('#free-gift').validate();
2032                        }
2033                    }).moby('show', '#freegift-modal');
2034                }
2035            }
2036        }
2037        
2038    });
2039}
2040
2041//4 payplan consent modal... called from AccountFourPayList.. no longer used in checkout
2042function showPayplanConsent() {
2043    var $trigger = $('#payplan-consent-modal-trigger');
2044    if ($trigger != null)
2045    {
2046        var $ppForm = $('#payplan-consent');
2047
2048        $trigger.moby({
2049            'modalClass': 'payplan-consent-modal',
2050            'ariaLabelText': '4-Pay',
2051            'onCompleteCallback': function () {
2052                Gorilla.util.initForms();
2053                $ppForm.validate();
2054
2055                $('.button.yes').on('click', function (event) {
2056                    event.preventDefault();
2057                    if ($ppForm.valid()) {
2058                        var orderNumber = $("#ConsentOrderNumber").val();
2059                        var phoneNumber = $("#ConsentPhone").val();
2060                        AjaxJsonPostWrapper.ajaxRouteNonAsync('account', 'editorderconsentphone', { order : orderNumber, phone : phoneNumber },
2061                            function (formattedPhone) {
2062                                $('li[data-order="' + orderNumber + '"] div span').text(formattedPhone);
2063                            }
2064                        );
2065
2066                        $trigger.moby('hide');
2067                    }
2068                });
2069
2070                $('a.close').on('click', function (event) {
2071                    event.preventDefault();
2072                    $ppForm.resetForm();
2073                    $trigger.moby('hide');
2074                });
2075            }
2076        }).moby('show', '#payplan-consent-modal');
2077    }
2078}
2079
2080function initQtyButtons(containerName)
2081{
2082    if (($container = $(containerName)).length)
2083    {
2084        setTimeout(function () {
2085            $(".qty-adjust", $container).click(function (e) {
2086                e.preventDefault();
2087
2088                var $this = $(this);
2089                var $form = $this.closest("form");
2090                var $qty = $("#quantity", $form);
2091                var qty = $qty.val();
2092
2093                // manage new version (button w/ enhanced ADA) vs old version (div no ADA)
2094                if ($this.prop("tagName").toLowerCase() === "button") { // new approach
2095                    if ($this.data("direction") == "plus" && qty < 99) {
2096                        qty++;
2097                    } else if ($this.data("direction") == "minus" && qty > 1) {
2098                        qty--;
2099                    }
2100                } else { // old approach, should go away after PDP A/B test is complete and everything is rolled over to new version
2101                    if ($this.text() == "+" && qty < 99) {
2102                        qty++;
2103                    } else if ($this.text() == "-" && qty > 1) {
2104                        qty--;
2105                    }
2106                }
2107
2108                // safety / default
2109                if (!$.isNumeric(qty) || qty < 1) {
2110                    qty = 1;
2111                }
2112
2113                $qty.val(qty);
2114                $form.validate().element($qty);
2115            });
2116        }, 1000);
2117    }
2118}
2119
2120function initFitRating(containerName, currentValue)
2121{
2122    if (($container = $(containerName)).length) {
2123        if (($fitRating = $("#BVFitRating", $container)).length) {
2124            $fitRating.slider({
2125                range: "max",
2126                min: 1,
2127                max: 5,
2128                step: 0.01,
2129                value: currentValue,
2130                disabled: true,
2131                create: function (event, ui) {
2132                    setSliderTicks(event.target);
2133                }
2134            });
2135        }
2136    }
2137}
2138
2139function initWidthRating(containerName, currentValue)
2140{
2141    if (($container = $(containerName)).length) {
2142        if (($widthRating = $("#BVWidthRating", $container)).length) {
2143            $widthRating.slider({
2144                range: "max",
2145                min: 1,
2146                max: 3,
2147                step: 0.1,
2148                value: currentValue,
2149                disabled: true,
2150                create: function (event, ui) {
2151                    setSliderTicks(event.target);
2152                }
2153            });
2154        }
2155    }
2156}
2157
2158//auto selects the only option in the size/color dropdowns
2159//function initAutoSelect(form) {
2160//    var $form = $(form);
2161//    processSelectedProductOption($form.find('.auto-select'));
2162//}
2163
2164function searchFaq(searchTerm) 
2165{
2166    // *** this function depends on the structure of the markup, if that changes this may stop working
2167    // most accordions are nested, some are not...
2168    // search the questions and answers together so we don't accidentally hide just one of the pair
2169
2170    $("#faqSearchCounts:visible").hide();
2171
2172    $(".sg-accordion-header").fadeIn(); // show them all
2173    $(".sg-accordion-header").removeClass("active");
2174    $(".sg-accordion-content").slideUp();
2175
2176    searchTerm = $.trim(searchTerm);
2177    if (searchTerm === "") {
2178        return; // bail out
2179    }
2180
2181    searchTerm = searchTerm.replace(/[']/ig, "");
2182    safeSearchTerm = jQuery.ui.autocomplete.escapeRegex(searchTerm); // escape any special characters that could affect regex; unofficial, per http://stackoverflow.com/questions/5306095/simple-jquery-javascript-method-to-escape-special-characters-in-string-for-reg
2183    var regexSearchTerm = new RegExp(safeSearchTerm, "i");
2184
2185    $("h2.sg-accordion-header").each(function () { // process each category
2186        var $thisHeader = $(this);
2187        var $thisContent = $thisHeader.next(".sg-accordion-content");
2188
2189
2190        if (searchQuestionAndAnswer(regexSearchTerm, $thisHeader, $())) { // check the category text first and skip children if found, assume they all apply
2191            $thisHeader.removeClass("hidden-header").fadeIn();
2192            $(".sg-accordion-header", $thisContent).removeClass("hidden-header").fadeIn(); // show all children
2193        } else {
2194            var foundText = false;
2195            if (($children = $thisContent.find(".sg-accordion-header")).length) {
2196                // nested ones, at this time they only contain one or more accordions, not a mix of accordions and content, not further nested accordions
2197                var childrenShowing = 0;
2198                $children.each(function () { // process each question
2199                    var $childHeader = $(this);
2200                    var $childContent = $childHeader.next(".sg-accordion-content");
2201
2202                    foundText = searchQuestionAndAnswer(regexSearchTerm, $childHeader, $childContent);
2203                    showOrHide(foundText, $childHeader, $childContent);
2204
2205                    if (foundText)
2206                        childrenShowing++;
2207                });
2208
2209                showOrHide(childrenShowing > 0, $thisHeader, $thisContent); // hide parent if all children are hidden
2210
2211            } else {
2212                // does not contain a nested accordion
2213                // just check the content, we already checked the category text and didn't find it
2214                foundText = searchQuestionAndAnswer(regexSearchTerm, $(), $thisContent)
2215                showOrHide(foundText, $thisHeader, $thisContent);
2216            }
2217        }
2218    });
2219
2220    var categoryCount = 0;
2221    var questionCount = 0;
2222
2223    // animation messes with the native :visible, i put my own "hidden-header" class on the elements to get around that
2224    if ((categoryCount = $("h2.sg-accordion-header:not(.hidden-header)").length) === 0) { // if none are not .hidden-header, then no data found
2225        $("#faqSearchCounts").html("No results found").show();
2226    } else {
2227        questionCount = $(".sg-accordion-content h3.sg-accordion-header:not(.hidden-header)").length
2228        $("#faqSearchCounts").html(questionCount + " FAQs found in " +categoryCount + " categories").show();
2229    }
2230
2231    // record a couple of things to provide direction when FAQ content is revisted
2232    var data = {
2233        faqSearchInput: searchTerm,
2234        foundCategoryCount: categoryCount,
2235        foundQuestionCount: questionCount
2236    };
2237    AjaxJsonPostWrapper.ajaxRoute('customerservice', 'searchfaqs', data, function (response) { }); // don't need to do anything with any returned information
2238
2239}
2240
2241function searchQuestionAndAnswer(regexSearchTerm, $header, $content) {
2242    return ($header.text().search(regexSearchTerm) >= 0) || ($content.text().search(regexSearchTerm) >= 0);
2243}
2244
2245function showOrHide(shouldShow, $header, $content) {
2246    if (shouldShow) {
2247        $header.removeClass("hidden-header");
2248        $header.fadeIn();
2249        // $content.fadeIn(); // this expands the accordion and kinda messes up their state
2250    } else {
2251        $header.addClass("hidden-header");
2252        $header.hide();
2253        $content.hide();
2254    }
2255}
2256
2257function initToolTips() { //lazy-load tool tips on demand.. but not the fake ones (ffl lookup)
2258    $(document).on("click mouseover", "button.tool-tip:not(.not-really)", function (e) {
2259        e.preventDefault();
2260        var $tip = $(this);
2261        if (!$tip.data('isSet')) {
2262            $tip.tipsy({
2263                bounds: $('body'),
2264                //show method not publicly exposed... re-fire the event to show the tip after its wired up
2265                afterInitCallback: function() {
2266                    if ($(window).width() > 960) { $tip.trigger('click'); }
2267                }
2268            });
2269        }
2270    });
2271}
2272
2273
2274// if they click / tap on a slider in mobile this should be used to take
2275//  care of any underlying link / anchor
2276// used during click: function, sister function to swipe: function
2277function sliderTap(event, target) {
2278    switch ($(target).get(0).tagName.toLowerCase()) {
2279        case "a":
2280            document.location.href = target;
2281            break;
2282        case "img":
2283            // this only goes up one level, obviously...
2284            var p = $(target).parent();
2285            if (p.get(0).tagName.toLowerCase() == "a") {
2286                document.location.href = p.attr("href");
2287            }
2288            break;
2289    }
2290}
2291
2292function hookUpQuickViews(el) {
2293    if (matchMedia('(min-width: 961px)').matches) {
2294        $(el).find(".btn-quickview > button:not(.bound961)").each(function () {
2295            $(this).removeClass("bound");
2296            $(this).parent().removeClass("hide-quick-view");
2297            $(this).off("click");
2298            $(this).addClass("bound961");
2299
2300            hookupQuickviewAda($(this));
2301
2302            //Bloomreach Related Products
2303            $(this).find("[href$='#brqv']").on("click", function () {
2304                swapBRRelProdImage($(this));
2305            });
2306
2307            $(this).moby({
2308                'modalClass': 'quickview',
2309                'ariaLabelText': 'Quick View',
2310                'onCompleteCallback': function (e) {
2311
2312                    var $form = $(e).find('form');
2313                    if ($form.length === 0) { // fix latent bug - seems like related products quickview's e is "window" and .find from there doesn't pick up the QV form...
2314                        $form = $(".moby-container.quickview.show").find('form');
2315                    }
2316                    
2317                    validateAndInitQuickViewForm($form);
2318                    autoselectAttributeIfSingle($(".attribute-select", $form).first());
2319                }
2320            });
2321        });
2322
2323        $(el).find(".btn-quickview > button:not(.bound961)").each(function () {
2324            $(this).removeClass("bound");
2325            $(this).parent().removeClass("hide-quick-view");
2326            $(this).off("click");
2327            $(this).addClass("bound961");
2328
2329            hookupQuickviewAda($(this));
2330
2331            //Bloomreach Related Products
2332            $(this).find("[href$='#brqv']").on("click", function () {
2333                swapBRRelProdImage($(this));
2334            });
2335
2336            $(this).moby({
2337                'modalClass': 'quickview',
2338                'ariaLabelText': 'Quick View',
2339                'onCompleteCallback': function (e) {
2340
2341                    var $form = $(e).find('form');
2342                    if ($form.length === 0) { // fix latent bug - seems like related products quickview's e is "window" and .find from there doesn't pick up the QV form...
2343                        $form = $(".moby-container.quickview.show").find('form');
2344                    }
2345
2346                    validateAndInitQuickViewForm($form);
2347                    autoselectAttributeIfSingle($(".attribute-select", $form).first());
2348                }
2349            });
2350        });
2351
2352        $(el).find(".add-on-quickview:not(.bound961)").each(function () {
2353            $(this).removeClass("bound");
2354            $(this).off("click");
2355            $(this).addClass("bound961");
2356            $(this).moby({
2357                'modalClass': 'quickview',
2358                'ariaLabelText': 'Quick View',
2359                'onCompleteCallback': function (e) {
2360
2361                    var $form = $(e).find('form');
2362                    if ($form.length === 0) { // fix latent bug - seems like related products quickview's e is "window" and .find from there doesn't pick up the QV form...
2363                        $form = $(".moby-container.quickview.show").find('form');
2364                    }
2365
2366                    validateAndInitQuickViewForm($form);
2367                    autoselectAttributeIfSingle($(".attribute-select", $form).first());
2368                }
2369            });
2370        });
2371    }
2372    else {
2373        $(el).find(".btn-quickview > button:not(.bound)").each(function () {
2374            $(this).removeClass("bound961");
2375            $(this).off("click");
2376            $(this).parent().removeClass("hide-quick-view");
2377            $(this).addClass("bound");
2378
2379            hookupQuickviewAda($(this));
2380
2381            if ($(this).attr("href").indexOf("#brqv") >= 0) { //Bloomreach Related Products
2382                $(this).on("click", function (e) {
2383                    e.preventDefault();
2384                    var $divId = $(this).attr("href").substr($(this).attr("href").lastIndexOf('#') + 1);
2385                    var $brQVDiv = $("div[id=" + $divId + "]");
2386                    var $brQVImg = $brQVDiv.find('img.brRelProd');
2387                    if ($brQVImg.length) {
2388                        $brQVImg.attr('src', $brQVImg.attr('src').replace("/m/", "/e/"));
2389                    }
2390                    $("#quickview-mmenu .quickview").html($brQVDiv.html());
2391                    $("#quickview-mmenu").data("mmenu").open();
2392                    trapFocus($("#quickview-mmenu"));
2393                    validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
2394                    return false;
2395                });
2396            }
2397            else {
2398                $(this).on("click", function (e) {
2399                    e.preventDefault();
2400                    $.ajax({
2401                        url: $(this).attr('href'),
2402                        type: 'GET',
2403                        datatype: "html",
2404                        success: function (result) {
2405                            $("#quickview-mmenu .quickview").html(result);
2406                            $("#quickview-mmenu").data("mmenu").open();
2407                            validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
2408                        }
2409                    });
2410                    return false;
2411                });
2412            }
2413        });
2414
2415        $(el).find(".btn-quickview > button:not(.bound)").each(function () {
2416            $(this).removeClass("bound961");
2417            $(this).off("click");
2418            $(this).parent().removeClass("hide-quick-view");
2419            $(this).addClass("bound");
2420
2421            hookupQuickviewAda($(this));
2422
2423            if ($(this).attr("href").indexOf("#brqv") >= 0) { //Bloomreach Related Products
2424                $(this).on("click", function (e) {
2425                    e.preventDefault();
2426                    var $divId = $(this).attr("href").substr($(this).attr("href").lastIndexOf('#') + 1);
2427                    var $brQVDiv = $("div[id=" + $divId + "]");
2428                    var $brQVImg = $brQVDiv.find('img.brRelProd');
2429                    if ($brQVImg.length) {
2430                        $brQVImg.attr('src', $brQVImg.attr('src').replace("/m/", "/e/"));
2431                    }
2432                    $("#quickview-mmenu .quickview").html($brQVDiv.html());
2433                    $("#quickview-mmenu").data("mmenu").open();
2434                    trapFocus($("#quickview-mmenu"));
2435                    validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
2436                    return false;
2437                });
2438            }
2439            else {
2440                $(this).on("click", function (e) {
2441                    e.preventDefault();
2442                    $.ajax({
2443                        url: $(this).attr('href'),
2444                        type: 'GET',
2445                        datatype: "html",
2446                        success: function (result) {
2447                            $("#quickview-mmenu .quickview").html(result);
2448                            $("#quickview-mmenu").data("mmenu").open();
2449                            validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
2450                        }
2451                    });
2452                    return false;
2453                });
2454            }
2455        });
2456
2457        $(el).find(".add-on-quickview:not(.bound)").each(function () {
2458            $(this).removeClass("bound961");
2459            $(this).off("click");
2460            $(this).addClass("bound");
2461            $(this).on("click", function (e) {
2462                e.preventDefault();
2463                $.ajax({
2464                    url: $(this).attr('href'),
2465                    type: 'GET',
2466                    datatype: "html",
2467                    success: function (result) {
2468                        $("#quickview-mmenu .quickview").html(result);
2469                        $("#quickview-mmenu").data("mmenu").open();
2470                        validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
2471                    }
2472                });
2473                return false;
2474            });
2475        });
2476    }
2477}
2478
2479function hookupQuickviewAda(el) {
2480    var $this = $(el);
2481
2482    //ada compliance...if the quickview has focus make it visible
2483    $this.on('focusin', function () {
2484        $(this).parent().addClass("show");
2485    }).on('focusout', function () {
2486        $(this).parent().removeClass("show");
2487    });
2488
2489    //ada compliance... hide all tab focused quick views when mousing over the parent anchor
2490    //this helps prevent a sticky quick view button
2491    $this.closest(".product-image").on("mouseover", function () {
2492        $("body").find(".products-grid .btn-quickview > button:visible").trigger("blur");
2493    });
2494
2495}
2496
2497function validateAndInitQuickViewForm(quickViewForm) {
2498    truncateQuickViewAdCopy(quickViewForm);
2499    quickViewForm.validate();
2500
2501    //register Notify Me Modal trigger in case quick view is of a product on notify
2502    quickViewForm.find('.notifyBtn').find("a").moby({
2503        'modalClass': 'giveaway-modal',
2504        'ariaLabelText': 'Notify Me',
2505        'onCompleteCallback': function () {
2506        }
2507    });
2508    Gorilla.util.initForms();
2509}
2510
2511//this function will de-parameterize a multi-value cookie to easily be able to retrieve a specific value
2512function deparamCookie(params) {
2513    var o = {};
2514    if (!params) return o;
2515    var a = params.split('&');
2516    for (var i = 0; i < a.length; i++) {
2517        var pair = a[i].split('=');
2518        o[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
2519    }
2520    return o;
2521}
2522
2523//this function retrives a query string parameter value
2524function getQueryStringParam(name) {
2525    var url = window.location.href;
2526    name = name.replace(/[\[\]]/g, "\\$&");
2527    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
2528        results = regex.exec(url);
2529    if (!results) return null;
2530    if (!results[2]) return '';
2531    return decodeURIComponent(results[2].replace(/\+/g, " "));
2532}
2533
2534//javascript format currency
2535function formatCurrency(value, locale, currency) {
2536    var formatter = new Intl.NumberFormat(locale,
2537        {
2538            style: 'currency',
2539            currency: currency,
2540            minimumFractionDigits: 2
2541        });
2542
2543    return formatter.format(value);
2544}
2545
2546function padLeft(num, size) { //mimics c#'s string.PadLeft
2547    var s = num + "";
2548    while (s.length < size) s = "0" + s;
2549    return s;
2550}
2551
2552function trapFocus(element) {
2553    var focusableEls =
2554            element.find(
2555                'a[href], button:not(.magic-thumbs-button-disabled,[tabindex="-1"],.i18n), textarea, input[type="button"], input[type="text"], input[type="radio"], input[type="checkbox"], select, [tabindex]:not([tabindex="-1"])'),
2556        firstFocusableEl = focusableEls.first()[0],
2557        lastFocusableEl = focusableEls.last()[0],
2558        TABKEYCODE = 9,
2559        ARROWLEFTCODE = 37,
2560        ARROWUPCODE = 38,
2561        ARROWRIGHTCODE = 39,
2562        ARROWDOWNCODE = 40;
2563
2564    if (firstFocusableEl != null) { firstFocusableEl.focus(); }
2565
2566    $(element).off('keydown').on('keydown', function (e) {
2567        // tab (no shift) or the right/down keys
2568        var next = e.key === 'ArrowRight' || e.keyCode === ARROWRIGHTCODE || e.key === 'ArrowDown' || e.keyCode === ARROWDOWNCODE || ((e.key === 'Tab' || e.keyCode === TABKEYCODE) && !e.shiftKey);
2569        // tab (with shift) or the left/up keys
2570        var prev = e.key === 'ArrowLeft' || e.keyCode === ARROWLEFTCODE || e.keyCode === 'ArrowUp' || e.keyCode === ARROWUPCODE || ((e.key === 'Tab' || e.keyCode === TABKEYCODE) && e.shiftKey);
2571
2572        if (!next && !prev) {
2573            return;
2574        }
2575
2576        if (next && document.activeElement === lastFocusableEl) {
2577            firstFocusableEl.focus();
2578            e.preventDefault();
2579        }
2580        if (prev && document.activeElement === firstFocusableEl) {
2581            lastFocusableEl.focus();
2582            e.preventDefault();
2583        }
2584    });
2585}
2586
2587function initSGAccordian(openByDefault) {
2588    // wire up events
2589    $(document).on("click", ".sg-accordion-header", function () {
2590        $this = $(this);
2591        $this.toggleClass("active");
2592        $this.next().slideToggle(250); // the very next element had better be the content...
2593
2594        if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
2595            $button.attr("aria-expanded", $this.hasClass("active")); // A360/ADA -- set aria-expanded as appropriate
2596        }
2597    });
2598
2599    $(document).on("click", "#accordion-controls-container #expand-all", function () {
2600        $(".sg-accordion-header").each(function (i, v) { // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
2601            $this = $(this);
2602            $this.addClass("active");
2603
2604            if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
2605                $button.attr("aria-expanded", true);
2606            }
2607        });
2608
2609        $(".sg-accordion-content").slideDown();
2610    });
2611
2612    $(document).on("click", "#accordion-controls-container #collapse-all", function () {
2613        $(".sg-accordion-header").each(function (i, v) { // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
2614            $this = $(this);
2615            $this.removeClass("active");
2616
2617            if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
2618                $button.attr("aria-expanded", false);
2619            }
2620        });
2621        $(".sg-accordion-content").slideUp();
2622    });
2623
2624    if (openByDefault) {
2625        // have all panels open by default
2626        $(".sg-accordion-header").addClass("active"); // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
2627        $(".sg-accordion-content").show(); // need it fast! // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
2628    }
2629
2630    // deal with some FAQ's specific A360/ADA things... Seems like this could be applied to all instances of our .sg-accordion-header, but limiting to the FAQs for now
2631    $("#faqsV3 .sg-accordion-header").each(function (i, v) {
2632        var $this = $(this);
2633        var $next = $this.next(); // the very next element had better be the content...
2634
2635        // generate and assign an id to the associated content block, if needed
2636        var nextId = $next.attr("id");
2637        if (nextId == undefined) {
2638            nextId = "sgac-" + i;
2639            $next.attr("id", nextId);
2640        }
2641
2642        // add the aria- stuff to $this
2643        if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
2644            $button.attr("aria-expanded", $this.hasClass("active"));
2645            $button.attr("aria-controls", nextId);
2646        }
2647    });
2648}
2649
2650function processSlickProductSliders() {
2651    workSlickProductSliders++;
2652    if (workSlickProductSliders == numSlickProductSliders) {
2653        $(document).find(".btn-quickview > button").each(function () {
2654            $(this).removeClass("bound");
2655            $(this).removeClass("bound961");
2656        });
2657        initResponsive();
2658        workSlickProductSliders = 0;
2659    }
2660}
2661
2662//Gift card functions on shopping resources and my account
2663function addAccountGiftCard(cardNum) {
2664    AjaxJsonPostWrapper.ajaxRoute("giftcard", "GiftCardAddToAccount", { cardNum: cardNum },
2665        function (result) {
2666            $("#gift-card-lookup-tables").html(result.giftCardLookupHtml);
2667        });
2668}
2669function removeAccountGiftCard(cardNum) {
2670    AjaxJsonPostWrapper.ajaxRoute("giftcard", "giftcardremovefromaccount", { cardNum: cardNum },
2671        function (result) {
2672            $("#gift-card-lookup-tables").html(result.giftCardLookupHtml);
2673        });
2674}
2675
2676function textInputDigitsOnly(keyCode) { // call from within a keypress (not key down) event, maxlength not enforced here, use html attribute
2677
2678    if (keyCode == 8 || keyCode == 127) { // backspace, delete, probably don't make it here but let them work if they do
2679        return true;
2680    }
2681
2682    if (keyCode >= 48 && keyCode <= 57) { // numbers
2683        return true;
2684    }     
2685
2686    return false; // don't allow keystroke to register
2687
2688}
2689
2690function enableTabIndicators(e) {
2691    if (e.keyCode === 9) { // keyboard tabber detected!
2692        document.body.classList.add('user-tab-detected');
2693        window.removeEventListener('keydown', enableTabIndicators);
2694    }
2695}
2696
2697window.addEventListener('keydown', enableTabIndicators);
2698
2699function setLeftNavActiveLinkProps() {
2700    $("#left-navigation li.active a").each(function (i, v) { // had better be one and only one.  if not, last one wins
2701        var $activeAnchor = $(this);
2702        $activeAnchor.attr("aria-current", "page");
2703        $activeAnchor.closest("aside#left-navigation").attr("aria-label", $activeAnchor.text() + " navigation"); // I asked / double-checked that this should be "page name" vs. "layout name" and A360 was pretty adamant
2704    });
2705}
2706
2707function hide2ndImageOnPDP() {
2708    $("#main-image.MagicZoom figure div.mz-lens img").addClass("display-none");
2709}
2710
2711//focus on first focusable element in the main page container
2712function focusOnFirstEl(container) {
2713    $(container).find(":focusable").first().focus();
2714}
2715
2716function autoselectAttributeIfSingle($ddl) {
2717
2718    if ($ddl.length === 0 || $ddl.hasClass("auto-select"))
2719        return;
2720
2721    var $opts = $("option", $ddl);
2722    if ($opts.length === 2) { // "Select an Option" + 1 value
2723        $opts.prop("selected", false); // unset them all
2724        $($opts[1]).prop("selected", "selected"); // make the first one selected
2725        $ddl.change(); // trigger the change event
2726    }
2727}
2728
2729//this sends the user straight through to the address page if called on or before bridge page
2730function initPayPalCheckout() {
2731
2732    var pp = new PayPal();
2733    pp.onPayPalSet = function (pp) {
2734        if (pp.payload.details.countryCode !== "US" || pp.payload.details.shippingAddress.countryCode !== "US") {
2735            $("#paypal-messages").html("PayPal is not currently available for customers outside the US.");
2736            return false;
2737        }
2738
2739        var ppData = {
2740            Email: pp.payload.details.email,
2741            PayerId: undefined, //let backend look it up
2742            Nonce: pp.payload.nonce,
2743            DeviceData: pp.deviceData
2744        }
2745
2746        var address = {
2747            FirstName: pp.payload.details.firstName,
2748            LastName: pp.payload.details.lastName,
2749            EmailAddress: pp.payload.details.email,
2750            Address1: pp.payload.details.shippingAddress.line1,
2751            Address2: pp.payload.details.shippingAddress.line2,
2752            City: pp.payload.details.shippingAddress.city,
2753            State: pp.payload.details.shippingAddress.state,
2754            Zip: pp.payload.details.shippingAddress.postalCode,
2755            Country: pp.payload.details.shippingAddress.countryCode,
2756            DayPhone: pp.payload.details.phone
2757        }
2758
2759        if (address.State && address.State.length > 2) {
2760            var self = this;
2761            self.logError("PayPal Value Error - State too Large - Email: " + address.EmailAddress +  " - State: " + address.State + " - City: " + address.City);
2762            address.State = "";
2763        }
2764
2765        return AjaxJsonPostWrapper.ajaxRoute("authenticate", "paypalcheckoutlogin", { PayPal: ppData, Address: address}, function(result) {
2766            if (result.success) {
2767                //todo just go to /checkout after a/b test is done
2768                return window.location.replace("/checkout");
2769            } else {
2770                $("#paypal-messages").html("We are unable to accept PayPal at this time. Please try again or use one of our other checkout methods.");
2771                return false;
2772            }
2773        });
2774    };
2775
2776}
2777
2778function initializeSlider(id) { // used to be in DynamicDataScript.cshmlt but we want to use it in angularized ViewCart as well
2779    //Init default sliders, use data api to set items count and margins
2780    if (($slider = $(id + ' .products-grid')).length) {
2781        if (!$slider.hasClass('slick-initialized')) {
2782            $slider.slick({
2783                accessibility: true,
2784                dots: false,
2785                arrows: true,
2786                slidesToShow: 4,
2787                slidesToScroll: 4,
2788                infinite: false,
2789                lazyLoad: 'ondemand',
2790                prevArrow: '<span class="sg-slick-prev" role="button" aria-label="Previous" tabindex="0">
2790 <img class="sg-carousel" src="/images/product/icon-image-left.svg"> </span>',
2791                nextArrow: '<span class="sg-slick-next" role="button" aria-label="Next" tabindex="0"> <img class="sg-carousel" src="/images/product/icon-image-right.svg"> </span>',
2792                responsive: [
2793                    {
2794                        breakpoint: 1060,
2795                        settings: {
2796                            slidesToShow: 3,
2797                            slidesToScroll: 3,
2798                            arrows: true,
2799                            dots: true
2800                        }
2801                    },
2802                    {
2803                        breakpoint: 768,
2804                        settings: {
2805                            slidesToShow: 2,
2806                            slidesToScroll: 2,
2807                            arrows: true,
2808                            dots: true
2809                        }
2810                    },
2811                    {
2812                        breakpoint: 480,
2813                        settings: {
2814                            slidesToShow: 1,
2815                            slidesToScroll: 1,
2816                            arrows: true,
2817                            dots: true
2818                        }
2819                    }
2820                ]
2821            });
2822            numSlickProductSliders++;
2823            $slider.on("breakpoint", function (event, slick, breakpoint) {
2824                event.preventDefault();
2825                processSlickProductSliders();
2826            });
2827        }
2828    }
2829}
2830
2831function submitArticleRating(stars, id) {
2832    return AjaxJsonPostWrapper.ajaxRoute('blogapi', 'ratearticle', { starRating: stars, webPageId: id }, function (result) {
2833        $(".article-ratings-input").hide();
2834        $(".article-ratings-title").html("<span>Thank you for rating this article.</span>");
2835    });
2836};
2837var altImagesSlider;
2838var $altImagesChangeSlider = false;
2839var $initClubAccordions = true;
2840var $initFooterLinksAccordion = true;
2841var promoCarouselTimeout;
2842var numSlickProductSliders = 0;
2843var workSlickProductSliders = 0;
2844var initMyAccountBackLink = true;
2845var lastFocus;
2846
2847domReady(function() {
2848    // Readied
2849    var w = $(window).width();
2850    initResponsive();
2851
2852    var resizeHandler = function () {
2853        $(window).on("resize", function () {
2854            if (w != $(window).width()) {
2855                initResponsive();
2856                w = $(window).width();
2857                delete w;
2858            }
2859        });
2860    }
2861    //we were losing the resize event listener using $(window).resize due to an mmenu collision
2862    $(function () {
2863        window.addEventListener('resize', resizeHandler, false);
2864    });
2865});
2866
2867function initResponsive() {
2868
2869    //fix for back button issue with mobile menu in IE... IE doesnt support the library's use of window.history.back()
2870    //this is unbound then bound as the menu can be created/destroyed based on breakpoint shifts
2871    var closeEvent = function () {
2872        if (($currentMenu = $('.mm-menu.mm-current.mm-menu_opened')).length) {
2873            $currentMenu.data("mmenu").close();
2874            lastFocus.focus();
2875        }
2876    }
2877    $(document).off("click", "a.mm-btn, a.mm-title", closeEvent).on("click", "a.mm-btn, a.mm-title", closeEvent);
2878
2879    if (matchMedia('(min-width:961px)').matches) {
2880        //Large screens, full menu
2881        $('.shop').find('.fly-out').html("<h4><span>Loading...</span></h4>");
2882        $('.shop').find('.fly-out').addClass('auto-height');
2883    }
2884
2885    if (matchMedia('(min-width: 961px)').matches) {
2886        //site wide promo message banner
2887        if ($('#site-wide-promos').length) {
2888            destroySiteWidePromoSlickSlider();
2889        }
2890    } else {
2891        //site wide promo message carousel
2892        if ($('#site-wide-promos').length) {
2893            createSiteWidePromoSlickSlider();
2894        }
2895    }
2896
2897    if (matchMedia('(min-width: 961px)').matches) {
2898        //reset the nav cover, may have been manipulated if they went down to mobile and then back up to desktop
2899        $(".nav-cover-x").toggleClass("nav-cover nav-cover-x");
2900
2901        if ($("#mm-nav").length) { //destroy mobile controls if orientation changed
2902            $("#mm-nav").gorillaAccordion('unset');
2903            $("#mm-nav").find('.drop-down').gorillaAccordion('unset');
2904            destroyMmenu();
2905        }
2906
2907        if (($nav = $('#nav')).length) {
2908            //init main nav
2909            if (!$nav.attr("data-dropit")) {
2910                $nav.DropIt({
2911                    'triggerSelector': 'li.level-top',
2912                    'menuSelector': '.drop-down',
2913                    'speed': 0,
2914                    'delay': 0,
2915                    'showCover': true
2916                });
2917            }
2918
2919            if (!$nav.find('.shop ul.level0').attr('data-dropit')) {
2920                $nav.find('.shop ul.level0').DropIt({
2921                    'triggerSelector': '> li',
2922                    'menuSelector': '.fly-out',
2923                    'speed': 0,
2924                    'delay': 200,
2925                    'onHover': function (elm) {
2926                        var $this = $(elm),
2927                            busy = false;
2928
2929                        if (busy || $this.data('loaded')) {
2930                            return;
2931                        }
2932
2933                        $.ajax({
2934                                url: $this.data('menu'),
2935                                type: 'post',
2936                                dataType: 'html',
2937                                beforeSend: function () {
2938                                    busy = true
2939                                }
2940                            })
2941                            .done(function (html) {
2942                                $this.find('> a').after(html).end().data('loaded', true);
2943                                $nav.find('ul.level0').DropIt('showMenu', $this.find('.fly-out'));
2944                            })
2945                            .always(function () {
2946                                busy = false;
2947                            })
2948                    }
2949                });
2950            }
2951        }
2952        //Quick View
2953        
2954        hookUpQuickViews(document);
2955
2956        //footer accordion unset
2957        if (($accordion = $('#footer').find('.accordion')).length) {
2958            $accordion.gorillaAccordion('unset');
2959        }
2960        $initFooterLinksAccordion = true;
2961
2962        $('body').removeClass('mobileVideo');
2963
2964    } else {
2965        
2966        //mobile navigation init
2967        if (($nav = $('#nav')).length) {
2968            $nav.DropIt('unset');
2969            $nav.find('ul.level0').DropIt('unset');
2970        }
2971
2972        //remove the nav cover if they ever hit this breakpoint, it can cause an issue with a tablet in landscape mode
2973        $(".nav-cover").hide().toggleClass("nav-cover nav-cover-x");
2974
2975        //mobile splash nav menu (for gift guide template)
2976        if (($splashNav = $("#splashNav")).length) {
2977            $("#splashNav-toggle").on("click", function (e) {
2978                e.preventDefault();
2979                lastFocus = document.activeElement;
2980                $splashNav.data("mmenu").open();
2981            });
2982            $splashNav.mmenu({
2983                extensions: ["pagedim-black", "position-right", "position-front", "theme-white"],
2984                backButton: { close: false },
2985                navbar: { title: "" }, //needed to hide the default title menu
2986                navbars: [{ position: "top", content: "<a class='mm-title' href='#' onclick='event.preventDefault();'>Menu</a><a class='mm-btn' href='#' onclick='event.preventDefault();' role='button'><span class='mmenu-close'></span><span class='sr-only'>close menu</span></a>" }],
2987                onClick: { close: false, setSelected: false },
2988                slidingSubmenus: false
2989            },{
2990                //configuration
2991                offCanvas: {
2992                    pageSelector: "#sg-page-wrapper"
2993                }
2994                });
2995            $("#splashNav-toggle").on("click", ".mm-navbars_top", function (e) {
2996                $("#splashNav-toggle").data("mmenu").close();
2997                lastFocus.focus();
2998            });
2999        }
3000
3001        //filter nav dropdown init
3002        if ($("#mm-filters-menu").length === 0) {
3003            if (($filters = $('aside.filters:not(.noMobileDisplay)')).length) {
3004                $("#filter-toggle").on("click", function (e) {
3005                    e.preventDefault();
3006                    lastFocus = document.activeElement;
3007                    $("#mm-filters-menu").data("mmenu").open();
3008                });
3009                $filters.mmenu({
3010                    extensions: ["pagedim-black", "position-right", "position-front", "theme-white"],
3011                    backButton: { close: false },
3012                    navbar: { title: "" }, //needed to hide the default title menu
3013                    navbars: [
3014                        {
3015                            position: "top",
3016                            content: "<a class='mm-title' href='#' onclick='event.preventDefault();'>Filter</a><a class='mm-btn' href='#' onclick='event.preventDefault();' role='button'><span class='mmenu-close'></span><span class='sr-only'>close menu</span></a>"
3017                        }
3018                    ],
3019                    onClick: { close: false, setSelected: false },
3020                    slidingSubmenus: false
3021                },
3022                {
3023                    //configuration
3024                    clone: true,
3025                    offCanvas: {
3026                        pageSelector: "#sg-page-wrapper"
3027                    }
3028                
3029                }).on("init", function () {
3030                    //we dont want nested elements to be submenus in this particular panel
3031                    $("#mm-filters-menu").find('ol.mm-listview').removeClass('mm-listview');
3032                    $("#mm-filters-menu").find('ul.mm-listview').removeClass('mm-listview');
3033                    
3034                    // the menu gets cloned with new mm- id's for the filter checkboxes, we need to manually adjust the (invisible, used by screen readers/WAVE extension) labels
3035                    $("#mm-filters-menu label[for^=dimSelected]").attr("for", function (i, val) { return "mm-" + val; });
3036
3037                    }).trigger("init");
3038                $("#mm-filters-menu").on("click", ".mm-navbars_top", function (e) {
3039                    $("#mm-filters-menu").data("mmenu").close();
3040                    lastFocus.focus();
3041                });
3042
3043                if (($accordion = $('#mm-filters-menu').find('.dim-accordion')).length) {
3044                    $accordion.gorillaAccordion({
3045                        trigger: 'a.trigger',
3046                        container: '.content',
3047                        containerInner: '> ul'
3048                    });
3049                }
3050
3051                //same idea as in ProductList.cshtml onReady: ensure the auto opened facet accordions are properly init'd
3052                $("#mm-filters-menu .dim-accordion a.open").each(function () {
3053                    var $this = $(this);
3054                    $this.closest(".dim-accordion").gorillaAccordion('open', $this);
3055                });
3056            }
3057        }
3058        
3059        //footer accordion init
3060        if (($accordion = $('#footer').find('.accordion')).length) {
3061            if ($initFooterLinksAccordion) {
3062                $accordion.gorillaAccordion({
3063                    trigger: 'h2',
3064                    container: '.content',
3065                    containerInner: '> ul'
3066                });
3067                $initFooterLinksAccordion = false;
3068            }
3069        }
3070
3071        //filter nav dropdown init
3072        if ($("#mm-left-navigation").length === 0) {
3073            if (($leftMenu = $('#left-navigation')).length) {
3074                $("#col-left-menu-toggle").on("click", function (e) {
3075                    e.preventDefault();
3076                    lastFocus = document.activeElement;
3077                    $("#mm-left-navigation").data("mmenu").open();
3078                    trapFocus($("#mm-left-navigation"));
3079                });
3080                $leftMenu.mmenu({
3081                    extensions: ["pagedim-black", "position-right", "position-front", "theme-white"],
3082                    backButton: { close: false },
3083                    navbar: { title: "" }, //needed to hide the default title menu
3084                    navbars: [{ position: "top", content: "<a class='mm-title' href='#' onclick='event.preventDefault();'>Menu</a><a class='mm-btn' href='#' onclick='event.preventDefault();' role='button'><span class='mmenu-close'></span><span class='sr-only'>close menu</span></a>" }],
3085                    onClick: { close: false, setSelected: false },
3086                    slidingSubmenus: false
3087                }, {
3088                    //configuration
3089                    clone: true,
3090                    offCanvas: {
3091                        pageSelector: "#sg-page-wrapper"
3092                    }
3093                    });
3094                $("#mm-left-navigation").on("click", ".mm-navbars_top", function (e) {
3095                    $("#mm-left-navigation").data("mmenu").close();
3096                    lastFocus.focus();
3097                });
3098            }
3099        }
3100        
3101        $(".btn-quickview").find("button").each(function () {
3102            $(this).parent().removeClass("hide-quick-view");
3103            if ($(this).moby.length) {
3104                $(this).moby('reset');
3105            }
3106        });
3107
3108        //rebind quickview to mmenu slideout
3109        if (($quickviewSlideout = $("#quickview-mmenu")).length) {
3110            hookUpQuickViews(document);
3111
3112            $quickviewSlideout.mmenu({
3113                extensions: ["pagedim-black", "position-right", "position-front", "theme-white"],
3114                backButton: { close: false },
3115                navbar: { title: "" }, //needed to hide the default title menu
3116                navbars: [{ position: "top", content: "<a class='mm-title' href='#' onclick='event.preventDefault();'>Close</a><a class='mm-btn' href='#' onclick='event.preventDefault();' role='button'><span class='mmenu-close'></span><span class='sr-only'>
3116close menu</span></a>" }],
3117                onClick: { close: false, setSelected: false },
3118                slidingSubmenus: false
3119            }, {
3120                //configuration
3121                offCanvas: {
3122                    pageSelector: "#sg-page-wrapper"
3123                }
3124                });
3125            $("#quickview-mmenu").on("click", ".mm-navbars_top", function (e) {
3126                $("#quickview-mmenu").data("mmenu").close();
3127                lastFocus.focus();
3128            });
3129        }
3130
3131        $('body').addClass('mobileVideo');
3132
3133        // init new sticky back link in My Account area
3134        if (($myAccountBackLink = $('.my-account-back-to')).length && initMyAccountBackLink) {
3135            initBackToMyAccount($myAccountBackLink);
3136        }
3137    }
3138
3139    if (matchMedia('(min-width: 731px) and (max-width: 960px)').matches) {
3140
3141    }
3142    if (matchMedia('(min-width: 480px) and (max-width: 730px)').matches) {
3143        $('body').removeClass('mobile');
3144    }
3145
3146    if (matchMedia('(min-width: 480px) and (max-width: 560px)').matches) {
3147        $('body').removeClass('mobile');
3148    }
3149
3150    if (matchMedia('(min-width: 300px) and (max-width: 479px)').matches) {
3151        $('body').addClass('mobile');
3152    }
3153
3154    if (matchMedia('(max-width: 680px)').matches) {
3155
3156        bindMobileSearch();
3157        //we may have an issue with events being bound multiple times with the dynamic data stuff calling initResponsive again
3158        $(document).off("click", "#search-trigger").on("click", "#search-trigger", function (e) {
3159            e.preventDefault();
3160            var $searchDiv = $(".site-search.mobile-search");
3161            var $searchIcon = $(".mobile-trigger.search .search-icon");
3162            var $searchInput = $(".site-search.mobile-search .input-text")
3163            if ($searchDiv.hasClass("closed")) {
3164                $searchDiv.slideToggle("fast").removeClass("closed").addClass("open");
3165                $searchIcon.addClass("open");
3166                $searchInput.focus();
3167            } else if ($searchDiv.hasClass("open")) {
3168                $searchDiv.slideToggle("fast").removeClass("open").addClass("closed");
3169                $searchIcon.removeClass("open");
3170                $searchInput.blur();
3171            }
3172        });
3173
3174        $(".site-header .nav-container div.secondary").removeClass("header-flex-parent");
3175
3176        $('#main').find('.cms-main [data-respond], .my-account-main [data-respond]').each(function() {
3177            var $_el = $(this);
3178            switch ($_el.data('respond')) {
3179                case 'accordion':
3180                    $_el.addClass('accordion').gorillaAccordion({
3181                        trigger: '.trigger',
3182                        container: '.content',
3183                        containerInner: '> .inner'
3184                    });
3185                    break;
3186            }
3187        });
3188
3189        $('#in-stock-mobile').each(function () {
3190            this.style.setProperty('display', 'inline', 'important');
3191            this.style.setProperty('font-size', '18px');
3192        });
3193
3194        $("#tabs").exploder({
3195            container: "#Details",
3196            elements: ".inner-wrap",
3197            buttonIndex: 0,
3198            buttonText: "Read More"
3199        });
3200
3201        $('#main').find('.family-group').each(function () {
3202            var $_mfh = $(this).find('.mobileFgHeader');
3203            $(this).find('.colorswatches').insertAfter($_mfh);
3204        });
3205
3206    } else {
3207        $(".site-header .nav-container div.secondary").addClass("header-flex-parent");
3208
3209        $('#main').find('.cms-main [data-respond], .my-account-main [data-respond]').each(function () {
3210            var $_el = $(this);
3211            switch ($_el.data('respond')) {
3212                case 'accordion':
3213                    $_el.removeClass('accordion').gorillaAccordion('unset');
3214                    break;
3215            }
3216        });
3217
3218        $("#tabs").exploder('unset');
3219
3220        $('#main').find('.family-group').each(function () {
3221            var $_fgi = $(this).find('.family-group-image');
3222            $(this).find('.colorswatches').appendTo($_fgi);
3223        });
3224    }
3225
3226    if (matchMedia('(min-width: 681px)').matches) {
3227        //mobile search to default state for shifting breakpoints
3228        $(".site-search.mobile-search").removeClass("open").addClass("closed").attr("style", "");
3229        $(".mobile-trigger.search .search-icon").removeClass("open");
3230    }
3231
3232    if (matchMedia('(max-width: 960px)').matches) {
3233        if ($("#main-scroll-images").length && $("#main-scroll-horizontal .slick-slide").length == 0) {
3234            if (!$altImagesChangeSlider) {
3235                $altImagesChangeSlider = true;
3236                createHorizontalProductImages();
3237                scrollToSelectedProductImage();
3238                setTimeout(function () {
3239                    $altImagesChangeSlider = false;
3240                }, 10);
3241            }
3242        }
3243    }
3244
3245    if (matchMedia('(min-width: 681px) and (max-width: 960px)').matches) {
3246        bindTabletSearch();
3247    }
3248
3249    if (matchMedia('(min-width:961px)').matches) {
3250
3251        bindDesktopSearch();
3252
3253        if ($("#main-scroll-images").length && $("#main-scroll-vertical .slick-slide").length == 0) {
3254            if (!$altImagesChangeSlider) {
3255                $altImagesChangeSlider = true;
3256                createVerticalProductImages();
3257                scrollToSelectedProductImage();
3258                setTimeout(function () {
3259                    $altImagesChangeSlider = false;
3260                }, 10);
3261            }
3262        }
3263    }
3264
3265    if ($(".product-list .products-grid").length) setEqualHeightPlp();
3266    
3267}
3268
3269function setEqualHeightPlp() {
3270    const items = Array.from(document.querySelectorAll(".product-list .products-grid > .product-tile"));
3271    const baseOffset = items[0].offsetTop;
3272    const breakIndex = items.findIndex(function (item) { return item.offsetTop > baseOffset; });
3273    const chunk = (breakIndex === -1 ? items.length : breakIndex);
3274
3275    if (chunk === 1) {
3276        $(items).find('.product-name, .price-box, .rating-box, .starting-at').css({ 'min-height': '0' });
3277        return false;
3278    }
3279
3280    const subsets = [];
3281    for (var i = 0; i < items.length; i += chunk) {
3282        subsets.push(items.slice(i, i + chunk));
3283    }
3284
3285    return subsets.forEach(function (subset) {
3286        const $subset = $(subset);
3287        const newHeight = Math.max.apply(null, $subset.find(".new").map(function () { return $(this).height(); }).get());
3288        const nameHeight = Math.max.apply(null, $subset.find(".product-name").map(function () { return $(this).height(); }).get());
3289        const priceHeight = Math.max.apply(null, $subset.find(".price-box").map(function () { return $(this).height(); }).get());
3290        const startingAt = Math.max.apply(null, $subset.find(".starting-at").map(function () { return $(this).height(); }).get());
3291
3292        $subset.find(".new").css({ "min-height": newHeight });
3293        $subset.find(".product-name").css({ "min-height": nameHeight });
3294        $subset.find(".price-box").css({ "min-height": priceHeight });
3295        $subset.find(".starting-at").css({ "min-height": startingAt });
3296    });
3297}
3298
3299function getUniqueKeys(request, response)
3300{
3301    var escapeTerm = $('<div/>').text(request.term).html();
3302    var fullSuggestAhead = getSuggestAheadTerms(escapeTerm);
3303    var fullTerms = fullSuggestAhead.split('|');
3304    var uniqueKeys = [];
3305    $.each(fullTerms, function (i, el) {
3306        var str = el.trim();
3307        if ($.inArray(str, uniqueKeys) == -1) uniqueKeys.push(str);
3308    });
3309    return uniqueKeys;
3310}
3311
3312function highlightSearchedTerm($elem)
3313{
3314    var acData = $elem.data('ui-autocomplete');
3315    acData.menu.element.find('li').each(function () {
3316        var container = $("div", $(this)); // ui-autocomplete now has a div inside the li wrapping the words
3317        var keywords = acData.term.split(' ').join('|');
3318        container.html(container.html().replace(new RegExp("(" + keywords + ")", "gi"), '<span class="highlight">$1</span>'));
3319    });
3320}
3321
3322function destroySlider() {
3323    if (altImagesSlider != undefined && altImagesSlider != null) {
3324        altImagesSlider.destroySlider();
3325    }
3326}
3327
3328function destroyMmenu() {
3329    $("div#mm-nav").remove();
3330    $("aside#mm-filters-menu").remove();
3331    $("div#mm-left-navigation").remove();
3332
3333    $("#filter-toggle").off("click");
3334    $("#col-left-menu-toggle").off("click");
3335}
3336
3337function createSiteWidePromoSlickSlider() {
3338    var $ss = $("#site-wide-promos");
3339    if (!$ss.hasClass('slick-initialized') && !$ss.hasClass("checkout-promo")) { 
3340        $ss.slick({
3341            slidesToShow: 1,
3342            slidesToScroll: 1,
3343            dots: true,
3344            appendDots: $('#promoBannerDots'),
3345            arrows: false,
3346            infinite: true,
3347            autoplay: true,
3348            autoplaySpeed: 5000
3349        });
3350    }
3351}
3352
3353function destroySiteWidePromoSlickSlider() {
3354    var $ss = $("#site-wide-promos");
3355    if ($ss.hasClass('slick-initialized')) {
3356        $ss.slick('unslick');
3357    }
3358}
3359
3360function bindMobileSearch() {
3361    var $searchMobile = $("#searchMobile");
3362    if ($searchMobile.data("ui-autocomplete") != undefined) {
3363        $searchMobile.autocomplete("destroy");
3364    }
3365
3366    $searchMobile.autocomplete({
3367        appendTo: "#searchSuggestionsMobile",
3368        source: function (request, response) {
3369            getSuggestAheadTerms(request, response);
3370        },
3371        minLength: 3,
3372        delay: 200,
3373        maxItems: 5,
3374
3375        select: function (event, ui) {
3376            $searchMobile.val(ui.item.label);
3377            $("#mobilekform").submit();
3378        },
3379
3380        open: function (event, ui) {
3381            highlightSearchedTerm($(this));
3382        }
3383    });
3384}
3385
3386function bindTabletSearch() {
3387    if ($("#k").data("ui-autocomplete") != undefined) {
3388        $("#k").autocomplete("destroy");
3389    }
3390
3391    $("#k").autocomplete({
3392        appendTo: "#searchSuggestions",
3393        source: function (request, response) {
3394            getSuggestAheadTerms(request, response);
3395        },
3396        minLength: 3,
3397        delay: 200,
3398        maxItems: 10,
3399
3400        select: function (event, ui) {
3401            $("#k").val(ui.item.label);
3402            $("#kform").submit();
3403        },
3404
3405        open: function (event, ui) {
3406            highlightSearchedTerm($(this));
3407        },
3408    });
3409}
3410
3411function bindDesktopSearch() {
3412    if ($("#k").data("ui-autocomplete") != undefined) {
3413        $("#k").autocomplete("destroy");
3414    }
3415
3416    $("#k").autocomplete({
3417        appendTo: "#searchSuggestions",
3418        source: function (request, response) {
3419            getSuggestAheadTerms(request, response);
3420        },
3421        minLength: 3,
3422        delay: 200,
3423        maxItems: 10,
3424
3425        response: function (event, ui) {
3426            $("#searchProducts").css({ display: 'block' });
3427        },
3428
3429        select: function (event, ui) {
3430            $("#k").val(ui.item.label);
3431
3432            $("#kform").submit();
3433        },
3434
3435        close: function (event, ui) {
3436            event.preventDefault();
3437        },
3438
3439        focus: function (event, ui) {
3440
3441        },
3442
3443        open: function (event, ui) {
3444            highlightSearchedTerm($(this));
3445        }
3446    });
3447
3448}
3449
3450function showHideSuggestAhead() {
3451    setTimeout(function () {
3452        if ($("#searchProducts :focus").length === 0) {
3453            $("#searchProducts").css({ display: 'none' });
3454        }
3455    }, 200);
3456}
3457
3458function initBackToMyAccount($myAccountBackLink) {
3459    // calc the scrollPoint amount in case link is at different spots on various pages
3460    // my location - 90px ("within 14px" of the header, per spec -- happens to be exactly where the words end up, so it feels "locked in")
3461    var spXY = $myAccountBackLink.offset();
3462    var sp = spXY.top - 90;
3463    $myAccountBackLink.headtacular({ scrollPoint: sp })
3464    // MIGHT NEED TO ENHANCE THE headtacular PLUGIN TO ALLOW UNSET-ING,
3465    //  if we care about that it's left enabled after they go from a small window to a large window
3466    // per Steve, at this time we don't
3467
3468    initMyAccountBackLink = false; // only want to hook up to the scroll event one time
3469};
3470//Notify Me Modal
3471//$('.notifyBtn').find("a").moby({
3472//    //'modalClass': 'giveaway-modal notifyMeModal',
3473//    'ariaLabelText': 'Notify Me',
3474//    'bodyClose': true,
3475//    'keyActions': true,
3476//    'onCompleteCallback': function () {
3477//        setTimeout(function () {
3478//            trapFocus($(".notifyMeModal"));
3479//        }, 500);
3480//    },
3481//    'onBeforeCloseCallback': function () {
3482//        //$('.moby-container.notifyMeModal').removeClass('notifyMeModalSubmit');
3483//        //$('.moby-container.notifyMeModal .moby-close img').remove();
3484//    }
3485//});
3486
3487//****************************product functions***********************************
3488        
3489//get's all forms from within an element that has the class sent in the wrapperClass param
3490//then serializes each form into a ProductBase and builds up an array of all of them and submits
3491function addItemsToCart(wrapperClass) {
3492    var myArray = [];
3493    $('.' + wrapperClass).find('form').each(function () {
3494        var myData = AjaxJsonPostWrapper.getFormData(this);
3495        myArray.push(myData);
3496    });
3497    return AjaxJsonPostWrapper.ajaxRoute('cart', 'addtocart', { data: myArray }, function (result) {
3498        var itemsAdded = false;
3499
3500        for (var i = result.inventoryInfo.length - 1; i > -1;  i--) {
3501            var item = result.inventoryInfo[i];
3502            if (item.SellAction != 'X' && item.SellAction != 'N')
3503            {
3504                //remove the div associated with this item as it was added to the cart.
3505                $('#quickOrderItems').find('form')[i].remove();
3506                itemsAdded = true;
3507            }
3508        }
3509        if (itemsAdded == true) //then display cart drop down
3510        {
3511            updateCartSummary();
3512            var div = $('#tealiumAjax');
3513            if (typeof div !== 'undefined') {
3514                div.empty();
3515                div.append(result.tealium);
3516            }
3517        }
3518        if (result.alertMsg != "")
3519            alert(result.alertMsg);
3520    });
3521}
3522
3523function addItemToCart(btn) {
3524    var myArray = []; //create an array, although we are only going to pass one item in it
3525    var myData = AjaxJsonPostWrapper.getFormData($(btn).closest('form'));
3526    myArray.push(myData);
3527    doAddToCartSingleItem(myArray);
3528}
3529
3530function addItemToCartCustom(itemId, promoCode, color, size, qty, personalize, description) {
3531    //TODO: Figure out how to serialize this data into a Json object of list<productbase> so we can send it in through the existing code
3532    var cartItem = { ID: itemId, PromoCode: promoCode, ColorCode: color, SizeCode: size, Quantity: qty, IsPersonalized: personalize };
3533    var myArray = []; //create an array, although we are only going to pass one item in it
3534    myArray.push(cartItem);
3535    doAddToCartSingleItem(myArray);
3536}
3537
3538function doAddToCartSingleItem(data) {
3539    return AjaxJsonPostWrapper.ajaxRoute('cart', 'addtocart', { data: data }, function (result) {
3540        if (result.inventoryInfo[0].SellAction == "N")
3541            notifyMe(data.ID, data.PromoCode, data.Name);
3542        else if (result.inventoryInfo[0].SellAction == "X")
3543            alert(result.inventoryInfo[0].Message);
3544        else {
3545            if (result.inventoryInfo[0].Message != "In Stock")
3546                alert(result.inventoryInfo[0].Message);
3547            $(window).scrollTop(0);
3548            updateCartSummary();
3549            var div = $('#tealiumAjax');
3550            if (typeof div !== 'undefined') {
3551                div.empty();
3552                div.append(result.tealium);
3553            }
3554        }
3555    });
3556}
3557
3558function getNextProductOption(dd, updateField, clearWaist, clearSize, clearColor) {
3559    var $form = $(dd).closest('form');
3560    //clear out any of the other drop downs below it
3561    if (clearWaist) {
3562        $form.find('#WaistCode').val("");
3563        $form.find('#WaistCode').prop('disabled', true);
3564        $form.find('#WaistCode').customSelect('updateText');
3565    }
3566    if (clearSize) {
3567        $form.find('#SizeCode').val("");
3568        $form.find('#SizeCode').prop('disabled', true);
3569        $form.find('#SizeCode').customSelect('updateText');
3570    }
3571    if (clearColor) {
3572        $form.find('#ColorCode').val("");
3573        $form.find('#ColorCode').prop('disabled', true);
3574        $form.find('#ColorCode').customSelect('updateText');
3575    }
3576    //reset buttons in case they had been modified
3577    $form.find('.addToCartButtonDiv').show();
3578    $form.find('.notifyMeButtonDiv').hide();
3579
3580    if ($form.hasClass("quickview-form")) {
3581        $form.find('.stock-note').text(" ");
3582    } else { 
3583        $('.stock-note').text(" ");
3584    }
3585
3586    var itemId = $form.find('input[id=ID]').val();
3587
3588    var prodDefData = getProductDefaultData(itemId);
3589
3590    checkCompanionProducts($(dd), $form);
3591
3592    if (dd.value != "") {
3593        var data = AjaxJsonPostWrapper.getFormData($form);
3594
3595        return AjaxJsonPostWrapper.ajaxRoute('product', 'getproductoption', { option: data, prodDefault: prodDefData },
3596            function (result) {
3597                updatePriceBlockHtml($form, result.main, result.sticky);
3598                toggleCustomizationBox($form, "YES", 0);
3599                toggleDropShipMessage($form, prodDefData.IsDropShip, prodDefData.IsDropShip);
3600                //set the js variables that hold the arrays of values for the selected value (these will only really contain data when it is returnign the last drop down selection list)
3601                prices[itemId] = result.product.Prices;
3602                clubPrices[itemId] = result.product.ClubPrices;
3603                expectDates[itemId] = result.product.ExpectDates;
3604                sellActions[itemId] = result.product.SellActions;
3605                clubDiscounts[itemId] = result.product.ClubDiscounts;
3606                comparePrices[itemId] = result.product.ComparePrices;
3607                wasPrices[itemId] = result.product.WasPrices;
3608                embroideryFlags[itemId] = result.product.EmbroideryFlags;
3609                engravePrompts[itemId] = result.product.EngravePrompts;
3610                engraveCharges[itemId] = result.product.EngraveCharges;
3611                clubPriceFlags[itemId] = result.product.ClubPriceFlags;
3612                dropShipFlags[itemId] = result.product.DropShipFlags;
3613                vendorExpectedShipDates[itemId] = result.product.VendorExpectedShipDates;
3614
3615                if (!$form.hasClass("quickview-form") && window.invMsg) {
3616                    window.invMsg.qtyOnHand = result.product.QtyOnHand;
3617                    window.invMsg.salesBySku = result.product.SalesBySku;
3618                }
3619
3620                var ddl = $form.find('#' + updateField);
3621                ddl.empty();
3622                $('<option/>', { value: "", text: "Select an Option" }).appendTo(ddl);
3623                $(result.product.Values).each(function () {
3624                    $('<option/>', {
3625                            value: this.Code,
3626                            text: this.Desc,
3627                            selected: result.product.Type = data.SizeCode != null && $(result.product.Values).length == 1 //color is always selected after size.  if size is populated, then the results are colors.  if only one, just select it.
3628                        }).appendTo(ddl);
3629                });
3630                ddl.prop('disabled', false);
3631                ddl.customSelect('updateText');
3632                if (data.SizeCode != null && $(result.product.Values).length == 1) {
3633                    //processSelectedProductOption(ddl); // last one..., auto-select done via server code
3634                } else {
3635                    autoselectAttributeIfSingle(ddl);
3636                }
3637            });
3638    } else {
3639        return AjaxJsonPostWrapper.ajaxRoute('product', 'getproductdefaultpriceblock', prodDefData, function (result) {
3640            updatePriceBlockHtml($form, result.main, result.sticky);
3641            toggleCustomizationBox($form, "YES", 0);
3642            toggleDropShipMessage($form, prodDefData.IsDropShip, prodDefData.IsDropShip);
3643        });
3644    }
3645}
3646
3647function arrayAllTheSameValues(array) {
3648    var first = array[0];
3649    var allTheSame = true;
3650    $(array).each(function (index) { if (array[index] != first) allTheSame = false; });
3651    return allTheSame;
3652}
3653
3654window.defaultThisImage = null;  // used for defaulting image when image gallery is ready
3655
3656function processSelectedProductOption(dd) {
3657    var $dd = $(dd);
3658
3659    // $dd.closet('form') was returning 2(!) forms (and using the incorrect 
3660    //  one half the time) when there are two $(".auto-select") dropdowns 
3661    //  in the markup (pdp + quickview).  we'd like to only process for the relevant
3662    //  form but don't have that available at this time, just process each/both correctly
3663    $dd.each(function (idx) {
3664        $myDD = $(this);
3665
3666        var $form = $myDD.closest('form');
3667
3668        //js variables contain a arrays of values that correspond to the values of the final drop down
3669        var addBtnDiv = $form.find('.addToCartButtonDiv');
3670        var addBtn = $form.find('.addToCartButton');
3671        var notifyBtnDiv = $form.find('.notifyMeButtonDiv');
3672        var quantityDiv = $form.find("#quantityAdjustment");
3673        var productOptionType = $form.find("#ProductOptionType").val();
3674        var stockMsgDiv; //not in the form on PDP
3675        var isTruck = $("#freightLookup").length > 0 && !($form.attr("id").indexOf('quickview') === 0); // IE doesn't support startsWith
3676        
3677        if ($myDD.attr('name') === 'ColorCode' && $form.attr('id') !== "free-gift") {
3678            var selectedColorCode = $myDD.val();
3679            if (selectedColorCode !== "") {
3680                if ($form.hasClass("quickview-form")) {
3681                    var $modal = $form.closest(".moby-container.quickview.show"); // the visible quickview...
3682                    // needs to NOT affect other quickviews or the pdp that may be behind this
3683                    var $i = $modal.find("#product-thumbs img[data-associatedcolorcode = '" + selectedColorCode + "']").first();
3684                    if ($i.length) {
3685                        $modal.find("#main-image img").attr("src", $i.attr('src').replace("/s/", "/l/"));
3686                        $modal.find('.mainImageCaption').text($i.attr('title'));
3687                    }
3688                } else {
3689                    var $mScroll = $("#product-thumbs");
3690                    //todo watch out for related products... it pre-renders the quickview with duplicate ids on the page...
3691                    //we should re-work those and we wouldnt need this check to see if the scroll is in a slider
3692                    if ($mScroll.closest(".slider-container").length === 0) {
3693                        var $btn = $mScroll.find("button img[data-associatedcolorcode = '" + selectedColorCode + "']").first().parent();
3694                        if ($btn.length) {
3695                            var scope = $("#ImageGalleryController").scope();
3696                            if (scope != undefined)
3697                                scope.swapImage($btn, true);
3698                            else
3699                                window.defaultThisImage = selectedColorCode;
3700                        }
3701                    }
3702                }
3703            }
3704        }
3705
3706        var isQuickView = false;
3707        if ($form.hasClass("quickview-form")) {
3708            isQuickView = true;
3709            stockMsgDiv = $form.find('.stock-note');
3710        } else {
3711            stockMsgDiv = $('.stock-note');
3712        }
3713
3714        var index;
3715        if (productOptionType == "A") {
3716            index = $myDD.prop('selectedIndex');
3717        } else {
3718            index = $myDD.prop('selectedIndex') - 1;
3719        }
3720
3721        var itemId = $form.find('input[id=ID]').val();
3722
3723        checkCompanionProducts($myDD, $form);
3724
3725        if (index > -1) //they selected a value
3726        {
3727            var sellAction = sellActions[itemId][index];
3728            var price = prices[itemId][index];
3729            var clubPrice = clubPrices[itemId][index];
3730            var name = names[itemId][index];
3731            if (name != undefined && name != null) { //ammo kit
3732                if ($form.hasClass("quickview-form")) {
3733                    $(".product-title > h1", $form).text(name); // needs to NOT affect other quickviews or the pdp that may be behind this
3734                    $(".itemNumberText", $form).text($myDD.val()); // needs to NOT affect other quickviews or the pdp that may be behind this
3735                } else {
3736                    var $productTitle = $(".product-title > h1", $form);
3737                    $productTitle.text(name); // needs to NOT affect Related Products Quickview modals that are already in page
3738                    $(".breadcrumbs.container > ul > li:last > span > strong").text(name);
3739                    $(".itemNumberText").text($myDD.val());
3740                }
3741
3742                $form.find("#Name").val(name);
3743                checkPurchaseQtyLimits($form, $myDD.val());
3744                //this is an ammo kit selection, hide the was price on selection change
3745                $(".was-price").hide();
3746            }
3747
3748            if (isTruck) {
3749                resetFreightLookup();
3750            }
3751            
3752            var comparePrice = comparePrices[itemId][index];
3753            var wasPrice = wasPrices[itemId][index];
3754            var pricingType = clubDiscounts[itemId][index];
3755            var clubPriceFlag = clubPriceFlags[itemId][index];
3756            var embroideryFlag = embroideryFlags[itemId][index];
3757            var engravePrompt = engravePrompts[itemId][index];
3758            var dropShipFlag = (dropShipFlags[itemId].length > 0 ) ? (dropShipFlags[itemId][index] === "Y") : priceDefaults[itemId][11];
3759
3760            var optData = {
3761                ID: itemId,
3762                MinPrice: price,
3763                MaxPrice: price,
3764                MinClubPrice: clubPrice,
3765                MaxClubPrice: clubPrice,
3766                ComparePrice: comparePrice,
3767                WasPrice: wasPrice,
3768                ClubPriceFlag: clubPriceFlag,
3769                PricingType: pricingType,
3770                IsGenericPage: priceDefaults[itemId][8],
3771                HasBullseyeSavings: priceDefaults[itemId][9],
3772                IsClubExclusive: priceDefaults[itemId][10],
3773                IsDropShip: dropShipFlag,
3774                IsQuickView: isQuickView
3775            };
3776
3777            return AjaxJsonPostWrapper.ajaxRoute('product', 'getproductoptionpriceblock', optData, function (result) {
3778                updatePriceBlockHtml($form, result.main, result.sticky);
3779                toggleCustomizationBox($form, embroideryFlag, engravePrompt);
3780                toggleDropShipMessage($form, priceDefaults[itemId][11], dropShipFlag);
3781                //default stock message to out...we'll change to in if needed
3782                $(stockMsgDiv).addClass("out").removeClass("in");
3783                var expectDate = expectDates[itemId][index];
3784                if (sellAction == "S" || sellAction == "B") {
3785                    $(notifyBtnDiv).hide();
3786                    $(addBtnDiv).show();
3787                    $(quantityDiv).show();
3788                    if (isTruck) {
3789                        $("#freightLookup").show();
3790                    }
3791                    if (sellAction == "B") //on backorder, show stock message on back order
3792                    {
3793                        if (!isQuickView) {
3794                            $(".backordered-note").show();
3795                        }
3796                        var message = "Item is on backorder. Estimated availability: " + expectDate;
3797                        $(stockMsgDiv).text(message);
3798                    }
3799                    else {
3800                        if (!isQuickView) {
3801                            $(".backordered-note").hide();
3802                        }
3803                        var isJIT = $form.find('input[id=hdnIsJIT]').val();
3804                        var isFireArm = $form.find('input[id=hdnIsFirearm]').val();
3805                        if (isJIT == "false" || isFireArm == "true") {
3806                            if (isFireArm == "true") {
3807                                $(stockMsgDiv).addClass("in").removeClass("out");
3808                                $(stockMsgDiv).text("In Stock");
3809                            }
3810                            else if (!dropShipFlag) {
3811                                $(stockMsgDiv).addClass("in").removeClass("out");
3812                                $(stockMsgDiv).text("In Stock");
3813                            }
3814                            else if (dropShipFlag) {
3815                                $(stockMsgDiv).addClass("in").removeClass("out");
3816                                $(stockMsgDiv).text(vendorExpectedShipDates[itemId][index]);
3817                            }
3818                        }
3819                    }
3820                }
3821                else if (sellAction == "N") {
3822                    $(stockMsgDiv).text("Item not currently available for sale.");
3823                    $(notifyBtnDiv).show();
3824                    $(addBtnDiv).hide();
3825                    $(quantityDiv).hide();
3826                }
3827                else if (sellAction == "X") {
3828                    $(stockMsgDiv).text("SOLD OUT");
3829                    $(notifyBtnDiv).hide();
3830                    $(addBtnDiv).hide();
3831                    $(quantityDiv).hide();
3832                }
3833
3834                var $warrantyPdp = $("#warranty-data-pdp");
3835                if ($warrantyPdp.length) {
3836                    var $prodData = {
3837                        ID: $form.find('#ID').val(),
3838                        PromoCode: $form.find('#PromoCode').val(),
3839                        SizeParam: $form.find('#SizeCode').val(),
3840                        ColorParam: $form.find('#ColorCode').val()
3841                    };
3842                    var $warrantyScope = angular.element(".warranty-control").scope();
3843                    $warrantyScope.$broadcast('skuChanged', $prodData);
3844                }
3845            });
3846        }
3847        else { //if -1, then they set back to default no value
3848            //reset buttons and display to remove any info that was previously populated
3849            $(notifyBtnDiv).hide();
3850            $(addBtnDiv).show();
3851            $(stockMsgDiv).text(" ");
3852            $(quantityDiv).show();
3853            
3854            var optionData = {
3855                Prices: prices[itemId],
3856                ClubPrices: clubPrices[itemId],
3857                ClubDiscounts: clubDiscounts[itemId],
3858                ComparePrices: comparePrices[itemId],
3859                WasPrices: wasPrices[itemId],
3860                ClubPriceFlags: clubPriceFlags[itemId],
3861                DropShipFlags: dropShipFlags[itemId]
3862            };
3863            var prodDefData = getProductDefaultData(itemId);
3864            prodDefData.IsQuickView = isQuickView;
3865            return AjaxJsonPostWrapper.ajaxRoute('product', 'getproductoptiondefaultpriceblock', { prodDefault: prodDefData, option: optionData }, function (result) {
3866                updatePriceBlockHtml($form, result.main, result.sticky);
3867                toggleCustomizationBox($form, "YES", 0);
3868                toggleDropShipMessage($form, prodDefData.IsDropShip, prodDefData.IsDropShip);
3869
3870                if (isTruck) {
3871                    resetFreightLookup();
3872                }
3873            });
3874        }
3875    });
3876
3877    //var end = new Date().getTime();
3878    //console.log('milliseconds taken:' + (end - start));
3879
3880}
3881
3882function getProductDefaultData(itemId) {
3883    var data = {
3884            ID: itemId,
3885            MinPrice: priceDefaults[itemId][0],
3886            MaxPrice: priceDefaults[itemId][1],
3887            MinClubPrice: priceDefaults[itemId][2],
3888            MaxClubPrice: priceDefaults[itemId][3],
3889            ComparePrice: priceDefaults[itemId][4],
3890            WasPrice: priceDefaults[itemId][5],
3891            ClubPriceFlag: priceDefaults[itemId][6],
3892            PricingType: priceDefaults[itemId][7],
3893            IsGenericPage: priceDefaults[itemId][8],
3894            HasBullseyeSavings: priceDefaults[itemId][9],
3895            IsClubExclusive: priceDefaults[itemId][10],
3896            IsDropShip: priceDefaults[itemId][11]
3897    };
3898    return data;
3899}
3900
3901function updatePriceBlockHtml(form, main, sticky) {
3902    if (main) {
3903        angular.element(document).injector().invoke(['$compile', '$rootScope', function ($compile, $rootScope) {
3904            form.find("#priceBlockPH").html($compile(main)($rootScope));
3905        }]);
3906    }
3907    if (sticky) {
3908        if (!(form.attr("id").indexOf('quickview') === 0)) { // IE doesn't support startsWith
3909            if ($("#stickyAddToCart").length) {
3910                $("#stickyAddToCart").find("#stickyPricePH").html(sticky);
3911            }
3912        }
3913    }
3914    if (main) {
3915        Gorilla.util.initForms();
3916    }
3917}
3918
3919function toggleCustomizationBox(form, embroideryFlag, engravePrompt) {
3920    var custBox = form.find("#customization-box");
3921    if (custBox) {
3922        if ((embroideryFlag && embroideryFlag != "N") || engravePrompt > 0) {
3923            custBox.show();
3924        } else {
3925            custBox.hide();
3926            form.find("#Personalize").prop('checked', false);
3927        }
3928    }
3929}
3930
3931function toggleDropShipMessage(form, itemDropShipDefault, dropShipFlag) {
3932    if (itemDropShipDefault) { 
3933        var restrictShipEle = form.find(".restrictShip");
3934        if (restrictShipEle) {
3935            var restrictAddlShipDiv = restrictShipEle.find("#restrictAddlShipTip");
3936            if (restrictAddlShipDiv) {
3937                var dropShipEle = restrictAddlShipDiv.find(".dropShip");
3938                if (dropShipEle) {
3939                    if (dropShipFlag) {
3940                        dropShipEle.show();
3941                        restrictShipEle.show();
3942                    } else {
3943                        dropShipEle.hide();
3944                        if (dropShipEle.parent().find("li").length === 1) {
3945                            restrictShipEle.hide();
3946                        }
3947                    }
3948                }
3949            }
3950        }
3951    }
3952}
3953
3954function loadCustomerCommentPage(page) {
3955    //return AjaxJsonPostWrapper.ajaxRoute('usefullinks', 'getcustomercommentspage', { page: page }, function (result) {
3956    //    $('#productReviewsSummary').html(result.reviewPageSummary);
3957    //    $('#productReviewContainer').html(result.reviews);
3958    //    $(window).scrollTop(0);
3959    //});
3960}
3961
3962function catalogQuickOrderChange()
3963{
3964    var itemNum = $('#newItemNumber').val();
3965    var id = 0;
3966    var promo = "";
3967    if (itemNum.split('-').length == 2) {
3968        id = parseInt(itemNum.split('-')[1], 10);
3969        var regex = new RegExp("^[0-9a-zA-Z0-9]+$");
3970        promo = itemNum.split('-')[0].toUpperCase();
3971        if (!regex.test(promo))
3972            promo = "";
3973    }
3974    $('#quickorderbtn').attr("href", "/product/getproductcartdata?ID=" + id + "&PCode=" + promo);
3975}
3976
3977//function notifyMe(btn) {
3978//    var data = AjaxJsonPostWrapper.getFormData($(btn).closest('form'));
3979//    return AjaxJsonPostWrapper.ajaxRoute('product', 'notifymeform', data, function (result) {
3980//        console.log('results', result)
3981//        $('#notifyMe').html(result);
3982//        $('#notifyMe').show();
3983
3984//    });
3985//}
3986
3987function notifyMeFamilyGroup(promo, id, name, colorCode, sizeCode) {
3988    var data = { ID: id, PromoCode: promo, Name: name, ColorCode: colorCode, SizeCode: sizeCode };
3989    return AjaxJsonPostWrapper.ajaxRoute('product', 'notifymeform', data, function (result) {
3990        $('#notifyMe').html(result);
3991        $('#notifyMe').show();
3992    });
3993}
3994
3995//****************************end product functions***********************************
3996
3997// trying to get bundle to make a new number...
3998function testFuncAS()
3999{
4000    return false;
4001}
4002
4003//****************************cart view functions***********************************
4004function updateQty(ctrl, entryId, qty, cqo) {
4005    if ((qty === 0 || $(ctrl).valid()) &&
4006        $.trim(qty) != "") {//remove links send in 0 but don't do validation
4007        return AjaxJsonPostWrapper.ajaxRoute('cart', 'updateqty', { entryId: entryId, qty: qty, cqo: cqo }, function (result) {
4008            //update the main cart display
4009            if (result.cartHtml && result.cartHtml != "") {
4010                //update the cart drop down display
4011                setCartQuantityText();
4012                if (result.cartQty < 1) {
4013                    $(".subheader .checkout-btn").attr("style", "display:none!important");
4014                }
4015                $('#cartSummary').html("");
4016                updateCartContainer(result.cartHtml);
4017                $("#UpdateLink_" + entryId).focus();
4018            }
4019
4020            if (result.miniCartHtml && result.miniCartHtml != "") {
4021                updateShowMiniCart(result.miniCartHtml, false);
4022            }
4023        });
4024    }
4025}
4026
4027function removeItems(entryIds, cqo) {
4028    return AjaxJsonPostWrapper.ajaxRoute('cart', 'removeitems', { entryIds: entryIds, cqo: cqo }, function (result) {
4029        //update the main cart display
4030        if (result.cartHtml && result.cartHtml != "") {
4031            //update the cart drop down display
4032            setCartQuantityText();
4033            $('#cartSummary').html("");
4034            updateCartContainer(result.cartHtml);
4035        }
4036    });
4037}
4038
4039function updateCartSummary() {
4040    return AjaxJsonPostWrapper.ajaxRoute('cart', 'getcartpreview', {}, function (result) {
4041        updateShowMiniCart(result, true);
4042    });
4043}
4044
4045function updateWishSummary(showFade) {
4046    return AjaxJsonPostWrapper.ajaxRoute('wishlist', 'getwishlistpreview', {}, function (result) {
4047        updateShowMiniWish(result, true, showFade);
4048    })
4049}
4050
4051function applyGiftCard()
4052{
4053    // there is jquery/javascript that attaches to the "update" CSS class on the links, which 
4054    //  binds this link click to form submission.  bottom line, we don't need to do anything here
4055    return false;
4056}
4057
4058function resetFreightLookup() {
4059    $("#freightLookup .lookup").show();
4060    $("#freightLookup .result").hide();
4061    $("#freightLookup").hide();
4062    $("#hdnFreightZip").val("");
4063    $("#hdnFreightAmount").val(0);
4064}
4065
4066function addCommas(nStr) {
4067    nStr += '';
4068    var x = nStr.split('.');
4069    var x1 = x[0];
4070    var x2 = x.length > 1 ? '.' + x[1] : '';
4071    var rgx = /(\d+)(\d{3})/;
4072    while (rgx.test(x1)) {
4073        x1 = x1.replace(rgx, '$1' + ',' + '$2');
4074    }
4075    return x1 + x2;
4076}
4077
4078
4079//****************************end cart view functions**********************************
4080
4081//************ Product quick view is needed on a lot of pages because of the recently viewed section. ************
4082function productQuickView(adId, id, promo) {
4083    return AjaxJsonPostWrapper.ajaxRoute('product', 'getproductcartdata', { ID: id, PromoCode: promo, AdId: adId }, function (result) {
4084        $('#notifyMe').html("<div id='productCart' style='width:1100px; background-color:white; border:5px outset black;'>" + result + "</div>");
4085        $('#notifyMe').show();
4086    });
4087}
4088
4089function enableOK(checkbox) {
4090    var val = checkbox.id;
4091    if ($('#' + val).prop('checked')) {
4092        $('#' +val + '-acknowledge').removeAttr('disabled');
4093    }
4094    else {
4095        $('#' + val + '-acknowledge').attr('disabled', 'disabled');
4096    }
4097}
4098
4099//This function animates for effect the recently added item to cart/wishlist drawers
4100function popFadeProduct(containerId) {
4101    setTimeout(function () {
4102        var $productsGrid = $("#" + containerId).find("ol.products-grid");
4103        var $el = $productsGrid.find("li:first-child");
4104        $el.remove();
4105        $el.prependTo($productsGrid).hide().delay(500).fadeIn(2000);
4106    }, 500);
4107}
4108
4109//Sold Out products in cart
4110if (($soldOutTrigger = $('#sold-out-modal-trigger')).length) {
4111    $('#sold-out-modal-trigger').appendTo('body');
4112    $('#sold-out-modal').appendTo('body');
4113    setTimeout(function () {
4114        $soldOutTrigger.moby({
4115            'modalClass': 'sold-out-modal',
4116            'bodyClose': false,
4117            'keyActions': false,
4118            'onCompleteCallback': function () {
4119                Gorilla.util.initForms();
4120                $("#soldOutRemoveItem").on("click", function() {
4121                    $("#sold-out-modal-trigger").moby('hide');
4122                });
4123            }
4124        }).moby('show', '#sold-out-modal');
4125    }, 0);
4126}
4127
4128//Return restriction messaging
4129$(document).ready(function () {
4130    if (($gasReturnRestrictionTrigger = $('#gas-return-restriction-modal-trigger')).length) {
4131        setTimeout(function () {
4132            $gasReturnRestrictionTrigger.moby({
4133                'modalClass': 'sold-out-modal',
4134                'bodyClose': false,
4135                'keyActions': false,
4136                'onCompleteCallback': function () {
4137                    $("#gas-modal-close, #check-gas-acknowledge").on('click', function (event) {
4138                        event.preventDefault();
4139                        $("#gas-return-restriction-modal-trigger").moby('hide');
4140                    });
4141                }
4142            }).moby('show', '#gas-return-restriction-modal');
4143        }, 40);
4144    }
4145
4146    if (($unopenedReturnRestrictionTrigger = $('#unopened-return-restriction-modal-trigger')).length) {
4147        setTimeout(function () {
4148            $unopenedReturnRestrictionTrigger.moby({
4149                'modalClass': 'sold-out-modal',
4150                'bodyClose': false,
4151                'keyActions': false,
4152                'onCompleteCallback': function () {
4153                    $("#unopened-modal-close, #check-unopened-acknowledge").on('click', function (event) {
4154                        event.preventDefault();
4155                        $("#unopened-return-restriction-modal-trigger").moby('hide');
4156                    });
4157                }
4158            }).moby('show', '#unopened-return-restriction-modal');
4159        }, 40);
4160    }
4161
4162    if (($origpackagingReturnRestrictionTrigger = $('#origpackaging-return-restriction-modal-trigger')).length) {
4163        setTimeout(function () {
4164            $origpackagingReturnRestrictionTrigger.moby({
4165                'modalClass': 'sold-out-modal',
4166                'bodyClose': false,
4167                'keyActions': false,
4168                'onCompleteCallback': function () {
4169                    $("#origpackaging-modal-close, #check-origpackaging-acknowledge").on('click', function (event) {
4170                        event.preventDefault();
4171                        $("#origpackaging-return-restriction-modal-trigger").moby('hide');
4172                    });
4173                }
4174            }).moby('show', '#origpackaging-return-restriction-modal');
4175        }, 40);
4176    }
4177});
4178
4179function liftgateChange(el) {
4180    var $this = $(el);
4181    $("#liftgate-modal").data('elid', $this.attr("id"));
4182    var onPdp = $('body').hasClass('product-view');
4183    var onCheckout = $('body').hasClass("checkout");
4184
4185    if (!$this.is(":checked")) {
4186        $("#liftgate-modal-trigger").moby({
4187            'bodyClose': false,
4188            'keyActions': false,
4189            'modalClass': 'freightModal',
4190            'onCompleteCallback': function () {
4191                
4192                if (onPdp) {
4193                    $(".freightWeight").html($("#hdnFreightWeight").val() + " lbs.");
4194                } else {
4195                    updateFreightWeight($("#" + $("#liftgate-modal").data("elid")));
4196                }
4197
4198                if ($("#liftgateAckText").hasClass("ajax-loading")) {
4199                    AjaxJsonPostWrapper.ajaxRoute('cart', 'getackmessages', {}, function (result) {
4200                        $("#liftgateAckText").removeClass("ajax-loading").html(result.ackMessages.Liftgate.Message);
4201                    });
4202                }
4203
4204                $(document).off("click", "#keepLiftgate").on("click", "#keepLiftgate", function () {
4205                    var $el = $("#" + $("#liftgate-modal").data("elid"));
4206                    $el.prop("checked", true);
4207                    Gorilla.util.customCheckbox.update($el);
4208                    $("#liftgate-modal-trigger").moby('hide');
4209                });
4210
4211                $(document).off("click", "#removeLiftgate").on("click", "#removeLiftgate", function () {
4212                    var $el = $("#" + $("#liftgate-modal").data("elid"));
4213
4214                    AjaxJsonPostWrapper.ajaxRoute('cart', 'sendackmessage', { ackId: 17 });
4215
4216                    //uncheck front door if its checked, cant have it without liftgate
4217                    var $frontDoorInput = $el.closest(".freightAddOns").find("input[name='FrontDoor']");
4218                    $frontDoorInput.prop("checked", false);
4219                    Gorilla.util.customCheckbox.update($frontDoorInput);
4220
4221                    if (onPdp) {
4222                        updateFreightTotal();
4223                    } else {
4224                        updateFreightDeliveryOpt($el);
4225                    }
4226                    
4227                    if (onCheckout) { //this is a hack used to trigger the payment postback
4228                        $('#cartModifiedBtn').click();
4229                    }
4230
4231                    $("#liftgate-modal-trigger").moby('hide');
4232                });
4233            }
4234        }).moby('show', '#liftgate-modal');
4235
4236        return;
4237    }
4238
4239    if (onPdp) {
4240        updateFreightTotal();
4241    } else {
4242        updateFreightDeliveryOpt($this);
4243    }
4244    
4245    if (onCheckout) { //this is a hack used to trigger the payment postback
4246        $('#cartModifiedBtn').click();
4247    }
4248}
4249
4250function frontDoorChange(el) {
4251    var $this = $(el);
4252    $("#frontDoor-modal").data('elid', $this.attr("id"));
4253    var onPdp = $('body').hasClass('product-view');
4254    var onCheckout = $('body').hasClass("checkout");
4255    
4256    if (!$this.is(":checked")) {
4257        $("#frontDoor-modal-trigger").moby({
4258            'bodyClose': false,
4259            'keyActions': false,
4260            'modalClass': 'freightModal',
4261            'onCompleteCallback': function () {
4262                
4263                if (onPdp) {
4264                    $(".freightWeight").html($("#hdnFreightWeight").val() + " lbs.");
4265                } else {
4266                    updateFreightWeight($("#" + $("#frontDoor-modal").data("elid")));
4267                }
4268
4269                $(document).off("click", "#keepFrontDoor").on("click", "#keepFrontDoor", function () {
4270                    var $el = $("#" + $("#frontDoor-modal").data("elid"));
4271                    $el.prop("checked", true);
4272                    Gorilla.util.customCheckbox.update($el);
4273                    $("#frontDoor-modal-trigger").moby('hide');
4274                });
4275
4276                $(document).off("click", "#removeFrontDoor").on("click", "#removeFrontDoor", function () {
4277                    var $el = $("#" + $("#frontDoor-modal").data("elid"));
4278
4279                    if (onPdp) {
4280                        updateFreightTotal();
4281                    } else {
4282                        updateFreightDeliveryOpt($el);
4283                    }
4284
4285                    if (onCheckout) { //this is a hack used to trigger the payment postback
4286                        $('#cartModifiedBtn').click();
4287                    }
4288
4289                    $("#frontDoor-modal-trigger").moby('hide');
4290                });
4291            }
4292        }).moby('show', '#frontDoor-modal');
4293
4294        return;
4295    }
4296
4297    //liftgate is required for front door, make sure its checked
4298    var $liftgateInput = $this.closest(".freightAddOns").find("input[name='Liftgate']");
4299    $liftgateInput.prop("checked", true);
4300    Gorilla.util.customCheckbox.update($liftgateInput);
4301
4302    if (onPdp) {
4303        updateFreightTotal();
4304    } else {
4305        updateFreightDeliveryOpt($this);
4306    }
4307
4308    if (onCheckout) { //this is a hack used to trigger the payment postback
4309        $('#cartModifiedBtn').click();
4310    }
4311}
4312
4313function updateFreightTotal() {
4314    var quote = parseFloat($(".quoteAmount").text().slice(1));
4315    var frontDoorAmount = parseFloat($(".frontDoorAmount").text().slice(1));
4316    var liftgateAmount = parseFloat($(".liftgateAmount").text().slice(1));
4317
4318    var liftgate = $(".freightAddOns").find("input[name=Liftgate]:not([type=hidden])").is(":checked");
4319    var frontDoor = $(".freightAddOns").find("input[name=FrontDoor]:not([type=hidden])").is(":checked");
4320
4321    if (liftgate && frontDoor) {
4322        $(".freightTotal").text("$" + (quote + frontDoorAmount + liftgateAmount).toFixed(2));
4323    } else if (liftgate) {
4324        $(".freightTotal").text("$" + (quote + liftgateAmount).toFixed(2));
4325    } else {
4326        $(".freightTotal").text("$" + quote.toFixed(2));
4327    }
4328}
4329
4330function updateFreightWeight(el) {
4331    var $this = $(el);
4332
4333    var request = {
4334        ItemId: $this.closest('tr.restrictions-row').data('itemid'),
4335        SizeCode: $this.closest('tr.restrictions-row').data('sizecode'),
4336        ColorCode: $this.closest('tr.restrictions-row').data('colorcode')
4337    }
4338
4339    AjaxJsonPostWrapper.ajaxRoute('cart', 'getfreightdata', { request: request }, function (result) {
4340        $(".freightWeight").html(result.data.Weight + " lbs.");
4341    });
4342}
4343
4344function updateFreightDeliveryOpt(el) {
4345    var $this = $(el);
4346    
4347    var liftgate = $this.closest(".freightAddOns").find("input[name=Liftgate]:not([type=hidden])").is(":checked");
4348    var frontDoor = $this.closest(".freightAddOns").find("input[name=FrontDoor]:not([type=hidden])").is(":checked");
4349
4350    var opt;
4351    if (liftgate && frontDoor)
4352        opt = "F";
4353    else if (liftgate)
4354        opt = "L";
4355    else
4356        opt = "D";
4357
4358    var request = {
4359        EntryId: $this.closest('tr.restrictions-row').data('entryid'),
4360        Opt: opt
4361    };
4362
4363    AjaxJsonPostWrapper.ajaxRouteNonAsync('cart', 'setfreightdeliveryopt', { request: request });
4364}
4365
4366function addToWishList(link, id, promo, form) {
4367    // validate form
4368    if (!form) {
4369        var form = $(link).closest('form');
4370        if (!form.valid())
4371            return;
4372    }
4373
4374    // Personalize is a checkbox which MVC renders also as a hidden field, deal with that duplication/binding complexity:
4375    if ($("#Personalize").is(":checked")) {
4376        // removed "false" Personalize inputs when the Personalize checkbox (which has an ID) is checked
4377        $("[name='Personalize']").each(function (index) {
4378            if ($(this).val() == "false") {
4379                $(this).remove();
4380            }
4381        });
4382    }
4383
4384    var data = AjaxJsonPostWrapper.getFormData(form);
4385    if (id.length > 0) data.ID = id;
4386
4387    //check to see if they're signed in
4388    AjaxJsonPostWrapper.ajaxRoute('authenticate', 'issignedin', {}, function (response) {
4389        if (!response.signedIn) {
4390            // save form data to cookie 
4391            Gorilla.util.setCookie('_wishlist-product-data', btoa(JSON.stringify(data)));
4392            // if not signed in, send them off to sign-in/create account with their wish list as the final landing page (wish list will add the item from the cookie and trigger personalization if needed)
4393            window.location = "/authenticate/accountlogin?returnUrl=/wishlist/index";
4394        }
4395        else {
4396            // add item to wish list and pop wish list drawer
4397            AjaxJsonPostWrapper.ajaxRoute('wishlist', 'addtowishlist', { data: data }, function (result) {
4398                //this is bad practice, but a necessary evil until we are fully angular on the rest of the site
4399                if (Gorilla.util.getCookie("ab-cart") === "Experiment") {
4400                    if (($moby = $('.moby-container.quickview')).length) {
4401                        $moby.find('.moby-close').trigger('click').off('click'); //close the actual window that triggered this....normal path
4402                    }
4403                    //close the quickview slideout if its open
4404                    if ($("#quickview-mmenu").length && $("#quickview-mmenu").hasClass("mm-menu_opened")) {
4405                        $("#quickview-mmenu").data("mmenu").close();
4406                        if (lastFocus) {
4407                            lastFocus.focus();
4408                        }
4409                    }
4410
4411                    var scope = angular.element(document.getElementById('ItemAddedDialogController')).scope();
4412                    return scope.showDialog("wishlist");
4413                }
4414                updateWishSummary(true);
4415                if (result.personalizeHtml) {
4416                    if (($personalizeTrigger = $('#personalize-trigger')).length && ($personalizeModal = $('#personalize-modal')).length) {
4417                        //init the modal and set the Html from the response, since Moby requires an anchor we're triggering a click on the hidden anchor
4418                        $personalizeModal.html(result.personalizeHtml);
4419                        $personalizeTrigger.moby({
4420                            'modalClass': 'personalize-mod',
4421                            'ariaLabelText': 'Customize Item',
4422                            'onCompleteCallback': function () {
4423                                Gorilla.util.initForms();
4424                                $('#personalize-mod').validate();
4425                            }
4426                        }).moby('show', '#personalize-modal');
4427                    }
4428                }
4429
4430                var scope = angular.element(document.getElementById('CartWishListHomepageController')).scope();
4431                if (scope != undefined) scope.addedToCart();
4432            });
4433        }
4434    });
4435}
4436
4437function updateShowMiniWish(html, showSlide, showFade) {
4438    if (html && html !== "") {
4439        var prevItemCount = $("#wishlistQtyText").text();
4440        setWishlistQuantityText();
4441        var $wishSummary = $("#wishSummary");
4442        setTimeout(function () {
4443            $wishSummary.empty().append(html);
4444            $("#mini-totals-wish").empty().append($wishSummary.find(".mini-totals-container-wish").detach());
4445            var itemCount = $wishSummary.find(".items-in-cart-wish").detach().text();
4446            if (itemCount.length) {
4447                $("#mini-count-wish").empty().append(itemCount);
4448            } else {
4449                $("#cart-mmenu").addClass("mm-unset");
4450                $("#mini-count-wish").text("0 items in your wish list");
4451            }
4452        }, 500);
4453
4454        if (showSlide) {
4455            dropMiniWish();
4456        }
4457
4458        if (showFade && ($("#wishlistQtyText").text() > prevItemCount)) {
4459            popFadeProduct("wish-mmenu");
4460        }
4461    }
4462}
4463
4464function dropMiniWish() {
4465    if (($moby = $('.moby-container.quickview')).length) {
4466        $moby.find('.moby-close').trigger('click').off('click'); //close the actual window that triggered this....normal path
4467    }
4468
4469    //close the quickview slideout if its open
4470    if ($("#quickview-mmenu").length && $("#quickview-mmenu").hasClass("mm-menu_opened")) {
4471        $("#quickview-mmenu").data("mmenu").close();
4472    }
4473
4474    $quickorderAdd = $("#quickorder-add");
4475    if (!$quickorderAdd.length)
4476        setTimeout(function () {
4477            $("#wish-mmenu").data("mmenu").open();
4478            trapFocus($("#wish-mmenu"));
4479            $("#wish-mmenu").on("click", ".mm-navbars_top", function (e) {
4480                $("#wish-mmenu").data("mmenu").close();
4481                if (lastFocus) {
4482                    lastFocus.focus();
4483                }
4484            });
4485        }, 500);
4486}
4487
4488function checkCompanionProducts($myDD, $form) {
4489    if ($("#companion-products").length && !$form.hasClass("quickview-form")) {
4490        if ($myDD.attr('name') === 'ColorCode' || $myDD.attr('name') === 'SizeCode') {
4491            var compScope = angular.element("#companion-products").scope();
4492
4493            var retVal = false;
4494            if ($(".product-options").length) {
4495                $('.product-options select:visible').each(function () {
4496                    retVal = $(this).val() ? false : true;
4497                });
4498            }
4499            
4500            compScope.parentOptionsEmpty = retVal;
4501            compScope.parentSkuChange($myDD.attr('name'), $myDD.val());
4502            compScope.$apply();
4503        }
4504    }
4505}
4506
4507function checkPurchaseQtyLimits($form, itemId) {
4508    return AjaxJsonPostWrapper.ajaxRoute('product', 'getpurchaseqtylimit', { itemId: itemId }, function(response) {
4509        $form.find("#hdnPurchaseQtyLimit").val(response.purchaseQtyLimit);
4510        return window.checkQtyLimit($form);
4511    });
4512};
4513// Readied
4514domReady(function() {
4515
4516    if (($techDetailsContainer = $(".techDetailsCarousel-container")).length) {
4517        $techDetailsContainer.each(function() {
4518            $(this).attr("role", "region");
4519            var title = $(this).find(".container-title").text() + " CAROUSEL";
4520            $(this).attr("aria-label", title);
4521        });
4522    }
4523
4524    //text media containers
4525    if (($textMediaContainers = $(".textMediaWide-container, .textMediaNarrow-container")).length) {
4526        if (($lazyImg = $textMediaContainers.find('.lazy')).length) {
4527            $lazyImg.lazy({
4528                afterLoad: function (element) {
4529                    var container = $(element).closest(".base-container");
4530                    initTextMediaScroll(container);
4531                }
4532            });
4533        }
4534    }
4535
4536    if (($countdownContainer = $(".countdown-container")).length) {
4537        $countdownContainer.each(function () {
4538            var $el = $(this).find(".countdown");
4539            var endDate = $el.find("input[name='EndDate']").val();
4540            if (endDate !== undefined && endDate !== "") {
4541                $el.ResponsiveCountdown({
4542                    target_date: endDate,
4543                    time_zone: -5,
4544                    target_future: true,
4545                    set_id: 0,
4546                    pan_id: 0,
4547                    day_digits: 2,
4548                    fillStyleSymbol1: "rgba(84, 86, 90, 1)",
4549                    fillStyleSymbol2: "rgba(84, 86, 90, 1)",
4550                    fillStylesPanel_g1_1: "rgba(237, 237, 237, 1)",
4551                    fillStylesPanel_g1_2: "rgba(237, 237, 237, 1)",
4552                    fillStylesPanel_g2_1: "rgba(237, 237, 237, 1)",
4553                    fillStylesPanel_g2_2: "rgba(237, 237, 237, 1)",
4554                    text_color: "#D54400",
4555                    text_glow: "#FFFFFF",
4556                    show_ss: true, show_mm: true, show_hh: true, show_dd: true,
4557                    f_family: "Verdana", show_labels: true,
4558                    type3d: "group", max_height: 100,
4559                    days_long: "DAYS", days_short: "dd", hours_long: "HOURS", hours_short: "hh", mins_long: "MINUTES", mins_short: "mm", secs_long: "SECONDS", secs_short: "ss",
4560                    min_f_size: 9, max_f_size: 30,
4561                    spacer: "circles", groups_spacing: 3,
4562                    text_blur: 2, f_weight: "bold", font_to_digit_ratio: 0.125
4563                });
4564            }
4565        });
4566    }
4567
4568    if (($imageGridWithTextContainer = $(".media-grid-container")).length) {
4569        $imageGridWithTextContainer.each(function () {
4570            var $el = $(this).find(".media-grid-media .media-grid-text .media-grid-view-area");
4571            $($el).on('scroll', function () {
4572                if ($el.scrollTop() + $el.innerHeight() >= $el[0].scrollHeight - 32) {
4573                    $el.parent().find('#text-teaser').hide();
4574                } else {
4575                    $el.parent().find('#text-teaser').show();
4576                }
4577            })
4578
4579            //Check to see if content is scrollable
4580            if (($el[0].scrollHeight > $el[0].clientHeight) && ($el[0].clientWidth < $el[0].offsetWidth)) {
4581                $el.parent().find('#text-teaser').show();
4582                $el.parent().find('.blah-bar').show();
4583            } else {
4584                $el.parent().find('#text-teaser').hide();
4585                $el.parent().find('.blah-bar').hide();
4586            }
4587        });
4588    }
4589
4590    if (($responsiveImageX = $('[class*="responsiveImageX"]')).length) {
4591        $responsiveImageX.each(function (index, el) {
4592            el.classList.remove("extendfull");
4593            $(el).find('.sub-base-container').removeClass('extendfull');
4594            var $containerTitle = $(el).find('.container-title');
4595            if ($containerTitle.length) {
4596                el.prepend($containerTitle[0]);
4597            }
4598
4599            //Needed to accomodate container spacing
4600            var buttonHeight = $(el).find('.button-div:first').height();
4601            if (buttonHeight) {
4602                $(el).css('margin-bottom', buttonHeight / 2);
4603            }
4604        });
4605    }
4606
4607    if ($('.coupon-offer-disclaimer').length) {
4608        $('.coupon-offer-disclaimer').each(function (index, el) {
4609            el.getElementsByClassName("sub-base-container")[0].classList.remove("extendfull");
4610            var paragraphs = el.getElementsByClassName('normal-text');
4611
4612            Array.prototype.forEach.call(paragraphs, function (paragraph, index) {
4613                if (paragraphs.length > 1 && index == 0) {
4614                    paragraph.firstChild.style.setProperty("display", "block");
4615                    var newHeader = document.createElement("h3");
4616                    newHeader.innerHTML = paragraph.innerHTML;
4617                    paragraph.parentNode.replaceChild(newHeader, paragraph);
4618                }
4619                paragraph.firstChild.setAttribute("id", el.id + "-coupon-" + index);
4620            });
4621
4622            //Create View Details button
4623            var button = document.createElement("BUTTON");
4624            button.appendChild(document.createTextNode("View Details"));
4625            el.getElementsByClassName('sub-base-container')[0].appendChild(button);
4626
4627            button.addEventListener("click", function () {
4628                if (paragraphs[paragraphs.length - 1].firstChild.style.display === "block") {
4629                    paragraphs[paragraphs.length - 1].firstChild.style.display = "none";
4630                    button.textContent = "View Details";
4631                } else {
4632                    paragraphs[paragraphs.length - 1].firstChild.style.display = 'block';
4633                    button.textContent = "Hide Details";
4634                }
4635            });
4636
4637            //Replace second h2 with h3 for accessibility purposes
4638            var oldHeader = el.getElementsByTagName("h2")[1];
4639            if (oldHeader != undefined) {
4640                var newHeader = document.createElement("h3");
4641                newHeader.innerHTML = oldHeader.innerHTML;
4642                oldHeader.parentNode.replaceChild(newHeader, oldHeader);
4643            }
4644        });
4645    }
4646
4647    if ($('.featuredProducts-container').length) {
4648        $('.featuredProducts-container').each(function (index, el) {
4649            el.getElementsByClassName("normal-text")[0].style.marginBottom = 0;
4650        });
4651    }
4652
4653    if ($('.textMediaNarrow-container').length) {
4654        $('.textMediaNarrow-container').each(function (index, el) {
4655            $(el).find('.media-story').each(function (index, el) {
4656                if ($(el).find('.youtube-video-object').length > 0) {
4657                    $(el).css("max-width", "1200px");
4658                }
4659            });
4660        });
4661    }
4662});;
4663var readied = domReady(function() {
4664    // Readied
4665    $(function () {
4666        var w = 0;
4667        w = $(window).width();
4668        bcwpInitResponsive();
4669        $(window).resize(function() {
4670            if (w != $(window).width()) {
4671                bcwpInitResponsive();
4672                w = $(window).width();
4673                delete w;
4674            }
4675        });
4676    });
4677});
4678
4679function bcwpInitResponsive() {
4680    if (matchMedia('(min-width:961px)').matches) {
4681        //help the text center when absolutely positioned in a div in media grids
4682        if ($('.media-grid-container').length) {
4683            $('.media-inner-text').each(function() {
4684                if ($(this).prop('scrollHeight') > $(this).prop('clientHeight')) {
4685                    $(this).find('div').removeClass('vcenter');
4686                } else if ($(this).children().length == 1) {
4687                    $(this).children().css('top', '50%');
4688                    $(this).children().css('transform', 'translateY(-45%)');
4689                }
4690            });
4691        }
4692    }
4693
4694    if (matchMedia('(max-width:960px)').matches) {
4695        mobilizeWysiwigFonts();
4696    }
4697
4698    if (($textMediaContainers = $(".textMediaWide-container, .textMediaNarrow-container")).length) {
4699        initTextMediaScroll($textMediaContainers);
4700    }
4701
4702    if (matchMedia('(min-width: 961px)').matches) {
4703        //club exclusive product list
4704        if ($('.club-exclusives-ss').length) {
4705            destroyClubExclusiveSlickSlider();
4706        }
4707    } else {
4708        //club exclusive slider
4709        if ($('.club-exclusives-ss').length) {
4710            createClubExclusiveSlickSlider();
4711        }
4712    }
4713
4714    if (($('.buyersClubExclusive-container')).length) {
4715        setClubExclusivePriceDisplay();
4716    }
4717
4718    if (($('.twoColumnImageText-container')).length) {
4719        setTwoColImageButtonsDisplay();
4720    }
4721
4722    if (matchMedia('(max-width: 730px)').matches) {
4723        if (($responsiveImageX2Container = $(".responsiveImageX2-container")).length) {
4724            $responsiveImageX2Container.each(function (index, el) {
4725                if ($(el).hasClass('gutter')) {
4726                    var $widgetOne = $(el).find('.responsiveImage-widget').eq(0);
4727                    if ($($widgetOne).find('.button-div').length) {
4728                        $($widgetOne).css('margin-bottom', '40px');
4729                    }
4730                }
4731                var $widgetTwo = $(el).find('.responsiveImage-widget').eq(1);
4732                if (!$($widgetTwo).find('.button-div').length) {
4733                    $(el).css('margin-bottom', '0px');
4734                }
4735            });
4736        }
4737
4738        if (($responsiveImageX3Container = $(".responsiveImageX3-container")).length) {
4739            $responsiveImageX3Container.each(function (index, el) {
4740                if ($(el).hasClass('gutter')) {
4741                    var $widgetOne = $(el).find('.responsiveImage-widget').eq(0);
4742                    if ($($widgetOne).find('.button-div').length) {
4743                        $($widgetOne).css('margin-bottom', '40px');
4744                    }
4745                    var $widgetTwo = $(el).find('.responsiveImage-widget').eq(1);
4746                    if ($($widgetTwo).find('.button-div').length) {
4747                        $($widgetTwo).css('margin-bottom', '40px');
4748                    }
4749                }
4750                var $widgetThree = $(el).find('.responsiveImage-widget').eq(2);
4751                if (!$($widgetThree).find('.button-div').length) {
4752                    $(el).css('margin-bottom', '0px');
4753                }
4754            });
4755        }
4756
4757        if (($responsiveImageX4Container = $(".responsiveImageX4-container")).length) {
4758            $responsiveImageX4Container.each(function (index, el) {
4759                if ($(el).hasClass('gutter')) {
4760                    var $widgetOne = $(el).find('.responsiveImage-widget').eq(0);
4761                    if ($($widgetOne).find('.button-div').length) {
4762                        $($widgetOne).css('margin-bottom', '40px');
4763                    }
4764                    var $widgetTwo = $(el).find('.responsiveImage-widget').eq(1);
4765                    if ($($widgetTwo).find('.button-div').length) {
4766                        $($widgetTwo).css('margin-bottom', '40px');
4767                    }
4768                    var $widgetThree = $(el).find('.responsiveImage-widget').eq(2);
4769                    if ($($widgetThree).find('.button-div').length) {
4770                        $($widgetThree).css('margin-bottom', '40px');
4771                    }
4772                }
4773
4774                var $widgetThree = $(el).find('.responsiveImage-widget').eq(2);
4775                var $widgetFour = $(el).find('.responsiveImage-widget').eq(3);
4776                if (!$($widgetThree).find('.button-div').length && !$($widgetFour).find('.button-div').length) {
4777                    $(el).css('margin-bottom', '0px');
4778                }
4779            });
4780        }
4781    }
4782}
4783
4784function setTwoColImageButtonsDisplay() {
4785    $('.twoColumnImageText-container .media-story .button-div').each(function () {
4786        var $left = $(this).find('a');
4787        var $right = $left.next('a');
4788        var diff = 0;
4789        if ($right.length && $left.length)
4790            diff = $right.offset().top - $left.offset().top;
4791        
4792        if (!$right.hasClass('full-width-button') && diff > 0) {
4793            $right.addClass('full-width-button').addClass('full-width-button-right');
4794            $left.addClass('full-width-button');
4795        } else if ($right.hasClass('full-width-button') && diff === 0) {
4796            $right.removeClass('full-width-button').removeClass('full-width-button-right');
4797            $left.removeClass('full-width-button');
4798            $left.width('auto');
4799            $right.width('auto');
4800        }
4801        if ($right.hasClass('full-width-button')) {
4802            $left.width('auto');
4803            $right.width('auto');
4804            if ($right.width() > $left.width()) {
4805                $left.width($right.width());
4806                $right.width('auto');
4807            } else if ($left.width() > $right.width()) {
4808                $right.width($left.width());
4809                $left.width('auto');
4810            }
4811        }
4812    });
4813}
4814
4815
4816function setClubExclusivePriceDisplay() {
4817    $('.exclusive-product-item .club-price').each(function () {
4818        var $left = $(this).find('.left');
4819        var $right = $(this).find('.price-right');
4820        var diff = $right.offset().top - $left.offset().top;
4821
4822        if ($right.hasClass('right') && diff > 0) {
4823            $right.removeClass('right').addClass('left');
4824        }
4825        else if ($right.hasClass('left') && diff === 0) {
4826            $right.removeClass('left').addClass('right');
4827        }
4828    });
4829
4830    $('.exclusive-product-item .sub-text').each(function () {
4831        var $left = $(this).find('.left');
4832        var $right = $(this).find('.text-right');
4833        var diff = $right.offset().top - $left.offset().top;
4834
4835        if ($right.hasClass('right') && diff > 0) {
4836            $right.removeClass('right').addClass('left');
4837        }
4838        else if ($right.hasClass('left') && diff === 0) {
4839            $right.removeClass('left').addClass('right');
4840        }
4841    });
4842}
4843
4844//make the text media container's text have a scroll bar and its height set to its media sibling
4845function initTextMediaScroll(containers) {
4846    var $containers = $(containers);
4847
4848    //set max-height on the text block to the adjacent image so we overflow and get a scroll bar
4849    if (matchMedia('(min-width:961px)').matches) {
4850        $containers.find(".media-story").each(function () {
4851            var $this = $(this);
4852            var imgHeight = $this.children('.img').outerHeight();
4853            $this.children('.text').css('max-height', imgHeight)
4854
4855            setTimeout(function () {
4856                var imgHeight2 = $this.children('.img').outerHeight(); // double-check it, seems to matter more on Safari
4857                if (imgHeight != imgHeight2) {
4858                    $this.children('.text').css('max-height', imgHeight2)
4859                }
4860            }, 100);
4861        });
4862    } else {
4863        $containers.find(".media-story > .text").css('max-height', '');
4864    }
4865}
4866
4867function createClubExclusiveSlickSlider() {
4868    var $ss = $('.club-exclusives-ss .inner-wrap');
4869    if (!$ss.hasClass('slick-initialized')) {
4870        $ss.slick({
4871            arrows: true,
4872            infinite: true,
4873            dots: true,
4874            slidesToShow: 1,
4875            slidesToScroll: 1
4876        });
4877    }
4878}
4879
4880function destroyClubExclusiveSlickSlider() {
4881    var $ss = $(".club-exclusives-ss .inner-wrap");
4882    if ($ss.hasClass('slick-initialized')) {
4883        $ss.slick('unslick');
4884    }
4885}
4886
4887function mobilizeWysiwigFonts() {
4888    $(".bcwp .base-container p span").each(function() {
4889        var fontSize = $(this).css("fontSize");
4890        switch (fontSize) {
4891            case "60px":
4892                $(this).css("fontSize", "42px");
4893                break;
4894            case "42px":
4895                $(this).css("fontSize", "36px");
4896                break;
4897            case "30px":
4898                $(this).css("fontSize", "27px");
4899                break;
4900        }
4901    });
4902};
4903var numSlickProductSliders = 0;
4904var workSlickProductSliders = 0;
4905var lastFocus;
4906var windowSize = 0;
4907
4908domReady(function () {
4909    //fire off resize handler for responsive js when window size changes
4910    //from now on to break up js, we will need to add an event listener to the resize event for individual controls
4911    windowSize = $(window).width();
4912    var resizeHandler = function () {
4913        $(window).on("resize", function () {
4914            if (windowSize !== $(window).width()) {
4915                windowSize = $(window).width();
4916            }
4917        });
4918    }
4919    //we were losing the resize event listener using $(window).resize due to an mmenu collision
4920    $(function () { window.addEventListener('resize', resizeHandler, false); });
4921
4922    //test for csscalc support
4923    Modernizr.addTest('csscalc', function () {
4924        var prop = 'width:';
4925        var value = 'calc(10px);';
4926        var el = document.createElement('div');
4927
4928        el.style.cssText = prop + Modernizr._prefixes.join(value + prop);
4929
4930        return !!el.style.length;
4931    });
4932    if (!Modernizr.csscalc) {
4933        $("html").addClass("no-csscalc");
4934    }
4935
4936    //fix for keyboard open and position fixed elements with iOS
4937    if (Modernizr.touch) {
4938        var $body = $('body');
4939
4940        $(document).on('focus', 'input:not(#searchMobile), textarea, select, md-select-menu', function () {
4941            $body.addClass('ios-kb-fix');
4942        }).on('blur', 'input, textarea, select, md-select-menu', function () {
4943            $body.removeClass('ios-kb-fix');
4944        });
4945    } 
4946
4947    //init custom form elements
4948    Gorilla.util.initForms();
4949
4950    if (($modalTrigger = $('.trigger-modal')).length) {
4951        $modalTrigger.moby({
4952            'modalClass': 'generic'
4953        });
4954    }
4955
4956    initToolTips();
4957
4958    if (($lazyImg = $('.lazy')).length) {
4959        $lazyImg.lazy();
4960    }
4961
4962    //Init default sliders, use data api to set items count and margins
4963    if (($slider = $('.default-slider .products-grid')).length) {
4964        if (!$slider.hasClass('slick-initialized')) {
4965            $slider.slick({
4966                dots: false,
4967                arrows: true,
4968                slidesToShow: 4,
4969                slidesToScroll: 4,
4970                infinite: false,
4971                lazyLoad: 'ondemand',
4972                prevArrow: '<span class="sg-slick-prev" role="button" aria-label="Previous" tabindex="0"> &lsaquo; </span>',
4973                nextArrow: '<span class="sg-slick-next" role="button" aria-label="Next" tabindex="0"> &rsaquo; </span>',
4974                responsive: [
4975                    {
4976                        breakpoint: 1060,
4977                        settings: {
4978                            slidesToShow: 3,
4979                            slidesToScroll: 3,
4980                            arrows: true,
4981                            dots: true
4982                        }
4983                    },
4984                    {
4985                        breakpoint: 768,
4986                        settings: {
4987                            slidesToShow: 2,
4988                            slidesToScroll: 2,
4989                            arrows: true,
4990                            dots: true
4991                        }
4992                    },
4993                    {
4994                        breakpoint: 480,
4995                        settings: {
4996                            slidesToShow: 1,
4997                            slidesToScroll: 1,
4998                            arrows: true,
4999                            dots: true
5000                        }
5001                    }
5002                ]
5003            });
5004            numSlickProductSliders += $('.default-slider .products-grid').length;
5005            $slider.on("breakpoint", function (event, slick, breakpoint) {
5006                event.preventDefault();
5007                processSlickProductSliders();
5008            });
5009        }
5010    }
5011
5012    //brands carousel slider
5013    if (($brandslider = $('.slick-brands-carousel')).length) {
5014        if (!$brandslider.hasClass('slick-initialized')) {
5015            $brandslider.slick({
5016                dots: false,
5017                infinite: true,
5018                respondTo: 'slider',
5019                slidesToShow: 8,
5020                slidesToScroll: 8,
5021                prevArrow: '<span class="sg-slick-prev" role="button" aria-label="Previous" tabindex="0"> &lsaquo; </span>',/*Needs styles*/
5022                nextArrow: '<span class="sg-slick-next" role="button" aria-label="Next" tabindex="0"> &rsaquo; </span>',
5023                responsive: [
5024                    {
5025                        breakpoint: 1400,
5026                        settings: {
5027                            slidesToShow: 7,
5028                            slidesToScroll: 7
5029                        }
5030                    },
5031                    {
5032                        breakpoint: 1200,
5033                        settings: {
5034                            slidesToShow: 6,
5035                            slidesToScroll: 6
5036                        }
5037                    },
5038                    {
5039                        breakpoint: 1060,
5040                        settings: {
5041                            slidesToShow: 5,
5042                            slidesToScroll: 5
5043                        }
5044                    },
5045                    {
5046                        breakpoint: 960,
5047                        settings: {
5048                            slidesToShow: 4,
5049                            slidesToScroll: 4
5050                        }
5051                    },
5052                    {
5053                        breakpoint: 680,
5054                        settings: {
5055                            slidesToShow: 3,
5056                            slidesToScroll: 3
5057                        }
5058                    },
5059                    {
5060                        breakpoint: 480,
5061                        settings: {
5062                            slidesToShow: 2,
5063                            slidesToScroll: 2
5064                        }
5065                    },
5066                    {
5067                        breakpoint: 320,
5068                        settings: {
5069                            slidesToShow: 1,
5070                            slidesToScroll: 1,
5071                            variableWidth: true,
5072                            centerMode: true,
5073                            arrows: false
5074                        }
5075                    }
5076                ]
5077            });
5078            $brandslider.find('img').show();
5079        }
5080    }
5081
5082    if (($navslider = $('.navigation-carousel .bcwp-widgets-wrapper')).length) {
5083        if (!$navslider.hasClass('slick-initialized')) {
5084            $navslider.slick({
5085                dots: false,
5086                infinite: true,
5087                respondTo: 'slider',
5088                slidesToShow: 6,
5089                slidesToScroll: 6,
5090                prevArrow: '<span class="sg-slick-prev-gray" role="button" aria-label="Previous" tabindex="0"></span>',
5091                nextArrow: '<span class="sg-slick-next-gray" role="button" aria-label="Next" tabindex="0"></span>',
5092                responsive: [
5093                    {
5094                        breakpoint: 1400,
5095                        settings: {
5096                            slidesToShow: 6,
5097                            slidesToScroll: 6
5098                        }
5099                    },
5100                    {
5101                        breakpoint: 1060,
5102                        settings: {
5103                            slidesToShow: 5,
5104                            slidesToScroll: 5
5105                        }
5106                    },
5107                    {
5108                        breakpoint: 960,
5109                        settings: {
5110                            slidesToShow: 4,
5111                            slidesToScroll: 4
5112                        }
5113                    },
5114                    {
5115                        breakpoint: 680,
5116                        settings: {
5117                            slidesToShow: 3,
5118                            slidesToScroll: 3
5119                        }
5120                    }
5121                ]
5122            });
5123        }
5124    }
5125
5126    //lifestyle plus 5 slider
5127    if (($lsp5slider = $('.lifestylePlusFive-container .bcwp-widgets-wrapper')).length) {
5128        if (!$lsp5slider.hasClass('slick-initialized')) {
5129            $lsp5slider.slick({
5130                dots: false,
5131                infinite: true,
5132                respondTo: 'slider',
5133                slidesToShow: 1,
5134                slidesToScroll: 1,
5135                prevArrow: '<span class="sg-slick-prev-gray" role="button" aria-label="Previous" tabindex="0"></span>',
5136                nextArrow: '<span class="sg-slick-next-gray" role="button" aria-label="Next" tabindex="0"></span>',
5137                autoplay: false,
5138                autoplaySpeed: 5000
5139            });
5140        }
5141    }
5142
5143    //new product tiles.. since we cant put an anchor inside an anchor we have to show the quickview using javascript :(
5144    if ($(".product-tile").length) {
5145        $(document).on("mouseenter mouseleave", ".product-tile .product-image, .product-tile .btn-quickview", function (e) {
5146            if (e.type === "mouseenter") {
5147                $(this).closest(".product-tile").find(".btn-quickview").addClass("show");
5148            } else {
5149                $(this).closest(".product-tile").find(".btn-quickview").removeClass("show");
5150            }
5151        });
5152    }
5153
5154    /**
5155     * keep body from scrolling when nav menu is open in iOS
5156     */
5157    $(document).on('touchmove', function (e) {
5158        if ($('body').hasClass('nav-showing')) {
5159            var $target = $(e.target);
5160            if ($target.is('#nav-wrapper') || $target.parents('#nav-wrapper')) {
5161                e.stopPropagation();
5162            }
5163        }
5164    });
5165
5166    // a simple pair of classes was addded to truncate top and bottom abstracts with "..." on mobile
5167    //  this allows user to expand and read the whole section if desired.
5168    $(document).on("click", ".single-line-ellipsis-trigger", function () {
5169        $(this).toggleClass("single-line-ellipsis");
5170    });
5171
5172    //handle nested links in a button for A360
5173    $(document).on("click", "button.tool-tip", function (e) {
5174        if (e.target.tagName.toLowerCase() === 'a') // let nested links work
5175            return true;
5176
5177        e.preventDefault();
5178        e.stopPropagation();
5179    });
5180
5181    //animate labels to shrink and anchor to left corner to solve the placeholder texts always being visible ADA issue
5182    if (($anchorLabel = $(".input-wrapper .anchor-label")).length) {
5183        $anchorLabel.each(function () {
5184            var $input = $("#" + $(this).attr("for"));
5185            if ($input.length) {
5186                $input.on('focusin', function () {
5187                    $(this).closest(".input-wrapper").addClass("anchored");
5188                }).on('focusout', function () {
5189                    if (!$(this).val()) {
5190                        $(this).closest(".input-wrapper").removeClass("anchored");
5191                    }
5192                });
5193            }
5194        });
5195    }
5196
5197    //fire the resize handler after we are fully ready... THIS LINE SHOULD BE LAST
5198    toolsResizeHandler();
5199}); //end dom ready
5200
5201
5202
5203//RESPONSIVE
5204var toolsResizeHandler = function () {
5205    //fix for back button issue with mobile menu in IE... IE doesnt support the library's use of window.history.back()
5206    //this is unbound then bound as the menu can be created/destroyed based on breakpoint shifts
5207    var closeEvent = function () {
5208        if (($currentMenu = $('.mm-menu.mm-current.mm-menu_opened')).length) {
5209            $currentMenu.data("mmenu").close();
5210            lastFocus.focus();
5211        }
5212    }
5213    $(document).off("click", "a.mm-btn, a.mm-title", closeEvent).on("click", "a.mm-btn, a.mm-title", closeEvent);
5214
5215    if (matchMedia('(min-width: 961px)').matches) {
5216        //reset the nav cover, may have been manipulated if they went down to mobile and then back up to desktop
5217        $(".nav-cover-x").toggleClass("nav-cover nav-cover-x");
5218
5219        if ($("#mm-nav").length) { //destroy mobile controls if orientation changed
5220            $("#mm-nav").gorillaAccordion('unset');
5221            $("#mm-nav").find('.drop-down').gorillaAccordion('unset');
5222            destroyMmenu();
5223        }
5224
5225        $('body').removeClass('mobileVideo');
5226    }
5227
5228    if (matchMedia('(max-width: 960px)').matches) {
5229        //remove the nav cover if they ever hit this breakpoint, it can cause an issue with a tablet in landscape mode
5230        $(".nav-cover").hide().toggleClass("nav-cover nav-cover-x");
5231        $('body').addClass('mobileVideo');
5232    }
5233
5234    if (matchMedia('(min-width: 480px) and (max-width: 730px)').matches) {
5235        $('body').removeClass('mobile');
5236    }
5237
5238    if (matchMedia('(min-width: 480px) and (max-width: 560px)').matches) {
5239        $('body').removeClass('mobile');
5240    }
5241
5242    if (matchMedia('(min-width: 300px) and (max-width: 479px)').matches) {
5243        $('body').addClass('mobile');
5244    }
5245}
5246window.addEventListener('resize', toolsResizeHandler);
5247
5248
5249
5250function initToolTips() { //lazy-load tool tips on demand.. but not the fake ones (ffl lookup)
5251    $(document).on("click mouseover", "button.tool-tip:not(.not-really)", function (e) {
5252        e.preventDefault();
5253        var $tip = $(this);
5254        if (!$tip.data('isSet')) {
5255            $tip.tipsy({
5256                bounds: $('body'),
5257                //show method not publicly exposed... re-fire the event to show the tip after its wired up
5258                afterInitCallback: function () {
5259                    if ($(window).width() > 960) { $tip.trigger('click'); }
5260                }
5261            });
5262        }
5263    });
5264}
5265
5266//this function will de-parameterize a multi-value cookie to easily be able to retrieve a specific value
5267function deparamCookie(params) {
5268    var o = {};
5269    if (!params) return o;
5270    var a = params.split('&');
5271    for (var i = 0; i < a.length; i++) {
5272        var pair = a[i].split('=');
5273        o[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
5274    }
5275    return o;
5276}
5277
5278function trapFocus(element) {
5279    var focusableEls =
5280        element.find(
5281            'a[href], button:not(.magic-thumbs-button-disabled,[tabindex="-1"],.i18n), textarea, input[type="button"], input[type="text"], input[type="radio"], input[type="checkbox"], select, [tabindex]:not([tabindex="-1"])'),
5282        firstFocusableEl = focusableEls.first()[0],
5283        lastFocusableEl = focusableEls.last()[0],
5284        TABKEYCODE = 9,
5285        ARROWLEFTCODE = 37,
5286        ARROWUPCODE = 38,
5287        ARROWRIGHTCODE = 39,
5288        ARROWDOWNCODE = 40;
5289    
5290    if (firstFocusableEl != null) { firstFocusableEl.focus(); }
5291
5292    $(element).off('keydown').on('keydown', function (e) {
5293        // tab (no shift) or the right/down keys
5294        var next = e.key === 'ArrowRight' || e.keyCode === ARROWRIGHTCODE || e.key === 'ArrowDown' || e.keyCode === ARROWDOWNCODE || ((e.key === 'Tab' || e.keyCode === TABKEYCODE) && !e.shiftKey);
5295        // tab (with shift) or the left/up keys
5296        var prev = e.key === 'ArrowLeft' || e.keyCode === ARROWLEFTCODE || e.keyCode === 'ArrowUp' || e.keyCode === ARROWUPCODE || ((e.key === 'Tab' || e.keyCode === TABKEYCODE) && e.shiftKey);
5297    
5298        if (!next && !prev) {
5299            return;
5300        }
5301
5302        if (next && document.activeElement === lastFocusableEl) {
5303            firstFocusableEl.focus();
5304            e.preventDefault();
5305        }
5306        if (prev && document.activeElement === firstFocusableEl) {
5307            lastFocusableEl.focus();
5308            e.preventDefault();
5309        }
5310    });
5311}
5312
5313function initSGAccordian(openByDefault) {
5314    // wire up events
5315    $(document).on("click", ".sg-accordion-header", function () {
5316        $this = $(this);
5317        $this.toggleClass("active");
5318        $this.next().slideToggle(250); // the very next element had better be the content...
5319
5320        if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
5321            $button.attr("aria-expanded", $this.hasClass("active")); // A360/ADA -- set aria-expanded as appropriate
5322        }
5323    });
5324
5325    $(document).on("click", "#accordion-controls-container #expand-all", function () {
5326        $(".sg-accordion-header").each(function (i, v) { // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
5327            $this = $(this);
5328            $this.addClass("active");
5329
5330            if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
5331                $button.attr("aria-expanded", true);
5332            }
5333        });
5334
5335        $(".sg-accordion-content").slideDown();
5336    });
5337
5338    $(document).on("click", "#accordion-controls-container #collapse-all", function () {
5339        $(".sg-accordion-header").each(function (i, v) { // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
5340            $this = $(this);
5341            $this.removeClass("active");
5342
5343            if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
5344                $button.attr("aria-expanded", false);
5345            }
5346        });
5347        $(".sg-accordion-content").slideUp();
5348    });
5349
5350    if (openByDefault) {
5351        // have all panels open by default
5352        $(".sg-accordion-header").addClass("active"); // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
5353        $(".sg-accordion-content").show(); // need it fast! // TODO: this selector is probably not specific enough, maybe pass the parent container in? :/
5354    }
5355
5356    // deal with some FAQ's specific A360/ADA things... Seems like this could be applied to all instances of our .sg-accordion-header, but limiting to the FAQs for now
5357    $("#faqsV3 .sg-accordion-header").each(function (i, v) {
5358        var $this = $(this);
5359        var $next = $this.next(); // the very next element had better be the content...
5360
5361        // generate and assign an id to the associated content block, if needed
5362        var nextId = $next.attr("id");
5363        if (nextId == undefined) {
5364            nextId = "sgac-" + i;
5365            $next.attr("id", nextId);
5366        }
5367
5368        // add the aria- stuff to $this
5369        if (($button = $(".sg-accordion-header-button", $this)).length > 0) {
5370            $button.attr("aria-expanded", $this.hasClass("active"));
5371            $button.attr("aria-controls", nextId);
5372        }
5373    });
5374}
5375
5376function processSlickProductSliders() {
5377    workSlickProductSliders++;
5378    if (workSlickProductSliders == numSlickProductSliders) {
5379        $(document).find(".btn-quickview > button").each(function () {
5380            $(this).removeClass("bound");
5381            $(this).removeClass("bound961");
5382        });
5383        initResponsive();
5384        workSlickProductSliders = 0;
5385    }
5386}
5387
5388function enableTabIndicators(e) {
5389    if (e.keyCode === 9) { // keyboard tabber detected!
5390        document.body.classList.add('user-tab-detected');
5391        window.removeEventListener('keydown', enableTabIndicators);
5392    }
5393}
5394window.addEventListener('keydown', enableTabIndicators);
5395
5396function setLeftNavActiveLinkProps() {
5397    $("#left-navigation li.active a").each(function (i, v) { // had better be one and only one.  if not, last one wins
5398        var $activeAnchor = $(this);
5399        $activeAnchor.attr("aria-current", "page");
5400        $activeAnchor.closest("aside#left-navigation").attr("aria-label", $activeAnchor.text() + " navigation"); // I asked / double-checked that this should be "page name" vs. "layout name" and A360 was pretty adamant
5401    });
5402}
5403
5404function destroyMmenu() {
5405    $("div#mm-nav").remove();
5406    $("aside#mm-filters-menu").remove();
5407    $("div#mm-left-navigation").remove();
5408
5409    $("#filter-toggle").off("click");
5410    $("#col-left-menu-toggle").off("click");
5411}
5412
5413function initializeSlider(id) { // used to be in DynamicDataScript.cshmlt but we want to use it in angularized ViewCart as well
5414    //Init default sliders, use data api to set items count and margins
5415    if (($slider = $(id + ' .products-grid')).length) {
5416        if (!$slider.hasClass('slick-initialized')) {
5417            $slider.slick({
5418                accessibility: true,
5419                dots: false,
5420                arrows: true,
5421                slidesToShow: 5,
5422                slidesToScroll: 5,
5423                infinite: false,
5424                lazyLoad: 'ondemand',
5425                prevArrow: '<span class="sg-slick-prev" role="button" aria-label="Previous" tabindex="0"> <img class="sg-carousel" src="/images/product/icon-image-left.svg"> </span>',
5426                nextArrow: '<span class="sg-slick-next" role="button" aria-label="Next" tabindex="0"> <img class="sg-carousel" src="/images/product/icon-image-right.svg"> </span>',
5427                responsive: [
5428                    {
5429                        breakpoint: 1250,
5430                        settings: {
5431                            slidesToShow: 4,
5432                            slidesToScroll: 4,
5433                            arrows: true,
5434                            dots: true
5435                        }
5436                    },
5437                    {
5438                        breakpoint: 1060,
5439                        settings: {
5440                            slidesToShow: 3,
5441                            slidesToScroll: 3,
5442                            arrows: true,
5443                            dots: true
5444                        }
5445                    },
5446                    {
5447                        breakpoint: 768,
5448                        settings: {
5449                            slidesToShow: 2,
5450                            slidesToScroll: 2,
5451                            arrows: true,
5452                            dots: true
5453                        }
5454                    },
5455                    {
5456                        breakpoint: 480,
5457                        settings: {
5458                            slidesToShow: 1,
5459                            slidesToScroll: 1,
5460                            arrows: true,
5461                            dots: true
5462                        }
5463                    }
5464                ]
5465            });
5466            numSlickProductSliders++;
5467            $slider.on("breakpoint", function (event, slick, breakpoint) {
5468                event.preventDefault();
5469                processSlickProductSliders();
5470            });
5471        }
5472    }
5473}
5474
5475
5476// if they click / tap on a slider in mobile this should be used to take
5477//  care of any underlying link / anchor
5478// used during click: function, sister function to swipe: function
5479function sliderTap(event, target) {
5480    switch ($(target).get(0).tagName.toLowerCase()) {
5481        case "a":
5482            document.location.href = target;
5483            break;
5484        case "img":
5485            // this only goes up one level, obviously...
5486            var p = $(target).parent();
5487            if (p.get(0).tagName.toLowerCase() == "a") {
5488                document.location.href = p.attr("href");
5489            }
5490            break;
5491    }
5492}
5493
5494function initQtyButtons(containerName) { //qty adjust buttons
5495    if (($container = $(containerName)).length) {
5496        setTimeout(function() {
5497            $(".qty-adjust", $container).click(function (e) {
5498                e.preventDefault();
5499
5500                var $this = $(this);
5501                var $form = $this.closest("form");
5502                var $qty = $("#quantity", $form);
5503                var qty = $qty.val();
5504
5505                // manage new version (button w/ enhanced ADA) vs old version (div no ADA)
5506                if ($this.prop("tagName").toLowerCase() === "button") { // new approach
5507                    if ($this.data("direction") == "plus" && qty < 99) {
5508                        qty++;
5509                        $(".qty-minus").prop("disabled", false);
5510                    } else if ($this.data("direction") == "minus" && qty > 1) {
5511                        qty--;
5512                        if (qty == 1) {
5513                            $(".qty-minus").prop("disabled", true);
5514                        }
5515                    }
5516                } else { // old approach, should go away after PDP A/B test is complete and everything is rolled over to new version
5517                    if ($this.text() == "+" && qty < 99) {
5518                        qty++;
5519                    } else if ($this.text() == "-" && qty > 1) {
5520                        qty--;
5521                    }
5522                }
5523
5524                // safety / default
5525                if (!$.isNumeric(qty) || qty < 1) {
5526                    qty = 1;
5527                }
5528
5529                $qty.val(qty);
5530                $form.validate().element($qty);
5531            });
5532        }, 1000);
5533    }
5534}
5535
5536function initFitRating(containerName, currentValue) {
5537    if (($container = $(containerName)).length) {
5538        if (($fitRating = $("#BVFitRating", $container)).length) {
5539            $fitRating.slider({
5540                range: "max",
5541                min: 1,
5542                max: 5,
5543                step: 0.01,
5544                value: currentValue,
5545                disabled: true,
5546                create: function (event, ui) {
5547                    setSliderTicks(event.target);
5548                }
5549            });
5550        }
5551    }
5552}
5553
5554function initWidthRating(containerName, currentValue) {
5555    if (($container = $(containerName)).length) {
5556        if (($widthRating = $("#BVWidthRating", $container)).length) {
5557            $widthRating.slider({
5558                range: "max",
5559                min: 1,
5560                max: 3,
5561                step: 0.1,
5562                value: currentValue,
5563                disabled: true,
5564                create: function (event, ui) {
5565                    setSliderTicks(event.target);
5566                }
5567            });
5568        }
5569    }
5570}
5571
5572
5573//auto selects the only option in the size/color dropdowns
5574//function initAutoSelect(form) {
5575//    var $form = $(form);
5576//    processSelectedProductOption($form.find('.auto-select'));
5577//}
5578
5579/****************************** Truncate ad copy*******************************************/
5580
5581function truncateQuickViewAdCopy(quickViewForm) {
5582    var overflowMaxHeight = 400;
5583    var productDesc = quickViewForm.find('.product-description'),
5584        productMore = quickViewForm.find('#quickViewMoreDetails');
5585    truncateElementTextToHeight(productDesc, overflowMaxHeight);
5586    productMore.detach().appendTo(productDesc.children().last());
5587}
5588
5589function truncateElementTextToHeight(elem, overflowMaxHeight) {
5590    if (elem.height() > overflowMaxHeight) {
5591        do {
5592            var lastChild = elem.children().last();
5593            if ((lastChild.is('ul')) && (lastChild.children().length > 0)) {
5594                lastChild.children().last().remove();
5595                if (lastChild.children().length == 0) {
5596                    lastChild.remove();
5597                }
5598            }
5599            else {
5600                var text = elem.html();
5601                text = text.slice(0, text.lastIndexOf(" "));
5602                elem.html(text);
5603            }
5604        } while (elem.height() > overflowMaxHeight);
5605    }
5606}
5607
5608/****************************** Bloomreach Related Product Quick View Image Swap *******************************************/
5609
5610function swapBRRelProdImage(anchor) {
5611    var $id = anchor.href.substr(anchor.href.lastIndexOf('#') + 1);
5612    var $div = $("div[id=" + $id + "]");
5613    var $img = $div.find('img.brRelProd');
5614    if ($img.length) {
5615        $img.attr("src", $img.attr("data-br-src").replace("/m/", "/e/"));
5616    }
5617    $div.find("#alternate-images img").each(function () {
5618        $(this).attr("src", $(this).attr("data-br-src").replace("/m/", "/e/"));
5619    });
5620}
5621
5622
5623function autoselectAttributeIfSingle($ddl) {
5624
5625    if ($ddl.length === 0 || $ddl.hasClass("auto-select"))
5626        return;
5627
5628    var $opts = $("option", $ddl);
5629    if ($opts.length === 2) { // "Select an Option" + 1 value
5630        $opts.prop("selected", false); // unset them all
5631        $($opts[1]).prop("selected", "selected"); // make the first one selected
5632        $ddl.change(); // trigger the change event
5633    }
5634}
5635
5636function checkQtyLimit($form) {
5637    var limit = $form.find("#hdnPurchaseQtyLimit").val();
5638    if (limit === "0" || limit === "99") return false;
5639    setTimeout(function() {
5640        $form.find('#quantity').attr('type', 'number').attr('max', limit);
5641    }, 1000);
5642    if ($form.find("#ammoQtyLimit").length) {
5643        $form.find("#ammoQtyLimit").text(limit);
5644    } else {
5645        $form.find('.pdp-title-flex-container').first().after(
5646            '<div class="bold-text" style="color:#54565a;">* THIS ITEM HAS A LIMIT OF <span id="ammoQtyLimit">' +
5647            limit + '</span> PER ORDER.</div>');
5648    }
5649};
5650var $initFooterLinksAccordion = true;
5651var promoCarouselTimeout;
5652var mmenuCloseHookup = true;
5653domReady(function() {
5654
5655    //promo banner "tool tips"
5656    $(document).on("click", ".promo-trigger", function () {
5657        var message = $(this).next("hdncontent");
5658        $("#site-promo-modal").html(message.text());
5659
5660        $("#site-promo-modal-trigger").moby({
5661            //'modalClass': 'cart-limit-modal gradient-gray',
5662            'ariaLabelText': 'Promotion',
5663            'onCompleteCallback': function () {
5664                $(".moby-close").on('click', function (event) {
5665                    event.preventDefault();
5666                    $("#site-promo-modal-trigger").moby('hide');
5667                });
5668            }
5669        }).moby('show', '#site-promo-modal');
5670    });
5671
5672    //PDP lightbox "tool tips"
5673    $(document).on("click", ".tooltip-button", function () {
5674        var message = $(this).next(".tooltip-content");
5675
5676        /* console.log(message[0].innerHTML);*/
5677        $("#site-modal").html(message[0].innerHTML);
5678
5679        $("#site-modal-trigger").moby({
5680            'modalClass': 'tooltip-modal',
5681            'ariaLabelText': 'tooltip',
5682            'onCompleteCallback': function () {
5683                $(".moby-close").on('click', function (event) {
5684                    event.preventDefault();
5685                    $("#site-modal-trigger").moby('hide');
5686                });
5687            }
5688        }).moby('show', '#site-modal');
5689    });
5690
5691    // setup a custom override of the jquery-ui's _renderMenu function
5692    $.widget("ui.autocomplete", $.ui.autocomplete, {
5693        options: {
5694            maxItems: 9999 // adds this maxItems property to the object and default to 9999, usually overridden during specific .autocomplete({ inits
5695        },
5696        _renderMenu: function (ul, items) { // override jQuery-Ui's _renderMenu so we can make use of the maxItems as needed
5697            var that = this;
5698            $.each(items, function (index, item) { // google says this goes in order that they appear in the DOM
5699                if (index < that.options.maxItems) {
5700                    that._renderItemData(ul, item);
5701                }
5702            });
5703        }
5704    });
5705
5706    //Canada/International Shopping Modal
5707    $(document).on("click", "a.international", function () {
5708        var $intlMoby = $(this).moby({
5709            'modalClass': 'generic intl-shopping-modal',
5710            'ariaLabelText': 'International options',
5711            'onCompleteCallback': function () {
5712                Gorilla.util.initForms();
5713                $('#intl-shopping-form').validate();
5714                $("#intl-shopping").find(".close-link").on("click", function (e) {
5715                    e.preventDefault();
5716                    $intlMoby.off('click.moby');
5717                    $intlMoby.moby('remove');
5718                });
5719                $(".intl-shopping-modal .moby-close").on("click", function () {
5720                    $(this).parent().find('.close-link').click();
5721                });
5722            }
5723        }).moby('show', '#intl-shopping');
5724    });
5725
5726    var fnSkipToContent = function () {
5727        focusOnFirstEl($("#main[role='main']"));
5728    }
5729
5730    $("#skipToContent > a").on("click", fnSkipToContent);
5731    $("#skipToContent > a").on('keypress', function (e) {
5732        if (e.which === 13) { fnSkipToContent(); }
5733    });
5734
5735    //allow the space bar to work on mock button elements
5736    $(document).on("keypress", "span[role=button]", function(e) {
5737        e.preventDefault();
5738        if (e.which === 32) $(this).click();
5739    });
5740
5741    //fire the resize handler after we are fully ready... THIS LINE SHOULD BE LAST
5742    layoutResizeHandler();
5743});
5744
5745
5746
5747//RESPONSIVE
5748var layoutResizeHandler = function () {
5749    if (matchMedia('(min-width:961px)').matches) {
5750        //Large screens, full menu
5751        $('.shop').find('.fly-out').html("<h4><span>Loading...</span></h4>");
5752        $('.shop').find('.fly-out').addClass('auto-height');
5753
5754        if (($nav = $('#nav')).length) {
5755            //init main nav
5756            if (!$nav.attr("data-dropit")) {
5757                $nav.DropIt({
5758                    'triggerSelector': 'li.level-top',
5759                    'menuSelector': '.drop-down',
5760                    'speed': 0,
5761                    'delay': 0,
5762                    'showCover': true
5763                });
5764            }
5765
5766            if (!$nav.find('.shop ul.level0').attr('data-dropit')) {
5767                $nav.find('.shop ul.level0').DropIt({
5768                    'triggerSelector': '> li',
5769                    'menuSelector': '.fly-out',
5770                    'speed': 0,
5771                    'delay': 200,
5772                    'onHover': function (elm) {
5773                        var $this = $(elm),
5774                            busy = false;
5775
5776                        if (busy || $this.data('loaded')) {
5777                            return;
5778                        }
5779
5780                        $.ajax({
5781                                url: $this.data('menu'),
5782                                type: 'post',
5783                                dataType: 'html',
5784                                beforeSend: function () {
5785                                    busy = true
5786                                }
5787                            })
5788                            .done(function (html) {
5789                                $this.find('> a').after(html).end().data('loaded', true);
5790                                $nav.find('ul.level0').DropIt('showMenu', $this.find('.fly-out'));
5791                            })
5792                            .always(function () {
5793                                busy = false;
5794                            })
5795                    }
5796                });
5797            }
5798        }
5799
5800        bindDesktopSearch();
5801        hookUpQuickViews(document);
5802
5803        //footer accordion unset
5804        if (($accordion = $('#footer').find('.accordion')).length) {
5805            $accordion.gorillaAccordion('unset');
5806        }
5807        $initFooterLinksAccordion = true;
5808
5809    }
5810
5811    if (matchMedia('(min-width: 961px)').matches) {
5812        //site wide promo message banner
5813        if ($('#site-wide-promos').length) {
5814            destroySiteWidePromoSlickSlider();
5815        }
5816    } else {
5817        //site wide promo message carousel
5818        if ($('#site-wide-promos').length) {
5819            createSiteWidePromoSlickSlider();
5820        }
5821    }
5822
5823    if (matchMedia('(max-width: 960px)').matches) {
5824        //mobile navigation init
5825        if (($nav = $('#nav')).length) {
5826            if ($nav.DropIt) {
5827                $nav.DropIt('unset');
5828                $nav.find('ul.level0').DropIt('unset');
5829            }
5830        }
5831
5832        //footer accordion init
5833        if (($accordion = $('#footer').find('.accordion')).length) {
5834            if ($initFooterLinksAccordion) {
5835                $accordion.gorillaAccordion({
5836                    trigger: 'h2',
5837                    container: '.content',
5838                    containerInner: '> ul'
5839                });
5840                $initFooterLinksAccordion = false;
5841            }
5842        }
5843
5844        if (($quickviewSlideout = $("#quickview-mmenu")).length) {
5845            hookUpQuickViews(document);
5846
5847            $quickviewSlideout.mmenu({
5848                extensions: ["pagedim-black", "position-right", "position-front", "theme-white"],
5849                backButton: { close: false },
5850                navbar: { title: "" }, //needed to hide the default title menu
5851                navbars: [{ position: "top", content: "<a class='mm-title' href='#' onclick='event.preventDefault();'>Close</a><a class='mm-btn' href='#' onclick='event.preventDefault();' role='button'><span class='mmenu-close'></span><span class='sr-only'>close menu</span></a>" }],
5852                onClick: { close: false, setSelected: false },
5853                slidingSubmenus: false
5854            }, {
5855                //configuration
5856                offCanvas: {
5857                    pageSelector: "#sg-page-wrapper"
5858                }
5859            });
5860            $("#quickview-mmenu").on("click", ".mm-navbars_top", function (e) {
5861                $("#quickview-mmenu").data("mmenu").close();
5862                lastFocus.focus();
5863            });
5864        }
5865    }
5866
5867    if (matchMedia('(min-width: 681px) and (max-width: 960px)').matches) {
5868        bindTabletSearch();
5869    }
5870
5871    if (matchMedia('(min-width: 681px)').matches) {
5872        //mobile search to default state for shifting breakpoints
5873        $(".site-search.mobile-search").removeClass("open").addClass("closed").attr("style", "");
5874        $(".mobile-trigger.search .search-icon").removeClass("open");
5875    }
5876
5877    if (matchMedia('(max-width: 680px)').matches) {
5878        bindMobileSearch();
5879        $(document).off("click", "#search-trigger").on("click",
5880            "#search-trigger",
5881            function(e) {
5882                e.preventDefault();
5883                var $searchDiv = $(".site-search.mobile-search");
5884                var $searchIcon = $(".mobile-trigger.search .search-icon");
5885                var $searchInput = $(".site-search.mobile-search .input-text")
5886                if ($searchDiv.hasClass("closed")) {
5887                    $searchDiv.slideToggle("fast").removeClass("closed").addClass("open");
5888                    $searchIcon.addClass("open");
5889                    $searchInput.focus();
5890                } else if ($searchDiv.hasClass("open")) {
5891                    $searchDiv.slideToggle("fast").removeClass("open").addClass("closed");
5892                    $searchIcon.removeClass("open");
5893                    $searchInput.blur();
5894                }
5895            });
5896    }
5897
5898}
5899window.addEventListener('resize', layoutResizeHandler);
5900
5901
5902
5903
5904function setWishlistQuantityText() {
5905    var cookieValue = "0";
5906    var cookieData =
5907        decodeURIComponent(document.cookie
5908            .replace(new RegExp("(?:(?:^|.*;)\\s*" +
5909                    encodeURIComponent("wlQty").replace(/[\-\.\+\*]/g, "\\$&") +
5910                    "\\s*\\=\\s*([^;]*).*$)|^.*$"),
5911                "$1")) || null;
5912
5913    if (cookieData != null)
5914        cookieValue = cookieData;
5915
5916    $('#wishlistQtyText').text(cookieValue);
5917    if (cookieValue != null && cookieValue != "0") {
5918        $('#wishlistQtyText').show();
5919        $('#wishlistQtyLbl').show();
5920    } else {
5921        $('#wishlistQtyText').hide();
5922        $('#wishlistQtyLbl').hide();
5923    }
5924        
5925}
5926
5927//ALL updates to the view cart container need to use this!!!
5928function updateCartContainer(html) {
5929    $('#cartContainer').replaceWith(html);
5930    $('#cartContainer').find($("img.lazy")).lazy();
5931    Gorilla.util.initForms();
5932    //need to refresh dynamic data on teh club spiff...
5933    //TODO since that no longer show/hides based on the cart or membership... this should be fixed to be static
5934    AjaxJsonPostWrapper.ajaxRoute('dynamicdata', 'getdata', { page: 'viewcart' }, function (result) {
5935        var $clubDd = $("club-dynamic-data");
5936        if (result.clubDd && $clubDd.length) {
5937            $("club-dynamic-data").replaceWith(result.clubDd);
5938        }
5939    });
5940}
5941
5942/****************************** Search SuggestAhead *******************************************/
5943function getSuggestAheadTerms(request, response) {
5944    var term = $('<div/>').text(request.term).html();
5945    $.ajax({
5946        type: "POST",
5947        url: window.location.protocol + "//" + window.location.host + "/main/suggestaheadsearchterms",
5948        async: true,
5949        data: JSON.stringify({ term: term }),
5950        contentType: 'application/json',
5951        traditional: true,
5952        success: function (result) {
5953            //dont post old data, the newest response should be used
5954            if ($('#k').val() != result.term) {
5955                //console.log($('#k').val() + " :bad: " + result.term);
5956                return false;
5957            }
5958            //else
5959                //console.log($('#k').val() + " :good: " + result.term);
5960            var fullTerms = result.suggestions.split('|');
5961            var uniqueKeys = [];
5962            $.each(fullTerms, function (i, el) {
5963                var str = el.trim();
5964                if ($.inArray(str, uniqueKeys) == -1) uniqueKeys.push(str);
5965            });
5966            $('#searchProducts').html(result.html);
5967            $itemContainer = $('#product-listing-container');
5968            $itemContainer.find("img.lazy").lazy({ delay: 0 });
5969            response(uniqueKeys);
5970        },
5971        error: function (XMLHttpRequest, textStatus, errorThrown) {
5972            var errId = XMLHttpRequest.getResponseHeader("System-Error-ID");
5973            var errIdMsg = "";
5974            if (errId != null) {
5975                errIdMsg = " [" + errId + "]"
5976            }
5977            console.log("An error occurred during ajax operation" + errIdMsg + ".") // mimics what has been "good enough" since redesign, circa 2014.  we don't really know what to do but probably don't want to interrupt the user
5978
5979            //if (error != undefined) {
5980            //    error(errorThrown);
5981            //}
5982            //else {
5983            //    Gorilla.util.messages.addMessage('Sorry, there was an error with your request. Please try again shortly.', 'error');
5984            //}
5985        }
5986    })
5987        .done(function (data) {
5988            if (data.errors) {
5989                onDataError(data);
5990            }
5991
5992            // tablet and desktop search, hook up keyboard functionality
5993            if (matchMedia('(min-width: 681px)').matches) {
5994                // add tab indexes to the suggest ahead terms and remove the tab index from the parent list
5995
5996                $("#searchSuggestions li:first").addClass('ac-first');
5997                $("#searchSuggestions li:last").addClass('ac-last');
5998                $("#searchSuggestionsQuantity").text($('#searchSuggestions li').length + " autocorrect results");
5999                $("#searchProductsQuantity").text($('#searchProducts li').length + " product results");
6000
6001                // triggers off search box
6002                $('#k').off('keydown').on('keydown', function (e) {
6003                    if (e.key === 'ArrowDown' || e.keyCode === 40 || ((e.key === 'Tab' || e.keyCode === 9) && !e.shiftKey)) {
6004                        //if suggest ahead list is showing and has values
6005                        if ($('#searchSuggestions ul li').length > 0) {
6006                            e.preventDefault();
6007                            $('#searchSuggestions ul.ui-menu').show();
6008                            $('#searchSuggestions li:first div').focus();
6009                            $('#searchProducts').attr("style", "display:block");
6010                        }
6011                    }
6012                    else if (e.key === 'ArrowUp' || e.keyCode === 38) {
6013                        //if suggest ahead list is showing and has values
6014                        if ($('#searchSuggestions ul li').length > 0) {
6015                            e.preventDefault();
6016                            $('#searchSuggestions ul.ui-menu').show();
6017                            $('#searchSuggestions li:last div').focus();
6018                        }
6019                    }
6020                    else if (e.shiftKey && (e.key === 'Tab' || e.keyCode === 9)) {
6021                        // leaving search box
6022                        $('#searchSuggestions ul.ui-menu').hide();
6023                        $('#searchProducts').hide();
6024                    }
6025                });
6026
6027                // redefine mouse hover effects
6028                $('#searchSuggestions li').hover(function (event, ui) {
6029                    //console.log($(this).text() + " :: " + $(this).index());
6030                    var i = 0;
6031                    for (i = 0; i < 11; i++) {
6032                        $('#suggestindex-' + i).hide();
6033                    }
6034                    $('#suggestindex-' + $(this).index()).show();
6035                });
6036
6037                // redefine off hover effects, 
6038                // hide if focus leaves all of the three elements (search box, suggest head, suggest products)
6039                $('#kform').focusout(function (e) {
6040                    var $elem = $(this);
6041                    setTimeout(function () {
6042                        var hasFocus = !!($elem.find(':focus').length > 0);
6043                        if (!hasFocus) {
6044                            $('#searchSuggestions ul.ui-menu').hide();
6045                            $('#searchProducts').hide();
6046                        }
6047                    }, 10);
6048                });
6049
6050                // define focus
6051                $('#searchSuggestions li div').focus(function (event, ui) {
6052                    event.preventDefault();
6053                    var i = 0;
6054                    for (i = 0; i < 11; i++) {
6055                        $('#suggestindex-' + i).hide();
6056                    }
6057                    $('#suggestindex-' + $(this).index()).show();
6058                });
6059
6060                // define arrow key movement
6061                //left and right moves through products
6062                //up and down (and shift+tab/tab) moves through suggest ahead
6063                $('#searchSuggestions li').on('keydown', function (e) {
6064                    if (e.key === 'Enter' || e.keyCode === 13) {
6065                        e.preventDefault();
6066                        $("#k").val($(this).text());
6067                        $("#kform").submit();
6068                    }
6069                    else if ((e.key === 'Tab' || e.keyCokde === 9) && !e.shiftKey) {
6070                        if ($('#searchProducts .category-products ol li').length > 0) {
6071                            e.preventDefault();
6072                            $('#searchProducts .category-products ol a:first').focus();
6073                        }
6074                    }
6075                });
6076
6077                // if tabbing past everything then make sure to close auto correct boxes
6078                $('.site-search .icon-wrapper button.button').focus(function () {
6079                    $('#searchSuggestions ul.ui-menu').hide();
6080                    $('#searchProducts').hide();
6081                });
6082                
6083
6084            } else {
6085                // add tab indexes to the suggest ahead terms and remove the tab index from the parent list
6086
6087
6088                $('#searchMobile').off('keydown').on('keydown', function (e) {
6089                    if (e.key === 'ArrowDown' || e.keyCode === 40 || ((e.key === 'Tab' || e.keyCode === 9) && !e.shiftKey)) {
6090                        //if suggest ahead list is showing and has values
6091                        if ($('#searchSuggestionsMobile ul li').length > 0) {
6092                            e.preventDefault();
6093                            $('#searchSuggestionsMobile ul.ui-menu').show();
6094                            $('#searchSuggestionsMobile li:first div').focus();
6095                        }
6096                    }
6097                    else if (e.key === 'ArrowUp' || e.keyCode === 38) {
6098                        //if suggest ahead list is showing and has values
6099                        if ($('#searchSuggestionsMobile ul li').length > 0) {
6100                            e.preventDefault();
6101                            $('#searchSuggestionsMobile ul.ui-menu').show();
6102                            $('#searchSuggestionsMobile li:last div').focus();
6103                        }
6104                    }
6105                    else if (e.shiftKey && (e.key === 'Tab' || e.keyCode === 9)) {
6106                        $('#search-trigger').trigger('click').off('click');
6107                    }
6108                });
6109
6110                // define arrow key movement
6111                //up and down (and shift+tab/tab) moves through suggest ahead
6112                $('#searchSuggestionsMobile li').on('keydown', function (e) {
6113                    if (e.key === 'Enter' || e.keyCode === 13) {
6114                        e.preventDefault();
6115                        $("#searchMobile").val($(this).text());
6116                        $("#mobilekform").submit();
6117                    }
6118                    else if ((e.key === 'Tab' || e.keyCode === 9) && !e.shiftKey) {
6119                        if ($(this).is(':last-child')) {
6120                            e.preventDefault();
6121                            $('#search-trigger').trigger('click').off('click');
6122                            $('#menu-trigger').focus();
6123                        }
6124
6125                    }
6126
6127                });
6128            }
6129        });
6130}
6131
6132// when an item in the suggested terms dropdown gets the focus/hover, call out and get products for that term
6133function getSuggestAheadTermsFocus(liID, label) {
6134    if ($("#" + liID).hasClass('ui-state-active')) { // used to be ui-state-focus in older version of jQuery
6135        getSuggestAheadTermsFocusCall(label);
6136    }
6137}
6138
6139function highlightSearchedTerm($elem) {
6140    var acData = $elem.data('ui-autocomplete');
6141    acData.menu.element.find('li').each(function () {
6142        var container = $("div", $(this)); // ui-autocomplete now has a div inside the li wrapping the words
6143        var keywords = acData.term.split(' ').join('|');
6144        container.html(container.html().replace(new RegExp("(" + keywords + ")", "gi"), '<span class="highlight">$1</span>'));
6145    });
6146}
6147
6148
6149function hookUpQuickViews(el) {
6150    if (matchMedia('(min-width: 961px)').matches) {
6151        $(el).find(".btn-quickview > button:not(.bound961)").each(function () {
6152            $(this).removeClass("bound");
6153            $(this).parent().removeClass("hide-quick-view");
6154            $(this).off("click");
6155            $(this).addClass("bound961");
6156
6157            hookupQuickviewAda($(this));
6158
6159            //Bloomreach Related Products
6160            $(this).find("[href$='#brqv']").on("click", function () {
6161                swapBRRelProdImage($(this));
6162            });
6163
6164            $(this).moby({
6165                'modalClass': 'quickview',
6166                'ariaLabelText': 'Quick View',
6167                'onCompleteCallback': function (e) {
6168
6169                    var $form = $(e).find('form');
6170                    if ($form.length === 0) { // fix latent bug - seems like related products quickview's e is "window" and .find from there doesn't pick up the QV form...
6171                        $form = $(".moby-container.quickview.show").find('form');
6172                    }
6173
6174                    validateAndInitQuickViewForm($form);
6175                    autoselectAttributeIfSingle($(".attribute-select", $form).first());
6176                },
6177                'onCloseCallback': function (e) {
6178                    callMonetateScripts();
6179                }
6180            });
6181        });
6182        $(el).find(".add-on-quickview:not(.bound961)").each(function () {
6183            $(this).removeClass("bound");
6184            $(this).off("click");
6185            $(this).addClass("bound961");
6186            $(this).moby({
6187                'modalClass': 'quickview',
6188                'ariaLabelText': 'Quick View',
6189                'onCompleteCallback': function (e) {
6190
6191                    var $form = $(e).find('form');
6192                    if ($form.length === 0) { // fix latent bug - seems like related products quickview's e is "window" and .find from there doesn't pick up the QV form...
6193                        $form = $(".moby-container.quickview.show").find('form');
6194                    }
6195
6196                    validateAndInitQuickViewForm($form);
6197                    autoselectAttributeIfSingle($(".attribute-select", $form).first());
6198                },
6199                'onCloseCallback': function (e) {
6200                    callMonetateScripts();
6201                }
6202            });
6203        });
6204    }
6205    else {
6206        $(el).find(".btn-quickview > button:not(.bound)").each(function () {
6207            $(this).removeClass("bound961");
6208            $(this).off("click");
6209            $(this).parent().removeClass("hide-quick-view");
6210            $(this).addClass("bound");
6211
6212            hookupQuickviewAda($(this));
6213
6214            if ($(this).attr("href").indexOf("#brqv") >= 0) { //Bloomreach Related Products
6215                $(this).on("click", function (e) {
6216                    e.preventDefault();
6217                    var $divId = $(this).attr("href").substr($(this).attr("href").lastIndexOf('#') + 1);
6218                    var $brQVDiv = $("div[id=" + $divId + "]");
6219                    var $brQVImg = $brQVDiv.find('img.brRelProd');
6220                    if ($brQVImg.length) {
6221                        $brQVImg.attr('src', $brQVImg.attr('src').replace("/m/", "/e/"));
6222                    }
6223                    $("#quickview-mmenu .quickview").html($brQVDiv.html());
6224                    $("#quickview-mmenu").data("mmenu").open();
6225                    trapFocus($("#quickview-mmenu"));
6226                    validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
6227                    return false;
6228                });
6229            }
6230            else {
6231                $(this).on("click", function (e) {
6232                    e.preventDefault();
6233                    $.ajax({
6234                        url: $(this).attr('href'),
6235                        type: 'GET',
6236                        datatype: "html",
6237                        success: function (result) {
6238                            $("#quickview-mmenu .quickview").html(result);
6239                            $("#quickview-mmenu").data("mmenu").open();
6240                            validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
6241                        }
6242                    });
6243                    return false;
6244                });
6245            }
6246        });
6247
6248        $(el).find(".add-on-quickview:not(.bound)").each(function () {
6249            $(this).removeClass("bound961");
6250            $(this).off("click");
6251            $(this).addClass("bound");
6252            $(this).on("click", function (e) {
6253                e.preventDefault();
6254                $.ajax({
6255                    url: $(this).attr('href'),
6256                    type: 'GET',
6257                    datatype: "html",
6258                    success: function (result) {
6259                        $("#quickview-mmenu .quickview").html(result);
6260                        $("#quickview-mmenu").data("mmenu").open();
6261                        validateAndInitQuickViewForm($("#quickview-mmenu").find('form'));
6262                    }
6263                });
6264                return false;
6265            });
6266        });
6267    }
6268}
6269
6270function hookupQuickviewAda(el) {
6271    var $this = $(el);
6272
6273    //ada compliance...if the quickview has focus make it visible
6274    $this.on('focusin', function () {
6275        $(this).parent().addClass("show");
6276    }).on('focusout', function () {
6277        $(this).parent().removeClass("show");
6278    });
6279
6280    //ada compliance... hide all tab focused quick views when mousing over the parent anchor
6281    //this helps prevent a sticky quick view button
6282    $this.closest(".product-image").on("mouseover", function () {
6283        $("body").find(".products-grid .btn-quickview > button:visible").trigger("blur");
6284    });
6285
6286}
6287
6288function validateAndInitQuickViewForm(quickViewForm) {
6289    truncateQuickViewAdCopy(quickViewForm);
6290    quickViewForm.validate();
6291
6292    //register Notify Me Modal trigger in case quick view is of a product on notify
6293    quickViewForm.find('.notifyBtn').find("a").moby({
6294        'modalClass': 'giveaway-modal',
6295        'ariaLabelText': 'Notify Me',
6296        'onCompleteCallback': function () {
6297        }
6298    });
6299    Gorilla.util.initForms();
6300}
6301
6302function createSiteWidePromoSlickSlider() {
6303    var $ss = $("#site-wide-promos");
6304    $(window).on('load', function () {
6305        if (!$ss.hasClass('slick-initialized') && !$ss.hasClass("checkout-promo")) {
6306            $ss.slick({
6307                slidesToShow: 1,
6308                slidesToScroll: 1,
6309                dots: true,
6310                appendDots: $('#promoBannerDots'),
6311                arrows: false,
6312                infinite: true,
6313                autoplay: true,
6314                autoplaySpeed: 5000
6315            });
6316        } 
6317    });
6318}
6319
6320function destroySiteWidePromoSlickSlider() {
6321    var $ss = $("#site-wide-promos");
6322    if ($ss.hasClass('slick-initialized')) {
6323        $ss.slick('unslick');
6324    }
6325}
6326
6327function bindMobileSearch() {
6328    var $searchMobile = $("#searchMobile");
6329    if ($searchMobile.data("ui-autocomplete") != undefined) {
6330        $searchMobile.autocomplete("destroy");
6331    }
6332
6333    $searchMobile.autocomplete({
6334        appendTo: "#searchSuggestionsMobile",
6335        source: function (request, response) {
6336            getSuggestAheadTerms(request, response);
6337        },
6338        minLength: 3,
6339        delay: 200,
6340        maxItems: 5,
6341
6342        select: function (event, ui) {
6343            $searchMobile.val(ui.item.label);
6344            $("#mobilekform").submit();
6345        },
6346
6347        open: function (event, ui) {
6348            highlightSearchedTerm($(this));
6349        }
6350    });
6351}
6352
6353function bindTabletSearch() {
6354    if ($("#k").data("ui-autocomplete") != undefined) {
6355        $("#k").autocomplete("destroy");
6356    }
6357
6358    $("#k").autocomplete({
6359        appendTo: "#searchSuggestions",
6360        source: function (request, response) {
6361            getSuggestAheadTerms(request, response);
6362        },
6363        minLength: 3,
6364        delay: 200,
6365        maxItems: 10,
6366
6367        select: function (event, ui) {
6368            $("#k").val(ui.item.label);
6369            $("#kform").submit();
6370        },
6371
6372        open: function (event, ui) {
6373            highlightSearchedTerm($(this));
6374        }
6375    });
6376}
6377
6378function bindDesktopSearch() {
6379    if ($("#k").data("ui-autocomplete") != undefined) {
6380        $("#k").autocomplete("destroy");
6381    }
6382
6383    $("#k").autocomplete({
6384        appendTo: "#searchSuggestions",
6385        source: function (request, response) {
6386            getSuggestAheadTerms(request, response);
6387        },
6388        minLength: 3,
6389        delay: 200,
6390        maxItems: 10,
6391
6392        response: function (event, ui) {
6393            $("#searchProducts").css({ display: 'block' });
6394        },
6395
6396        select: function (event, ui) {
6397            $("#k").val(ui.item.label);
6398
6399            $("#kform").submit();
6400        },
6401
6402        close: function (event, ui) {
6403            event.preventDefault();
6404        },
6405
6406        focus: function (event, ui) {
6407        },
6408
6409        open: function (event, ui) {
6410            highlightSearchedTerm($(this));
6411        }
6412    });
6413
6414}
6415
6416function showHideSuggestAhead() {
6417    setTimeout(function () {
6418        if ($("#searchProducts :focus").length === 0) {
6419            $("#searchProducts").css({ display: 'none' });
6420        }
6421    }, 200);
6422}
6423
6424function updateShowMiniCart(html, showSlide) {
6425    if (html && html !== "") {
6426        setCartQuantityText();
6427        var $cartSummary = $("#cartSummary");
6428        setTimeout(function () {
6429            $cartSummary.empty().append(html);
6430            $("#mini-totals").empty().append($cartSummary.find(".mini-totals-container").detach());
6431
6432            var itemCount = $cartSummary.find(".items-in-cart").detach().text();
6433            var cartTotal = $("#mini-cart-total-preview").html();
6434            var fsThreshold = $("#mini-cart-fs-threshold").html();
6435            var cls = $("#mini-cart-total-preview").attr('class');
6436            var division = $("#cart-mmenu").data("division");
6437            $("#cart-mmenu").removeClass("mm-nomap").removeClass("mm-map").removeClass("mm-unset").removeClass("mm-noSavings");
6438            if (itemCount.length) {
6439                $("#cart-mmenu").addClass(cls);
6440                $("#mini-cart-total").html(cartTotal).show();
6441                $("#mini-cart-fs-threshold-ds").html(fsThreshold).show();
6442                $("#mini-count").empty().append(itemCount);
6443                $("#mini-cart-actions").show();
6444                /*$("#cart-mmenu .mm-navbars_top .mm-navbar").css("height", ""); */
6445                if (division == 32) {
6446                    $("#cart-mmenu .mm-navbars_top .mm-navbar").css("height", "");
6447                    $("#cart-mmenu .mm-navbars_top .mm-navbar").addClass("softball-style");
6448                }
6449                else if (division == 31)
6450                {
6451                    $("#cart-mmenu .mm-navbars_top .mm-navbar").css("height", "");
6452                }
6453                $("#cart-mmenu.mm-menu_navbar_top-1 .mm-panels").css("top", "");
6454            } else {
6455                $("#mini-cart-actions").hide();
6456                $("#cart-mmenu").addClass("mm-unset");
6457                $("#mini-count").text("0 items in your cart");
6458                $("#mini-cart-total").hide();
6459            }
6460        }, 500);
6461
6462        if (showSlide) {
6463            dropMiniCart();
6464        }
6465    }
6466}
6467
6468function dropMiniCart() {
6469    //close the quickview slideout if its open
6470    if ($("#quickview-mmenu").length && $("#quickview-mmenu").hasClass("mm-menu_opened")) {
6471        $("#quickview-mmenu").data("mmenu").close();
6472        if (lastFocus) {
6473            lastFocus.focus();
6474        }
6475    }
6476
6477    $quickorderAdd = $("#quickorder-add");
6478    if (!$quickorderAdd.length)
6479        setTimeout(function () {
6480            var mmenuHookup = $("#cart-mmenu").data("mmenu").open();
6481            if (mmenuCloseHookup) {
6482                mmenuCloseHookup = false;
6483                mmenuHookup.bind("close:after", function () {
6484                    callMonetateScripts();
6485                });
6486            }
6487            trapFocus($("#cart-mmenu"));
6488            $("#cart-mmenu").on("click", ".mm-navbars_top", function (e) {
6489                $("#cart-mmenu").data("mmenu").close();
6490            });
6491        }, 500);
6492}
6493
6494function focusOnFirstEl(container) {
6495    var $focusableEl = $(container).find(":focusable").first();
6496    $focusableEl.focus();
6497    $([document.documentElement, document.body]).animate({ scrollTop: $focusableEl.offset().top }, 500);
6498}
6499
6500function removeQueryParameter(key, sourceURL) {
6501    var rtn = sourceURL.split("?")[0],
6502        param,
6503        params_arr = [],
6504        queryString = (sourceURL.indexOf("?") !== -1) ? sourceURL.split("?")[1] : "";
6505    if (queryString !== "") {
6506        params_arr = queryString.split("&");
6507        for (var i = params_arr.length - 1; i >= 0; i -= 1) {
6508            param = params_arr[i].split("=")[0];
6509            if (param === key) {
6510                params_arr.splice(i, 1);
6511            }
6512        }
6513        if (params_arr.length) rtn = rtn + "?" + params_arr.join("&");
6514    }
6515    return rtn;
6516}
6517
6518function monetateClick(recToken) {
6519    if (recToken) {
6520        AjaxJsonPostWrapper.ajaxRoute('monetate', 'monetateclickevent', { recToken: recToken }, function () { });
6521    }
6522    return false;
6523}
6524
6525function algoliaClick(pid, pos, queryid, name) {
6526    var pids = [pid];
6527    var poss = [pos];
6528    AjaxJsonPostWrapper.ajaxRoute('algolia', 'algoliaclickevent', { eventObject: { queryId: queryid, eventName: name, positions: poss, objectIDs: pids } });
6529    return false;
6530}
6531
6532function buildDDLink(type, typeValue, keepNonInternalQuery) {
6533    AjaxJsonPostWrapper.ajaxRoute('main', 'buildplponchangelink', { basePath: document.location.href, type: type, typeValue: typeValue, keepNonInternalQuery: keepNonInternalQuery }, function (result) {
6534        if(result.newUrl)
6535            document.location.href = result.newUrl;
6536    });
6537}
6538
6539function callMonetateScripts() {
6540    var fullMonetateScript = "";
6541
6542    if (window.monetatePageScript && window.monetatePageScript.length) {
6543        fullMonetateScript = window.monetatePageScript;
6544    }
6545
6546    if (window.monetateBreadCrumbScript && window.monetateBreadCrumbScript.length) {
6547        fullMonetateScript = fullMonetateScript + window.monetateBreadCrumbScript;
6548    }
6549
6550    if (window.monetateCartScript && window.monetateCartScript.length) {
6551        fullMonetateScript = fullMonetateScript + window.monetateCartScript;
6552    }
6553
6554    if (window.monetateProductScript && window.monetateProductScript.length) {
6555        fullMonetateScript = fullMonetateScript + window.monetateProductScript;
6556    }
6557
6558    if (window.monetateProductListScript && window.monetateProductListScript.length) {
6559        fullMonetateScript = fullMonetateScript + window.monetateProductListScript;
6560    }
6561
6562    if (fullMonetateScript && fullMonetateScript.length) {
6563        fullMonetateScript = fullMonetateScript + "<script id=\"monetateTrackData\" type=\"text/javascript\"> window.monetateQ.push([\"trackData\"]);<\/script>";
6564        var monetateDiv = $('#monetateAjax');
6565        monetateDiv.empty();
6566        if (monetateDiv && monetateDiv.length) {
6567            monetateDiv.append(fullMonetateScript);
6568        }
6569    }
6570    return false;
6571}
6572
6573function tealiumLinkCall(dataObject) {
6574    if (window?.utag) { //Make sure Tealium is initialized, otherwise will cause JS errors.
6575        //All data in data object should be a string or an array of strings.
6576        //All link calls should include a "tealium_event" key-value pair.
6577
6578        //Checking if "tealium_event" key is defined.
6579        if (!dataObject.tealium_event) {
6580            console.error("No tealium_event defined for the link call. Please define a tealium_event key-value pair.");
6581            return;
6582        }
6583
6584        //Force everything to be strings
6585        var objString = Object.fromEntries(
6586            Object.entries(dataObject).map(([key, value]) => {
6587                if (typeof value === 'object' && value !== null) {
6588                    if (Array.isArray(value)) {
6589                        var newValue = [];
6590                        for (var i = 0; i < value.length; i++) {
6591                            newValue[i] = String(value[i]);
6592                        }
6593                        return [key, newValue];
6594                    }
6595                    console.log('Tealium link() calls do not accept any objects outside of arrays and strings, ommitting object from data set.');
6596                    return [key, ''];
6597                }
6598                return [key, String(value)];
6599            })
6600        );
6601
6602        window.utag.link(objString);
6603        return;
6604    }
6605
6606    console.error("Tealium script was not initialized before link function was called. Please check the timing of the link call.");
6607    return;
6608};

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.