1(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ 2'use strict'; 3 4var _ = require('lodash'); 5var AddressVerificationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper'); 6var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 7 8var options; 9var dataBuffer; 10var templates; 11 12function initialize(optionsParameter, addressData) { 13 options = $.extend({ 14 successCallback: null, 15 errorCallback: null 16 }, optionsParameter); 17 dataBuffer = $.extend({}, addressData); 18 19 if (addressData && addressData.$field && addressData.$form) { 20 templates = {}; 21 templates.container = _.template($('#template-address-autocomplete-container').html(), TemplateConstants.Lodash.Settings); 22 templates.address = _.template($('#template-address-autocomplete-item').html(), TemplateConstants.Lodash.Settings); 23 24 var addressSuggestionsHtml = ''; 25 if (addressData && addressData.InquiryResult && addressData.InquiryResult.suggestions && addressData.InquiryResult.suggestions.length > 0) { 26 for (var addressSuggestionKey in addressData.InquiryResult.suggestions) { 27 var addressSuggestion = addressData.InquiryResult.suggestions[addressSuggestionKey]; 28 addressSuggestionsHtml += templates.address({ Address: buildAddressHtmlFromAddressObject(AddressVerificationHelper.BuildAddressObjectFromAddressAutocompleteSuggestion(addressSuggestion)) }); 29 } 30 } 31 32 var $fieldContainer = addressData.$field.parent(); 33 if ($fieldContainer.find('.address-autocomplete-dialog').length > 0) { 34 $fieldContainer.find('.address-autocomplete-dialog').remove(); 35 } 36 37 var addressSuggestionsContainerHtml = templates.container({ Addresses: addressSuggestionsHtml }); 38 $fieldContainer.prepend(addressSuggestionsContainerHtml); 39 40 addressData.$form.off('click.AddressAutocompleteSelect').on('click.AddressAutocompleteSelect', '.address-autocomplete-dialog li', function(event) { 41 var $this = $(this); 42 43 addressData.$form.find('.address-autocomplete-dialog').remove(); 44 $(document).trigger('SetAddressFromAddressAutocomplete', { 45 $form: addressData.$form, 46 $field: addressData.$field, 47 Address: AddressVerificationHelper.BuildAddressObjectFromAddressAutocompleteSuggestion(addressData.InquiryResult.suggestions[$this.index()]) 48 }); 49 }); 50 51 $(document).off('click.AddressAutocompleteClose').on('click.AddressAutocompleteClose', function(event) { 52 var $target = $(event.currentTarget); 53 54 if ($target.closest('.address-autocomplete-dialog').length == 0) { 55 $('.address-autocomplete-dialog').remove(); 56 } 57 }); 58 } 59} 60 61function buildAddressHtmlFromAddressObject(addressObject) { 62 var addressArray = []; 63 if (addressObject.PrimaryLine) { 64 addressArray[addressArray.length] = addressObject.PrimaryLine; 65 } 66 if (addressObject.City || addressObject.StateCode || addressObject.PostalCode) { 67 var addressLine = ''; 68 if (addressObject.City) { 69 addressLine += addressObject.City + ', '; 70 } 71 if (addressObject.StateCode) { 72 addressLine += addressObject.StateCode; 73 if (addressObject.PostalCode) { 74 addressLine += ' '; 75 } 76 } 77 if (addressObject.PostalCode) { 78 addressLine += addressObject.PostalCode; 79 } 80 81 addressArray[addressArray.length] = addressLine; 82 } 83 84 return addressArray.join('<br/>'); 85} 86 87exports.initialize = initialize; 88},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper":112,"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"lodash":133}],2:[function(require,module,exports){ 89'use strict'; 90 91var _ = require('lodash'); 92var dialog = require('../../dialog'); 93var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 94 95var options; 96var dataBuffer; 97var templates; 98 99function initialize(optionsParameter, addressType, addressData) { 100 options = $.extend({ 101 successCallback: null, 102 continueCallback: null, 103 errorCallback: null 104 }, optionsParameter); 105 dataBuffer = $.extend({}, addressData); 106 templates = {};
107 templates.address = _.template($('#template-address-verification-address').html(), TemplateConstants.Lodash.Settings); 108 109 dialog.open({ 110 html: $('#dialog-address-verification').html(), 111 options: { 112 dialogClass: 'dialog-address-verification', 113 width: 320, 114 draggable: false, 115 resizable: false, 116 open: function(event, ui) { 117 var $this = $(this); 118 var $addresses = $this.find('.addresses'); 119 $addresses.html(''); 120 $this.closest('.ui-dialog').attr('status', dataBuffer.Status); 121 122 var addressRecommendedHtml; 123 if (dataBuffer.Status == 'deliverable' && !dataBuffer.Match) { 124 addressRecommendedHtml = templates.address({ 125 AddressType: addressType, 126 Action: 'recommended', 127 Class: 'selected', 128 Checked: 'checked', 129 Header: 'Recommended Address', 130 Address: buildAddressHtmlFromAddressObject(dataBuffer.AddressVerified) 131 }); 132 } 133 134 var addressEnteredHtml; 135 addressEnteredHtml = templates.address({ 136 AddressType: addressType, 137 Action: 'entered', 138 Class: !addressRecommendedHtml ? 'selected' : '', 139 Checked: !addressRecommendedHtml ? 'checked' : '', 140 Header: 'Address as Entered', 141 Address: buildAddressHtmlFromAddressObject(dataBuffer.AddressOriginal) 142 }); 143 144 if (addressRecommendedHtml) { 145 $addresses.append(addressRecommendedHtml); 146 } 147 if (addressEnteredHtml) { 148 $addresses.append(addressEnteredHtml); 149 } 150 151 $this.find('.address-type').text(addressType); 152 $this.find('h3:visible').focus(); // ADA compliance - add focus to first element in modal to help screen readers 153 154 $this.off('click.AddressSelect').on('click.AddressSelect', '.address-container .radio-large', function(event) { 155 event.preventDefault(); 156 var $addressContainer = $(this).closest('.address-container'); 157 158 $this.find('.address-container').removeClass('selected'); 159 $addressContainer.addClass('selected'); 160 $addressContainer.find('input').prop('checked', true); 161 }); 162 163 $this.off('click.AddressUse').on('click.AddressUse', '.address-use', function(event) { 164 event.preventDefault(); 165 var addressToUse = $(this).closest('.address-container').find('input').val(); 166 var addressObject; 167 if (addressToUse == 'recommended') { 168 addressObject = dataBuffer.AddressVerified; 169 } else if (addressToUse == 'entered') { 170 addressObject = dataBuffer.AddressOriginal; 171 } 172 173 if (addressObject) { 174 $(document).trigger('SetAddressFromAddressVerification', $.extend(addressObject, { $form: options.$form, AddressType: addressType })); 175 } 176 $this.dialog('close'); 177 if (options.successCallback && typeof options.successCallback == 'function') { 178 options.successCallback(options.$form); 179 } 180 }); 181 182 $this.off('click.AddressContinue').on('click.AddressContinue', '.address-continue', function(event) { 183 event.preventDefault(); 184 $(document).trigger('SetAddressFromAddressVerification', $.extend(dataBuffer.AddressOriginal, { $form: options.$form, AddressType: addressType })); 185 $this.dialog('close'); 186 if (options.continueCallback && typeof options.continueCallback == 'function') { 187 options.continueCallback(options.$form); 188 } 189 }); 190 191 $this.off('click.AddressEdit').on('click.AddressEdit', '.address-edit', function(event) { 192 event.preventDefault(); 193 $this.dialog('close'); 194 var $focusElement = $('#billingAddressForm').find('input[name="dwfrm_billingaddress_address1"]'); 195 if (addressType == 'shipping') { 196 $focusElement = $('#shippingAddressForm').find('input[name="dwfrm_shippingaddress_address1"]'); 197 } 198 $focusElement.focus(); 199 }); 200 }, 201 close: function(event, ui) { 202 var $this = $(this); 203 $this.off('click.SelectAddress'); 204 $this.off('click.UseEnteredAddress'); 205 $this.off('click.UseRecommendedAddress'); 206 $this.off('click.EditShippingAddress'); 207 } 208 } 209 }); 210} 211 212function buildAddressHtmlFromAddressObject(addressObject) { 213 var addressArray = []; 214 if (addressObject.PrimaryLine) { 215 addressArray[addressArray.length] = addressObject.PrimaryLine; 216 } 217 if (addressObject.SecondaryLine) { 218 addressArray[addressArray.length] = addressObject.SecondaryLine; 219 } 220 if (addressObject.City || addressObject.StateCode || addressObject.PostalCode) { 221 var addressLine = ''; 222 if (addressObject.City) { 223 addressLine += addressObject.City + ', '; 224 } 225 if (addressObject.StateCode) { 226 addressLine += addressObject.StateCode;
227 if (addressObject.PostalCode) { 228 addressLine += ' '; 229 } 230 } 231 if (addressObject.PostalCode) { 232 addressLine += addressObject.PostalCode; 233 } 234 235 addressArray[addressArray.length] = addressLine; 236 } 237 238 return addressArray.join('<br/>'); 239} 240 241exports.initialize = initialize; 242},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../dialog":36,"lodash":133}],3:[function(require,module,exports){ 243'use strict'; 244 245var progress = require('./progress'), 246 util = require('./util'); 247 248var currentRequests = []; 249 250/** 251 * @function 252 * @description Ajax request to get json response 253 * @param {Boolean} async Asynchronous or not 254 * @param {String} url URI for the request 255 * @param {Object} data Name/Value pair data request 256 * @param {Function} callback Callback function to be called 257 */ 258var getJson = function (options) { 259 options.url = util.toAbsoluteUrl(options.url); 260 // return if no url exists or url matches a current request 261 if (!options.url || currentRequests[options.url]) { 262 return; 263 } 264 265 currentRequests[options.url] = true; 266 267 // make the server call 268 $.ajax({ 269 dataType: 'json', 270 url: options.url, 271 async: (typeof options.async === 'undefined' || options.async === null) ? true : options.async, 272 data: options.data || {} 273 }) 274 // success 275 .done(function (response) { 276 if (options.callback) { 277 options.callback(response); 278 } 279 }) 280 // failed 281 .fail(function (xhr, textStatus) { 282 if (textStatus === 'parsererror') { 283 window.alert(Resources.BAD_RESPONSE); 284 } 285 if (options.callback) { 286 options.callback(null); 287 } 288 }) 289 // executed on success or fail 290 .always(function () { 291 // remove current request from hash 292 if (currentRequests[options.url]) { 293 delete currentRequests[options.url]; 294 } 295 }); 296}; 297/** 298 * @function 299 * @description ajax request to load html response in a given container 300 * @param {String} url URI for the request 301 * @param {Object} data Name/Value pair data request 302 * @param {Function} callback Callback function to be called 303 * @param {Object} target Selector or element that will receive content 304 */ 305var load = function (options) { 306 options.url = util.toAbsoluteUrl(options.url); 307 // return if no url exists or url matches a current request 308 if (!options.url || currentRequests[options.url]) { 309 return; 310 } 311 312 currentRequests[options.url] = true; 313 314 // make the server call 315 $.ajax({ 316 dataType: 'html', 317 url: util.appendParamToURL(options.url, 'format', 'ajax'), 318 data: options.data, 319 xhrFields: { 320 withCredentials: true 321 } 322 }) 323 .done(function (response) { 324 // success 325 if (options.target) { 326 $(options.target).empty().html(response); 327 } 328 if (options.callback) { 329 options.callback(response); 330 } 331 }) 332 .fail(function (xhr, textStatus) { 333 // failed 334 if (textStatus === 'parsererror') { 335 window.alert(Resources.BAD_RESPONSE); 336 } 337 options.callback(null, textStatus); 338 }) 339 .always(function () { 340 progress.hide(); 341 // remove current request from hash 342 if (currentRequests[options.url]) { 343 delete currentRequests[options.url]; 344 } 345 }); 346}; 347 348exports.getJson = getJson; 349exports.load = load; 350 351},{"./progress":86,"./util":102}],4:[function(require,module,exports){ 352'use strict'; 353 354/** 355 * @function 356 * @description Initializes the alert widget 357 */ 358exports.init = function(options) { 359 var type = options.type ? options.type : 'alert-primary'; 360 var timer = options.timer ? options.timer : 5000; 361 var alertElement = '<div class="alert ' + type + '"><div class="alert-content">' + options.content + '</div></div>'; 362 363 $('body').append(alertElement).fadeIn('slow'); 364 365 if (timer >= 0) { 366 var alertTimer = setTimeout(function() { 367 $('.alert').fadeOut('slow').remove(); 368 }, timer); 369 } 370 371 $('body').on('click', '.alert', function() { 372 $(this).fadeOut('slow').remove(); 373 }); 374}; 375 376},{}],5:[function(require,module,exports){ 377/**
378 * (c) 2009-2014 Demandware Inc. 379 * Subject to standard usage terms and conditions 380 * For all details and documentation: 381 * https://bitbucket.com/demandware/sitegenesis 382 */ 383 384'use strict'; 385 386var countries = require('./countries'), 387 dialog = require('./dialog'), 388 minicart = require('./minicart'), 389 page = require('./page'), 390 rating = require('./rating'), 391 searchplaceholder = require('./searchplaceholder'), 392 //tooltip = require('./tooltip'), 393 util = require('./util'), 394 validator = require('./validator'), 395 tls = require('./tls'), 396 TPromise = require('promise'), 397 ajax = require('./ajax'), 398 rotate3d = require('./productRotate3d.js'), 399 count_down = require('./countdown'), 400 lazyloadPageElements = require('./lazyloadPageElements'), 401 notification = require('./components/Notification'), 402 navigation = require('./components/NavigationController'), 403 emailForm = require('./components/EmailForm'), 404 slickHelpers = require('./slickSliderHelpers'), 405 quantityStepper = require('./quantityStepper'), 406 wishlist = require('./wishlist'), 407 loginDialog = require('./loginDialog'), 408 register = require('./register'), 409 alert = require('./alert'), 410 Globale = require('./components/Globale'), 411 searchbar = require('./searchbar'), 412 sliders = require('./sliders'), 413 cordialTagging = require('./components/CordialTagging'); 414 415var login = {}; 416if (window.SiteID === 'bootbarn_workforce_us') { 417 login = require('../../../app_storefront_workforce/cartridge/js/login'); 418} else { 419 login = require('./login'); 420} 421 422var EmailSignup = require('./components/EmailSignup'); 423var giftCardBalanceInquiryHelper = require('./helpers/GiftCardBalanceInquiryHelper'); 424var GoogleTagManagerClient = require('../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 425var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 426 427// if jQuery has not been loaded, load from google cdn 428if (!window.jQuery) { 429 var s = document.createElement('script'); 430 s.setAttribute('src', 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'); 431 s.setAttribute('type', 'text/javascript'); 432 document.getElementsByTagName('head')[0].appendChild(s); 433} 434 435require('./jquery-ext')(); 436require('./cookieprivacy')(); 437require('./captcha')(); 438require('./watermark')(); 439 440var dataBuffer = {}; 441var siteName; 442 443var $sliderMobile; 444var $navSecondary; 445var $navUtilities; 446var $navUl; 447var $topBannerBar; 448var $topBannerBarInner; 449var $navigation; 450var $topBannerInnerLinks; 451var $selectSort; 452var $secondaryHead; 453var $searchResultContainer; 454var $productContainerImage; 455var $productDetail; 456var $sectionCheckout; 457var $mainInnerAlt; 458var $sectionErrorFigure; 459var $sectionErrorBox; 460var $footerMenuItems; 461var $promoMessages; 462 463function initializeEvents() { 464 notification.initialize(); 465 var controlKeys = ['8', '13', '46', '45', '36', '35', '38', '37', '40', '39']; 466 var $win = $(window); 467 var $doc = $(document); 468 $doc.on('app.resize', function () { 469 resizeDeviceHelper(); 470 }); 471 $win.on('load resize', function () { 472 resizeDeviceHelper(); 473 }); 474 475 $(document).off('CategoryHeaderSliders.Initialize').on('CategoryHeaderSliders.Initialize', function(event) { 476 sliders.initializeCategorySliders('.cat-header-content.cat-header-slider:not(.slick-initialized)'); 477 }); 478 479 $(document).off('PostAjaxAuthenticationActions.Initialize').on('PostAjaxAuthenticationActions.Initialize', function(event, options) { 480 var data = options.results; 481 var isAccountDialog = options.isAccountDialog; 482 if (isAccountDialog) { 483 var customerFirstName = data.customerFirstName ? ', ' + data.customerFirstName + '.' : '.'; 484 var alertMessage; 485 if (options.displayMessage == 'login') { 486 alertMessage = 'Welcome back' + customerFirstName; 487 } 488 if (options.displayMessage == 'register') { 489 alertMessage = 'Thanks for creating an account' + customerFirstName; 490 } 491 492 if (SitePreferences.WISHLIST_ENABLED) { // Future-forward: in case we ever implement login/register dialogs other than with wishlist 493 /**** Wishlist icon updates ****/ 494 var wishlistItems = data.controllerResults && data.controllerResults.allWishlistItems ? data.controllerResults.allWishlistItems : data.allWishlistItems ? data.allWishlistItems : null; 495 var returnedResult = data.controllerResults && data.controllerResults.result ? data.controllerResults.result : data.result ? data.result : null; 496 if (wishlistItems != null) { 497 window.localStorage.WishlistProductIDs = JSON.stringify(wishlistItems); 498 wishlist.renderAllWishlistButtons(); 499 if (returnedResult == 'complete') { 500 alertMessage += ' This item is already saved to your Wishlist.'; 501 } else { 502 alertMessage += ' An item has been added to your Wishlist.'; 503 } 504 } 505 } 506 507 /**** Selected store updates ****/ 508 var storeFromProfile = data.storeFromProfile ? data.storeFromProfile : null; 509 var addToCartOptionsStoreId = $('.bopis-add-to-cart-options-store-selector .selected-store').length > 0 ? $('.bopis-add-to-cart-options-store-selector .selected-store').attr('store-id') : null; 510 var navStoresDropdownStoreId = $('.stores-dropdown .current-store .map.store').length > 0 ? $('.stores-dropdown .current-store .map.store').attr('data-id') : null; 511 var storeID; 512 513 var isProductPage = $('.pt_product-details').length; 514 var isCategory = $('.pt_product-search-result').length; 515 if (isProductPage) { 516 storeID = addToCartOptionsStoreId ? addToCartOptionsStoreId : storeFromProfile ? storeFromProfile : null; 517 if (storeID) { 518 // Redraw the "My Store" piece on the PDP 519 $(document).trigger('Bopis.StoreSearch.Select', storeID); 520 } 521 } 522 if (isCategory) { 523 storeID = navStoresDropdownStoreId ? navStoresDropdownStoreId : storeFromProfile ? storeFromProfile : null; 524 } 525 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 526 if (isCategory) { 527 if (storeID) { 528 // Make sure to update the store number in customer profile when on the PLP 529 $(document).trigger('Bopis.AssignStoreToProfile', storeID); 530 } 531 } 532 if (storeID) { 533 // Redraw the selected store pieces in nav, Shop Your Store on PLP, My Account store drop-down, and store search modal 534 $(document).trigger('Bopis.SelectedStore.Refresh', storeID); 535 } 536 } 537 538 /**** Minicart update ****/ 539 if (data.cartQuantity) { 540 var $miniCartElm = $('.mini-cart .minicart-quantity').length > 0 ? $('.mini-cart .minicart-quantity') : $('.mini-cart .btn-minicart .btn-minicart-qty'); 541 $miniCartElm.html(data.cartQuantity); 542 } 543 544 /**** My Account navigation update ****/ 545 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 546 $('.login-dropdown .user-panel .form-login').addClass('d-none'); 547 $('.login-dropdown .login-dropdown-customer-menu').removeClass('d-none'); 548 } else { 549 var profileName = data.customerFirstName ? ' ' + data.customerFirstName : ''; 550 $('.mobile-account-main.first-name a').first().find('span').html('Hello' + profileName); 551 } 552 553 /**** Client Window > Customer object update ****/ 554 Customer.authenticated = true; 555 Customer.registered = true; 556 557 /**** Close the account dialog ****/ 558 dialog.close(); 559 560 /**** Show the alert ****/ 561 alert.init({ 562 type: 'alert-primary', 563 timer: 3000, 564 content: alertMessage 565 }); 566 } else { 567 window.location.href = data.registerDialogContinueUrl ? data.registerDialogContinueUrl : data.loginDialogContinueUrl ? data.loginDialogContinueUrl : location.reload(); 568 } 569 }); 570 571 // Dom-Ready Sliders 572 sliders.init('.barn-slider', {dots: false, breakpoints: {0: {slidesToShow: 1}, 1024: {slidesToShow: 2}}}); 573 sliders.init('.content-tiles-slider.has-slider .row', {spaceBetween: 2, loop: false, dots: false, breakpoints: {0: {slidesToShow: 1.5}, 768: {slidesToShow: 3}}}); 574 sliders.init('.brands-slider.has-slider.slider-mobile-overflow .row', {spaceBetween: 40, loop: false, dots: false, breakpoints: {0: {slidesToShow: 2.5}, 768: {slidesToShow: 6}}}); 575 sliders.init('.store-offerings-slider.has-slider .row', {spaceBetween: 20, loop: false, dots: false, breakpoints: {0: {slidesToShow: 2}, 768: {slidesToShow: 4}}}); 576 sliders.init('.store-ads-slider.has-slider .row', {spaceBetween: 10, loop: false, dots: false, breakpoints: {0: {slidesToShow: 1.5}, 768: {slidesToShow: 3}}}); 577 sliders.init('.einstein-product-recos-slider.has-slider .row', {spaceBetween: 20, loop: false, dots: false, breakpoints: {0: {slidesToShow: 2}, 768: {slidesToShow: 4}}}); 578 sliders.init('.single-hero-slider.has-slider .row', {spaceBetween: 0, loop: false, dots: false, breakpoints: {0: {slidesToShow: 1}, 768: {slidesToShow: 1}}}); 579 sliders.init('.content-tiles-m2-slider.has-slider .row', {spaceBetween: 2, loop: false, dots: false, breakpoints: {0: {slidesToShow: 2}, 768: {slidesToShow: 3}}}); 580 sliders.init('.collections-content.has-slider .curated', {loop: false, dots: false, breakpoints: {0: {slidesToShow: 1}, 768: {slidesToShow: 3}}}); 581 sliders.init('.section-offers.tiles .section-body', {dots: false, breakpoints: {0: {slidesToShow: 1}, 480: {slidesToShow: 3}, 768: {slidesToShow: 4}}}); 582 sliders.init('.section-offers.section-brands .brand-list', {dots: false, breakpoints: {0: {slidesToShow: 4}, 480: {slidesToShow: 3}, 768: {slidesToShow: 6}}}); 583 sliders.init('.pt_storefront .product-recommendations-sfcc .slider-products-primary .slides:not(.slick-slider):not(.swiper-full-wrapper):has(li)', {dots: false, breakpoints: {0: {slidesToShow: 1}, 480: {slidesToShow: 3}, 768: {slidesToShow: 4}}}); 584 sliders.init('.product-banner-slots-carousel.swiper .swiper-wrapper', {dots: false, loop: false, breakpoints: {0: {slidesToShow: 1}, 768: {slidesToShow: 1}}}); 585 586 // Tabbed Sliders
587 if ($('.tabbed-slider').length > 0) { 588 var $tabbedSlidersParent = $('<div class="tabbed-sliders-container"></div>'); 589 var $tabbedButtons = $('<div class="slider-panel-buttons"></div>'); 590 591 $('.tabbed-slider').each(function(i, slider) { 592 var $tabbedSlider = $(slider); 593 var $header = $tabbedSlider.find('.section-head'); 594 var $button = $tabbedSlider.find('.slider-panel-btn'); 595 var $panel = $tabbedSlider.find('.section-body'); 596 var isFeatured = $tabbedSlider.attr('data-tab-featured'); 597 598 if (isFeatured == 'true') { // Slot attribute that allows Site Managers to select a default tab to show on render 599 $button.addClass('slider-panel-btn-active'); 600 $panel.addClass('slider-panel-active'); 601 } 602 if (i == 0) { 603 $tabbedSlidersParent.insertBefore($tabbedSlider); 604 $tabbedSlidersParent.append($header).append($tabbedButtons); 605 } 606 $tabbedButtons.append($button); 607 $tabbedSlidersParent.append($tabbedSlider); 608 }); 609 if ($('.slider-panel-active').length <= 0) { // If Site Managers didn't select a default tab to show, go ahead and activate the first tab 610 var $activateTab = $('.tabbed-slider').first(); 611 $activateTab.find('.slider-panel-btn').addClass('slider-panel-btn-active'); 612 $activateTab.find('.section-body').addClass('slider-panel-active'); 613 } 614 initTabPanels(); 615 } 616 617 $('.pt_storefront .product-recommendations-sfcc .accordion-head').addClass('active'); 618 $('.pt_storefront .product-recommendations-sfcc .accordion-body').show(); 619 620 if ($(document).find('.jumbotron-mobile').length > 0 && window.innerWidth <= 767) { 621 var jumbotronExpandedCookie = getCookie('jumbotronExpandedCookie'); 622 if (jumbotronExpandedCookie == 'true' && $('#jumbotron-current-offers-icon').hasClass('fa-angle-down')) { 623 $('.jumbotron-mobile').toggleClass('active'); 624 $('#jumbotron-current-offers-icon').removeClass('fa-angle-down'); 625 $('#jumbotron-current-offers-icon').addClass('fa-angle-up'); 626 } else if(jumbotronExpandedCookie == 'false' && $('#jumbotron-current-offers-icon').hasClass('fa-angle-up')) { 627 $('.jumbotron-mobile').toggleClass('active'); 628 $('#jumbotron-current-offers-icon').removeClass('fa-angle-up'); 629 $('#jumbotron-current-offers-icon').addClass('fa-angle-down'); 630 } 631 } 632 633 if(window.innerWidth > 767 ) { 634 $('.mobile-only .guest-checkout-form').remove(); 635 $('.mobile-only .auto-checkout-form').remove(); 636 } else { 637 $('.mobile-hidden .guest-checkout-form').remove(); 638 $('.mobile-hidden .auto-checkout-form').remove(); 639 } 640 641 $('#guest_checkout_optin:checkbox').change(function() { 642 if ($('#guest_checkout_optin').prop("checked")) { 643 $('.optin-input').addClass('checked'); 644 } else { 645 $('.optin-input').removeClass('checked'); 646 } 647 }); 648 649 $('#auto_checkout_optin:checkbox').change(function() { 650 if ($('#auto_checkout_optin').prop("checked")) { 651 $('.optin-input').addClass('checked'); 652 } else { 653 $('.optin-input').removeClass('checked'); 654 } 655 }); 656 657 $('#checkout_email_optin:checkbox').change(function() { 658 if ($('#checkout_email_optin').prop("checked")) { 659 $('.optin-input').addClass('checked'); 660 } else { 661 $('.optin-input').removeClass('checked'); 662 } 663 }); 664 665 //rewards auto-enrollment points earned message 666 if ($(document).find('.pt_order-confirmation').length > 0) { 667 var orderTotal = $('.order-total').text().replace('$',''); 668 var earnedPoints = Math.round(orderTotal); 669 $('span.rewardsEarnedPoints').text(earnedPoints); 670 } 671 672 // selected states for account navigation 673 if ($(document).find('.pt_account, .pt_order, .pt_customer-service, .pt_wish-list').length > 0) { 674 var currentPage = window.location.origin + window.location.pathname; 675 var isOnTopLevelPage = false; 676 $('#secondary nav a') 677 .removeClass('is-active') 678 .each(function(index, value) { 679 if (value.href === currentPage) { 680 $(this).addClass('is-active'); 681 isOnTopLevelPage = true; 682 } 683 }); 684 if (!isOnTopLevelPage) { 685 $('#secondary nav a').each(function(index, value) { 686 if (value.href === document.referrer) { 687 $(this).addClass('is-active'); 688 } 689 }); 690 } 691 } 692 693 // ---------------- ADA Fixes ------------------- 694 // Slick slider fixes 695 $(document).trigger('SlickSliderAccessibilityMods'); 696 // Vendor fixes 697 var adaTagIntervalCounter = 0; 698 var adaTagInterval = setInterval(function(){ 699 if (!$('img[src*="arttrk.com"]').is('[alt]')) { 700 $('img[src*="arttrk.com"]').attr('alt','Tracking pixel'); 701 } 702 if (!$('#fileUploadForm input#fileSelector').is('[aria-label]')) { 703 $('#fileUploadForm input#fileSelector').attr('aria-label', 'Select file to upload'); 704 } 705 if (adaTagIntervalCounter > 9 || ($('img[src*="arttrk.com"]').is('[alt]') && $('#fileUploadForm input#fileSelector').is('[aria-label]'))) { 706 clearInterval(adaTagInterval); 707 } 708 adaTagIntervalCounter++; 709 }, 1000); // 1000 ms = start after 1sec 710 711 $(document).ready(function() { 712 $('#g-recaptcha-response').attr('tabindex','-1'); 713 }); 714 715 $(document).off('click.ShippingWarnings').on('click.ShippingWarnings','.shipping-warnings .shipping-warning-button', function(e) { 716 var $button = $(this); 717 if ($button.hasClass('shipping-warning-button-closed')) { 718 $button.removeClass('shipping-warning-button-closed').addClass('shipping-warning-button-open').attr('aria-expanded','true'); 719 $button.siblings('ul.shipping-warning-product-items').show(); 720 } else if ($button.hasClass('shipping-warning-button-open')) { 721 $button.removeClass('shipping-warning-button-open').addClass('shipping-warning-button-closed').attr('aria-expanded','false'); 722 $button.siblings('ul.shipping-warning-product-items').hide(); 723 } 724 }); 725 726 // Skip link for product recommendations container 727 $(document).off('click.Skip.Recommendations').on('click.Skip.Recommendations','.skip-product-recommendations-container', function(e) { 728 $(this).siblings('.product-recommendations-container-dive').focus(); 729 }); 730 731 732 $(document).off('click.Zoom.Skip.Section').on('click.Zoom.Skip.Section','.product-image-container-mobile .skip-to-next', function(e) { 733 e.preventDefault(); 734 var isSkipToWishlistButton = $(this).attr('href').indexOf('pdp-wishlist-button-container') > -1; 735 if (isSkipToWishlistButton) { 736 $('#pdp-wishlist-button-container .wishlist-item-status-button').addClass('focus-visible-indicator').focus(); 737 } else { 738 window.location = $(this).attr('href'); 739 } 740 }); 741 742 // --- Initialize Events: ADA Compliance Keyboard Tab Visual Indicator --- 743 $(document).on('keyup', function (event) { 744 if (event.which === SiteConstants.KeyCodes.Tab) { 745 $(':focus').addClass('focus-visible-indicator'); 746 if ($(':focus').hasClass('visually-hidden')) { 747 // Get the innards of the current focus element and copy them into the hidden-element-memo that is then prepended to the <body> 748 var htmlText = $(':focus').html(); 749 var $hiddenElementMemo = $('<div/>', {"class": "hidden-element-memo"}).html(htmlText); 750 $('body').prepend($hiddenElementMemo); 751
752 // Clear memo after 3 seconds if it has not already been cleared 753 setTimeout(function() { 754 $('.hidden-element-memo').remove(); 755 }, 3000); // 3000 ms = start after 1sec 756 } 757 } 758 }).on('keydown keypress mousemove', function (event) { 759 $('.focus-visible-indicator').removeClass('focus-visible-indicator'); 760 $('.hidden-element-memo').remove(); 761 }); 762 763 $(document).on('init.Slider.Aria', '.slider', function(event, slick) { 764 $(this).find('.slick-list').removeAttr('aria-live'); 765 }).on('click.Slider.Aria keyup.Slider.Aria', function(event) { 766 if (event.target.matches('.slider, .slider *')) { 767 if (!$(event.target).closest('.slider').find('.slick-list').attr('aria-live')) { 768 $(event.target).closest('.slider').find('.slick-list').attr('aria-live', 'polite'); 769 } 770 } else { 771 $('.slider').find('.slick-list').removeAttr('aria-live'); 772 } 773 }); 774 775 $.fn.hasAttr = function(name) { 776 return this.attr(name) !== undefined; 777 }; 778 779 function CheckloginCreate() { 780 var loginCreateCount = $(".login-create-account").length; 781 if(loginCreateCount == 0) { 782 $(".order-confirmation-details").addClass("fullWidth"); 783 }else { 784 $(".order-confirmation-details").removeClass("fullWidth"); 785 } 786 } 787 788 // birthday month has to be selected first 789 // which then adjusts the day options 790 // BB registration form and my account page 791 $(document).ready(function() { 792 var $birthdayForm = $('#dwfrm_rewardsregistration'); 793 if ($('#dwfrm_birthday').length >= 1 ){ 794 var $birthdayForm = $('#dwfrm_birthday'); 795 } 796 797 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').prop('disabled', true); 798 var longMonths = ['1','3','5','7','8','10','12']; 799 var febMonth = '2'; 800 $birthdayForm.on('change', 'select#dwfrm_rewardsregistration_rewardscustomer_birthday_month', function(e) { 801 $('.birthday.day').removeClass('disabled'); 802 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').find('option:selected').prop('selected', false); 803 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day .select-option').prop('disabled', false); 804 var monthVal = $('#dwfrm_rewardsregistration_rewardscustomer_birthday_month').val(); 805 if ($.inArray(monthVal, longMonths) === -1) { 806 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day .select-option[value="31"]').prop('disabled', true); 807 if (monthVal == febMonth){ 808 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day .select-option[value="30"]').prop('disabled', true); 809 } 810 } 811 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').prop('disabled', false); 812 }); 813 }); 814 815 // set customer birthday 816 $(document).on('click','#dwfrm_birthday button.confirm', function(event){ 817 event.preventDefault(); 818 var email = $('.credential-list--email').text().trim(); 819 var birthdayField = $('#dwfrm_birthday'); 820 var birthmonth = birthdayField.find('.birthday.month select'); 821 var birthday = birthdayField.find('.birthday.day select'); 822 var year = '1976'; 823 var month, day, birthdate; 824 825 if (!birthmonth.val()) { 826 birthmonth.addClass('error-red'); 827 } else { 828 birthmonth.removeClass('error-red'); 829 month = birthmonth.find("option:selected").text(); 830 } 831 832 if (!birthday.val()) { 833 birthday.addClass('error-red'); 834 } else { 835 birthday.removeClass('error-red'); 836 day = birthday.find("option:selected").text(); 837 } 838 839 if (birthdayField.find('.error-red').length > 0){ 840 return; 841 } 842 843 birthdate = month + '/' + day; 844 845 $.ajax({ 846 type: 'post', 847 url: Urls.setBirthday, 848 contentType: 'application/json', 849 data: JSON.stringify({ 850 email: email, 851 month: month, 852 day: day, 853 year: year 854 }), 855 success: function (data) { 856 $('#dwfrm_birthday').remove(); 857 $('.credential-list--birthdate').text(birthdate); 858 859 if(SitePreferences.CORDIAL_ENABLED){ 860 var auth_data = { 861 email: email 862 } 863 var contact_data = { 864 'channels': { 865 'email': { 866 'address': email 867 } 868 }, 869 'birthday': birthdate + '/' + year 870 }; 871 872 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 873 crdl('contact', auth_data, contact_data); 874 } 875 } 876 } 877 }); 878 }); 879 880 if(siteName == SiteConstants.SiteIds.BootBarnUS && SitePreferences.PINTEREST_ENABLED){ 881 if ($(document).find('.pt_product-details').length > 0) { 882 setTimeout(function(){ 883 var thisItem = JSON.parse($('.productCardMetadata.pdp-browse').attr('data-product-gtm-json')); 884 var productID = thisItem["id"]; 885 var dateTime = Math.floor(Date.now() / 1000); 886 var eventID = 'pdp-' + productID + '-' + dateTime; 887 888 pintrk('track', 'pagevisit', { 889 event_id: eventID, 890 line_items: [ 891 { 892 product_name: thisItem["name"].replace(/\\/g, ""), 893 product_id: productID, 894 product_category: thisItem["category"].replace(/\\/g, ""), 895 product_price: thisItem["price"], 896 product_brand: thisItem["brand"] 897 } 898 ] 899 }); 900 }, 3000); 901 } 902 903 // checkout event created on confirmation
904 if ($(document).find('.order-confirmation-details').length > 0) { 905 var orderID = $('.orderdetails .sectionheader h3').text().replace('Order Number:','').trim(); 906 var dateTime = Math.floor(Date.now() / 1000); 907 var eventID = 'checkout-' + orderID + '-' + dateTime; 908 var currency = 'USD'; 909 910 var items = []; 911 $('.order-item').each(function(index, el) { 912 var _this = $(this); 913 items[index] = {}; 914 _this.find('.productCardMetadata').each(function(key, v) { 915 var thisItem = JSON.parse($(this).attr('data-product-gtm-json')); 916 var currency = thisItem["currency"]; 917 var product = {}; 918 product.product_name = thisItem["id"]; 919 product.product_variant_id = thisItem["skuid"]; 920 product.product_name = thisItem["name"].replace(/\\/g, ""); 921 product.product_brand = thisItem["brand"]; 922 product.product_quantity = thisItem["quantity"]; 923 product.product_price = thisItem["price"]; 924 items[index]= product; 925 }); 926 }); 927 928 pintrk('track', 'checkout', { 929 event_id: eventID, 930 value: parseFloat($('.orderdetails .total .order-total').text().replace('$','')).toFixed(2), 931 order_quantity: Math.round($('.orderdetails span.item-count').data('count')), 932 currency: currency, 933 order_id: orderID, 934 line_items: items 935 }); 936 } 937 } 938 939 // CORDIAL ACCOUNT SIGN-UP, BROWSE, CART, ORDER 940 if(SitePreferences.CORDIAL_ENABLED){ 941 // homepage browse 942 if ($(document).find('[content-slot-id="homepage-01"]').length > 0) { 943 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 944 crdl('event', 'homepage_browse'); 945 } 946 } 947 948 // plp browse 949 if ($(document).find('.pt_product-search-result').length > 0) { 950 var maxTiles = 10; 951 var products = []; 952 $('.product-tile').each(function(i) { 953 if (i < maxTiles) { 954 var product = $(this).attr('data-itemid'); 955 products.push(product); 956 } 957 }); 958 959 var properties = { 960 "category": $('#categoryTitle').text().replace(/\\/g, "").trim(), 961 "url": $(location).attr("href").split("?utm")[0].split("#utm")[0].split("&utm")[0], 962 "products": products 963 }; 964 965 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 966 crdl('event', 'category_browse', properties); 967 } 968 } 969 970 // pdp browse 971 if ($(document).find('.pt_product-details').length > 0) { 972 setTimeout(function(){ 973 var thisItem = JSON.parse($('.productCardMetadata.pdp-browse').attr('data-product-gtm-json')); 974 var images = []; 975 $('.product-primary-image [class*="-slide"]').each(function () { 976 var image = $(this).find('a').attr('href'); 977 if (!image || image == undefined || image == null) { 978 image = $(this).find('img').attr('src'); 979 } 980 if (images.indexOf(image) === -1) { 981 images.push(image); 982 } 983 }); 984 985 var properties = { 986 "productID": thisItem["id"], 987 "productName": thisItem["name"].replace(/\\/g, ""), 988 "category": thisItem["category"].replace(/\\/g, ""), 989 "price": thisItem["price"], 990 "images": images, 991 "url": $(location).attr("href").split("?utm")[0].split("#utm")[0].split("&utm")[0], 992 "attr": { 993 "manufacturer": thisItem["brand"] 994 }, 995 }; 996 997 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 998 crdl('event', 'product_browse', properties); 999 } 1000 }, 3000); 1001 } 1002 1003 // add Cordial contact from checkout 1004 $('#submitBilling').on('click', function(e){ 1005 e.preventDefault(); 1006 if ($('.bill-address-fields .field.error').length == 0) { 1007 var email = $('#dwfrm_billingaddress_email').val().trim(); 1008 var firstName = $('#dwfrm_billingaddress_firstName').val(); 1009 var lastName = $('#dwfrm_billingaddress_lastName').val(); 1010 var phone = $('#dwfrm_billingaddress_phone').val(); 1011 var zip = $('#dwfrm_billingaddress_postal').val(); 1012 var country = $('#dwfrm_billingaddress_country').val(); 1013 var state = $('#dwfrm_billingaddress_states_state').val(); 1014 var city = $('#dwfrm_billingaddress_city').val(); 1015 1016 if ($('input#newslettersignup').is(':checked')){ 1017 var auth_data = { 1018 email: email 1019 } 1020 var contact_data = { 1021 'channels': { 1022 'email': { 1023 'address': email, 1024 'subscribeStatus': 'subscribed' 1025 } 1026 }, 1027 'first_name': firstName, 1028 'last_name': lastName, 1029 'phone': phone, 1030 'postal_code': zip, 1031 'signup_source': 'checkout', 1032 'welcome_signup': true, 1033 'geo_location': { 1034 'postal_code': zip, 1035 'country': country, 1036 'state': state, 1037 'city': city 1038 } 1039 }; 1040 1041 var properties = { 1042 "signup_source": 'checkout', 1043 "welcome_signup": true 1044 }; 1045 1046 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 1047 crdl([ 1048 ['contact', auth_data, contact_data], 1049 ['event', 'email_signup', properties] 1050 ]); 1051 } 1052 } 1053 } 1054 }); 1055 1056 // update Cart when qty change or removal in cart 1057 function cordialUpdateCart() { 1058 setTimeout(function(){ 1059 var items = []; 1060 $('.order-item').each(function(index, el) { 1061 var _this = $(this); 1062 items[index] = {}; 1063 _this.find('.productCardMetadata').each(function(key, v) { 1064 var thisItem = JSON.parse($(this).attr('data-product-gtm-json')); 1065 var product = {}; 1066 product.productID = thisItem["id"]; 1067 product.sku = thisItem["skuid"]; 1068 product.category = thisItem["category"].replace(/\\/g, ""); 1069 product.name = thisItem["name"].replace(/\\/g, ""); 1070 product.qty = thisItem["quantity"]; 1071 product.itemPrice = thisItem["price"]; 1072 product.images = [_this.find('img').attr('src')]; 1073 product.url = window.location.origin + _this.find('.name').find('a').attr('href').split("?utm")[0].split("#utm")[0].split("&utm")[0]; 1074 product.attr = {'manufacturer': thisItem["brand"], 'color': thisItem["color"], 'size': thisItem["size"] }; 1075 items[index]= product; 1076 }); 1077 }); 1078 1079 var cart_data = items; 1080 1081 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 1082 crdl([ 1083 ['cart', 'clear'], 1084 ['cartitem', 'add' , cart_data], 1085 ['event', 'cart'] 1086 ]); 1087 } 1088 }, 3000); 1089 } 1090 1091 function cordialClearCart() { 1092 setTimeout(function(){ 1093 var properties = { 1094 'status': 'empty' 1095 }; 1096 1097 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 1098 crdl([ 1099 ['cart', 'clear'], 1100 ['event', 'cart', properties] 1101 ]); 1102 } 1103 }, 3000); 1104 } 1105 1106 if ($(document).find('.pt_cart').length > 0 || $(document).find('.pt_onepcheckout').length > 0) { 1107 if($('.order-item').length > 0){ 1108 cordialUpdateCart(); 1109 } else { 1110 cordialClearCart(); 1111 } 1112 } 1113 1114 $('body').on('change', 'input.opc-qty', function(event) { 1115 cordialUpdateCart(); 1116 }); 1117 1118 $('body').on('click', '.cart-change', function(event) { 1119 setTimeout(function(){ 1120 if($('.order-item').length == 0){ 1121 cordialClearCart(); 1122 } else { 1123 cordialUpdateCart(); 1124 } 1125 }, 2000); 1126 }); 1127 1128 // order event created on confirmation; myaccount signup
1129 if ($(document).find('.order-confirmation-details').length > 0) { 1130 var orderID = $('.order-history-info span.value').first().text().trim(); 1131 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 1132 var orderID = $('.orderdetails .sectionheader h3').text().replace('Order Number:','').trim(); 1133 } 1134 var email = $('.order-billing-email').text().trim(); 1135 var shippingName = $('.order-shipping-name').text().trim(); 1136 var shippingAddress2 = $('.order-shipping-address2').text().trim(); 1137 var shippingAddress3 = $('.order-shipping-address3').text().trim(); 1138 var shippingAddress = $('.order-shipping-address1').text().trim(); 1139 if(shippingAddress2) { 1140 shippingAddress += ", " + shippingAddress2; 1141 } 1142 if(shippingAddress3) { 1143 shippingAddress += ", " + shippingAddress3; 1144 } 1145 var shippingCity = $('.order-shipping-geo .city').text().trim().replace(',',''); 1146 var shippingState = $('.order-shipping-geo .state').text().trim(); 1147 var shippingZip = $('.order-shipping-geo .zip').text().trim(); 1148 var shippingCountry = $('.order-shipping-country').text().trim(); 1149 var billingName = $('.order-billing-name').text().trim(); 1150 var billingAddress2 = $('.order-billing-address2').text().trim(); 1151 var billingAddress3 = $('.order-billing-address3').text().trim(); 1152 var billingAddress = $('.order-billing-address1').text().trim(); 1153 if(billingAddress2) { 1154 billingAddress += ", " + billingAddress2; 1155 } 1156 if(billingAddress3) { 1157 billingAddress += ", " + billingAddress3; 1158 } 1159 var billingCity = $('.order-billing-geo .city').text().trim().replace(',',''); 1160 var billingState = $('.order-billing-geo .state').text().trim(); 1161 var billingZip = $('.order-billing-geo .zip').text().trim(); 1162 var billingCountry = $('.order-billing-country').text().trim(); 1163 var billingPhone = $('.order-billing-phone').text().replace('Phone:','').trim(); 1164 1165 var name = billingName.split(' '); 1166 var firstName = name[0]; 1167 var lastName = name[name.length-1]; 1168 1169 var items = []; 1170 $('.order-item').each(function(index, el) { 1171 var _this = $(this); 1172 items[index] = {}; 1173 _this.find('.productCardMetadata').each(function(key, v) { 1174 var thisItem = JSON.parse($(this).attr('data-product-gtm-json')); 1175 var product = {}; 1176 product.productID = thisItem["id"]; 1177 product.sku = thisItem["skuid"]; 1178 product.category = thisItem["category"].replace(/\\/g, ""); 1179 product.name = thisItem["name"].replace(/\\/g, ""); 1180 product.qty = thisItem["quantity"]; 1181 product.itemPrice = thisItem["price"]; 1182 product.images = [_this.find('img').attr('src')]; 1183 product.url = window.location.origin + _this.find('.name').find('a').attr('href'); 1184 product.attr = {'manufacturer': thisItem["brand"], 'color': thisItem["color"], 'size': thisItem["size"] }; 1185 items[index]= product; 1186 }); 1187 }); 1188 1189 var order_data = { 1190 "orderID": orderID, 1191 "shippingAddress": { 1192 "name": shippingName, 1193 "address": shippingAddress, 1194 "city": shippingCity, 1195 "state": shippingState, 1196 "postalCode": shippingZip, 1197 "country": shippingCountry 1198 }, 1199 "billingAddress": { 1200 "name": billingName, 1201 "address": billingAddress, 1202 "city": billingCity, 1203 "state": billingState, 1204 "postalCode": billingZip, 1205 "country": billingCountry 1206 }, 1207 "items": items 1208 }; 1209 1210 var properties = { 1211 "orderID": orderID 1212 }; 1213 1214 var auth_data = { 1215 email: email 1216 } 1217 var contact_data = { 1218 'channels': { 1219 'email': { 1220 'address': email 1221 } 1222 }, 1223 'first_name': firstName, 1224 'last_name': lastName, 1225 'phone': billingPhone, 1226 'postal_code': billingZip, 1227 'source_create': 'order', 1228 'geo_location': { 1229 'postal_code': billingZip, 1230 'country': billingCountry, 1231 'state': billingState, 1232 'city': billingCity 1233 } 1234 }; 1235 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 1236 crdl([ 1237 ['contact', auth_data, contact_data], 1238 ['cart', 'clear'], 1239 ['order', 'add', order_data], 1240 ['event', 'order', properties] 1241 ]); 1242 } 1243 1244 // create Cordial contact on confirmation page 1245 $(document).on('click','.largebutton[name="dwfrm_profile_confirm"]', function(){ 1246 var password = $('.password-holder .password').val(); 1247 var passwordConfirm = $('.password-holder .password-confirm').val(); 1248 var formValidation = true; 1249 var signupEvent = ""; 1250 1251 var regexPassword = /^(?=.*?[A-z])(?=.*?[0-9])(?=.*?[#?!\=\/\,\.\~\`\(\)\{\}\[\]\\@_$%^&*-]).{6,15}$/g; 1252 if ( String(password).match(regexPassword) == null ) { 1253 formValidation = false;
1254 } 1255 1256 if (password !== passwordConfirm) { 1257 formValidation = false; 1258 } 1259 1260 if (!password || !passwordConfirm) { 1261 formValidation = false; 1262 } 1263 1264 if (formValidation && $('#RegistrationForm .field.error').length == 0){ 1265 var auth_data = { 1266 email: email 1267 } 1268 1269 var contact_data = { 1270 'channels': { 1271 'email': { 1272 'address': email 1273 } 1274 }, 1275 'first_name': firstName, 1276 'last_name': lastName, 1277 'phone': billingPhone, 1278 'postal_code': billingZip, 1279 'source_create': 'myaccount', 1280 'geo_location': { 1281 'postal_code': billingZip, 1282 'country': billingCountry, 1283 'state': billingState, 1284 'city': billingCity 1285 } 1286 }; 1287 1288 var loginProperties = { 1289 "email": email 1290 }; 1291 1292 if ($('input#newslettersignup').is(':checked')){ 1293 var contact_data = { 1294 'channels': { 1295 'email': { 1296 'address': email, 1297 'subscribeStatus': 'subscribed' 1298 } 1299 }, 1300 'first_name': firstName, 1301 'last_name': lastName, 1302 'phone': billingPhone, 1303 'postal_code': billingZip, 1304 'signup_source': 'myaccount', 1305 'source_create': 'myaccount', 1306 'welcome_signup': true, 1307 'geo_location': { 1308 'postal_code': billingZip, 1309 'country': billingCountry, 1310 'state': billingState, 1311 'city': billingCity 1312 } 1313 }; 1314 1315 var properties = { 1316 "signup_source": 'myaccount', 1317 "page": 'confirmation', 1318 "welcome_signup": true 1319 }; 1320 1321 signupEvent = ['event', 'email_signup', properties]; 1322 } 1323 1324 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 1325 crdl([ 1326 ['contact', auth_data, contact_data], 1327 ['event', 'account_create'], 1328 ['event', 'login', loginProperties], 1329 signupEvent 1330 ]); 1331 } 1332 } 1333 }); 1334 } 1335 1336 // Password Reset - No Account 1337 if ($(document).find('.reset-password .no-account').length > 0) { 1338 var email = $('.no-account').text(); 1339 1340 var auth_data = { 1341 email: email 1342 } 1343 var contact_data = { 1344 'channels': { 1345 'email': { 1346 'address': email 1347 } 1348 } 1349 }; 1350 1351 var properties = { 1352 "email": email 1353 }; 1354 1355 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 1356 crdl([ 1357 ['contact', auth_data, contact_data], 1358 ['event', 'reset-password-no-account', properties] 1359 ]); 1360 } 1361 } 1362 1363 // Password Reset Confirmation 1364 if ($(document).find('#password-reset-confirm').length > 0) { 1365 var email = $('#password-reset-confirm').attr('data-email'); 1366 var passwordEvent = "reset-password"; 1367 1368 if ($(document).find('.noAccount').length > 0) { 1369 var passwordEvent = "reset-password-no-account"; 1370 } 1371 1372 var auth_data = { 1373 email: email 1374 } 1375 var contact_data = { 1376 'channels': { 1377 'email': { 1378 'address': email 1379 } 1380 } 1381 }; 1382 1383 var properties = { 1384 "email": email 1385 }; 1386 1387 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 1388 crdl([ 1389 ['contact', auth_data, contact_data], 1390 ['event', passwordEvent, properties] 1391 ]); 1392 } 1393 } 1394 } 1395 //END CORDIAL 1396 1397 1398 // Reloading login page after unsuccessful attempt w/ error messaging, 1399 // and retaining username if 'Remember me' was checked 1400 if (window.location.href.indexOf('retry') >= 0) { 1401 $('.login-dialog-error .invalid-login').removeClass('d-none'); 1402 if (window.location.href.indexOf('=') >= 0) { 1403 var username = window.location.href.split('=')[1]; 1404 $('input[name*="dwfrm_login_username"]').val(username); 1405 $('input[name*="dwfrm_login_rememberme"]').prop('checked', true); 1406 } 1407 } 1408 1409 // Setting marketing email optin default to checked on Account Edit page 1410 $(document).ready(function() { 1411 $('.update-account #dwfrm_profile_customer_addtoemaillist').prop('checked', true); 1412 }); 1413 1414 // Make this my store click delegation 1415 $(document).on('click','.assign-store-container .assign-store', function(e){ 1416 e.preventDefault(); 1417 var storeID = $(this).parents('.store').data('id'); 1418 $.ajax({ 1419 url : Urls.assignStoreId, 1420 data : { store_id : storeID }, 1421 method : "POST", 1422 dataType : "JSON", 1423 success : function(data) { 1424 if ( 'success' in data && data['success'] == true ) { 1425 location.reload(); 1426 } 1427 } 1428 }); 1429 }); 1430
1431 // Bold day of the week on store page 1432 $(document).ready(function() { 1433 if ($('#wrapper').hasClass('pt_store-locator')) { 1434 var daysOfWeek = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; 1435 var currentDay = new Date().getDay(); //0=Sun, 1=Mon, ..., 6=Sat 1436 var matchingStoreHours = $('.store-detail-info .store-hours-days .stores-day').filter(function() { 1437 return $(this).html().indexOf(daysOfWeek[currentDay]) >= 0; 1438 }); 1439 $(matchingStoreHours).css('font-weight','bold').next().css('font-weight','bold'); 1440 } 1441 }); 1442 1443 //EMPLIFI REVIEWS 1444 if(SitePreferences.TURNTO_ENABLED){ 1445 if (pageContext && 'type' in pageContext && pageContext.type == 'product') { 1446 //show/hide teaser div for BB desktop/mobile 1447 if (window.innerWidth <= 767) { 1448 $('.mobile-hidden .turntoTeaser').remove(); 1449 } else { 1450 $('.mobile-only .turntoTeaser').remove(); 1451 } 1452 1453 var iterations = 0; 1454 var maxIterations = 100; 1455 var intervalId = setInterval(function() { 1456 iterations++; 1457 //hide empty inline ratings and reviews 1458 if($('.tt-c-teaser__avg-rating').length > 0){ 1459 $('.product-review').removeClass('hide-reviews'); 1460 $('.product-reviews-container').removeClass('hide-reviews'); 1461 } 1462 //autoclick the mobile "Show details" summary button 1463 if (window.innerWidth <= 767) { 1464 $('.tt-o-expander__button').trigger('click'); 1465 } 1466 if (iterations >= maxIterations) { 1467 clearInterval(intervalId); 1468 } 1469 }, 100); 1470 } 1471 } 1472 1473 //PIXLEE ADD-TO-CART TRACKING 1474 if(SitePreferences.PIXLEE_ENABLED){ 1475 function pixleeAddToCart(id) { 1476 setTimeout(function(){ 1477 var thisItem = $('.productCardMetadata[data-product-id="'+id+'"]'); 1478 var itemMeta = JSON.parse(thisItem.attr('data-product-ga4-json')); 1479 var quantity = $('.quantity-stepper[data-product-id="'+id+'"] input.opc-qty').val(); 1480 if (typeof pixlee_analytics !== 'undefined') { 1481 pixlee_analytics.events.trigger('add:to:cart', { 1482 'product_sku': itemMeta["item_id"], 1483 'price': itemMeta["price"], 1484 'quantity': quantity, 1485 'currency': itemMeta["currency"] 1486 }); 1487 } 1488 }, 3000); 1489 } 1490 1491 $('body').on('change', 'input.opc-qty', function(e) { 1492 var thisItemID = $(this).parent('.opc-qty-container').parent('.quantity-stepper').attr('data-product-id'); 1493 pixleeAddToCart(thisItemID); 1494 }); 1495 1496 $('body').on('click', '.increase.cart-change', function(e) { 1497 var thisItemID = $(this).parent('.quantity-stepper').attr('data-product-id'); 1498 pixleeAddToCart(thisItemID); 1499 }); 1500 } 1501 1502 $('.section-group .section-body:last').append($('.section-reviews')); 1503 1504 $(".pt_customer-service #secondary .nav-title").click(function() { 1505 $(this).toggleClass('active'); 1506 $(".pt_customer-service #secondary #customer-service-nav").slideToggle(); 1507 }); 1508 1509 searchbar.init(); 1510 1511 if (siteName == SiteConstants.SiteIds.CountryOutfittersUS) { 1512 var btn = $('#back-to-top'), 1513 scroll_position = 2100; 1514 1515 if (window.innerWidth <= 767) { 1516 scroll_position = 2771; 1517 } 1518 1519 if (window.innerWidth > 767) { 1520 $('#main').prepend('<div class="menu-hover-overlay" style="display:none;"></div>'); 1521 1522 $('.has-dropdown.nav-menu').hover( 1523 function() { 1524 $('#wrapper').addClass('menu-active'); 1525 }, 1526 function() { 1527 $('#wrapper').removeClass('menu-active'); 1528 } 1529 ); 1530 } 1531 1532 $(window).scroll(function() { 1533 if ($(window).scrollTop() > scroll_position) { 1534 btn.addClass('show'); 1535 } else { 1536 btn.removeClass('show'); 1537 } 1538 }); 1539 1540 btn.on('click', function(e) { 1541 e.preventDefault(); 1542 $('html, body').animate({scrollTop:0}, scroll_position); 1543 }); 1544 1545 if($('.homepage-03 .content-asset-body').length >= 1) { 1546 var slot_position = $('.homepage-03 .content-asset-body').attr('slot-position').trim(); 1547 if(slot_position != '3'){ 1548 var promo_slot = $('.shell.homepage-03').html(), 1549 before_this_slot = '.homepage-0' + parseInt(slot_position, 10); 1550 $('.shell.homepage-03').remove(); 1551 1552 if(slot_position > 3 && slot_position < 8){ 1553 before_this_slot = '.homepage-0' + (parseInt(slot_position, 10) + 1); 1554 } 1555 if(slot_position > 7){ 1556 $('.shell' + before_this_slot).after('<div class="shell homepage-03">' + promo_slot + '</div>'); 1557 } else { 1558 $('.shell' + before_this_slot).before('<div class="shell homepage-03">' + promo_slot + '</div>'); 1559 } 1560 } 1561 } 1562 } 1563 1564 var brands_count = $('.brand').length; 1565 var styles_count = $('.style').length; 1566 var toestyle_count = $('.toe-style').length; 1567 1568 if(brands_count < 16) { 1569 $('.pt_content .viewallbrands').hide(); 1570 } 1571 1572 if(styles_count < 8) { 1573 $('.pt_content .viewallstyles').hide(); 1574 } 1575 1576 if(toestyle_count < 8) { 1577 $('.pt_content .viewalltoes').hide(); 1578 } 1579
1580 $(document).on('click','.ca-header-contact-info',function(event) { 1581 if(window.innerWidth > 767) { 1582 event.preventDefault(); 1583 } 1584 }); 1585 1586 /*if(window.innerWidth < 767 ) { 1587 if(siteName == SiteConstants.SiteIds.CountryOutfittersUS) { 1588 $('.product-listing-1x4 .grid-tile').each(function(){ 1589 $(this).find('.product-content').before('<div class="savings-bar"></div>'); 1590 if($(this).find('.product-sales-price').length !== 0){ 1591 var $promoMsg = $(this).find('.product-sales-price').text().trim().replace('You Save:', 'Save'); 1592 $(this).find('.savings-bar').css('background-color','#E3ECEE').text($promoMsg).show(); 1593 } 1594 }); 1595 } 1596 }*/ 1597 1598 if(window.innerWidth < 767 ) { 1599 if(brands_count > 8) { 1600 $('.pt_content .viewallbrands').show(); 1601 } 1602 1603 $('.pt_content .style:nth-child(n+9)').css({'display':'none'}); 1604 $('.pt_content .toe-style:nth-child(n+9)').css({'display':'none'}); 1605 1606 if ($('.top-banner-bar').attr('data-header-for') != 'bootbarn_us') { 1607 $('.pt_storefront .list-review-products li .offer-list').slideUp(); 1608 $('.pt_storefront .offer-head h2').addClass('close'); 1609 } 1610 } else { 1611 $('.pt_content .style:nth-child(n+9)').css({'display':'block'}); 1612 $('.pt_content .toe-style:nth-child(n+9)').css({'display':'block'}); 1613 } 1614 1615 $(document).on('click','.pt_content .viewallbrands',function(event) { 1616 event.preventDefault(); 1617 if($('.pt_content .viewallbrands').hasClass("expanded")) { 1618 $('.pt_content .viewallbrands').removeClass("expanded"); 1619 $('.pt_content .brand:nth-child(n+9)').css({'display':'none'}); 1620 $('.pt_content .viewallbrands').html(Resources.SHOWMOREBRANDS); 1621 } else { 1622 $('.pt_content .viewallbrands').addClass("expanded"); 1623 $('.pt_content .brand:nth-child(n+9)').css({'display':'block'}); 1624 $('.pt_content .viewallbrands').html(Resources.CLOSE); 1625 } 1626 }); 1627 1628 $(document).on('click','.pt_content .viewallstyles',function(event) { 1629 event.preventDefault(); 1630 if($('.pt_content .viewallstyles').hasClass("expanded")) { 1631 $('.pt_content .viewallstyles').removeClass("expanded"); 1632 $('.pt_content .style:nth-child(n+9)').css({'display':'none'}); 1633 $('.pt_content .viewallstyles').html(Resources.SHOWMORESTYLE); 1634 } else { 1635 $('.pt_content .viewallstyles').addClass("expanded"); 1636 $('.pt_content .style:nth-child(n+9)').css({'display':'block'}); 1637 $('.pt_content .viewallstyles').html(Resources.CLOSE); 1638 } 1639 }); 1640 1641 $(document).on('click','.pt_content .viewalltoes',function(event) { 1642 event.preventDefault(); 1643 if($('.pt_content .viewalltoes').hasClass("expanded")) { 1644 $('.pt_content .viewalltoes').removeClass("expanded"); 1645 $('.pt_content .toe-style:nth-child(n+9)').css({'display':'none'}); 1646 $('.pt_content .viewalltoes').html(Resources.SHOWMORETOE); 1647 } else { 1648 $('.pt_content .viewalltoes').addClass("expanded"); 1649 $('.pt_content .toe-style:nth-child(n+9)').css({'display':'block'}); 1650 $('.pt_content .viewalltoes').html(Resources.CLOSE); 1651 } 1652 }); 1653 1654 $(document).on('click', '.swatch-list .swatch:not(.selected) [class*="swatch-im"]', function() { 1655 var $parentBlock = $(this).closest('.slide, .swatch-list'); 1656 var $mainImg = $parentBlock.find('.product-image img:first'); 1657 var swatchData = $(this).data('thumb'); 1658 1659 if (swatchData) { 1660 $mainImg.attr('alt', swatchData.alt); 1661 $mainImg.attr('title', swatchData.title); 1662 $mainImg.attr('src', swatchData.src); 1663 1664 $parentBlock.find('.swatch').removeClass('selected'); 1665 $(this).closest('.swatch').addClass('selected'); 1666 } else { 1667 window.location.href = $(this).closest('.swatch').attr('href'); 1668 } 1669 }); 1670 1671 $(document).on('click','.yes-alts button.altButton', function(e){ 1672 e.preventDefault(); 1673 var altHiddenCount = $(this).closest('.yes-alts ul.swatch-list').find('.hidden-content').length; 1674 var altHiddenToggle = '+ ' + altHiddenCount; 1675 $(this).text( $(this).text().indexOf('+') >= 0 ? "- Less" : altHiddenToggle); 1676 $(this).closest('.yes-alts ul.swatch-list').find('.hidden-content').toggle(); 1677 }); 1678 1679 //Terms and Conditions Popup on Checkout 1680 $(document).off('click', '[dialog-content]').on('click', '[dialog-content]', function(event) { 1681 event.preventDefault(); 1682 1683 var $this = $(event.currentTarget); 1684 var $contentContainer = $($this.attr('dialog-content')); 1685 1686 dialog.open({ 1687 html: $contentContainer.html(), 1688 options: { 1689 title: $contentContainer.attr('title'), 1690 dialogClass: 'fixed checkout-terms' + ($contentContainer.attr('dialog-class') ? ' ' + $contentContainer.attr('dialog-class') : ''), 1691 draggable: false, 1692 open: function(event, ui) { 1693 var $this = $(this); 1694 1695 $('body').addClass('dialog-open'); 1696 $this.scrollTop(0); 1697 emailForm.initialize($this); 1698 }, 1699 close: function(event, ui) { 1700 $('body').removeClass('dialog-open'); 1701 } 1702 } 1703 }); 1704 }); 1705 1706 //Page Top functionality for popup content in terms and conditions 1707 $(document).off('click', '.ui-dialog [href="#pgTop"]').on('click', '.ui-dialog [href="#pgTop"]', function(event) { 1708 event.preventDefault(); 1709 1710 var $this = $(event.currentTarget); 1711 $this.closest('.ui-dialog-content').scrollTop(0); 1712 }); 1713 1714 $('.video-play-btn') 1715 .on('click', function(e) { 1716 var $this = $(this); 1717 var $video = $this.closest('.video'); 1718 var $iframe = $video.find('iframe'); 1719 var originalSRC = $video.find('iframe').attr('src').replace('?autoplay=1',''); 1720 var videoHtml = $(this).next('iframe').prop('outerHTML'); 1721 videoHtml = videoHtml.replace(/src=".+?"/, 'src="' + originalSRC + '?autoplay=1"'); 1722 dialog.open({ 1723 html:(videoHtml), 1724 options: { 1725 width: 560, 1726 dialogClass: 'videopopup', 1727 title: $video.find('.video-caption').text(), 1728 close: function() { 1729 $('.ui-dialog').find('iframe').attr('src', ''); 1730 } 1731 }, 1732 }); 1733 1734 e.preventDefault(); 1735 }) 1736 1737 1738 //Prepare for touch/menu 1739 if (util.isTouchDevice()) { 1740 $('body').addClass('touchDevice'); 1741 } 1742 if(window.navigator.platform.match("i(Win)")){ 1743 $('body').addClass('isWin') 1744 } 1745 1746 if (siteName != SiteConstants.SiteIds.BootBarnUS && siteName != SiteConstants.SiteIds.SheplersUS) { 1747 if(window.innerWidth < 767) { 1748 if ($('.header-banner').children().length == 0) { 1749 $('.top-banner').addClass('no-top'); 1750 } 1751 } 1752 } 1753 1754 $('body') 1755 .on('keydown', 'textarea[data-character-limit]', function (e) { 1756 var text = $.trim($(this).val()), 1757 charsLimit = $(this).data('character-limit'), 1758 charsUsed = text.length; 1759 1760 if ((charsUsed >= charsLimit) && (controlKeys.indexOf(e.which.toString()) < 0)) { 1761 e.preventDefault(); 1762 } 1763 }) 1764 .on('change keyup mouseup', 'textarea[data-character-limit]', function () { 1765 var text = $.trim($(this).val()), 1766 charsLimit = $(this).data('character-limit'), 1767 charsUsed = text.length,
1768 charsRemain = charsLimit - charsUsed; 1769 1770 if (charsRemain < 0) { 1771 $(this).val(text.slice(0, charsRemain)); 1772 charsRemain = 0; 1773 } 1774 1775 $(this).next('div.char-count').find('.char-remain-count').html(charsRemain); 1776 }) 1777 .on('click','.pt_storefront .offer-head h2',function(event) { 1778 event.preventDefault(); 1779 if(window.innerWidth < 767 && $('.top-banner-bar').attr('data-header-for') != 'bootbarn_us') { 1780 $(this) 1781 .toggleClass('close') 1782 .closest('li') 1783 .find('.offer-list') 1784 .slideToggle(200); 1785 } else if ($('.top-banner-bar').attr('data-header-for') == 'bootbarn_us') { 1786 $(this) 1787 .toggleClass('active') 1788 .closest('li') 1789 .toggleClass('active') 1790 .find('.offer-list') 1791 .toggleClass('active') 1792 .slideToggle(200); 1793 } 1794 }) 1795 .on('click', '.footer-item .content-asset h3', function(event) { 1796 event.preventDefault(); 1797 1798 if(window.innerWidth < 1025) { 1799 $(this) 1800 .toggleClass('active') 1801 .closest('.footer-item') 1802 .siblings() 1803 .find('.active') 1804 .removeClass('active'); 1805 1806 $(this) 1807 .next() 1808 .stop() 1809 .slideToggle() 1810 .closest('.footer-item') 1811 .siblings() 1812 .find('.menu-footer') 1813 .slideUp(); 1814 } 1815 }) 1816 .on('click', '.btn-expand', function (event) { 1817 event.preventDefault(); 1818 1819 var element = $(this).attr('href'); 1820 1821 if($('.sticky-menu').length > 0) { 1822 var element = element + ".search-mobile"; 1823 } 1824 1825 $(element).toggleClass('show'); 1826 1827 if($('.sticky-menu').length > 0) { 1828 $('#main').toggleClass('search-open'); 1829 } 1830 1831 if($('.menu-toggle').hasClass('active')) { 1832 navigation.CloseNavigation(); 1833 } 1834 1835 if($('#mini-cart').hasClass('active')) { 1836 $('#mini-cart .mini-cart-link').removeClass('active'); 1837 $('#mini-cart').removeClass('active'); 1838 } 1839 1840 if($('.second-mobnav').hasClass('active')) { 1841 $('.second-mobnav').removeClass('active') 1842 $('#second-mobnav').slideUp(); 1843 } 1844 1845 if (element == '#search' || element == '#search.search-mobile') { 1846 $(document).trigger('SearchBar.Expand'); 1847 } 1848 }) 1849 .on('click', '.btn-location-redirect', function(event){ 1850 event.preventDefault(); 1851 var linkRedirectStore = $(this).find('span').attr('loc-link'); 1852 if (linkRedirectStore != null) { 1853 location.href = linkRedirectStore; 1854 } 1855 }) 1856 .on('click', '.btn-location', function(event) { 1857 event.preventDefault(); 1858 1859 if($('#mini-cart').hasClass('active')) { 1860 $('#mini-cart .mini-cart-link').removeClass('active'); 1861 $('#mini-cart').removeClass('active'); 1862 } 1863 1864 $('#navigation') 1865 .stop() 1866 .slideToggle(); 1867 1868 navigation.CloseNavigation(); 1869 1870 var element = $(this).attr('href'); 1871 1872 $(element) 1873 .find('.nav-secondary-dropdown') 1874 .stop() 1875 .slideToggle() 1876 .parent() 1877 .siblings() 1878 .find('.nav-secondary-dropdown') 1879 .slideUp(); 1880 }) 1881 .on('click', '.jumbotron-current-offers', function (event) { 1882 $('.jumbotron-mobile').toggleClass('active'); 1883 if($('#jumbotron-current-offers-icon').hasClass('fa-angle-up')) { 1884 $('#jumbotron-current-offers-icon').removeClass('fa-angle-up'); 1885 $('#jumbotron-current-offers-icon').addClass('fa-angle-down'); 1886 setCookie('jumbotronExpandedCookie', false, 2); 1887 } else { 1888 $('#jumbotron-current-offers-icon').removeClass('fa-angle-down'); 1889 $('#jumbotron-current-offers-icon').addClass('fa-angle-up'); 1890 setCookie('jumbotronExpandedCookie', true, 2); 1891 } 1892 }) 1893 .on('click', '.second-mobnav', function (event) { 1894 event.preventDefault(); 1895 1896 $(this).toggleClass('active'); 1897 1898 $('#second-mobnav') 1899 .stop() 1900 .slideToggle(150); 1901 1902 if($('.menu-toggle').hasClass('active')) { 1903 $('.menu-toggle').removeClass('active'); 1904 $('html').removeClass('menu-active'); 1905 } 1906 1907 if($('#mini-cart').hasClass('active')) { 1908 $('#mini-cart .mini-cart-link').removeClass('active'); 1909 $('#mini-cart').removeClass('active'); 1910 } 1911 $(document).trigger('SearchBar.Hide'); 1912 }) 1913 1914 .on('click', '.accordion > a', function (event) { 1915 var $container = $(this).closest('.accordion'); 1916 $container.find('ul').slideToggle('fast'); 1917 }) 1918/* 1919 .on('touchstart', function(event) { 1920 if (!$(event.target).closest('#navigation').length && !$(event.target).is('#navigation') && $win.width() > 767 ) { 1921 $('.level-2').stop().slideUp(400); 1922 } 1923 }) 1924*/ 1925 1926 .on('mouseover', '#mini-cart', function () { 1927 if(window.innerWidth > 1024) { 1928 $(this) 1929 .find('.mini-cart-link') 1930 .addClass('active'); 1931 1932 $(this) 1933 .addClass('active'); 1934 } 1935 1936 if($('#navigation').hasAttr('style')) { 1937 $('.menu-toggle').removeClass('active'); 1938 } 1939 $(document).trigger('SearchBar.Hide'); 1940 }) 1941 .on('mouseleave', '#mini-cart', function () { 1942 var $this = $(this); 1943 1944 if(window.innerWidth > 1024) { 1945 setTimeout(function () { 1946 $this 1947 .find('.mini-cart-link') 1948 .removeClass('active'); 1949 1950 $this 1951 .removeClass('active'); 1952 }, 1000); 1953 } 1954 }) 1955 .on('click', '.edit-search-query', function () { 1956 $('.category-popup-list-stores').dialog('close'); 1957 $('.grid-page-storeselector-popup').dialog('open'); 1958 }) 1959 .on('click', '.popup-list-stores input[name="apply"]', function () { 1960 if (!$('input[name="store"]:checked').val()) { 1961 alert('Select one of stores'); 1962 1963 return; 1964 } 1965 1966 $.ajax({ 1967 type: 'get', 1968 url: Urls.setDefaultStore, 1969 data: { 1970 storeId: $('input[name="store"]:checked').val() 1971 }, 1972 1973 success: function (data) { 1974 $('.category-popup-list-stores').dialog('close'); 1975 document.location.reload(); 1976 } 1977 }); 1978 }) 1979 1980 .on('click', '.pt_product-search-result .category-slot a', function(event) { 1981 var refinementValue = $(event.target).closest('[data-link-attribute-value]').data('link-attribute-value'); 1982 var isRefinementLink = refinementValue != undefined; 1983 1984 if (isRefinementLink) { 1985 var $sidebarRefinement = $('#refinements-inner').find('#field-' + refinementValue); 1986 var urlRefinementData = getUrlRefinementData(); 1987 1988 if ($sidebarRefinement.length > 0) { 1989 event.preventDefault(); 1990 $sidebarRefinement.trigger('click'); 1991 } else if (urlRefinementData.hasRefinements) { 1992 event.preventDefault(); 1993 var refinementId = $(event.target).closest('[data-link-attribute-id]').data('link-attribute-id'); 1994 var refinementIsAlreadySelected = false;
1995 var redirectUrl; 1996 1997 for (var refinement in urlRefinementData.parameters) { 1998 if (urlRefinementData.parameters[refinement] === refinementValue) { 1999 refinementIsAlreadySelected = true; 2000 } 2001 } 2002 2003 if (!refinementIsAlreadySelected) { 2004 redirectUrl = window.location.href + '&prefn' + urlRefinementData.newRefinementStartNumber + '=' + refinementId + '&prefv' + urlRefinementData.newRefinementStartNumber + '=' + refinementValue; 2005 window.location.href = redirectUrl; 2006 } 2007 } 2008 } 2009 }); 2010 2011 $(document).on('click', '.thumb-link, .name-link', function(event) { 2012 var $this = $(this); 2013 var $container = $this.closest('.accordion, .section-offers, .tiles, .cat-header-content.cat-header-slider').first(); 2014 if ($container.length > 0) { 2015 event.preventDefault(); 2016 2017 if ($container.find('.product-tile').length > 0) { 2018 var containerId = $container.attr('content-slot-id') || $container.attr('id'); 2019 2020 var dataObject = { 2021 promotion_name: containerId 2022 } 2023 2024 var pageType; 2025 var $wrapper = $this.closest('.add-to-cart-modal'); 2026 if ($wrapper.length > 0) { 2027 pageType = 'addtocartmodal'; 2028 } 2029 2030 if (!pageType) { 2031 $wrapper = $('#wrapper'); 2032 if ($wrapper.length > 0) { 2033 if (pageContext && pageContext.type) { 2034 switch (pageContext.type) { 2035 case 'storefront': 2036 pageType = 'Homepage'; 2037 break; 2038 2039 case 'search': 2040 pageType = 'PLP'; 2041 break; 2042 2043 case 'product': 2044 pageType = 'PDP'; 2045 break; 2046 2047 case 'cart': 2048 pageType = 'Cart'; 2049 break; 2050 2051 case 'onepcheckout_groups': 2052 pageType = 'Checkout'; 2053 break; 2054 2055 case 'orderconfirmation': 2056 pageType = 'Order Confirmation'; 2057 break; 2058 2059 case 'customerservice': 2060 pageType = 'Customer Service'; 2061 break; 2062 2063 case 'account': 2064 pageType = 'Account'; 2065 break; 2066 2067 case 'content': 2068 pageType = 'Content Page'; 2069 break; 2070 2071 case 'error': 2072 pageType = 'Error Page'; 2073 break; 2074 } 2075 } 2076 } 2077 } 2078 2079 if (pageType) { 2080 dataObject.promotion_id = pageType; 2081 } 2082 2083 var redirectHandler = function() { 2084 location.href = $this.attr('href'); 2085 }; 2086 2087 GoogleTagManagerClient.PushDataLayerForDataLayerType('SelectPromotion', dataObject, { Container: $this.closest('.product-tile') }).then(redirectHandler).catch(redirectHandler); 2088 } 2089 } 2090 }); 2091 2092 $(document).on('click', '[content-asset-id] a, [content-asset-id] button', function(event) { 2093 var $this = $(this); 2094 var isLink = $this.attr('href') && $this.attr('href').length > 0 && $this.attr('href').indexOf('//') >= 0; 2095 var isClose = $this.attr('class') && $this.attr('class').length > 0 && $this.attr('class').indexOf('close') >= 0; 2096 2097 if ($this.closest('.product-tile').length == 0 && !isClose) { 2098 var $container = $this.closest('[content-asset-id]').first(); 2099 if ($container.length > 0) { 2100 if (isLink) { 2101 event.preventDefault(); 2102 } 2103 2104 var dataObject = { 2105 content_type: 'content', 2106 item_id: $container.attr('content-asset-id') 2107 } 2108 2109 var redirectHandler = function() { 2110 if (isLink) { 2111 if ($this.attr('target')) { 2112 window.open($this.attr('href'), $this.attr('target')); 2113 } else { 2114 location.href = $this.attr('href'); 2115 } 2116 } 2117 }; 2118 2119 GoogleTagManagerClient.PushDataLayerForDataLayerType('SelectContent', dataObject).then(redirectHandler).catch(redirectHandler); 2120 } 2121 } 2122 }); 2123 2124 $(document).on('click.CassidyClick', '.btn-cassidy', function(event) { 2125 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', { 2126 'action_name': 'cassidyclick', 2127 'action_page_type': 'pdp', 2128 'action_value': window.location.href.split('?')[0], 2129 'action_items': [] 2130 }); 2131 }); 2132 2133 $(document).on('click.CassidySuggestionButton', '.cim-widget-modal-container .cim-widget-suggestion-button', function(event) { 2134 var $this = $(this); 2135 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', { 2136 'action_name': 'suggestionbutton_cassidy', 2137 'action_page_type': 'cassidy', 2138 'action_value': window.location.href.split('?')[0], 2139 'action_items': [$this.text().trim()] 2140 }); 2141 }); 2142 2143 $(document).on('click.CassidyProductRecommendation', '.cim-widget-modal-container a.cim-widget-product-tile-pdp', function(event) { 2144 var $this = $(this); 2145 var hrefArray = $this.attr('href').split('.html')[0].split('/'); 2146 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', { 2147 'action_name': 'productrec_cassidy', 2148 'action_page_type': 'cassidy', 2149 'action_value': window.location.href.split('?')[0], 2150 'action_items': [hrefArray[hrefArray.length - 1]] 2151 }); 2152 }); 2153 2154 addPromotionDataLayers(); 2155 $(document).off('GoogleTagManager.AddPromotionDataLayers').on('GoogleTagManager.AddPromotionDataLayers', function(event) { 2156 addPromotionDataLayers(); 2157 }); 2158 2159 /** 2160 * Add class to content slot refinements if they're currently active 2161 * and remove any static refinements if they're not found in the sidebar 2162 * to prevent empty search results. 2163 */ 2164 if ($('body').find('.pt_product-search-result .category-slot a').length > 0) { 2165 var $slotLink = $('body').find('.pt_product-search-result .category-slot a'); 2166 var urlRefinementData = getUrlRefinementData(); 2167 var sidebarRefinements = getSidebarRefinements(); 2168 $slotLink.each(function(index, value) { 2169 var linkRefinementType = $(value).data('link-attribute-value'); 2170 for (var refinement in urlRefinementData.parameters) { 2171 if (refinement.match(/^\prefv/)) { 2172 var refinementValues = urlRefinementData.parameters[refinement].split('%7C'); 2173 for (var index = 0; index < refinementValues.length; index++) { 2174 if (refinementValues[index] === linkRefinementType) { 2175 $(value).addClass('refinement-active'); 2176 } 2177 } 2178 } 2179 }
2180 if (linkRefinementType != undefined) { 2181 var foundInSidebar = false; 2182 for (var index = 0; index < sidebarRefinements.length; index++) { 2183 if (sidebarRefinements[index] === linkRefinementType) { 2184 var foundInSidebar = true; 2185 } 2186 } 2187 if (!foundInSidebar) { 2188 $(value).closest('li').remove(); 2189 } 2190 } 2191 }); 2192 $slotLink.closest('.section-block').removeClass('hidden'); 2193 } 2194 2195 /** 2196 * helper function to get a list of existing refinements from the URL 2197 */ 2198 function getUrlRefinementData() { 2199 var refinements = location.search.substr(1).split('&'); 2200 var urlRefinementData = { 2201 newRefinementStartNumber: 1, 2202 parameters: {}, 2203 hasRefinements: false 2204 }; 2205 if (refinements.length > 0) { 2206 for (var index = 0; index < refinements.length; index++) { 2207 var parameter = refinements[index].split('='); 2208 if (parameter[0].match(/^\prefn/)) { 2209 urlRefinementData.newRefinementStartNumber++; 2210 urlRefinementData.hasRefinements = true; 2211 urlRefinementData.parameters[parameter[0]] = parameter[1]; 2212 } 2213 if (parameter[0].match(/^\prefv/)) { 2214 urlRefinementData.parameters[parameter[0]] = parameter[1]; 2215 } 2216 } 2217 } 2218 return urlRefinementData; 2219 } 2220 2221 /** 2222 * helper function to get a list of refinement names present in refinement sidebar 2223 */ 2224 function getSidebarRefinements() { 2225 var sidebarRefinementList = []; 2226 $('#secondary.refinements .checkbox input').each(function(index, value) { 2227 if ($(value).attr('id').match(/^field/)) { 2228 var refinementName = $(value).attr('id').split('-')[1]; 2229 sidebarRefinementList.push(refinementName); 2230 } 2231 }); 2232 return sidebarRefinementList; 2233 } 2234 2235 //ready #navigation for interaction (arrests odd initial interaction on touch devices) 2236 $("#navigation").addClass("hoverReady"); 2237 2238 // Switch show text 2239 $('.switch input').change(function () { 2240 if($(this).prop('checked')) { 2241 $(this) 2242 .closest('.result-options') 2243 .addClass('show-info'); 2244 } else { 2245 $(this) 2246 .closest('.result-options') 2247 .removeClass('show-info'); 2248 } 2249 }); 2250 2251 if($('body').find('.result-options .switch input[name="field-true"]').prop('checked')) { 2252 var toggleBtn = $('body').find('.result-options .switch input[name="field-switch"]'); 2253 2254 if(!toggleBtn.prop('checked')) { 2255 toggleBtn.closest('.result-options').addClass('show-info'); 2256 toggleBtn.closest('.result-options').find('input[name="field-switch"]').attr('checked', 'checked'); 2257 } else { 2258 toggleBtn.closest('.result-options').removeClass('show-info'); 2259 toggleBtn.closest('.result-options').find('input[name="field-switch"]').removeAttr('checked'); 2260 } 2261 } 2262 2263 $('.swatches > li > ul').on('click', 'a', function(event) { 2264 event.preventDefault(); 2265 2266 $(this) 2267 .toggleClass('current') 2268 .parent() 2269 .siblings() 2270 .find('.current') 2271 .removeClass('current'); 2272 }); 2273 2274 // Generic slider init 2275 sliders.init('.slider .slides'); 2276 2277 $('.service-toggle-item').on('click', function (event) { 2278 event.preventDefault(); 2279 2280 $(this).toggleClass('active'); 2281 2282 $(this).next('.customer-service-inner').toggleClass('open'); 2283 $(this).next('.customer-service-inner').slideToggle(); 2284 }); 2285 2286 $('.top-brands .category-head').on('click', function (event) { 2287 event.preventDefault(); 2288 2289 $(this).toggleClass('active'); 2290 2291 $(this).next('.category-body').toggleClass('open'); 2292 $(this).next('.category-body').slideToggle(); 2293 }); 2294 2295 $(document).on('update', '.slider-products-primary', function() { 2296 sliders.init('.slider-products-primary .slides', {breakpoints: {0: {slidesToShow: 1, dots: true}, 768: {slidesToShow: 3}, 1024: {slidesToShow: 4}}}); 2297 }); 2298 2299 // make sure slider gets initialized for product recommendations when dynamically added 2300 if ($('.pt_product-details').length > 0 || $('.no-hits-banner').length > 0) { 2301 sliders.initializeRecommendationSlider(); 2302 } 2303 2304 $(document).off('EinsteinProductRecommendations.Initialize').on('EinsteinProductRecommendations.Initialize', function() { 2305 sliders.initializeRecommendationSlider(); 2306 }); 2307 2308 $(document).on('init-slider', '.slider-products-primary', function() { 2309 if (pageContext.site !== SiteConstants.SiteIds.BootBarnUS) {
2310 var showMobileDots = siteName == SiteConstants.SiteIds.CountryOutfittersUS ? false : true; 2311 sliders.init('.product-recommendations .slider-products-primary .slides:not(.slick-slider):not(.swiper-full-wrapper):has(li)', {loop: false, breakpoints: {0: {slidesToShow: 1, dots: showMobileDots, arrows: true}, 768: {slidesToShow: 3, dots: false, arrows: true}, 1024: {slidesToShow: 4, dots: false, arrows: true}}}, true); 2312 sliders.init('.product-recommendations-sfcc .slider-products-primary .slides:not(.slick-slider):not(.swiper-full-wrapper):has(li)', {loop: false, breakpoints: {0: {slidesToShow: 1, dots: showMobileDots, arrows: true}, 768: {slidesToShow: 3, dots: false, arrows: true}, 1024: {slidesToShow: 4, dots: false, arrows: true}}}); 2313 sliders.init('.last-visited .slider-products-primary .slides:not(.slick-slider):not(.swiper-full-wrapper):has(li)', {loop: false, breakpoints: {0: {slidesToShow: 1, dots: showMobileDots, arrows: true}, 768: {slidesToShow: 3, dots: false, arrows: true}, 1024: {slidesToShow: 4, dots: false, arrows: true}}}); 2314 } else { 2315 sliders.init('.product-recommendations .slider-products-primary .slides:not(.slick-slider):not(.swiper-full-wrapper):has(li)', {loop: false, breakpoints: {0: {slidesToShow: 1, dots: true, arrows: true}, 768: {slidesToShow: 3, dots: false, arrows: true}}}, true); 2316 sliders.init('.product-recommendations-sfcc .slider-products-primary .slides:not(.slick-slider):not(.swiper-full-wrapper):has(li)', {loop: false, breakpoints: {0: {slidesToShow: 1, dots: true, arrows: true}, 768: {slidesToShow: 4, dots: false, arrows: true}}}); 2317 sliders.init('.last-visited .slider-products-primary .slides:not(.slick-slider):not(.swiper-full-wrapper):has(li)', {loop: false, breakpoints: {0: {slidesToShow: 1, dots: true, arrows: true}, 768: {slidesToShow: 4, dots: false, arrows: true}}}); 2318 } 2319 }); 2320 2321 sliders.init('.slider-filmstrip .slides', {loop: true}); 2322 2323 sliders.initializeCategorySliders('.cat-header-content.cat-header-slider:not(.slick-initialized)'); 2324 2325 // Waypoints 2326 $('.waypoint').on('click', function(event) { 2327 event.preventDefault(); 2328 2329 var element = $(this).attr('href'); 2330 2331 $('html, body').animate({ 2332 scrollTop: $(element).offset().top 2333 }, 1000); 2334 }); 2335 2336 // Btn Expand Alt 2337 $('.btn-expand-alt').on('click', function(event) { 2338 event.preventDefault(); 2339 event.stopPropagation(); 2340 2341 var element = $(this).attr('href'); 2342 2343 2344 if ($(element).hasClass('grid-page-storeselector-popup')) { 2345 $(element).dialog('open'); 2346 2347 return; 2348 } 2349 2350 $(element) 2351 .toggleClass('show'); 2352 }); 2353 2354 $('.grid-page-storeselector-popup').dialog({ 2355 width: 450, 2356 autoOpen: false, 2357 modal: true, 2358 resizable: false 2359 }); 2360 2361 // Sidebar Close 2362 $('#secondary .close, #sort-by .close, .popup-close').on('click', function (event) { 2363 event.preventDefault(); 2364 2365 $(this) 2366 .closest('.show') 2367 .removeClass('show'); 2368 }); 2369 2370 $('.message .close').on('click', function (event) { 2371 event.preventDefault(); 2372 2373 $(this) 2374 .parent() 2375 .slideUp(); 2376 }); 2377 2378 if ($('#GlobaleFreeShippingBannerContainer').length > 0) { 2379 var globaleFreeShippingBannerObserver = new MutationObserver(function(mutations, observer) { 2380 for (var mutationKey in mutations) { 2381 var mutation = mutations[mutationKey]; 2382 if (mutation.type === 'childList') { 2383 resizeDeviceHelper(); 2384 } 2385 } 2386 }); 2387 globaleFreeShippingBannerObserver.observe(document.getElementById('GlobaleFreeShippingBannerContainer'), {attributes: false, childList: true, subtree: true }); 2388 } 2389 2390 // Back to Top button 2391 function topButtonToggle() { 2392 var $scrollTop = $win.scrollTop(); 2393 if ($scrollTop > 100 ) { 2394 $('body').addClass('btn-go-top-active'); 2395 $( '.btn-go-top' ).addClass('active'); 2396 } else { 2397 $('body').removeClass('btn-go-top-active'); 2398 $( '.btn-go-top' ).removeClass('active'); 2399 } 2400 } 2401 2402 $win.on('scroll', function () { 2403 topButtonToggle(); 2404 $(document).trigger('SearchBar.ScrollTop'); 2405 }); 2406 2407 $win.on('load', function() { 2408 accordionMobile(); 2409 accordionMobileAlt(); 2410 2411 // Disabled per BOOT-3517 2412 // $( '<span class="btn-go-top"><i class="fa fa-angle-up" aria-hidden="true"></i><span>Top</span></span>
2412' ).insertBefore($('.footer:not(.footer-mobile)')); 2413 // topButtonToggle(); 2414 }); 2415 2416 $doc.on('click', '.btn-go-top', function(e){ 2417 $('html, body').animate({scrollTop: 0},800); 2418 e.preventDefault(); 2419 }) 2420 2421 // Read More / Less 2422 $doc.on('click', '.section-offers-text .read-more', function(e) { 2423 e.preventDefault(); 2424 $(this).parents('.section-body').first().addClass('expand'); 2425 return false; 2426 }); 2427 2428 $doc.on('click', '.section-offers-text .read-less', function(e) { 2429 e.preventDefault(); 2430 $(this).parents('.section-body').first().removeClass('expand'); 2431 return false; 2432 }); 2433 2434 2435 // Accordion 2436 function accordionMobile() { 2437 $('.offer .offer-head h6').on('click', function (e) { 2438 if(event.target.nodeName == "H6"){ 2439 e.preventDefault(); 2440 e.stopImmediatePropagation(); 2441 $(this).find('.chevron-collapse').click(); 2442 } 2443 }); 2444 2445 $('.offer .offer-head h6 .chevron-collapse').on('click', function (event) { 2446 if (window.innerWidth > 1024) { 2447 return; 2448 } 2449 event.stopImmediatePropagation(); 2450 event.preventDefault(); 2451 var $this = $(this) 2452 var $parent = $this.closest('.offer') 2453 2454 if ($parent.hasClass("active")) {
2455 $parent.removeClass('active').find('.offer-body').slideUp(); 2456 2457 } 2458 else { 2459 $parent.addClass('active').find('.offer-body').slideDown(); 2460 } 2461 2462 }); 2463 2464 $win.resize(function() { 2465 if(window.innerWidth > 1024) { 2466 $('.offer .offer-body').show(); 2467 } else { 2468 $('.offer .offer-body').hide() 2469 } 2470 }); 2471 }; 2472 2473 function accordionMobileAlt() { 2474 $('.accordion-mobile .accordion-mobile-head').on('click', function (event) { 2475 if (window.innerWidth > 1024) { 2476 return; 2477 } 2478 2479 event.preventDefault(); 2480 var $this = $(this), 2481 $parent = $this.closest('.accordion-mobile'); 2482 2483 $this 2484 .toggleClass('active') 2485 .next() 2486 .stop() 2487 .slideToggle(); 2488 }); 2489 }; 2490 2491 // Accordion 2492 $(document).on('click', '.accordion-section .accordion-head', function(event) { 2493 event.preventDefault(); 2494 var $this = $(this); 2495 var $container = $this.closest('.accordion'); 2496 $this.toggleClass('active'); 2497 $this.next('.accordion-body').stop().slideToggle(400); 2498 2499 if ($this.hasClass('active') && $container.find('.slides').length > 0 && $container.find('.slick-initialized').length > 0) { 2500 $container.find('.slides').slick('refresh'); 2501 } 2502 }); 2503 2504 $(document).on('click', '.section-offers.content-columns .section-column h6.column-title', function(event) { 2505 if (pageContext.site === SiteConstants.SiteIds.SheplersUS && window.innerWidth < 768) { 2506 event.preventDefault(); 2507 $(this).toggleClass('active'); 2508 $(this).next('.column-content').stop().slideToggle(); 2509 } 2510 }); 2511 2512 // Rotate Text 2513 function rotateText($element, duration) { 2514 var lengthSlider = $element.find('.rotate-element').length; 2515 var $rotateElement = $element.find('.rotate-element'); 2516 2517 if (lengthSlider > 0) { 2518 var interval = setInterval(function () { 2519 var $rotateElementActive = $element.find('.active'); 2520 var $nextElement = $rotateElementActive.next(); 2521 2522 if($nextElement.index() === -1) { 2523 $nextElement = $element.find('.rotate-element:first-child'); 2524 2525 $nextElement 2526 .addClass('active') 2527 .siblings() 2528 .removeClass('active'); 2529 } else { 2530 $nextElement 2531 .addClass('active') 2532 .siblings() 2533 .removeClass('active'); 2534 } 2535 }, duration); 2536 } 2537 } 2538 rotateText($('.top-banner-message'), $('.top-banner-message').data('duration')); 2539 2540 if (window.innerWidth <= 767) { 2541 $('.refinement h3.toggle.expanded:not(.selected), .refinement .refinement-body.toggle-content.expanded:not(.selected)').removeClass('expanded'); 2542 } 2543 2544 // add generic toggle functionality 2545 $('.toggle:not(.disabled)').not('.expanded').next('.toggle-content').hide(); 2546 $('.toggle:not(.disabled)').click(function () { 2547 var $this = $(this); 2548 if ($this.siblings('.toggle-content').length > 0) { 2549 $this.toggleClass('expanded').next('.toggle-content').toggle(); 2550 } 2551 }); 2552 2553 // subscribe email box 2554 var $subscribeEmail = $('.subscribe-email'); 2555 if ($subscribeEmail.length > 0) { 2556 $subscribeEmail.focus(function () { 2557 var val = $(this.val()); 2558 if (val.length > 0 && val !== Resources.SUBSCRIBE_EMAIL_DEFAULT) { 2559 return; // do not animate when contains non-default value 2560 } 2561 2562 $(this).animate({color: '#999999'}, 500, 'linear', function () { 2563 $(this).val('').css('color', '#333333'); 2564 }); 2565 }).blur(function () { 2566 var val = $.trim($(this.val())); 2567 if (val.length > 0) { 2568 return; // do not animate when contains value 2569 } 2570 $(this).val(Resources.SUBSCRIBE_EMAIL_DEFAULT) 2571 .css('color', '#999999') 2572 .animate({color: '#333333'}, 500, 'linear'); 2573 }); 2574 } 2575 2576 $('.privacy-policy').on('click', function (e) { 2577 e.preventDefault(); 2578 dialog.open({ 2579 url: $(e.target).attr('href'), 2580 options: { 2581 height: 600 2582 } 2583 }); 2584 }); 2585 2586 $("#Mapmobile area").click(function () { 2587 $("#store-name").removeClass('storeheading'); 2588 var value = $(this).attr("href"); 2589 var valueName = value.replace('#',''); 2590 $('html,body').animate({ 2591 scrollTop: $("a[name="+ valueName +"]").offset().top - 200 2592 }) 2593 }); 2594 2595 $( ".user-info" ).hover( 2596 function() { 2597 $(this).addClass('active'); 2598 }, 2599 function() { 2600 $(this).removeClass('active'); 2601 } 2602 2603 ); 2604 2605 var storesMediaQuery = matchMedia('(max-width: 1024px)'); 2606 storesMediaQuery.addListener(mobileStores); 2607 $(mobileStores); 2608 2609 $(document).on('click', '.detail-toggle-item', function(e) { 2610 e.preventDefault(); 2611 2612 $(this).toggleClass('active'); 2613 $('.discount-details-entry').toggleClass('open').animate({ 'height': 'toggle', 'opacity': 'toggle' }, 250, null, function() { 2614 2615 }); 2616 }); 2617 2618 // add show/hide password functionality 2619 $(document).on('click', '[data-action="toggle-password-visibility"]', function(e) { 2620 e.preventDefault(); 2621 var $button = $(e.target); 2622 var $passwordInput = $button.closest('.password-holder').find('input'); 2623 var passwordInputType = $passwordInput.attr('type'); 2624 if (passwordInputType === 'password') { 2625 $button.addClass('password-visibility--visible'); 2626 $button.removeClass('password-visibility--invisible'); 2627 $passwordInput.attr('type', 'text').focus(); 2628 } else { 2629 $button.addClass('password-visibility--invisible'); 2630 $button.removeClass('password-visibility--visible'); 2631 $passwordInput.attr('type', 'password').focus(); 2632 } 2633 }); 2634 2635 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 2636 $(document).off('submit.CouponForm').on('submit.CouponForm', 'form.coupon-form', function(event) { 2637 event.preventDefault(); 2638 var $this = $(this); 2639 var $container = $this.closest('.enter-discount-code'); 2640 $container.find('.error').remove(); 2641 2642 $.ajax({ 2643 type: 'GET', 2644 url: Urls.addCoupon, 2645 data: { 2646 couponCode: $this.find('input[type="text"]').val(), 2647 format: 'ajax' 2648 }, 2649 success: function (data) { 2650 if (data && data.success) { 2651 window.location.href = $this.attr('action'); 2652 } else { 2653 $container.append('<div class="error">There was a problem applying that code.</div>'); 2654 } 2655 } 2656 }); 2657 }); 2658 } 2659 2660 // BOOT-5363: show/hide total savings message based on promotion callout messages 2661 $('.product-tile').each(function() { 2662 var $tile = $(this); 2663 if ($tile.find('.hide-total-savings').length > 0) { 2664 $tile.find('.product-total-savings').addClass('d-none'); 2665 } 2666 }); 2667 if($('.product-detail').find('.hide-total-savings').length > 0) { 2668 $('.product-total-savings').addClass('d-none'); 2669 } 2670} 2671 2672/** 2673 * @private 2674 * @function 2675 * @description Adds tab functionality for slider panels. When a tab is clicked, the corresponding panel will be displayed and all other panels will be hidden. 2676 */ 2677function initTabPanels() { 2678 $(document).on('click', '.slider-panel-btn', function() { 2679 $('.slider-panel-btn').attr('aria-selected','false').removeClass('slider-panel-btn-active'); 2680 $('.section-body').removeClass('slider-panel-active'); 2681 var $button = $(this); 2682 var buttonID = $button.attr('id'); 2683 var $panel = $('[aria-labelledby="' + buttonID + '"]'); 2684 $button.attr('aria-selected','true').addClass('slider-panel-btn-active'); 2685 $panel.addClass('slider-panel-active'); 2686 }); 2687} 2688 2689/** 2690 * @private 2691 * @function 2692 * @description Adds class ('js') to html for css targeting and loads js specific styles. 2693 */ 2694function initializeDom() { 2695 // add class to html for css targeting 2696 $('html').addClass('js'); 2697 // load js specific styles 2698 util.limitCharacters(); 2699 2700 // DOM EVENT FOR HEADER STORE LOCATOR
2701 $('.stores-near-content .list-stores').delegate( 'a.make-this-mystore', 'click',function(e){ 2702 e.preventDefault(); 2703 var postCode = $(this).attr('data-postalcode'); 2704 $('a.ico-crosshairs-use-my-location').data('postalcode',postCode); 2705 headerNavStoreSearch(); 2706 }); 2707 2708} 2709 2710// Resize Helper 2711function resizeDeviceHelper() { 2712 var countryOutfitters = 'country_outfitters_us'; 2713 var bootBarn = 'bootbarn_us'; 2714 var sliderMobileSwiper; 2715 2716 $('html').removeClass('size-mobile size-tablet size-desktop'); 2717 if (window.innerWidth <= 767) { 2718 $('html').addClass('size-mobile'); 2719 } else if (window.innerWidth <= 1024) { 2720 $('html').addClass('size-tablet'); 2721 } else { 2722 $('html').addClass('size-desktop'); 2723 } 2724 2725 var $navigationContainer = $('#navigation'); 2726 2727 if (!$('.second-mobnav').hasClass('active')) { 2728 $('.nav-utilities').hide(); 2729 } 2730 2731 $('.nav-utilities, #navigation').removeClass('preload'); 2732 $('#nav-utils').removeClass('loadhide'); 2733 2734 if ((siteName != bootBarn && window.innerWidth <= 1024) || window.innerWidth <= 767) { 2735 if (siteName != SiteConstants.SiteIds.BootBarnUS) { 2736 $navSecondary.insertAfter($navUl); 2737 } 2738 2739 $sectionErrorFigure.insertBefore($sectionErrorBox); 2740 $navUtilities.insertAfter($topBannerInnerLinks); 2741 if ($sliderMobile.length > 0) { 2742 sliderMobileSwiper = sliders.init('.slider-mobile', {dots: true, loop: true}); 2743 } 2744 2745 var image = $(".slider-single-image img"); 2746 $.removeData(image, 'elevateZoom'); 2747 $('.zoomContainer').remove(); 2748 2749 if($('.section-offers.all-on-sale').length){ 2750 setTimeout(function(){ 2751 $('.section-offers.all-on-sale .chevron-collapse').each(function(){ 2752 $(this).click(); 2753 }); 2754 }, 13); 2755 2756 } 2757 $('.accordion-mobile').each(function () { 2758 var accMobile = $(this); 2759 2760 if (!accMobile.hasClass('active')) { 2761 accMobile.find('.accordion-mobile-body').hide(); 2762 } 2763 }); 2764 } else { 2765 $navUl.find('.has-dropdown.active').removeClass('active'); 2766 2767 $navUtilities.insertBefore($topBannerBarInner); 2768 if (siteName != SiteConstants.SiteIds.BootBarnUS) { 2769 $navSecondary.prependTo($topBannerBar); 2770 } 2771 2772 $sectionErrorFigure.insertAfter($sectionErrorBox); 2773 $navigation.removeAttr('style'); 2774 2775 if ($sliderMobile.length > 0) { 2776 if ($sliderMobile.find('.swiper-initialized').length > 0) { 2777 sliderMobileSwiper.destroy(); 2778 } 2779 if ($sliderMobile.find('.slick-initialized').length > 0) { 2780 $sliderMobile.slick('unslick'); 2781 } 2782 } 2783 $('.accordion-mobile-body').show(); 2784 2785 $('html').removeClass('menu-active'); 2786 $('.menu-toggle').removeClass('active'); 2787 $('#navigation .level-2').hide(); 2788 } 2789 2790 resizeLayoutHelper(); 2791} 2792 2793function resizeLayoutHelper() { 2794 var newMarginTop = 0; 2795 var innerWidthThreshold; 2796 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 2797 innerWidthThreshold = 1024; 2798 } else { 2799 innerWidthThreshold = 766; /* Changing this to 766 since the mobile menu for CO and SHP isn't kicking in at 768 */ 2800 } 2801 if (window.innerWidth <= innerWidthThreshold) { 2802 newMarginTop = parseFloat($('.header-wrapper').outerHeight()); 2803 } 2804 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 2805 if (!$('html').hasClass('menu-active')) { 2806 $('#main').css('margin-top', newMarginTop); 2807 } 2808 } else { 2809 if (!$('html').hasClass('menu-active')) { 2810 $('#wrapper').css('margin-top', newMarginTop); 2811 } 2812 } 2813 if (!$('html').hasClass('initialized')) { 2814 $('html').addClass('initialized'); 2815 } 2816} 2817 2818function usemylocation(storeid) { 2819 var t_url = Urls.usecurrentlocation; 2820 if (storeid === undefined) { 2821 storeid = 'getall'; 2822 } 2823 2824 $.ajax({ 2825 url: t_url, 2826 type: 'POST', 2827 data: { 'source' : 'ajax' }, 2828 dataType: 'json', 2829 error: function() { 2830 console.log('error'); 2831 }, 2832 success: function(dataJson) { 2833 if( 'stores' in dataJson && dataJson['stores'].length > 0 ) { 2834 if(storeid == 'getall') { 2835 $('.stores-near-content .stores-near-body ul.list-stores').html(''); 2836 } 2837 $('div.stores-near-actions a.go-to-findstore').html(Resources.FIND_MORE_STORES); 2838 if ( dataJson['stores'].length == 1 ) { 2839 $('.stores-near-content').slideUp(); 2840 } 2841 dataJson['stores'].forEach(function(element, index){ 2842 var store = element; 2843 var htmlDisplay = ''; 2844 var storePhoneNumber = ('' + element['phone']).replace(/\D/g,''); 2845 var postalCodeVal = ( typeof element['postalCode'] != 'undefined' ? element['postalCode'] : '' ); 2846 2847 if(storeid == 'getall') { 2848 if(index == 0) { 2849 htmlDisplay += '<span class="red store-name-value">'+element['name']+'</span>'; 2850 htmlDisplay += element['address1']; 2851 htmlDisplay += '<br/>'+ ( typeof element['city'] != 'undefined' ? element['city'] +', ' : '' ); 2852 htmlDisplay += ( typeof element['stateCode'] != 'undefined' ? element['stateCode'] +' ' : '' ); 2853 htmlDisplay += postalCodeVal; 2854 htmlDisplay += '<br /><a href="tel:'+storePhoneNumber+'">'+store['phone']+'</a>'; 2855 htmlDisplay += '<span>'+unescape(store['storeHours'])+'</span>'; 2856 $('.stores-dropdown .current-store address').html(htmlDisplay); 2857 $('.stores-dropdown .current-store').slideDown(); 2858 } else { 2859 htmlDisplay += '<li><h5><span>'+element['name']+'</span><a href="#" class="make-this-mystore" id="' + element['ID'] + '" data-postalcode="'+postalCodeVal+'">'+Resources.MAKE_THIS_MYSTORE+'</a></h5>'; 2860 htmlDisplay += '<address>'+element['address1']; 2861 htmlDisplay += '<br/>'+ ( typeof element['city'] != 'undefined' ? element['city'] +', ' : '' ); 2862 htmlDisplay += ( typeof element['stateCode'] != 'undefined' ? element['stateCode'] +' ' : '' ); 2863 htmlDisplay += postalCodeVal; 2864 htmlDisplay += '<br /><a href="tel:'+storePhoneNumber+'">'+store['phone']+'</a>'; 2865 htmlDisplay += '/<address>' + unescape(store['storeHours']); 2866 htmlDisplay += '</li>'; 2867 $('.stores-near-content .stores-near-body ul.list-stores').append($(htmlDisplay)); 2868 $('.stores-near-content').slideDown(); 2869 } 2870 } else { 2871 if(storeid == element['ID']) { 2872 htmlDisplay += '<span class="red store-name-value">'+element['name']+'</span>'; 2873 htmlDisplay += element['address1']; 2874 htmlDisplay += '<br/>'+ ( typeof element['city'] != 'undefined' ? element['city'] +', ' : '' ); 2875 htmlDisplay += ( typeof element['stateCode'] != 'undefined' ? element['stateCode'] +' ' : '' ); 2876 htmlDisplay += postalCodeVal; 2877 htmlDisplay += '<br /><a href="tel:'+storePhoneNumber+'">'+store['phone']+'</a>'; 2878 htmlDisplay += '<span>'+unescape(store['storeHours'])+'</span>'; 2879 $('.stores-dropdown .current-store address').html(htmlDisplay); 2880 $('.stores-dropdown .current-store').slideDown(); 2881 } 2882 } 2883 2884 }); 2885 } else { 2886 $('.stores-near-content').slideUp(); 2887 $('div.stores-near-actions a.go-to-findstore').html(Resources.FIND_STORES); 2888 $('.stores-dropdown .current-store').slideUp(); 2889 if ( $('.stores-dropdown h3.no_results').length == 0 ) { 2890 $('.stores-dropdown').prepend('<h3 class="no_results">'+Resources.NO_STORE_RESULTS+'</h3>'); 2891 } else { 2892 $('.stores-dropdown h3.no_results').fadeIn(); 2893 } 2894 $('.stores-dropdown h3.no_results').show().delay(2000).fadeOut(); 2895 } 2896 } 2897 }); 2898} 2899 2900 2901/** 2902 * 2903 * Moves customer specific stores info in main header to mobile utility header. 2904 * This is needed because the store info is part of a remote include in another spot on desktop. 2905 * 2906 */ 2907function mobileStores() { 2908 var $mobileStoreMetadata = $('#mobile-storeMetadata'); 2909 var $mobileStoreBannerText = $('#mobile-banner-store-text'); 2910 2911 if ($mobileStoreMetadata !== undefined && $mobileStoreMetadata != null && $mobileStoreMetadata.length > 0){ 2912 if ($mobileStoreBannerText !== undefined && $mobileStoreBannerText != null && $mobileStoreBannerText.length > 0){ 2913 var isOpen = $mobileStoreMetadata.data('is-open'); 2914 if (isOpen){ 2915 var storeName = $mobileStoreMetadata.data('store-name'); 2916 var openUntil = $mobileStoreMetadata.data('open-until'); 2917 var closingTime = $mobileStoreMetadata.data('closing-time'); 2918 var bannerText = storeName + ' • ' + openUntil + ' ' + closingTime; 2919 $mobileStoreBannerText.html(bannerText); 2920 } else { 2921 var closedText = $mobileStoreMetadata.data('closed-text'); 2922 $mobileStoreBannerText.html(closedText); 2923 } 2924 } 2925 } 2926} 2927 2928function setCookie(cname, cvalue, exdays) { 2929 var d = new Date(); 2930 d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); 2931 var expires = "expires="+d.toUTCString(); 2932 document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; 2933 } 2934 2935 function getCookie(cname) { 2936 var name = cname + "="; 2937 var ca = document.cookie.split(';'); 2938 for(var i = 0; i < ca.length; i++) { 2939 var c = ca[i]; 2940 while (c.charAt(0) == ' ') { 2941 c = c.substring(1); 2942 } 2943 if (c.indexOf(name) == 0) { 2944 return c.substring(name.length, c.length); 2945 } 2946 } 2947 return ""; 2948 } 2949 2950 2951 2952function addPromotionDataLayers() { 2953 var $containers = $('.accordion:visible, .section-offers:visible, .cat-header-content.cat-header-slider:visible'); 2954 if ($containers.length > 0) { 2955 $containers.each(function() { 2956 var $container = $(this); 2957 if ($container.attr('data-layer-added') != 'true' && $container.find('.product-tile').length > 0) { 2958 var containerId = $container.attr('content-slot-id') || $container.attr('id'); 2959 2960 var dataObject = { 2961 promotion_name: containerId 2962 } 2963 2964 var pageType; 2965 var $wrapper = $container.closest('.add-to-cart-modal'); 2966 if ($wrapper.length > 0) { 2967 pageType = 'addtocartmodal'; 2968 } 2969 2970 if (!pageType) { 2971 $wrapper = $('#wrapper'); 2972 if ($wrapper.length > 0) { 2973 if (pageContext && pageContext.type) { 2974 switch (pageContext.type) { 2975 case 'storefront': 2976 pageType = 'Homepage'; 2977 break; 2978 2979 case 'search': 2980 pageType = 'PLP'; 2981 break; 2982 2983 case 'product': 2984 pageType = 'PDP'; 2985 break; 2986 2987 case 'cart': 2988 pageType = 'Cart'; 2989 break; 2990 2991 case 'onepcheckout_groups': 2992 pageType = 'Checkout'; 2993 break; 2994 2995 case 'orderconfirmation': 2996 pageType = 'Order Confirmation'; 2997 break; 2998 2999 case 'customerservice': 3000 pageType = 'Customer Service'; 3001 break; 3002 3003 case 'account': 3004 pageType = 'Account'; 3005 break; 3006 3007 case 'content': 3008 pageType = 'Content Page'; 3009 break; 3010 3011 case 'error': 3012 pageType = 'Error Page'; 3013 break; 3014 } 3015 } 3016 } 3017 } 3018 3019 if (pageType) { 3020 dataObject.promotion_id = pageType; 3021 } 3022 3023 GoogleTagManagerClient.PushDataLayerForDataLayerType('ViewPromotion', dataObject, { Container: $container }); 3024 $container.attr('data-layer-added', true); 3025 } 3026 }); 3027 } 3028} 3029 3030var pages = { 3031 storefront: require('./pages/storefront'), 3032 account: require('./pages/account'), 3033 bootfinder: require('./pages/bootfinder'), 3034 cart: require('./pages/cart'), 3035 cart_echo: require('./pages/cart_echo'),
3036 checkout: require('./pages/checkout'), 3037 checkout_echo: require('../../../app_storefront_core/cartridge/js/pages/checkout_echo'), 3038 compare: require('./pages/compare'), 3039 product: require('./pages/product'), 3040 registry: require('./pages/registry'), 3041 search: require('./pages/search'), 3042 storelocator: require('./pages/storelocator'), 3043 onepcheckout_groups: require('./pages/onepcheckout_groups'), 3044 orderconfirmation: require('./pages/orderconfirmation'), 3045 categorylanding: require('./pages/categorylanding'), 3046 content: require('./pages/content'), 3047 authentication_EmailAddressCapture: require('./pages/Authentication/EmailAddressCapture') 3048}; 3049 3050var lastScrollTop = 0; 3051var scrollDelta = 100; 3052var fixedHeaderLimit = 800; 3053var headerWrapper = $('.header-wrapper'); 3054 3055var app = { 3056 init: function () { 3057 $.extend(page, window.pageContext); 3058 3059 $sliderMobile = $('.slider-mobile'); 3060 $navSecondary = $('.nav-secondary'); 3061 $navUtilities = $('.nav-utilities'); 3062 $navUl = $('#navigation > ul'); 3063 $topBannerBar = $('.top-banner-bar'); 3064 $topBannerBarInner = $('.top-banner-bar-inner'); 3065 $navigation = $('#navigation'); 3066 $topBannerInnerLinks = $('.top-banner-inner-links'); 3067 $selectSort = $('#sort-by'); 3068 $secondaryHead = $('#secondary .refinements-head'); 3069 $searchResultContainer = $('#search-result'); 3070 $productContainerImage = $('#pdpMain .product-image-container'); 3071 $productDetail = $('#pdpMain .product-detail'); 3072 $sectionCheckout = $('.section-checkout'); 3073 $mainInnerAlt = $('.main-inner-alt'); 3074 $sectionErrorFigure = $('.section-error figure'); 3075 $sectionErrorBox = $('.section-error .box'); 3076 $footerMenuItems = $('.footer-item .content-asset'); 3077 $promoMessages = $productContainerImage.find('.promo-messages'); 3078 siteName = pageContext.site || ''; 3079 window.sgDialog = require('./dialog'); 3080 window.sgUtil = require('./util'); 3081 3082 if (document.cookie.length === 0) { 3083 $('<div/>').addClass('browser-compatibility-alert cookies').append($('<p/>').addClass('browser-error').html(Resources.COOKIES_DISABLED)).appendTo('#browser-check'); 3084 $('.browser-compatibility-alert.cookies').prepend('<i class="fa fa-exclamation-triangle fa-3x pull-left"></i>'); 3085 } 3086 initializeDom(); 3087 initializeEvents(); 3088 3089 login.init(page.options); 3090 register.init(); 3091 navigation.Initialize(); 3092 countries.init(); 3093 //tooltip.init(); 3094 minicart.init(); 3095 validator.init(); 3096 rating.init(); 3097 searchplaceholder.init(); 3098 rotate3d.init(); 3099 count_down.init(); 3100 lazyloadPageElements.init(); 3101 giftCardBalanceInquiryHelper.initializeAllFoundComponents(); 3102 slickHelpers.init(); 3103 if (pageContext && 'type' in pageContext && pageContext.type != 'cart' && pageContext.type != 'onepcheckout_groups') { 3104 quantityStepper.init(); 3105 }
3106 wishlist.init(); 3107 Globale.initialize(); 3108 cordialTagging.init(); 3109 3110 // execute page specific initializations 3111 3112 var ns = page.ns; 3113 if (ns && pages[ns] && pages[ns].init) { 3114 pages[ns].init(page.options || {}); 3115 } 3116 3117 GoogleTagManagerClient.PushDataLayerForPage(page); 3118 EmailSignup.Initialize(page); 3119 3120 // Check TLS status if indicated by site preference 3121 if (SitePreferences.CHECK_TLS === true) { 3122 tls.getUserAgent(); 3123 } 3124 3125 // Initialize Sticky header events 3126 $(window).scroll(function(event){ 3127 if ((siteName == SiteConstants.SiteIds.BootBarnUS || siteName == SiteConstants.SiteIds.SheplersUS) && window.innerWidth <= 1023) { 3128 if ($(window).scrollTop() > fixedHeaderLimit) { 3129 headerWrapper.addClass('header-fixed'); 3130 } else { 3131 headerWrapper.removeClass('header-fixed'); 3132 } 3133 3134 var nowScrollTop = $(this).scrollTop(); 3135 if(Math.abs(lastScrollTop - nowScrollTop) >= scrollDelta){ 3136 if (nowScrollTop > lastScrollTop){ 3137 if (headerWrapper.hasClass('header-fixed-active')) { 3138 headerWrapper.removeClass('header-fixed-active'); 3139 } 3140 } else { 3141 if ($(window).scrollTop() > fixedHeaderLimit) { 3142 if (!headerWrapper.hasClass('header-fixed-active')) { 3143 headerWrapper.addClass('header-fixed-active'); 3144 } 3145 } else { 3146 headerWrapper.removeClass('header-fixed-active'); 3147 } 3148 } 3149 lastScrollTop = nowScrollTop; 3150 } 3151 } 3152 3153 if (siteName == SiteConstants.SiteIds.BootBarnUS && $('html').hasClass('size-tablet') && window.innerWidth == 1024) { 3154 var nowScrollTop = $(this).scrollTop(); 3155 if(Math.abs(nowScrollTop) > 300) { 3156 if ($('#navigation .has-dropdown').hasClass('active')) { 3157 $('#navigation .has-dropdown').removeClass('active'); 3158 $('html').removeClass('menu-active'); 3159 $('.header-wrapper .top-banner').removeClass('nav-active'); 3160 $('html').removeClass('desktop-nav-active'); 3161 } 3162 3163 } 3164 } 3165 3166 if ( $(".top-banner-inner .primary-logo a img.mobile-logo[src*=sheplers_us]").length ) { 3167 if ( $(".second-mobnav").length > 0 && $(".second-mobnav").is(":visible") ) { 3168 var st = $(this).scrollTop(); 3169 3170 if (st > 0) { 3171 $(".top-banner-bar .shell").hide(); 3172 $(".top-banner div.top-banner-inner").css("margin-top","0px"); 3173 $(".top-banner div.top-banner-bar .header-search").attr("style","top:55px !important"); 3174 } else { 3175 $(".top-banner-bar .shell").show(); 3176 $(".top-banner div.top-banner-inner").css("margin-top","25px"); 3177 $(".top-banner div.top-banner-bar .header-search").attr("style","top:80px !important"); 3178 } 3179 } else { 3180 $(".top-banner-bar .shell").show(); 3181 $(".top-banner div.top-banner-inner").css("margin-top","0px"); 3182 $(".top-banner div.top-banner-bar .header-search").attr("style","top:80px !important"); 3183 if ( $(".top-banner-bar-aside #second-mobnav").length ) { 3184 $(".top-banner-bar-aside #second-mobnav").show(); 3185 } 3186 } 3187 } 3188 }); 3189 3190 resizeDeviceHelper(); 3191 } 3192}; 3193 3194// general extension functions 3195(function () { 3196 String.format = function () { 3197 var s = arguments[0]; 3198 var i, len = arguments.length - 1; 3199 for (i = 0; i < len; i++) { 3200 var reg = new RegExp('\\{' + i + '\\}', 'gm'); 3201 s = s.replace(reg, arguments[i + 1]); 3202 } 3203 return s; 3204 }; 3205})(); 3206 3207// initialize app 3208$(document).ready(function () { 3209 app.init(); 3210}); 3211 3212(function () { 3213 String.format = function () { 3214 var s = arguments[0]; 3215 var i, len = arguments.length - 1; 3216 for (i = 0; i < len; i++) { 3217 var reg = new RegExp('\\{' + i + '\\}', 'gm'); 3218 s = s.replace(reg, arguments[i + 1]); 3219 } 3220 return s; 3221 }; 3222})(); 3223 3224 3225},{"../../../app_storefront_core/cartridge/js/pages/checkout_echo":67,"../../../app_storefront_workforce/cartridge/js/login":109,"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"./ajax":3,"./alert":4,"./captcha":14,"./components/CordialTagging":17,"./components/EmailForm":18,"./components/EmailSignup":19,"./components/Globale":22,"./components/NavigationController":26,"./components/Notification":27,"./cookieprivacy":33,"./countdown":34,"./countries":35,"./dialog":36,"./helpers/GiftCardBalanceInquiryHelper":40,"./jquery-ext":41,"./lazyloadPageElements":42,"./login":43,"./loginDialog":44,"./minicart":45,"./page":46,"./pages/Authentication/EmailAddressCapture":47,"./pages/account":48,"./pages/bootfinder":49,"./pages/cart":50,"./pages/cart_echo":51,"./pages/categorylanding":52,"./pages/c
3225heckout":62,"./pages/compare":68,"./pages/content":69,"./pages/onepcheckout_groups":70,"./pages/orderconfirmation":71,"./pages/product":75,"./pages/registry":79,"./pages/search":80,"./pages/storefront":81,"./pages/storelocator":82,"./productRotate3d.js":85,"./quantityStepper":87,"./rating":89,"./register":90,"./searchbar":91,"./searchplaceholder":92,"./slickSliderHelpers":94,"./sliders":95,"./tls":100,"./util":102,"./validator":103,"./watermark":104,"./wishlist":105,"promise":134}],6:[function(require,module,exports){ 3226'use strict'; 3227 3228var dialog = require('./dialog'), 3229 page = require('./page'), 3230 util = require('./util'); 3231 3232var selectedList = []; 3233var maxItems = 1; 3234var bliUUID = ''; 3235 3236/** 3237 * @private 3238 * @function 3239 * description Gets a list of bonus products related to a promoted product 3240 */ 3241function getBonusProducts() { 3242 var bonusproducts = []; 3243 3244 var i, len; 3245 for (i = 0, len = selectedList.length; i < len; i++) { 3246 var p = { 3247 pid: selectedList[i].pid, 3248 qty: selectedList[i].qty, 3249 options: {} 3250 }; 3251 var a, alen, bp = selectedList[i]; 3252 if (bp.options) { 3253 for (a = 0, alen = bp.options.length; a < alen; a++) { 3254 var opt = bp.options[a]; 3255 p.options = {optionName:opt.name, optionValue:opt.value}; 3256 } 3257 } 3258 bonusproducts.push({product:p}); 3259 } 3260 return {bonusproducts: bonusproducts}; 3261} 3262 3263var selectedItemTemplate = function (data) { 3264 var attributes = ''; 3265 for (var attrID in data.attributes) { 3266 var attr = data.attributes[attrID]; 3267 attributes += '<li data-attribute-id="' + attrID + '">\n'; 3268 attributes += '<span class="display-name">' + attr.displayName + '</span>: '; 3269 attributes += '<span class="display-value">' + attr.displayValue + '</span>\n'; 3270 attributes += '</li>'; 3271 } 3272 attributes += '<li class="item-qty">\n'; 3273 attributes += '<span class="display-name">Qty</span>: '; 3274 attributes += '<span class="display-value">' + data.qty + '</span>'; 3275 return [ 3276 '<li class="selected-bonus-item" data-uuid="' + data.uuid + '" data-pid="' + data.pid + '">', 3277 '<i class="remove-link fa fa-remove" title="Remove this product" href="#"></i>', 3278 '<div class="item-name">' + data.name + '</div>', 3279 '<ul class="item-attributes">', 3280 attributes, 3281 '<ul>', 3282 '<li>' 3283 ].join('\n'); 3284}; 3285 3286// hide swatches that are not selected or not part of a Product Variation Group 3287var hideSwatches = function () { 3288 $('.bonus-product-item:not([data-producttype="master"]) .swatches li').not('.selected').not('.variation-group-value').hide(); 3289 // prevent unselecting the selected variant 3290 $('.bonus-product-item .swatches .selected').on('click', function () { 3291 return false; 3292 }); 3293}; 3294 3295/** 3296 * @private 3297 * @function 3298 * @description Updates the summary page with the selected bonus product 3299 */ 3300function updateSummary() { 3301 var $bonusProductList = $('#bonus-product-list'); 3302 if (!selectedList.length) { 3303 $bonusProductList.find('li.selected-bonus-item').remove(); 3304 } else { 3305 var ulList = $bonusProductList.find('ul.selected-bonus-items').first(); 3306 var i, len; 3307 for (i = 0, len = selectedList.length; i < len; i++) { 3308 var item = selectedList[i]; 3309 var li = selectedItemTemplate(item); 3310 $(li).appendTo(ulList); 3311 } 3312 } 3313 3314 // get remaining item count 3315 var remain = maxItems - selectedList.length; 3316 $bonusProductList.find('.bonus-items-available').text(remain); 3317 if (remain <= 0) { 3318 $bonusProductList.find('.select-bonus-item').attr('disabled', 'disabled'); 3319 } else { 3320 $bonusProductList.find('.select-bonus-item').removeAttr('disabled'); 3321 } 3322 $(document).trigger('update-summary'); 3323} 3324 3325function initializeGrid () { 3326 var $bonusProduct = $('#bonus-product-dialog'), 3327 $bonusProductList = $('#bonus-product-list'), 3328 bliData = $bonusProductList.data('line-item-detail'); 3329 maxItems = bliData.maxItems; 3330 bliUUID = bliData.uuid; 3331 3332 if (bliData.itemCount >= maxItems) { 3333 $bonusProductList.find('.select-bonus-item').attr('disabled', 'disabled'); 3334 } 3335 3336 var cartItems = $bonusProductList.find('.selected-bonus-item'); 3337 cartItems.each(function () { 3338 var ci = $(this); 3339 var product = { 3340 uuid: ci.data('uuid'), 3341 pid: ci.data('pid'), 3342 qty: ci.find('.item-qty').text(), 3343 name: ci.find('.item-name').html(), 3344 attributes: {} 3345 }; 3346 var attributes = ci.find('ul.item-attributes li'); 3347 attributes.each(function () { 3348 var li = $(this); 3349 product.attributes[li.data('attributeId')] = { 3350 displayName:li.children('.display-name').html(), 3351 displayValue:li.children('.display-value').html() 3352 }; 3353 }); 3354 selectedList.push(product); 3355 }); 3356 3357 $bonusProductList.on('click', '.bonus-product-item a[href].swatchanchor', function (e) { 3358 e.preventDefault(); 3359 var url = this.href, 3360 $this = $(this); 3361 url = util.appendParamsToUrl(url, { 3362 'source': 'bonus', 3363 'format': 'ajax' 3364 }); 3365 $.ajax({ 3366 url: url, 3367 success: function (response) { 3368 $this.closest('.bonus-product-item').empty().html(response); 3369 hideSwatches(); 3370 } 3371 }); 3372 }) 3373 .on('change', '.input-text', function () { 3374 $bonusProductList.find('.select-bonus-item').removeAttr('disabled'); 3375 $(this).closest('.bonus-product-form').find('.quantity-error').text(''); 3376 }) 3377 .on('click', '.select-bonus-item', function (e) { 3378 e.preventDefault(); 3379 if (selectedList.length >= maxItems) { 3380 $bonusProductList.find('.select-bonus-item').attr('disabled', 'disabled'); 3381 $bonusProductList.find('.bonus-items-available').text('0'); 3382 return; 3383 } 3384 3385 var form = $(this).closest('.bonus-product-form'), 3386 detail = $(this).closest('.product-detail'), 3387 uuid = form.find('input[name="productUUID"]').val(), 3388 qtyVal = form.find('input[name="Quantity"]').val(), 3389 qty = (isNaN(qtyVal)) ? 1 : (+qtyVal); 3390 3391 if (qty > maxItems) { 3392 $bonusProductList.find('.select-bonus-item').attr('disabled', 'disabled'); 3393 form.find('.quantity-error').text(Resources.BONUS_PRODUCT_TOOMANY); 3394 return; 3395 } 3396 3397 var product = { 3398 uuid: uuid, 3399 pid: form.find('input[name="pid"]').val(), 3400 qty: qty, 3401 name: detail.find('.product-name').text(), 3402 attributes: detail.find('.product-variations').data('attributes'), 3403 options: [] 3404 }; 3405 3406 var optionSelects = form.find('.product-option'); 3407 3408 optionSelects.each(function () { 3409 product.options.push({ 3410 name: this.name, 3411 value: $(this).val(), 3412 display: $(this).children(':selected').first().html() 3413 }); 3414 }); 3415 selectedList.push(product); 3416 updateSummary(); 3417 }) 3418 .on('click', '.remove-link', function (e) { 3419 e.preventDefault(); 3420 var container = $(this).closest('.selected-bonus-item'); 3421 if (!container.data('uuid')) { return; } 3422 3423 var uuid = container.data('uuid'); 3424 var i, len = selectedList.length; 3425 for (i = 0; i < len; i++) { 3426 if (selectedList[i].uuid === uuid) { 3427 selectedList.splice(i, 1); 3428 break; 3429 } 3430 } 3431 updateSummary(); 3432 }) 3433 .on('click', '.add-to-cart-bonus', function (e) { 3434 e.preventDefault(); 3435 var url = util.appendParamsToUrl(Urls.addBonusProduct, {bonusDiscountLineItemUUID: bliUUID}); 3436 var bonusProducts = getBonusProducts(); 3437 if (bonusProducts.bonusproducts[0].product.qty > maxItems) { 3438 bonusProducts.bonusproducts[0].product.qty = maxItems; 3439 } 3440 // make the server call 3441 $.ajax({ 3442 type: 'POST', 3443 dataType: 'json', 3444 cache: false, 3445 contentType: 'application/json', 3446 url: url, 3447 data: JSON.stringify(bonusProducts) 3448 }) 3449 .done(function () { 3450 // success 3451 page.refresh(); 3452 }) 3453 .fail(function (xhr, textStatus) { 3454 // failed 3455 if (textStatus === 'parsererror') { 3456 window.alert(Resources.BAD_RESPONSE); 3457 } else { 3458 window.alert(Resources.SERVER_CONNECTION_ERROR); 3459 } 3460 }) 3461 .always(function () { 3462 $bonusProduct.dialog('close'); 3463 }); 3464 }) 3465 .on('click', '#more-bonus-products', function (e) { 3466 e.preventDefault(); 3467 var uuid = $('#bonus-product-list').data().lineItemDetail.uuid; 3468 3469 //get the next page of choice of bonus products 3470 var lineItemDetail = JSON.parse($('#bonus-product-list').attr('data-line-item-detail')); 3471 lineItemDetail.pageStart = lineItemDetail.pageStart + lineItemDetail.pageSize; 3472 $('#bonus-product-list').attr('data-line-item-detail', JSON.stringify(lineItemDetail)); 3473 3474 var url = util.appendParamsToUrl(Urls.getBonusProducts, { 3475 bonusDiscountLineItemUUID: uuid, 3476 format: 'ajax', 3477 lazyLoad: 'true', 3478 pageStart: lineItemDetail.pageStart, 3479 pageSize: $('#bonus-product-list').data().lineItemDetail.pageSize, 3480 bonusProductsTotal: $('#bonus-product-list').data().lineItemDetail.bpTotal 3481 }); 3482 3483 $.ajax({ 3484 type: 'GET', 3485 cache: false, 3486 contentType: 'application/json', 3487 url: url 3488 }) 3489 .done(function (data) { 3490 //add the new page to DOM and remove 'More' link if it is the last page of results 3491 $('#more-bonus-products').before(data); 3492 if ((lineItemDetail.pageStart + lineItemDetail.pageSize) >= $('#bonus-product-list').data().lineItemDetail.bpTotal) { 3493 $('#more-bonus-products').remove(); 3494 } 3495 }) 3496 .fail(function (xhr, textStatus) { 3497 if (textStatus === 'parsererror') { 3498 window.alert(Resources.BAD_RESPONSE); 3499 } else { 3500 window.alert(Resources.SERVER_CONNECTION_ERROR); 3501 } 3502 }); 3503 }); 3504} 3505 3506var bonusProductsView = { 3507 /** 3508 * @function
3509 * @description Open the list of bonus products selection dialog 3510 */ 3511 show: function (url) { 3512 var $bonusProduct = $('#bonus-product-dialog'); 3513 // create the dialog 3514 dialog.open({ 3515 target: $bonusProduct, 3516 url: url, 3517 options: { 3518 width: 795, 3519 title: Resources.BONUS_PRODUCTS 3520 }, 3521 callback: function () { 3522 initializeGrid(); 3523 hideSwatches(); 3524 } 3525 }); 3526 }, 3527 /** 3528 * @function 3529 * @description Open bonus product promo prompt dialog 3530 */ 3531 loadBonusOption: function () { 3532 var self = this, 3533 bonusDiscountContainer = document.querySelector('.bonus-discount-container'); 3534 if (!bonusDiscountContainer) { return; } 3535 3536 // get the html from minicart, then trash it 3537 var bonusDiscountContainerHtml = bonusDiscountContainer.outerHTML; 3538 bonusDiscountContainer.parentNode.removeChild(bonusDiscountContainer); 3539 3540 dialog.open({ 3541 html: bonusDiscountContainerHtml, 3542 options: { 3543 width: 400, 3544 title: Resources.BONUS_PRODUCT, 3545 buttons: [{ 3546 text: Resources.SELECT_BONUS_PRODUCTS, 3547 click: function () { 3548 var uuid = $('.bonus-product-promo').data('lineitemid'), 3549 url = util.appendParamsToUrl(Urls.getBonusProducts, { 3550 bonusDiscountLineItemUUID: uuid, 3551 source: 'bonus', 3552 format: 'ajax', 3553 lazyLoad: 'false', 3554 pageStart: 0, 3555 pageSize: 10, 3556 bonusProductsTotal: -1 3557 }); 3558 $(this).dialog('close'); 3559 self.show(url); 3560 } 3561 }, { 3562 text: Resources.NO_THANKS, 3563 click: function () { 3564 $(this).dialog('close'); 3565 } 3566 }] 3567 }, 3568 callback: function () { 3569 // show hide promo details 3570 $('.show-promo-details').on('click', function () { 3571 $('.promo-details').toggleClass('visible'); 3572 }); 3573 } 3574 }); 3575 } 3576}; 3577 3578module.exports = bonusProductsView; 3579 3580},{"./dialog":36,"./page":46,"./util":102}],7:[function(require,module,exports){ 3581'use strict'; 3582 3583var _ = require('lodash'); 3584var addToCartOptionsStoreSearch = require('./AddToCartOptionsStoreSearch'); 3585var dialog = require('../../dialog'); 3586var loadingIndicator = require('../../components/LoadingIndicator'); 3587var LocalDeliveryDialog = require('./LocalDeliveryDialog'); 3588var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 3589var util = require('../../util'); 3590var tooltip = require('../../tooltip'); 3591 3592exports.initialize = initialize; 3593 3594var options; 3595var optionsStoreSearch; 3596var optionsLocalDelivery; 3597var dataBuffer; 3598var storeSearch; 3599var localDeliveryStoreSearch; 3600 3601var resultContainerTemplate; 3602var resultItemTemplate; 3603var localDeliveryDecorator; 3604 3605var $container; 3606var $storeSearchButton; 3607var $storeSearchButtonContainer; 3608var $addToCartOptions; 3609var $bopisButton; 3610 3611function initialize($containerParameter, optionsParameter) { 3612 dataBuffer = {}; 3613 options = $.extend({ 3614 successCallback: null, 3615 errorCallback: null, 3616 StorePickupOnly: $('#quantity_source_type').val() == 'BOP' 3617 }, optionsParameter); 3618 3619 var selectedSize; 3620 var $selectedSizeInDropdown = $('div.product-variations .size.size-options li.selected'); 3621 var $selectedLength = $('div.product-variations .length.length-options li.selected'); 3622 var $selectedWidth = $('div.product-variations .width.width-options li.selected'); 3623 if ($selectedLength.length && $selectedWidth.length) { 3624 selectedSize = $selectedLength.find('[data-length-name]').attr('data-length-name') + ' ' + $selectedWidth.find('[data-width-name]').attr('data-width-name'); 3625 } else if ($selectedSizeInDropdown.length > 0) { 3626 selectedSize = $selectedSizeInDropdown.find('[data-size-name]').attr('data-size-name'); 3627 } else { 3628 selectedSize = util.getPreferenceValueFromWindowLocation('size'); 3629 } 3630 storeSearch = new addToCartOptionsStoreSearch(); 3631 localDeliveryStoreSearch = new addToCartOptionsStoreSearch(); 3632 optionsStoreSearch = Object.assign(options); 3633 optionsLocalDelivery = Object.assign({ 3634 LocalDeliveryOnly: true, 3635 Events: { 3636 SelectStore: 'Bopis.LocalDelivery.StoreSelect' 3637 }, 3638 Functions: { 3639 Close: function() { 3640 $('.dialog-bopis-options').removeClass('hidden'); 3641 $('.ui-widget-overlay').removeClass('hidden'); 3642 $('.bopis-local-delivery-store-search-container').removeClass('show'); 3643 } 3644 }, 3645 }, options); 3646 3647 resultContainerTemplate = _.template($('#template-bopis-result-container').html(), TemplateConstants.Lodash.Settings); 3648 resultItemTemplate = _.template($('#template-bopis-result-item').html(), TemplateConstants.Lodash.Settings); 3649 localDeliveryDecorator = _.template($('#template-bopis-localdelivery-decorator').html(), TemplateConstants.Lodash.Settings); 3650 3651 $container = $containerParameter; 3652 $storeSearchButton = $container.find('.btn.store-search'); 3653 $storeSearchButtonContainer = $container.find('.btn-store-search-container'); 3654 $bopisButton = $container.find('.btn.bopis'); 3655 3656 $addToCartOptions = $container.find('.bopis-add-to-cart-options'); 3657 $addToCartOptions.attr('state', 'form'); 3658 initializeTooltips(selectedSize); 3659
3660 $(document).off('click.SearchByStore.Display').on('click.SearchByStore.Display', '.bopis-add-to-cart-options-container .search-store:not(.disabled)', function(event) { 3661 event.preventDefault(); 3662 event.stopImmediatePropagation(); 3663 3664 var sizeSelected = $('div.product-variations .size.size-options li.selected').length; 3665 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 3666 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 3667 var colorSelected = $('div.product-variations .color.color-options li.selected').length; 3668 var isSizeSelected = (sizeSelected || (lengthSelected && widthSelected)) && colorSelected; 3669 3670 if (options.StoreUIVersion != '2024Redesign') { 3671 if (!isSizeSelected && !colorSelected) { 3672 dialog.open({ 3673 html: 'Please select a size and color.', 3674 options: { 3675 dialogClass: 'dialog-alert', 3676 draggable: false 3677 } 3678 }); 3679 return false; 3680 } else if (!isSizeSelected) { 3681 dialog.open({ 3682 html: 'Please select a size', 3683 options: { 3684 dialogClass: 'dialog-alert', 3685 draggable: false 3686 } 3687 }); 3688 return false; 3689 } else if (!colorSelected) { 3690 dialog.open({ 3691 html: 'Please select a color', 3692 options: { 3693 dialogClass: 'dialog-alert', 3694 draggable: false 3695 } 3696 }); 3697 return false; 3698 } 3699 } 3700 3701 if ($container.find('input[name="AddToCartOption"]:checked').val() == 'delivery') { 3702 localDeliveryStoreSearch.initialize($('.bopis-local-delivery-store-search-container'), optionsLocalDelivery); 3703 } else { 3704 storeSearch.initialize($('.bopis-add-to-cart-store-search-container'), optionsStoreSearch); 3705 } 3706 }); 3707 3708 $(document).off('click.SearchByZipCode.Display').on('click.SearchByZipCode.Display', '.bopis-add-to-cart-options .search-zipcode:not(.disabled)', function (event) { 3709 event.preventDefault(); 3710 event.stopImmediatePropagation(); 3711 3712 localDeliveryStoreSearch.initialize($('.bopis-local-delivery-store-search-container'), optionsLocalDelivery); 3713 }); 3714 3715 $(document).off('Bopis.LocalDelivery.StoreSelect').on('Bopis.LocalDelivery.StoreSelect', function (event, store) { 3716 $.ajax({ 3717 method: 'GET', 3718 url: Urls.Bopis.GetLocalDeliveryFormData, 3719 dataType: 'json', 3720 success: function(localDeliveryFormData) { 3721 LocalDeliveryDialog.initialize(optionsLocalDelivery, store, localDeliveryFormData); 3722 }, 3723 error: function() { 3724 LocalDeliveryDialog.initialize(optionsLocalDelivery, store); 3725 } 3726 }); 3727 }); 3728 3729 $(document).off('Bopis.LocalDelivery.Display').on('Bopis.LocalDelivery.Display', function (event, data) { 3730 var $storeData = $container.find('.selected-store[store-data]'); 3731 if ($storeData.length > 0) { 3732 if (data) { 3733 optionsLocalDelivery = $.extend(optionsLocalDelivery, data); 3734 } 3735 3736 $.ajax({ 3737 method: 'GET', 3738 url: Urls.Bopis.GetLocalDeliveryFormData, 3739 dataType: 'json', 3740 success: function(localDeliveryFormData) { 3741 LocalDeliveryDialog.initialize(optionsLocalDelivery, JSON.parse($storeData.attr('store-data')), localDeliveryFormData); 3742 }, 3743 error: function() { 3744 LocalDeliveryDialog.initialize(optionsLocalDelivery, JSON.parse($storeData.attr('store-data'))); 3745 } 3746 }); 3747 } 3748 }); 3749 3750 $(document).off('Bopis.StoreSearch.Select').on('Bopis.StoreSearch.Select', function (event, storeId) { 3751 dataBuffer['SelectedLocation'] = storeId; 3752 redraw(true); 3753 }); 3754 3755 $(document).off('click.Store.Select').on('click.Store.Select', '.bopis-add-to-cart-options-container .select-store', function(event) { 3756 dataBuffer['SelectedLocation'] = $(this).closest('[store-id]').attr('store-id'); 3757 redraw(true); 3758 }); 3759 3760 $(document).off('ProductDetailPage.Variant.AddToCartOptions').on('ProductDetailPage.Variant.AddToCartOptions', function() { 3761 redraw(); 3762 }); 3763 3764 $(document).off('click.AddToCartOptionsSelect').on('click.AddToCartOptionsSelect', '.bopis-add-to-cart-options-container li[option] input', function(event) { 3765 $(document).trigger('ProductDetailPage.AddToCartOptionsSelect', { ProductId: $('#pid').val(), StoreId: $('.bopis-add-to-cart-options-container .selected-store').attr('store-id') }); 3766 }); 3767 3768 dataBuffer['SelectedLocation'] = options.SelectedLocations; 3769} 3770 3771function redraw(saveSelectedLocation) { 3772 var selectedColor; 3773 var $selectedColorInSwatch = $('div.product-variations .color.color-options li.selected');; 3774 if ($selectedColorInSwatch.length > 0) { 3775 selectedColor = $selectedColorInSwatch.find('[data-color-name]').attr('data-color-id'); 3776 } else { 3777 selectedColor = util.getPreferenceValueFromWindowLocation('color'); 3778 } 3779 3780 var selectedSize; 3781 var $selectedSizeInDropdown = $('div.product-variations .size.size-options li.selected'); 3782 var $selectedLength = $('div.product-variations .length.length-options li.selected'); 3783 var $selectedWidth = $('div.product-variations .width.width-options li.selected'); 3784 if ($selectedLength.length && $selectedWidth.length) { 3785 selectedSize = $selectedLength.find('[data-length-name]').attr('data-length-name') + ' ' + $selectedWidth.find('[data-width-name]').attr('data-width-name'); 3786 } else if ($selectedSizeInDropdown.length > 0) { 3787 selectedSize = $selectedSizeInDropdown.find('[data-size-name]').attr('data-size-name'); 3788 } else { 3789 selectedSize = util.getPreferenceValueFromWindowLocation('size'); 3790 } 3791 3792 var payload = { 3793 Channel: options.Channel, 3794 ProductId: options.ProductId, 3795 SelectedLocation: dataBuffer['SelectedLocation'], 3796 SaveSelectedLocation: !!saveSelectedLocation, 3797 SelectedOption: $container.find('input[name="AddToCartOption"]:checked').val() 3798 } 3799 payload['dwvar_' + options.ProductId + '_color'] = selectedColor; 3800 payload['dwvar_' + options.ProductId + '_size'] = selectedSize; 3801 3802 $.ajax({ 3803 method: 'GET', 3804 url: Urls.Bopis.AddToCartOptions, 3805 contentType: 'application/json', 3806 data: payload, 3807 dataType: 'html', 3808 success: function(data) { 3809 $container.html($(data).children()); 3810 $addToCartOptions = $container.find('.bopis-add-to-cart-options'); 3811 initializeTooltips(selectedSize); 3812 }, 3813 error: function() { 3814 3815 } 3816 }); 3817} 3818 3819function initializeTooltips(selectedSize) { 3820 if (!selectedSize) { 3821 $addToCartOptions.find('label.disabled > span').each(function(index, element) { 3822 var $this = $(this); 3823 3824 tooltip.init({ 3825 items: $this, 3826 tooltipClass: 'tooltip-select-size', 3827 content: 'Select a size to<br />see availability' 3828 }, $this); 3829 }); 3830 } 3831
3832 var localDeliveryRadius; 3833 var $storeData = $container.find('.selected-store[store-data]'); 3834 if ($storeData && $storeData.length > 0) { 3835 var storeData = JSON.parse($storeData.first().attr('store-data')); 3836 if (storeData && storeData.location && storeData.location.local_delivery_vendor && storeData.location.local_delivery_radius) { 3837 localDeliveryRadius = storeData.location.local_delivery_radius; 3838 } 3839 } 3840 3841 $('.add-to-cart-options-tooltip').find('.delivery-radius').html(localDeliveryRadius); 3842 tooltip.init({ 3843 items: '.add-to-cart-options-tooltip', 3844 tooltipClass: 'add-to-cart-options-tooltip' 3845 }, $('.add-to-cart-options-tooltip')); 3846} 3847},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../components/LoadingIndicator":25,"../../dialog":36,"../../tooltip":101,"../../util":102,"./AddToCartOptionsStoreSearch":8,"./LocalDeliveryDialog":9,"lodash":133}],8:[function(require,module,exports){ 3848'use strict'; 3849 3850var _ = require('lodash'); 3851var loadingIndicator = require('../../components/LoadingIndicator'); 3852var GeolocationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/Geolocation/GeolocationHelper'); 3853var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 3854var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 3855var tooltip = require('../../tooltip'); 3856var ValidationSettings = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 3857var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 3858var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 3859var ZipCodeToStateMap = require('../../../../../bc_sheplersbootbarn_core/cartridge/data/ZipCodeToStateMap.json'); 3860 3861module.exports = AddToCartOptionsStoreSearch; 3862 3863function AddToCartOptionsStoreSearch() { 3864 this.options; 3865 this.validator; 3866 this.loaded; 3867 this.dataBuffer; 3868 3869 this.resultContainerTemplate; 3870 this.resultItemTemplate; 3871 this.localDeliveryDecorator; 3872 3873 this.$container; 3874 this.$form; 3875 this.$result; 3876 this.$formInputPostalCode; 3877 this.$formInputRadius; 3878 this.$storeSearchButton; 3879 this.$storeSearchButtonContainer; 3880 this.$bopisButton; 3881 this.$errorMessage; 3882 this.$inputTooltip; 3883 3884 this.initialize = function($containerParameter, optionsParameter) { 3885 var self = this; 3886 if (!this.dataBuffer) { 3887 this.dataBuffer = {}; 3888 } 3889 if (!this.loaded) { 3890 this.loaded = {}; 3891 } 3892 this.options = $.extend({ 3893 successCallback: null, 3894 errorCallback: null 3895 }, optionsParameter); 3896 3897 this.resultContainerTemplate = _.template($('#template-bopis-result-container-addtocartoptions').html(), TemplateConstants.Lodash.Settings); 3898 this.resultItemTemplate = _.template($('#template-bopis-result-item-addtocartoptions').html(), TemplateConstants.Lodash.Settings); 3899 this.localDeliveryDecorator = _.template($('#template-bopis-localdelivery-decorator').html(), TemplateConstants.Lodash.Settings); 3900 3901 this.$container = $containerParameter; 3902 this.$form = this.$container.find('form'); 3903 this.$result = this.$container.find('.result'); 3904 this.$formInputPostalCode = this.$form.find('input[name$="_postalCode"]'); 3905 this.$formInputRadius = this.$form.find('[name$="_radius"]'); 3906 this.$storeSearchButton = this.$container.find('.btn.store-search'); 3907 this.$storeSearchButtonContainer = this.$container.find('.btn-store-search-container'); 3908 this.$bopisButton = this.$container.find('.btn.bopis'); 3909 this.$errorMessage = this.$form.find('span.error'); 3910 this.$inputTooltip = this.$formInputPostalCode.parent(); 3911 this.$container.find('.btn.store-select').addClass('disabled'); 3912 $('html').addClass('scroll-lock'); 3913 3914 if (this.options && this.options.LocalDelivery && this.options.LocalDelivery.Radius) { 3915 this.$container.find('.delivery-radius').html(this.options.LocalDelivery.Radius); 3916 } 3917 this.$container.attr('state', 'form'); 3918 this.validator = this.$form.validate(ValidationSettings.Global); 3919 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_POSTAL_CODE); 3920 this.$formInputPostalCode.rules('add', ValidationRules.ZipCode); 3921 3922 this.$container.addClass('show'); 3923 if (this.$container.attr('state') === 'form' && this.validator.checkForm() && !this.$storeSearchButton.hasClass('ready')) { 3924 this.$storeSearchButton.addClass('ready'); 3925 } 3926 3927 this.$form.off('click.apply').on('click.apply', '.btn.store-search:not([loading])', function (event) { 3928 event.preventDefault(); 3929 self.$storeSearchButtonContainer.loading(); 3930 self.search(); 3931 }); 3932 3933 this.$container.off('click.apply').on('click.apply', '.btn.bopis:not([loading])', function (event) { 3934 event.preventDefault(); 3935 3936 var selectedLocation = self.dataBuffer['StoresDisplayed'][$('input[name="Bopis_StoreSearch_StoreId"]:checked').val()]; 3937 if (selectedLocation) { 3938 $(document).trigger('ProductDetailPage.Bopis.AddToCart', { bopis: true, shippingOption: 'pickup', channel: self.options.Channel }); 3939 } else { 3940 $(document).trigger('ProductDetailPage.Bopis.AddToCart', { channel: self.options.Channel }); 3941 } 3942 }); 3943 3944 this.$formInputPostalCode.off('keydown.BopisStoreSearch.ValidationCheck').on('keydown.BopisStoreSearch.ValidationCheck', function (event) { 3945 if (self.$formInputPostalCode.val().length == 5 && parseInt(event.key, 10) == event.key && !window.getSelection().toString()) { 3946 event.preventDefault(); 3947 } 3948 }); 3949 3950 this.$formInputPostalCode.off('change.BopisStoreSearch.ValidationCheck').on('change.BopisStoreSearch.ValidationCheck', function (event) { 3951 if (self.$formInputPostalCode.val().length > 5) { 3952 self.$formInputPostalCode.val(self.$formInputPostalCode.val().substr(0, 5)); 3953 } 3954 }); 3955 3956 this.$formInputPostalCode.off('keyup.BopisStoreSearch.ValidationCheck, change.BopisStoreSearch.ValidationCheck').on('keyup.BopisStoreSearch.ValidationCheck, change.BopisStoreSearch.ValidationCheck', function (event) { 3957 event.stopImmediatePropagation(); 3958 3959 if (self.$container.attr('state') === 'form') { 3960 if (self.validator.checkForm() && !self.$storeSearchButton.hasClass('ready')) { 3961 self.$storeSearchButton.addClass('ready'); 3962 } else if (!self.validator.checkForm() && self.$storeSearchButton.hasClass('ready')) { 3963 self.$storeSearchButton.removeClass('ready'); 3964 } 3965 } 3966 3967 if (self.$container.attr('state') === 'result') { 3968 self.$container.attr('state', 'form'); 3969 self.$formInputPostalCode.val(''); 3970 } 3971 }); 3972 3973 $(document).off('mousedown.BopisStoreSearch.ValidationClear').on('mousedown.BopisStoreSearch.ValidationClear', function (event) { 3974 if (self.validator && $(event.target).closest(self.$container).length == 0) { 3975 self.validator.resetForm(); 3976 self.$errorMessage.html('').hide(); 3977 } 3978 }); 3979 3980 $(document).off('Bopis.StoreSearch.Reset').on('Bopis.StoreSearch.Reset', function (event) { 3981 self.reset(); 3982 }); 3983 3984 this.$container.off('click.BopisStoreSearch.Selection').on('click.BopisStoreSearch.Selection', 'input[name="Bopis_StoreSearch_StoreId"]', function (event) { 3985 var bopisStore = $('input[name="Bopis_StoreSearch_StoreId"]:checked').val(); 3986 3987 if (!self.$bopisButton.hasClass('ready')) { 3988 self.$bopisButton.addClass('ready'); 3989 } 3990 3991 $('.product-add-to-cart button').attr('disabled', 'disabled').addClass('hidden'); 3992 3993 if (bopisStore) { 3994 self.$bopisButton.attr('state', 'pickup'); 3995 } else { 3996 self.$bopisButton.attr('state', 'ship'); 3997 } 3998 }); 3999 4000 this.$container.off('click.BopisStoreSearch.NoResultsShip').on('click.BopisStoreSearch.NoResultsShip', '.btn.no-results-ship', function (event) { 4001 $('html').removeClass('scroll-lock'); 4002 self.close(); 4003 $(document).trigger('ProductDetailPage.Bopis.AddToCart', { channel: self.options.Channel }); 4004 }); 4005 4006 this.$container.off('click.BopisAddToCartOptionsStoreSearch.Select').on('click.BopisAddToCartOptionsStoreSearch.Select', 'li[store]', function (event) { 4007 event.preventDefault(); 4008 4009 var $this = $(this); 4010 $this.find('input').prop('checked', true); 4011 self.$container.find('.btn.store-select').removeClass('disabled'); 4012 }); 4013 4014 this.$container.off('click.BopisAddToCartOptionsStoreSearch.Confirm').on('click.BopisAddToCartOptionsStoreSearch.Confirm', '.btn.store-select:not(.disabled)', function (event) { 4015 var store = $(this).closest('input[store]').attr('store'); 4016 var store = self.$container.find('input[name="bopis-store"]:checked').val(); 4017 var eventName = 'Bopis.StoreSearch.Select'; 4018 4019 if (self.options.Events && self.options.Events.SelectStore) { 4020 eventName = self.options.Events.SelectStore; 4021 store = self.dataBuffer['StoresDisplayed'][store]; 4022 } 4023 $('html').removeClass('scroll-lock'); 4024 $(document).trigger(eventName, store); 4025 self.close(); 4026 }); 4027 4028 this.$container.off('click.BopisAddToCartOptionsStoreSearch.Close').on('click.BopisAddToCartOptionsStoreSearch.Close', '.close', function (event) { 4029 $('html').removeClass('scroll-lock'); 4030 self.close(); 4031 }); 4032 4033 this.$container.off('click.UseMyLocation').on('click.UseMyLocation', '.use-my-location', function (event) { 4034 event.preventDefault(); 4035 4036 GeolocationHelper.GetPosition().then(function(position) { 4037 self.search(true, position); 4038 }).catch(); 4039 }); 4040 4041 this.reset(); 4042 if (this.options.StoreUIVersion == '2024Redesign' && this.$formInputPostalCode.val()) { 4043 this.search(); 4044 } 4045 } 4046 4047 this.reset = function() { 4048 this.$container.attr('result-count', '0'); 4049 this.$result.html(''); 4050 } 4051 4052 this.close = function() { 4053 $('html').removeClass('scroll-lock'); 4054 if (this.options.Functions && this.options.Functions.Close) { 4055 this.options.Functions.Close(); 4056 } else { 4057 $('.bopis-add-to-cart-store-search-container').removeClass('show'); 4058 } 4059 } 4060 4061 this.search = function(isByGeolocation, position) { 4062 var self = this; 4063 var colorSelected = $('div.product-variations .color.color-options li.selected').length; 4064 var sizeSelected = $('div.product-variations .size.size-options li.selected'); 4065 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 4066 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 4067 var isSizeSelected = sizeSelected.length || (lengthSelected && widthSelected); 4068 4069 if (this.options.StoreUIVersion != '2024Redesign') { 4070 if (!isSizeSelected && !colorSelected) { 4071 this.$errorMessage.html('Please select a size and color.').show(); 4072 return false;
4073 } else if (!isSizeSelected) { 4074 this.$errorMessage.html('Please select a size.').show(); 4075 return false; 4076 } else if (!colorSelected) { 4077 this.$errorMessage.html('Please select a color.').show(); 4078 return false; 4079 } 4080 } 4081 this.$errorMessage.html('').hide(); 4082 this.$storeSearchButton.removeAttr('disabled'); 4083 4084 var geolocationPosition; 4085 if (isByGeolocation && position && position.coords) { 4086 geolocationPosition = { 4087 coords: { 4088 accuracy: position.coords.accuracy, 4089 latitude: position.coords.latitude, 4090 longitude: position.coords.longitude 4091 }, 4092 timestamp: position.timestamp 4093 } 4094 } 4095 4096 var isValid = isByGeolocation || this.validator.valid(); 4097 if (Urls && Urls.Bopis.GetStoreInventoryForProductForPostalCode && isValid) { 4098 this.$result.html(''); 4099 this.$result.loading(); 4100 4101 this.loaded['LocationData'] = false; 4102 this.loaded['InventoryData'] = false; 4103 this.dataBuffer['LocationData'] = null; 4104 this.dataBuffer['InventoryData'] = null; 4105 4106 var getLocationUrl; 4107 var getLocationData; 4108 if (isByGeolocation) { 4109 getLocationUrl = Urls.Bopis.GetLocationsForGeolocationPosition; 4110 getLocationData = { 4111 Channel: this.options.Channel, 4112 Source: this.options.Source, 4113 GeolocationPosition: geolocationPosition, 4114 Radius: parseFloat(this.$formInputRadius.val()) || 3000 4115 } 4116 } else { 4117 getLocationUrl = Urls.Bopis.GetLocationsForPostalCode; 4118 getLocationData = { 4119 Channel: this.options.Channel, 4120 Source: this.options.Source, 4121 PostalCode: this.$formInputPostalCode.val(), 4122 Radius: parseFloat(this.$formInputRadius.val()) || 3000 4123 }; 4124 } 4125 4126 $.ajax({ 4127 method: 'POST', 4128 url: getLocationUrl, 4129 contentType: 'application/json', 4130 data: JSON.stringify(getLocationData), 4131 dataType: 'json', 4132 success: function(data) { 4133 var locationData; 4134 if (data && data.ServiceSuccessfullyCalled && data.InquiryResult && data.InquiryResult.data && data.InquiryResult.data.length > 0) { 4135 locationData = data.InquiryResult.data; 4136 4137 if (locationData && locationData.length > 0) { 4138 locationData = locationData.sort(function(left, right) { 4139 return left.distance - right.distance; 4140 }); 4141 4142 self.dataBuffer['LocationData'] = locationData; 4143 } 4144 } 4145 4146 self.loaded['LocationData'] = true; 4147 self.render(); 4148 }, 4149 error: function() { 4150 if (self.options.errorCallback) { 4151 self.options.errorCallback(); 4152 } 4153 } 4154 }); 4155 4156 var productId = $('.product-add-to-cart input[name="pid"]').val(); 4157 var getStoreInventoryUrl; 4158 var getStoreInventoryData; 4159 if (isByGeolocation) { 4160 getStoreInventoryUrl = Urls.Bopis.GetStoreInventoryForProductForGeolocationPosition; 4161 getStoreInventoryData = { 4162 Channel: this.options.Channel, 4163 Source: this.options.Source, 4164 ProductId: productId, 4165 GeolocationPosition: geolocationPosition, 4166 StoreSearchRadius: parseFloat(this.$formInputRadius.val()) || 3000, 4167 } 4168 } else { 4169 getStoreInventoryUrl = Urls.Bopis.GetStoreInventoryForProductForPostalCode; 4170 getStoreInventoryData = { 4171 Channel: this.options.Channel, 4172 Source: this.options.Source, 4173 ProductId: productId, 4174 PostalCode: this.$formInputPostalCode.val(), 4175 StoreSearchRadius: parseFloat(this.$formInputRadius.val()) || 3000, 4176 SavePostalCode: true 4177 }; 4178 } 4179 4180 $.ajax({ 4181 method: 'POST', 4182 url: getStoreInventoryUrl, 4183 contentType: 'application/json', 4184 data: JSON.stringify(getStoreInventoryData), 4185 dataType: 'json', 4186 success: function(data) { 4187 if (data && data.ServiceSuccessfullyCalled && data.InquiryResult && data.InquiryResult.data && data.InquiryResult.data.length > 0 && data.InquiryResult.data[0].inventory_supplies) { 4188 var inquiryResult = data.InquiryResult.data[0].inventory_supplies; 4189 4190 if (inquiryResult && inquiryResult.length > 0) { 4191 self.dataBuffer['InventoryData'] = []; 4192 4193 for (var inventoryRecordElement in inquiryResult) { 4194 var inventoryRecord = inquiryResult[inventoryRecordElement]; 4195 self.dataBuffer['InventoryData'][inventoryRecord.location.code] = inventoryRecord; 4196 } 4197 } 4198 } 4199 4200 self.loaded['InventoryData'] = true; 4201 self.render(); 4202 }, 4203 error: function() { 4204 if (self.$result.attr('loading')) { 4205 self.$result.loading('destroy'); 4206 } 4207 4208 if (self.options.errorCallback) { 4209 self.options.errorCallback(); 4210 } 4211 } 4212 }); 4213 } 4214 } 4215 4216 this.render = function() { 4217 if (this.loaded['LocationData'] && this.loaded['InventoryData']) { 4218 if (this.$storeSearchButtonContainer.attr('loading')) { 4219 this.$storeSearchButtonContainer.loading('destroy'); 4220 } 4221 if (this.$result.attr('loading')) { 4222 this.$result.loading('destroy'); 4223 } 4224 4225 this.$container.attr('state', 'result'); 4226 if (this.dataBuffer['LocationData'] && this.dataBuffer['LocationData'].length > 0) { 4227 this.dataBuffer['StoresDisplayed'] = []; 4228 4229 var $addToCartOptions = $('.bopis-add-to-cart-options'); 4230 var quantitySourceType; 4231 var dropshipLeadDays; 4232 if ($addToCartOptions.length > 0) { 4233 quantitySourceType = $addToCartOptions.attr('quantity-source-type'); 4234 dropshipLeadDays = parseInt($addToCartOptions.attr('dropship-lead-days'), 10); 4235 } 4236 var quantitySourceTypeOffset = 0; 4237 if (quantitySourceType == 'WHS') { 4238 quantitySourceTypeOffset = -1; 4239 } 4240 4241 var storeListHtml = ''; 4242 var isStoreSelected = false;
4243 var status = ''; 4244 var statusDisplay = ''; 4245 var isLocalDeliverySupported = false; 4246 var localDeliveryHtml = ''; 4247 var storesDisplayedCount = 0; 4248 var selectedStoreAttribute; 4249 var quantityAvailable = false; 4250 for (var locationKey in this.dataBuffer['LocationData']) { 4251 var location = this.dataBuffer['LocationData'][locationKey]; 4252 4253 var inventoryRecord; 4254 if (this.dataBuffer['InventoryData'] && this.dataBuffer['InventoryData'][location.code]) { 4255 inventoryRecord = this.dataBuffer['InventoryData'][location.code]; 4256 } 4257 4258 status = 'unavailable'; 4259 statusDisplay = 'Unavailable'; 4260 isLocalDeliverySupported = false; 4261 localDeliveryHtml = ''; 4262 if (inventoryRecord && inventoryRecord.detail && inventoryRecord.detail.quantity > 0 && !this.dataBuffer['StoresDisplayed'][inventoryRecord.location.code] && (!this.options.LocalDeliveryOnly || (inventoryRecord.location.local_delivery_enabled && this.isLocationInLocalDeliveryRadius(inventoryRecord.location)))) { 4263 if (this.options && this.options.SelectedLocations == inventoryRecord.location.code) { 4264 isStoreSelected = true; 4265 selectedStoreAttribute ='checked'; 4266 } else { 4267 selectedStoreAttribute = ''; 4268 } 4269 4270 if (this.options.LocalDelivery.Enabled && this.isLocationInLocalDeliveryRadius(inventoryRecord.location) && inventoryRecord.location.local_delivery_enabled) { 4271 localDeliveryHtml = this.localDeliveryDecorator(); 4272 isLocalDeliverySupported = true; 4273 } 4274 4275 if (isLocalDeliverySupported && inventoryRecord.detail && inventoryRecord.detail.quantity > 0) { 4276 if (this.options.LocalDeliveryOnly) { 4277 statusDisplay = 'Same-Day Delivery<br/>Available'; 4278 status = 'available'; 4279 } else if (!this.options.LocalDeliveryOnly) { 4280 // statusDisplay = 'Pickup & Same-Day<br/>Delivery Available'; 4281 statusDisplay = 'Available Today'; 4282 status = 'available'; 4283 } 4284 } else if (!this.options.LocalDeliveryOnly && inventoryRecord.detail && inventoryRecord.detail.quantity > 0) { 4285 statusDisplay = 'Available Today'; 4286 status = 'available'; 4287 } 4288 4289 quantityAvailable = inventoryRecord.detail.quantity; 4290 } else if (!this.options.LocalDeliveryOnly && !this.options.StorePickupOnly && pageContext.site != SiteConstants.SiteIds.BootBarnRspUS) { 4291 statusDisplay = 'Arrives in ' + (this.options.ShippingMethods.ShipToStore.DayRangeStart + dropshipLeadDays + quantitySourceTypeOffset) + '-' + (this.options.ShippingMethods.ShipToStore.DayRangeEnd + dropshipLeadDays + quantitySourceTypeOffset) + '<br/>Business Days'; 4292 status = 'available'; 4293 } else { 4294 quantityAvailable = false 4295 } 4296 4297 var locationName; 4298 if (this.options && this.options.StoreUIVersion == '2024Redesign') { 4299 locationName = '<strong>' + location.StoreInfo.Name + ' - ' + location.StoreInfo.StoreId + '</strong>'; 4300 } else { 4301 locationName = '<strong>' + location.StoreInfo.Name + '</strong>'; 4302 } 4303 if (this.options && this.options.AgentStoreID == location.code) { 4304 locationName += '<br/>(Your Store)'; 4305 } 4306 4307 storeListHtml += this.resultItemTemplate({ 4308 StoreId: location.code, 4309 QuantityAvailable: quantityAvailable, 4310 Html: '<span class="store-name">' + locationName + '</span><br/>' + location.StoreInfo.Address1 + '<br/>' + location.StoreInfo.City + ', ' + location.StoreInfo.StateCodeParsed + ', ' + location.StoreInfo.PostalCode.substr(0, 5), 4311 Selected: selectedStoreAttribute, 4312 LocalDelivery: localDeliveryHtml, 4313 Status: status, 4314 CarriesFR: 'carriesFR' in location.StoreInfo.Custom && location.StoreInfo.Custom.carriesFR, 4315 StatusDisplay: statusDisplay 4316 }); 4317 4318 storesDisplayedCount += 1; 4319 this.dataBuffer['StoresDisplayed'][location.code] = inventoryRecord ? inventoryRecord : { location: location }; 4320 } 4321 4322 var resultHtml = this.resultContainerTemplate({ 4323 Html: storeListHtml 4324 }); 4325 4326 if (isStoreSelected) { 4327 this.$bopisButton.addClass('ready'); 4328 } 4329 4330 if (storesDisplayedCount > 0) { 4331 this.$result.html(resultHtml); 4332 this.$container.attr('result-count', storesDisplayedCount); 4333 this.$container.find('.result-container').show(); 4334 this.$container.find('.result-empty').hide(); 4335 } else { 4336 this.$container.attr('result-count', 0); 4337 this.$container.find('.result-container').hide(); 4338 this.$container.find('.result-empty').show(); 4339 } 4340 4341 tooltip.init({ 4342 items: '.tooltip' 4343 }, this.$result); 4344 4345 if (this.options.successCallback) { 4346 this.options.successCallback(inquiryResult); 4347 } 4348 } else { 4349 $('.product-add-to-cart button').removeAttr('disabled').removeClass('hidden'); 4350 this.reset(); 4351 this.$result.closest('.result-container').hide(); 4352 this.$container.find('.result-empty').show(); 4353 4354 if (this.options.errorCallback) { 4355 this.options.errorCallback(); 4356 } 4357 } 4358 } 4359 } 4360
4361 this.isLocationInLocalDeliveryRadius = function(location) { 4362 var localDeliveryRadius; 4363 if (this.options && this.options.LocalDelivery) { 4364 if (location.local_delivery_vendor && location.local_delivery_vendor == 'GoLocal') { 4365 localDeliveryRadius = this.options.LocalDelivery.RadiusForGoLocal; 4366 } else { 4367 localDeliveryRadius = this.options.LocalDelivery.RadiusForRoadie; 4368 } 4369 } 4370 4371 if (localDeliveryRadius && location && location.distance && localDeliveryRadius >= location.distance) { 4372 return true; 4373 } 4374 4375 return false; 4376 } 4377} 4378},{"../../../../../bc_sheplersbootbarn_core/cartridge/data/ZipCodeToStateMap.json":111,"../../../../../bc_sheplersbootbarn_core/cartridge/js/Geolocation/GeolocationHelper":115,"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../components/LoadingIndicator":25,"../../tooltip":101,"lodash":133}],9:[function(require,module,exports){ 4379'use strict'; 4380 4381var _ = require('lodash'); 4382var addToCartOptionsStoreSearch = require('./AddToCartOptionsStoreSearch'); 4383var dialog = require('../../dialog'); 4384var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 4385var loadingIndicator = require('../../components/LoadingIndicator'); 4386var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 4387var tooltip = require('../../tooltip'); 4388var ValidationSettings = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 4389var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 4390var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 4391var ZipCodeToStateMap = require('../../../../../bc_sheplersbootbarn_core/cartridge/data/ZipCodeToStateMap.json'); 4392 4393exports.initialize = initialize; 4394exports.remove = remove; 4395 4396var options; 4397var optionsLocalDelivery; 4398var validator; 4399var dataBuffer; 4400var localDeliveryStoreSearch; 4401var localDeliveryRadius; 4402 4403function initialize(optionsParameter, selectedLocation, localDeliveryFormData) { 4404 dataBuffer = {}; 4405 options = $.extend({ 4406 successCallback: null, 4407 errorCallback: null 4408 }, optionsParameter); 4409 4410 if (selectedLocation && selectedLocation.location && selectedLocation.location.local_delivery_vendor && selectedLocation.location.local_delivery_vendor == 'GoLocal') { 4411 localDeliveryRadius = options.LocalDelivery.RadiusForGoLocal; 4412 } else if (selectedLocation && selectedLocation.location && selectedLocation.location.local_delivery_vendor && selectedLocation.location.local_delivery_vendor == 'Roadie') { 4413 localDeliveryRadius = options.LocalDelivery.RadiusForRoadie; 4414 } 4415 4416 buildAddressHtmlForLocation(selectedLocation.location); 4417 $('#dialog-bopis-options').find('.delivery-radius').html(localDeliveryRadius); 4418 var $optionalMessage = $('#dialog-bopis-options header .optional-message'); 4419 4420 if (options.OptionalMessage) { 4421 if ($optionalMessage.length == 0) { 4422 $('#dialog-bopis-options header').append('<p class="optional-message">' + options.OptionalMessage + '</p>') 4423 } 4424 } else if ($optionalMessage.length > 0) { 4425 $optionalMessage.remove(); 4426 } 4427 4428 localDeliveryStoreSearch = new addToCartOptionsStoreSearch(); 4429 optionsLocalDelivery = Object.assign(options, { 4430 LocalDeliveryOnly: true, 4431 Events: { 4432 SelectStore: 'Bopis.StoreSearchSelectLocalDelivery' 4433 }, 4434 Functions: { 4435 Close: function() { 4436 $('.dialog-bopis-options').removeClass('hidden'); 4437 $('.ui-widget-overlay').removeClass('hidden'); 4438 $('.bopis-local-delivery-store-search-container').removeClass('show'); 4439 } 4440 } 4441 }); 4442 4443 GoogleTagManagerClient.PushDataLayerForEvent('roadieFormDisplay'); 4444 dialog.open({ 4445 html: $('#dialog-bopis-options').html(), 4446 options: { 4447 dialogClass: 'dialog-bopis-options', 4448 width: 320, 4449 draggable: false, 4450 resizable: false, 4451 open: function(event, ui) { 4452 var $this = $(this); 4453 var $addressForm = $this.find('form.bopis-delivery-address'); 4454 appendCSRFToken($addressForm); 4455 4456 if (localDeliveryFormData) { 4457 $addressForm.find('input[name="email"]').val(localDeliveryFormData.Email || ''); 4458 $addressForm.find('input[name="phone"]').val(localDeliveryFormData.Phone || ''); 4459 $addressForm.find('input[name="firstName"]').val(localDeliveryFormData.FirstName || ''); 4460 $addressForm.find('input[name="lastName"]').val(localDeliveryFormData.LastName || ''); 4461 $addressForm.find('input[name="address1"]').val(localDeliveryFormData.Address1 || ''); 4462 $addressForm.find('input[name="address2"]').val(localDeliveryFormData.Address2 || ''); 4463 $addressForm.find('input[name="address3"]').val(localDeliveryFormData.Address3 || ''); 4464 $addressForm.find('input[name="city"]').val(localDeliveryFormData.City || ''); 4465 $addressForm.find('select[name="stateCode"] option[value="' + localDeliveryFormData.State + '"]').prop('selected', true); 4466 $addressForm.find('input[name="postalCode"]').val(localDeliveryFormData.PostalCode || ''); 4467 $addressForm.find('textarea[name="deliveryNote"]').val(localDeliveryFormData.DeliveryNote || ''); 4468 } 4469 4470 var addressValidator = $addressForm.validate(ValidationSettings.Global); 4471 $.validator.addMethod('requiredExcludingPunctuation', ValidationHelper.ValidateRequiredExcludingPunctuation, Resources.INVALID_VALUE); 4472 $.validator.addMethod('postOfficeBox', ValidationHelper.ValidateAddressForPostOfficeBox, Resources.INVALID_ADDRESS_POBOX); 4473 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_POSTAL_CODE); 4474 $.validator.addMethod('stateCodeForCaliforniaStateLine', ValidationHelper.ValidateStateCodeForCaliforniaStateLine, Resources.INVALID_CALIFORNIA_STATE_LINE_LOCAL_DELIVERY); 4475 4476 $addressForm.find('input[name="address1"]').rules('add', ValidationRules.ValidateAddressForPostOfficeBox); 4477 $addressForm.find('input[name="address2"]').rules('add', ValidationRules.ValidateAddressForPostOfficeBox); 4478 $addressForm.find('input[name="address3"]').rules('add', ValidationRules.ValidateAddressForPostOfficeBox); 4479 $addressForm.find('select[name="stateCode"]').rules('add', ValidationRules.StateCodeForCaliforniaStateLine); 4480 $addressForm.find('input[name="postalCode"]').rules('add', ValidationRules.ZipCode); 4481 $addressForm.find('input.required, select.required').rules('add', ValidationRules.RequiredExcludingPunctuation); 4482 $addressForm.find('input[name="email"]').rules('add', ValidationRules.Email); 4483 $this.attr('local-delivery-vendor', $('#dialog-bopis-options').attr('local-delivery-vendor')); 4484 $this.attr('local-delivery-radius', isLocalDeliveryValid(selectedLocation)); 4485 $this.attr('store-state', selectedLocation.location.postal_address.province_or_state); 4486 4487 $this.off('click.SelectDeliveryOption').on('click.SelectDeliveryOption', '.delivery-option label', function (event) { 4488 var deliveryOption = $(this).find('input').val(); 4489 4490 if (deliveryOption == 'pickup') { 4491 $this.find('.address-form').hide(); 4492 } else if (deliveryOption == 'delivery') { 4493 $this.find('.address-form').show(); 4494 } 4495 }); 4496 4497 $this.off('click.Apply').on('click.Apply', '.btn.bopis-option:not([loading])', function (event) { 4498 event.preventDefault(); 4499 4500 $this.find('.ui-dialog-footer .error').remove(); 4501 4502 var selectedBopisOption; 4503 if (options && options.Mode == 'AddToCartOptions') { 4504 selectedBopisOption = 'delivery'; 4505 } else { 4506 selectedBopisOption = $this.find('input[name="bopis-option"]:checked').val(); 4507 } 4508 var eventData = {bopis: true, bopisStore: selectedLocation.location.code, shippingOption: selectedBopisOption, channel: options.Channel, quantityAvailable: selectedLocation.detail.quantity}; 4509 if (selectedBopisOption == 'delivery') { 4510 var deliveryAddressObject = {}; 4511 var $deliveryAddressForm = $this.find('.bopis-delivery-address'); 4512 var deliveryAddressArray = $deliveryAddressForm.serializeArray(); 4513 $(deliveryAddressArray).each(function(index, element) { 4514 if (element.value != 'disabled' && $deliveryAddressForm.find('[name="' + element.name + '"]').attr('type') != 'hidden') { 4515 deliveryAddressObject[element.name] = element.value; 4516 } 4517 }); 4518 eventData.deliveryAddress = JSON.stringify(deliveryAddressObject); 4519 $deliveryAddressForm.find('input[type="hidden"]').each(function () { 4520 var $this = $(this); 4521 eventData[$this.attr('name')] = $this.val(); 4522 }); 4523 } 4524 4525 if (selectedBopisOption != 'delivery' || $addressForm.valid()) { 4526 if (selectedBopisOption == 'delivery') { 4527 $.ajax({ 4528 method: 'POST', 4529 url: Urls.Bopis.ValidatePostalCodeForLocations, 4530 contentType: 'application/json', 4531 data: JSON.stringify({ 4532 PostalCode: $addressForm.find('input[name="postalCode"]').val(), 4533 Locations: [selectedLocation.location.code] 4534 }), 4535 dataType: 'json', 4536 success: function(data) { 4537 if (data) { 4538 GoogleTagManagerClient.PushDataLayerForEvent('roadieFormSubmit'); 4539 $(document).trigger('ProductDetailPage.Bopis.AddToCart', eventData); 4540 } else { 4541 var errorMessage = '<div class="error">The zip code you entered is different than the one you searched with, and the selected location is not in range. Please update your address and try again.</div>' 4542 4543 $this.find('.ui-dialog-footer').prepend(errorMessage); 4544 } 4545 } 4546 }); 4547 } else { 4548 $(document).trigger('ProductDetailPage.Bopis.AddToCart', eventData); 4549 } 4550 } 4551 }); 4552 4553 $this.off('click.ChangeZip').on('click.ChangeZip', '.btn.change-zip', function (event) { 4554 $(document).trigger('Bopis.StoreSearch.Reset'); 4555 dialog.close(); 4556 }); 4557 4558 $this.off('click.ChangeStore').on('click.ChangeStore', '.btn.change-store', function (event) { 4559 dialog.close(); 4560 }); 4561 4562 $this.off('click.SearchStore').on('click.SearchStore', '.search-store', function (event) { 4563 event.preventDefault(); 4564 event.stopImmediatePropagation(); 4565 4566 $('.dialog-bopis-options').addClass('hidden'); 4567 $('.ui-widget-overlay').addClass('hidden'); 4568 4569 localDeliveryStoreSearch.initialize($('.bopis-local-delivery-store-search-container'), optionsLocalDelivery); 4570 }); 4571 }, 4572 close: function(event, ui) { 4573 4574 } 4575 } 4576 }); 4577 4578 $(document).off('Bopis.StoreSearchSelectLocalDelivery').on('Bopis.StoreSearchSelectLocalDelivery', function (event, store) { 4579 buildAddressHtmlForLocation(store.location); 4580 $('.dialog-bopis-options').removeClass('hidden'); 4581 $('.ui-widget-overlay').removeClass('hidden'); 4582 $('.bopis-local-delivery-store-search-container').removeClass('show'); 4583 $('.dialog-bopis-options').find('.dialog-content').attr('local-delivery-radius', isLocalDeliveryValid(store)); 4584 $('.dialog-bopis-options').find('.dialog-content').attr('store-state', store.location.postal_address.province_or_state); 4585 }); 4586} 4587 4588function remove() { 4589 validator.destroy(); 4590 $('.product-add-to-cart button').removeAttr('disabled').removeClass('hidden'); 4591} 4592 4593function buildAddressHtmlForLocation(location) { 4594 var locationHtml; 4595 if (options && options.Mode == 'AddToCartOptions') { 4596 locationHtml = '<p class="selected-location-name">' + location.postal_address.name + '</p>' + 4597 '<p class="selected-location-address">' + location.postal_address.address_line1 + '<br/>' + 4598 location.postal_address.city + ', ' + location.postal_address.province_or_state + '</p>' + 4599 '<a class="search-store">Change Store</a>'; 4600 } else { 4601 locationHtml = location.postal_address.address_line1 + '<br/>' + 4602 location.postal_address.city + ', ' + location.postal_address.province_or_state; 4603 } 4604 4605 $('.ui-dialog.dialog-bopis-options').find('.selected-location-detail
4605s').html(locationHtml); 4606 $('#dialog-bopis-options').find('.selected-location-details').html(locationHtml); 4607} 4608 4609function isLocalDeliveryValid(record) { 4610 if (options.LocalDelivery && options.LocalDelivery.Enabled && isLocationInLocalDeliveryRadius(record.location) && record.location.local_delivery_enabled && record.detail && record.detail.quantity > 0) { 4611 return true; 4612 } 4613 4614 return false; 4615} 4616 4617function isLocationInLocalDeliveryRadius(location) { 4618 if (localDeliveryRadius && location.distance && localDeliveryRadius >= location.distance) { 4619 return true; 4620 } 4621 4622 return false; 4623} 4624 4625function appendCSRFToken($form) { 4626 $.ajax({ 4627 method: 'get', 4628 url: Urls.CSRFToken.Get, 4629 dataType: 'json', 4630 success: function(response) { 4631 $form.append('<input type="hidden" name="' + response.name + '" value="' + response.token + '"/>'); 4632 } 4633 }); 4634} 4635},{"../../../../../bc_sheplersbootbarn_core/cartridge/data/ZipCodeToStateMap.json":111,"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../components/LoadingIndicator":25,"../../dialog":36,"../../tooltip":101,"./AddToCartOptionsStoreSearch":8,"lodash":133}],10:[function(require,module,exports){ 4636'use strict'; 4637 4638var _ = require('lodash'); 4639var loadingIndicator = require('../../components/LoadingIndicator'); 4640var GeolocationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/Geolocation/GeolocationHelper'); 4641var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 4642var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 4643var ValidationSettings = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 4644var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 4645var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 4646 4647var siteName; 4648 4649module.exports = LocationSearch; 4650 4651function LocationSearch() { 4652 this.$container; 4653 this.$form; 4654 this.dataBuffer; 4655 this.options; 4656 this.validator; 4657 4658 this.resultContainerTemplate = _.template($('#template-bopis-result-container').html(), TemplateConstants.Lodash.Settings); 4659 this.resultItemTemplate = _.template($('#template-bopis-result-item').html(), TemplateConstants.Lodash.Settings); 4660 4661 this.$result; 4662 this.$formInputPostalCode; 4663 this.$formInputRadius; 4664 this.$storeSearchButton; 4665 this.$storeSelectButton; 4666 this.$bopisButton; 4667 this.$errorMessage; 4668 4669 this.initialize = function ($container, options) { 4670 if (pageContext) { 4671 siteName = pageContext.siteId ? pageContext.siteId : pageContext.site ? pageContext.site : null; 4672 } 4673 4674 var self = this; 4675 this.$container = $container; 4676 this.$form = $container.find('form'); 4677 this.options = $.extend({ 4678 successCallback: null, 4679 errorCallback: null 4680 }, options); 4681 this.dataBuffer = { 4682 limit: this.options && this.options.Bopis && this.options.Bopis.StoreSearchLimit ? this.options.Bopis.StoreSearchLimit : 5 4683 }; 4684 this.$result = this.$container.find('.result'); 4685 this.$formInputPostalCode = this.$form.find('input[name$="_postalCode"]'); 4686 this.$formInputRadius = this.$form.find('[name$="_radius"]'); 4687 this.$storeSearchButton = this.$container.find('.btn.store-search'); 4688 this.$storeSelectButton = this.$container.find('.btn.store-select'); 4689 this.$bopisButton = this.$container.find('.btn.bopis'); 4690 this.$errorMessage = this.$form.find('span.error'); 4691 $('html').addClass('scroll-lock'); 4692 4693 if (this.options.DefaultZipCode) { 4694 this.$formInputPostalCode.val(this.options.DefaultZipCode); 4695 } 4696 4697 this.$container.attr('state', 'form'); 4698 this.validator = this.$form.validate(ValidationSettings.Global); 4699 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_POSTAL_CODE); 4700 this.$formInputPostalCode.rules('add', ValidationRules.ZipCode); 4701 4702 if (this.validator.checkForm() && this.$container.attr('state') === 'form' && !this.$storeSearchButton.hasClass('ready')) { 4703 this.$storeSearchButton.addClass('ready').removeAttr('disabled'); 4704 } 4705 this.$container.show(); 4706 4707 this.$form.off('click.Apply').on('click.Apply', '.btn.store-search:not([loading])', '.btn.store-search:not([loading])', function (event) { 4708 event.preventDefault(); 4709 $('.bopis-store-search').attr('state', 'form'); 4710 self.$container.trigger('LocationSearch.FormSubmit'); 4711 if ($('.stores-near-location .location-identifier').length) { 4712 $('.stores-near-location .location-identifier').text(' ' + $('#Bopis_StoreSearch_postalCode_ls').val()); 4713 } 4714 }); 4715 4716 this.$container.off('click.DialogClose').on('click.DialogClose', '.close', function (event) { 4717 event.preventDefault(); 4718 $('html').removeClass('scroll-lock'); 4719 $('.bopis-store-search').attr('state', 'form'); 4720 $('.location-search-dialog').hide(); 4721 }); 4722 4723 this.$container.off('LocationSearch.FormSubmit').on('LocationSearch.FormSubmit', function (event) { 4724 event.preventDefault(); 4725 4726 self.$errorMessage.html('').hide(); 4727 if (Urls && Urls.Bopis.GetLocationsForPostalCode && self.validator.valid() && self.$formInputPostalCode.val()) { 4728 self.dataBuffer.loadMore = 'postalCode'; 4729 self.dataBuffer.offset = 0; 4730 self.$storeSearchButton.loading(); 4731 self.$result.html(''); 4732 self.$result.loading(); 4733 self.getStoreListForPostalCode(self.$formInputPostalCode.val()); 4734 } 4735 }); 4736 4737 this.$container.off('click.SelectStore').on('click.SelectStore', '.btn.select-store:not([loading])', function (event) { 4738 $('html').removeClass('scroll-lock'); 4739 $(this).loading({ 4740 IsLabelShown: false, 4741 CssClass: 'fullscreen',
4742 BackgroundColor: 'transparent' 4743 }); 4744 }); 4745 4746 this.$container.off('click.SelectStore').on('click.SelectStore', '.btn.set-my-store:not([loading])', function (event) { 4747 var $this = $(this); 4748 var $storeInput = $this.closest('li').find('input'); 4749 var storeId; 4750 $('html').removeClass('scroll-lock'); 4751 if ($storeInput && $storeInput.length > 0) { 4752 storeId = $storeInput.val(); 4753 } 4754 if (storeId) { 4755 self.updateStoreDetails(storeId); 4756 } 4757 }); 4758 4759 this.$formInputPostalCode.off('keypress.LocationSearch.FormSubmit').on('keypress.LocationSearch.FormSubmit', function (event) { 4760 if (event.key == 'Enter') { 4761 self.$container.trigger('LocationSearch.FormSubmit'); 4762 return false; 4763 } 4764 }); 4765 4766 this.$formInputPostalCode.off('keydown.LocationSearch.ValidationCheck').on('keydown.LocationSearch.ValidationCheck', function (event) { 4767 if (self.$formInputPostalCode.val().length == 5 && parseInt(event.key, 10) == event.key && !window.getSelection().toString()) { 4768 event.preventDefault(); 4769 } 4770 4771 $(document).find('.bopis-store-search').attr('state', 'form'); 4772 }); 4773 4774 4775 this.$formInputPostalCode.off('change.LocationSearch.ValidationCheck').on('change.LocationSearch.ValidationCheck', function (event) { 4776 if (self.$formInputPostalCode.val().length > 5) { 4777 self.$formInputPostalCode.val(self.$formInputPostalCode.val().substr(0, 5)); 4778 } 4779 4780 $(document).find('.bopis-store-search').attr('state', 'form'); 4781 }); 4782 4783 this.$formInputPostalCode.off('keyup.LocationSearch.ValidationCheck, change.LocationSearch.ValidationCheck').on('keyup.LocationSearch.ValidationCheck, change.LocationSearch.ValidationCheck', function (event) { 4784 event.stopImmediatePropagation(); 4785 4786 if ($container.attr('state') === 'form') { 4787 if (self.validator.checkForm() && !self.$storeSearchButton.hasClass('ready')) { 4788 self.$storeSearchButton.addClass('ready').removeAttr('disabled'); 4789 } else if (!self.validator.checkForm() && self.$storeSearchButton.hasClass('ready')) { 4790 self.$storeSearchButton.removeClass('ready').attr('disabled', 'disabled'); 4791 } 4792 } 4793 }); 4794 4795 $(document).off('mousedown.LocationSearch.ValidationClear').on('mousedown.LocationSearch.ValidationClear', function (event) { 4796 if (self.validator && $(event.target).closest(self.$container).length == 0) { 4797 self.$errorMessage.html('').hide(); 4798 } 4799 }); 4800 4801 this.$container.off('click.LocationSearch.Reset').on('click.LocationSearch.Reset', '.reset', function (event) { 4802 self.$formInputPostalCode.val(''); 4803 self.$container.attr('state', 'form'); 4804 self.$storeSearchButton.removeClass('ready').attr('disabled', 'disabled'); 4805 $('.product-add-to-cart button').removeAttr('disabled'); 4806 self.$bopisButton.removeClass('ready'); 4807 }); 4808 4809 this.$container.off('click.LocationSearch.Selection').on('click.LocationSearch.Selection', 'input[name="Bopis_StoreSearch_StoreId"]', function (event) { 4810 var bopisStore = $('input[name="Bopis_StoreSearch_StoreId"]:checked').val(); 4811 4812 if (!self.$bopisButton.hasClass('ready')) { 4813 self.$bopisButton.addClass('ready'); 4814 } 4815 4816 if (self.$storeSelectButton.length > 0) { 4817 self.$storeSelectButton.attr('href', Urls.storeLandingPage + '?Store=' + bopisStore).addClass('ready');; 4818 } 4819 4820 $('.product-add-to-cart button').attr('disabled', 'disabled'); 4821 4822 if (bopisStore) { 4823 self.$bopisButton.attr('state', 'pickup'); 4824 } else { 4825 self.$bopisButton.attr('state', 'ship'); 4826 } 4827 }); 4828 4829 this.$container.off('click.UseMyLocation').on('click.UseMyLocation', '.use-my-location', function (event) { 4830 event.preventDefault(); 4831 self.geolocationSearch(); 4832 }); 4833 4834 $(document).off('LocationSearch.GeolocationSearch').on('LocationSearch.GeolocationSearch', function (event) { 4835 self.geolocationSearch(); 4836 }); 4837 4838 this.$container.off('click.LoadMore').on('click.LoadMore', '.load-more', function (event) { 4839 event.preventDefault(); 4840 4841 $(this).loading({ IsLabelShown: false }); 4842 4843 if (siteName == SiteConstants.SiteIds.BootBarnUS && SitePreferences.MOBILE_NAV_REDESIGN == 'redesign' && window.innerWidth <= 1024) { 4844 if (!self.dataBuffer.loadMore) { 4845 self.dataBuffer.loadMore = 'postalCode'; 4846 } 4847 if (!self.dataBuffer.offset) { 4848 self.dataBuffer.offset = 0; 4849 } 4850 } 4851 4852 self.dataBuffer.offset += self.dataBuffer.limit; 4853 if (self.dataBuffer.loadMore == 'geolocationPosition') { 4854 self.getStoreListForGeolocationPosition(self.dataBuffer.geolocationPosition, true); 4855 } else if (self.dataBuffer.loadMore == 'postalCode') { 4856 self.getStoreListForPostalCode(self.$formInputPostalCode.val(), true); 4857 } 4858 }); 4859 } 4860 4861 this.geolocationSearch = function() { 4862 var self = this; 4863 self.dataBuffer.loadMore = 'geolocationPosition'; 4864 self.dataBuffer.offset = 0; 4865 this.$result.html(''); 4866 this.$result.loading(); 4867 GeolocationHelper.GetPosition().then(function(position) { 4868 self.dataBuffer.geolocationPosition = position; 4869 self.getStoreListForGeolocationPosition(self.dataBuffer.geolocationPosition); 4870 }).catch(function() { 4871 if (self.$result.attr('loading')) { 4872 self.$result.loading('destroy'); 4873 } 4874 }); 4875 } 4876 4877 this.remove = function() { 4878 this.validator.destroy(); 4879 $('.product-add-to-cart button').removeAttr('disabled'); 4880 } 4881
4882 this.getStoreListForGeolocationPosition = function(position, isLoadMore) { 4883 var self = this; 4884 var geolocationPosition; 4885 if (position && position.coords) { 4886 geolocationPosition = { 4887 coords: { 4888 accuracy: position.coords.accuracy, 4889 latitude: position.coords.latitude, 4890 longitude: position.coords.longitude 4891 }, 4892 timestamp: position.timestamp 4893 }; 4894 } 4895 $.ajax({ 4896 method: 'POST', 4897 url: Urls.Bopis.GetLocationsForGeolocationPosition, 4898 contentType: 'application/json', 4899 data: JSON.stringify({ 4900 Channel: this.options.Channel, 4901 Source: this.options.Source, 4902 GeolocationPosition: geolocationPosition, 4903 Radius: parseFloat(this.$formInputRadius.val()) || 3000, 4904 Limit: this.dataBuffer.limit, 4905 Offset: this.dataBuffer.offset 4906 }), 4907 dataType: 'json', 4908 success: function(data) { 4909 self.renderStoreList(data, isLoadMore); 4910 }, 4911 error: function() { 4912 4913 } 4914 }); 4915 } 4916 4917 this.getStoreListForPostalCode = function(postalCode, isLoadMore) { 4918 var self = this; 4919 $.ajax({ 4920 method: 'POST', 4921 url: Urls.Bopis.GetStoresByCityStatePostalSearchKeyAjax, 4922 contentType: 'application/json', 4923 data: JSON.stringify({ 4924 Channel: self.options.Channel, 4925 Source: self.options.Source, 4926 SearchKey: postalCode, 4927 Radius: self.$formInputRadius.val() || 3000, 4928 Limit: self.dataBuffer.limit, 4929 Offset: self.dataBuffer.offset 4930 }), 4931 dataType: 'json', 4932 success: function(data) { 4933 self.renderStoreList(data, isLoadMore); 4934 }, 4935 error: function() { 4936 if (self.options.errorCallback) { 4937 self.options.errorCallback(); 4938 } 4939 } 4940 }); 4941 } 4942 4943 this.renderStoreList = function(data, isLoadMore) { 4944 var locationData; 4945 if (data && data.ServiceSuccessfullyCalled && data.InquiryResult && data.InquiryResult.data && data.InquiryResult.data.length > 0) { 4946 locationData = data.InquiryResult.data; 4947 } 4948 4949 this.$container.attr('state', 'result'); 4950 if (locationData && locationData.length > 0) { 4951 var locationsDisplayed = 0; 4952 locationData = locationData.sort(function(left, right) { 4953 return left.distance - right.distance; 4954 }); 4955 4956 this.dataBuffer['StoresDisplayed'] = []; 4957 this.$container.attr('result-count', locationData.length); 4958 4959 var storeListHtml = ''; 4960 for (var locationElement in locationData) { 4961 var location = locationData[locationElement]; 4962 4963 if (location && !this.dataBuffer['StoresDisplayed'][location.code]) { 4964 var storePhone = ''; 4965 var storeOpenUntil = ''; 4966 if (location.StoreInfo) { 4967 if (location.StoreInfo.Phone) { 4968 storePhone = location.StoreInfo.Phone; 4969 } 4970 if (location.StoreInfo.OpenUntil) { 4971 storeOpenUntil = location.StoreInfo.OpenUntil; 4972 } 4973 } 4974 4975 var locationName; 4976 if (this.options && this.options.StoreUIVersion == '2024Redesign') { 4977 locationName = '<strong>' + location.StoreInfo.Name + ' - ' + location.StoreInfo.StoreId + '</strong>'; 4978 } else { 4979 locationName = '<strong>' + location.StoreInfo.Name + '</strong>'; 4980 } 4981 if (this.options && this.options.AgentStoreID == location.code) { 4982 locationName += '<br/>(Your Store)'; 4983 } 4984 var html = locationName + '<br/>' + 4985 location.StoreInfo.Address1 + '<br />' + 4986 location.StoreInfo.City + ', ' + location.StoreInfo.StateCodeParsed + ' ' + location.StoreInfo.PostalCode.substr(0, 5) + '<br />' + 4987 storePhone; 4988 var address = location.StoreInfo.Name + ' - ' + location.StoreInfo.Address1 + ' - ' + location.StoreInfo.City + ', ' + location.StoreInfo.StateCodeParsed + ' ' + location.StoreInfo.PostalCode.substr(0, 5); 4989 if (pageContext.siteId == SiteConstants.BootBarnRspUS && storeOpenUntil) { 4990 html += '<br />' + storeOpenUntil; 4991 } 4992 4993 storeListHtml += this.resultItemTemplate({ 4994 StoreId: location.code, 4995 Distance: location.StoreInfo.Distance.toFixed(1) + ' mi', 4996 Selected: '', 4997 LandingCategory: this.options.LandingCategory, 4998 StatusDisplay: storeOpenUntil, 4999 Address: address, 5000 CarriesFR: 'carriesFR' in location.StoreInfo.Custom && location.StoreInfo.Custom.carriesFR, 5001 Html: html 5002 }); 5003 } 5004 5005 locationsDisplayed++; 5006 if (locationsDisplayed >= this.dataBuffer.limit) { 5007 break; 5008 } 5009 this.dataBuffer['StoresDisplayed'][location.code] = true; 5010 } 5011 5012 var resultHtml = this.resultContainerTemplate({ 5013 Html: storeListHtml 5014 }); 5015 if (pageContext.siteId == SiteConstants.BootBarnRspUS && data.InquiryResult.meta.page < data.InquiryResult.meta.pages) { 5016 resultHtml += '<a href="#" class="load-more">Load More</a>'; 5017 } 5018 if (this.$storeSearchButton.attr('loading')) { 5019 this.$storeSearchButton.loading('destroy'); 5020 } 5021 if (this.$result.attr('loading')) { 5022 this.$result.loading('destroy'); 5023 } 5024 if (isLoadMore) { 5025 this.$result.find('.load-more').remove(); 5026 this.$result.append(resultHtml); 5027 } else { 5028 this.$result.html(resultHtml); 5029 } 5030 } else if (!isLoadMore) { 5031 this.$container.attr('result-count', '0'); 5032 this.$result.html(''); 5033 } 5034 } 5035 5036 this.updateStoreDetails = function(storeId) { 5037 if (storeId) { 5038 $.ajax({ 5039 method: 'POST', 5040 url: Urls.Stores.SetMyStore, 5041 contentType: 'application/json', 5042 data: JSON.stringify({ 5043 StoreId: storeId 5044 }), 5045 dataType: 'html', 5046 success: function(data) { 5047 $('.my-store-panel').replaceWith(data); 5048 $('.my-store-modal').hide(); 5049 $('.location-search-dialog').hide(); 5050 5051 $.ajax({ 5052 method: 'GET', 5053 url: Urls.Stores.GetMyStorePanel, 5054 dataType: 'html', 5055 success: function(data) { 5056 $('.my-store-panel').replaceWith(data); 5057 $(document).trigger('Mobile.Redesign.ToggleEllipsis'); 5058 } 5059 }); 5060 5061 $.ajax({ 5062 method: 'GET', 5063 url: Urls.Stores.GetMyStoreModal, 5064 dataType: 'html', 5065 success: function(data) { 5066 $('.my-store-modal').replaceWith(data); 5067 $(document).trigger('Mobile.Redesign.SetStore'); 5068 } 5069 }); 5070 5071 $.ajax({ 5072 method: 'GET', 5073 url: Urls.getStoresPanel, 5074 dataType: 'html', 5075 success: function(data) { 5076 $('#location').html(data); 5077 } 5078 }); 5079 5080 $(document).trigger('ShopMyStore.Update', storeId); 5081 }, 5082 error: function() { 5083 $('.my-store-modal').hide(); 5084 $('.location-search-dialog').hide(); 5085 } 5086 }); 5087 } 5088 } 5089 5090 this.assignStoreId = function(storeId) { 5091 if (storeId) { 5092 $.ajax({ 5093 url : Urls.assignStoreId, 5094 data : { store_id : storeId }, 5095 method : "POST", 5096 dataType : "JSON", 5097 success : function(data) { 5098 if ('success' in data && data['success'] == true) { 5099 // TODO: any follow-up needed client-side? 5100 } 5101 } 5102 }); 5103 } 5104 } 5105 5106 return this; 5107} 5108 5109},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/Geolocation/GeolocationHelper":115,"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../components/LoadingIndicator":25,"lodash":133}],11:[function(require,module,exports){ 5110'use strict'; 5111 5112exports.ValidateProductLineItems = validateProductLineItems; 5113 5114var options; 5115var buffer = {}; 5116 5117function validateProductLineItems($bopisProductLineItems, optionsParameter) { 5118 if (optionsParameter) { 5119 options = optionsParameter; 5120 } 5121 5122 buffer['TotalCount'] = $bopisProductLineItems.length; 5123 buffer['LoadedCount'] = 0; 5124 buffer['ProductLineItems'] = {}; 5125 5126 $bopisProductLineItems.each(function(index, element) { 5127 var $this = $(this); 5128 var uuid = $this.attr('uuid'); 5129 var productId = $this.attr('sku'); 5130 var storeId = $this.attr('store'); 5131 var quantityRequested = $this.closest('.order-item').find('.qty-edit input[type="text"]').val(); 5132 5133 $.ajax({ 5134 method: 'POST', 5135 url: Urls.Bopis.GetStoreInventoryForProductForStore, 5136 contentType: 'application/json', 5137 async: true, 5138 data: JSON.stringify({ 5139 ProductId: productId, 5140 StoreId: storeId 5141 }), 5142 dataType: 'json', 5143 success: function(data) { 5144 var inquiryResult; 5145 if (data && data.ServiceSuccessfullyCalled && data.InquiryResult && data.InquiryResult.data[0].inventory_supplies) { 5146 inquiryResult = data.InquiryResult.data[0].inventory_supplies; 5147 } 5148 5149 if (inquiryResult && inquiryResult && inquiryResult.length > 0) { 5150 buffer['ProductLineItems'][uuid] = { 5151 QuantityRequested: parseInt(quantityRequested, 10), 5152 InquiryResult: inquiryResult 5153 }; 5154 5155 buffer['LoadedCount'] += 1; 5156 validateProductLineItemsSuccess(); 5157 } else { 5158 $result.html(''); 5159 5160 if (options && options.ErrorCallback) { 5161 options.errorCallback(); 5162 } 5163 } 5164 }, 5165 error: function() { 5166 if (options && options.ErrorCallback) { 5167 options.errorCallback(); 5168 } 5169 } 5170 }); 5171 }); 5172 5173 return false;
5174} 5175 5176function validateProductLineItemsSuccess() { 5177 if (buffer['LoadedCount'] == buffer['TotalCount']) { 5178 var isBopisInventoryValid = true; 5179 for (var productLineItemUUID in buffer['ProductLineItems']) { 5180 var productLineItem = buffer['ProductLineItems'][productLineItemUUID]; 5181 5182 if (productLineItem.QuantityRequested > productLineItem.InquiryResult[0].detail.quantity) { 5183 isBopisInventoryValid = false; 5184 } 5185 } 5186 5187 if (options && options.SuccessEvent) { 5188 $(document).trigger(options.SuccessEvent, { 5189 SubmitPaymentForBopis: true, 5190 IsBopisInventoryValid: isBopisInventoryValid 5191 }); 5192 } 5193 } 5194} 5195},{}],12:[function(require,module,exports){ 5196'use strict'; 5197 5198var dialog = require('../../dialog'); 5199var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 5200var loadingIndicator = require('../../components/LoadingIndicator'); 5201 5202exports.initialize = initialize; 5203 5204var options; 5205var dataBuffer; 5206 5207function initialize(optionsParameter) { 5208 dataBuffer = {}; 5209 options = $.extend({ 5210 successCallback: null, 5211 errorCallback: null 5212 }, optionsParameter); 5213 5214 $('#shop-your-store-dialog').find('.store-name').text(options.StoreName); 5215 $('#shop-your-store-dialog').find('.category-links a').each(function(index, element) { 5216 var $this = $(this); 5217 var href = $this.attr('href'); 5218 if (href.indexOf('?') > -1) { 5219 href = href.substr(0, href.indexOf('?')); 5220 } 5221 $this.attr('href', href + '?prefn1=availableStores&prefv1=' + options.StoreId + '&shopmystore=true'); 5222 }) 5223 5224 // GoogleTagManagerClient.PushDataLayerForEvent('roadieFormDisplay'); 5225 dialog.open({ 5226 html: $('#shop-your-store-dialog').html(), 5227 options: { 5228 dialogClass: 'shop-your-store-dialog', 5229 width: 380, 5230 draggable: false, 5231 resizable: false, 5232 open: function(event, ui) { 5233 var $this = $(this); 5234 var $shopYourStoreToggle = $this.find('.shop-my-store-toggle .checkbox-toggle'); 5235 $(this).closest('.ui-dialog').attr({ 5236 id: "shop-your-store-dialog-container", 5237 "tabindex": "-1" 5238 }).focus(); 5239 dataBuffer['toggleTimer'] = setInterval(function() { 5240 $shopYourStoreToggle.click(); 5241 }, 2000); 5242 }, 5243 close: function(event, ui) { 5244 clearInterval(dataBuffer['toggleTimer']); 5245 $(this).find('.shop-my-store-toggle .checkbox-toggle input').prop('checked', false); 5246 } 5247 } 5248 }); 5249 5250} 5251},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../components/LoadingIndicator":25,"../../dialog":36}],13:[function(require,module,exports){ 5252'use strict'; 5253 5254var _ = require('lodash'); 5255var dialog = require('../../dialog'); 5256var loadingIndicator = require('../../components/LoadingIndicator'); 5257var LocalDeliveryDialog = require('./LocalDeliveryDialog'); 5258var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 5259var tooltip = require('../../tooltip'); 5260var ValidationSettings = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 5261var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 5262var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 5263var ZipCodeToStateMap = require('../../../../../bc_sheplersbootbarn_core/cartridge/data/ZipCodeToStateMap.json'); 5264 5265exports.initialize = initialize; 5266exports.search = search; 5267exports.remove = remove; 5268 5269var options; 5270var validator; 5271var dataBuffer; 5272 5273var resultContainerTemplate; 5274var resultItemTemplate; 5275var localDeliveryDecorator; 5276 5277var $container; 5278var $form; 5279var $result; 5280var $formInputPostalCode; 5281var $storeSearchButton; 5282var $storeSearchButtonContainer; 5283var $bopisButton; 5284var $errorMessage; 5285var $inputTooltip; 5286 5287function initialize($containerParameter, optionsParameter) { 5288 dataBuffer = {}; 5289 options = $.extend({ 5290 successCallback: null, 5291 errorCallback: null 5292 }, optionsParameter); 5293 5294 resultContainerTemplate = _.template($('#template-bopis-result-container').html(), TemplateConstants.Lodash.Settings); 5295 resultItemTemplate = _.template($('#template-bopis-result-item').html(), TemplateConstants.Lodash.Settings); 5296 localDeliveryDecorator = _.template($('#template-bopis-localdelivery-decorator').html(), TemplateConstants.Lodash.Settings); 5297 5298 $container = $containerParameter; 5299 $form = $container.find('form'); 5300 $result = $container.find('.result'); 5301 $formInputPostalCode = $form.find('input[name$="_postalCode"]'); 5302 $storeSearchButton = $container.find('.btn.store-search'); 5303 $storeSearchButtonContainer = $container.find('.btn-store-search-container'); 5304 $bopisButton = $container.find('.btn.bopis'); 5305 $errorMessage = $form.find('span.error'); 5306 $inputTooltip = $formInputPostalCode.parent(); 5307 5308 if (options && options.IsVariantSelected) { 5309 $('.btn.store-search').removeAttr('disabled'); 5310 $inputTooltip.removeClass('tooltip'); 5311 } 5312 5313 tooltip.init({ 5314 items: '.store-search-tooltip', 5315 tooltipClass: 'store-search-tooltip' 5316 }, $('.store-search-tooltip')); 5317 5318 $container.attr('state', 'form'); 5319 validator = $form.validate(ValidationSettings.Global); 5320 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_POSTAL_CODE); 5321 $formInputPostalCode.rules('add', ValidationRules.ZipCode); 5322 5323 if ($container.attr('state') === 'form' && validator.checkForm() && !$storeSearchButton.hasClass('ready')) { 5324 $storeSearchButton.addClass('ready'); 5325 } 5326 5327 $form.off('click.apply').on('click.apply', '.btn.store-search:not([loading])', function (event) { 5328 event.preventDefault(); 5329 search(); 5330 }); 5331 5332 $container.off('click.apply').on('click.apply', '.btn.bopis:not([loading])', function (event) { 5333 event.preventDefault(); 5334 5335 var selectedLocation = dataBuffer['StoresDisplayed'][$('input[name="Bopis_StoreSearch_StoreId"]:checked').val()]; 5336 if (selectedLocation) { 5337 if (options.LocalDelivery.Enabled) { 5338 LocalDeliveryDialog.initialize(options, selectedLocation); 5339 } else { 5340 $(document).trigger('ProductDetailPage.Bopis.AddToCart', { bopis: true, shippingOption: 'pickup', channel: options.Channel }); 5341 } 5342 } else { 5343 $(document).trigger('ProductDetailPage.Bopis.AddToCart', { channel: options.Channel }); 5344 } 5345 }); 5346 5347 $formInputPostalCode.off('keydown.BopisStoreSearch.ValidationCheck').on('keydown.BopisStoreSearch.ValidationCheck', function (event) { 5348 if ($formInputPostalCode.val().length == 5 && parseInt(event.key, 10) == event.key && !window.getSelection().toString()) { 5349 event.preventDefault(); 5350 } 5351 }); 5352 5353 $formInputPostalCode.off('change.BopisStoreSearch.ValidationCheck').on('change.BopisStoreSearch.ValidationCheck', function (event) { 5354 if ($formInputPostalCode.val().length > 5) { 5355 $formInputPostalCode.val($formInputPostalCode.val().substr(0, 5)); 5356 } 5357 }); 5358 5359 $formInputPostalCode.off('keyup.BopisStoreSearch.ValidationCheck, change.BopisStoreSearch.ValidationCheck').on('keyup.BopisStoreSearch.ValidationCheck, change.BopisStoreSearch.ValidationCheck', function (event) { 5360 event.stopImmediatePropagation(); 5361 5362 if ($container.attr('state') === 'form') { 5363 if (validator.checkForm() && !$storeSearchButton.hasClass('ready')) { 5364 $storeSearchButton.addClass('ready'); 5365 } else if (!validator.checkForm() && $storeSearchButton.hasClass('ready')) { 5366 $storeSearchButton.removeClass('ready'); 5367 } 5368 } 5369 5370 if ($container.attr('state') === 'result') { 5371 $container.attr('state', 'form'); 5372 $formInputPostalCode.val(''); 5373 } 5374 }); 5375 5376 $(document).off('mousedown.BopisStoreSearch.ValidationClear').on('mousedown.BopisStoreSearch.ValidationClear', function (event) { 5377 if (validator && $(event.target).closest($container).length == 0) { 5378 validator.resetForm(); 5379 $errorMessage.html('').hide(); 5380 } 5381 }); 5382 5383 $(document).off('Bopis.StoreSearch.Reset').on('Bopis.StoreSearch.Reset', function (event) { 5384 reset(); 5385 }); 5386 5387 $container.off('click.BopisStoreSearch.Reset').on('click.BopisStoreSearch.Reset', '.reset', function (event) { 5388 reset(); 5389 }); 5390 5391 $(document).off('ProductDetailPage.Variant.StoreSearch').on('ProductDetailPage.Variant.StoreSearch', function (event) { 5392 if (options.SelectedLocations) { 5393 var sizeSelected = $('div.product-variations .size.size-options li.selected'); 5394 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 5395 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 5396 var isSizeSelected = sizeSelected.length || (lengthSelected && widthSelected); 5397 var isColorSelected = $('div.product-variations .color.color-options li.selected').length; 5398 5399 if (isSizeSelected && isColorSelected) { 5400 search(); 5401 } 5402 } 5403 }); 5404 5405 $container.off('click.BopisStoreSearch.Selection').on('click.BopisStoreSearch.Selection', 'input[name="Bopis_StoreSearch_StoreId"]', function (event) { 5406 var bopisStore = $('input[name="Bopis_StoreSearch_StoreId"]:checked').val(); 5407 5408 if (!$bopisButton.hasClass('ready')) { 5409 $bopisButton.addClass('ready'); 5410 } 5411 5412 $('.product-add-to-cart button').attr('disabled', 'disabled').addClass('hidden'); 5413 5414 if (bopisStore) { 5415 $bopisButton.attr('state', 'pickup'); 5416 } else { 5417 $bopisButton.attr('state', 'ship'); 5418 } 5419 }); 5420} 5421 5422function reset() { 5423 $formInputPostalCode.val(''); 5424 $container.attr('state', 'form'); 5425 $storeSearchButton.removeClass('ready'); 5426 $('.product-add-to-cart button').removeAttr('disabled').removeClass('hidden'); 5427 $bopisButton.removeClass('ready'); 5428} 5429 5430function search() { 5431 var sizeSelected = $('div.product-variations .size.size-options li.selected'); 5432 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 5433 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 5434 var isSizeSelected = sizeSelected.length || (lengthSelected && widthSelected); 5435 var isColorSelected = $('div.product-variations .color.color-options li.selected').length; 5436 5437 if (!isSizeSelected && !isColorSelected) { 5438 $errorMessage.html('Please select a size and color first.').show(); 5439 return false;
5440 } else if (!isSizeSelected) { 5441 $errorMessage.html('Please select a size first.').show(); 5442 return false; 5443 } else if (!isColorSelected) { 5444 $errorMessage.html('Please select a color first.').show(); 5445 return false; 5446 } else { 5447 $errorMessage.html('').hide(); 5448 $storeSearchButton.removeAttr('disabled'); 5449 } 5450 5451 if (Urls && Urls.Bopis.GetStoreInventoryForProductForPostalCode && validator.valid()) { 5452 $storeSearchButtonContainer.loading({ 5453 IsImageShown: false, 5454 Label: Resources.Loading.Loading, 5455 BackgroundColor: $storeSearchButton.css('background-color') 5456 }); 5457 5458 $.ajax({ 5459 method: 'POST', 5460 url: Urls.Bopis.GetStoreInventoryForProductForPostalCode, 5461 contentType: 'application/json', 5462 data: JSON.stringify({ 5463 Channel: options.Channel, 5464 Source: options.Source, 5465 ProductId: $('.product-add-to-cart input[name="pid"]').val(), 5466 PostalCode: $formInputPostalCode.val() 5467 }), 5468 dataType: 'json', 5469 success: function(data) { 5470 if ($storeSearchButtonContainer.attr('loading')) { 5471 $storeSearchButtonContainer.loading('destroy'); 5472 } 5473 $('.product-add-to-cart button').attr('disabled', 'disabled').addClass('hidden'); 5474 5475 var inquiryResult; 5476 if (data && data.ServiceSuccessfullyCalled && data.InquiryResult && data.InquiryResult.data && data.InquiryResult.data.length > 0 && data.InquiryResult.data[0].inventory_supplies) { 5477 inquiryResult = data.InquiryResult.data[0].inventory_supplies; 5478 } 5479 5480 $container.attr('state', 'result'); 5481 if (inquiryResult && inquiryResult.length > 0) { 5482 dataBuffer['StoresDisplayed'] = []; 5483 $container.attr('result-count', inquiryResult.length); 5484 5485 var storeListHtml = ''; 5486 var isStoreSelected = false; 5487 var selectedStoreAttribute; 5488 for (var inventoryRecordElement in inquiryResult) { 5489 var inventoryRecord = inquiryResult[inventoryRecordElement]; 5490 5491 if (inventoryRecord.detail && inventoryRecord.detail.quantity > 0 && !dataBuffer['StoresDisplayed'][inventoryRecord.location.code]) { 5492 if (options && options.SelectedLocations == inventoryRecord.location.code) { 5493 isStoreSelected = true; 5494 selectedStoreAttribute ='checked'; 5495 } else { 5496 selectedStoreAttribute = ''; 5497 } 5498 5499 var localDeliveryHtml = ''; 5500 if (options.LocalDelivery.Enabled && isLocationInLocalDeliveryRadius(inventoryRecord.location) && inventoryRecord.location.local_delivery_enabled) { 5501 localDeliveryHtml = localDeliveryDecorator(); 5502 } 5503 5504 var labelPrefix; 5505 if (options && options.IsStoreHoliday) { 5506 labelPrefix = 'Available At '; 5507 } else { 5508 labelPrefix = 'Available TODAY At '; 5509 } 5510 5511 if (inventoryRecord.location.postal_address.namePrefix) { 5512 labelPrefix += '<span class="nowrap">' + inventoryRecord.location.postal_address.namePrefix + '</span> '; 5513 } 5514 5515 storeListHtml += resultItemTemplate({ 5516 StoreId: inventoryRecord.location.code, 5517 QuantityAvailable: inventoryRecord.detail.quantity, 5518 Html: labelPrefix + inventoryRecord.location.postal_address.name + ',<br/>' + inventoryRecord.location.postal_address.address_line1 + ', ' + inventoryRecord.location.postal_address.city + ', ' + inventoryRecord.location.postal_address.province_or_state, 5519 Selected: selectedStoreAttribute, 5520 LocalDelivery: localDeliveryHtml 5521 }); 5522 } 5523 5524 dataBuffer['StoresDisplayed'][inventoryRecord.location.code] = inventoryRecord; 5525 } 5526 storeListHtml += resultItemTemplate({ 5527 StoreId: '', 5528 QuantityAvailable: '', 5529 Html: 'Ship Instead', 5530 Selected: '', 5531 LocalDelivery: '' 5532 }); 5533 5534 var resultHtml = resultContainerTemplate({ 5535 Html: storeListHtml 5536 }); 5537 5538 if (isStoreSelected) { 5539 $bopisButton.addClass('ready'); 5540 } 5541 5542 $result.html(resultHtml); 5543 5544 tooltip.init({ 5545 items: '.tooltip' 5546 }, $result); 5547 5548 if (options.successCallback) { 5549 options.successCallback(inquiryResult); 5550 } 5551 } else { 5552 $('.product-add-to-cart button').removeAttr('disabled').removeClass('hidden'); 5553 $container.attr('result-count', '0'); 5554 $result.html(''); 5555 5556 if (options.errorCallback) { 5557 options.errorCallback(); 5558 } 5559 } 5560 }, 5561 error: function() { 5562 if ($storeSearchButtonContainer.attr('loading')) { 5563 $storeSearchButtonContainer.loading('destroy'); 5564 } 5565 5566 if (options.errorCallback) { 5567 options.errorCallback(); 5568 } 5569 } 5570 }); 5571 } 5572} 5573 5574function remove() { 5575 validator.destroy(); 5576 $('.product-add-to-cart button').removeAttr('disabled').removeClass('hidden'); 5577} 5578
5579function isLocationInLocalDeliveryRadius(location) { 5580 var localDeliveryRadius; 5581 if (location.local_delivery_vendor && location.local_delivery_vendor == 'GoLocal') { 5582 localDeliveryRadius = options.LocalDelivery.RadiusForGoLocal; 5583 } else { 5584 localDeliveryRadius = options.LocalDelivery.RadiusForRoadie; 5585 } 5586 5587 if (localDeliveryRadius && location && location.distance && localDeliveryRadius >= location.distance) { 5588 return true; 5589 } 5590 5591 return false; 5592} 5593},{"../../../../../bc_sheplersbootbarn_core/cartridge/data/ZipCodeToStateMap.json":111,"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../components/LoadingIndicator":25,"../../dialog":36,"../../tooltip":101,"./LocalDeliveryDialog":9,"lodash":133}],14:[function(require,module,exports){ 5594'use strict'; 5595 5596var dialog = require('./dialog'); 5597var util = require('./util'); 5598var SessionAttributes = window.SessionAttributes; 5599 5600/** 5601 * @function captcha Used to display/control the scrim containing the simulated captcha code 5602 **/ 5603module.exports = function () { 5604 /** 5605 * if the session.privacy.ratelimited element is present then show the notification 5606 * NOTE: You will probably want to replace this with a call to an actual CAPTCHA system to replace the simple one here 5607 */ 5608 if (SessionAttributes.SHOW_CAPTCHA) { 5609 dialog.open({ 5610 html: '<p>' + Resources.PASSWORD_TIP_1 + '</p><p>' + Resources.PASSWORD_TIP_2 + '</p>', 5611 options: { 5612 title: Resources.ARE_YOU_HUMAN, 5613 closeOnEscape: false, 5614 dialogClass: 'no-close password-error', 5615 width: 400, 5616 buttons: [{ 5617 text: Resources.OK, 5618 click: function () { 5619 var url = util.appendParamsToUrl(Urls.rateLimiterReset, {format: 'ajax'}); 5620 $.ajax({ 5621 url: url 5622 }); 5623 $(this).dialog('close'); 5624 } 5625 }] 5626 } 5627 }); 5628 } 5629}; 5630 5631},{"./dialog":36,"./util":102}],15:[function(require,module,exports){ 5632'use strict'; 5633 5634var page = require('./page'), 5635 util = require('./util'), 5636 TPromise = require('promise'); 5637 5638var _currentCategory = '', 5639 MAX_ACTIVE = 6; 5640 5641/** 5642 * @private 5643 * @function 5644 * @description Verifies the number of elements in the compare container and updates it with sequential classes for ui targeting 5645 */ 5646function refreshContainer() { 5647 var $compareContainer = $('.compare-items'); 5648 var $compareItems = $compareContainer.find('.compare-item'); 5649 var numActive = $compareItems.filter('.active').length; 5650 5651 if (numActive < 2) { 5652 $('#compare-items-button').attr('disabled', 'disabled'); 5653 } else { 5654 $('#compare-items-button').removeAttr('disabled'); 5655 } 5656 5657 $compareContainer.toggle(numActive > 0); 5658} 5659/** 5660 * @private 5661 * @function 5662 * @description Adds an item to the compare container and refreshes it 5663 */ 5664function addToList(data) { 5665 // get the first compare-item not currently active 5666 var $item = $('.compare-items .compare-item').not('.active').first(), 5667 $productTile = $('#' + data.uuid); 5668 5669 if ($item.length === 0) { 5670 if ($productTile.length > 0) { 5671 $productTile.find('.compare-check')[0].checked = false; 5672 } 5673 window.alert(Resources.COMPARE_ADD_FAIL); 5674 return; 5675 } 5676 5677 // if already added somehow, return 5678 if ($('[data-uuid="' + data.uuid + '"]').length > 0) { 5679 return; 5680 } 5681 // set as active item 5682 $item.addClass('active') 5683 .attr('data-uuid', data.uuid) 5684 .attr('data-itemid', data.itemid) 5685 .data('uuid', data.uuid) 5686 .data('itemid', data.itemid) 5687 .append($(data.img).clone().addClass('compare-item-image')); 5688} 5689/** 5690 * @private 5691 * @function 5692 * description Removes an item from the compare container and refreshes it 5693 */ 5694function removeFromList($item) { 5695 if ($item.length === 0) { return; } 5696 // remove class, data and id from item 5697 $item.removeClass('active') 5698 .removeAttr('data-uuid') 5699 .removeAttr('data-itemid') 5700 .data('uuid', '') 5701 .data('itemid', '') 5702 // remove the image 5703 .find('.compare-item-image').remove(); 5704} 5705 5706function addProductAjax(args) { 5707 var promise = new TPromise(function (resolve, reject) { 5708 $.ajax({ 5709 url: Urls.compareAdd, 5710 data: { 5711 pid: args.itemid, 5712 category: _currentCategory 5713 }, 5714 dataType: 'json' 5715 }).done(function (response) { 5716 if (!response || !response.success) { 5717 reject(new Error(Resources.COMPARE_ADD_FAIL)); 5718 } else { 5719 resolve(response); 5720 } 5721 }).fail(function (jqxhr, status, err) { 5722 reject(new Error(err)); 5723 }); 5724 }); 5725 return promise; 5726} 5727 5728function removeProductAjax(args) { 5729 var promise = new TPromise(function (resolve, reject) { 5730 $.ajax({ 5731 url: Urls.compareRemove, 5732 data: { 5733 pid: args.itemid, 5734 category: _currentCategory 5735 }, 5736 dataType: 'json' 5737 }).done(function (response) { 5738 if (!response || !response.success) { 5739 reject(new Error(Resources.COMPARE_REMOVE_FAIL)); 5740 } else { 5741 resolve(response); 5742 } 5743 }).fail(function (jqxhr, status, err) { 5744 reject(new Error(err)); 5745 }); 5746 }); 5747 return promise; 5748} 5749 5750function shiftImages() { 5751 return new TPromise(function (resolve) { 5752 var $items = $('.compare-items .compare-item'); 5753 $items.each(function (i, item) { 5754 var $item = $(item); 5755 // last item 5756 if (i === $items.length - 1) { 5757 return removeFromList($item); 5758 } 5759 var $next = $items.eq(i + 1); 5760 if ($next.hasClass('active')) { 5761 // remove its own image 5762 $next.find('.compare-item-image').detach().appendTo($item); 5763 $item.addClass('active') 5764 .attr('data-uuid', $next.data('uuid')) 5765 .attr('data-itemid', $next.data('itemid')) 5766 .data('uuid', $next.data('uuid')) 5767 .data('itemid', $next.data('itemid')); 5768 } 5769 }); 5770 resolve(); 5771 }); 5772} 5773 5774/** 5775 * @function 5776 * @description Adds product to the compare table 5777 */ 5778function addProduct(args) { 5779 var promise; 5780 var $items = $('.compare-items .compare-item'); 5781 var $cb = $(args.cb); 5782 var numActive = $items.filter('.active').length; 5783 if (numActive === MAX_ACTIVE) { 5784 if (!window.confirm(Resources.COMPARE_CONFIRMATION)) { 5785 $cb[0].checked = false;
5786 return; 5787 } 5788 5789 // remove product using id 5790 var $firstItem = $items.first(); 5791 promise = removeItem($firstItem).then(function () { 5792 return shiftImages(); 5793 }); 5794 } else { 5795 promise = TPromise.resolve(0); 5796 } 5797 return promise.then(function () { 5798 return addProductAjax(args).then(function () { 5799 addToList(args); 5800 if ($cb && $cb.length > 0) { $cb[0].checked = true; } 5801 refreshContainer(); 5802 }); 5803 }).then(null, function () { 5804 if ($cb && $cb.length > 0) { $cb[0].checked = false; } 5805 }); 5806} 5807 5808/** 5809 * @function 5810 * @description Removes product from the compare table 5811 * @param {object} args - the arguments object should have the following properties: itemid, uuid and cb (checkbox) 5812 */ 5813function removeProduct(args) { 5814 var $cb = args.cb ? $(args.cb) : null; 5815 return removeProductAjax(args).then(function () { 5816 var $item = $('[data-uuid="' + args.uuid + '"]'); 5817 removeFromList($item); 5818 if ($cb && $cb.length > 0) { $cb[0].checked = false; } 5819 refreshContainer(); 5820 }, function () { 5821 if ($cb && $cb.length > 0) { $cb[0].checked = true; } 5822 }); 5823} 5824 5825function removeItem($item) { 5826 var uuid = $item.data('uuid'), 5827 $productTile = $('#' + uuid); 5828 return removeProduct({ 5829 itemid: $item.data('itemid'), 5830 uuid: uuid, 5831 cb: ($productTile.length === 0) ? null : $productTile.find('.compare-check') 5832 }); 5833} 5834 5835/** 5836 * @private 5837 * @function 5838 * @description Initializes the DOM-Object of the compare container 5839 */ 5840function initializeDom() { 5841 var $compareContainer = $('.compare-items'); 5842 _currentCategory = $compareContainer.data('category') || ''; 5843 var $active = $compareContainer.find('.compare-item').filter('.active'); 5844 $active.each(function () { 5845 var $productTile = $('#' + $(this).data('uuid')); 5846 if ($productTile.length === 0) {return;} 5847 $productTile.find('.compare-check')[0].checked = true; 5848 }); 5849 // set container state 5850 refreshContainer(); 5851} 5852 5853/** 5854 * @private 5855 * @function 5856 * @description Initializes the events on the compare container 5857 */ 5858function initializeEvents() { 5859 // add event to buttons to remove products 5860 $('.compare-item').on('click', '.compare-item-remove', function () { 5861 removeItem($(this).closest('.compare-item')); 5862 }); 5863 5864 // Button to go to compare page 5865 $('#compare-items-button').on('click', function () { 5866 page.redirect(util.appendParamToURL(Urls.compareShow, 'category', _currentCategory)); 5867 }); 5868 5869 // Button to clear all compared items 5870 // rely on refreshContainer to take care of hiding the container 5871 $('#clear-compared-items').on('click', function () { 5872 $('.compare-items .active').each(function () { 5873 removeItem($(this)); 5874 }); 5875 }); 5876} 5877 5878exports.init = function () { 5879 initializeDom(); 5880 initializeEvents(); 5881}; 5882 5883exports.addProduct = addProduct; 5884exports.removeProduct = removeProduct; 5885 5886},{"./page":46,"./util":102,"promise":134}],16:[function(require,module,exports){ 5887'use strict'; 5888 5889var dialog = require('../../js/dialog'); 5890 5891var openCarouselVideoModal = function(event) { 5892 var $videoElement = $('[data-carousel-video-element]').wrap('<div class="video-container"></div>').parent(); 5893 5894 dialog.open({ 5895 html: $videoElement[0].outerHTML, 5896 options: { 5897 dialogClass: 'fixed carousel-video-modal', 5898 width: '100%', 5899 height: '100%', 5900 draggable: false, 5901 resizable: false, 5902 open: function(event, ui) { 5903 var $this = $(this); 5904 $this.find('.carousel-video-element')[0].play(); 5905 }, 5906 close: function(event, ui) { 5907 var $this = $(this); 5908 $this.find('.carousel-video-element')[0].pause(); 5909 } 5910 } 5911 }); 5912} 5913 5914function initialize() { 5915 $(document).off('click.CarouselVideo.Play').on('click.CarouselVideo.Play', '.product-primary-image [data-carousel-video]', openCarouselVideoModal); 5916 5917 $(document).off('click.CarouselVideo.Catch').on('click.CarouselVideo.Catch', '.product-primary-image .carousel-video-link', function(event) { 5918 event.preventDefault(); 5919 }); 5920} 5921 5922module.exports.init = initialize; 5923 5924},{"../../js/dialog":36}],17:[function(require,module,exports){ 5925'use strict'; 5926 5927var dialog = require('../dialog'); 5928 5929exports.init = initialize; 5930 5931function initialize() { 5932 wishlistPostOrder(); 5933} 5934 5935function wishlistPostOrder() { 5936 $(document).off('CordialTagging.WishlistPostOrder').on('CordialTagging.WishlistPostOrder', function (event, removedProducts, orderNumber) {
5937 if ($(document).find('.order-confirmation-details').length > 0 && removedProducts && orderNumber) { 5938 var auth_data = { 5939 email: $('.confirmation .billing-info .order-billing-email').text() 5940 }; 5941 var contact_data = { 5942 'channels': { 5943 'email': { 5944 'address': $('.confirmation .billing-info .order-billing-name').text() 5945 } 5946 }, 5947 'first_name': $('.confirmation .billing-info .order-billing-name').text().split(' ')[0], 5948 'last_name': $('.confirmation .billing-info .order-billing-name').text().split(' ')[1], 5949 'phone': $('.confirmation .billing-info .order-billing-phone').text(), 5950 'postal_code': $('.confirmation .billing-info .order-billing-geo .zip').text(), 5951 'source_create': 'order', 5952 'geo_location': { 5953 'postal_code': $('.confirmation .billing-info .order-billing-geo .zip').text(), 5954 'country': $('.confirmation .billing-info .order-billing-country').text(), 5955 'state': $('.confirmation .billing-info .order-billing-geo .state').text(), 5956 'city': $('.confirmation .billing-info .order-billing-geo .city').text() 5957 } 5958 }; 5959 5960 $('.order-item').each(function(index, el) { 5961 var _this = $(this); 5962 _this.find('.productCardMetadata').each(function(key, v) { 5963 var thisItem = JSON.parse($(this).attr('data-product-gtm-json')); 5964 if (removedProducts.indexOf(thisItem["skuid"]) > -1) { 5965 var product = {}; 5966 product.productID = thisItem["skuid"]; 5967 product.productName = thisItem["name"].replace(/\\/g, ""); 5968 product.category = thisItem["category"].replace(/\\/g, ""); 5969 product.price = thisItem["price"]; 5970 product.images = [_this.find('img').attr('src')]; 5971 product.url = window.location.origin + _this.find('.name').find('a').attr('href'); 5972 product.attr = { 5973 'manufacturer': thisItem["brand"] 5974 }; 5975 5976 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 5977 crdl('event', 'wishlist_remove', product); 5978 } 5979 } 5980 }); 5981 }); 5982 } 5983 }); 5984} 5985 5986},{"../dialog":36}],18:[function(require,module,exports){ 5987'use strict'; 5988 5989var dialog = require('../dialog'); 5990 5991var ValidationSettings = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 5992var ValidationRules = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 5993var ValidationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 5994 5995exports.initialize = initialize; 5996 5997function initialize($container) { 5998 $container.find('[email-form]').each(function (index, element) { 5999 var $form = $(element); 6000 var formType = $form.attr('email-form'); 6001 appendCSRFToken($form); 6002 6003 if (formType && typeof handlers[formType] == 'function') { 6004 handlers[formType]($form); 6005 } 6006 }); 6007} 6008 6009var handlers = { 6010 'cpra': function($form) { 6011 var $requiredFields = $form.find('input.required'); 6012 var $formNameFirst = $form.find('input[name$="name_first"]'); 6013 var $formNameLast = $form.find('input[name$="name_last"]'); 6014 var $formEmail = $form.find('input[name$="email"]'); 6015 var $formPhone = $form.find('input[name$="phone"]'); 6016 var $formRequestType = $form.find('input[name$="requestType"]'); 6017 6018 var formValidator = $form.validate(ValidationSettings.Global); 6019 $.validator.addMethod('requiredExcludingPunctuation', ValidationHelper.ValidateRequiredExcludingPunctuation, Resources.INVALID_VALUE); 6020 $requiredFields.rules('add', ValidationRules.RequiredExcludingPunctuation); 6021 $formEmail.rules('add', ValidationRules.Email); 6022 $form.find('span.error').remove(); 6023 6024 $form.find('input[type="submit"]').on('click', function(event) { 6025 event.preventDefault(); 6026 6027 if (formValidator.form()) { 6028 var data = { 6029 'form_type': $form.attr('email-form'), 6030 'name_first': $formNameFirst.val(), 6031 'name_last': $formNameLast.val(), 6032 'email': $formEmail.val(), 6033 'phone': $formPhone.val(), 6034// 'request_type': $formRequestType.filter(':checked').map(function() { return this.value; }).get().join(' and ') 6035 'request_type': $formRequestType.val() 6036 } 6037 6038 $form.find('input[type="hidden"]').each(function () { 6039 var $this = $(this); 6040 data[$this.attr('name')] = $this.val(); 6041 }); 6042 6043 $.ajax({ 6044 url: Urls.EmailForm.Send, 6045 type: 'POST', 6046 data: data, 6047 success: function(data) { 6048 if (data && data.EmailSent) { 6049 var $successContent = $('.content.cpra-form-success'); 6050 6051 dialog.open({ 6052 html: $successContent.html(), 6053 options: { 6054 title: $successContent.attr('title'), 6055 dialogClass: 'fixed checkout-terms' + ($successContent.attr('dialog-class') ? ' ' + $successContent.attr('dialog-class') : ''), 6056 draggable: false, 6057 open: function(event, ui) { 6058 var $this = $(this); 6059 6060 $('body').addClass('dialog-open'); 6061 $this.scrollTop(0); 6062 }, 6063 close: function(event, ui) { 6064 $('body').removeClass('dialog-open'); 6065 } 6066 } 6067 }); 6068 } else { 6069 var $errorContent = $('.content.cpra-form-error'); 6070 6071 dialog.open({ 6072 html: $errorContent.html(), 6073 options: { 6074 title: $errorContent.attr('title'), 6075 dialogClass: 'fixed checkout-terms' + ($errorContent.attr('dialog-class') ? ' ' + $errorContent.attr('dialog-class') : ''), 6076 draggable: false, 6077 open: function(event, ui) { 6078 var $this = $(this); 6079 6080 $('body').addClass('dialog-open'); 6081 $this.scrollTop(0); 6082 }, 6083 close: function(event, ui) { 6084 $('body').removeClass('dialog-open'); 6085 } 6086 } 6087 }); 6088 } 6089 }, 6090 error: function() { 6091 var $errorContent = $('.content.cpra-form-error'); 6092 6093 dialog.open({ 6094 html: $errorContent.html(), 6095 options: { 6096 title: $errorContent.attr('title'), 6097 dialogClass: 'fixed checkout-terms' + ($errorContent.attr('dialog-class') ? ' ' + $errorContent.attr('dialog-class') : ''), 6098 draggable: false, 6099 open: function(event, ui) { 6100 var $this = $(this); 6101 6102 $('body').addClass('dialog-open'); 6103 $this.scrollTop(0); 6104 }, 6105 close: function(event, ui) { 6106 $('body').removeClass('dialog-open'); 6107 } 6108 } 6109 }); 6110 } 6111 }); 6112 } 6113 }); 6114 } 6115} 6116 6117function appendCSRFToken($form) { 6118 $.ajax({ 6119 method: 'get', 6120 url: Urls.CSRFToken.Get, 6121 dataType: 'json', 6122 success: function(response) { 6123 $form.append('<input type="hidden" name="' + response.name + '" value="' + response.token + '"/>'); 6124 } 6125 }); 6126} 6127},{"../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../dialog":36}],19:[function(require,module,exports){ 6128'use strict'; 6129 6130var Recaptcha = require('../components/Recaptcha'); 6131var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 6132var ValidationRules = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 6133 6134exports.Initialize = initialize; 6135 6136var $footerEmailForm; 6137var validator; 6138var dataBuffer = {}; 6139var options = {}; 6140var loaded = {}; 6141 6142 6143function initialize(page) { 6144 if (page && page.options) { 6145 options = page.options; 6146 } 6147 6148 var footerEmailFormSelector;
6149 if (page.site == SiteConstants.SiteIds.CountryOutfittersUS) { 6150 footerEmailFormSelector = 'form#email-alert-signup'; 6151 } else if (page.site == SiteConstants.SiteIds.BootBarnUS) { 6152 footerEmailFormSelector = 'form#bootbarn-footer-email-alert-signup'; 6153 } else { 6154 footerEmailFormSelector = 'form#footer-email-signup'; 6155 } 6156 6157 $footerEmailForm = $(footerEmailFormSelector); 6158 if ($footerEmailForm.length > 0) { 6159 var $validatorErrorMessage = $footerEmailForm.find('span.error'); 6160 6161 $footerEmailForm.on('submit', function(event) { 6162 event.preventDefault(); 6163 6164 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForFooterEmailSignup) { 6165 submitEmailSignup(); 6166 } 6167 }); 6168 6169 $(document).off('mousedown.EmailSignUp.ValidationClear').on('mousedown.EmailSignUp.ValidationClear', function(event) { 6170 if (validator && $(event.target).closest(footerEmailFormSelector).parent().length == 0) { 6171 validator.resetForm(); 6172 $validatorErrorMessage.removeClass('signup-success').html('').hide(); 6173 } 6174 }); 6175 6176 $(document).on('Global.EmailSignup', function (event, data) { 6177 if (options && options.Recaptcha && options.Recaptcha.EnabledForFooterEmailSignup) { 6178 submitEmailSignup(); 6179 } 6180 }); 6181 6182 if (options && options.Recaptcha && options.Recaptcha.EnabledForFooterEmailSignup && options.Recaptcha.GoogleSiteKey) { 6183 Recaptcha.initialize(); 6184 renderRecaptchaForEmailSignup(); 6185 $(document).on('Recaptcha.Loaded', function(event) { 6186 if (!loaded.Recaptcha) { 6187 loaded.Recaptcha = true; 6188 renderRecaptchaForEmailSignup(); 6189 } 6190 }); 6191 } 6192 } 6193} 6194 6195function submitEmailSignup() { 6196 var $emailAddress = $footerEmailForm.find('input#email-alert-address'); 6197 validator = $footerEmailForm.validate(); 6198 $emailAddress.rules('add', ValidationRules.Email); 6199 validator.form(); 6200 6201 if (validator.valid()) { 6202 if(SitePreferences.CORDIAL_ENABLED){ 6203 var auth_data = { 6204 email: $emailAddress.val() 6205 } 6206 var contact_data = { 6207 'channels': { 6208 'email': { 6209 'address': $emailAddress.val(), 6210 'subscribeStatus': 'subscribed' 6211 } 6212 }, 6213 'signup_source': 'footer', 6214 'welcome_signup': true 6215 }; 6216 6217 var properties = { 6218 "signup_source": 'footer', 6219 "welcome_signup": true 6220 }; 6221 6222 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 6223 crdl([ 6224 ['contact', auth_data, contact_data], 6225 ['event', 'email_signup', properties] 6226 ]); 6227 } 6228 } 6229 if (SitePreferences.RETENTION_COM_ENABLED) { 6230 geq.suppress(); 6231 } 6232 6233 if ($('#email-alert-address.valid').length > 0 && $('#email-alert-address').val() != '') { 6234 $('input#email-alert-address').val(''); 6235 $('.signup-success').show(); 6236 } 6237 setTimeout(function() { 6238 $('.signup-success').hide(); 6239 }, 5000); 6240 } 6241} 6242 6243function renderRecaptchaForEmailSignup() { 6244 if (loaded.Recaptcha && $footerEmailForm.length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForFooterEmailSignup && options.Recaptcha.GoogleSiteKey) { 6245 if (dataBuffer.EmailSignupRecaptcha) { 6246 grecaptcha.reset(dataBuffer.EmailSignupRecaptcha); 6247 } 6248 dataBuffer.EmailSignupRecaptcha = grecaptcha.render('footer-email-alert-signup-submit', { 6249 'sitekey': options.Recaptcha.GoogleSiteKey, 6250 'callback': emailSignup, 6251 'badge': 'inline' 6252 }); 6253 } 6254} 6255},{"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../components/Recaptcha":29}],20:[function(require,module,exports){ 6256'use strict'; 6257 6258var loadingIndicator = require('./LoadingIndicator'); 6259var ReturnCodes = require('../../../../int_svs/cartridge/scripts/GiftCardConstants').ReturnCodes; 6260var ValidationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 6261var ValidationRules = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 6262 6263exports.initialize = initialize; 6264exports.remove = remove; 6265 6266var giftCardBalanceInquiryValidator; 6267 6268function initialize($container, optionsParameter) { 6269 var options = $.extend({ 6270 successCallback: null, 6271 errorCallback: null 6272 }, optionsParameter); 6273 6274 var $giftCardBalanceInquiryComponent = $container.find('.gift-card-balance-inquiry-component'); 6275 6276 var $giftCardBalanceInquiryForm = $giftCardBalanceInquiryComponent.find('form'); 6277 var $giftCardBalanceInquiryResult = $giftCardBalanceInquiryComponent.find('.balance-inquiry-result'); 6278 var $giftCardBalanceInquiryResultAmount = $giftCardBalanceInquiryComponent.find('.amount'); 6279 var $giftCardBalanceInquiryCardNumber = $giftCardBalanceInquiryForm.find('input[name$="giftCard_number"]'); 6280 var $giftCardBalanceInquiryPinNumber = $giftCardBalanceInquiryForm.find('input[name$="giftCard_pin"]'); 6281 var $giftCardBalanceInquiryErrorMessage = $giftCardBalanceInquiryForm.find('span.error'); 6282 6283 $container.attr('balance-inquiry-state', 'form'); 6284 6285 $giftCardBalanceInquiryComponent.off('click.apply').on('click.apply', '.btn.balance-inquiry:not([loading])', function (event) { 6286 event.preventDefault(); 6287 6288 $giftCardBalanceInquiryErrorMessage.html('').hide(); 6289 giftCardBalanceInquiryValidator = $giftCardBalanceInquiryForm.validate(); 6290 $.validator.addMethod('giftCardNumberLength', ValidationHelper.ValidateGiftCardNumberLength, Resources.Validation.Messages.GiftCard.Number.Length); 6291 $.validator.addMethod('giftCardNumberValues', ValidationHelper.ValidateGiftCardNumberValues, Resources.Validation.Messages.GiftCard.Number.Values); 6292 $giftCardBalanceInquiryCardNumber.rules('add', ValidationRules.GiftCard.Number); 6293 $giftCardBalanceInquiryPinNumber.rules('add', ValidationRules.GiftCard.Pin); 6294 giftCardBalanceInquiryValidator.form(); 6295 6296 if (Urls && Urls.GiftCard.BalanceInquiry && giftCardBalanceInquiryValidator.valid()) { 6297 var $this = $(this); 6298 6299 $this.loading({ 6300 IsImageShown: false, 6301 Label: Resources.Loading.Loading 6302 }); 6303 6304 var giftCardBalanceInquiryCardNumber = $giftCardBalanceInquiryCardNumber.val().match(/(\d)/g); 6305 if (giftCardBalanceInquiryCardNumber && giftCardBalanceInquiryCardNumber.length) { 6306 giftCardBalanceInquiryCardNumber = giftCardBalanceInquiryCardNumber.join(''); 6307 } 6308 6309 $.ajax({ 6310 method: 'POST', 6311 url: Urls.GiftCard.BalanceInquiry, 6312 contentType: 'application/json', 6313 data: JSON.stringify({ 6314 cardNumber: giftCardBalanceInquiryCardNumber, 6315 pin: $giftCardBalanceInquiryPinNumber.val() 6316 }), 6317 dataType: 'json', 6318 success: function (data) { 6319 $this.loading('destroy'); 6320 6321 var inquiryResult; 6322 if (data && data.ServiceSuccessfullyCalled && data.InquiryResult) { 6323 inquiryResult = data.InquiryResult; 6324 } 6325 6326 if (inquiryResult && inquiryResult.ReturnCode.ReturnCode == ReturnCodes.Approval) { 6327 $container.attr('balance-inquiry-state', 'result'); 6328 6329 $giftCardBalanceInquiryResultAmount.text(inquiryResult.BalanceAmount.AmountFormatted); 6330 6331 if (options.successCallback) { 6332 options.successCallback(inquiryResult); 6333 } 6334 } else { 6335 if (inquiryResult.ReturnCode.ReturnDescription == 'Invalid Message') { 6336 inquiryResult.ReturnCode.ReturnDescription = Resources.Error.Generic; 6337 } 6338 6339 $giftCardBalanceInquiryErrorMessage.html(inquiryResult.ReturnCode.ReturnDescription || Resources.Error.Generic).show(); 6340 6341 if (options.errorCallback) { 6342 options.errorCallback(); 6343 } 6344 } 6345 } 6346 }); 6347 } 6348 }); 6349 6350 $giftCardBalanceInquiryCardNumber.off('keydown.GiftCardBalanceInquiry.ValidationClear, change.GiftCardBalanceInquiry.ValidationClear').on('keydown.GiftCardBalanceInquiry.ValidationClear, change.GiftCardBalanceInquiry.ValidationClear', function (event) { 6351 if ($container.attr('balance-inquiry-state') === 'result') { 6352 $container.attr('balance-inquiry-state', 'form'); 6353 $giftCardBalanceInquiryPinNumber.val(''); 6354 $giftCardBalanceInquiryResultAmount.text(''); 6355 } 6356 }); 6357 6358 $(document).off('mousedown.GiftCardBalanceInquiry.ValidationClear').on('mousedown.GiftCardBalanceInquiry.ValidationClear', function (event) { 6359 if (giftCardBalanceInquiryValidator && $(event.target).closest('.gift-card-balance-inquiry-component').parent().length == 0) { 6360 giftCardBalanceInquiryValidator.resetForm(); 6361 $giftCardBalanceInquiryErrorMessage.html('').hide(); 6362 } 6363 }); 6364} 6365 6366function remove() { 6367 giftCardBalanceInquiryValidator.destroy(); 6368} 6369},{"../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../../../int_svs/cartridge/scripts/GiftCardConstants":128,"./LoadingIndicator":25}],21:[function(require,module,exports){ 6370'use strict'; 6371 6372var dialog = require('../dialog'); 6373 6374exports.initialize = initialize; 6375 6376function initialize() { 6377 dialog.open({ 6378 html: $('#dialog-content-gift-card-balance-inquiry').html(), 6379 options: { 6380 title: 'Gift Card Balance Check', 6381 dialogClass: 'gift-card-balance-inquiry', 6382 resizable: false, 6383 draggable: false 6384 } 6385 }); 6386} 6387 6388},{"../dialog":36}],22:[function(require,module,exports){ 6389'use strict'; 6390 6391var loadingIndicator = require('./LoadingIndicator'); 6392 6393exports.initialize = initialize; 6394 6395var options; 6396var dataBuffer; 6397var loadingIndicatorSettings = { 6398 IsLabelShown: false, 6399 CssClass: 'fullscreen',
6400 BackgroundColor: 'transparent' 6401}; 6402 6403function initialize(optionsParameter) { 6404 options = $.extend({ 6405 successCallback: null, 6406 errorCallback: null 6407 }, optionsParameter); 6408 dataBuffer = { 6409 initialized: false 6410 }; 6411 6412 $(document).off('click.GlobaleInitialize').on('click.GlobaleInitialize', '.country-selector', function(event) { 6413 if ($('div#globale-script-loader-data').length > 0 && !dataBuffer.initialized) { 6414 dataBuffer.initialized = true; 6415 event.preventDefault(); 6416 $('body').loading(loadingIndicatorSettings); 6417 $('body').append('<script type="text/javascript" id="globale-script-loader" src="' + Urls.Globale.ScriptLoader + '"></script>'); 6418 } 6419 }); 6420 6421 $(document).off('Globale.Initialized').on('Globale.Initialized', function(event) { 6422 if (dataBuffer.initialized && $('.pt_checkout_globale').length == 0) { 6423 dataBuffer.showShippingSwitcherInterval = setInterval(showShippingSwitcher, 250); 6424 } 6425 }); 6426} 6427 6428function showShippingSwitcher() { 6429 if (GlobalE && GlobalE.ShippingSwitcher && GlobalE.ShippingSwitcher.Show && typeof GlobalE.ShippingSwitcher.Show == 'function') { 6430 if ($('body').attr('loading')) { 6431 $('body').loading('destroy'); 6432 } 6433 clearInterval(dataBuffer.showShippingSwitcherInterval); 6434 GlobalE.ShippingSwitcher.Show(); 6435 } 6436} 6437},{"./LoadingIndicator":25}],23:[function(require,module,exports){ 6438'use strict'; 6439 6440exports.initialize = initialize; 6441 6442var ImageConstants; 6443var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 6444 6445var carouselVideo = require('./../CarouselVideo'); 6446 6447var singleImageSlickOptions; 6448var productThumbnailSlickOptions; 6449 6450var html = []; 6451var data = []; 6452var loaded = []; 6453var options; 6454 6455var $singleImageSlides; 6456var $thumbnailImageContainer; 6457var $thumbnailImageSlides; 6458 6459function initialize(params) { 6460 if (params) { 6461 options = params; 6462 } 6463 var $pdpMain = $('#pdpMain'); 6464 6465 if (pageContext.site === SiteConstants.SiteIds.CountryOutfittersUS) { 6466 ImageConstants = require('../../../../../app_storefront_countryoutfitters/cartridge/js/ImageConstants'); 6467 } else if (pageContext.isstoresite) { 6468 ImageConstants = require('../../../../../bootbarn_rsp/cartridge/js/ImageConstants'); 6469 } else { 6470 ImageConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ImageConstants'); 6471 } 6472 singleImageSlickOptions = ImageConstants.SlickSlider.Options.Single; 6473 productThumbnailSlickOptions = ImageConstants.SlickSlider.Options.Thumbnail; 6474 6475 $singleImageSlides = $('.slider-single-image .slides'); 6476 $thumbnailImageContainer = $('.product-thumbnails-container'); 6477 $thumbnailImageSlides = $thumbnailImageContainer.find('.slides'); 6478 6479 $pdpMain.off('click.Variant.Leaflet.Zoom.In').on('click.Variant.Leaflet.Zoom.In', '.custom.leaflet-control-zoom-in', function (e) { 6480 var $slides = $('.slider-single-image .slides'); 6481 var slick = $slides.slick('getSlick'); 6482 $slides.find('[data-slick-index="' + slick.currentSlide + '"] img.high-resolution').imgViewer2('getMap').zoomIn(); 6483 }); 6484 6485 $pdpMain.off('click.Variant.Leaflet.Zoom.Out').on('click.Variant.Leaflet.Zoom.Out', '.custom.leaflet-control-zoom-out', function (e) { 6486 var $slides = $('.slider-single-image .slides'); 6487 var slick = $slides.slick('getSlick'); 6488 $slides.find('[data-slick-index="' + slick.currentSlide + '"] img.high-resolution').imgViewer2('getMap').zoomOut(); 6489 }); 6490 6491 if (pageContext.site === SiteConstants.SiteIds.SheplersUS || pageContext.site === SiteConstants.SiteIds.BootBarnUS || pageContext.options.StoreUIVersion == '2024Redesign') { 6492 $(window).off('resize.PDP.Slider.Primary').on('resize.PDP.Slider.Primary', function (event) { 6493 if (data['mapResizeTimer']) { 6494 clearTimeout(data['mapResizeTimer']); 6495 } 6496 data['mapResizeTimer'] = setTimeout(mapResizeTimerHandler, 250); 6497 }); 6498 } 6499 6500 $singleImageSlides.on('init', function(event, slick) { 6501 // if (pageContext.site === SiteConstants.SiteIds.SheplersUS || pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 6502 var $initialSlide = $singleImageSlides.find('.slick-slide.slick-active'); 6503 data['singleImageSlidesInitialSlide'] = $initialSlide.attr('data-slick-index'); 6504 data['singleImageSlidesCurrentSlide'] = data['singleImageSlidesInitialSlide']; 6505 6506 initializeImageViewerOnSlide($initialSlide); 6507 // setTimeout(function(){resizeSliderToMatchSlide($initialSlide);}, 250); 6508 // } 6509 }); 6510 6511 $singleImageSlides.on('beforeChange', function(event, slick, currentSlide, nextSlide) { 6512 if (nextSlide != data['singleImageSlidesCurrentSlide']) { 6513 $thumbnailImageSlides.find('.slick-current').removeClass('slick-current'); 6514 $thumbnailImageSlides.find('.slide[data-slick-index="' + nextSlide + '"]').addClass('slick-current'); 6515 setThumbnailPageBySlide(nextSlide + 1); 6516 6517 // var $currentSlide = $singleImageSlides.find('[data-slick-index="' + currentSlide + '"]'); 6518 // removeImageViewerOnSlide($currentSlide); 6519 6520 var $nextSlide = $singleImageSlides.find('[data-slick-index="' + nextSlide + '"]'); 6521 // turn off zoom on video slide 6522 if (!$nextSlide.hasClass('carousel-video-slide')) { 6523 initializeImageViewerOnSlide($nextSlide); 6524 } 6525 // initializeSlidesToSide($nextSlide); 6526 6527 data['singleImageSlidesCurrentSlide'] = nextSlide; 6528 } 6529 }); 6530 6531 var singleImageSlickOptions = ImageConstants.SlickSlider.Options.Single; 6532 if (pageContext.site === SiteConstants.SiteIds.SheplersUS || pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 6533 singleImageSlickOptions.dots = true; 6534 singleImageSlickOptions.responsive[0].settings.arrows = false;
6535 } 6536 6537 $singleImageSlides.not('.slick-initialized').slick(singleImageSlickOptions); 6538 6539 var productThumbnailSlickOptions = ImageConstants.SlickSlider.Options.Thumbnail; 6540 if (pageContext.site === SiteConstants.SiteIds.SheplersUS || pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 6541 productThumbnailSlickOptions.vertical = true; 6542 } 6543 $thumbnailImageSlides.not('.slick-initialized').slick(productThumbnailSlickOptions); 6544 6545 data['thumbnailsCurrentPage'] = 1; 6546 data['thumbnailsMaximumSlide'] = $thumbnailImageSlides.find('.slide').length; 6547 data['thumbnailsMaximumPage'] = Math.ceil(data['thumbnailsMaximumSlide'] / productThumbnailSlickOptions.slidesToShow); 6548 6549 if (data['thumbnailsMaximumPage'] <= 1) { 6550 $thumbnailImageContainer.find('.product-thumbnails-arrow.next').addClass('disable'); 6551 } else { 6552 $thumbnailImageContainer.find('.product-thumbnails-arrow.next').removeClass('disable'); 6553 } 6554 6555 $('.product-thumbnails-container .product-thumbnails-arrow').on('click', function(event) { 6556 event.preventDefault(); 6557 6558 var $this = $(this); 6559 var pageDelta = 0; 6560 if ($this.hasClass('next')) { 6561 pageDelta = 1; 6562 } else if ($this.hasClass('previous')) { 6563 pageDelta = -1; 6564 } 6565 6566 setThumbnailPage(data['thumbnailsCurrentPage'] + pageDelta); 6567 }); 6568 6569 $('.product-thumbnails .slide a').on('click', function(event) { 6570 event.preventDefault(); 6571 6572 var $this = $(this); 6573 var $currentSlide = $this.closest('.slick-track').find('.slick-current'); 6574 var currentSlide = $currentSlide.data('slick-index'); 6575 var $nextSlide = $this.closest('.slide'); 6576 var nextSlide = $nextSlide.data('slick-index'); 6577 6578 $thumbnailImageSlides.find('.slick-current').removeClass('slick-current'); 6579 $nextSlide.addClass('slick-current'); 6580 $singleImageSlides.slick('slickGoTo', nextSlide); 6581 }); 6582 6583 carouselVideo.init(); 6584} 6585 6586function initializeSlidesToSide($slide) { 6587 var $leftSlide = $slide.prev(); 6588 if ($leftSlide.length > 0) { 6589 initializeImageViewerOnSlide($leftSlide); 6590 } 6591 6592 var $rightSlide = $slide.next(); 6593 if ($rightSlide.length > 0) { 6594 initializeImageViewerOnSlide($rightSlide); 6595 } 6596} 6597 6598function setThumbnailPageBySlide(selectedSlide) { 6599 if (selectedSlide >= 1 && selectedSlide <= data['thumbnailsMaximumSlide']) { 6600 setThumbnailPage(Math.ceil(selectedSlide / ImageConstants.SlickSlider.Options.Thumbnail.slidesToShow)); 6601 } 6602} 6603 6604function setThumbnailPage(selectedPage) { 6605 if (selectedPage >= 1 && selectedPage <= data['thumbnailsMaximumPage']) { 6606 if (pageContext.site === SiteConstants.SiteIds.CountryOutfittersUS) { 6607 var offsetX = $thumbnailImageSlides.find('.slick-track').offset().left - $thumbnailImageSlides.find('.slick-track .slide[data-slick-index="' + (selectedPage * ImageConstants.SlickSlider.Options.Thumbnail.slidesToShow - ImageConstants.SlickSlider.Options.Thumbnail.slidesToShow) + '"]').offset().left + 'px'; 6608 $thumbnailImageSlides.find('.slick-track').css('transform', 'translate3d(' + offsetX + ', 0, 0)'); 6609 } else { 6610 var offsetY = $thumbnailImageSlides.find('.slick-track').offset().top - $thumbnailImageSlides.find('.slick-track .slide[data-slick-index="' + (selectedPage * ImageConstants.SlickSlider.Options.Thumbnail.slidesToShow - ImageConstants.SlickSlider.Options.Thumbnail.slidesToShow) + '"]').offset().top + 'px'; 6611 $thumbnailImageSlides.find('.slick-track').css('transform', 'translate3d(0, ' + offsetY + ', 0)'); 6612 } 6613 6614 if (selectedPage > 1) { 6615 $thumbnailImageContainer.find('.product-thumbnails-arrow.previous').removeClass('disable'); 6616 } else { 6617 $thumbnailImageContainer.find('.product-thumbnails-arrow.previous').addClass('disable'); 6618 } 6619 6620 if (selectedPage < data['thumbnailsMaximumPage']) { 6621 $thumbnailImageContainer.find('.product-thumbnails-arrow.next').removeClass('disable'); 6622 } else { 6623 $thumbnailImageContainer.find('.product-thumbnails-arrow.next').addClass('disable'); 6624 } 6625 6626 data['thumbnailsCurrentPage'] = selectedPage; 6627 } 6628} 6629 6630function removeImageViewerOnSlide($slide) { 6631 if ($slide.find('img.high-resolution').length > 0) { 6632 $slide.find('img').removeClass('high-resolution').imgViewer2('destroy'); 6633 } 6634} 6635 6636function initializeImageViewerOnSlide($slideToInitialize) { 6637 if ($slideToInitialize.find('img.high-resolution').length == 0) { 6638 $slideToInitialize.find('img').attr('src', $slideToInitialize.find('a.zoomedImage').attr('href')).addClass('high-resolution').imgViewer2({ 6639 zoomMax: 4, 6640 dragable: false, 6641 onReady: function() { 6642 var imgViewer2 = this; 6643 var map = this.map; 6644 6645 imgViewer2.setZoom(1); 6646 if (map && map.tap) { 6647 map.tap.disable(); 6648 } 6649 if (map && map.dragging) { 6650 map.dragging.disable(); 6651 } 6652 6653 $(map.getContainer()).off('wheel').on('wheel', function(event) { 6654 var wheelScrollAnimationTargetDelta = 0; 6655 6656 if (data['wheelScrollAnimation']) { 6657 wheelScrollAnimationTargetDelta = data['wheelScrollAnimationTarget'] - $(window).scrollTop(); 6658 data['wheelScrollAnimation'].stop(); 6659 } 6660 6661 var zoomLevel = imgViewer2.getZoom(); 6662 var zoomMaximum = $slideToInitialize.find('img.high-resolution').imgViewer2('option', 'zoomMax'); 6663 if ((zoomLevel == 1 && event.originalEvent.deltaY > 0) || (zoomLevel > (zoomMaximum - 0.5)) && event.originalEvent.deltaY < 0) { 6664 data['wheelScrollAnimationTarget'] = $(window).scrollTop() + event.originalEvent.deltaY + wheelScrollAnimationTargetDelta; 6665 data['wheelScrollAnimation'] = $('html, body').animate({ 6666 scrollTop: data['wheelScrollAnimationTarget'] 6667 }, {
6668 duration: 'fast', 6669 complete: function() { 6670 data['wheelScrollAnimation'] = null; 6671 } 6672 }); 6673 } 6674 }); 6675 6676 map.on('zoom', function(event) { 6677 var zoomLevel = imgViewer2.getZoom(); 6678 6679 if (zoomLevel > 1.05) { 6680 $slideToInitialize.find('img.high-resolution').imgViewer2('option', 'dragable', true); 6681 6682 if (map && map.tap) { 6683 map.tap.enable(); 6684 } 6685 if (map && map.dragging) { 6686 map.dragging.enable(); 6687 } 6688 $('.slider-single-image .slides').slick('slickSetOption', 'draggable', false, true); 6689 $('.slider-single-image .slides').slick('slickSetOption', 'swipe', false, true); 6690 $('.slider-single-image .slides').slick('slickSetOption', 'touchMove', false, true); 6691 } else { 6692 $slideToInitialize.find('img.high-resolution').imgViewer2('option', 'dragable', false); 6693 6694 if (map && map.tap) { 6695 map.tap.disable(); 6696 } 6697 if (map && map.dragging) { 6698 map.dragging.disable(); 6699 } 6700 $('.slider-single-image .slides').slick('slickSetOption', 'draggable', true, true); 6701 $('.slider-single-image .slides').slick('slickSetOption', 'swipe', true, true); 6702 $('.slider-single-image .slides').slick('slickSetOption', 'touchMove', true, true); 6703 } 6704 }); 6705 } 6706 }); 6707 } else { 6708 var slideImageMap = $slideToInitialize.find('img.high-resolution').imgViewer2('getMap'); 6709 if (slideImageMap) { 6710 slideImageMap.invalidateSize(); 6711 } 6712 } 6713} 6714 6715function mapResizeTimerHandler() { 6716 if (data['singleImageSlidesInitialSlide'] != undefined) { 6717 var $initialSlide = $('.slider-single-image .slides').find('[data-slick-index="' + data['singleImageSlidesInitialSlide'] + '"]'); 6718 resizeSliderToMatchSlide($initialSlide); 6719 6720 var slick = $singleImageSlides.slick('getSlick'); 6721 var $currentSlide = $singleImageSlides.find('[data-slick-index="' + slick.currentSlide + '"]'); 6722 var currentSlideImageMap = $currentSlide.find('img.high-resolution').imgViewer2('getMap'); 6723 if (currentSlideImageMap) { 6724 currentSlideImageMap.invalidateSize(); 6725 } 6726 } 6727} 6728 6729function resizeSliderToMatchSlide($slide) { 6730 var $slideTrack = $slide.closest('.slick-track'); 6731 $slideTrack.css('height', 'auto'); 6732 6733 var $slideImage = $slide.find('.slide-image > img'); 6734 var slideImageHeight = $slide.height(); 6735 var slideImageWidth = $slide.width(); 6736 var slideAspectRatio = slideImageWidth / slideImageHeight; 6737 6738 $slideTrack.css('height', slideImageHeight); 6739 $slideTrack.find('.slick-slide').not($slide).each(function() { 6740 var $this = $(this); 6741 var $thisImage = $this.find('.slide-image > img'); 6742 var thisImageAspectRatio = $thisImage.width() / $thisImage.height(); 6743 6744 if ($thisImage.height() > slideImageHeight && thisImageAspectRatio <= slideAspectRatio) { 6745 $this.addClass('constrain-height'); 6746 } 6747 }); 6748} 6749},{"../../../../../app_storefront_countryoutfitters/cartridge/js/ImageConstants":106,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ImageConstants":116,"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../bootbarn_rsp/cartridge/js/ImageConstants":125,"./../CarouselVideo":16}],24:[function(require,module,exports){ 6750'use strict'; 6751 6752var carouselVideo = require('../CarouselVideo'); 6753 6754// Global vars 6755var options; 6756var isMobile = window.innerWidth <= 767; 6757 6758exports.initialize = initialize; 6759 6760function initialize(params) { 6761 if (params) { 6762 options = params; 6763 } 6764 var thumbGallerySwiper, largeSwiper, 6765 thumbGalleryBreakpoints = options && options.thumbGalleryBreakpoints ? options.thumbGalleryBreakpoints : null, 6766 thumbGalleryBreakpointSettings = thumbGalleryBreakpoints ? (isMobile ? thumbGalleryBreakpoints['0'] : thumbGalleryBreakpoints['768']) : null, 6767 enableThumbGalleryForCurrentBreakpoint = thumbGalleryBreakpointSettings && thumbGalleryBreakpointSettings.enabled, 6768 isThumbnailsElm = $('.thumbs-product-swiper').length > 0; 6769 6770 // Check to see if we have any thumbnails at all 6771 if (isThumbnailsElm) { 6772 // Initialize thumbnails gallery and assign instance to 'thumbGallerySwiper' 6773 if (enableThumbGalleryForCurrentBreakpoint) { 6774 thumbGallerySwiper = thumbGallerySwiperInit(options); 6775 // Thumbnail slider modifications - can only make mods after thumbs gallery slider has been initialized. 6776 // No default arrow navigation exists for thumbnails gallery in swiper, so we add our own. 6777 thumbGalleryNavigation(options, thumbGallerySwiper, thumbGalleryBreakpointSettings); 6778 if (isMobile) { 6779 $('.product-image-container-mobile').addClass('swiper-thumbs-mobile-edits'); 6780 } 6781 } else { 6782 $('.thumbs-product-swiper').addClass('d-none'); 6783 } 6784 // Initialize PDP main image swiper and pass in thumbnails gallery if it exists 6785 largeSwiper = largeSwiperInit(options, thumbGallerySwiper); 6786 } else { 6787 largeSwiper = largeSwiperInit(options, null); 6788 } 6789 6790 if (options.zoom) { 6791 $('#pdpMain').off('click.Variant.Swiper.Zoom.In').on('click.Variant.Swiper.Zoom.In', '.custom.leaflet-control-zoom-in', function (e) { 6792 largeSwiper.zoom.in(); 6793 }); 6794 6795 $('#pdpMain').off('click.Variant.Swiper.Zoom.Out').on('click.Variant.Swiper.Zoom.Out', '.custom.leaflet-control-zoom-out', function (e) { 6796 largeSwiper.zoom.out(); 6797 }); 6798 } 6799 6800 carouselVideo.init(); 6801} 6802 6803function thumbGallerySwiperInit(options) { 6804 // Thumbnails swiper options 6805 var thumbnailsSwiperOptions = { 6806 direction: isMobile ? 'horizontal' :'vertical', 6807 slidesPerView: 7, 6808 slidesPerGroup: 7, 6809 loop: false, 6810 slideToClickedSlide: true, 6811 allowTouchMove: true, 6812 a11y: { 6813 enabled: true, 6814 firstSlideMessage: 'This is the first slide', 6815 lastSlideMessage: 'This is the last slide' 6816 }, 6817 keyboard: { 6818 enabled: true, 6819 pageUpDown: true 6820 } 6821 }; 6822 6823 if (options.thumbGalleryScrollDirection) { 6824 thumbnailsSwiperOptions.direction = isMobile ? 'horizontal' : options.thumbGalleryScrollDirection; 6825 } 6826 6827 // Initiate thumbnails swiper 6828 return new Swiper ('.thumbs-product-swiper', thumbnailsSwiperOptions); 6829} 6830 6831function largeSwiperInit(options, thumbnailsSwiper) { 6832 var largeSwiperOptions; 6833 var mobileDots = options.breakpoints && options.breakpoints['0'] && options.breakpoints['0'].dots ? options.breakpoints['0'].dots : true; 6834 var desktopDots = options.breakpoints && options.breakpoints['768'] && options.breakpoints['768'].dots ? options.breakpoints['768'].dots : false;
6835 6836 // Large product swiper options 6837 largeSwiperOptions = { 6838 slidesPerView: 1, 6839 centeredSlides: true, 6840 loop: false, 6841 a11y: { 6842 enabled: true, 6843 firstSlideMessage: 'This is the first slide', 6844 lastSlideMessage: 'This is the last slide' 6845 }, 6846 keyboard: { 6847 enabled: true, 6848 pageUpDown: true 6849 }, 6850 breakpoints: { 6851 0: { 6852 pagination: { 6853 enabled: mobileDots, 6854 el: '.swiper-pagination', 6855 clickable: true 6856 } 6857 }, 6858 768: { 6859 pagination: { 6860 enabled: desktopDots, 6861 el: '.swiper-pagination', 6862 clickable: true 6863 } 6864 } 6865 } 6866 }; 6867 6868 if (desktopDots || mobileDots) { 6869 var modifierClass; 6870 if (!desktopDots && mobileDots) { 6871 modifierClass = 'swiper-paginated-mobile-'; 6872 } 6873 if (desktopDots && !mobileDots) { 6874 modifierClass = 'swiper-paginated-desktop-'; 6875 } 6876 if (desktopDots && mobileDots) { 6877 modifierClass = 'swiper-paginated-both-'; 6878 } 6879 if (modifierClass) { 6880 largeSwiperOptions.containerModifierClass = modifierClass; 6881 } 6882 } 6883 6884 if (options.zoom) { 6885 largeSwiperOptions.zoom = { 6886 maxRatio: 3, 6887 minRatio: 1 6888 } 6889 } 6890 6891 if (thumbnailsSwiper) { 6892 largeSwiperOptions.thumbs = { 6893 swiper: thumbnailsSwiper 6894 } 6895 } 6896 6897 // Initiate large product swiper 6898 return new Swiper ('.large-product-swiper', largeSwiperOptions); 6899} 6900 6901function thumbGalleryNavigation(options, swiperInstance, breakpointSettings) { 6902 var $swiperThumbnailsDomElement = $('.thumbs-product-swiper'); 6903 if (!$swiperThumbnailsDomElement || !swiperInstance || !breakpointSettings || $swiperThumbnailsDomElement.find('.swiper-slide').length < 8) { 6904 return; 6905 } else { 6906 var addNavigation = breakpointSettings ? (breakpointSettings.arrows ? breakpointSettings.arrows : false) : null, 6907 isVertical = $swiperThumbnailsDomElement.hasClass('swiper-vertical'), 6908 isHorizontal = $swiperThumbnailsDomElement.hasClass('swiper-horizontal'), 6909 thumbGallerySlides = $swiperThumbnailsDomElement.find('.swiper-slide'), 6910 thumbsDirectionClass = isVertical ? 'thumbs-vertical' : 'thumbs-horizontal', 6911 $thumbnailsNavigation = $('<div />', { 'class': 'thumbs-product-navigation' }), 6912 carets; 6913 6914 if (addNavigation) { 6915 if (isVertical) { 6916 carets = '<i class="fa-solid fa-angle-up d-none"></i><i class="fa-solid fa-angle-down"></i>'; 6917 } 6918 if (isHorizontal) { 6919 carets = '<i class="fa-solid fa-angle-left d-none"></i><i class="fa-solid fa-angle-right"></i>'; 6920 } 6921 $thumbnailsNavigation.html(carets).addClass(thumbsDirectionClass).insertBefore($swiperThumbnailsDomElement); 6922 var prevIcons = '.thumbs-product-navigation .fa-angle-up, .thumbs-product-navigation .fa-angle-left'; 6923 var nextIcons = '.thumbs-product-navigation .fa-angle-down, .thumbs-product-navigation .fa-angle-right'; 6924 $(document).on('click', prevIcons, function() { 6925 swiperInstance.slidePrev(500); 6926 var prevIconsFirstVisibleIndex = thumbGallerySlides.index($swiperThumbnailsDomElement.find('.swiper-slide-visible:first')); 6927 var prevIconsLastVisibleIndex = thumbGallerySlides.index($swiperThumbnailsDomElement.find('.swiper-slide-visible:last')); 6928 if (prevIconsFirstVisibleIndex == 0) { 6929 $(prevIcons).addClass('d-none'); 6930 } else { 6931 $(prevIcons).removeClass('d-none'); 6932 } 6933 if (prevIconsLastVisibleIndex < 7) { 6934 $(nextIcons).removeClass('d-none'); 6935 } else { 6936 $(nextIcons).addClass('d-none'); 6937 } 6938 }); 6939 $(document).on('click', nextIcons, function() { 6940 swiperInstance.slideNext(500); 6941 var nextIconsLastVisibleIndex = thumbGallerySlides.index($swiperThumbnailsDomElement.find('.swiper-slide-visible:last')); 6942 if (nextIconsLastVisibleIndex == (thumbGallerySlides.length - 1)) { 6943 $(nextIcons).addClass('d-none'); 6944 } else { 6945 $(nextIcons).removeClass('d-none'); 6946 } 6947 if (nextIconsLastVisibleIndex > 6) { 6948 $(prevIcons).removeClass('d-none'); 6949 } else { 6950 $(prevIcons).addClass('d-none'); 6951 } 6952 }); 6953 } 6954 } 6955} 6956 6957},{"../CarouselVideo":16}],25:[function(require,module,exports){ 6958'use strict'; 6959 6960var _ = require('lodash'); 6961var TemplateConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 6962 6963$.widget('bootbarn.loading', { 6964 options: { 6965 IsImageShown: true, 6966 IsLabelShown: true, 6967 Label: Resources.Loading.Loading, 6968 Content: '', 6969 CssClass: '',
6970 BackgroundColor: null 6971 }, 6972 6973 _create: function() { 6974 this.element.attr('loading', 'loading'); 6975 6976 var loadingIndicatorTemplate = _.template($('#template-loading-indicator').html(), TemplateConstants.Lodash.Settings); 6977 var $loadingIndicatorContainer = $(loadingIndicatorTemplate({ 6978 Content: this.options.Content 6979 })); 6980 var $loadingIndicator = $loadingIndicatorContainer.find('.loading-indicator'); 6981 $loadingIndicatorContainer.css('background-color', this.options.BackgroundColor ? this.options.BackgroundColor : this.element.css('background-color')); 6982 6983 if (this.options.CssClass) { 6984 $loadingIndicatorContainer.addClass(this.options.CssClass); 6985 } 6986 6987 if (this.options.IsLabelShown && !this.options.Content) { 6988 $loadingIndicator.addClass('label'); 6989 $loadingIndicator.attr('label', this.options.Label); 6990 } 6991 6992 if (this.options.IsImageShown) { 6993 $loadingIndicator.addClass('image'); 6994 } 6995 6996 $loadingIndicatorContainer.appendTo(this.element); 6997 }, 6998 6999 _destroy: function() { 7000 this.element.removeAttr('loading').find('.loading-indicator-container').remove(); 7001 } 7002}); 7003 7004},{"../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"lodash":133}],26:[function(require,module,exports){ 7005'use strict'; 7006 7007var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 7008 7009exports.Initialize = initialize; 7010exports.CloseNavigation = closeNavigation; 7011 7012var navDataBuffer = {}; 7013 7014function initialize() { 7015 var siteName = pageContext && pageContext.site ? pageContext.site : ''; 7016 var $navSecondary = $('.nav-secondary'); 7017 7018 $('.nav-secondary-dropdown').parent().addClass('has-dropdown'); 7019 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 7020 if (window.innerWidth < 1024) { 7021 $navSecondary.find('li#location').removeClass('has-dropdown'); 7022 } 7023 } 7024 7025 // BootBarn 2020 Full width nav drop down helper 7026 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 7027 // main nav hover effects 7028 $('html #navigation .has-dropdown').hover(function () { 7029 if ($('html').hasClass('size-desktop') || ($('html').hasClass('size-tablet') && window.innerWidth >= 1025)) { 7030 $(this).addClass('active'); 7031 $(this).closest('.top-banner').addClass('nav-active'); 7032 $('html').addClass('desktop-nav-active'); 7033 $('.nav-cover').show(); 7034 } 7035 }, function () { 7036 if ($('html').hasClass('size-desktop') || ($('html').hasClass('size-tablet') && window.innerWidth >= 1025)) { 7037 $('.nav-cover').hide(); 7038 $('.top-banner').removeClass('nav-active'); 7039 $('html').removeClass('desktop-nav-active'); 7040 $(this).removeClass('active'); 7041 } 7042 }); 7043 } 7044 7045 if ($navSecondary.find('#location-display-caption').length > 0 && $navSecondary.find('#location-display-caption').hasClass('no-store-to-display')) { 7046 if ($navSecondary.find('#location-display-caption').parents('#location').length > 0) { 7047 $navSecondary.find('#location-display-caption').parents('#location').removeClass('has-dropdown'); 7048 } 7049 } 7050 7051 // collision detection and adjustment for if menu off-screen 7052 // this is bound to document and .size-desktop to avoid iOS issue with first tap triggering mouseover instead of click - dan@redvan 7053 $(document).on('mouseover', 'html.size-desktop #navigation .has-dropdown > a', function(event) { 7054 navigationCollisionDetection($(event.currentTarget)); 7055 }); 7056 7057 $('body').on('click', '#navigation .has-dropdown > a, .nav-secondary .has-dropdown > a', function(event) { 7058 event.preventDefault(); 7059 7060 var $this = $(this); 7061 var $parent = $this.closest('.has-dropdown'); 7062 var $container = $parent.closest('#navigation, .nav-secondary'); 7063 7064 if ($('html').hasClass('size-mobile') && (siteName != SiteConstants.SiteIds.BootBarnUS || SitePreferences.MOBILE_NAV_REDESIGN != 'redesign')) { 7065 var $scrollingContainer = $('#navigation'); 7066 var offsetOpenMenu = 0; 7067 var scrollTopNew = 0; 7068 7069 if ($('#navigation .has-dropdown.active').first().length > 0 && ($('#navigation .has-dropdown.active').first().offset().top < $this.offset().top)) { 7070 offsetOpenMenu = $('#navigation .has-dropdown.active').first().find('.level-2, .nav-secondary-dropdown').outerHeight(); 7071 } 7072 7073 scrollTopNew = $this.offset().top - $scrollingContainer.offset().top + $scrollingContainer.scrollTop() - offsetOpenMenu; 7074 7075 $scrollingContainer.animate({ 7076 scrollTop: scrollTopNew 7077 }, 150); 7078 } 7079 7080 if (siteName === SiteConstants.SiteIds.SheplersUS && $('html').hasClass('size-tablet')) { 7081 if ($parent.hasClass('active')) { 7082 $parent.removeClass('active'); 7083 } else if (!$parent.hasClass('active')) { 7084 $('#navigation .has-dropdown').removeClass('active'); 7085 $parent.addClass('active'); 7086 } 7087 } 7088 7089 // Mobile nav functionality 7090 if ((!$('html').hasClass('size-desktop') && siteName !== SiteConstants.SiteIds.SheplersUS) || ($('html').hasClass('size-mobile') && siteName === SiteConstants.SiteIds.SheplersUS)) { 7091 7092 /* -- 2025 Nav Redesign -- */ 7093 if (siteName == SiteConstants.SiteIds.BootBarnUS && SitePreferences.MOBILE_NAV_REDESIGN == 'redesign') { 7094 // Close other header menus 7095 $('.top-banner .nav-secondary .has-dropdown .nav-secondary-dropdown').stop().animate({ left: '-100%' }, 'fast'); 7096 7097 // Show/hide sub-menu drawers 7098 if ($parent.hasClass('active')) { 7099 $parent.removeClass('active').find('.level-2, .nav-secondary-dropdown').stop().animate({ left: '-100%' }, 'fast').removeClass('submenu-active'); 7100 } else { 7101 $('#navigation .has-dropdown.active').removeClass('active').find('.level-2, .nav-secondary-dropdown').stop().animate({ left: '-100%' }, 'fast').removeClass('submenu-active'); 7102 $parent.addClass('active').find('.level-2, .nav-secondary-dropdown').stop().animate({ left: '0px' }, 'fast').addClass('submenu-active');
7103 $('.top-banner-inner').addClass('drawer-open'); 7104 $(document).trigger('Mobile.Redesign.AutoScroll'); 7105 } 7106 7107 // Toggle active-menu-level class on main navigation element 7108 if ($('#navigation .has-dropdown.active:not(.accordion)').length > 0) { 7109 $container.attr('active-menu-level', '1'); 7110 } else { 7111 $container.removeAttr('active-menu-level'); 7112 } 7113 7114 // Page classes based on menu open/close 7115 if ($('#navigation .has-dropdown.active').length > 0) { // Mobile 7116 $('.menu-toggle').addClass('active'); 7117 $('html').addClass('menu-active'); 7118 7119 if (siteName == SiteConstants.SiteIds.BootBarnUS && $('html').hasClass('size-tablet') && window.innerWidth == 1024) { 7120 $(this).closest('.top-banner').addClass('nav-active'); 7121 $('html').addClass('desktop-nav-active'); 7122 } 7123 } else if (window.innerWidth >= 1024) { // Desktop 7124 $('.menu-toggle').removeClass('active'); 7125 $('html').removeClass('menu-active'); 7126 7127 if (siteName == SiteConstants.SiteIds.BootBarnUS && $('html').hasClass('size-tablet') && window.innerWidth == 1024) { 7128 $(this).closest('.top-banner').removeClass('nav-active'); 7129 $('html').removeClass('desktop-nav-active'); 7130 } 7131 } 7132 /* -- Legacy Nav -- */ 7133 } else { 7134 //close other header menus 7135 if (siteName == SiteConstants.SiteIds.CountryOutfittersUS) { 7136 $('.top-banner-bar .nav-secondary .has-dropdown .nav-secondary-dropdown').hide(); 7137 } else { 7138 $('.top-banner-bar .nav-secondary .has-dropdown .nav-secondary-dropdown').stop().slideUp(150); 7139 } 7140 7141 if ($parent.hasClass('active')) { 7142 if (siteName == SiteConstants.SiteIds.CountryOutfittersUS) { 7143 $parent.removeClass('active').find('.level-2, .nav-secondary-dropdown').hide(); 7144 } else { 7145 $parent.removeClass('active').find('.level-2, .nav-secondary-dropdown').stop().slideUp(150); 7146 } 7147 } else { 7148 if (siteName == SiteConstants.SiteIds.CountryOutfittersUS) { 7149 $('#navigation .has-dropdown.active').removeClass('active').find('.level-2, .nav-secondary-dropdown').hide(); 7150 $parent.addClass('active').find('.level-2, .nav-secondary-dropdown').show(); 7151 } else { 7152 $('#navigation .has-dropdown.active').removeClass('active').find('.level-2, .nav-secondary-dropdown').stop().slideUp(150); 7153 $parent.addClass('active').find('.level-2, .nav-secondary-dropdown').stop().slideDown(150); 7154 } 7155 } 7156 7157 if ($('#navigation .has-dropdown.active:not(.accordion)').length > 0) { 7158 $container.attr('active-menu-level', '1'); 7159 } else { 7160 $container.removeAttr('active-menu-level'); 7161 } 7162 7163 if ($('#navigation .has-dropdown.active').length > 0) { 7164 $('.menu-toggle').addClass('active'); 7165 $('html').addClass('menu-active'); 7166 7167 if (siteName == SiteConstants.SiteIds.BootBarnUS && $('html').hasClass('size-tablet') && window.innerWidth == 1024) { 7168 $(this).closest('.top-banner').addClass('nav-active'); 7169 $('html').addClass('desktop-nav-active'); 7170 } 7171 } else if (window.innerWidth >= 1024) { 7172 $('.menu-toggle').removeClass('active'); 7173 $('html').removeClass('menu-active'); 7174 7175 if (siteName == SiteConstants.SiteIds.BootBarnUS && $('html').hasClass('size-tablet') && window.innerWidth == 1024) { 7176 $(this).closest('.top-banner').removeClass('nav-active'); 7177 $('html').removeClass('desktop-nav-active'); 7178 } 7179 } 7180 } 7181 } 7182 7183 if (!$('html').hasClass('size-mobile')) { 7184 navigationCollisionDetection($this); 7185 } 7186 7187 if (!$('html').hasClass('size-mobile') && $this.is('[id="location-display-caption"]') && siteName == SiteConstants.SiteIds.BootBarnUS) { 7188 window.location.href = $this.attr('href'); 7189 } else { 7190 return false; 7191 } 7192 }) 7193 .on('click', '.menu-toggle', function (event) { 7194 event.preventDefault(); 7195 7196 var $this = $(this); 7197 if ($('html').hasClass('size-mobile') || $('html').hasClass('size-tablet')) { 7198 var $html = $('html'); 7199 var $body = $('body'); 7200 var $container = $('#wrapper'); 7201 var headerWrapper = $('.header-wrapper'); 7202 var jumbotronContainer = headerWrapper.find('.jumbotron-ajax'); 7203 var logoAndLinks = headerWrapper.find('.logo-and-links-container'); 7204 var navFixedHeaderLimit = 800; 7205 var topBannerBar = headerWrapper.find('.top-banner-bar'); 7206 7207 var tobBannerInnerHeight = window.innerHeight - (parseFloat(topBannerBar.outerHeight()) + parseFloat(jumbotronContainer.outerHeight())); 7208 var navContainerHeight = window.innerHeight - (parseFloat(topBannerBar.outerHeight()) + parseFloat(logoAndLinks.outerHeight()) + parseFloat(jumbotronContainer.outerHeight()));
7209 7210 if (!$html.hasClass('menu-active')) { 7211 var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; 7212 navDataBuffer['wrapperScrollTop'] = scrollTop; 7213 navDataBuffer['wrapperMarginTop'] = $container.css('margin-top'); 7214 $container.attr('buffer-scrollTop', scrollTop); 7215 7216 $('.top-banner-inner').css('height', tobBannerInnerHeight); 7217 $('.top-banner-inner .navigation-and-jumbotron-container').css('height', navContainerHeight); 7218 7219 $html.addClass('menu-active'); 7220 $this.addClass('active'); 7221 $this.attr('aria-label', $this.attr('data-close')); // Change the aria-label on the menu-toggle for screen readers 7222 7223 if (window.innerWidth <= 1023 && scrollTop > navFixedHeaderLimit) { 7224 $('.header-wrapper').css('max-height', window.innerHeight); 7225 } 7226 $('.my-store-panel.mobile-only .show-store-search').focus(); 7227 } else { 7228 $html.removeClass('menu-active'); 7229 $this.removeClass('active'); 7230 $this.attr('aria-label', $this.attr('data-open')); // Change the aria-label on the menu-toggle for screen readers 7231 7232 if (navDataBuffer['wrapperScrollTop'] > 0) { 7233 document.body.scrollTop = document.documentElement.scrollTop = navDataBuffer['wrapperScrollTop']; 7234 } 7235 $('#navigation').removeAttr('active-menu-level'); 7236 7237 $('.top-banner-inner').css('height', ''); 7238 $('.top-banner-inner .navigation-and-jumbotron-container').css('height', 'auto'); 7239 7240 if (window.innerWidth <= 1023) { 7241 $('.header-wrapper').css('transform', 'none'); 7242 $('.header-wrapper').css('max-height', 'auto'); 7243 $('html, body').animate({ scrollTop: 0 }, 300); 7244 } 7245 7246 $(document).trigger('Mobile.Redesign.Reset', true); // Close other open menu drawers 7247 } 7248 $(document).trigger('Mobile.Redesign.ToggleEllipsis'); 7249 } 7250 7251 $('#navigation .level-2').hide(); 7252 $('#navigation .level-1').slideDown(); 7253 $('#navigation .active').removeClass('active'); 7254 $('.nav-secondary-dropdown').slideUp(150); 7255 7256 if ($('#mini-cart').hasClass('active')) { 7257 $('#mini-cart .mini-cart-link').removeClass('active'); 7258 $('#mini-cart').removeClass('active'); 7259 } 7260 7261 $(document).trigger('SearchBar.Hide'); 7262 7263 if ($('.second-mobnav').hasClass('active')) { 7264 $('.second-mobnav').removeClass('active') 7265 $('#second-mobnav').stop().slideUp(150); 7266 } 7267 }) 7268 .on('click.MenuItemToggle', '.menu-category li .menu-item-toggle', function (event) { 7269 event.preventDefault(); 7270 var $parentLi = $(e.target).closest('li'); 7271 $parentLi.siblings('li').removeClass('active').find('.menu-item-toggle').removeClass('fa-chevron-up active').addClass('fa-chevron-right'); 7272 $parentLi.toggleClass('active'); 7273 $(e.target).toggleClass('fa-chevron-right fa-chevron-up active'); 7274 }); 7275 7276 /* --- ADA Compliance: Keyboard main menu navigation --- 7277 * ARROW DOWN: Will open flyouts; focus goes to first clickable link in flyout 7278 * ARROW UP: Will close flyouts; focus returns to the parent of the flyout 7279 * TAB: A focus indicator will show up at time of each tab 7280 * ENTER: By default, hitting enter will engage any link that has current focus 7281 */ 7282 $(document).on('keyup', 'ul.menu-category li.has-dropdown', function (event) { 7283 // Down Arrow: If sub-menu has been opened... 7284 if (event.which === SiteConstants.KeyCodes.ArrowDown) { 7285 // BootBarn-specific nav features 7286 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 7287 $(this).trigger('mouseenter'); 7288 } 7289 $(this).find('ul').find('a[href!=""][href]').removeAttr('tabindex'); // Remove tabindex to allow natural tab flow of nav list 7290 var navLinksPopulated = $(this).find('.level-2 ul:first-of-type li:first-of-type').find('a').filter(function(x, navLink) { 7291 if ($(navLink).attr('href') && $(navLink).attr('href').trim().length > 0) { 7292 return navLink; 7293 } 7294 }); 7295 $(navLinksPopulated[0]).focus().addClass('focus-visible-indicator'); // Focus on first populated <a> within opened sub-menu and add visual indicator 7296 $(this).attr('aria-expanded','true').addClass('active keyboard-activated'); // Update expanded attribute and add keyboard class 7297 } 7298 // Up Arrow: If sub-menu has been closed... 7299 if (event.which === SiteConstants.KeyCodes.ArrowUp) { 7300 // BootBarn-specific nav features 7301 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 7302 $(this).trigger('mouseleave'); 7303 } 7304 $(this).find('ul').find('a[href!=""][href]').attr('tabindex','-1'); // Add negative tabindex to skip nested anchors 7305 $(this).attr('aria-expanded','false').removeClass('active keyboard-activated').focus().addClass('focus-visible-indicator'); // Update expanded attribute, remove keyboard class and reposition focus indicator 7306 } 7307 // Tab: Keyboard logic for nav tabbing... 7308 if (event.which === SiteConstants.KeyCodes.Tab) { 7309 if (!$(document.activeElement).hasClass('keyboard-activated') && ($(document.activeElement).closest('li.has-dropdown') && !$(document.activeElement).closest('li.has-dropdown').hasClass('keyboard-activated'))) { // If user tabbed away from activated sub-menu, close the sub-menu 7310 // BootBarn-specific nav features 7311 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 7312 $('li.has-dropdown.keyboard-activated').trigger('mouseleave'); 7313 } 7314 $('li.has-dropdown.keyboard-activated').find('ul').find('a[href!=""][href]').attr('tabindex','-1'); // Add negative tabindex to skip nested anchors when submenu is closed 7315 $('li.has-dropdown.keyboard-activated').attr('aria-expanded','false').removeClass('active keyboard-activated'); // Update expanded attribute and remove keyboard class 7316 } 7317 } 7318 }) 7319 .on('keydown', '.menu-toggle', function (event) { 7320 if (($('html').hasClass('size-mobile') || $('html').hasClass('size-tablet')) && event.which === SiteConstants.KeyCodes.Enter) { 7321 $('.my-store-panel.mobile-only a').focus().addClass('focus-visible-indicator'); 7322 } 7323 }) 7324 .on('mouseover', 'ul.menu-category li.has-dropdown', function (event) { 7325 $(this).attr('aria-expanded','true'); // CSS-expaned sub-menu occurs on hover. Use JS to update the expanded attribute for mouse users. 7326 }) 7327 .on('mousemove', function (event) { 7328 $('.focus-visible-indicator').removeClass('focus-visible-indicator'); 7329 if ($('li.has-dropdown.keyboard-activated')) { 7330 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 7331 $('li.has-dropdown.keyboard-activated').trigger('mouseleave'); 7332 } 7333 $('li.has-dropdown.keyboard-activated').find('ul').find('a[href!=""][href]').attr('tabindex','-1'); // Add negative tabindex to skip nested anchors when submenu is closed 7334 $('li.has-dropdown.keyboard-activated').attr('aria-expanded','false').removeClass('active keyboard-activated'); // Update expanded attribute and remove keyboard class 7335 } 7336 }); 7337 7338 /* --- Document Ready --- */ 7339 $(document).ready(function() { 7340 var adaSubMenuAttributes = { 7341 'role': 'menuitem', 7342 'aria-haspopup': 'true', 7343 'aria-expanded': 'false' 7344 } 7345 $('ul.menu-category.level-1 ul').attr('role','menu').attr('aria-label', function(n, x) { 7346 return $(this).closest('li').find('.has-sub-menu').first().html(); 7347 }); 7348 $('ul.menu-category.level-1').find('a').filter(function(n, navLink) { 7349 // Add role="none" to all list items, and then use specificity further down to override if needed 7350 $(navLink).parents('ul:not(.level-1)').find('li').attr('role','none'); 7351 // Add tabindex="-1" to all nested anchor tags to force tab order using arrow up and down events 7352 $(navLink).attr('tabindex','-1'); 7353 // IF the href attribute is not empty, apply ADA attributes correctly for a menuitem 7354 if ($(navLink).attr('href') && $(navLink).attr('href').trim().length > 0) { 7355 $(navLink).attr('role','menuitem'); 7356 // ELSE, if href attribute is empty, then ensure <a> gets skipped in keyboard navigation and screen readers 7357 } else { 7358 $(navLink).parent().attr(adaSubMenuAttributes); 7359 } 7360 }); 7361 7362 if (siteName == SiteConstants.SiteIds.BootBarnUS && SitePreferences.MOBILE_NAV_REDESIGN == 'redesign' && window.innerWidth <= 1024) { 7363 mobileSubMenus(); 7364 } 7365 }); 7366 7367 if (siteName == SiteConstants.SiteIds.BootBarnUS && SitePreferences.MOBILE_NAV_REDESIGN != 'redesign' && window.innerWidth == 1024) { 7368 $('body').on('click', function(e) { 7369 if ($('html').hasClass('size-tablet') && $('#navigation .has-dropdown').hasClass('active')) { 7370 if(e.target.id == '#navigation .has-dropdown') { 7371 return false;
7372 } 7373 if( $(e.target).closest('#navigation .has-dropdown').length > 0 ) { 7374 return false; 7375 } 7376 7377 $('#navigation .has-dropdown').removeClass('active'); 7378 $('html').removeClass('menu-active'); 7379 $('.header-wrapper .top-banner').removeClass('nav-active'); 7380 $('html').removeClass('desktop-nav-active'); 7381 } 7382 }); 7383 } 7384 7385 7386 $('body').on('click', '#navigation .level-3 > li > a.offer-primary', function(event) { 7387 if (siteName == SiteConstants.SiteIds.CountryOutfittersUS && $('html').hasClass('size-mobile')) { 7388 event.preventDefault(); 7389 7390 var $this = $(this); 7391 var $parent = $this.closest('li'); 7392 var $container = $parent.closest('.level-2'); 7393 7394 $container.find('.level-3 li').not($parent).removeClass('active'); 7395 $parent.toggleClass('active'); 7396 } 7397 }); 7398} 7399 7400function mobileSubMenus() { 7401 var $navigation = $('.nav-rd-mobile'); 7402 var $submenus = $navigation.find('div.level-2'); 7403 var $columns = $navigation.find('.navigation-column'); 7404 var $currentWrapper = null; 7405 7406 $columns.each(function () { 7407 var $col = $(this); 7408 var $headers = $col.find('h4.nav-list-header'); 7409 7410 if ($headers.length) { // If we have headers... 7411 $headers.each(function(i, header) { 7412 var $header = $(header); 7413 var $newAccordionSection = $('<div class="accordion-section"></div>'); // Create a new accordion section 7414 var $createNavColumn = $('<div class="navigation-column"></div>'); // Create new nav column 7415 var $list = $header.nextAll('ul').first(); // Submenu list of links 7416 $col.before($newAccordionSection); // Insert new accordion section before original nav column 7417 $createNavColumn.append($header, $list); // Append current header and <ul> to new nav column 7418 $newAccordionSection.append($createNavColumn); // Append new nav column to new accordion section 7419 $currentWrapper = $newAccordionSection; // Set the current accordion section to currentWrapper for appends of columns without headers 7420 }); 7421 $col.remove(); // Remove original nav column, now that it's empty 7422 } else if ($currentWrapper) { 7423 // Append to the current accordion section 7424 $currentWrapper.append($col); 7425 } 7426 }); 7427 7428 // Now loop through each section and set up the accordion behavior 7429 $('.accordion-section').each(function () { 7430 var $section = $(this); 7431 var $header = $section.find('h4.nav-list-header').first(); 7432 7433 // Wrap the content in a collapsible div 7434 var $content = $('<div class="accordion-content"></div>'); 7435 var $navigationColumns = $section.children('.navigation-column'); 7436 7437 $navigationColumns.appendTo($content); 7438 $section.append($header).append($content); 7439 }); 7440 7441 // Set up on-click for accordion headers 7442 $(document).on('click', 'h4.nav-list-header', function () { 7443 $(this).toggleClass('accordion-open'); 7444 $(this).siblings('.accordion-content').slideToggle(200); 7445 }); 7446 7447 $submenus.each(function() { 7448 var $sub = $(this);
7449 var $submenuContainer = $('<div class="submenu-container"></div>'); 7450 var $menuHeader = $('<div class="submenu-header"></div>'); 7451 var $returnButton = $('<button class="submenu-header-return" name="submenu-header-return"><span class="visually-hidden">Return to previous menu</span></button>'); 7452 var $submenuHeadline = $('<h3 class="submenu-header-text"></h3>') 7453 7454 $submenuHeadline.append($sub.siblings('a.has-sub-menu').text()); //Get text to fill H3 7455 $returnButton.append($submenuHeadline); //Append H3 to return button 7456 $menuHeader.append($returnButton); //Append the return button to header 7457 $sub.prepend($menuHeader); //Append header to div.level-2 7458 $submenuContainer.append($sub.contents()); //Remove submenu HTML and append it to the new submenu-container 7459 $sub.append($submenuContainer); //Append new submenu-container to div.level-2 7460 }); 7461 7462 // Set up on-click of submenu return buttons 7463 $(document).on('click', '.submenu-header-return', function () { 7464 var $this = $(this); 7465 $this.closest('.level-2, .stores-drawer').animate({ 7466 "left": "-100%" // Slide left 100% 7467 }, 500, "linear", function() { 7468 $('.top-banner-inner').removeClass('drawer-open'); 7469 $this.closest('li.has-dropdown').removeClass('active'); 7470 $('.store-location-drawer-open').removeClass('store-location-drawer-open'); 7471 $(document).trigger('Mobile.Redesign.Reset'); // Close other open menu drawers 7472 }).removeClass('submenu-active'); 7473 }); 7474} 7475 7476function navigationCollisionDetection($navigationEventTarget) { 7477 var $container = $navigationEventTarget.closest('.has-dropdown'); 7478 7479 $container.removeClass('collision-right collision-both'); 7480 7481 var $menu = $container.find('> .level-2'); 7482 7483 if ($menu.length > 0) { 7484 var menuLeft = $menu.offset().left; 7485 var menuRight = menuLeft + $menu.outerWidth(); 7486 7487 var $boundaryContainer = $('.top-banner-inner'); 7488 7489 if ($boundaryContainer.find('> .shell').length > 0) { 7490 $boundaryContainer = $boundaryContainer.find('> .shell'); 7491 } 7492 7493 var boundaryLeft = $boundaryContainer.offset().left; 7494 var boundaryRight = boundaryLeft + $boundaryContainer.outerWidth(); 7495 7496 var boundaryBuffer = 30; 7497 7498 if (menuRight >= (boundaryRight + boundaryBuffer)) { 7499 var buttonRight = $navigationEventTarget.offset().left + $navigationEventTarget.outerWidth(); 7500 7501 if (buttonRight - $menu.outerWidth() <= (boundaryLeft - boundaryBuffer)) { 7502 $container.addClass('collision-both'); 7503 } else { 7504 $container.addClass('collision-right'); 7505 } 7506 } 7507 } 7508} 7509 7510function closeNavigation() { 7511 $('html').removeClass('menu-active'); 7512 $('.menu-toggle').removeClass('active'); 7513 if (siteName == SiteConstants.SiteIds.BootBarnUS && SitePreferences.MOBILE_NAV_REDESIGN == 'redesign') { 7514 $('.nav-rd-mobile .has-dropdown.active').removeClass('active'); 7515 $('.nav-rd-mobile .submenu-active, .nav-rd-mobile .stores-drawer').css('left', '-100%'); 7516 $('.nav-rd-mobile .submenu-active, .nav-rd-mobile .accordion-content').hide(); 7517 } else { 7518 $('#navigation .has-dropdown.active').removeClass('active').find('.level-2, .nav-secondary-dropdown').stop().slideUp(150); 7519 } 7520} 7521},{"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120}],27:[function(require,module,exports){ 7522'use strict'; 7523 7524exports.initialize = initialize; 7525 7526function initialize() { 7527 $(document).off('click.HeaderBanner.Close').on('click.HeaderBanner.Close', '.header-banner .close', function(event) { 7528 event.preventDefault(); 7529 var $this = $(this); 7530 7531 var contentAssetId = $this.closest('[content-asset-id]').attr('content-asset-id'); 7532 if (contentAssetId) { 7533 acknowledge(contentAssetId, 'Yes', function() { 7534 $('.header-banner').hide(); 7535 $(document).trigger('app.resize'); 7536 }); 7537 } 7538 }); 7539 7540 $(document).off('click.NotificationYes').on('click.NotificationYes', '.notification .yes', function(event) { 7541 event.preventDefault(); 7542 var $this = $(this); 7543 var contentAssetId = $this.closest('[content-asset-id]').attr('content-asset-id'); 7544 acknowledge(contentAssetId, 'Yes'); 7545 $this.closest('.notification').addClass('hidden'); 7546 }); 7547 7548 $(document).off('click.NotificationNo').on('click.NotificationNo', '.notification .no', function(event) { 7549 event.preventDefault(); 7550 var $this = $(this); 7551 var contentAssetId = $this.closest('[content-asset-id]').attr('content-asset-id'); 7552 acknowledge(contentAssetId, 'No'); 7553 window.location.href = $this.attr('href'); 7554 }); 7555} 7556 7557function acknowledge(notification, acknowledgement, callbackSuccessParameter, callbackErrorParameter) { 7558 var callbackSuccess = callbackSuccessParameter || function() { }; 7559 var callbackError = callbackErrorParameter || function() { }; 7560 7561 if (notification && acknowledgement) { 7562 $.ajax({ 7563 url: Urls.Notification.Acknowledge, 7564 type: 'POST', 7565 data: { 7566 Notification: notification, 7567 Acknowledgement: acknowledgement 7568 }, 7569 dataType: 'json', 7570 success: callbackSuccess, 7571 error: callbackError 7572 }); 7573 } 7574} 7575},{}],28:[function(require,module,exports){ 7576'use strict'; 7577 7578var ValidationSettings = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 7579var ValidationRules = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 7580var ValidationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 7581 7582exports.initialize = initialize; 7583 7584function initialize($orderStatusForm) { 7585 $.validator.addMethod('orderNumber', ValidationHelper.ValidateOrderNumber, Resources.INVALID_ORDER_NUMBER); 7586 $.validator.addMethod('postalCode', ValidationHelper.ValidatePostalCode, Resources.INVALID_POSTAL_CODE); 7587 7588 var $orderStatusFormOrderNumber = $orderStatusForm.find('input[name$="_orderNumber"]'); 7589 var $orderStatusFormOrderEmail = $orderStatusForm.find('input[name$="_orderEmail"]'); 7590 var $orderStatusFormOrderPostalCode = $orderStatusForm.find('input[name$="_postalCode"]'); 7591 7592 var formValidator = $orderStatusForm.validate(ValidationSettings.Global); 7593 $orderStatusFormOrderNumber.rules('add', ValidationRules.OrderNumber); 7594 $orderStatusFormOrderEmail.rules('add', ValidationRules.Email); 7595 $orderStatusFormOrderPostalCode.rules('add', ValidationRules.PostalCode); 7596} 7597},{"../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124}],29:[function(require,module,exports){ 7598'use strict'; 7599 7600var Promise = require('promise'); 7601 7602exports.initialize = initialize; 7603exports.verify = verify; 7604 7605function initialize() { 7606 window.recaptchaLoaded = function () { 7607 $(document).trigger('Recaptcha.Loaded'); 7608 }; 7609 7610 window.emailSignup = function (token) { 7611 return verifyAndTriggerEvent(token, 'Global.EmailSignup'); 7612 }; 7613 7614 window.accountLogin = function (token) { 7615 return verifyAndTriggerEvent(token, 'Account.SubmitLogin'); 7616 }; 7617 7618 window.resetPassword = function (token) { 7619 return verifyAndTriggerEvent(token, 'Account.ResetPassword'); 7620 }; 7621 7622 window.submitOPCPayment = function (token) { 7623 return verifyAndTriggerEvent(token, 'Checkout.SubmitPayment'); 7624 }; 7625 7626 window.submitOPCPaymentPrivateLabel = function (token) { 7627 return verifyAndTriggerEvent(token, 'Checkout.SubmitPaymentPrivateLabel'); 7628 }; 7629 7630 window.submitRewardsCredit = function (token) { 7631 return verifyAndTriggerEvent(token, 'RewardsCredit.Add'); 7632 }; 7633 7634 window.submitLoyaltyCredit = function (token) { 7635 return verifyAndTriggerEvent(token, 'LoyaltyCredit.Add'); 7636 }; 7637 7638 window.submitGiftCard = function (token) { 7639 return verifyAndTriggerEvent(token, 'GiftCard.Apply'); 7640 }; 7641 7642 window.submitPaymentVoucher = function (token) { 7643 return verifyAndTriggerEvent(token, 'PaymentVoucher.Apply'); 7644 }; 7645}; 7646 7647function verifyAndTriggerEvent(token, eventName) { 7648 return $.when(verify(token)).then(function(data, textStatus, xmlHttpRequest) { 7649 return new Promise(function(resolve, reject) { 7650 if (data.success) { 7651 $(document).trigger(eventName); 7652 resolve(); 7653 } else { 7654 reject(); 7655 } 7656 }); 7657 }); 7658} 7659 7660function verify(token) { 7661 return $.ajax({ 7662 method: 'POST', 7663 url: Urls.verifyRecaptcha, 7664 contentType: 'application/json', 7665 data: JSON.stringify({ 7666 token: token 7667 }) 7668 }); 7669} 7670},{"promise":134}],30:[function(require,module,exports){ 7671'use strict'; 7672 7673var loadingIndicator = require('./LoadingIndicator'); 7674var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 7675 7676exports.initialize = initialize; 7677 7678var productTileContainers = []; 7679 7680function initialize(options) { 7681 if (options.Url && options.Containers && options.Containers.length > 0) { 7682 for (var index = 0; index < options.Containers.length; index++) { 7683 var container = options.Containers[index]; 7684 7685 productTileContainers[productTileContainers.length] = new ProductTileContainer(options.Url, container).load(); 7686 } 7687 } 7688} 7689 7690function ProductTileContainer(url, container, requestData) { 7691 var $container; 7692 var $containerBody; 7693 var dataBuffer = {}; 7694 var htmlBuffer = {}; 7695 var currentHtmlBufferCount = 0; 7696 var expectedHtmlBufferCount = 0; 7697 7698 this.load = function() { 7699 $container = $(container.Selector); 7700 $containerBody = $container.find('.accordion-body'); 7701 $container.hide(); 7702 7703 if ($container.length > 0) { 7704 $containerBody.loading(); 7705 $container.show(); 7706 7707 $.ajax({ 7708 method: 'POST', 7709 url: url, 7710 data: JSON.stringify({ 7711 addProductId: container.addProductId, 7712 excludeProductId: container.excludeProductId 7713 }), 7714 contentType: 'application/json', 7715 dataType: 'json', 7716 success: function(data) { 7717 if (data && data.ProductIds && data.ProductIds.length > 0) { 7718 dataBuffer = data; 7719 expectedHtmlBufferCount = data.ProductIds.length; 7720 7721 for (var index = 0; index < data.ProductIds.length; index++) { 7722 getProductHitTile(data.ProductIds[index]); 7723 } 7724 } else { 7725 $(document).trigger('RecentlyViewedProducts.Done', $container); 7726 $container.hide(); 7727 finish(); 7728 } 7729 }, 7730 error: function() { 7731 $container.hide(); 7732 finish(); 7733 } 7734 }); 7735 } else { 7736 $(document).trigger('RecentlyViewedProducts.Done', $container); 7737 } 7738 } 7739 7740 var getProductHitTile = function(productId) { 7741 var requestData = { 7742 pid: productId, 7743 showswatches: 'true', 7744 showpricing: 'true', 7745 showpromotion: 'true', 7746 showrating: 'true', 7747 showbadges: 'false', 7748 showaffirm: 'false', 7749 } 7750 7751 $.ajax({ 7752 method: 'GET', 7753 url: Urls.hitTile, 7754 data: requestData, 7755 dataType: 'html', 7756 success: function (data) { 7757 if (data) { 7758 htmlBuffer[productId] = '<li class="slide">' + data + '</li>'; 7759 } 7760 },
7761 complete: function () { 7762 currentHtmlBufferCount++; 7763 render(); 7764 } 7765 }); 7766 } 7767 7768 var render = function() { 7769 if (currentHtmlBufferCount == expectedHtmlBufferCount) { 7770 var html = ''; 7771 7772 for (var index = 0; index < dataBuffer.ProductIds.length; index++) { 7773 if (htmlBuffer[dataBuffer.ProductIds[index]]) { 7774 html += htmlBuffer[dataBuffer.ProductIds[index]]; 7775 } 7776 } 7777 7778 var $html = $(html); 7779 if (pageContext.site != SiteConstants.SiteIds.CountryOutfittersUS) { 7780 $html.find('.product-tile').addClass('product'); 7781 } 7782 $container.find('.slides').html($html); 7783 $container.find('.slider-products-primary').trigger('init-slider'); 7784 finish(); 7785 7786 if ('affirm' in window && 'ui' in affirm && 'refresh' in affirm.ui) { 7787 affirm.ui.refresh(); 7788 } 7789 } 7790 } 7791 7792 var finish = function() { 7793 $containerBody.loading('destroy'); 7794 $(document).trigger('RecentlyViewedProducts.Done', $container); 7795 $(document).trigger('Currency.Update', $container); 7796 } 7797} 7798},{"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"./LoadingIndicator":25}],31:[function(require,module,exports){ 7799'use strict'; 7800 7801var loadingIndicator = require('./LoadingIndicator'); 7802 7803exports.initialize = initialize; 7804 7805var recommendationsContainers = []; 7806 7807function initialize(options) { 7808 if (options.Url && options.Containers && options.Containers.length > 0) { 7809 for (var index = 0; index < options.Containers.length; index++) { 7810 recommendationsContainers[recommendationsContainers.length] = new RecommendationsContainer(options.Url, options.Containers[index]).load(); 7811 } 7812 } 7813} 7814 7815function RecommendationsContainer(url, container) { 7816 var $container; 7817 var $containerBody; 7818 var dataBuffer = {}; 7819 var htmlBuffer = {}; 7820 var currentHtmlBufferCount = 0; 7821 var expectedHtmlBufferCount = 0; 7822 7823 this.load = function() { 7824 $container = $(container.Selector); 7825 $containerBody = $container.find('.accordion-body'); 7826 7827 $container.hide(); 7828 7829 if ($container.length > 0 && container.ProductId && container.RelationType) { 7830 $containerBody.loading(); 7831 $container.show(); 7832 7833 var requestData = { 7834 'styles': container.ProductId, 7835 'relationtype': container.RelationType 7836 } 7837 7838 $.ajax({ 7839 method: 'GET', 7840 url: url, 7841 data: requestData, 7842 dataType: 'json', 7843 success: function(data) { 7844 if (data && data.products && data.products.length > 0) { 7845 dataBuffer = data; 7846 expectedHtmlBufferCount = data.products.length; 7847 7848 for (var index = 0; index < data.products.length; index++) { 7849 getProductHitTile((index + 1), data.products[index].productid); 7850 } 7851 } else { 7852 $container.hide(); 7853 finish(); 7854 } 7855 }, 7856 error: function() { 7857 $container.hide(); 7858 finish(); 7859 } 7860 }); 7861 } 7862 } 7863 7864 var getProductHitTile = function(position, productId) { 7865 var requestData = { 7866 'position': position, 7867 'pid': productId, 7868 'showswatches': 'true', 7869 'showpricing': 'true', 7870 'showpromotion': 'true', 7871 'showrating': 'true', 7872 'showbadges': 'false', 7873 'showaffirm': 'false', 7874 } 7875 7876 $.ajax({ 7877 method: 'GET', 7878 url: Urls.hitTile, 7879 data: requestData, 7880 dataType: 'html', 7881 success: function (data) { 7882 if (data) { 7883 htmlBuffer[productId] = '<li class="slide">' + data + '</li>'; 7884 } 7885 }, 7886 complete: function () { 7887 currentHtmlBufferCount++; 7888 render(); 7889 } 7890 }); 7891 } 7892 7893 var render = function() { 7894 if (currentHtmlBufferCount == expectedHtmlBufferCount) { 7895 var html = ''; 7896 7897 for (var index = 0; index < dataBuffer.products.length; index++) { 7898 if (htmlBuffer[dataBuffer.products[index].productid]) { 7899 html += htmlBuffer[dataBuffer.products[index].productid]; 7900 } 7901 } 7902 7903 var $html = $(html); 7904 $html.find('.product-tile').addClass('product'); 7905 7906 $container.find('.slides').html($html); 7907 $container.find('.slider-products-primary').trigger('init-slider'); 7908 finish(); 7909 7910 if ('affirm' in window && 'ui' in affirm && 'refresh' in affirm.ui) { 7911 affirm.ui.refresh(); 7912 } 7913 } 7914 } 7915 7916 var finish = function() { 7917 $containerBody.loading('destroy'); 7918 $(document).trigger('RelevantProductRecommendations.Done', $container); 7919 $(document).trigger('Currency.Update', $container); 7920 } 7921} 7922},{"./LoadingIndicator":25}],32:[function(require,module,exports){ 7923'use strict'; 7924 7925var _ = require('lodash'); 7926var TemplateConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 7927 7928exports.initialize = initialize; 7929exports.render = render; 7930 7931var data; 7932var loaded; 7933var options; 7934var $container; 7935 7936function initialize($containerObject, optionsObject) { 7937 if (Urls && Urls.getSameDayShippingCountdownData && Urls.getSameDayShippingCountdownContentSlot) { 7938 $container = $containerObject; 7939 options = optionsObject; 7940 data = {}; 7941 loaded = { 7942 ContentSlot: false, 7943 Data: false 7944 } 7945 7946 $(document).off('SameDayShippingCountdown.Update').on('SameDayShippingCountdown.Update', update); 7947 7948 $.ajax({ 7949 method: 'POST', 7950 url: Urls.getSameDayShippingCountdownData, 7951 dataType: 'json', 7952 success: function (response) { 7953 loaded.Data = true; 7954 data.Response = response; 7955 render(); 7956 } 7957 }); 7958 7959 $.ajax({ 7960 method: 'POST', 7961 url: Urls.getSameDayShippingCountdownContentSlot, 7962 dataType: 'html', 7963 success: function (html) { 7964 loaded.ContentSlot = true; 7965 data.Html = html; 7966 render(); 7967 } 7968 }); 7969 } 7970} 7971 7972function render() { 7973 if (loaded && loaded.ContentSlot && loaded.Data && data) { 7974 var countdownText = ''; 7975 7976 if (data.Response && data.Response.TimeLeft) { 7977 if (data.Response.TimeLeft.Hours > 0) { 7978 countdownText += data.Response.TimeLeft.Hours + ' ' + (data.Response.TimeLeft.Hours > 1 ? Resources.HOURS_ABBREVIATED : Resources.HOUR_ABBREVIATED); 7979 } 7980 7981 if (data.Response.TimeLeft.Minutes > 0) { 7982 if (countdownText != '') { 7983 countdownText += ' '; 7984 } 7985 7986 countdownText += data.Response.TimeLeft.Minutes + ' ' + (data.Response.TimeLeft.Minutes > 1 ? Resources.MINUTES_ABBREVIATED : Resources.MINUTE_ABBREVIATED); 7987 } 7988 } 7989 7990 if (data.Html) { 7991 $container.html(data.Html).find('input[name="initTime"]').remove(); 7992 } 7993 7994 if (countdownText) { 7995 $container.html(_.template($container.html(), TemplateConstants.Lodash.Settings)({ 7996 countdown: countdownText 7997 })); 7998 7999 update(); 8000 } else { 8001 $(document).off('SameDayShippingCountdown.Update'); 8002 } 8003 } 8004}; 8005
8006function update() { 8007 if ($container.html().replace(/<!--([^\d]*)-->/g, '').trim().length > 0) { 8008 var $selectedVariation = $('.product-variations .attribute-size .select-text [same-day-shipping]'); 8009 8010 if ($selectedVariation.length > 0) { 8011 if ($selectedVariation.attr('same-day-shipping').toLowerCase() == 'true') { 8012 $container.show(); 8013 } else { 8014 $container.hide(); 8015 } 8016 } else if (parseFloat(options.percentageOfVariantsFromWarehouse) >= parseFloat(options.sameDayShippingWindowWarehousePercentage)) { 8017 $container.show(); 8018 } else { 8019 $container.hide(); 8020 } 8021 } 8022} 8023},{"../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"lodash":133}],33:[function(require,module,exports){ 8024'use strict'; 8025 8026var dialog = require('./dialog'); 8027 8028/** 8029 * @function cookieprivacy Used to display/control the scrim containing the cookie privacy code 8030 **/ 8031module.exports = function () { 8032 /** 8033 * If we have not accepted cookies AND we're not on the Privacy Policy page, then show the notification 8034 * NOTE: You will probably want to adjust the Privacy Page test to match your site's specific privacy / cookie page 8035 */ 8036 if (SitePreferences.COOKIE_HINT === true && document.cookie.indexOf('dw_cookies_accepted') < 0) { 8037 // check for privacy policy page 8038 if ($('.privacy-policy').length === 0) { 8039 dialog.open({ 8040 url: Urls.cookieHint, 8041 options: { 8042 closeOnEscape: false, 8043 dialogClass: 'no-close', 8044 buttons: [{ 8045 text: Resources.I_AGREE, 8046 click: function () { 8047 $(this).dialog('close'); 8048 enableCookies(); 8049 } 8050 }] 8051 } 8052 }); 8053 } 8054 } else { 8055 // Otherwise, we don't need to show the asset, just enable the cookies 8056 enableCookies(); 8057 } 8058 8059 function enableCookies() { 8060 if (document.cookie.indexOf('dw=1') < 0) { 8061 document.cookie = 'dw=1; path=/'; 8062 } 8063 if (document.cookie.indexOf('dw_cookies_accepted') < 0) { 8064 document.cookie = 'dw_cookies_accepted=1; path=/'; 8065 } 8066 } 8067}; 8068 8069},{"./dialog":36}],34:[function(require,module,exports){ 8070'use strict'; 8071 8072exports.init = function init () { 8073 8074 $('.countdown-wrapper').each(function() { 8075 var $this = $(this), 8076 countdownStr = $this.data('countdown-date'), 8077 countdownDate = new Date(countdownStr); 8078 8079 var ts = countdown(new Date(), countdownDate, countdown.DAYS | countdown.HOURS | countdown.MINUTES); 8080 var showCountdown = ts.value > 0; 8081 8082 if (showCountdown) { 8083 $this.find('.countdown-text').text(ts.toString()); 8084 } 8085 8086 8087 }); 8088 8089}; 8090 8091},{}],35:[function(require,module,exports){ 8092'use strict'; 8093 8094exports.init = function init () { 8095 $('.country-selector .current-country').on('click', function () { 8096 $('.country-selector .selector').toggleClass('active'); 8097 $(this).toggleClass('selector-active'); 8098 }); 8099}; 8100 8101},{}],36:[function(require,module,exports){ 8102'use strict'; 8103 8104var ajax = require('./ajax'), 8105 util = require('./util'), 8106 _ = require('lodash'), 8107 imagesLoaded = require('imagesloaded'); 8108 8109var dialog = { 8110 /** 8111 * @function 8112 * @description Appends a dialog to a given container (target) 8113 * @param {Object} params params.target can be an id selector or an jquery object 8114 */ 8115 create: function (params) { 8116 var $target, id; 8117 8118 if (_.isString(params.target)) { 8119 if (params.target.charAt(0) === '#') { 8120 $target = $(params.target); 8121 // if no element found, create one 8122 if ($target.length === 0) { 8123 id = params.target.substr(1); 8124 $target = $('<div>').attr('id', id).addClass('dialog-content').appendTo('body'); 8125 } 8126 } 8127 } else if (params.target instanceof jQuery) { 8128 $target = params.target; 8129 } else if ($('#dialog-container').length > 0) { 8130 $target = $('#dialog-container'); 8131 } else {
8132 $target = $('<div id="dialog-container"/>').appendTo('body'); 8133 } 8134 8135 if ((params.options != undefined && params.options != null) && (params.options.title == undefined || ('title' in params.options && params.options.title.length == 0))) { 8136 params.options.dialogClass += ' ui-dialog-title-collapse'; 8137 } 8138 8139 // create the dialog 8140 this.$container = $target; 8141 this.$container.dialog(_.merge({}, this.settings, params.options || {})); 8142 8143 /* --- BOOT-5386 --- 8144 * This is a workaround for a known jquery Dialog UI bug with the maxWidth option. By setting the Dialog width option to 100% and setting the CSS max-width 8145 * to 800px, this allows the dialogs to be responsive width. This fix is necessary to create responsive Dialogs for smaller screens, but also be backwards 8146 * compatible with existing dialogs on the site that have been previously set to the default size of 800px. 8147 * https://stackoverflow.com/questions/16471890/responsive-jquery-ui-dialog-and-a-fix-for-maxwidth-bug 8148 */ 8149 var maxWidth = params.options != undefined && params.options != null && 'maxWidth' in params.options && params.options.maxWidth ? params.options.maxWidth : "800px"; 8150 this.$container.parent().css("max-width", maxWidth); 8151 8152 // Adding keyboard support for Enter key on close button 8153 this.$container.find(".ui-dialog-titlebar-close").on("keydown", function (e) { 8154 if (e.key === "Enter") { 8155 e.preventDefault(); 8156 $(this).trigger("click"); 8157 } 8158 }); 8159 }, 8160 /** 8161 * @function 8162 * @description Opens a dialog using the given url (params.url) or html (params.html) 8163 * @param {Object} params 8164 * @param {Object} params.url should contain the url 8165 * @param {String} params.html contains the html of the dialog content 8166 */ 8167 open: function (params) { 8168 if (this.$container && this.$container.closest('.ui-dialog-close-on-retrigger').length && this.$container.dialog('isOpen')) { 8169 this.close(); 8170 return; 8171 } 8172 // close any open dialog 8173 this.close(); 8174 this.create(params); 8175 this.replace(params); 8176 }, 8177 /** 8178 * @description populate the dialog with html content, then open it 8179 **/ 8180 openWithContent: function (params) { 8181 var content, position, callback; 8182 8183 if (!this.$container) { return; } 8184 content = params.content || params.html; 8185 if (!content) { return; } 8186 this.$container.empty().html(content); 8187 if (!this.$container.dialog('isOpen')) { 8188 this.$container.dialog('open'); 8189 } 8190 8191 if (params.options) { 8192 position = params.options.position; 8193 } 8194 if (!position) { 8195 position = this.settings.position; 8196 } 8197 imagesLoaded(this.$container).on('done', function () { 8198 this.$container.dialog('option', 'position', position); 8199 }.bind(this)); 8200 8201 callback = (typeof params.callback === 'function') ? params.callback : function () {}; 8202 callback(); 8203 }, 8204 /** 8205 * @description Replace the content of current dialog 8206 * @param {object} params 8207 * @param {string} params.url - If the url property is provided, an ajax call is performed to get the content to replace 8208 * @param {string} params.html - If no url property is provided, use html provided to replace 8209 */ 8210 replace: function (params) { 8211 if (!this.$container) { 8212 return; 8213 } 8214 if (params.url) { 8215 params.url = util.appendParamToURL(params.url, 'format', 'ajax'); 8216 ajax.load({ 8217 url: params.url, 8218 data: params.data, 8219 callback: function (response) { 8220 params.content = response; 8221 this.openWithContent(params); 8222 }.bind(this) 8223 }); 8224 } else if (params.html) { 8225 this.openWithContent(params); 8226 } 8227 }, 8228 /** 8229 * @function 8230 * @description Closes the dialog 8231 */ 8232 close: function () { 8233 if (!this.$container || !this.$container.dialog("instance") || this.$container.find('[data-multi-layered="true"]').length) { 8234 return; 8235 } 8236 this.$container.dialog('close'); 8237 }, 8238 /** 8239 * @function
8240 * @description Submits the dialog form with the given action 8241 * @param {String} The action which will be triggered upon form submit 8242 */ 8243 submit: function (action, callback) { 8244 var $form = this.$container.find('form:first'); 8245 // set the action 8246 $('<input/>').attr({ 8247 name: action, 8248 type: 'hidden' 8249 }).appendTo($form); 8250 // serialize the form and get the post url 8251 var data = $form.serialize(); 8252 var url = $form.attr('action'); 8253 // make sure the server knows this is an ajax request 8254 if (data.indexOf('ajax') === -1) { 8255 data += '&format=ajax'; 8256 } 8257 // post the data and replace current content with response content 8258 $.ajax({ 8259 type: 'POST', 8260 url: url, 8261 data: data, 8262 dataType: 'html', 8263 success: function (html) { 8264 this.$container.html(html); 8265 if (callback) { 8266 callback(); 8267 } 8268 }.bind(this), 8269 failure: function () { 8270 window.alert(Resources.SERVER_ERROR); 8271 } 8272 }); 8273 }, 8274 exists: function () { 8275 return this.$container && (this.$container.length > 0); 8276 }, 8277 isActive: function () { 8278 return this.exists() && (this.$container.children.length > 0); 8279 }, 8280 settings: { 8281 autoOpen: false, 8282 height: 'auto', 8283 modal: true, 8284 overlay: { 8285 opacity: 0.5, 8286 background: 'black' 8287 }, 8288 resizable: false, 8289 title: '', 8290 width: '100%', 8291 open: function(event, ui) { 8292 var $dialog = $(this); 8293 if ($dialog.closest('.ui-dialog-outer-click-close').length) { 8294 setTimeout(() => { 8295 $dialog.off('outside.element.clicked'); 8296 $dialog.on('outside.element.clicked', function () { 8297 $dialog.dialog('close'); 8298 $dialog.off('outside.element.clicked'); 8299 }); 8300 }, 0); 8301 } 8302 $dialog.parent().addClass('ui-dialog-open'); 8303 $('body').addClass('modal-open'); 8304 }, 8305 close: function () { 8306 var $dialog = $(this); 8307 $dialog.parent().removeClass('ui-dialog-open'); 8308 $dialog.dialog('close'); 8309 $dialog.off('outside.element.clicked'); 8310 $('body').removeClass('modal-open'); 8311 }, 8312 position: { 8313 my: 'center', 8314 at: 'center', 8315 of: window, 8316 collision: 'flipfit' 8317 } 8318 } 8319}; 8320 8321module.exports = dialog; 8322 8323},{"./ajax":3,"./util":102,"imagesloaded":132,"lodash":133}],37:[function(require,module,exports){ 8324'use strict'; 8325 8326var _ = require('lodash'), 8327 dialog = require('./dialog'); 8328 8329var $dialogContent, 8330 state = {}, 8331 ready = {}, 8332 templates = {}, 8333 html = {}; 8334 8335var templateSettings = { interpolate: /{{([\s\S]+?)}}/g }; 8336 8337function initialize(options) { 8338 state['options'] = options || {}; 8339 8340 loadTemplates(); 8341 loadStores(); 8342 loadStates(); 8343 8344 openDialog(); 8345} 8346 8347function openDialog() { 8348 ready['dialog'] = false; 8349 8350 dialog.open({ 8351 html: '<div class="dialog-loading"></div>', 8352 options: { 8353 title: Resources.FIND_MORE_STORES, 8354 dialogClass: 'dialog-find-more-stores', 8355 resizable: false, 8356 draggable: false, 8357 open: function() { 8358 $dialogContent = $(this); 8359 ready['dialog'] = true; 8360 8361 events(); 8362 render(); 8363 } 8364 } 8365 }); 8366} 8367 8368function events() { 8369 $dialogContent.off('click.findMoreStores.go').on('click.findMoreStores.go', '.search button', function () { 8370 loadStores(true); 8371 }); 8372 8373 $dialogContent.off('click.findMoreStores.submit').on('click.findMoreStores.submit', '.submit', function () { 8374 var selectedStore = $dialogContent.find('.stores-list input:checked').val(); 8375 8376 if (selectedStore) { 8377 $(document).trigger('opc.SetShippingAddress', state['stores'].addresses[selectedStore]); 8378 dialog.close(); 8379 } 8380 }); 8381} 8382 8383function loadStates() { 8384 ready['states'] = false; 8385 8386 $.ajax({ method: 'POST', url: Urls.getCountryStates, data: 'countryCode=US', dataType: 'json', success: function (data) { 8387 state['states'] = JSON.parse(data.statesList); 8388 ready['states'] = true; 8389 8390 render(); 8391 }}); 8392} 8393
8394function renderStates() { 8395 html['states'] = '<option class="placeholder"></option>'; 8396 8397 for (var stateElement in state['states']) { 8398 var stateOption = state.states[stateElement]; 8399 8400 html['states'] += '<option value="' + stateOption.label + '">' + stateOption.label + '</option>'; 8401 } 8402 8403 $dialogContent.find('select[name="StateCode"]').html(html['states']); 8404} 8405 8406function loadStores(update) { 8407 ready['stores'] = false; 8408 8409 var payload = {}; 8410 8411 if ($dialogContent) { 8412 payload.PostalCode = $dialogContent.find('.search [name="PostalCode"]').val(); 8413 payload.StateCode = $dialogContent.find('.search [name="StateCode"]').val(); 8414 } 8415 8416 payload.storeQuery = state.options['storeQuery'] ? state.options['storeQuery'] : {}; 8417 8418 $.ajax({ method: 'POST', url: Urls.getMoreStoresAddressList, data: JSON.stringify(payload), contentType: 'application/json', dataType: 'json', success: function (data) { 8419 state['stores'] = data; 8420 ready['stores'] = true; 8421 8422 if (update) { 8423 renderStores(); 8424 } else { 8425 render(); 8426 } 8427 }}); 8428} 8429 8430function renderStores() { 8431 html['stores'] = ''; 8432 8433 if (state['stores'].addresses.length > 0) { 8434 var index = 0; 8435 for (var storeAddressesElement in state['stores'].addresses) { 8436 var storeAddress = state['stores'].addresses[storeAddressesElement]; 8437 8438 var streetAddress = storeAddress.address1; 8439 if (storeAddress.address2) { 8440 streetAddress += storeAddress.address2; 8441 } 8442 8443 html['stores'] += templates['location']({ 8444 id: index, 8445 name: storeAddress.fullName + ' ' + storeAddress.lastName, 8446 address: streetAddress, 8447 city: storeAddress.city, 8448 state: storeAddress.stateCode, 8449 postal: storeAddress.postalCode, 8450 phone: storeAddress.phone 8451 }); 8452 8453 index++; 8454 } 8455 8456 $dialogContent.find('.no-results').hide(); 8457 $dialogContent.find('.stores-list').html(html['stores']).show(); 8458 } else { 8459 $dialogContent.find('.no-results').show(); 8460 $dialogContent.find('.stores-list').hide(); 8461 } 8462 8463 8464} 8465 8466function loadTemplates() { 8467 templates = {}; 8468 8469 $.ajax({ method: 'POST', url: Urls.getMoreStoresDialogTemplate, dataType: 'html', success: function (data) { 8470 templates['dialog'] = _.template(data, templateSettings); 8471 render(); 8472 }}); 8473 8474 $.ajax({ method: 'POST', url: Urls.getMoreStoresLocationTemplate, dataType: 'html', success: function (data) { 8475 templates['location'] = _.template(data, templateSettings); 8476 render(); 8477 }}); 8478} 8479 8480function render(update) { 8481 if (ready['dialog'] && ready['stores'] && ready['states'] && templates['dialog'] && templates['location']) { 8482 $dialogContent.html(templates['dialog']()); 8483 8484 if (state.options && state.options.view) { 8485 $dialogContent.attr('view', state.options.view); 8486 } else { 8487 $dialogContent.removeAttr('view'); 8488 } 8489 8490 renderStores(); 8491 renderStates(); 8492 } 8493} 8494 8495exports.initialize = initialize; 8496},{"./dialog":36,"lodash":133}],38:[function(require,module,exports){ 8497'use strict'; 8498 8499var ajax = require('./ajax'), 8500 util = require('./util'); 8501/** 8502 * @function 8503 * @description Load details to a given gift certificate 8504 * @param {String} id The ID of the gift certificate 8505 * @param {Function} callback A function to called 8506 */ 8507exports.checkBalance = function (id, callback) { 8508 // load gift certificate details 8509 var url = util.appendParamToURL(Urls.giftCardCheckBalance, 'giftCertificateID', id); 8510 8511 ajax.getJson({ 8512 url: url, 8513 callback: callback 8514 }); 8515}; 8516 8517},{"./ajax":3,"./util":102}],39:[function(require,module,exports){ 8518'use strict'; 8519 8520var ajax = require('./ajax'), 8521 minicart = require('./minicart'), 8522 util = require('./util'); 8523 8524var setAddToCartHandler = function (e) { 8525 e.preventDefault(); 8526 var form = $(this).closest('form'); 8527 8528 var options = { 8529 url: util.ajaxUrl(form.attr('action')), 8530 method: 'POST', 8531 cache: false, 8532 data: form.serialize() 8533 }; 8534 $.ajax(options).done(function (response) { 8535 if (response.success) { 8536 ajax.load({ 8537 url: Urls.minicartGC, 8538 data: {lineItemId: response.result.lineItemId}, 8539 callback: function (response) { 8540 minicart.show(response); 8541 form.find('input,textarea').val(''); 8542 } 8543 }); 8544 } else { 8545 form.find('span.error').hide(); 8546 for (var id in response.errors.FormErrors) { 8547 var $errorEl = $('#' + id).addClass('error').removeClass('valid').next('.error'); 8548 if (!$errorEl || $errorEl.length === 0) { 8549 $errorEl = $('<span for="' + id + '" generated="true" class="error" style=""></span>'); 8550 $('#' + id).after($errorEl); 8551 } 8552 $errorEl.text(response.errors.FormErrors[id].replace(/\\'/g, '\'')).show(); 8553 } 8554 } 8555 }).fail(function (xhr, textStatus) { 8556 // failed 8557 if (textStatus === 'parsererror') { 8558 window.alert(Resources.BAD_RESPONSE); 8559 } else { 8560 window.alert(Resources.SERVER_CONNECTION_ERROR); 8561 } 8562 }); 8563}; 8564 8565exports.init = function () { 8566 $('#AddToBasketButton').on('click', setAddToCartHandler); 8567}; 8568 8569},{"./ajax":3,"./minicart":45,"./util":102}],40:[function(require,module,exports){ 8570'use strict'; 8571 8572var giftCardBalanceInquiryComponent = require('../components/GiftCardBalanceInquiryComponent'); 8573 8574exports.initializeAllFoundComponents = initializeAllFoundComponents; 8575 8576function initializeAllFoundComponents($containerParameter) { 8577 var $container = $containerParameter || $(document); 8578 8579 var $balanceInquiryComponents = $container.find('.gift-card-balance-inquiry-component'); 8580 if ($balanceInquiryComponents.length > 0) { 8581 $balanceInquiryComponents.each(function() { 8582 giftCardBalanceInquiryComponent.initialize($(this).parent()); 8583 }); 8584 } 8585} 8586},{"../components/GiftCardBalanceInquiryComponent":20}],41:[function(require,module,exports){ 8587'use strict'; 8588// jQuery extensions 8589 8590module.exports = function () { 8591 // params 8592 // toggleClass - required 8593 // triggerSelector - optional. the selector for the element that triggers the event handler. defaults to the child elements of the list. 8594 // eventName - optional. defaults to 'click' 8595 $.fn.toggledList = function (options) { 8596 if (!options.toggleClass) { return this; } 8597 var list = this; 8598 return list.on(options.eventName || 'click', options.triggerSelector || list.children(), function (e) { 8599 e.preventDefault(); 8600 var classTarget = options.triggerSelector ? $(this).parent() : $(this); 8601 classTarget.toggleClass(options.toggleClass); 8602 // execute callback if exists 8603 if (options.callback) {options.callback();} 8604 }); 8605 }; 8606 8607 $.fn.syncHeight = function () { 8608 this.height('auto'); 8609 var arr = $.makeArray(this); 8610 arr.sort(function (a, b) { 8611 return $(a).height() - $(b).height(); 8612 }); 8613 return this.height($(arr[arr.length - 1]).height()); 8614 }; 8615 8616 $.fn.syncHeightToMinimum = function () { 8617 this.height('auto'); 8618 var arr = $.makeArray(this); 8619 arr.sort(function (a, b) { 8620 return $(a).height() - $(b).height(); 8621 }); 8622 return this.height($(arr[0]).height()); 8623 }; 8624 8625 $.fn.syncHeightToAverage = function () { 8626 this.height('auto'); 8627 var arr = $.makeArray(this); 8628 arr.sort(function (a, b) { 8629 return $(a).height() - $(b).height(); 8630 }); 8631 return this.height($(arr[parseInt(arr.length/2, 10)]).height()); 8632 }; 8633}; 8634 8635},{}],42:[function(require,module,exports){ 8636'use strict'; 8637 8638var _ = require('lodash'); 8639var sliders = require('./sliders'); 8640var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 8641 8642exports.init = function init () { 8643 slickSlideJumbotron(); 8644 8645 // $('.jumbotron-ajax').ready(function(){ 8646 // renderJumbotronSlot(); 8647 // }); 8648 8649 var renderJumbotronSlot = function(){ 8650 if (Urls && Urls.getJumbotronSlot) { 8651 $.ajax({ method: 'POST', url: Urls.getJumbotronSlot, dataType: 'html', success: function (data) { 8652 var html = ''; 8653 var contentSlot; 8654 var isJson = false;
8655 8656 var templateSettings = { 8657 interpolate: /{{([\s\S]+?)}}/g 8658 }; 8659 8660 var template = _.template($('#template-jumbotron').html(), templateSettings); 8661 8662 var dataPayload = data.substr(data.indexOf('{'), data.length); 8663 8664 var endPayloadIndex = dataPayload.length; 8665 if (dataPayload.indexOf('<!-- dwMarker') > 0) { 8666 endPayloadIndex = dataPayload.indexOf('<!-- dwMarker'); 8667 } 8668 dataPayload = dataPayload.substr(0, endPayloadIndex); 8669 8670 try { 8671 contentSlot = JSON.parse(dataPayload); 8672 isJson = true; 8673 } catch (e) { 8674 console.warn('ContentSlot template not set to JSON'); 8675 } 8676 8677 if (contentSlot) { 8678 if (contentSlot.content) { 8679 html = template({ jumbotron: buildContentSlotFromJSON(contentSlot) }); 8680 } 8681 } else if (!isJson) { 8682 html = template({ jumbotron: data }); 8683 } 8684 8685 $('.jumbotron-ajax').addClass('active').html(html); 8686 if (pageContext.site === SiteConstants.SiteIds.SheplersUS) { 8687 slickSlideJumbotron(); 8688 } 8689 $(document).trigger('app.resize'); 8690 }}); 8691 } 8692 } 8693 8694 //fishtag rigging content asset 'cat-global-header' 8695 //$('.cat-global-header').ready(function(){ 8696 // renderFishtag(); 8697 //}); 8698 8699 function renderFishtag(){ 8700 if (Urls && Urls.getFishtag) { 8701 $.ajax({ method: 'POST', url: Urls.getFishtag, dataType: 'html', success: function(data){ 8702 var html = ''; 8703 var contentSlot; 8704 var isJson = false; 8705 8706 try { 8707 contentSlot = JSON.parse(data.substr(data.indexOf('{'), data.length)); 8708 isJson = true; 8709 } catch (e) { 8710 console.warn('ContentSlot template not set to JSON'); 8711 } 8712 8713 if (contentSlot && contentSlot.content) { 8714 html = buildContentSlotFromJSON(contentSlot); 8715 } else if (!isJson) { 8716 html = data; 8717 } 8718 8719 $('.fishtag-slot').html(html); 8720 rotateText($('.top-banner-message'), $('.top-banner-message').data('duration')); 8721 }}); 8722 } 8723 } 8724 8725 function buildContentSlotFromJSON(contentSlotJSON) { 8726 var body = ''; 8727 8728 if (contentSlotJSON && contentSlotJSON.content) { 8729 for (var contentSlotItem in contentSlotJSON.content) { 8730 body += contentSlotJSON.content[contentSlotItem].body; 8731 } 8732 8733 if (contentSlotJSON.countdownTo) { 8734 body = '<div class="countdown-wrapper" data-countdown-date="' + contentSlotJSON.countdownTo + '">' + body + '</div>'; 8735 } 8736 } 8737 8738 return body; 8739 } 8740 8741 // Rotate Text for fishtag 8742 function rotateText($element, duration) { 8743 var lengthSlider = $element.find('.rotate-element').length; 8744 var $rotateElement = $element.find('.rotate-element'); 8745 8746 setInterval(function() { 8747 var $rotateElementActive = $element.find('.active'); 8748 var $nextElement = $rotateElementActive.next(); 8749 8750 if($nextElement.index() === -1) { 8751 $nextElement = $element.find('.rotate-element:first-child'); 8752 8753 $nextElement 8754 .addClass('active') 8755 .siblings() 8756 .removeClass('active'); 8757 } else { 8758 $nextElement 8759 .addClass('active') 8760 .siblings() 8761 .removeClass('active'); 8762 } 8763 }, duration); 8764 } 8765 8766 function slickSlideJumbotron() { 8767 var slidesMobile = $('.gbcolumns').closest('[data-slides-mobile]').length > 0 ? parseInt($('.gbcolumns').closest('[data-slides-mobile]').attr('data-slides-mobile')) : 1; 8768 var slidesDesktop = $('.gbcolumns').closest('[data-slides-desktop]').length > 0 ? parseInt($('.gbcolumns').closest('[data-slides-desktop]').attr('data-slides-desktop')) : 4; 8769 8770 sliders.init('.gbcolumns', {dots: false, breakpoints: {0: {slidesToShow: slidesMobile, arrows: true}, 768: {slidesToShow: slidesDesktop}}}); 8771 } 8772} 8773},{"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"./sliders":95,"lodash":133}],43:[function(require,module,exports){ 8774'use strict'; 8775 8776/* ------------------------- 8777 * LOGIN 8778 * ------------------------- 8779 */ 8780 8781var loadingIndicator = require('./components/LoadingIndicator'); 8782var dialog = require('./dialog'); 8783var loginDialog = require('./loginDialog'); 8784var recaptcha = require('./components/Recaptcha'); 8785var tooltip = require('./tooltip'); 8786var util = require('./util'); //util reference 8787var validator = require('./validator'); 8788 8789var GoogleTagManagerClient = require('../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 8790var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 8791var TPromise = require('promise'); 8792 8793var dataBuffer = {}; 8794var options = {}; 8795var loaded = {}; 8796var loadingIndicatorSettings = { 8797 IsLabelShown: false, 8798 CssClass: 'fullscreen',
8799 BackgroundColor: 'transparent' 8800}; 8801var opcLoggedInCustomerAddresses = []; 8802 8803/** 8804 * @private 8805 * @function 8806 * @description init events for the loginPage 8807 */ 8808function initLoginEvents() { 8809 //toggle the value of the rememberme checkbox 8810 $(document).on('change', '.login-rememberme input', function () { 8811 if ($(this).prop('checked')) { 8812 $('#rememberme').val('true'); 8813 } else { 8814 $('#rememberme').val('false'); 8815 } 8816 }); 8817 $(document).on('click', '#optin-privacy-policy', function(e) { 8818 e.preventDefault(); 8819 location.href = Urls.privacyPage; 8820 }); 8821 $(document).on('click', '#reward-learn-more', function(e) { 8822 e.preventDefault(); 8823 location.href = Urls.learnFAQ; 8824 }); 8825 $(document).on('click', '.movetoaddr', function(e){ 8826 e.preventDefault(); 8827 $('html, body').animate({ 8828 scrollTop: $('.billing-address-form').eq(0).offset().top 8829 }, 1000); 8830 }); 8831 $(document).on('click', '#attach-rewards-form label', function() { 8832 $('#attach-rewards-form input').removeAttr('checked'); 8833 $(this).siblings('[name="attach-rewards-options"]').attr('checked', 'checked'); 8834 }); 8835} 8836 8837function validateLoginForm($form, checkFields) { 8838 if (!$form || !checkFields) { return false } 8839 8840 var $emailField = $form.find('input[name*="_username"]'); 8841 var $passwordField = $form.find('input[name*="_password"]'); 8842 var emailValue = $emailField.length > 0 ? $emailField.val().trim() : null; 8843 var passwordValue = $passwordField.length > 0 ? $passwordField.val().trim() : null; 8844 var formValidation = true; 8845 8846 for (var i = 0; i < checkFields.length; i++) { 8847 var currentField = checkFields[i]; 8848 8849 if (currentField.toUpperCase() == 'EMAIL' && (!emailValue || emailValue.length == 0)) { 8850 formValidation = false; 8851 $form.find('input[name*="_username"]').addClass('error'); 8852 } 8853 if (currentField.toUpperCase() == 'PASSWORD' && (!passwordValue || passwordValue.length == 0)) { 8854 formValidation = false; 8855 $form.find('input[name*="_password"]').addClass('error'); 8856 } 8857 } 8858 8859 if (!formValidation) { 8860 $form.find('.login-dialog-error .invalid-missing-fields').removeClass('d-none'); 8861 return false; 8862 } else { 8863 $form.find('.login-dialog-error span').addClass('d-none'); 8864 return true; 8865 } 8866} 8867 8868function errorHandling(data, dialogTitle, dialogHtml) { 8869 if (data && typeof data === 'object' && 'message' in data) { 8870 console.log(data.message); 8871 } 8872 dialog.open({ 8873 html: dialogHtml, 8874 options: { 8875 title: dialogTitle, 8876 draggable: false, 8877 open: function(event, ui) { 8878 $('body').addClass('dialog-open'); 8879 }, 8880 close: function(event, ui) { 8881 $('body').removeClass('dialog-open'); 8882 } 8883 } 8884 }); 8885} 8886 8887// Cordial tracking for loginPage and loginDialog 8888function loginCordialAccountEvent($form, isLoginDialog) { 8889 var username = $form.find('input[name*="_username"]').val().trim(); 8890 8891 var auth_data = { 8892 email: username 8893 } 8894 8895 var contact_data = { 8896 'channels': { 8897 'email': { 8898 'address': username 8899 } 8900 } 8901 }; 8902 8903 var properties = { 8904 "email": username, 8905 "loginType": isLoginDialog ? "login-dialog" : "login" 8906 }; 8907 8908 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 8909 crdl([ 8910 ['contact', auth_data, contact_data], 8911 ['event', 'login', properties] 8912 ]); 8913 } 8914} 8915 8916// Cordial password reset - no account event 8917function passwordResetNoAccountCordialEvent(container) { 8918 if (container && $(container).find('.reset-password .no-account').length > 0) { 8919 var email = $('.no-account').text(); 8920 8921 var auth_data = { 8922 email: email 8923 } 8924 var contact_data = { 8925 'channels': { 8926 'email': { 8927 'address': email 8928 } 8929 } 8930 }; 8931 8932 var properties = { 8933 "email": email 8934 }; 8935 8936 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 8937 crdl([ 8938 ['contact', auth_data, contact_data], 8939 ['event', 'reset-password-no-account', properties] 8940 ]); 8941 } 8942 } 8943} 8944 8945function initializeRecaptchaForLogin() { 8946 renderRecaptchaForLogin(); 8947 $(document).on('Account.SubmitLogin', function(event) { 8948 $('#accountLoginButton').click(); 8949 }); 8950} 8951 8952function renderRecaptchaForLogin() { 8953 if (loaded.Recaptcha && $('#accountLoginButton').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForAccountLogin && options.Recaptcha.GoogleSiteKey) { 8954 dataBuffer.LoginRecaptcha = grecaptcha.render('accountLoginButton', { 8955 'sitekey': options.Recaptcha.GoogleSiteKey, 8956 'callback': accountLogin, 8957 'badge': 'bottomleft' 8958 }); 8959 } 8960} 8961 8962function renderRecaptchaForPasswordReset() { 8963 if (loaded.Recaptcha && $('#request-password-send-btn').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForPasswordReset && options.Recaptcha.GoogleSiteKey) { 8964 if (dataBuffer.ResetPasswordRecaptcha) { 8965 grecaptcha.reset(dataBuffer.ResetPasswordRecaptcha); 8966 } 8967 8968 dataBuffer.ResetPasswordRecaptcha = grecaptcha.render('request-password-send-btn', { 8969 'sitekey': options.Recaptcha.GoogleSiteKey, 8970 'callback': window.resetPassword, 8971 'badge': 'bottomleft' 8972 }); 8973 } 8974} 8975 8976var updateCustomerDetails = function (form, name) { 8977 var $form = $(form); 8978 8979 return TPromise.resolve($.ajax({ 8980 type: 'POST', 8981 url: util.ajaxUrl(Urls.onePageLogin), 8982 data: $form.serialize() + '&' + name + '=' + name 8983 })); 8984 } 8985 8986function showNotification(text, selector, msgType) { 8987 var $selector = $(selector); 8988 if ($selector.length == 0) { 8989 var $form = $('form.opc-login'), 8990 $selector = $('<span/>', {'class': 'login-notification', 'tabindex': '0'}).wrap('<div class="formfield clearfix error-box"><div class="form-row required"><div class="field-wrapper"></div></div></div>'); 8991 8992 $selector.parent().parent().parent().insertBefore('form.opc-login .form-row-button'); 8993 $selector = $(selector); 8994 } 8995 8996 $selector.removeClass('success error').addClass(msgType).text(text).focus(); 8997} 8998 8999function clearNotification(selector) { 9000 if(selector.length){ 9001 $('.formfield.error-box').remove(); 9002 selector.removeClass('success error'); 9003 } 9004} 9005 9006// GTM and Cordial tagging for cart opc-login 9007function opcLoginTagging($form, callback) { 9008 var email = $form.find('input[name*="username"]').val(); 9009 var auth_data = { 9010 email: email 9011 } 9012 var contact_data = { 9013 'channels': { 9014 'email': { 9015 'address': email 9016 } 9017 } 9018 }; 9019 var properties = { 9020 "email": email 9021 }; 9022 GoogleTagManagerClient.PushDataLayerForDataLayerType('CustomerLogin', { method: 'cart' }).then(function() { 9023 if (SitePreferences.CORDIAL_ENABLED) { 9024 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 9025 crdl([ 9026 ['contact', auth_data, contact_data],['event', 'login', properties] 9027 ]); 9028 } 9029 } 9030 if (callback) callback(); 9031 }); 9032} 9033 9034/** 9035 * Login reporting - increments counters in custom object 9036 * @param {String} type - login type 9037 * @param {String} source - Source of login, which can be original, cart, cart-modal, or wishlist-modal 9038 */ 9039function trackLoginActions(type, source) { 9040 if (!type || !source) { 9041 return; 9042 } 9043 9044 $.ajax({ 9045 type: 'POST', 9046 url: Urls.loginTracking, 9047 contentType: 'application/json', 9048 data: JSON.stringify({ 9049 type: type, 9050 source: source 9051 }), 9052 error: function(jqXHR, textStatus, errorThrown) { 9053 console.log('Login-TrackActions: Error in incrementing login action counters. ERROR TEXT: '+textStatus+', ERROR THROWN: '+errorThrown+'.'); 9054 }, 9055 success: function(response) { 9056 if (response) {} 9057 } 9058 }); 9059} 9060 9061/** 9062 * @private 9063 * @function 9064 * @description init login button event for the loginPage, loginDialog and checkout login 9065 */ 9066function initLoginButtons() { 9067 $(document).on('click', '#accountLoginButton', function(event) { 9068 event.preventDefault(); 9069 var dialogHtml = '<p style="padding: 10px;">Oops, something went wrong with login. Please try again later.</p>'; 9070 var $accountLoginButton = $(this); 9071 var $accountLoginForm = $accountLoginButton.closest('form#dwfrm_login'); 9072 var formRememberMe = $accountLoginForm.find('input[name*="dwfrm_login_rememberme"]').is(':checked'); 9073 var formUsername = formRememberMe ? '=' + $accountLoginForm.find('input[name*="dwfrm_login_username"]').val() : ''; 9074 var formUrl = $accountLoginForm.attr('action'); 9075 9076 // Clear previous form errors 9077 $accountLoginForm.find('input').removeClass('error'); 9078 $accountLoginForm.find('.login-dialog-error span').addClass('d-none'); 9079 9080 var isValidForm = validateLoginForm($accountLoginForm, ['email','password']); 9081 var isLoginDialog = formUrl.indexOf('loginDialog') >= 0; 9082 var formData = $accountLoginForm.serialize(); 9083 9084 if (!isLoginDialog) { 9085 $('[data-login-source]').attr('data-login-source', 'original'); // For reporting 9086 } 9087 9088 // Using AJAX instead of default HTML button submit for login page and dialog 9089 if (isValidForm) { 9090 $('body').loading(loadingIndicatorSettings); 9091 $.ajax({ 9092 type: 'POST', 9093 url: formUrl, 9094 data: formData, 9095 success: function(data, textStatus, jqXHR) { 9096 if (typeof data === 'object' && 'result' in data) { 9097 if (data.result == 'error') { 9098 $('body').loading('destroy'); 9099 if (isLoginDialog) { 9100 $accountLoginForm.find('.login-dialog-error .invali
9100d-login').removeClass('d-none'); 9101 } else { 9102 window.location.href = data.loginDialogContinueUrl + '?retry'; 9103 } 9104 } else if (data.result == 'success' || data.result == 'complete') { 9105 $('body').loading('destroy'); 9106 // 'validateCustomer' property only returns in the data if this is a dialog. Otherwise, rewards validation happens through the URL using loginDialogContinueUrl. 9107 // If this is a rewards customer, and the cusomter account requires validation... 9108 if ('validateCustomer' in data && data.validateCustomer) { 9109 if (SitePreferences.CORDIAL_ENABLED) { 9110 loginCordialAccountEvent($accountLoginForm, isLoginDialog); 9111 } 9112 var newAttributes = { 9113 "data-modal-type": "login", 9114 "data-continue-url": 'loginDialogContinueUrl' in data ? data.loginDialogContinueUrl : '', 9115 "data-first-name": 'customerFirstName' in data ? data.customerFirstName : '', 9116 "data-store-number": 'storeFromProfile' in data ? data.storeFromProfile : '', 9117 "data-cart-quantity": 'cartQuantity' in data ? data.cartQuantity : '' 9118 } 9119 $('.login-dialog-validate-customer').html(data.validateCustomer); 9120 $('.login-dialog-validate-customer').addClass('validate-customer-show follow-account-dialog-path').attr(newAttributes); 9121 // Do this in two places: 9122 // (1) for login-dialog here because the element is only loaded into page via AJAX, 9123 // (2) init of page load for regular rewards verification pages through normal login flow 9124 initAddRulesForCodeInput(); 9125 } else { 9126 // Fire the cordial login event 9127 if (SitePreferences.CORDIAL_ENABLED) { 9128 loginCordialAccountEvent($accountLoginForm, isLoginDialog); 9129 } 9130 trackLoginActions('password', $('[data-login-source]').attr('data-login-source')); 9131 9132 // Handle follow-up actions accordingly 9133 $(document).trigger('PostAjaxAuthenticationActions.Initialize', { results: data, isAccountDialog: isLoginDialog, displayMessage: 'login' }); 9134 } 9135 } else { 9136 $('body').loading('destroy'); 9137 errorHandling(data, 'Login - Error', dialogHtml); 9138 } 9139 } else { 9140 $('body').loading('destroy'); 9141 if (isLoginDialog) { 9142 errorHandling(data, 'Login - Error', dialogHtml); 9143 } else { 9144 window.location.href = location.href.split('?')[0]+'?retry'; 9145 } 9146 } 9147 }, 9148 error: function(jqXHR, textStatus, errorThrown) { 9149 $('body').loading('destroy'); 9150 if (!isLoginDialog) { 9151 window.location.href = location.href.split('?')[0]+'?retry'; 9152 } 9153 } 9154 }); 9155 } 9156 }); 9157 9158 $(document).on('click', '.opc-login-submit-button', function(event) { 9159 event.preventDefault(); 9160 var $opcLoginButton = $(this); 9161 var $opcLoginForm = $opcLoginButton.closest('form.opc-login'); 9162 var notificationSelector = $('.login-notification'); 9163 9164 $('body').loading(loadingIndicatorSettings); 9165 9166 $('[data-login-source]').attr('data-login-source', 'cart'); // For reporting 9167 $opcLoginForm.validate().form(); 9168 clearNotification(notificationSelector); 9169 updateCustomerDetails($opcLoginForm, $(this).attr('name')).then(function (response) { 9170 if (typeof response != 'object') { 9171 try { 9172 response = JSON.parse(response); 9173 } catch(e) { 9174 console.log(e); 9175 response = {}; 9176 } 9177 } 9178 if ('viewModel' in response && 'Customer' in response.viewM
9178odel && response.viewModel.Customer.authenticated == true) { 9179 Customer.authenticated = response.viewModel.Customer.authenticated; 9180 opcLoggedInCustomerAddresses = response.viewModel.Addresses; 9181 if ('validateCustomer' in response) { 9182 $.ajax({ 9183 type: 'GET', 9184 url: Urls.renderDialogTemplate, 9185 error: function(jqXHR, textStatus, errorThrown) { 9186 $('body').loading('destroy'); 9187 console.log(errorThrown); 9188 }, 9189 success: function(data) { 9190 if (data) { 9191 $('body').loading('destroy'); 9192 opcLoginTagging($opcLoginForm); 9193 var opcLoginContinueUrl = $('#cart-items-form').length ? Urls.onePage : Urls.account; 9194 9195 dialog.open({ 9196 html: data, 9197 options: { 9198 dialogClass: 'login-dialog', 9199 draggable: false, 9200 height: 600, 9201 open: function() { 9202 $('body').addClass('dialog-open'); 9203 $(this).scrollTop(0); 9204 if (SitePreferences.CORDIAL_ENABLED) { 9205 loginCordialAccountEvent($opcLoginForm, false); 9206 } 9207 9208 $('.ui-dialog.login-dialog').css('height', '430px'); 9209 $('.ui-dialog.login-dialog .login-dialog-forms-container').css('margin', '0 -8px'); 9210 $('.login-dialog-register-container').hide(); 9211 9212 var newAttributes = { 9213 "data-modal-type": "login", 9214 "data-continue-url": opcLoginContinueUrl, 9215 "data-first-name": 'customerFirstName' in response ? response.customerFirstName : '', 9216 "data-store-number": 'storeFromProfile' in response ? response.storeFromProfile : '', 9217 "data-cart-quantity": 'cartQuantity' in response ? response.cartQuantity : '', 9218 "data-opc-login": true 9219 } 9220 $('.login-dialog-validate-customer').html(response.validateCustomer); 9221 $('.login-dialog-validate-customer').addClass('validate-customer-show follow-account-dialog-path').attr(newAttributes); 9222 9223 initAddRulesForCodeInput(); 9224 9225 var $passwordReset = $(this).find('.login-dialog-forms-container #password-reset-button'); 9226 $passwordReset.attr('data-target', $passwordReset.attr('data-target') + '?loginDialog=true'); 9227 }, 9228 close: function() { 9229 $('body').removeClass('dialog-open'); 9230 } 9231 } 9232 }); 9233 } 9234 } 9235 }); 9236 } else { 9237 $('body').loading('destroy'); 9238 opcLoginTagging($opcLoginForm); 9239 trackLoginActions('password', $('[data-login-source]').attr('data-login-source')); 9240 location.href = Urls.onePage; 9241 } 9242 } else { 9243 $('body').loading('destroy'); 9244 $('.opc-login .field-wrapper input').addClass('error'); 9245 showNotification(Resources.PWD_EMAIL_ERROR, '.login-notification', 'error'); 9246 } 9247 }.bind(this)); 9248 }); 9249 9250 // OwnID OTP flow 9251 $(document).on('click', '#ownid-otp', function(event) { 9252 event.preventDefault(); 9253 $('input[type="password"]').val(''); // clears out password 9254 9255 // Clear errors and re-validate 9256 var $accountLoginButton = $(this); 9257 var $accountLoginForm = $accountLoginButton.closest('form#dwfrm_login'); 9258 $accountLoginForm.find('input').removeClass('error'); 9259 $accountLoginForm.find('.login-dialog-error span').addClass('d-none'); 9260 9261 var isValidEmail = validateLoginForm($accountLoginForm, ['email']); 9262 if (isValidEmail) { 9263 window.ownidStartOtp(); 9264 } 9265 }); 9266 9267 // OwnID passkey tooltip 9268 tooltip.init({ 9269 items: '.tooltip' 9270 }); 9271} 9272 9273function callNextController(url, callback) { 9274 $.ajax({ 9275 type: 'GET', 9276 url: url, 9277 contentType: 'application/json', 9278 error: function(jqXHR, textStatus, errorThrown) { 9279 }, 9280 success: function(response) { 9281 if (response) { 9282 if (callback) callback(response); 9283 } 9284 } 9285 }); 9286} 9287 9288/** 9289 * @private 9290 * @function 9291 * @description register on-click event for rewards validation > send code button 9292 * @notes changed the button.on('click') to a document.on('click') for HTML that is dynamically loaded in page with AJAX well after initial page load 9293 */ 9294function initValidateRewardsAccount() { 9295 $(document).on('click', '#validate-account button#send-code', function(event) { 9296 event.preventDefault(); 9297 9298 var $validateAccountForm = $('#validate-account'); 9299 var isAccountDialog = $('.login-dialog-validate-customer').hasClass('follow-account-dialog-path'); 9300 var sendType = $validateAccountForm.find('input[name=validate-account]:checked').attr('id').indexOf('none') > -1 ? 'none' : 'other'; 9301 9302 if (sendType == "none") { 9303 $.ajax({ 9304 type: 'post', 9305 url: Urls.createRewardsAccount, 9306 contentType: 'application/json', 9307 data: JSON.stringify({ 9308 firstName: $('.customer-account .first-name').text(), 9309 lastName: $('.customer-account .last-name').text(), 9310 emailAddress: $('.customer-account .email-address').text(), 9311 phoneNumber: $('.customer-account .phone-number').text(), 9312 zipCode: $('.customer-account .zip-code').text(), 9313 birthDate: $('.customer-account .birth-date').text(), 9314 autoEnroll: false 9315 }), 9316 success: function (data) { 9317 console.log('Rewards account created.'); 9318 initVerificationDirection(); 9319 } 9320 }); 9321 } else { 9322 $.ajax({ 9323 url: Urls.sendValidationCode, 9324 dataType: 'JSON', 9325 method: 'POST', 9326 data: { 9327 'sendMethod': $validateAccountForm.find('input[name=validate-account]:checked').val(), 9328 'sendTo': $validateAccountForm.find('input[name=validate-account]:checked').attr('data-value') 9329 }, 9330 success : function(data) { 9331 var resultStatus = 'status' in data && data.status != 'pending' ? true : 'result' in data && 'status' in data.result && data.result.status != 'pending' ? true : false;
9332 if (('error' in data && data.error) || resultStatus) { 9333 $('.further-info').hide(); 9334 $('.verify-form').hide(); 9335 $('.verify-fail').removeClass('hidden'); 9336 } 9337 $('.account-recognized').hide(); 9338 if (isAccountDialog) { 9339 $('.verify-account').removeClass('hidden').addClass('validate-customer-show'); 9340 } else { 9341 $('.verify-account').removeClass('hidden'); 9342 } 9343 $('.' + sendType + '-method').removeClass('hidden'); 9344 }, 9345 complete: function(data, status, xhr) { 9346 if (data.status == 302 && data.responseText) { 9347 location.href = data.responseText; 9348 } 9349 } 9350 }); 9351 } 9352 }); 9353 9354 $(document).on('click', '#attach-rewards-button', function(event) { 9355 event.preventDefault(); 9356 var errorMessage = '<p style="padding: 10px;">Sorry, we were unable to finalize your rewards account updates.</p>'; 9357 var $attachRewardsForm = $('#attach-rewards-form'); 9358 var $selectedOption = $attachRewardsForm.find('input[name=attach-rewards-options]:checked'); 9359 var submittedEmail = $('.login-dialog-passcode-container, .otp-login-form-container').attr('data-email'); 9360 9361 if (!$selectedOption) { 9362 $('.attach-rewards-form-errors').removeClass('d-none'); 9363 return; 9364 } 9365 9366 $.ajax({ 9367 url: Urls.attachRewards, 9368 dataType: 'JSON', 9369 method: 'POST', 9370 data: { 9371 'option': $selectedOption.val(), 9372 'email': submittedEmail 9373 }, 9374 success : function(data) { 9375 if (data && data.result && data.result == 'success') { 9376 console.log('Rewards attachment complete.'); 9377 initVerificationDirection(); 9378 } else { 9379 errorHandling(data, 'Rewards Account - Error', errorMessage); 9380 } 9381 }, 9382 error: function(jqXHR, textStatus, errorThrown) { 9383 errorHandling(data, 'Rewards Account - Error', errorMessage); 9384 } 9385 }); 9386 }); 9387} 9388 9389/** 9390 * @private 9391 * @function 9392 * @description register on-click event for rewards validation > verify code button 9393 */ 9394function initVerifyCodeSent() { 9395 $(document).on('click', '#verify-code button#verify-user', function(event) { 9396 event.preventDefault(); 9397 9398 var $verifyCodeForm = $('#verify-code'); 9399 if (!$verifyCodeForm.valid()) { 9400 return false; 9401 } 9402 9403 $.ajax({ 9404 url: Urls.verifySubmittedCode, 9405 dataType: 'JSON', 9406 method: 'POST', 9407 data: { 9408 'code': $verifyCodeForm.find('input[name=enter-code]', '#verify-code').val(), 9409 'sendTo': $('#validate-account').find('input[name=validate-account]:checked').attr('data-value') 9410 }, 9411 success : function(data) { 9412 if (('error' in data && data.error) || ('status' in data && data.status != 'approved')) { 9413 $('.further-info').hide(); 9414 $('.verify-form').hide(); 9415 $('.verify-fail').removeClass('hidden'); 9416 } else { 9417 console.log('Rewards verification complete.'); 9418 initVerificationDirection(); 9419 } 9420 }, 9421 complete: function(data, status, xhr) { 9422 if (data.status == 302 && data.responseText) { 9423 location.href = data.responseText; 9424 } 9425 } 9426 }); 9427 }); 9428} 9429 9430/** 9431 * @private 9432 * @function 9433 * @description directs the page load or the page redraw after rewards verification screen 9434 */ 9435function initVerificationDirection() { 9436 var $validateDialog = $('.login-dialog-validate-customer'); 9437 var isAccountDialog = $('.login-dialog-validate-customer').hasClass('follow-account-dialog-path'); 9438 var dataModalType, dataNextControllerUrl, dataContinueUrl, dataFirstName, dataStore, dataCartQuantity, isOpcLogin; 9439 9440 if ($validateDialog.length) { 9441 dataModalType = $validateDialog.attr('data-modal-type'); 9442 dataNextControllerUrl = $validateDialog.attr('data-next-controller-url'); 9443 dataContinueUrl = $validateDialog.attr('data-continue-url'); 9444 dataFirstName = $validateDialog.attr('data-first-name'); 9445 dataStore = $validateDialog.attr('data-store-number'); 9446 dataCartQuantity = $validateDialog.attr('data-cart-quantity'); 9447 isOpcLogin = $validateDialog.attr('data-opc-login') == 'true'; 9448 9449 if (isOpcLogin) { 9450 dialog.close(); 9451 location.href = Urls.onePage; 9452 } 9453 if (isAccountDialog) { 9454 if (dataNextControllerUrl) { 9455 callNextController(dataNextControllerUrl, function(response) { 9456 if (response && 'result' in response && (response.result == 'success' || response.result == 'complete')) { 9457 response.customerFirstName = dataFirstName; 9458 response.storeFromProfile = dataStore; 9459 response.cartQuantity = dataCartQuantity; 9460 // Handle follow-up actions accordingly 9461 $(document).trigger('PostAjaxAuthenticationActions.Initialize', { results: response, isAccountDialog: isAccountDialog, displayMessage: dataModalType }); 9462 } 9463 }); 9464 } else { 9465 if (dataContinueUrl) { 9466 location.href = dataContinueUrl; 9467 } else { 9468 location.href = Urls.account; 9469 } 9470 } 9471 } 9472 } else { 9473 location.href = Urls.account; 9474 } 9475} 9476 9477/** 9478 * @private 9479 * @function 9480 * @description add rules to code input field 9481 */ 9482function initAddRulesForCodeInput() { 9483 $('form#verify-code').validate(); 9484 $('#verify-code #enter-code').rules('add', { 9485 required: true, 9486 digits: true, 9487 minlength: 6, 9488 messages: {
9489 required: Resources.VALIDATE_CODE, 9490 minlength: Resources.VALIDATE_CODE 9491 }, 9492 normalizer: function(value) { 9493 return $.trim(value); 9494 } 9495 }); 9496} 9497 9498/** 9499 * @private 9500 * @function 9501 * @description register on-click event for rewards validation > verify code > resend code link 9502 */ 9503function initResendValidationCode() { 9504 $(document).on('click', '.verify-account a.resend-code', function(event) { 9505 event.preventDefault(); 9506 if ($('.login-dialog-validate-customer').hasClass('follow-account-dialog-path')) { 9507 $('.verify-account, .further-info span').addClass('hidden'); 9508 $('.account-recognized').css('left','-9999px').removeClass('hidden').show().addClass('validate-customer-show'); 9509 } else { 9510 location.reload(); 9511 } 9512 }); 9513} 9514 9515/** 9516 * @private 9517 * @function 9518 * @description register on-click events for reset-password flow 9519 */ 9520function initResetPasswordEvents() { 9521 // Show reset password form 9522 $(document).on('click', '#password-reset-button', function(event) { 9523 event.preventDefault(); 9524 var $resetPasswordButton = $(this); 9525 var resetDialogUrl = $resetPasswordButton.attr('data-target'); 9526 var isLoginDialog = resetDialogUrl.indexOf('loginDialog') >= 0; 9527 9528 if (isLoginDialog) { 9529 $('body').loading(loadingIndicatorSettings); 9530 var dialogHtml = '<p style="padding: 10px;">Oops, something went wrong with Password Reset. Please try again later.</p>'; 9531 9532 $.ajax({ 9533 type: 'GET', 9534 url: resetDialogUrl, 9535 success: function(data, textStatus, jqXHR) { 9536 if (typeof data === 'object' && 'result' in data) { 9537 if (data.result == 'complete') { 9538 $('body').loading('destroy'); 9539 // If we received HTML in the data for displaying the reset password form, then dis
9539play it... 9540 if ('resetPasswordForm' in data && data.resetPasswordForm) { 9541 $('.login-dialog-reset-password').html(data.resetPasswordForm); 9542 $('.login-dialog-reset-password').addClass('reset-password-show'); 9543 $('.login-dialog-reset-password').find('#PasswordResetForm').attr('action', $('.login-dialog-reset-password').find('#PasswordResetForm').attr('action') + '?loginDialog=true'); 9544 renderRecaptchaForPasswordReset(); 9545 } else { 9546 $('body').loading('destroy'); 9547 errorHandling(data, 'Reset Password - Error', dialogHtml); 9548 } 9549 } else { 9550 $('body').loading('destroy'); 9551 errorHandling(data, 'Reset Password - Error', dialogHtml); 9552 } 9553 } else { 9554 $('body').loading('destroy'); 9555 if (isLoginDialog) { 9556 errorHandling(data, 'Reset Password - Error', dialogHtml); 9557 } else { 9558 window.location.href = location.href; 9559 } 9560 } 9561 }, 9562 error: function(jqXHR, textStatus, errorThrown) { 9563 $('body').loading('destroy'); 9564 if (!isLoginDialog) { 9565 window.location.href = location.href; 9566 } 9567 } 9568 }); 9569 } else if (SitePreferences.RESET_POPUP_ENABLED) { 9570 dialog.open({ 9571 url: resetDialogUrl, 9572 options: { 9573 dialogClass: 'resetpwdpopup', 9574 width: 385, 9575 open: function () { 9576 renderRecaptchaForPasswordReset(); 9577 $(".reset-password-heading-close-btn, .ui-widget-overlay").on('click',function(){ 9578 $("button.ui-dialog-titlebar-close").click(); 9579 }); 9580 } 9581 } 9582 }); 9583 } else { 9584 window.location.href = resetDialogUrl; 9585 } 9586 }); 9587 9588 // Submit reset password form 9589 $(document).on('click.ResetPassword', '#request-password-send-btn, [name$="_requestpassword_send"]', function(event) { 9590 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForPasswordReset) { 9591 resetPassword(event, $(this)); 9592 } 9593 }); 9594 9595 $(document).on('Account.ResetPassword', function (event, data) { 9596 resetPassword(event, null, true); 9597 }); 9598} 9599 9600function resetPassword(event, $resetPasswordSendButton, isRecaptchaEvent) { 9601 if (!$resetPasswordSendButton) { 9602 $resetPasswordSendButton = $('#request-password-send-btn'); 9603 } 9604 9605 var $resetPasswordSendForm = $resetPasswordSendButton.closest('form#PasswordResetForm'); 9606 var isLoginDialog = $resetPasswordSendForm.attr('action').indexOf('loginDialog') >= 0; 9607 9608 // Try to prevent the form submission as quickly as possible before doing all of the other logic 9609 if (isLoginDialog || (SitePreferences.RESET_POPUP_ENABLED && dialog.isActive())) { 9610 event.preventDefault(); 9611 } 9612 9613 validator.init(); 9614 var isValidForm = $resetPasswordSendForm.valid(); 9615 9616 if (isValidForm) { 9617 if (isLoginDialog) { 9618 $('body').loading(loadingIndicatorSettings); 9619 var dialogHtml = '<p style="padding: 10px;">Oops, something went wrong with Password Reset. Please try again later.</p>'; 9620 var formData = $resetPasswordSendForm.serialize(); 9621 formData += '&' + $resetPasswordSendButton.attr('name') + '=' + $resetPasswordSendButton.attr('name'); 9622 9623 $.ajax({ 9624 type: 'POST', 9625 url: $resetPasswordSendForm.attr('action'), 9626 data: formData, 9627 success: function(data, textStatus, jqXHR) { 9628 if (typeof data === 'object' && 'result' in data) { 9629 if (data.result == 'complete') { 9630 $('body').loading('destroy'); 9631 // If reset password email was sent, show confirmation within the dialog 9632 if ('resetPasswordConfirmation' in data && data.resetPasswordConfirmation) { 9633 $('.login-dialog-reset-password').html(data.resetPasswordConfirmation); 9634 $('.login-dialog-reset-password').addClass('reset-password-show'); 9635 passwordResetNoAccountCordialEvent('.login-dialog-reset-password'); 9636 } else { 9637 $('body').loading('destroy'); 9638 errorHandling(data, 'Reset Password - Error', dialogHtml); 9639 } 9640 } else { 9641 $('body').loading('destroy'); 9642 errorHandling(data, 'Reset Password - Error', dialogHtml); 9643 } 9644 } else { 9645 $('body').loading('destroy'); 9646 if (isLoginDialog) { 9647 errorHandling(data, 'Reset Password - Error', dialogHtml); 9648 } else { 9649 window.location.href = location.href; 9650 } 9651 } 9652 }, 9653 error: function(jqXHR, textStatus, errorThrown) { 9654 $('body').loading('destroy'); 9655 if (!isLoginDialog) { 9656 window.location.href = location.href; 9657 } 9658 } 9659 }); 9660 } else if (SitePreferences.RESET_POPUP_ENABLED && dialog.isActive()) { 9661 dialog.submit($resetPasswordSendButton.attr('name'), function() { 9662 passwordResetNoAccountCordialEvent('.resetpwdpopup'); 9663 }); 9664 } else if (isRecaptchaEvent) { 9665 $resetPasswordSendForm.append('<input type="hidden" name="' + $resetPasswordSendButton.attr('name') + '" value="' + $resetPasswordSendButton.val() + '"/>') 9666 $resetPasswordSendForm.submit(); 9667 } 9668 } 9669} 9670 9671module.exports = { 9672 init: function (optionsParameter) { 9673 options = optionsParameter; 9674 9675 initLoginEvents(); 9676 if (options && options.Recaptcha && (options.Recaptcha.EnabledForAccountLogin || options.Recaptcha.EnabledForPasswordReset)) { 9677 $(document).on('Recaptcha.Loaded', function(event) { 9678 if (!loaded.Recaptcha) { 9679 loaded.Recaptcha = true; 9680 renderRecaptchaForLogin(); 9681 renderRecaptchaForPasswordReset(); 9682 } 9683 }); 9684 9685 recaptcha.initialize(); 9686 initializeRecaptchaForLogin(); 9687 renderRecaptchaForPasswordReset(); 9688 } 9689 initLoginButtons(); 9690 initValidateRewardsAccount(); 9691 initVerifyCodeSent(); 9692 initResendValidationCode(); 9693 initAddRulesForCodeInput(); 9694 initResetPasswordEvents(); 9695 } 9696}; 9697},{"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"./components/LoadingIndicator":25,"./components/Recaptcha":29,"./dialog":36,"./loginDialog":44,"./tooltip":101,"./util":102,"./validator":103,"promise":134}],44:[function(require,module,exports){ 9698'use strict'; 9699 9700var dialog = require('./dialog'); 9701 9702/* ------------------------- 9703 * LOGIN MODAL 9704 * ------------------------- 9705 */ 9706 9707var loginDialog = { 9708 /** 9709 * @function
9710 * @description Shows the account-login form in a dialog 9711 */ 9712 show: function(callback, controller, action, productID, params, completeUrl) { 9713 $.ajax({ 9714 type: 'POST', 9715 url: Urls.loginDialog, 9716 data: JSON.stringify({ 9717 controller: controller, 9718 action: action, 9719 passedQueryString: params 9720 }), 9721 contentType: 'application/json', 9722 error: function(jqXHR, textStatus, errorThrown) { 9723 console.log(errorThrown); 9724 }, 9725 success: function(response) { 9726 if (response) { 9727 9728 dialog.open({ 9729 html: response, 9730 options: { 9731 dialogClass: 'login-dialog', 9732 draggable: false, 9733 open: function() { 9734 $('body').addClass('dialog-open'); 9735 $(this).scrollTop(0); 9736 $(this).find('.login-dialog-forms-container').attr('data-controller', controller).attr('data-action', action).attr('data-product', productID); 9737 $(this).find('.login-dialog-forms-container form').each(function(i, form) { 9738 var actionUrl = $(form).attr('action') + '?loginDialog=true'; 9739 $(form).attr('action', actionUrl); 9740 }); 9741 $(this).find('.login-dialog-validate-customer').attr('data-next-controller-url', completeUrl); 9742 var $passwordReset = $(this).find('.login-dialog-forms-container #password-reset-button'); 9743 $passwordReset.attr('data-target', $passwordReset.attr('data-target') + '?loginDialog=true'); 9744 if (callback) { 9745 callback(); 9746 } 9747 }, 9748 close: function() { 9749 $('body').removeClass('dialog-open'); 9750 } 9751 } 9752 }); 9753 } 9754 } 9755 }); 9756 }, 9757 /** 9758 * @function 9759 * @description Closes the account-login dialog 9760 */ 9761 close: function() { 9762 dialog.close(); 9763 } 9764} 9765 9766module.exports = loginDialog; 9767},{"./dialog":36}],45:[function(require,module,exports){ 9768'use strict'; 9769 9770var util = require('./util'), 9771 bonusProductsView = require('./bonus-products-view'); 9772 9773var timer = { 9774 id: null, 9775 clear: function () { 9776 if (this.id) { 9777 window.clearTimeout(this.id); 9778 delete this.id; 9779 } 9780 }, 9781 start: function (duration, callback) { 9782 this.id = setTimeout(callback, duration); 9783 } 9784}; 9785 9786var minicart = { 9787 init: function () { 9788 this.$el = $('#mini-cart'); 9789 this.$content = this.$el.find('.mini-cart-content'); 9790 9791 $('.mini-cart-product').eq(0).find('.mini-cart-toggle').addClass('fa-caret-down'); 9792 $('.mini-cart-product').not(':first').addClass('collapsed') 9793 .find('.mini-cart-toggle').addClass('fa-caret-right'); 9794 9795 $('.mini-cart-toggle').on('click', function () { 9796 $(this).toggleClass('fa-caret-down fa-caret-right'); 9797 $(this).closest('.mini-cart-product').toggleClass('collapsed'); 9798 }); 9799 9800 // events 9801 this.$el.find('.mini-cart-total').on('mouseenter', function () { 9802 if (this.$content.not(':visible')) { 9803 this.slide(); 9804 } 9805 }.bind(this)); 9806 9807 this.$content.on('mouseenter', function () { 9808 timer.clear(); 9809 }).on('mouseleave', function () { 9810 timer.clear(); 9811 timer.start(30, this.close.bind(this)); 9812 }.bind(this)); 9813 9814 $(document).on('minicart:update', function(){ 9815 //implement minicart update here 9816 }); 9817 }, 9818 /** 9819 * @function 9820 * @description Shows the given content in the mini cart 9821 * @param {String} A HTML string with the content which will be shown 9822 */ 9823 show: function (html) { 9824 this.$el.html(html); 9825 util.scrollBrowser(0); 9826 this.init(); 9827 this.slide(); 9828 bonusProductsView.loadBonusOption(); 9829 }, 9830 /** 9831 * @function
9832 * @description Slides down and show the contents of the mini cart 9833 */ 9834 slide: function () { 9835 timer.clear(); 9836 // show the item 9837 this.$content.slideDown('slow'); 9838 // after a time out automatically close it 9839 timer.start(6000, this.close.bind(this)); 9840 }, 9841 /** 9842 * @function 9843 * @description Closes the mini cart with given delay 9844 * @param {Number} delay The delay in milliseconds 9845 */ 9846 close: function (delay) { 9847 timer.clear(); 9848 this.$content.slideUp(delay); 9849 } 9850}; 9851 9852module.exports = minicart; 9853 9854},{"./bonus-products-view":6,"./util":102}],46:[function(require,module,exports){ 9855'use strict'; 9856 9857var util = require('./util'); 9858 9859var page = { 9860 title: '', 9861 type: '', 9862 params: util.getQueryStringParams(window.location.search.substr(1)), 9863 redirect: function (newURL) { 9864 setTimeout(function () { 9865 window.location.href = newURL; 9866 }, 0); 9867 }, 9868 refresh: function () { 9869 setTimeout(function () { 9870 window.location.assign(window.location.href); 9871 }, 500); 9872 } 9873}; 9874 9875module.exports = page; 9876 9877},{"./util":102}],47:[function(require,module,exports){ 9878'use strict'; 9879 9880var util = require('../../util'); 9881 9882var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 9883 9884var $authenticationContainer = $('.authentication-form-container'); 9885var $authenticationForm = $authenticationContainer.closest('form'); 9886var $authenticationEmailAddress = $authenticationForm.find('input[name="AuthenticationEmailAddress"]'); 9887var authenticationValidator; 9888 9889exports.init = function(options) { 9890 $authenticationContainer.on('click', 'input[type="submit"]', function (event) { 9891 event.preventDefault(); 9892 9893 authenticationValidator = $authenticationForm.validate(); 9894 $authenticationEmailAddress.rules('add', ValidationRules.Email); 9895 authenticationValidator.form(); 9896 9897 if (authenticationValidator.valid()) { 9898 $('<input />').attr('type', 'hidden').attr('name', 'isMobile').attr('value', $('html.size-mobile').length > 0).appendTo($authenticationForm); 9899 $authenticationForm.submit(); 9900 } 9901 }); 9902}; 9903},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../util":102}],48:[function(require,module,exports){ 9904'use strict'; 9905 9906var AddressAutocompleteDialog; 9907var AddressVerificationDialog; 9908var AddressVerificationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper'); 9909var dialog = require('../dialog'); 9910var findMoreStores = require('../findMoreStores'); 9911var orderStatusForm = require('../components/OrderStatusForm'); 9912var giftcert = require('../giftcert'); 9913var page = require('../page'); 9914var recaptcha = require('../components/Recaptcha'); 9915var tooltip = require('../tooltip'); 9916var util = require('../util'); 9917var validator = require('../validator'); 9918 9919var PaymentMethodConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').PaymentMethods; 9920var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 9921 9922var dataBuffer = {}; 9923var options = {}; 9924var loaded = {}; 9925 9926/** 9927 * @function 9928 * @description Initializes the events on the address form (apply, cancel, delete) 9929 * @param {Element} form The form which will be initialized 9930 */ 9931function initializeAddressForm() { 9932 var $addressEditForm = $('#edit-address-form'); 9933 $addressEditForm.on('click', '.submit-shipping', function (e) { 9934 e.preventDefault(); 9935 9936 var addressType = $addressEditForm.attr('address-type') ? $addressEditForm.attr('address-type') : 'saved'; 9937 var addressDeliverable = function () { 9938 $addressEditForm.submit(); 9939 } 9940 var addressNotDeliverable = function (addressVerifyData) { 9941 AddressVerificationDialog.initialize(options, addressType, addressVerifyData); 9942 } 9943 var country = $addressEditForm.find('[id*="_country"]').val(); 9944 if (options && options.Lob && options.Lob.AddressVerification.Enabled && country.toUpperCase() == 'US' && $addressEditForm.find('.submit-shipping').attr('verified') != 'true') { 9945 AddressVerificationHelper.VerifyAddress($addressEditForm, options).then(addressDeliverable, addressNotDeliverable); 9946 } else { 9947 addressDeliverable(); 9948 } 9949 }); 9950 9951 if (options && options.Lob && options.Lob.AddressAutocomplete.Enabled) {
9952 $(document).on('keyup.AddressAutocomplete', '#edit-address-form input[type="text"]', function (event) { 9953 var $this = $(this); 9954 var formValidator = $addressEditForm.validate(); 9955 9956 if (event.keyCode == 8 || event.keyCode == 46) { 9957 $this.parent().find('.address-autocomplete-dialog').remove(); 9958 } else if (!formValidator.checkForm() && ($this.attr('id').indexOf('_address1') >= 0 || $this.attr('id').indexOf('_address2') >= 0 || $this.attr('id').indexOf('_city') >= 0 || $this.attr('id').indexOf('_postal') >= 0)) { 9959 var addressAutocompleteHandler = function (addressAutocompleteData) { 9960 AddressAutocompleteDialog.initialize(options, addressAutocompleteData); 9961 } 9962 9963 AddressVerificationHelper.AutocompleteAddress($addressEditForm, $this, options).then(addressAutocompleteHandler); 9964 } else { 9965 $this.parent().find('.address-autocomplete-dialog').remove(); 9966 } 9967 }); 9968 9969 $(document).on('SetAddressFromAddressAutocomplete', function (event, data) { 9970 AddressVerificationHelper.SetAddressFromAddressVerificationDialog(data.$form, data.Address); 9971 }); 9972 } 9973 9974 if (options && options.Lob && options.Lob.AddressVerification.Enabled) { 9975 $(document).on('SetAddressFromAddressVerification', function (event, addressData) { 9976 AddressVerificationHelper.SetAddressFromAddressVerificationDialog($addressEditForm, addressData); 9977 $addressEditForm.submit(); 9978 }); 9979 } 9980 9981 validator.init(); 9982} 9983/** 9984 * @private 9985 * @function 9986 * @description Toggles the list of Orders 9987 */ 9988function toggleFullOrder () { 9989 $('.order-items') 9990 .find('li.hidden:first') 9991 .prev('li') 9992 .append('<a class="toggle">View All</a>') 9993 .children('.toggle') 9994 .click(function () { 9995 $(this).parent().siblings('li.hidden').show(); 9996 $(this).remove(); 9997 }); 9998} 9999/** 10000 * @private 10001 * @function 10002 * @description Binds the events on the address form (edit, create, delete) 10003 */ 10004function initAddressEvents() { 10005 $(document).ready(function(){ 10006 if ( $('.address-field-container form select').length > 0 ) { 10007 $('.address-field-container form select').each(function(){ 10008 $(this).selectmenu({}); 10009 }); 10010 } 10011 10012 $("#dwfrm_profile_customer_berewarded").on("click",function(){ 10013 if ( $(this).is(':checked') ) { 10014 $('.rewardsNumberContainer').slideDown(); 10015 } else { 10016 $('.rewardsNumberContainer').slideUp(); 10017 } 10018 }); 10019 10020 if ($('#edit-address-form').length > 0) { 10021 initializeAddressForm(); 10022 } 10023 }); 10024 10025 $(window).on('load', function() {
10026 $('#primary #edit-address-form input[name="dwfrm_profile_address_remove"]').off('click'); 10027 $('#primary #edit-address-form input[name="dwfrm_profile_address_remove"]').on('click', function(e){ 10028 e.preventDefault(); 10029 var $form = $(this).parents('form'); 10030 if (window.confirm(String.format(Resources.CONFIRM_DELETE, Resources.TITLE_ADDRESS))) { 10031 var url = util.appendParamsToUrl(Urls.deleteAddress, { 10032 AddressID: $form.find('#addressid').val(), 10033 format: 'ajax' 10034 }); 10035 $.ajax({ 10036 url: url, 10037 method: 'POST', 10038 dataType: 'json' 10039 }).done(function (data) { 10040 if (data.status.toLowerCase() === 'ok') { 10041 dialog.close(); 10042 var qParams = util.getQueryStringParams(window.location.search.substr(1)); 10043 if(qParams.cid !== null && qParams.cid == 'billing'){ 10044 location.href = Urls.paymentsList; 10045 } else { 10046 location.href = Urls.addressesList; 10047 } 10048 } else if (data.message.length > 0) { 10049 window.alert(data.message); 10050 return false; 10051 } else { 10052 dialog.close(); 10053 location.href = Urls.addressesList; 10054 } 10055 }); 10056 } 10057 }); 10058 }); 10059} 10060/** 10061 * @private 10062 * @function 10063 * @description Binds the events of the payment methods list (delete card) 10064 */ 10065function initPaymentEvents() { 10066 var $creditCardTypeSelect = $('select[id*="creditcard_type"]'); 10067 10068 // Remove dialog payment add/edit implementation to use page redirect instead 10069 /*$('.add-card').on('click', function (e) { 10070 e.preventDefault(); 10071 dialog.open({ 10072 url: $(e.target).attr('href') 10073 }); 10074 });*/ 10075 10076 $creditCardTypeSelect.off('change.CreditCardTypeDetection').on('change.CreditCardTypeDetection', function (e) { 10077 var $this = $(this); 10078 var paymentInstrumentType = $this.val(); 10079 var $allianceDataFieldDelta = $('input[name*="_owner"], select[name*="_month"], select[name*="_year"], label.expiration-date'); 10080 var $allianceDataDisplayDelta = $('label.expiration-date'); 10081 10082 switch (paymentInstrumentType) { 10083 case PaymentMethodConstants.AllianceData: 10084 $allianceDataFieldDelta.removeClass('required').closest('.formfield').hide(); 10085 $allianceDataDisplayDelta.hide(); 10086 break; 10087 10088 default: 10089 $allianceDataFieldDelta.addClass('required').closest('.formfield').show(); 10090 $allianceDataDisplayDelta.show(); 10091 break; 10092 } 10093 }); 10094 10095 $('.cc-number-container input[type="text"]').off('keyup.CreditCardTypeDetection').on('keyup.CreditCardTypeDetection', function (e) { 10096 var selectedCreditCardType = util.getCreditCardType($(this).val()); 10097 10098 if (selectedCreditCardType) { 10099 $creditCardTypeSelect.val(selectedCreditCardType.PaymentCardDisplayKey); 10100 } else { 10101 $creditCardTypeSelect.val(''); 10102 } 10103 10104 $creditCardTypeSelect.trigger('change.CreditCardTypeDetection'); 10105 }); 10106 10107 $creditCardTypeSelect.trigger('change.CreditCardTypeDetection'); 10108 10109 var paymentList = $('.payment-list'); 10110 if (paymentList.length === 0) { return; } 10111 10112 $('form[name="payment-remove"] button[type="submit"]').on('click', function (e) { 10113 e.preventDefault(); 10114 10115 // override form submission in order to prevent refresh issues 10116 var $button = $(e.target); 10117 10118 // confirm delete 10119 if ($button.hasClass('delete')) { 10120 if (!window.confirm(String.format(Resources.CONFIRM_DELETE, Resources.TITLE_CREDITCARD))) { 10121 return false; 10122 } 10123 } 10124 10125 var $form = $(this).closest('form'); 10126 10127 $('<input/>').attr({ 10128 type: 'hidden', 10129 name: $button.attr('name'), 10130 value: $button.attr('value') || 'delete card' 10131 }).appendTo($form); 10132 var data = $form.serialize(); 10133 $.ajax({ 10134 type: 'POST', 10135 url: $form.attr('action'), 10136 data: data 10137 }) 10138 .done(function () { 10139 page.redirect(Urls.paymentsList); 10140 }); 10141 }); 10142} 10143/** 10144 * @private 10145 * @function 10146 * @description init events for the loginPage 10147 */ 10148function initLoginPage() { 10149 //o-auth binding for which icon is clicked 10150 $('.oAuthIcon').bind('click', function () {
10151 $('#OAuthProvider').val(this.id); 10152 }); 10153 $('.btn-lookup-order').on('click', function (e) { 10154 e.preventDefault(); 10155 $('div.check-order-content').slideDown(); 10156 $(this).slideUp(); 10157 }); 10158 $('#password-reset-rewards').on('click', function (e) { 10159 e.preventDefault(); 10160 dialog.open({ 10161 url: $(e.target).attr('href'), 10162 target : $(".password-reset-dialog-container"), 10163 options: { 10164 dialogClass: 'select-rewards-number-popup', 10165 width: 385, 10166 open: function () { 10167 validator.init(); 10168 var $requestPasswordForm = $('[name$="_requestpassword"]'), 10169 $submit = $requestPasswordForm.find('[name$="_requestpassword_send"]'), 10170 $resetPasswordForm = $('[name$="_resetpassword"]'); 10171 $($submit).on('click', function (e) { 10172 if (!$requestPasswordForm.valid()) { 10173 return; 10174 } 10175 }); 10176 if ( $resetPasswordForm.length > 0 ) { 10177 $resetPasswordForm.find("button[type=submit]").on('click', function (e) { 10178 e.preventDefault(); 10179 var nameAttr = $(this).attr('name'); 10180 dialog.submit(nameAttr); 10181 }); 10182 } 10183 $(".reset-password-heading-close-btn").on('click',function(){ 10184 $("button.ui-dialog-titlebar-close").click(); 10185 }); 10186 execBarCodeGeneration(); 10187 } 10188 } 10189 }); 10190 }); 10191 if ( $('#password-reset-rewards').length > 0 ) { 10192 var ct = 0; 10193 while(ct < 2) { 10194 ct++; 10195 $('#password-reset-rewards').click(); 10196 } 10197 } 10198} 10199 10200/** 10201 * @private 10202 * @function 10203 * @description Binds the events of the order, address and payment pages 10204 */ 10205function initializeEvents() { 10206 toggleFullOrder(); 10207 initAddressEvents(); 10208 initPaymentEvents(); 10209 initLoginPage(); 10210 initCreateAccountEventHandlers(); 10211 if (util.isMobile()) { 10212 util.limitInputToLength('#CreditCardForm input[name*="_number"]', 16); 10213 } 10214 10215 var blurFields = "#dwfrm_profile_customer_email, #dwfrm_profile_customer_emailconfirm, input[id*=dwfrm_profile_login_password_], input[id*=dwfrm_profile_login_passwordconfirm_]"; 10216 $(blurFields).blur(function(){ 10217 if ( $(this).val() == '' ) { 10218 if ( $(this).parents('.form-row').find( '.form-caption.error-message' ).length ) { 10219 $(this).parents('.form-row').find( '.form-caption.error-message' ).html(''); 10220 } 10221 } 10222 }); 10223} 10224 10225function execBarCodeGeneration() { 10226 if ($('.rewardsregistrationconfirmation').length > 0) { 10227 var barcodeNumber = ""+$('.rewardsregistrationconfirmation').find("[data-rewardsnumber]").data('rewardsnumber'); 10228 var barcodeType = 'code128'; 10229 10230 $("#barcodeTarget").barcode(barcodeNumber, barcodeType, { 10231 barHeight:'75', 10232 barWidth:'2', 10233 fontSize:'14', 10234 fontWeight:'bold', 10235 output:'bmp' 10236 }); 10237 } 10238} 10239 10240function initRewardsPage() { 10241 $(window).on('load', function() { 10242 execBarCodeGeneration(); 10243 }); 10244} 10245 10246$(window).on("message", function(e) { 10247 var data = e.originalEvent.data; 10248 if(data == "error"){ 10249 $(".menu-utility-user").addClass("loginError"); 10250 } 10251}); 10252 10253function renderOptions(optionParent, optionsStoreId) { 10254 var options = ''; 10255 var statesList = JSON.parse($(optionsStoreId + ' option:selected').data('options').replace(/\'/g, '\"')); 10256 10257 statesList.forEach(function(state){ 10258 options += '<option class="select-option" label="'+state.label+'" value="'+state.code+'">'+state.label+'</option>'; 10259 }); 10260 $(optionParent).empty().append(options); 10261 10262 if (statesList.length <= 1) { 10263 $(optionParent).parent().parent().parent().hide(); 10264 $(optionParent + '_sbm').val($(optionParent).val()).attr('disabled', false); 10265 } else { 10266 $(optionParent).parent().parent().parent().show(); 10267 $(optionParent + '_sbm').attr('disabled', true); 10268 } 10269} 10270 10271function initRewardRegisterForm() { 10272 $(document).ready(function() { 10273 var $rewardRegisterForm = $('#dwfrm_rewardsregistration'); 10274 if ($rewardRegisterForm.length > 0) { 10275 $rewardRegisterForm.find('#dwfrm_rewardsregistration_rewardscustomer_phone').rules('add', { 10276 phone: true 10277 }); 10278 $rewardRegisterForm.find('#dwfrm_rewardsregistration_rewardscustomeraddress_zipcode').rules('add', { 10279 postal: true 10280 }); 10281 $rewardRegisterForm.find('#dwfrm_rewardsregistration_rewardscustomer_email').rules('add', { 10282 requireEmailExtension: true 10283 }); 10284 $rewardRegisterForm.find('#dwfrm_rewardsregistration_rewardscustomer_emailconfirm').rules('add', { 10285 requireEmailExtension: true, 10286 equalTo: '#dwfrm_rewardsregistration_rewardscustomer_email' 10287 }); 10288 10289 $rewardRegisterForm.on('keyup', '#dwfrm_rewardsregistration_rewardscustomer_email', function(event) { 10290 var serverErrorMessage = $(event.target).closest('.form-row').find('.error-message'); 10291 if (serverErrorMessage.length > 0) { 10292 serverErrorMessage.remove(); 10293 } 10294 }); 10295 } 10296 }); 10297} 10298 10299function initRewardsAttached() { 10300 $(window).on('load', function() { 10301 if ($('#rewardsCheckBalance #fieldRewardsNumber').val() != '') { 10302 $('#rewardsCheckBalance input[type="submit"]').trigger('click'); 10303 } 10304 }); 10305} 10306 10307function getStatusDetails(status) { 10308 var statusLevel = "B.REWARDED"; 10309 var tooltip = "Earn 1 point for every dollar spent." 10310 var rewardsStatus = status.toLowerCase(); 10311 if (rewardsStatus != "bbreward" && rewardsStatus != "basic"){ 10312 statusLevel = "B.REWARDED " + status; 10313 if (rewardsStatus == "gold"){ 10314 tooltip = "Earn 1.25 points for every dollar spent." 10315 } else { 10316 tooltip = "Earn 2 points for every dollar spent." 10317 } 10318 } 10319 10320 return { 10321 statusLevel: statusLevel, 10322 tooltip: tooltip 10323 }; 10324} 10325 10326function initDisplayRewardsData() { 10327 $.ajax({ 10328 url: Urls.getRewardInfoForRegistered, 10329 dataType: 'JSON', 10330 method: 'POST', 10331 data : { 10332 'csrf_token': $('.account-overview input[name="csrf_token"]').val(), 10333 'rewardsNumber': $('.attached-rewards-account .rewards-number').text(), 10334 'email': $('.attached-rewards-account.email-address').text(), 10335 'zipcode': $('.attached-rewards-account.zip-code').text(), 10336 'phone': $('.attached-rewards-account.phone-number').text() 10337 }, 10338 success : function(data) { 10339 if ('error' in data && data['error']) { 10340 $('.myaccount-contact-custserv').removeClass('hidden'); 10341 } else { 10342 if (data.securityRisk) { 10343 $('.myaccount-contact-custserv').removeClass('hidden'); 10344 } else { 10345 var statusDetails = getStatusDetails(data.rewardsStatus); 10346 10347 $('#active-rewards').removeClass('hidden'); 10348 $('.attached-rewards-account .tooltiptext .points-earned').html(statusDetails.tooltip); 10349 $('.attached-rewards-account.status').html(statusDetails.statusLevel); 10350 $('.attached-rewards-account.available-rewards').html("$" + parseFloat(data.creditAmount).toFixed(0)); 10351 $('.attached-rewards-account.current-points').html(data.pointBalance); 10352 } 10353 } 10354 }, 10355 complete: function(data, status, xhr) { 10356 if (data.status == 302 && data.responseText) { 10357 location.href = data.responseText; 10358 } 10359 } 10360 }); 10361} 10362 10363function initRewardCheckForm() { 10364 $(document).ready(function() { 10365 $('#rewardsSelect1').selectmenu(); 10366 $('#rewardsSelect2').selectmenu(); 10367 $('body').on('click', '#rewardsSelect1-menu .ui-menu-item-wrapper', function(){ 10368 var select1text = $(this).text(); 10369 10370 if (select1text == "B Rewarded" || select1text == "Rewards Number" ) { 10371 $('#rewardsCheckBalance .brewarded-number').removeClass('hidden'); 10372 $('#rewardsCheckBalance .rewards-number').removeClass('hidden'); 10373 $('#rewardsCheckBalance .email-address').addClass('hidden'); 10374 $('#rewardsSelect1-button').addClass('hidden'); 10375 } 10376 10377 if (select1text == "Email Address") { 10378 $('#rewardsCheckBalance .email-address').removeClass('hidden'); 10379 $('#rewardsCheckBalance .brewarded-number').addClass('hidden'); 10380 $('#rewardsCheckBalance .rewards-number').addClass('hidden'); 10381 $('#rewardsSelect1-button').addClass('hidden'); 10382 } 10383 }); 10384 10385 $('body').on('click', '#rewardsSelect2-menu .ui-menu-item-wrapper', function(){ 10386 var select2text = $(this).text(); 10387 10388 if (select2text == "Zip Code") { 10389 $('#rewardsCheckBalance .zip-code').removeClass('hidden'); 10390 $('#rewardsCheckBalance .phone-number').addClass('hidden'); 10391 $('#rewardsSelect2-button').addClass('hidden'); 10392 } 10393 10394 if (select2text == "Phone Number") { 10395 $('#rewardsCheckBalance .phone-number').removeClass('hidden'); 10396 $('#rewardsCheckBalance .zip-code').addClass('hidden'); 10397 $('#rewardsSelect2-button').addClass('hidden'); 10398 } 10399 }); 10400 10401 var $rewardCheckForm = $('#rewardsCheckBalance'); 10402 if ($rewardCheckForm.length > 0) { 10403 $rewardCheckForm.find('#fieldRewardsNumber').rules('add', { 10404 positivenumber: true 10405 }); 10406 $rewardCheckForm.find('#fieldRewardsEmail').rules('add', { 10407 requireEmailExtension: true 10408 }); 10409 $rewardCheckForm.find('#fieldRewardsZipcode').rules('add', { 10410 postal: true 10411 }); 10412 $rewardCheckForm.find('#fieldRewardsPhone').rules('add', { 10413 phone: true 10414 }); 10415 10416 $('#rewardsCheckBalance #resetRewardsInquiry').on('click', function(event) { 10417 event.preventDefault(); 10418 $('.ui-selectmenu-text').text('Select One'); 10419 $('#rewardsSelect1-button').removeClass('hidden'); 10420 $('#rewardsSelect2-button').removeClass('hidden'); 10421 $('#rewardsCheckBalance .form-row').addClass('hidden').find('input.input-text').val(''); 10422 $('#sendRewardsInquiry').attr('disabled', true); 10423 $('.rewards-results').html(''); 10424 }); 10425 10426 $('#rewardsCheckBalance').on('change', 'input.input-text', function() { 10427 if ( $('#fieldRewardsNumber').val() || $('#fieldRewardsEmail').val() ) { 10428 if ( $('#fieldRewardsZipcode').val() || $('#fieldRewardsPhone').val() ){ 10429 $('#sendRewardsInquiry').removeAttr('disabled'); 10430 } 10431 } 10432 }); 10433 10434 $rewardCheckForm.find('input#sendRewardsInquiry').on('click', function(event) { 10435 event.preventDefault(); 10436 var $resultsContainer = $('.rewards-results'); 10437 10438 $resultsContainer.html(''); 10439 10440 if (!$rewardCheckForm.valid()) { 10441 return false;
10442 } 10443 10444 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 10445 $.ajax({ 10446 url: Urls.getRewardInfo, 10447 dataType: 'JSON', 10448 method: 'POST', 10449 data: { 10450 'csrf_token': $rewardCheckForm.find('input[name="csrf_token"]').val(), 10451 'rewardsNumber': $rewardCheckForm.find('#fieldRewardsNumber').val(), 10452 'email': $rewardCheckForm.find('#fieldRewardsEmail').val(), 10453 'zipcode': $rewardCheckForm.find('#fieldRewardsZipcode').val(), 10454 'phone': $rewardCheckForm.find('#fieldRewardsPhone').val() 10455 }, 10456 success : function(data) { 10457 if ('error' in data && data['error']) { 10458 $resultsContainer.append('<p class="error-block">'+data['message']+'</p>'); 10459 $('.rewards-contact-custserv').removeClass('hidden'); 10460 } else { 10461 $('#rewards-dashboard').show(); 10462 if (data.securityRisk) { 10463 $('.rewards-contact-custserv').removeClass('hidden'); 10464 } else { 10465 $('.display-rewards').removeClass('hidden'); 10466 if ( $('#goToCreditTwo').length < 1 ) { 10467 renderRewardCheckResults(data, $resultsContainer); 10468 } 10469 } 10470 $('.rewards-details').hide(); 10471 } 10472 }, 10473 complete: function(data, status, xhr) { 10474 if (data.status == 302 && data.responseText) { 10475 location.href = data.responseText; 10476 } 10477 } 10478 }); 10479 } 10480 }); 10481 } 10482 }); 10483} 10484 10485function renderRewardCheckResults(data, $resultsContainer) { 10486 var rewardsCreditAmount = $('.available-rewards').data('credit'); 10487 var pointsRequired = $('.available-rewards').data('required'); 10488 var pointsNeeded = pointsRequired-data.pointBalance; 10489 var pointsText = data.pointBalance == 1 ? ' PT ' : ' PTS '; 10490 var statusDetails = getStatusDetails(data.rewardsStatus); 10491 10492 10493 $('#rewards-number').text("#" + data.rewardsNumber).removeClass('loader'); 10494 $('.rewards-status div').text(statusDetails.statusLevel).removeClass('loader'); 10495 $('#rewards-earned').text("$" + (Math.floor(parseFloat(data.pointsEarnedInLastYear/pointsRequired))*15).toFixed(2)); 10496 $('.rewards-message div').removeClass('loader'); 10497 $('#rewards-credit').show().html("$" + parseFloat(data.creditAmount).toFixed(0)).removeClass('loader'); 10498 if (data.creditAmount != 0){ 10499 $('#rewards-expiration').show().find('span').text(data.creditExpirationDate); 10500 } else { 10501 $('.rewards-zero-message').show(); 10502 } 10503 $('.available-points div').removeClass('loader'); 10504 $('.points-accrued').removeClass('loader').html(data.pointBalance); 10505 $('.tooltiptext .points-earned').text(statusDetails.tooltip); 10506} 10507 10508function initDisplayLoyaltyData() { 10509 if ($('.pt_account').length > 0) { 10510 $.ajax({ 10511 url: Urls.loyaltyCheck, 10512 dataType: 'JSON', 10513 method: 'POST', 10514 data: { 10515 'loyaltyNumber': $('.settings--loyalty').attr('data-number'), 10516 'loyaltyZip': $('.settings--loyalty').attr('data-zip') 10517 }, 10518 success : function(data) { 10519 if (('error' in data && data['error'])) { 10520 $('.loyalty-error').text(data.message); 10521 } else { 10522 renderLoyaltyInfo(data.status); 10523 } 10524 }, 10525 complete: function(data, status, xhr) { 10526 if (data.status == 302 && data.responseText) { 10527 location.href = data.responseText; 10528 } 10529 } 10530 }); 10531 } 10532} 10533 10534function renderLoyaltyInfo(data) { 10535 var optinStatus = data.optIn; 10536 10537 if (optinStatus){ 10538 $('.loyalty-number span.value').text(data.loyaltyMemberNumber); 10539 $('.current-points span.value').text(Math.floor(data.points)); 10540 $('.available-rewards span.value').text("$" + data.totalRewards); 10541 } else { 10542 $('.settings--loyalty').hide(); 10543 } 10544} 10545 10546function clearLoyaltyForm() { 10547 $('.check-my-balance').show(); 10548 $('.my-balance').hide(); 10549 $('.ui-selectmenu-text').text('Select One'); 10550 $('#loyaltySelect1-button').removeClass('hidden'); 10551 $('#loyaltySelect2-button').removeClass('hidden'); 10552 $('#loyaltyCheckBalance .form-row').addClass('hidden').find('input.input-text').val(''); 10553 $('#sendLoyaltyInquiry').attr('disabled', true); 10554 $('.loyalty-results span').text(''); 10555 $('.loyalty-error').html(''); 10556} 10557 10558function initLoyaltyCheckForm() { 10559 if ($('.pt_loyalty').length > 0) { 10560 $('#loyaltySelect1').selectmenu(); 10561 $('#loyaltySelect2').selectmenu(); 10562 10563 $('body').on('click', '#loyaltySelect1-menu .ui-menu-item-wrapper', function(){ 10564 var select1text = $(this).text(); 10565 10566 if (select1text == "Loyalty Number" ) { 10567 $('#loyaltyCheckBalance .brewarded-number').removeClass('hidden'); 10568 $('#loyaltyCheckBalance .loyalty-number').removeClass('hidden'); 10569 $('#loyaltyCheckBalance .email-address').addClass('hidden'); 10570 $('#loyaltySelect1-button').addClass('hidden'); 10571 } 10572 10573 if (select1text == "Email Address") { 10574 $('#loyaltyCheckBalance .email-address').removeClass('hidden'); 10575 $('#loyaltyCheckBalance .brewarded-number').addClass('hidden'); 10576 $('#loyaltyCheckBalance .loyalty-number').addClass('hidden'); 10577 $('#loyaltySelect1-button').addClass('hidden'); 10578 } 10579 }); 10580 10581 $('body').on('click', '#loyaltySelect2-menu .ui-menu-item-wrapper', function(){ 10582 var select2text = $(this).text(); 10583 10584 if (select2text == "Zip Code") { 10585 $('#loyaltyCheckBalance .zip-code').removeClass('hidden'); 10586 $('#loyaltyCheckBalance .phone-number').addClass('hidden'); 10587 $('#loyaltySelect2-button').addClass('hidden'); 10588 } 10589 10590 if (select2text == "Phone Number") { 10591 $('#loyaltyCheckBalance .phone-number').removeClass('hidden'); 10592 $('#loyaltyCheckBalance .zip-code').addClass('hidden'); 10593 $('#loyaltySelect2-button').addClass('hidden'); 10594 } 10595 }); 10596 10597 var $loyaltyCheckForm = $('#loyaltyCheckBalance'); 10598 if ($loyaltyCheckForm.length > 0) { 10599 $loyaltyCheckForm.find('#fieldLoyaltyNumber').rules('add', { 10600 positivenumber: true 10601 }); 10602 $loyaltyCheckForm.find('#fieldLoyaltyEmail').rules('add', { 10603 requireEmailExtension: true 10604 }); 10605 $loyaltyCheckForm.find('#fieldLoyaltyZipcode').rules('add', { 10606 postal: true 10607 }); 10608 $loyaltyCheckForm.find('#fieldLoyaltyPhone').rules('add', { 10609 phone: true 10610 }); 10611 10612 $('#loyaltyCheckBalance #resetLoyaltyInquiry').on('click', function(event) { 10613 event.preventDefault(); 10614 clearLoyaltyForm(); 10615 }); 10616 10617 var scrollMinus = 0; 10618 if ($('.voucher').length > 8 ){ 10619 scrollMinus = 100; 10620 } 10621 if ($(window).width() < 767) { 10622 scrollMinus = 190; 10623 } 10624 10625 $('.my-balance #startOverLoyalty').on('click', function() { 10626 clearLoyaltyForm(); 10627 if (scrollMinus > 0) { 10628 $('html,body').animate({scrollTop: $(".tab").offset().top - scrollMinus}, 200); 10629 } 10630 }); 10631 10632 $('#loyaltyCheckBalance').on('change', 'input.input-text', function() { 10633 if ( $('#fieldLoyaltyNumber').val() || $('#fieldLoyaltyEmail').val() ) { 10634 if ( $('#fieldLoyaltyZipcode').val() || $('#fieldLoyaltyPhone').val() ){ 10635 $('#sendLoyaltyInquiry').removeAttr('disabled'); 10636 } 10637 } 10638 }); 10639 10640 $loyaltyCheckForm.find('input#sendLoyaltyInquiry').on('click', function(event) { 10641 event.preventDefault(); 10642 10643 if (!$loyaltyCheckForm.valid()) { 10644 return false;
10645 } 10646 10647 $.ajax({ 10648 url: Urls.loyaltyCheck, 10649 dataType: 'JSON', 10650 method: 'POST', 10651 data: { 10652 'loyaltyNumber': $loyaltyCheckForm.find('#fieldLoyaltyNumber').val(), 10653 'loyaltyEmail': $loyaltyCheckForm.find('#fieldLoyaltyEmail').val(), 10654 'loyaltyZip': $loyaltyCheckForm.find('#fieldLoyaltyZipcode').val(), 10655 'loyaltyPhone': $loyaltyCheckForm.find('#fieldLoyaltyPhone').val() 10656 }, 10657 success : function(data) { 10658 if (('error' in data && data['error'])) { 10659 $('.loyalty-error').text(data.message); 10660 } else { 10661 renderLoyaltyCheckResults(data.status); 10662 } 10663 }, 10664 complete: function(data, status, xhr) { 10665 if (data.status == 302 && data.responseText) { 10666 location.href = data.responseText; 10667 } 10668 } 10669 }); 10670 }); 10671 } 10672 } 10673} 10674 10675function renderLoyaltyCheckResults(data) { 10676 var optinStatus = data.optIn; 10677 var currentSite = ''; 10678 if (pageContext.site === SiteConstants.SiteIds.SheplersUS) { 10679 currentSite = Resources.LoyaltyCredit.NotOptedInSHEP; 10680 } 10681 if (pageContext.site === SiteConstants.SiteIds.CountryOutfittersUS) { 10682 currentSite = Resources.LoyaltyCredit.NotOptedInCO; 10683 } 10684 10685 if (optinStatus){ 10686 $('.check-my-balance').hide(); 10687 $('.my-balance').removeClass('hidden').show(); 10688 $('.loyalty-number span').text(data.loyaltyMemberNumber); 10689 $('.current-points span').text(Math.floor(data.points)); 10690 $('.available-rewards span').text("$" + data.totalRewards); 10691 var details = ''; 10692 var vouchers = data.rewardInfo; 10693 10694 vouchers.forEach(function(voucher){ 10695 details += '<div class="voucher"><span class="reward-amount">Reward Amount: <b>$'+voucher.rewardAmount+'</b></span><span class="expiration">Expiration Date: <b>'+voucher.expirationDate+'</b></span></div>'; 10696 }); 10697 10698 $('.details').html(details); 10699 } else { 10700 $('.loyalty-error').text(currentSite); 10701 } 10702} 10703 10704function initLoyaltySocial() { 10705 var handle = ''; 10706 10707 $('body').on('focus', '#fieldLoyaltySocialHandleInstagram', function() { 10708 $('.handle-error').text(''); 10709 }); 10710 10711 $('body').on('click', '#updateInstagramHandle', function(){ 10712 $('.handle-display').removeClass('show-handle').addClass('show-form'); 10713 $('.form-display').removeClass('show-handle').addClass('show-form'); 10714 }); 10715 10716 $('body').on('click', '#addInstagramHandle', function(){ 10717 event.preventDefault(); 10718 10719 var formValidation = true; 10720 var handle = $('#fieldLoyaltySocialHandleInstagram').val(); 10721 var regexHandle = /^@([a-zA-Z0-9]|[._](?![._])){2,30}$/; 10722 if (String(handle).match(regexHandle) == null ) { 10723 formValidation = false; 10724 } 10725 10726 if (formValidation) { 10727 $.ajax({ 10728 url: Urls.loyaltyOptin, 10729 dataType: 'JSON', 10730 method: 'POST', 10731 data: { 10732 'email': $('.settings--loyalty').attr('data-email'), 10733 'dwCustomerID': $('.settings--loyalty').attr('data-dwid'), 10734 'instaHandle': handle, 10735 'optStatus': $('.settings--loyalty').attr('data-optin') 10736 }, 10737 success : function(data) { 10738 if (('error' in data && data['error'])) { 10739 $('.handle-error').text(data.message); 10740 } else { 10741 $('.handle-display').removeClass('show-form').addClass('show-handle'); 10742 $('.handle-display .value').text(handle); 10743 $('.form-display').removeClass('show-form').addClass('show-handle'); 10744 } 10745 } 10746 }); 10747 } else { 10748 $('.handle-error').text('Please enter a valid social handle.'); 10749 } 10750 }); 10751} 10752 10753function initAddressFormEvents() { 10754 $(document).ready(function(){ 10755 $(document).on('change', '#dwfrm_profile_address_country', function(){ 10756 renderOptions('#dwfrm_profile_address_states_state', '#dwfrm_profile_address_country'); 10757 var $initialState = $('#dwfrm_profile_address_states_state_sbm'); 10758 10759 if ($initialState.length > 0 && $initialState.val() != '') { 10760 $('#dwfrm_profile_address_states_state').val($initialState.val()); 10761 } 10762 }); 10763 $('#dwfrm_profile_address_country').trigger('change'); 10764 10765 $(document).on('click', '.find-more-stores a', function () { 10766 findMoreStores.initialize({ view: 'account' }); 10767 }); 10768 10769 $(document).on('opc.SetShippingAddress', function (e, address) { 10770 var $closestStores = $('#closestStores'); 10771 var $makeThisMystore = $('#storeControls').find('[data-action="makethismystore"]'); 10772 10773 $closestStores.find('option.find-more-stores').remove(); 10774 if ($closestStores.find('option[value="' + address.storeId + '"]').length == 0) { 10775 $closestStores.find('option').first().after('<option class="find-more-stores" value="' + address.storeId + '">' + address.firstName + ' - ' + address.labelText + '</option>'); 10776 } 10777 10778 $closestStores.val(address.storeId); 10779 $closestStores.trigger('change'); 10780 if ($makeThisMystore.length > 0) { 10781 $makeThisMystore.trigger('click'); 10782 } 10783 }); 10784 10785 $(document).on('click', '.address-tile .address-delete', function(event) { 10786 event.preventDefault(); 10787 10788 // Clear the previous data in the attributes 10789 $('.address-select-new-dialog .address-dialog-confirm').removeAttr('data-url data-default'); 10790 10791 var $deleteButton = $(this); 10792 var $addressTile = $deleteButton.closest('.address-tile'); 10793 var isDefault = $addressTile.hasClass('default'); 10794 var addressCount = $deleteButton.closest('.address-tiles').find('.address-tile').length; 10795 var addressID = $addressTile.attr('data-address-id'); 10796 var addressSectionType = $deleteButton.closest('.address-tiles').next('.account-address-select').attr('data-address-type'); 10797 var $dialogContent = addressSectionType === 'billing' ? $('#dialog-billing-addresses') : $('#dialog-shipping-addresses'); 10798 10799 if (isDefault) { 10800 $dialogContent.find('.delete-address-select select option[value="'+ addressID +'"]').attr('disabled','disabled').hide(); 10801 } 10802 10803 dialog.open({ 10804 html: $dialogContent.html(), 10805 options: { 10806 dialogClass: 'address-select-new-dialog', 10807 draggable: false, 10808 open: function(event, ui) { 10809 var $this = $(this); 10810 $this.find('.address-dialog-confirm').attr({ 10811 'data-url': $deleteButton.attr('data-url'), 10812 'data-default': isDefault 10813 }); 10814 if (isDefault && addressCount > 1) { 10815 $this.find('.replace-default-address').removeClass('d-none'); 10816 } else { 10817 $this.find('.confirm-delete-address').removeClass('d-none'); 10818 } 10819 }, 10820 close: function(event, ui) { 10821 $('body').removeClass('dialog-open'); 10822 } 10823 } 10824 }); 10825 }); 10826 10827 $(document).on('click', '.delete-address-actions button.address-dialog-confirm', function(event) { 10828 event.preventDefault(); 10829 10830 var $deleteConfirmButton = $(this); 10831 var $dialogContent = $deleteConfirmButton.closest('.address-select-new-dialog'); 10832 var isDefault = $deleteConfirmButton.attr('data-default'); 10833 var url = $deleteConfirmButton.attr('data-url'); 10834 10835 if (isDefault === 'true' && $dialogContent.find('.replace-default-address').is(':visible')) { 10836 var newDefaultAddress = $dialogContent.find('.replace-default-address select').val(); 10837 url = url + '&newDefault=' + newDefaultAddress; 10838 } 10839 10840 window.location.href = url; 10841 }); 10842 10843 $(document).on('click', '.delete-address-actions button.address-dialog-cancel', function(event) { 10844 // Clear the previous data 10845 $('.address-select-new-dialog .address-dialog-confirm').removeAttr('data-url data-default'); 10846 10847 dialog.close(); 10848 }); 10849 }); 10850} 10851 10852function verifyAccountCode() { 10853 // 'enter-code' rules will be applied to rewards verification page with this code. See loginDialog.js for the rules added after account dialog is opened. 10854 $('#verify-code').find('#enter-code').rules('add', { 10855 required: true, 10856 digits: true, 10857 minlength: 6, 10858 messages: {
10859 required: Resources.VALIDATE_CODE, 10860 minlength: Resources.VALIDATE_CODE 10861 }, 10862 normalizer: function(value) { 10863 return $.trim(value); 10864 } 10865 }); 10866} 10867 10868/* On the Account registration (aka settings) page, hook up the event handler to update the hidden form field 10869 * for 'My Store Number' when the (dynamically populated) Closest Stores drop down is changed. 10870 * Also, set the value of the selected option in the drop down, or the value in 'My Store Number' 10871 * appropriately on load (based on if creating an Account or editing one. 10872 */ 10873function initCreateAccountEventHandlers(){ 10874 var $closestStores = $('#closestStores'); 10875 var $storeControls = $('#storeControls'); 10876 if ($closestStores != undefined && $closestStores != null){ 10877 var lengthStores = $closestStores.find('option').length; 10878 if (lengthStores > 0) { 10879 var storedValue = $('#dwfrm_profile_customer_myStoreNumber').val(); 10880 $closestStores.on('change', function(e) { 10881 var newValue = $(this).val(); 10882 $('#dwfrm_profile_customer_myStoreNumber').val(newValue); 10883 updateSelectedStorePreview($(e.target).find(':selected')); 10884 10885 if (storedValue !== newValue) { 10886 $storeControls.removeClass('hidden'); 10887 } else { 10888 $storeControls.addClass('hidden'); 10889 } 10890 }); 10891 10892 setSelectedStoreDropdownOrMyStoreNumber(); 10893 } 10894 $storeControls.on('click', 'a', function(e) { 10895 e.preventDefault(); 10896 var storeId = $('#dwfrm_profile_customer_myStoreNumber').val(); 10897 $.ajax({ 10898 url : Urls.assignStoreId, 10899 data : { store_id : storeId }, 10900 method : "POST", 10901 dataType : "JSON", 10902 success : function(data) { 10903 if ( 'success' in data && data['success'] == true ) { 10904 location.reload(); 10905 } 10906 } 10907 }); 10908 }); 10909 } 10910} 10911 10912/* Check and see if the profile has a value for 'My Store Number', which it might if on the Account Edit page. 10913 * If so, then set the store drop down to the store on the profile. 10914 * If not, then set the hidden form field for 'My Store Number' to the selected store in the drop down, which will be the first one when on the Create Account page. 10915 */ 10916function setSelectedStoreDropdownOrMyStoreNumber() { 10917 var $myStoreNumberSelected = $('#dwfrm_profile_customer_myStoreNumber'); 10918 if ($myStoreNumberSelected != undefined && $myStoreNumberSelected != null){ 10919 var currentMyStoreValue = $myStoreNumberSelected.val(); 10920 if (currentMyStoreValue == undefined || currentMyStoreValue == null || currentMyStoreValue.length == 0){ 10921 $myStoreNumberSelected.val($('#closestStores').val()); 10922 } else { 10923 $('#closestStores option[value=' + currentMyStoreValue + ']').attr('selected','selected'); 10924 updateSelectedStorePreview($('#closestStores option[value=' + currentMyStoreValue + ']')); 10925 } 10926 $('#storeSection').removeClass('hidden'); 10927 } 10928} 10929 10930function updateSelectedStorePreview($store) { 10931 if ($('#selectedStore').length > 0) { 10932 $('#selectedStore .name').text($store.data('name')); 10933 $('#selectedStore .address1').text($store.data('address1')); 10934 if ($store.data('address2') && $store.data('address2').length > 0) { 10935 $('#selectedStore .address2').text($store.data('address2')).removeClass('hidden'); 10936 } else { 10937 $('#selectedStore .address2').text('').addClass('hidden'); 10938 } 10939 10940 $('#selectedStore .city').text($store.data('city')); 10941 $('#selectedStore .stateCode').text($store.data('statecode')); 10942 $('#selectedStore .postalCode').text($store.data('postalcode')); 10943 $('#selectedStore .countryCode').text($store.data('countrycode')); 10944 $('#selectedStore .phone').text($store.data('phone')); 10945 } 10946} 10947 10948 10949 10950module.exports = { 10951 init: function (optionsParameter) { 10952 options = optionsParameter; 10953 10954 if (options && options.Lob && options.Lob.AddressVerification.Enabled) { 10955 AddressVerificationDialog = require('../Lob/AddressVerification/AddressVerificationDialog'); 10956 } 10957 10958 if (options && options.Lob && options.Lob.AddressAutocomplete.Enabled) { 10959 AddressAutocompleteDialog = require('../Lob/AddressAutocomplete/AddressAutocompleteDialog'); 10960 } 10961 10962 initializeEvents(); 10963 giftcert.init(); 10964 initAddressFormEvents(); 10965 initRewardRegisterForm(); 10966 initRewardCheckForm(); 10967 initLoyaltyCheckForm(); 10968 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 10969 initDisplayRewardsData(); 10970 }
10971 if ((pageContext.site === SiteConstants.SiteIds.CountryOutfittersUS || pageContext.site === SiteConstants.SiteIds.SheplersUS) && SitePreferences.LOYALTY_ENABLED) { 10972 initDisplayLoyaltyData(); 10973 initLoyaltySocial(); 10974 } 10975 initRewardsAttached(); 10976 verifyAccountCode(); 10977 orderStatusForm.initialize($('#dwfrm_ordertrack')); 10978 }, 10979 initCartLogin: function () { 10980 initLoginPage(); 10981 initRewardsPage(); 10982 } 10983}; 10984},{"../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper":112,"../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants":117,"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../Lob/AddressAutocomplete/AddressAutocompleteDialog":1,"../Lob/AddressVerification/AddressVerificationDialog":2,"../components/OrderStatusForm":28,"../components/Recaptcha":29,"../dialog":36,"../findMoreStores":37,"../giftcert":39,"../page":46,"../tooltip":101,"../util":102,"../validator":103}],49:[function(require,module,exports){ 10985'use strict'; 10986 10987var _ = require('lodash'); 10988var GoogleTagManagerClient = require('../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 10989var loadingIndicator = require('../components/LoadingIndicator'); 10990var TemplateConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 10991var util = require('../util'); 10992var ValidationSettings = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 10993var ValidationRules = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 10994var ValidationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 10995 10996var options; 10997var dataBuffer; 10998var $container; 10999var $step; 11000var templates; 11001var loadingIndicatorSettings; 11002 11003exports.init = function (optionsParameter) { 11004 if (optionsParameter) { 11005 options = optionsParameter; 11006 } else { 11007 options = {}; 11008 } 11009 $container = $('.bootfinder'); 11010 $step = $container.find('[step]'); 11011 dataBuffer = { 11012 step: 0, 11013 stepData: {} 11014 }; 11015 templates = { 11016 sectionContainer: _.template($('#template-bootfinder-section-container').html(), TemplateConstants.Lodash.Settings), 11017 section: _.template($('#template-bootfinder-section').html(), TemplateConstants.Lodash.Settings), 11018 option: _.template($('#template-bootfinder-option').html(), TemplateConstants.Lodash.Settings), 11019 optionImage: _.template($('#template-bootfinder-option-image').html(), TemplateConstants.Lodash.Settings), 11020 results: _.template($('#template-bootfinder-results').html(), TemplateConstants.Lodash.Settings) 11021 } 11022 loadingIndicatorSettings = { 11023 IsLabelShown: false 11024 }; 11025 11026 $container.off('click.BootFinderStepDelta').on('click.BootFinderStepDelta', '[step-delta]', function(event) { 11027 var $this = $(this); 11028 var stepDelta = parseInt($this.attr('step-delta'), 10); 11029 dataBuffer.stepDelta = stepDelta; 11030 var step = dataBuffer.step + dataBuffer.stepDelta; 11031 if (step >= 0 && step <= options.Configuration.Steps.length) { 11032 dataBuffer.step = step; 11033 } 11034 render(); 11035 }); 11036 11037 // $container.off('click.BootFinderStepIndex').on('click.BootFinderStepIndex', '[step-index]', function(event) { 11038 // var $this = $(this); 11039 // var step = parseInt($this.attr('step-index'), 10); 11040 // if (step >= 0 && step <= options.Configuration.Steps.length) { 11041 // dataBuffer.step = step; 11042 // } 11043 // render(); 11044 // }); 11045 11046 $container.off('click.BootFinderStepOptions').on('click.BootFinderStepOptions', '[step] .options .option', function(event) { 11047 var $this = $(this); 11048 var sectionIndex = parseInt($this.closest('[section]').attr('section'), 10); 11049 if ($this.hasClass('selected') && !options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].SelectRequired) { 11050 $this.removeClass('selected'); 11051 if (dataBuffer.stepData[dataBuffer.step] && dataBuffer.stepData[dataBuffer.step][sectionIndex]) { 11052 var selectedIndex = dataBuffer.stepData[dataBuffer.step][sectionIndex].indexOf($this.attr('value')); 11053 if (selectedIndex > -1) { 11054 dataBuffer.stepData[dataBuffer.step][sectionIndex].splice(selectedIndex, 1); 11055 } 11056 } 11057 if (options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].Refinement == 'size' || options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].Refinement == 'width') { 11058 updateSizes(sectionIndex, options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex]); 11059 } 11060 } else { 11061 if (!options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].SelectMultiple) { 11062 $this.closest('.options').find('.option').removeClass('selected'); 11063 } 11064 if (options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].SelectReset && (dataBuffer.step + 1) <= options.Configuration.Steps.length) { 11065 for (var stepIndex = (dataBuffer.step + 1); stepIndex <= options.Configuration.Steps.length; stepIndex++) { 11066 dataBuffer.stepData[stepIndex] = {}; 11067 } 11068 } 11069 $this.addClass('selected'); 11070 if (!dataBuffer.stepData[dataBuffer.step]) { 11071 dataBuffer.stepData[dataBuffer.step] = {} 11072 } 11073 if (!dataBuffer.stepData[dataBuffer.step][sectionIndex] || !options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].SelectMultiple) { 11074 dataBuffer.stepData[dataBuffer.step][sectionIndex] = []; 11075 } 11076 var sectionData = dataBuffer.stepData[dataBuffer.step][sectionIndex]; 11077 sectionData[sectionData.length] = $this.attr('value'); 11078 if (options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].Refinement == 'size' || options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].Refinement == 'width') { 11079 updateSizes(sectionIndex, sectionData); 11080 } 11081 } 11082 11083 if (!options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].SelectMultiple && $this.closest('.options').find('.selected').length > 0 && dataBuffer.step < (options.Configuration.Steps.length - 1)) { 11084 dataBuffer.stepDelta = 1; 11085 dataBuffer.step += dataBuffer.stepDelta; 11086 render(); 11087 } 11088 }); 11089 11090 $container.off('click.BootFinderSendResultsEmail').on('click.BootFinderSendResultsEmail', '.send-results-email', function(event) { 11091 event.preventDefault(); 11092 11093 var $this = $(this); 11094 var $form = $this.closest('form'); 11095 if (dataBuffer.$emailForm && dataBuffer.$emailForm.valid()) { 11096 var url = buildUrl(); 11097 url = util.appendParamToURL(url, 'bootfinderemail'); 11098 11099 var payload = { 11100 email: $form.find('input[type="email"]').val(), 11101 url: url 11102 } 11103 $step.loading($.extend(loadingIndicatorSettings, { 11104 IsLabelShown: true, 11105 Content: 'Sending Email...' 11106 })); 11107 $.ajax({ 11108 type: 'post', 11109 data: payload, 11110 url: buildUrl(Urls.BootFinder.SendResultsEmail), 11111 success: function(data) { 11112 if (data && data.success) { 11113 $step.find('.loading-indicator').find('.content').html('Email Sent!<br/>Loading Results...'); 11114 window.location = $('.view-results').attr('href'); 11115 } else { 11116 $container.find('.validation-error-container').html('<span class="error">An error occurred sending the email. Please try again.</span>'); 11117 } 11118 } 11119 }); 11120 } 11121 }); 11122 11123 $container.off('click.BootFinderViewResults').on('click.BootFinderViewResults', '.view-results', function(event) { 11124 if (!$step.attr('loading')) { 11125 $step.loading($.extend(loadingIndicatorSettings, { 11126 Content: 'Loading Results...' 11127 })); 11128 var url = buildUrl(); 11129 url = util.appendParamToURL(url, 'bootfinderviewresults'); 11130 window.location = url; 11131 } 11132 }); 11133 11134 $(window).off('load.BootFinder resize.BootFinder').on('load.BootFinder resize.BootFinder', function(event) { 11135 if ($(window).outerWidth() <= 768) { 11136 $container.css('min-height', $(window).outerHeight() - $('.header-wrapper').height()); 11137 } else { 11138 $container.css('min-height', 0); 11139 } 11140 }); 11141 11142 var stepListHtml = ''; 11143 for (var stepIndex in options.Configuration.Steps) { 11144 stepListHtml += '<a step-index="' + stepIndex + '"></a>'; 11145 } 11146 $container.find('.step-list').html(stepListHtml); 11147 render(); 11148}; 11149 11150function render() { 11151 $step.height($step.outerHeight()); 11152 $step.html(''); 11153 $step.loading(loadingIndicatorSettings); 11154 $('html').animate({ scrollTop: 0 }, 250); 11155 if (dataBuffer.step == (options.Configuration.Steps.length - 1)) { 11156 $container.find('.next').hide(); 11157 $container.find('.view-results').show(); 11158 } else { 11159 $container.find('.next').show(); 11160 $container.find('.view-results').hide(); 11161 }
11162 renderStep(); 11163 sendDataLayer(); 11164 if ($container.hasClass('results')) { 11165 $container.removeClass('results'); 11166 } 11167 11168 $container.find('.step-list a').removeClass('active'); 11169 $container.find('.step-list a:nth-child(' + (dataBuffer.step + 1) + ')').addClass('active'); 11170 $container.find('[step]').attr('step', dataBuffer.step); 11171} 11172 11173function updateSizes(sectionIndex, sectionData) { 11174 return getRefinementCountsForSection(sectionIndex, sectionData).then(function(data) { 11175 if (options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex] && options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].Refinement == 'size') { 11176 var $selectedLengths = $('[section="' + sectionIndex + '"] .options').find('.option.selected'); 11177 var $widths = $('[section="' + (sectionIndex + 1) + '"] .options .option'); 11178 if ($selectedLengths && $selectedLengths.length > 0) { 11179 $widths.addClass('disabled'); 11180 $selectedLengths.each(function() { 11181 var selectedLength = $(this).attr('value'); 11182 $widths.each(function() { 11183 var width = $(this).attr('value'); 11184 var size = selectedLength + ' ' + width; 11185 if (dataBuffer.Refinements && dataBuffer.Refinements.size && dataBuffer.Refinements.size[size]) { 11186 $widths.filter('[value="' + width + '"]').removeClass('disabled'); 11187 } 11188 }); 11189 }); 11190 } else { 11191 $widths.removeClass('disabled'); 11192 } 11193 } else if (options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex] && options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex].Refinement == 'width') { 11194 var $selectedWidths = $('[section="' + sectionIndex + '"] .options').find('.option.selected'); 11195 var $lengths = $('[section="' + (sectionIndex - 1) + '"] .options .option'); 11196 if ($selectedWidths && $selectedWidths.length > 0) { 11197 $lengths.addClass('disabled'); 11198 $selectedWidths.each(function() { 11199 var selectedWidth = $(this).attr('value'); 11200 $lengths.each(function() { 11201 var length = $(this).attr('value'); 11202 var size = length + ' ' + selectedWidth; 11203 if (dataBuffer.Refinements && dataBuffer.Refinements.size && dataBuffer.Refinements.size[size]) { 11204 $lengths.filter('[value="' + length + '"]').removeClass('disabled'); 11205 } 11206 }); 11207 }); 11208 } else { 11209 $lengths.removeClass('disabled'); 11210 } 11211 } 11212 }); 11213} 11214
11215function renderStep() { 11216 var step = options.Configuration.Steps[dataBuffer.step]; 11217 var stepData; 11218 if (dataBuffer.stepData && dataBuffer.stepData[dataBuffer.step]) { 11219 stepData = dataBuffer.stepData[dataBuffer.step]; 11220 } 11221 dataBuffer.sectionRenderCount = 0; 11222 for (var sectionIndex in step.Sections) { 11223 var section = step.Sections[sectionIndex]; 11224 var columns = 1; 11225 if (section.Columns) { 11226 columns = section.Columns; 11227 } 11228 $container.find('[step]').append(templates.sectionContainer({ 11229 Section: sectionIndex, 11230 Columns: columns 11231 })); 11232 11233 var optionsHtml = ''; 11234 if (section.Options) { 11235 var sectionOptions; 11236 if (typeof section.Options == 'object' && section.OptionsRelatedSelectionStep != undefined && section.OptionsRelatedSelectionSection != undefined && dataBuffer.stepData && dataBuffer.stepData[section.OptionsRelatedSelectionStep] && dataBuffer.stepData[section.OptionsRelatedSelectionStep][section.OptionsRelatedSelectionSection]) { 11237 var optionsRelatedSelectionValue = dataBuffer.stepData[section.OptionsRelatedSelectionStep][section.OptionsRelatedSelectionSection]; 11238 sectionOptions = section.Options[optionsRelatedSelectionValue]; 11239 } else { 11240 sectionOptions = section.Options; 11241 } 11242 for (var optionIndex in sectionOptions) { 11243 var option = sectionOptions[optionIndex]; 11244 if (option.Text) { 11245 var cssClass = ''; 11246 if (stepData && stepData[sectionIndex] && 'indexOf' in stepData[sectionIndex] && stepData[sectionIndex].indexOf(option.Text) > -1) { 11247 cssClass = 'selected'; 11248 } 11249 11250 optionsHtml += templates.option({ 11251 Image: '', 11252 Text: option.Text, 11253 Value: option.Text, 11254 CssClass: cssClass 11255 }); 11256 } 11257 } 11258 renderSection(sectionIndex, section.Header, section.Text, optionsHtml); 11259 } else if (section.Refinement && section.Refinement != 'width') { 11260 getRefinementCountsForSection(sectionIndex, section).then(function(data) { 11261 var optionsHtmlInner = ''; 11262 if (data.Section.Refinement == 'size') { 11263 var lengths = []; 11264 var widths = []; 11265 var widthRegex = / [\w\/]+/gi; 11266 for (var refinementKey in data.Refinements) { 11267 var refinementCount = data.Refinements[refinementKey]; 11268 if (refinementCount) { 11269 var widthRegexResult = refinementKey.match(widthRegex); 11270 var length; 11271 var width; 11272 if (widthRegexResult && widthRegexResult.length) { 11273 width = widthRegexResult[widthRegexResult.length - 1].trim(); 11274 } 11275 if (width) { 11276 length = refinementKey.replace(width, '').trim(); 11277 } 11278 if (length && lengths.indexOf(length) < 0) { 11279 lengths[lengths.length] = length; 11280 } 11281 if (width && widths.indexOf(width) < 0) { 11282 widths[widths.length] = width; 11283 } 11284 } 11285 } 11286 lengths.sort(function(left, right) { 11287 var leftValue = left.replace(/ *1\/2/, '.5'); 11288 var rightValue = right.replace(/ *1\/2/, '.5'); 11289 return parseFloat(leftValue) - parseFloat(rightValue); 11290 }); 11291 11292 widths.sort(function(left, right) { 11293 var leftValue = parseInt(left, 10); 11294 var rightValue = parseInt(right, 10); 11295 if (leftValue) { 11296 leftValue = ''.padStart(leftValue, left.replace(/\d/g, '')[0]); 11297 } else { 11298 leftValue = left; 11299 } 11300 if (rightValue) { 11301 rightValue = ''.padStart(rightValue, right.replace(/\d/g, '')[0]); 11302 } else { 11303 rightValue = right; 11304 } 11305 11306 var leftWidthDescription; 11307 if (options.WidthDescriptionConfiguration && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]] && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'] && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'][left]) { 11308 leftWidthDescription = options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'][left]; 11309 } 11310 11311 var rightWidthDescription; 11312 if (options.WidthDescriptionConfiguration && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]] && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'] && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'][right]) { 11313 rightWidthDescription = options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'][right]; 11314 } 11315 11316 if (leftWidthDescription == 'Medium' && rightWidthDescription != 'Medium') { 11317 return -1; 11318 } else if (leftWidthDescription != 'Medium' && rightWidthDescription == 'Medium') { 11319 return 1; 11320 } 11321 if (leftWidthDescription == 'Wide' && rightWidthDescription != 'Wide') { 11322 return -1; 11323 } else if (leftWidthDescription != 'Wide' && rightWidthDescription == 'Wide') { 11324 return 1; 11325 } 11326 return leftValue.localeCompare(rightValue); 11327 }); 11328 11329 for (var lengthIndex in lengths) { 11330 var length = lengths[lengthIndex]; 11331 var cssClass = ''; 11332 if (stepData && stepData[data.SectionIndex] && 'indexOf' in stepData[data.SectionIndex] && stepData[data.SectionIndex].indexOf(length) > -1) { 11333 cssClass = 'selected'; 11334 } 11335 optionsHtmlInner += templates.option({ 11336 Image: '', 11337 Text: length, 11338 Value: length, 11339 CssClass: cssClass 11340 }); 11341 } 11342 dataBuffer.lengths = lengths; 11343 renderSection(data.SectionIndex, data.Section.Header, data.Section.Text, optionsHtmlInner); 11344 11345 var widthsHtml = ''; 11346 var widthSectionIndex = parseInt(data.SectionIndex, 10) + 1; 11347 for (var widthIndex in widths) { 11348 var width = widths[widthIndex]; 11349 var cssClass = ''; 11350 if (stepData && stepData[widthSectionIndex] && 'indexOf' in stepData[widthSectionIndex] && stepData[widthSectionIndex].indexOf(width) > -1) { 11351 cssClass = 'selected'; 11352 } 11353 var widthDescription = ''; 11354 if (options.WidthDescriptionConfiguration && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]] && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'] && options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'][width]) { 11355 widthDescription = ' (' + options.WidthDescriptionConfiguration[dataBuffer.stepData[0][0]]['Boot'][width] + ')'; 11356 } 11357 widthsHtml += templates.option({ 11358 Image: '', 11359 Text: width + widthDescription, 11360 Value: width, 11361 CssClass: cssClass 11362 }); 11363 } 11364 dataBuffer.widths = widths; 11365 $container.find('[section="' + widthSectionIndex + '"] .options').html(widthsHtml); 11366 updateSizes(sectionIndex, options.Configuration.Steps[dataBuffer.step].Sections[sectionIndex]); 11367 } else { 11368 for (var refinementKey in data.Refinements) { 11369 var refinementCount = data.Refinements[refinementKey]; 11370 if (refinementCount) { 11371 var refinementText; 11372 if (dataBuffer.DisplayValues[data.Section.Refinement] && dataBuffer.DisplayValues[data.Section.Refinement][refinementKey]) { 11373 refinementText = dataBuffer.DisplayValues[data.Section.Refinement][refinementKey]; 11374 } else { 11375 refinementText = refinementKey; 11376 } 11377 11378 var cssClass = ''; 11379 if (stepData && stepData[data.SectionIndex] && 'indexOf' in stepData[data.SectionIndex] && stepData[data.SectionIndex].indexOf(refinementKey) > -1) { 11380 cssClass = 'selected'; 11381 } 11382 11383 var sectionImages; 11384 if (typeof section.Images == 'object' && section.ImagesRelatedSelectionStep != undefined && section.ImagesRelatedSelectionSection != undefined && dataBuffer.stepData && dataBuffer.stepData[section.ImagesRelatedSelectionStep] && dataBuffer.stepData[section.ImagesRelatedSelectionStep][section.ImagesRelatedSelectionSection]) { 11385 var imagesRelatedSelectionValue = dataBuffer.stepData[section.ImagesRelatedSelectionStep][section.ImagesRelatedSelectionSection]; 11386 sectionImages = section.Images[imagesRelatedSelectionValue]; 11387 } else { 11388 sectionImages = section.Images; 11389 } 11390 var imageHtml = ''; 11391 if (sectionImages && sectionImages[refinementKey]) { 11392 imageHtml = templates.optionImage({ 11393 ImageUrl: sectionImages[refinementKey] 11394 }); 11395 } 11396 optionsHtmlInner += templates.option({ 11397 Image: imageHtml, 11398 Text: refinementText, 11399 Value: refinementKey, 11400 CssClass: cssClass 11401 }); 11402 } 11403 } 11404 renderSection(data.SectionIndex, data.Section.Header, data.Section.Text, optionsHtmlInner); 11405 } 11406 }).catch(); 11407 } else { 11408 renderSection(sectionIndex, section.Header, section.Text, optionsHtml); 11409 } 11410 } 11411} 11412
11413function renderSection(index, header, textParameter, sectionOptions) { 11414 dataBuffer.sectionRenderCount++; 11415 var text = ''; 11416 if (textParameter) { 11417 text = '<p>' + textParameter + '</p>'; 11418 } 11419 $container.find('[section="' + index + '"]').html(templates.section({ 11420 Header: header, 11421 Text: text, 11422 Options: sectionOptions 11423 })); 11424 11425 if (dataBuffer.sectionRenderCount == options.Configuration.Steps[dataBuffer.step].Sections.length) { 11426 if ($step.attr('loading')) { 11427 $step.css('height', ''); 11428 $step.loading('destroy'); 11429 $('html').animate({ scrollTop: 0 }, 250); 11430 } 11431 $container.find('[step-delta]').removeClass('disabled'); 11432 if (options.Configuration.Steps[dataBuffer.step].Sections[index].SelectRequired && $('.options').length != $('.options').find('.selected').length) { 11433 $container.find('.next').addClass('disabled'); 11434 } 11435 if (dataBuffer.step == 0) { 11436 $container.find('.back').addClass('disabled'); 11437 } 11438 if ($container.find('.option').length == 0) { 11439 if (dataBuffer.step < (options.Configuration.Steps.length - 1)) { 11440 dataBuffer.step += dataBuffer.stepDelta; 11441 render(); 11442 } else { 11443 $('section header h2').text('No more options to choose from, click the View Results button!') 11444 } 11445 } 11446 } 11447} 11448 11449function renderResults() { 11450 var url = buildUrl(); 11451 url = util.appendParamToURL(url, 'bootfinderviewresults'); 11452 11453 $container.find('[step]').html(templates.results({ 11454 Url: url 11455 })); 11456 11457 dataBuffer.$emailForm = $container.find('form.email'); 11458 dataBuffer.emailValidator = dataBuffer.$emailForm.validate(ValidationSettings.Global); 11459 dataBuffer.$emailForm.find('input[name="email"]').rules('add', $.extend(ValidationRules.Email, { 11460 required: true, 11461 messages: { 11462 required: $.validator.format('Please enter an email address.') 11463 } 11464 })); 11465 dataBuffer.$emailForm.find('input[name="useragreement"]').rules('add', { 11466 required: true, 11467 messages: { 11468 required: $.validator.format('Please agree to the terms and conditions.') 11469 } 11470 }); 11471 11472 if ($step.attr('loading')) { 11473 $step.css('height', ''); 11474 $step.loading('destroy'); 11475 $('html').animate({ scrollTop: 0 }, 250); 11476 } 11477 $container.find('[step-delta]').removeClass('disabled'); 11478 $container.find('.next').addClass('disabled'); 11479} 11480 11481function buildUrl(urlParameter, includeAdditionalData) { 11482 var url; 11483 if (dataBuffer && dataBuffer.stepData[options.Configuration.CategorySelectionStep] && dataBuffer.stepData[options.Configuration.CategorySelectionStep][options.Configuration.CategorySelectionSection]) { 11484 var categorySelectionSection = options.Configuration.Steps[options.Configuration.CategorySelectionStep].Sections[options.Configuration.CategorySelectionSection]; 11485 var optionRelatedSelection = dataBuffer.stepData[categorySelectionSection.OptionsRelatedSelectionStep][categorySelectionSection.OptionsRelatedSelectionSection][0]; 11486 var categorySelection = dataBuffer.stepData[options.Configuration.CategorySelectionStep][options.Configuration.CategorySelectionSection][0]; 11487 11488 var categorySelectionIndex; 11489 var optionRelatedSelectionOptionIndex = 0; 11490 var optionRelatedSelectionOptions = categorySelectionSection.Options[optionRelatedSelection]; 11491 while (!categorySelectionIndex && optionRelatedSelectionOptionIndex <= optionRelatedSelectionOptions.length) { 11492 if (optionRelatedSelectionOptions[optionRelatedSelectionOptionIndex] && optionRelatedSelectionOptions[optionRelatedSelectionOptionIndex].Text == categorySelection) { 11493 categorySelectionIndex = optionRelatedSelectionOptionIndex; 11494 } 11495 optionRelatedSelectionOptionIndex++; 11496 } 11497 11498 var categorySelectionData = categorySelectionSection.Options[optionRelatedSelection][categorySelectionIndex]; 11499 if (urlParameter) { 11500 url = urlParameter; 11501 } else { 11502 url = categorySelectionData.Url; 11503 } 11504 var parameterIndex = 1; 11505 for (var categorySelectionDataKey in categorySelectionData) { 11506 var categorySelectionDataValue = categorySelectionData[categorySelectionDataKey]; 11507 if (urlParameter && categorySelectionDataKey == 'cgid') { 11508 url = util.appendParamToURL(url, 'cgid', categorySelectionDataValue); 11509 } else if (categorySelectionDataKey != 'Text' && categorySelectionDataKey != 'Url' && categorySelectionDataKey != 'cgid') { 11510 url = util.appendParamToURL(url, 'prefn' + parameterIndex, categorySelectionDataKey); 11511 url = util.appendParamToURL(url, 'prefv' + parameterIndex, categorySelectionDataValue); 11512 parameterIndex++; 11513 } 11514 } 11515 11516 for (var stepIndexInner in options.Configuration.Steps) { 11517 if (stepIndexInner <= dataBuffer.step) { 11518 var stepInner = options.Configuration.Steps[stepIndexInner]; 11519 for (var sectionIndexInner in stepInner.Sections) { 11520 var sectionInner = stepInner.Sections[sectionIndexInner]; 11521 if (sectionInner.Refinement && sectionInner.Refinement != 'width') { 11522 var refinementValues; 11523 if (dataBuffer.stepData && dataBuffer.stepData[stepIndexInner] && dataBuffer.stepData[stepIndexInner][sectionIndexInner]) { 11524 refinementValues = dataBuffer.stepData[stepIndexInner][sectionIndexInner]; 11525 } else { 11526 refinementValues = []; 11527 } 11528 11529 if (sectionInner.Refinement == 'size') { 11530 var widthSectionIndex = parseInt(sectionIndexInner, 10) + 1; 11531 var selectedWidths = dataBuffer.stepData[stepIndexInner][widthSectionIndex]; 11532 var isDatabufferWidths = false;
11533 if (!selectedWidths || !selectedWidths.length) { 11534 selectedWidths = dataBuffer.widths; 11535 isDatabufferWidths = true; 11536 } 11537 var isDatabufferLengths = false; 11538 if (!refinementValues || !refinementValues.length) { 11539 refinementValues = dataBuffer.lengths; 11540 isDatabufferLengths = true; 11541 } 11542 var selectedSizes = []; 11543 if (!isDatabufferWidths || !isDatabufferLengths) { 11544 for (var refinementIndex in refinementValues) { 11545 var selectedLength = refinementValues[refinementIndex]; 11546 for (var widthIndex in selectedWidths) { 11547 var selectedWidth = selectedWidths[widthIndex]; 11548 var selectedSize = selectedLength + ' ' + selectedWidth; 11549 if (selectedSizes.indexOf(selectedSize) < 0) { 11550 selectedSizes[selectedSizes.length] = selectedSize; 11551 } 11552 } 11553 } 11554 } 11555 refinementValues = selectedSizes; 11556 } 11557 11558 if (refinementValues && refinementValues.length > 0) { 11559 if (sectionInner.Refinement == 'Price') { 11560 if (dataBuffer.Thresholds && dataBuffer.Thresholds[sectionInner.Refinement] && dataBuffer.Thresholds[sectionInner.Refinement][refinementValues]) { 11561 var threshold = dataBuffer.Thresholds[sectionInner.Refinement][refinementValues[0]]; 11562 url = util.appendParamToURL(url, 'pmin', threshold.valueFrom); 11563 url = util.appendParamToURL(url, 'pmax', threshold.valueTo); 11564 } 11565 } else { 11566 url = util.appendParamToURL(url, 'prefn' + parameterIndex, sectionInner.Refinement); 11567 url = util.appendParamToURL(url, 'prefv' + parameterIndex, refinementValues.join('|')); 11568 parameterIndex++; 11569 } 11570 } 11571 } 11572 } 11573 } 11574 } 11575 if (includeAdditionalData) { 11576 url = util.appendParamToURL(url, 'displayvalues', 'Price'); 11577 url = util.appendParamToURL(url, 'thresholds', 'Price'); 11578 } 11579 } 11580 11581 return url; 11582} 11583 11584function getRefinementCountsForSection(sectionIndex, section) { 11585 var promise = new Promise(function(resolve, reject) { 11586 $.ajax({ 11587 type: 'get', 11588 url: buildUrl(Urls.getRefinementCounts, true), 11589 success: function(data) { 11590 dataBuffer = $.extend(dataBuffer, data); 11591 11592 var payload = { 11593 SectionIndex: sectionIndex, 11594 Section: section 11595 }; 11596 if (section && section.Refinement) { 11597 payload.Refinements = data.Refinements[section.Refinement]; 11598 } 11599 resolve(payload); 11600 } 11601 }); 11602 }); 11603 11604 return promise; 11605} 11606 11607function sendDataLayer() { 11608 GoogleTagManagerClient.PushDataLayerForEvent('bootfinderquiz', { 11609 step: dataBuffer.step, 11610 stepData: JSON.parse(JSON.stringify(dataBuffer.stepData)) 11611 }, null, 'GoogleAnalytics4'); 11612} 11613},{"../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../components/LoadingIndicator":25,"../util":102,"lodash":133}],50:[function(require,module,exports){ 11614'use strict'; 11615 11616var dialog = require('../dialog'); 11617 11618var quantityStepper = require('../quantityStepper'); 11619var account = require('./account'); 11620var ApplePay = require('./checkout/ApplePay'); 11621var bonusProductsView = require('../bonus-products-view'); 11622var quickview = require('../quickview'); 11623var cartStoreInventory = require('../storeinventory/cart'); 11624var ajax = require('../ajax'); 11625var util = require('../util'); 11626var formPrepare = require('./checkout/formPrepare'); 11627var page = require('../page'); 11628var tooltip = require('../tooltip'); 11629var TPromise = require('promise'); 11630var CheckoutConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants'); 11631var DataLayerConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/DataLayerConstants'); 11632var GoogleTagManagerClient = require('../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 11633var PaymentMethodConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').PaymentMethods; 11634var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 11635 11636var isCartPage = false;
11637var dataBuffer = {}; 11638var options; 11639 11640/** 11641 * @private 11642 * @function 11643 * @description Binds events to the cart page (edit item's details, bonus item's actions, coupon code entry) 11644 */ 11645function initializeEvents() { 11646 $(document).off('click', '#cart-table .item-edit-details a').on('click', '#cart-table .item-edit-details a', function (e) { 11647 e.preventDefault(); 11648 11649 quickview.show({ 11650 url: e.target.href, 11651 source: 'cart' 11652 }); 11653 }); 11654 11655 $(document).off('click', '#cart-table .bonus-item-actions a, #cart-table .item-details .bonusproducts a').on('click', '#cart-table .bonus-item-actions a, #cart-table .item-details .bonusproducts a', function (e) { 11656 e.preventDefault(); 11657 11658 bonusProductsView.show(this.href); 11659 }); 11660 11661 $(document).off('keydown', 'form input[name$="_couponCode"]').on('keydown', 'form input[name$="_couponCode"]', function (e) { 11662 if (e.which === SiteConstants.KeyCodes.Enter) { 11663 e.preventDefault(); 11664 11665 $('.error.coupon-error').remove(); 11666 if ($(document.activeElement).val().length === 0 || e.which === SiteConstants.KeyCodes.Enter && $(this).val().length === 0) { 11667 $('<span/>', {"class":"error coupon-error", text : Resources.COUPON_ADD_ERROR}).insertAfter('.cart-coupon-code .pcode-coupon'); 11668 11669 return false; 11670 } else { 11671 $('button[name$="addCoupon"]').trigger('click'); 11672 } 11673 } 11674 }); 11675 11676 $(document).off('click', 'button[name$="deleteProduct"]').on('click', 'button[name$="deleteProduct"]', function (e) { 11677 e.preventDefault(); 11678 11679 updateCart($(this).attr('name')); 11680 }); 11681 11682 $(document).off('click', 'button[name$="addCoupon"]').on('click', 'button[name$="addCoupon"]', function (e) { 11683 e.preventDefault(); 11684 11685 $('.error.coupon-error').text(''); 11686 var $form = $('form#cart-items-form'); 11687 var name = $(this).attr('name'); 11688 11689 (function() { 11690 return TPromise.resolve($.ajax({ 11691 type: 'POST', 11692 url: util.ajaxUrl(Urls.onePageSubmit), 11693 data: $form.serialize() + '&' + name + '=' + name + '&respType=json' 11694 })) 11695 }()).then(function (response) { 11696 if (response.success && response.success !== CheckoutConstants.ResponseCodes.AlreadyInBasket) { 11697 var couponCode = $('.pcode-coupon input[name*="_couponCode"]').val(); 11698 11699 var dataObject = { 11700 creative_name: couponCode, 11701 creative_slot: 'couponcode', 11702 promotion_id: response.Promotion && response.Promotion.ID ? response.Promotion.ID : '', 11703 promotion_name: response.Promotion && response.Promotion.Name ? response.Promotion.Name : '' 11704 } 11705 11706 GoogleTagManagerClient.PushDataLayerForDataLayerType('SelectPromotion', dataObject); 11707 $(document).trigger('Cart.Update'); 11708 } else {1 11709 var message = response.success == CheckoutConstants.ResponseCodes.AlreadyInBasket ? Resources.COUPON_ADD_ERROR_DUP : Resources.COUPON_ADD_ERROR; 11710 $('<span/>', {'class': 'error coupon-error', 'text': message}).insertAfter('.cart-coupon-code .pcode-coupon'); 11711 } 11712 }.bind(this)); 11713 }); 11714 11715 $(document).off('click', 'button[name$="deleteCoupon"]').on('click', 'button[name$="deleteCoupon"]', function (e) { 11716 e.preventDefault(); 11717 11718 var name = $(this).attr('name'); 11719 (function(){ 11720 return TPromise.resolve($.ajax({ 11721 type: 'POST', 11722 url: util.ajaxUrl(Urls.onePageSubmit), 11723 data: $('form#cart-items-form').serialize() + '&' + name + '=' + name + '&respType=json' 11724 })) 11725 }()).then(function (response) { 11726 $(document).trigger('Cart.Update'); 11727 }.bind(this)); 11728 }); 11729 11730 $(document).off('refresh-required').on('refresh-required', function(){ 11731 if ($('form#cart-items-form input[name$="_quantity"]').length > 0) { 11732 setTimeout( function(){ 11733 $('form#cart-items-form input[name$="_quantity"]:first').trigger('focus').trigger('blur'); 11734 }, 300); 11735 } 11736 }); 11737 11738 $(document).on('focus', 'input[name^="dwfrm_guestcheckout_username_"]', function () { 11739 $(this).removeClass('error'); 11740 $('#dwfrm_guestcheckout span.error').remove(); 11741 }); 11742 11743 $(document).off('keydown', 'form input[name^="dwfrm_guestcheckout_username_"]').on('keydown', 'input[name^="dwfrm_guestcheckout_username_"]', function (e) { 11744 if (e.which === SiteConstants.KeyCodes.Enter) { 11745 e.preventDefault(); 11746 $('#dwfrm_guestcheckout span.error').remove(); 11747 11748 var $form = $('form.guest-checkout'); 11749 $form.validate().form(); 11750 11751 var email = $(document.activeElement).val(); 11752 var isEmailValid = validateEmail(email); 11753 11754 if ($form.valid() && isEmailValid && $('#dwfrm_guestcheckout span.error').length < 1 ) { 11755 renderGuestCheckout(email) 11756 } else { 11757 if ($('input[name^="dwfrm_guestcheckout_username_"].error').length == 0) { 11758 invalidateGuestCheckout(); 11759 } 11760 } 11761 } 11762 }); 11763 11764 $(document).off('click', 'button#guestCheckout').on('click', 'button#guestCheckout', function (e) { 11765 e.preventDefault(); 11766 $('#dwfrm_guestcheckout span.error').remove(); 11767 11768 var $form = $('form.guest-checkout'); 11769 $form.validate().form(); 11770 11771 var email = $('input[name^="dwfrm_guestcheckout_username_"]').val(); 11772 if ($('input[name^="dwfrm_guestcheckout_username_"].valid').length > 0) { 11773 var email = $('input[name^="dwfrm_guestcheckout_username_"].valid').val(); 11774 } 11775 11776 var isEmailValid = validateEmail(email); 11777 11778 if ($form.valid() && isEmailValid && $('#dwfrm_guestcheckout span.error').length < 1 ) { 11779 renderGuestCheckout(email); 11780 } else { 11781 if ($('input[name^="dwfrm_guestcheckout_username_"].error').length == 0) { 11782 invalidateGuestCheckout(); 11783 } 11784 } 11785 }); 11786 11787 $(document).off('click', '#editCustomerEmail').on('click', '#editCustomerEmail', function (e) { 11788 $('.auto-checkout-form').show(); 11789 $('.login-form').addClass('login-hidden'); 11790 clearFormErrors(); 11791 }); 11792 11793 $(document).on('focus', 'input[name^="dwfrm_autocheckout_username_"], input[name^="dwfrm_login_"]', function () { 11794 clearFormErrors(); 11795 }); 11796 11797 $(document).off('keydown', 'form input[name^="dwfrm_autocheckout_username_"]').on('keydown', 'input[name^="dwfrm_autocheckout_username_"]', function (e) { 11798 if (e.which === SiteConstants.KeyCodes.Enter) { 11799 e.preventDefault(); 11800 $('#dwfrm_autocheckout span.error').remove(); 11801 11802 var $form = $('form.auto-checkout'); 11803 $form.validate().form(); 11804 11805 var email = $(document.activeElement).val(); 11806 var isEmailValid = validateEmail(email); 11807 11808 if ($form.valid() && isEmailValid && $('#dwfrm_autocheckout span.error').length < 1 ) { 11809 $('.displayAutoEmail').text(email); 11810 $('input[name^="dwfrm_login_username_"]').val(email); 11811 renderAutoCheckout(email) 11812 } else { 11813 if ($('input[name^="dwfrm_autocheckout_username_"].error').length == 0) { 11814 invalidateAutoCheckout(); 11815 } 11816 } 11817 } 11818 }); 11819 11820 $(document).off('click', 'button#autoCheckout').on('click', 'button#autoCheckout', function (e) { 11821 e.preventDefault(); 11822 $('#dwfrm_autocheckout span.error').remove(); 11823 11824 var $form = $('form.auto-checkout'); 11825 $form.validate().form(); 11826 11827 var email = $('input[name^="dwfrm_autocheckout_username_"]').val(); 11828 if ($('input[name^="dwfrm_autocheckout_username_"].valid').length > 0) { 11829 var email = $('input[name^="dwfrm_autocheckout_username_"].valid').val(); 11830 } 11831 11832 var isEmailValid = validateEmail(email); 11833 11834 if ($form.valid() && isEmailValid && $('#dwfrm_autocheckout span.error').length < 1 ) { 11835 $('.displayAutoEmail').text(email); 11836 $('input[name^="dwfrm_login_username_"]').val(email); 11837 renderAutoCheckout(email); 11838 } else { 11839 if ($('input[name^="dwfrm_autocheckout_username_"].error').length == 0) { 11840 invalidateAutoCheckout(); 11841 } 11842 } 11843 }); 11844 11845 $('.app-checkout #submitBilling').on('click', function(e){ 11846 e.preventDefault(); 11847 11848 var email = $('input[name^="dwfrm_billingaddress_email"]').val(); 11849 if (email.length > 0) { 11850 var isEmailValid = validateEmail(email); 11851 if (isEmailValid) { 11852 $.ajax({ 11853 url: Urls.checkCustomerExists, 11854 type: "get", 11855 data: {email: email}, 11856 success: function (response) { 11857 var data = JSON.parse(response); 11858 $('.app-checkout').attr('customer-exists', data.customerExists); 11859 $('.app-checkout').attr('has-rewards', data.hasRewards); 11860 }, 11861 error: function(jqXHR, textStatus, errorThrown) { 11862 console.log(textStatus, errorThrown); 11863 } 11864 }); 11865 } 11866 } 11867 }); 11868 11869 $(document).off('click', '.order-total-payments [payment-method] .remove').on('click', '.order-total-payments [payment-method] .remove', function (e) { 11870 var paymentInstrumentUUID = $(e.currentTarget).closest('[payment-method').attr('uuid'); 11871 11872 if (paymentInstrumentUUID) { 11873 var requestPayload = { 11874 UUID: paymentInstrumentUUID 11875 } 11876 11877 $.ajax({ 11878 url: Urls.removePaymentInstrument, 11879 type: 'POST', 11880 contentType: 'application/json', 11881 data: JSON.stringify(requestPayload), 11882 dataType: 'json', 11883 success: function(data) { 11884 updateCart('dwfrm_cart_updateCart'); 11885 } 11886 }); 11887 } 11888 }); 11889 11890 $(document).on('Cart.Update', function (event, data) { 11891 updateCart('dwfrm_cart_updateCart', data); 11892 }); 11893} 11894 11895function validateEmail(email) { 11896 var isEmailValid = true; 11897 11898 if (email.length == 0){ 11899 isEmailValid = true; 11900 } 11901 11902 var regexEmail = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; 11903 if (email.length > 0 && email.match(regexEmail) == null) { 11904 isEmailValid = false;
11905 invalidateGuestCheckout(); 11906 } 11907 11908 return isEmailValid; 11909} 11910 11911function clearFormErrors() { 11912 $('.form-checkout input[name^="dwfrm_"]').removeClass('error'); 11913 $('.form-checkout span.error').remove(); 11914 $('.form-checkout .error-box').remove(); 11915} 11916 11917function invalidateGuestCheckout() { 11918 $('input[name^="dwfrm_guestcheckout_username_"]').removeClass('valid').addClass('error'); 11919 $('.guest-checkout .field-wrapper').append('<span class="error custom-guestcheckout-error" style="display:block !important;">' + Resources.VALIDATE_EMAIL + '</span>'); 11920} 11921 11922function renderGuestCheckout(email) { 11923 11924 if(email.length > 0){ 11925 var optIn = false; 11926 11927 if(SitePreferences.CORDIAL_ENABLED){ 11928 var signupEvent = ''; 11929 11930 var auth_data = { 11931 email: email 11932 } 11933 var contact_data = { 11934 'channels': { 11935 'email': { 11936 'address': email, 11937 'subscribeStatus': 'none' 11938 } 11939 }, 11940 'workflow_checkout_abandon': true 11941 }; 11942 11943 var guestProperties = { 11944 'email': email, 11945 'workflow_checkout_abandon': true 11946 }; 11947 11948 if ($('#guest_checkout_optin').prop("checked")) { 11949 var auth_data = { 11950 email: email 11951 } 11952 var contact_data = { 11953 'channels': { 11954 'email': { 11955 'address': email, 11956 'subscribeStatus': 'subscribed' 11957 } 11958 }, 11959 'signup_source': 'checkout', 11960 'welcome_signup': true, 11961 'workflow_checkout_abandon': true 11962 }; 11963 11964 var properties = { 11965 'signup_source': 'checkout', 11966 'welcome_signup': true, 11967 'workflow_checkout_abandon': true 11968 }; 11969 11970 var signupEvent = ['event', 'email_signup', properties]; 11971 } 11972 11973 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 11974 crdl([ 11975 ['contact', auth_data, contact_data], 11976 ['event', 'guest_checkout', guestProperties], 11977 signupEvent 11978 ]); 11979 } 11980 } 11981 } else { 11982 var optIn = $('#guest_checkout_optin').prop("checked"); 11983 } 11984 11985 $.ajax({ 11986 url: Urls.setEmailOnCart, 11987 type: "get", 11988 data: {email: email}, 11989 success: function (response) { 11990 var data = JSON.parse(response); 11991 11992 if (data.status == 'success') { 11993 window.location.href = Urls.onePage + ((window.innerWidth < SiteConstants.Responsive.Widths.Mobile) ? '#addressinfo' : ''); 11994 } 11995 }, 11996 error: function(jqXHR, textStatus, errorThrown) { 11997 console.log(textStatus, errorThrown); 11998 } 11999 }); 12000 12001 $.ajax({ 12002 url: Urls.setEmailOptin, 12003 type: "get", 12004 data: {optIn: optIn}, 12005 success: function (response) { 12006 var data = JSON.parse(response); 12007 12008 if (data.status == 'success') { 12009 window.location.href = Urls.onePage + ((window.innerWidth < SiteConstants.Responsive.Widths.Mobile) ? '#addressinfo' : ''); 12010 } 12011 }, 12012 error: function(jqXHR, textStatus, errorThrown) { 12013 console.log(textStatus, errorThrown); 12014 } 12015 }); 12016} 12017 12018 12019function validateAutoEmail(email) { 12020 var isEmailValid = true; 12021 12022 var regexEmail = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; 12023 if (email.length > 0 && email.match(regexEmail)){ 12024 isEmailValid = true; 12025 } else { 12026 isEmailValid = false; 12027 invalidateGuestCheckout(); 12028 } 12029 12030 return isEmailValid; 12031} 12032
12033function invalidateAutoCheckout() { 12034 $('input[name^="dwfrm_autocheckout_username_"]').removeClass('valid').addClass('error'); 12035 $('.auto-checkout .field-wrapper').append('<span class="error custom-autocheckout-error" style="display:block !important;">' + Resources.VALIDATE_EMAIL + '</span>'); 12036} 12037 12038function renderAutoCheckout(email) { 12039 var gotocheckout = true; 12040 12041 if(email.length > 0){ 12042 var optIn = false; 12043 12044 if(SitePreferences.CORDIAL_ENABLED){ 12045 var signupEvent = ''; 12046 12047 var auth_data = { 12048 email: email 12049 } 12050 var contact_data = { 12051 'channels': { 12052 'email': { 12053 'address': email, 12054 'subscribeStatus': 'none' 12055 } 12056 }, 12057 'workflow_checkout_abandon': true, 12058 'workflow_loyalty_transactional': true 12059 }; 12060 12061 var autoProperties = { 12062 'email': email, 12063 'workflow_checkout_abandon': true, 12064 'workflow_loyalty_transactional': true 12065 }; 12066 12067 if ($('#auto_checkout_optin').prop("checked")) { 12068 var auth_data = { 12069 email: email 12070 } 12071 var contact_data = { 12072 'channels': { 12073 'email': { 12074 'address': email, 12075 'subscribeStatus': 'subscribed' 12076 } 12077 }, 12078 'signup_source': 'checkout', 12079 'welcome_signup': true, 12080 'workflow_checkout_abandon': true, 12081 'workflow_loyalty_transactional': false 12082 }; 12083 12084 var properties = { 12085 'signup_source': 'checkout', 12086 'welcome_signup': true, 12087 'workflow_checkout_abandon': true, 12088 'workflow_loyalty_transactional': false 12089 }; 12090 12091 var signupEvent = ['event', 'email_signup', properties]; 12092 } 12093 12094 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 12095 crdl([ 12096 ['contact', auth_data, contact_data], 12097 ['event', 'guest_checkout', autoProperties], 12098 signupEvent 12099 ]); 12100 } 12101 } 12102 } else { 12103 var optIn = $('#auto_checkout_optin').prop("checked"); 12104 } 12105 12106 $.ajax({ 12107 url: Urls.checkCustomerExists, 12108 type: "get", 12109 data: {email: email}, 12110 success: function (response) { 12111 var data = JSON.parse(response); 12112 12113 if (data.status == 'success') { 12114 gotocheckout = false; 12115 $('.auto-checkout-form').hide(); 12116 $('.login-form').removeClass('login-hidden'); 12117 } else { 12118 window.location.href = Urls.onePage + ((window.innerWidth < SiteConstants.Responsive.Widths.Mobile) ? '#addressinfo' : ''); 12119 } 12120 }, 12121 error: function(jqXHR, textStatus, errorThrown) { 12122 console.log(textStatus, errorThrown); 12123 } 12124 }); 12125 12126 $.ajax({ 12127 url: Urls.setEmailOnCart, 12128 type: "get", 12129 data: {email: email}, 12130 success: function (response) { 12131 var data = JSON.parse(response); 12132 12133 if (data.status == 'success') { 12134 12135 } 12136 }, 12137 error: function(jqXHR, textStatus, errorThrown) { 12138 console.log(textStatus, errorThrown); 12139 } 12140 }); 12141 12142 $.ajax({ 12143 url: Urls.setEmailOptin, 12144 type: "get", 12145 data: {optIn: optIn}, 12146 success: function (response) { 12147 var data = JSON.parse(response); 12148 12149 if (data.status == 'success') { 12150 12151 } 12152 }, 12153 error: function(jqXHR, textStatus, errorThrown) { 12154 console.log(textStatus, errorThrown); 12155 } 12156 }); 12157} 12158 12159function triggerReactWebviewEvent() { 12160 if ('ReactNativeWebView' in window) { 12161 window.ReactNativeWebView.postMessage(JSON.stringify({ action: 'cart-refresh' })); 12162 } 12163} 12164 12165var updateCartBuffer; 12166var updateCartXmlHttpRequestBuffer; 12167function updateCart(triggerElementName, updateCartOptions, isCartPage) { 12168 if (updateCartXmlHttpRequestBuffer) { 12169 for (var updateCartXmlHttpRequestKey in updateCartXmlHttpRequestBuffer) { 12170 var updateCartXmlHttpRequest = updateCartXmlHttpRequestBuffer[updateCartXmlHttpRequestKey]; 12171 12172 if (updateCartXmlHttpRequest.readyState !== 4) { 12173 updateCartXmlHttpRequest.abort(); 12174 } 12175 } 12176 } 12177 updateCartXmlHttpRequestBuffer = []; 12178 updateCartBuffer = []; 12179 12180 getCartHtml(triggerElementName, updateCartOptions, isCartPage); 12181 if (!isCartPage) { 12182 getOrderSummaryCalloutHtml(triggerElementName, updateCartOptions, isCartPage); 12183 } 12184} 12185 12186function getCartHtml(triggerElementName, updateCartOptions, isCartPage) { 12187 var form = $(".update-cart-button").parents('form'); 12188 updateCartBuffer['Cart'] = null; 12189 12190 if (form.attr('action')) { 12191 if (isCartPage == undefined) { 12192 isCartPage = $('.pt_cart').length > 0; 12193 } 12194 12195 updateCartXmlHttpRequestBuffer['getCartHtml'] = $.ajax({ 12196 url : form.attr('action'), 12197 type : "POST", 12198 data : triggerElementName + '=' + triggerElementName + '&selectedPaymentMethod=' + $('input[name*="_selectedPaymentMethodID"]').val() + '&format=ajax', 12199 success : function (data) { 12200 updateCartBuffer['Cart'] = data; 12201 if (pageContext.site == SiteConstants.SiteIds.BootBarnWorkforceUS) { 12202 getWorkforcePaymentPanel(triggerElementName, updateCartOptions, isCartPage); 12203 } else { 12204 updateCartBuffer['WorkforceVouchersPaymentPanel'] = true; 12205 } 12206 getCartData(triggerElementName, updateCartOptions, isCartPage); 12207 updateCartRender(triggerElementName, updateCartOptions, isCartPage); 12208 } 12209 }); 12210 } 12211} 12212 12213function getWorkforcePaymentPanel(triggerElementName, updateCartOptions, isCartPage) { 12214 updateCartBuffer['WorkforceVouchersPaymentPanel'] = null; 12215 updateCartBuffer['WorkforceVouchersPaymentPanelHtml'] = null; 12216 12217 updateCartXmlHttpRequestBuffer['getWorkforceVouchersPaymentPanelHtml'] = $.ajax({ 12218 url: Urls.Workforce.Vouchers.PaymentPanel.Get, 12219 dataType: 'html', 12220 success: function (data) { 12221 updateCartBuffer['WorkforceVouchersPaymentPanel'] = true; 12222 updateCartBuffer['WorkforceVouchersPaymentPanelHtml'] = $(data).html(); 12223 updateCartRender(triggerElementName, updateCartOptions, isCartPage); 12224 } 12225 }); 12226} 12227 12228function getOrderSummaryCalloutHtml(triggerElementName, updateCartOptions, isCartPage) { 12229 updateCartBuffer['OrderSummaryCallout'] = null; 12230 12231 updateCartXmlHttpRequestBuffer['getOrderSummaryCalloutHtml'] = $.ajax({ 12232 url: Urls.getOrderSummaryCalloutContentSlot, 12233 dataType: 'html', 12234 success: function (data) { 12235 updateCartBuffer['OrderSummaryCallout'] = data; 12236 updateCartRender(triggerElementName, updateCartOptions, isCartPage); 12237 } 12238 }); 12239} 12240 12241function getCartData(triggerElementName, updateCartOptions, isCartPage) { 12242 updateCartBuffer['CartData'] = null; 12243 12244 updateCartXmlHttpRequestBuffer['getCartData'] = $.ajax({ 12245 url : Urls.getCartData, 12246 type : "POST", 12247 data: { 12248 isCart: isCartPage 12249 }, 12250 success : function (data) { 12251 $('[has-local-delivery-shipment]').attr('has-local-delivery-shipment', data.HasLocalDeliveryShipment || false); 12252 $('[has-physical-shipment]').attr('has-physical-shipment', data.HasPhysicalShipment || false); 12253 $('[has-warehouse-shipment]').attr('has-warehouse-shipment', data.HasWarehouseShipment || false); 12254 $('[has-warehouse-shipment]').attr('has-shipping-methods', data.ShippingMethods ? data.ShippingMethods.join(' ') : false); 12255 $('[has-subscription-products]').attr('has-subscription-products', data.HasSubscriptionProducts || false); 12256 $('[has-gift-cards]').attr('has-gift-cards', data.HasGiftCards || false); 12257 $('[has-gift-cards-only]').attr('has-gift-cards-only', data.HasGiftCardsOnly || false); 12258 $('[has-store-pickup-shipment]').attr('has-store-pickup-shipment', (data.Bopis && data.Bopis.HasStorePickupShipment) || false); 12259 $('[has-store-pickup-shipment-only]').attr('has-store-pickup-shipment-only', (data.Bopis && data.Bopis.HasStorePickupShipmentOnly) || false); 12260 12261 if (data.Bopis && data.Bopis.HasStorePickupShipmentOnly) { 12262 $('#isShippingAddressSameAsBillingAddress').prop('checked', true); 12263 $('input[name$="_useAsShippingAddress"]').prop('checked', true); 12264 } 12265 12266 $(document).trigger('CartData.Update', data); 12267 12268 updateCartBuffer['CartData'] = data; 12269 if (data.Bopis) { 12270 updateCartBuffer['Bopis'] = data.Bopis; 12271 } 12272 12273 if (!data.IsGlobaleValidOrInactive) {
12274 $('.section-checkout').addClass('global-e-validation-error'); 12275 $('.section-checkout').find('.cart-errors').addClass('active'); 12276 } else { 12277 $('.section-checkout').removeClass('global-e-validation-error'); 12278 $('.section-checkout').find('.cart-errors').removeClass('active'); 12279 } 12280 12281 if ((!data.OrderTotal || !data.OrderTotal.balanceAvailable) || (data.ShippingRestrictions && data.ShippingRestrictions.Status == 'shippingRestrictionsError')) { 12282 if (!isCartPage) { 12283 $('.payment-methods-section').hide(); 12284 } 12285 } else { 12286 if (isCartPage) { 12287 $('.guest-checkout .error-form').remove(); 12288 } else { 12289 $('.payment-methods-section').show(); 12290 } 12291 } 12292 12293 handleOrderTotal(triggerElementName, updateCartOptions, isCartPage); 12294 } 12295 }); 12296} 12297 12298function handleOrderTotal(triggerElementName, updateCartOptions, isCartPage) { 12299 updateCartBuffer['PaymentInstrumentHtml'] = null; 12300 var removeAction = '<a class="remove">Remove</a>'; 12301 var rewardsProgram = ''; 12302 if (pageContext.site == SiteConstants.SiteIds.CountryOutfittersUS) { 12303 rewardsProgram = 'Club CO'; 12304 } 12305 if (pageContext.site == SiteConstants.SiteIds.SheplersUS) { 12306 rewardsProgram = 'Sheplers'; 12307 } 12308 12309 if (updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length > 0) { 12310 updateCartBuffer['PaymentInstrumentHtml'] = ''; 12311 12312 for (var paymentInstrumentKey in updateCartBuffer['CartData'].OrderTotal.paymentInstruments) { 12313 var paymentInstrument = updateCartBuffer['CartData'].OrderTotal.paymentInstruments[paymentInstrumentKey]; 12314 var paymentInstrumentUUIDAttribute = 'uuid="' + paymentInstrument.UUID + '"'; 12315 var showYouPayLabel = false; 12316 12317 switch (paymentInstrument.paymentMethod.Id) { 12318 case PaymentMethodConstants.WorkforceVoucher: 12319 showYouPayLabel = true; 12320 updateCartBuffer['PaymentInstrumentHtml'] += '<div ' + paymentInstrumentUUIDAttribute + ' payment-method="' + paymentInstrument.paymentMethod.Id + '" allow-remove="' + paymentInstrument.allowRemove + '">' + 12321 '<i class="fa-solid fa-ticket fa-animated"></i>' + 12322 '<span class="label"><span class="name">' + 'Company Pays' + '</span> <span class="number">' + paymentInstrument.number + '</span>' + removeAction + '</span>' + 12323 '<span class="value">' + paymentInstrument.amountDisplay + '</span>' + 12324 '</div>'; 12325 break; 12326 12327 case PaymentMethodConstants.RewardsCredit: 12328 updateCartBuffer['PaymentInstrumentHtml'] += '<div ' + paymentInstrumentUUIDAttribute + ' payment-method="' + paymentInstrument.paymentMethod.Id + '" allow-remove="' + paymentInstrument.allowRemove + '">' + 12329 '<span class="label"><span class="name">B Rewarded</span> <span class="number">Reward</span></span>' + 12330 '<span class="value">' + paymentInstrument.amountDisplay + '</span>' + 12331 '</div>'; 12332 break; 12333 12334 case PaymentMethodConstants.LoyaltyCredit: 12335 updateCartBuffer['PaymentInstrumentHtml'] += '<div ' + paymentInstrumentUUIDAttribute + ' payment-method="' + paymentInstrument.paymentMethod.Id + '" allow-remove="' + paymentInstrument.allowRemove + '">' + 12336 '<span class="label"><span class="name">'+rewardsProgram+'</span> <span class="number">Reward</span></span>' + 12337 '<span class="value">' + paymentInstrument.amountDisplay + '</span>' + 12338 '</div>'; 12339 break; 12340 12341 default: 12342 updateCartBuffer['PaymentInstrumentHtml'] += '<div ' + paymentInstrumentUUIDAttribute + ' payment-method="' + paymentInstrument.paymentMethod.Id + '" allow-remove="' + paymentInstrument.allowRemove + '">' + 12343 '<span class="label"><span class="name">' + paymentInstrument.paymentMethod.Name + '</span> <span class="number">' + paymentInstrument.number + '</span>' + removeAction + '</span>' + 12344 '<span class="value">' + paymentInstrument.amountDisplay + '</span>' + 12345 '</div>'; 12346 break; 12347 } 12348 } 12349 } else { 12350 $(document).trigger('GiftCard.Clear'); 12351 $(document).trigger('RewardsCredit.Clear'); 12352 $(document).trigger('LoyaltyCredit.Clear'); 12353 } 12354 12355 var balanceDueLabel = showYouPayLabel ? 'You Pay' : 'Balance Due'; 12356 if (updateCartBuffer['CartData'].OrderTotal.balance < updateCartBuffer['CartData'].OrderTotal.total) { 12357 updateCartBuffer['BalanceDueHtml'] = '<span class="label">' + balanceDueLabel + '</span>' + 12358 '<span class="value">' + updateCartBuffer['CartData'].OrderTotal.balanceDisplay + '</span>'; 12359 } 12360 12361 updateCartRender(triggerElementName, updateCartOptions, isCartPage); 12362} 12363 12364function updateCartRender(triggerElementName, updateCartOptions, isCartPage) { 12365 if (updateCartBuffer['Cart'] && (isCartPage || (updateCartBuffer['OrderSummaryCallout'] && updateCartBuffer['CartData'])) && updateCartBuffer['WorkforceVouchersPaymentPanel']) { 12366 var $basketContainerHtml = $(updateCartBuffer['Cart']); 12367 12368 if (updateCartBuffer['CartData'] && updateCartBuffer['CartData'].OrderTotal) { 12369 $basketContainerHtml.find('.order-total-price .value').html(updateCartBuffer['CartData'].OrderTotal.totalDisplay); 12370 $('.payment-section .order-total-price .value').html(updateCartBuffer['CartData'].OrderTotal.totalDisplay); 12371 12372 if (updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length > 0) { 12373 $basketContainerHtml.find('.order-totals-table').attr('payments-applied', updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length); 12374 $('.payment-section').attr('payments-applied', updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length); 12375 } else { 12376 $basketContainerHtml.find('.order-totals-table').removeAttr('payments-applied'); 12377 $('.payment-section').removeAttr('payments-applied'); 12378 } 12379 12380 $basketContainerHtml.find('.order-totals-table').attr('balance-due', updateCartBuffer['CartData'].OrderTotal.balance); 12381 $('body').attr('balance-due', updateCartBuffer['CartData'].OrderTotal.balance); 12382 $('.payment-section').attr('balance-due', updateCartBuffer['CartData'].OrderTotal.balance); 12383 12384 if (updateCartBuffer['CartData'].OrderTotal.balance > 0) { 12385 $('.payment-method-options').show(); 12386 $('.payment-section-footer[data-method="PayPal"] button').hide(); 12387 } else { 12388 $('.payment-method-options').hide(); 12389 $('.payment-section-footer[data-method="PayPal"] button').show(); 12390 } 12391 12392 if (updateCartBuffer['BalanceDueHtml']) { 12393 $basketContainerHtml.find('.order-balance-due').html(updateCartBuffer['BalanceDueHtml']); 12394 $('.payment-section .order-balance-due').html(updateCartBuffer['BalanceDueHtml']); 12395 } else { 12396 $('.payment-section .order-balance-due').html(''); 12397 } 12398 12399 if (updateCartBuffer['PaymentInstrumentHtml']) { 12400 $basketContainerHtml.find('.order-total-payments').html(updateCartBuffer['PaymentInstrumentHtml']); 12401 $('.payment-section .order-total-payments').html(updateCartBuffer['PaymentInstrumentHtml']); 12402 } else { 12403 $('.payment-section .order-total-payments').html(''); 12404 } 12405 12406 if (updateCartBuffer['WorkforceVouchersPaymentPanelHtml']) { 12407 $('.payment-methods-section .opc-summary [payment-method="Workforce_Voucher"]').html(updateCartBuffer['WorkforceVouchersPaymentPanelHtml']); 12408 } 12409 } 12410 12411 $('.basket-container').html($basketContainerHtml); 12412 if ($('.approaching-discount-progress-bar-container.hidden').length > 0) { 12413 $('.approaching-discount-progress-bar-container:not(.hidden)').html($('.approaching-discount-progress-bar-container.hidden').html()); 12414 } else { 12415 $('.approaching-discount-progress-bar-container:not(.hidden)').html(''); 12416 } 12417 if (updateCartBuffer['CartData']) { 12418 var orderTotalForAffirm = updateCartBuffer['CartData'].OrderTotal.balance; 12419 if (!orderTotalForAffirm && updateCartBuffer['CartData'].OrderTotal.adjustedMerchandizeTotalPrice) { 12420 orderTotalForAffirm = updateCartBuffer['CartData'].OrderTotal.adjustedMerchandizeTotalPrice; 12421 } 12422 if ('affirm' in window && 'ui' in affirm && 'refresh' in affirm.ui && orderTotalForAffirm >= updateCartBuffer['CartData'].AffirmMinimumOrderTotal) { 12423 $('.affirm-product-modal').attr('data-amount', orderTotalForAffirm * 100); 12424 affirm.ui.refresh(); 12425 } else { 12426 $('.affirm-product-modal').attr('data-amount', 5000); 12427 } 12428 } 12429 12430 if ($('.basket-container').find('.product-availability-list .not-available').length > 0) { 12431 $('#submitOPCPayment, #submitOPCPaymentPrivateLabel').attr('disabled', 'disabled'); 12432 $('#errorBoxOPC').remove(); 12433 $('#submitOPCPayment').after('<div id="errorBoxOPC" class="p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>' + Resources.Validation.Messages.Products.Availability + ':</b> ' + Resources.Validation.Messages.Products.AvailabilityExceeded + '</div>'); 12434 } else if (updateCartBuffer['Bopis'] && updateCartBuffer['Bopis'].NumberOfBopisStoresInCart > updateCartBuffer['Bopis'].MaximumNumberOfBopisStoresInCart) { 12435 $('#submitOPCPayment, #submitOPCPaymentPrivateLabel').attr('disabled', 'disabled'); 12436 $('#errorBoxOPC').remove(); 12437 $('#submitOPCPayment').after('<div id="errorBoxOPC" class="p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>' + Resources.Validation.Messages.General.CartLimit + ':</b> ' + Resources.Validation.Messages.Bopis.MaximumStoresExceeded + '</div>'); 12438 } else { 12439 $('#submitOPCPayment, #submitOPCPaymentPrivateLabel').removeAttr('disabled'); 12440 $('#errorBoxOPC').remove(); 12441 } 12442 12443 if (updateCartBuffer['OrderSummaryCallout']) { 12444 $('.callout-ordersummary').html(updateCartBuffer['OrderSummaryCallout']); 12445 } 12446 if (SitePreferences.ID_ME_DEFAULT_BUTTON) { 12447 document.dispatchEvent(new CustomEvent('idme:bind')); 12448 } 12449 if (SitePreferences.STORE_PICKUP) { 12450 cartStoreInventory.init(); 12451 } 12452 12453 account.initCartLogin(); 12454 checkCheckoutAccessibility(); 12455 12456 var $cartMiniCartButton = $('.banner-cart-holder .btn-minicart'); 12457 if ($cartMiniCartButton.length > 0) { 12458 $.ajax({url : Urls.cartMiniCart, data : {desktop: '1'}, dataType: 'html', success : function(data) { 12459 $('.banner-cart-holder').html(data); 12460 }}); 12461 12462 $.ajax({url : Urls.cartMiniCart, dataType: 'html', success : function(data) { 12463 var parentMiniCart = $(".top-banner-inner-links #mini-cart"); 12464 12465 if (parentMiniCart.length > 0) { 12466 parentMiniCart.html(data); 12467 } 12468 }}); 12469 } 12470 12471 $.ajax({url: Urls.cartItemQuantity, data: {desktop: '1'}, dataType: 'html', success: function (data) { 12472 $('.confirmation-message .item-count').html(data); 12473 12474 var quantity = parseInt($('.confirmation-message .item-count').find('span').text(), 10); 12475 if (!quantity) { 12476 $('.checkout-buttons.mobile-only').hide(); 12477 } 12478 }}); 12479 12480 12481 if (triggerElementName.indexOf('deleteProduct') > -1) { 12482 $(document).trigger('refresh-required'); 12483 } 12484 12485 if (!options || !options.EventTriggers || options.EventTriggers['update-summary']) { 12486 $(document).trigger('update-summary'); 12487 } 12488 12489 if (!options || !options.EventTriggers || options.EventTriggers['update-shipping']) { 12490 $(document).trigger('update-shipping'); 12491 } 12492 12493 $('[minimum-cart-total], [maximum-cart-total]').each(function(index, element) { 12494 var $this = $(this); 12495 var paymentMethodCartTotalMinimum = parseFloat($this.attr('minimum-cart-total')); 12496 var paymentMethodCartTotalMaximum = parseFloat($this.attr('maximum-cart-total')); 12497 12498 var isCartTotalMinimumValid = false;
12499 if (isNaN(paymentMethodCartTotalMinimum) || updateCartBuffer['CartData'].OrderTotal.balance >= paymentMethodCartTotalMinimum) { 12500 isCartTotalMinimumValid = true; 12501 } 12502 12503 var isCartTotalMaximumValid = false; 12504 if (isNaN(paymentMethodCartTotalMaximum) || updateCartBuffer['CartData'].OrderTotal.balance <= paymentMethodCartTotalMaximum) { 12505 isCartTotalMaximumValid = true; 12506 } 12507 12508 if (isCartTotalMinimumValid && isCartTotalMaximumValid) { 12509 $this.closest('.payment-method-option').attr('valid-for-balance-due', 'true'); 12510 } else { 12511 $this.closest('.payment-method-option').attr('valid-for-balance-due', 'false'); 12512 } 12513 }); 12514 12515 if (updateCartBuffer['CartData'] && !updateCartBuffer['CartData'].HasPhysicalShipment && $('.single.shipping-address-type-selector input:checked').val() != SiteConstants.AddressTypes.Customer) { 12516 $('.single.shipping-address-type-selector input[value="' + SiteConstants.AddressTypes.Customer + '"]').click(); 12517 } 12518 12519 tooltip.init({ 12520 items: '.shipping-method-tooltip', 12521 tooltipClass: 'shipping-method-tooltip' 12522 }, $('[shipping-method]')); 12523 12524 tooltip.init({ 12525 items: '.tooltip' 12526 }); 12527 12528 triggerReactWebviewEvent(); 12529 triggerSrFocus(); 12530 $(document).trigger('QuantityStepper.TargetFocus'); 12531 $(document).trigger('Cart.UpdateSuccess'); 12532 } 12533} 12534 12535function triggerSrFocus() { 12536 $('[role="alert"]:visible').last().focus().addClass('focus-visible-indicator'); 12537} 12538 12539function checkCheckoutAccessibility() { 12540 if ($('.order-item').length == 0) { 12541 $('.section-checkout > div').removeClass('active'); 12542 $('.billing-address-form, .shipping-address-cont, .shipping-payment-cont').hide(); 12543 $('.form-checkout.login-element, .section-checkout').addClass('empty-cart'); 12544 } 12545} 12546 12547/** 12548 * @description Make the AJAX request to get customer data 12549 * @param {Element} form The form element that contains the item quantity and ID data 12550 * @param {Element} Action name to apply to form 12551 * @returns {Promise} 12552 */ 12553var updateCustomerDetails = function (form, name) { 12554 var $form = $(form); 12555 12556 return TPromise.resolve($.ajax({ 12557 type: 'POST', 12558 url: util.ajaxUrl(Urls.onePageLogin), 12559 data: $form.serialize() + '&' + name + '=' + name 12560 })); 12561}; 12562 12563/** 12564 * @description Make the AJAX request to reset customer password 12565 * @param {String} registered customer email 12566 * @returns {Promise} 12567 */ 12568var resetCustomerPassword = function (email) { 12569 return TPromise.resolve($.ajax({ 12570 type: 'POST', 12571 url: util.ajaxUrl(Urls.resetOPCPass), 12572 data: 'email='+ email 12573 })); 12574}; 12575 12576/** 12577 * @description Make the AJAX request to reset customer password 12578 * @param {String} error message 12579 * @param {Element} element to add error after 12580 * @returns {Void} 12581 */ 12582var showError = function(message, selector){ 12583 var $errorContainer = selector.closest('field-wrapper').next('.error'); 12584 12585 if (!$errorContainer.prop('defaultText') || $errorContainer.text() != message) { 12586 selector.prop('defaultText', $errorContainer.text()); 12587 } 12588 12589 $errorContainer.text(message).show(); 12590}; 12591 12592/** 12593 * @description Make the AJAX request to reset customer password 12594 * @param {String} notification text 12595 * @param {Element} selector to apply message 12596 * @param {String} notification type: error or success 12597 * @returns {Void} 12598 */ 12599function showNotification(text, selector, msgType) { 12600 var $selector = $(selector); 12601 if ($selector.length == 0) { 12602 var $form = $('form.opc-login'); 12603 $selector = $('<span/>', {'class': 'login-notification'}).wrap('<div class="formfield clearfix error-box"><div class="form-row required"><div class="field-wrapper"></div></div></div>'); 12604 12605 $selector.parent().parent().parent().insertBefore('form.opc-login .form-row-button'); 12606 $selector = $(selector); 12607 } 12608 12609 $selector.removeClass('success error').addClass(msgType).text(text); 12610}; 12611 12612/** 12613 * @description Make the AJAX request to reset customer password 12614 * @param {Element} selector to clear notification type: error or success 12615 * @returns {Void} 12616 */ 12617function clearNotification(selector){ 12618 if (selector.length) { 12619 $('.formfield.error-box').remove(); 12620 selector.removeClass('success error'); 12621 } 12622}; 12623 12624exports.updateCart = updateCart; 12625exports.init = function (optionsParameter) { 12626 options = optionsParameter; 12627 if (options && options.isCartPage) { 12628 isCartPage = true; 12629 } 12630 initializeEvents(); 12631 if (SitePreferences.STORE_PICKUP) { 12632 cartStoreInventory.init(); 12633 } 12634 ApplePay.initialize(options); 12635 account.initCartLogin(); 12636 quantityStepper.init(updateCart); 12637 updateCart('dwfrm_cart_updateCart', null, options.isCartPage); 12638 12639 12640 12641 $(document).off('click', '.discount-custom-button').on('click', '.discount-custom-button', function(event) { 12642 event.preventDefault(); 12643 12644 dialog.open({ 12645 html: $('.discount-dialog-content').html(), 12646 options: { 12647 title: 'Thorogood Boot Barn Discount', 12648 dialogClass: 'fixed', 12649 draggable: false, 12650 open: function(event, ui) { 12651 $('body').addClass('dialog-open'); 12652 }, 12653 close: function(event, ui) { 12654 $('body').removeClass('dialog-open'); 12655 } 12656 } 12657 }); 12658 }); 12659}; 12660 12661},{"../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants":113,"../../../../bc_sheplersbootbarn_core/cartridge/js/DataLayerConstants":114,"../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants":117,"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../ajax":3,"../bonus-products-view":6,"../dialog":36,"../page":46,"../quantityStepper":87,"../quickview":88,"../storeinventory/cart":96,"../tooltip":101,"../util":102,"./account":48,"./checkout/ApplePay":53,"./checkout/formPrepare":61,"promise":134}],51:[function(require,module,exports){ 12662'use strict'; 12663 12664var addToCart = require('./product/addToCart'); 12665var quantityStepper = require('../quantityStepper'); 12666var loadingIndicator = require('../components/LoadingIndicator'); 12667var _ = require('lodash'); 12668var TemplateConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 12669 12670var html = {}; 12671var options = {}; 12672var data = {}; 12673var templates = {}; 12674 12675var video; 12676var stream; 12677var barcodeDetector; 12678var barcodeDetectorInterval; 12679var barcodeScanInputAddProductTimer; 12680var barcodeScanInputFocusInterval; 12681var productSearchInputFocusInterval; 12682 12683var $productFinder; 12684var $barcodeScanner; 12685var $barcodeScannerInputContainer; 12686var $barcodeScannerInput; 12687var $barcodeScannerErrorContainer; 12688var $barcodeScannerAddButton; 12689var $barcodeScannerAddButtonText; 12690var $barcodeScannerStartButton; 12691var $barcodeScannerStartButtonText; 12692var $barcodeScannerModal; 12693var $productSearch; 12694var $productSearchInputContainer; 12695var $productSearchInput; 12696var $productSearchErrorContainer; 12697var $productSearchSearchButton; 12698var $productSearchSearchButtonText; 12699var $productSearchResultsContainer; 12700var $productSearchResults; 12701var $productSearchResultsFooter; 12702var $productSearchResultsLoadMore; 12703 12704function initialize(options) { 12705 $productFinder = $('.product-finder'); 12706 $barcodeScanner = $productFinder.find('.section.scan'); 12707 $barcodeScannerInputContainer = $barcodeScanner.find('.input'); 12708 $barcodeScannerInput = $barcodeScannerInputContainer.find('input'); 12709 $barcodeScannerErrorContainer = $barcodeScanner.find('.error'); 12710 $barcodeScannerAddButton = $barcodeScanner.find('.action.add'); 12711 $barcodeScannerAddButtonText = $barcodeScannerAddButton.find('span'); 12712 $barcodeScannerStartButton = $barcodeScanner.find('.action.start'); 12713 $barcodeScannerStartButtonText = $barcodeScannerStartButton.find('span'); 12714 $barcodeScannerModal = $barcodeScanner.find('.modal'); 12715 $productSearch = $productFinder.find('.section.search'); 12716 $productSearchInputContainer = $productSearch.find('.input'); 12717 $productSearchInput = $productSearchInputContainer.find('input'); 12718 $productSearchErrorContainer = $productSearch.find('.error'); 12719 $productSearchSearchButton = $productSearch.find('.action.search'); 12720 $productSearchSearchButtonText = $productSearchSearchButton.find('span'); 12721 $productSearchResultsContainer = $productSearch.find('.results-container'); 12722 $productSearchResults = $productSearchResultsContainer.find('.results'); 12723 $productSearchResultsFooter = $productSearchResultsContainer.find('footer'); 12724 $productSearchResultsLoadMore = $productSearchResultsContainer.find('.load-more'); 12725 12726 if (('BarcodeDetector' in window)) { 12727 $barcodeScanner.addClass('barcode-detector'); 12728 } 12729 12730 data['ProductSearchPageSize'] = 5; 12731 12732 templates['variations'] = _.template($('#template-variations').html(), TemplateConstants.Lodash.Settings); 12733 templates['variationSelector'] = _.template($('#template-variations-selector').html(), TemplateConstants.Lodash.Settings); 12734 templates['variationSelectorAttributeGuide'] = _.template($('#template-variations-attribute-guide').html(), TemplateConstants.Lodash.Settings); 12735 templates['variationSelectorDropdown'] = _.template($('#template-variations-selector-dropdown').html(), TemplateConstants.Lodash.Settings); 12736 templates['variationSelectorDropdownOption'] = _.template($('#template-variations-selector-dropdown-option').html(), TemplateConstants.Lodash.Settings); 12737 templates['variationSelectorDropdownOptionSelected'] = _.template($('#template-variations-selector-dropdown-option-selected').html(), TemplateConstants.Lodash.Settings); 12738 templates['variationSelectorSwatch'] = _.template($('#template-variations-selector-swatch').html(), TemplateConstants.Lodash.Settings); 12739 templates['variationSelectorSwatchOption'] = _.template($('#template-variations-selector-swatch-option').html(), TemplateConstants.Lodash.Settings); 12740 templates['variationSelectorSwatchOptionUnselectable'] = _.template($('#template-variations-selector-swatch-option-unselectable').html(), TemplateConstants.Lodash.Settings); 12741 12742 // $(document).off('keyup.BarcodeScannerInput').on('keyup.BarcodeScannerInput', '.input', function(event) { 12743 // var $this = $(this); 12744 12745 // $barcodeScannerErrorContainer.html(''); 12746 // if (barcodeScanInputAddProductTimer) {
12747 // clearTimeout(barcodeScanInputAddProductTimer); 12748 // } 12749 12750 // barcodeScanInputAddProductTimer = setTimeout(function() { 12751 // addProductWithUpc($this.val()); 12752 // }, 250); 12753 // }); 12754 12755 $productFinder.off('click.Add').on('click.Add', '.action.add', function(event) { 12756 event.preventDefault(); 12757 addProductWithUpc($barcodeScannerInput.val()); 12758 }); 12759 12760 $productFinder.off('click.OptionsToggle').on('click.OptionsToggle', '.action.options', function(event) { 12761 $(this).addClass('active'); 12762 }); 12763 12764 $productFinder.off('click.ModeSet').on('click.ModeSet', '.options [set-mode]', function(event) { 12765 $barcodeScannerErrorContainer.html(''); 12766 $productSearchErrorContainer.html(''); 12767 $('.product-finder').attr('mode', $(this).attr('set-mode')); 12768 $('.action.options').removeClass('active'); 12769 }); 12770 12771 $(document).off('click.OptionsClose').on('click.OptionsClose', function(event) { 12772 var $target = $(event.target); 12773 if (!$target.hasClass('options') && $target.closest('.options').length == 0) { 12774 $('.action.options').removeClass('active'); 12775 } 12776 }); 12777 12778 $barcodeScanner.off('click.KeyboardToggle').on('click.KeyboardToggle', '.options .keyboard', function(event) { 12779 if ($(this).hasClass('active')) { 12780 $(this).removeClass('active'); 12781 $barcodeScannerInput.attr('inputmode', 'none'); 12782 } else { 12783 $(this).addClass('active'); 12784 $barcodeScannerInput.attr('inputmode', $barcodeScannerInput.attr('type')); 12785 } 12786 $('.action.options').removeClass('active'); 12787 }); 12788 12789 $barcodeScanner.off('click.BarcodeScannerStart').on('click.BarcodeScannerStart', '.action.start', function(event) { 12790 if (!('BarcodeDetector' in window)) { 12791 alert('Barcode Detector is not supported by this browser.'); 12792 } else { 12793 $('.section.scan').addClass('active'); 12794 12795 if (!barcodeDetector) { 12796 barcodeDetector = new BarcodeDetector(); 12797 } 12798 12799 video = $barcodeScannerModal.find('video')[0]; 12800 video.setAttribute('playsinline', ''); 12801 video.setAttribute('autoplay', ''); 12802 video.setAttribute('muted', ''); 12803 video.style.width = '100%'; 12804 video.style.height = '100%'; 12805 12806 var constraints = { 12807 audio: false, 12808 video: { 12809 facingMode: 'environment' 12810 } 12811 }; 12812 12813 navigator.mediaDevices.getUserMedia(constraints).then(function success(mediaStream) { 12814 stream = mediaStream; 12815 video.srcObject = stream; 12816 }); 12817 12818 video.onloadedmetadata = function(event) { 12819 barcodeDetectorInterval = setInterval(detectBarcode, 500); 12820 }; 12821 } 12822 }); 12823 12824 $(document).off('click.BarcodeScannerStop').on('click.BarcodeScannerStop', '.modal .close', function(event) { 12825 closeBarcodeScanner(); 12826 }); 12827 12828 $(document).off('paste.UPC').on('paste.UPC', function(event) { 12829 if (!$barcodeScannerInput.is(":focus") && $(event.target).closest('.product-finder').length > 0) { 12830 getClipboardValue(event, this, function(upc) { 12831 $barcodeScannerErrorContainer.html(''); 12832 addProductWithUpc(upc); 12833 }); 12834 } 12835 }); 12836 12837 $productSearchInput.off('keyup.ProductSearchChange').on('keyup.ProductSearchChange', function(event) { 12838 updateProductSearchAction(); 12839 }); 12840 12841 $productSearch.off('click.ProductSearchStart').on('click.ProductSearchStart', '.action.search', function(event) { 12842 event.preventDefault(); 12843 var query = $productSearchInput.val(); 12844 if (query) { 12845 if ($productSearchInputContainer.attr('action') == 'search') { 12846 $productSearchResults.html(''); 12847 $productSearch.removeClass('active'); 12848 data['ProductSearchPage'] = 1; 12849 searchProductsWithQuery(query); 12850 } else { 12851 resetProductSearch(); 12852 } 12853 } 12854 }); 12855 12856 $productSearch.off('click.ProductSearchLoadMore').on('click.ProductSearchLoadMore', '.load-more', function(event) { 12857 var query = $productSearchInput.val(); 12858 if (query) { 12859 data['ProductSearchPage'] += 1; 12860 searchProductsWithQuery(query); 12861 } 12862 }); 12863 12864 $productSearch.off('click.ProductSearchProductSelect').on('click.ProductSearchProductSelect', '.grid-tile .product-tile a', function(event) { 12865 event.preventDefault(); 12866 12867 var $this = $(this); 12868 var $gridTile = $this.closest('.grid-tile'); 12869 var $productTile = $this.closest('.product-tile'); 12870 if ($gridTile.find('.product-variations').length > 0) { 12871 $gridTile.find('.product-variations').remove(); 12872 } else { 12873 getStylesForProduct($productTile.data('itemid')); 12874 } 12875 }); 12876 12877 $productSearch.off('change.ProductSearchAttributeSelect').on('change.ProductSearchAttributeSelect', '.grid-tile .product-variations select', function(event) { 12878 var $productTile = $(this).closest('.grid-tile').find('.product-tile'); 12879 getStylesForProduct($productTile.data('itemid')); 12880 }); 12881 12882 $productSearch.off('click.ProductSearchProductAdd').on('click.ProductSearchProductAdd', '.grid-tile .product-variations .btn.add', function(event) { 12883 var $this = $(this); 12884 if ($this.attr('pid')) { 12885 addProductWithProductId($this.attr('pid'), $this); 12886 } 12887 }); 12888 12889 $productSearch.off('click.ProductSearchClose').on('click.ProductSearchClose', '.results-container .close', function(event) { 12890 $('body').removeClass('product-search'); 12891 }); 12892 12893 if (!options || options.StoreUIVersion != '2024Redesign') { 12894 barcodeScanInputFocusInterval = setInterval(function() { 12895 if (!$barcodeScannerInput.is(':visible:focus') && $barcodeScanner.find(':focus').length == 0) { 12896 $barcodeScannerInput.focus(); 12897 } 12898 }, 500); 12899 12900 productSearchInputFocusInterval = setInterval(function() { 12901 if (!$productSearchInput.is(':visible:focus') && !$productSearch.hasClass('active') && $productSearch.find(':focus').length == 0) { 12902 $productSearchInput.focus(); 12903 } 12904 }, 500); 12905 12906 $(document).off('click.Checkout').on('click.Checkout', '.checkout .btn.btn-checkout', function (event) { 12907 $(this).loading({ 12908 IsLabelShown: false,
12909 BackgroundColor: 'transparent' 12910 }); 12911 }); 12912 12913 quantityStepper.init(null, renderCart); 12914 addToCart(); 12915 } 12916} 12917 12918function updateProductSearchAction() { 12919 var productSearchInputValue = $productSearchInput.val(); 12920 if (productSearchInputValue) { 12921 productSearchInputValue = productSearchInputValue.toLowerCase(); 12922 } 12923 var productSearchQueryValue = $productSearchInputContainer.attr('query'); 12924 if (productSearchQueryValue) { 12925 productSearchQueryValue = productSearchQueryValue.toLowerCase(); 12926 } 12927 12928 if (productSearchInputValue && productSearchQueryValue && productSearchInputValue == productSearchQueryValue) { 12929 $productSearchInputContainer.attr('action', 'reset'); 12930 } else { 12931 $productSearchInputContainer.attr('action', 'search'); 12932 } 12933} 12934 12935function searchProductsWithQuery(query) { 12936 $productSearchErrorContainer.html(''); 12937 $productSearchInputContainer.attr('query', query); 12938 $productSearchInputContainer.loading({ 12939 IsImageShown: false, 12940 IsLabelShown: false 12941 }); 12942 $productSearchSearchButton.loading({ 12943 IsLabelShown: false, 12944 BackgroundColor: 'transparent' 12945 }); 12946 if ($productSearchResultsLoadMore.is(':visible')) { 12947 $productSearchResultsLoadMore.loading({ 12948 IsLabelShown: false,
12949 BackgroundColor: 'transparent' 12950 }); 12951 } 12952 $productSearchInput.attr('disabled', 'disabled'); 12953 12954 $.ajax({ 12955 type: 'GET', 12956 url: Urls.Search.Show, 12957 data: { 12958 format: 'ajax', 12959 q: query, 12960 // prefn1: 'availableStores', 12961 // prefv1: options.AgentStoreID, 12962 start: parseInt((data['ProductSearchPage'] - 1) * data['ProductSearchPageSize'], 10), 12963 sz: data['ProductSearchPageSize'] 12964 }, 12965 success: function(response) { 12966 var $html = $(response); 12967 var $productGrid = $html.find('#search-result-items'); 12968 var $pagination = $html.find('.search-result-options .pagination[count]').first(); 12969 var productTileCount = $productGrid.find('.grid-tile').length + $('.section.search .results-container').find('.grid-tile').length; 12970 var productTotalCount = 0; 12971 if ($pagination.length > 0) { 12972 productTotalCount = parseInt($html.find('.search-result-options .pagination[count]').first().attr('count').replace(/\D/g, ''), 10); 12973 } 12974 12975 if (productTileCount > 0) { 12976 $productSearchResults.append($productGrid.html()); 12977 if (productTileCount < productTotalCount) { 12978 $productSearchResultsFooter.show(); 12979 } else { 12980 $productSearchResultsFooter.hide(); 12981 } 12982 } else { 12983 $productSearchResults.append($('<li class="no-results">No products found for your search.</li>')); 12984 $productSearchResultsFooter.hide(); 12985 } 12986 $productSearch.addClass('active'); 12987 }, 12988 complete: function(xhr) { 12989 $productSearchInputContainer.attr('upc', ''); 12990 $productSearchInputContainer.loading('destroy'); 12991 $productSearchSearchButton.loading('destroy'); 12992 if ($productSearchResultsLoadMore.attr('loading')) { 12993 $productSearchResultsLoadMore.loading('destroy'); 12994 } 12995 $productSearchInput.removeAttr('disabled'); 12996 updateProductSearchAction(); 12997 } 12998 }); 12999} 13000 13001function getStylesForProduct(productId) { 13002 var $productTile = $productSearchResults.find('.product-tile[data-itemid="' + productId + '"]'); 13003 13004 if ($productTile.length > 0) { 13005 var $gridTile = $productTile.closest('.grid-tile'); 13006 13007 if ($gridTile.length > 0) { 13008 var isFirstLoad = false; 13009 var $productVariations; 13010 if ($gridTile.find('.product-variations').length > 0) { 13011 $productVariations = $gridTile.find('.product-variations'); 13012 } else { 13013 isFirstLoad = true; 13014 $productVariations = $gridTile.append('<div class="product-variations"></div>').find('.product-variations'); 13015 } 13016 $productVariations.loading({ 13017 IsLabelShown: false, 13018 BackgroundColor: 'transparent' 13019 }); 13020 if ($gridTile.find('.btn.add').is(':visible')) { 13021 $gridTile.find('.btn.add').loading({ 13022 IsLabelShown: false, 13023 BackgroundColor: 'transparent' 13024 }); 13025 } 13026 data['attributeGuides'] = {}; 13027 13028 var payload = { 13029 pid: $productTile.data('itemid') 13030 } 13031 13032 if (!isFirstLoad) { 13033 var $productVariationAttributesSelected = $productVariations.find('[attribute] option.selectable:checked'); 13034 $productVariationAttributesSelected.each(function() { 13035 var $this = $(this); 13036 var productVariationAttributeId = $this.closest('[attribute]').attr('attribute'); 13037 var productVariationAttributeValue = $this.val(); 13038 payload['dwvar_' + payload.pid + '_' + productVariationAttributeId] = productVariationAttributeValue; 13039 }); 13040 } 13041 13042 $.ajax({ 13043 method: 'post', 13044 url: Urls.getVariationAttributes, 13045 data: payload, 13046 dataType: 'json', 13047 success: function(response) { 13048 html['variationSelectors'] = ''; 13049 for (var variation in response.variations) { 13050 var variationData = response.variations[variation]; 13051 var variationDataValueSelected = null; 13052 13053 html['variationSelectorWidgetOptions'] = ''; 13054 13055 for (var variationValue in variationData.values) { 13056 var variationDataValue = variationData.values[variationValue]; 13057 var variationDataValueTemplate; 13058 13059 var variationDataValuePayload = { 13060 attribute: variationDataValue.attribute, 13061 valueId: variationDataValue.valueId, 13062 value: variationDataValue.value, 13063 title: variationDataValue.title, 13064 text: variationDataValue.text, 13065 stock: variationDataValue.stock, 13066 shipping: variationDataValue.shipping, 13067 isSameDayShippingWindow: variationDataValue.isSameDayShippingWindow, 13068 quantitySourceType: variationDataValue.quantitySourceType, 13069 href: variationDataValue.href, 13070 selectable: variationDataValue.selectable ? 'selectable' : 'unselectable', 13071 selected: !isFirstLoad && variationDataValue.selected ? 'selected' : '', 13072 swatchImageUrl: variationDataValue.images.swatch.url, 13073 largeSwatchImageUrl: variationDataValue.images.largeSwatch.url, 13074 hrefAttribute: variationDataValue.selectable ? 'href' : 'xhref' 13075 }; 13076 13077 if (variationData.type == 'swatch') { 13078 if (variationDataValue.selectable) { 13079 variationDataValueTemplate = templates['variationSelectorSwatchOption']; 13080 13081 variationDataValuePayload.imageLarge = JSON.stringify({ 13082 url: variationDataValue.images.large.url, 13083 title: variationDataValue.images.large.title, 13084 alt: variationDataValue.images.large.alt, 13085 hires: variationDataValue.images.hires.url 13086 }); 13087 } else { 13088 variationDataValueTemplate = templates['variationSelectorSwatchOptionUnselectable']; 13089 } 13090 } else { 13091 variationDataValueTemplate = templates['variationSelectorDropdownOption']; 13092 13093 if (variationDataValue.selected) { 13094 variationDataValueSelected = variationDataValue; 13095 } 13096 } 13097 13098 html['variationSelectorWidgetOptions'] += variationDataValueTemplate(variationDataValuePayload); 13099 } 13100 13101 if (variationData.type == 'swatch') { 13102 html['variationSelectorWidget'] = templates['variationSelectorSwatch']({ 13103 attribute: variationData.productVariationAttribute, 13104 options: html['variationSelectorWidgetOptions'] 13105 }); 13106 } else { 13107 var placeholder = variationData.label.placeholder; 13108 if (variationDataValueSelected) { 13109 placeholder = templates['variationSelectorDropdownOptionSelected']({ 13110 text: variationDataValueSelected.text, 13111 stock: variationDataValueSelected.stock, 13112 shipping: variationDataValueSelected.shipping, 13113 isSameDayShippingWindow: variationDataValueSelected.isSameDayShippingWindow, 13114 quantitySourceType: variationDataValueSelected.quantitySourceType 13115 }); 13116 } 13117 13118 html['variationSelectorWidget'] = templates['variationSelectorDropdown']({ 13119 attribute: variationData.productVariationAttribute, 13120 text: placeholder, 13121 options: html['variationSelectorWidgetOptions'] 13122 }); 13123 } 13124 13125 html['attributeGuide'] = ''; 13126 if (variationData.attributeGuide) { 13127 data['attributeGuides'][variationData.productVariationAttribute] = variationData.attributeGuide; 13128 html['attributeGuide'] = templates['variationSelectorAttributeGuide'](_.extend(variationData.attributeGuide, { Attribute: variationData.productVariationAttribute })); 13129 } 13130 13131 html['variationSelector'] = templates['variationSelector']({ 13132 attribute: variationData.productVariationAttribute, 13133 label: { 13134 text: variationData.label.text, 13135 message: variationData.label.message 13136 }, 13137 selector: html['variationSelectorWidget'], 13138 guide: html['attributeGuide'] 13139 }); 13140 13141 html['variationSelectors'] += html['variationSelector']; 13142 } 13143 13144 html['selectors'] = templates['variations']({ 13145 selectors: html['variationSelectors'] 13146 }); 13147 13148 $productVariations.html(html['selectors']).addClass('loaded'); 13149 if (response.pid) { 13150 $gridTile.find('.btn.add').attr('pid', response.pid); 13151 } else { 13152 $gridTile.find('.btn.add').removeAttr('pid'); 13153 } 13154 }, 13155 complete: function(xhr) { 13156 $productVariations.loading('destroy'); 13157 } 13158 }); 13159 } 13160 } 13161} 13162 13163function resetProductSearch() { 13164 $productSearch.removeClass('active'); 13165 $productSearchInputContainer.attr('query', ''); 13166 $productSearchInput.val(''); 13167 $productSearchInput.focus(); 13168 updateProductSearchAction(); 13169} 13170 13171function addProductWithProductId(productId, $gridTileAddButton) { 13172 if ($gridTileAddButton) { 13173 $gridTileAddButton.loading({ 13174 IsLabelShown: false,
13175 BackgroundColor: 'transparent' 13176 }); 13177 } 13178 $productSearchErrorContainer.html(''); 13179 13180 addProduct({ 13181 payload: { 13182 pid: productId 13183 }, 13184 complete: function(xhr) { 13185 if ($gridTileAddButton && $gridTileAddButton.attr('loading')) { 13186 $gridTileAddButton.loading('destroy'); 13187 } 13188 resetProductSearch(); 13189 renderCart(); 13190 } 13191 }); 13192} 13193 13194function detectBarcode() { 13195 var canvas = $barcodeScannerModal.find('canvas')[0]; 13196 canvas.width = video.videoWidth; 13197 canvas.height = video.videoHeight; 13198 13199 var canvasContext = canvas.getContext('2d'); 13200 canvasContext.drawImage(video, 0, 0, canvas.width, canvas.height); 13201 13202 var barcodeDetector = new BarcodeDetector(); 13203 barcodeDetector.detect(canvasContext.getImageData(0, 0, canvas.width, canvas.height)).then(barcodes => { 13204 $barcodeScannerModal.addClass('scanned'); 13205 13206 barcodes.forEach(function(barcode) { 13207 var barcodeValue; 13208 if ('rawValue' in barcode) { 13209 barcodeValue = barcode.rawValue; 13210 } else if ('rawData' in barcode) { 13211 barcodeValue = barcode.rawData; 13212 } 13213 13214 closeBarcodeScanner(); 13215 addProductWithUpc(barcodeValue); 13216 }); 13217 }).catch(error => { 13218 // alert(error); 13219 }); 13220} 13221 13222function closeBarcodeScanner() { 13223 $('.section.scan').removeClass('active'); 13224 if (barcodeDetectorInterval) { 13225 barcodeDetectorInterval = clearInterval(barcodeDetectorInterval); 13226 } 13227 stream.getTracks().forEach(function(track) { 13228 track.stop(); 13229 }); 13230 video.srcObject = null; 13231} 13232 13233function getClipboardValue(event, element, callback) { 13234 if (navigator.clipboard && navigator.clipboard.readText) { 13235 // modern approach with Clipboard API 13236 navigator.clipboard.readText().then(callback); 13237 } else if (event.originalEvent && event.originalEvent.clipboardData) { 13238 // OriginalEvent is a property from jQuery, normalizing the event object 13239 callback(event.originalEvent.clipboardData.getData('text')); 13240 } else if (event.clipboardData) { 13241 // used in some browsers for clipboardData 13242 callback(event.clipboardData.getData('text/plain')); 13243 } else if (window.clipboardData) {
13244 // Older clipboardData version for Internet Explorer only 13245 callback(window.clipboardData.getData('Text')); 13246 } else { 13247 // Last resort fallback, using a timer 13248 setTimeout(function() { 13249 callback(element.value) 13250 }, 100); 13251 } 13252} 13253 13254function addProductWithUpc(upc) { 13255 $barcodeScannerInputContainer.attr('upc', upc); 13256 $barcodeScannerInputContainer.loading({ 13257 IsImageShown: false, 13258 IsLabelShown: false 13259 }); 13260 $barcodeScannerAddButton.loading({ 13261 IsLabelShown: false, 13262 BackgroundColor: 'transparent' 13263 }); 13264 $barcodeScannerInput.val(''); 13265 $barcodeScannerErrorContainer.html(''); 13266 $barcodeScannerInput.attr('disabled', 'disabled'); 13267 13268 addProduct({ 13269 payload: { 13270 upc: upc 13271 }, 13272 success: function(response) { 13273 if (response && !response.IsProductInProductService) { 13274 $barcodeScannerErrorContainer.append('<p>Product not found in service!</p>'); 13275 } else if (response && !response.IsProductInCatalog) { 13276 $barcodeScannerErrorContainer.append('<p>Product not found in catalog!</p>'); 13277 } 13278 }, 13279 complete: function(xhr) { 13280 $barcodeScannerInputContainer.attr('upc', ''); 13281 $barcodeScannerInputContainer.loading('destroy'); 13282 $barcodeScannerAddButton.loading('destroy'); 13283 $barcodeScannerInput.removeAttr('disabled'); 13284 renderCart(); 13285 } 13286 }); 13287} 13288 13289function addProduct(parameters) { 13290 var payload = $.extend(parameters.payload || {}, { 13291 format: 'ajax', 13292 Quantity: 1, 13293 cartAction: 'add', 13294 csrf_token: options.Token, 13295 channel: 'Echo', 13296 bopis_store: '', 13297 bopis_quantity_available: '', 13298 bopis_shipping_option: '' 13299 }); 13300 13301 if (payload.pid || payload.upc) { 13302 $.ajax({ 13303 type: 'POST', 13304 url: Urls.addProduct, 13305 data: payload, 13306 success: function(response) { 13307 if (parameters.success && typeof parameters.success == 'function') { 13308 parameters.success(response); 13309 } 13310 }, 13311 complete: function(xhr) { 13312 if (parameters.complete && typeof parameters.complete == 'function') { 13313 parameters.complete(xhr); 13314 } 13315 } 13316 }); 13317 } 13318} 13319 13320function renderCart() { 13321 if (options && options.StoreUIVersion == '2024Redesign') { 13322 location.reload(); 13323 } else { 13324 $.ajax({ 13325 type: 'GET', 13326 url: Urls.Cart.GetCartBodyProductLineItems, 13327 success: function(response) { 13328 $('#wrapper > .cart > form').html(response); 13329 } 13330 }); 13331 13332 $.ajax({ 13333 type: 'POST', 13334 url: Urls.getCartData, 13335 data: { 13336 isCart: true 13337 }, 13338 success: function(response) { 13339 if (response && response.OrderTotal && response.OrderTotal.adjustedMerchandizeTotalPrice) { 13340 $('.order-subtotal .order-value').text(response.OrderTotal.adjustedMerchandizeTotalPriceDisplay); 13341 $('.order-totals-table').removeClass('hidden'); 13342 } else { 13343 $('.order-totals-table').addClass('hidden'); 13344 } 13345 } 13346 }); 13347 } 13348 13349 updateCSRFToken(); 13350} 13351 13352function updateCSRFToken() { 13353 $.ajax({ 13354 method: 'get', 13355 url: Urls.CSRFToken.Get, 13356 dataType: 'json', 13357 success: function(response) { 13358 options.Token = response.token; 13359 } 13360 }); 13361} 13362 13363exports.renderCart = renderCart; 13364exports.init = function (optionsParameter) { 13365 options = optionsParameter; 13366 initialize(options); 13367}; 13368},{"../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../components/LoadingIndicator":25,"../quantityStepper":87,"./product/addToCart":72,"lodash":133}],52:[function(require,module,exports){ 13369'use strict'; 13370 13371var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 13372var sizeRefinements = require('../size-refinements'); 13373var sliders = require('../sliders'); 13374var styleCounts = require('../style-counts'); 13375var util = require('../util'); 13376 13377exports.init = function(options) { 13378 styleCounts.render(options.StyleCountCache); 13379 sizeRefinements.init(); 13380 sliders.initializeCategorySliders('.main-content .category-landing-slider:not(.slick-initialized)'); 13381}; 13382},{"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../size-refinements":93,"../sliders":95,"../style-counts":99,"../util":102}],53:[function(require,module,exports){ 13383'use strict'; 13384 13385var dialog = require('../../dialog'); 13386var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 13387var OrderConfirmation = require('../orderconfirmation'); 13388 13389exports.initialize = initialize; 13390 13391var applePaySession; 13392var options = {}; 13393var buffer = {}; 13394 13395function initialize(optionsParameter) { 13396 options = optionsParameter || {}; 13397 13398 $('[payment-method-container="DW_APPLE_PAY"]').attr('can-make-payments', 'ApplePaySession' in window && 'canMakePayments' in ApplePaySession && ApplePaySession.canMakePayments()); 13399 $('[payment-method-group-container="DW_APPLE_PAY"]').attr('can-make-payments', 'ApplePaySession' in window && 'canMakePayments' in ApplePaySession && ApplePaySession.canMakePayments()); 13400 if (options.isCartPage || options.isCheckoutPage) { 13401 getApplePayPaymentRequest(); 13402 }
13403 $(document).off('ApplePay.GetPaymentRequest').on('ApplePay.GetPaymentRequest Cart.UpdateSuccess ProductDetailPage.Variant.Updated ProductDetailPage.AddToCartOptionsSelect', function(event, data) { 13404 $('[payment-method-container="DW_APPLE_PAY"]').attr('can-make-payments', 'ApplePaySession' in window && 'canMakePayments' in ApplePaySession && ApplePaySession.canMakePayments()); 13405 $('[payment-method-group-container="DW_APPLE_PAY"]').attr('can-make-payments', 'ApplePaySession' in window && 'canMakePayments' in ApplePaySession && ApplePaySession.canMakePayments()); 13406 getApplePayPaymentRequest(data); 13407 }); 13408 13409 $(document).off('click.ApplePay').on('click.ApplePay', '.submit-applepay-button', function(event) { 13410 var isVariantSelected = true; 13411 if (options.ProductId) { 13412 var sizeSelected = $('div.product-variations .size.size-options li.selected'); 13413 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 13414 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 13415 var isSizeSelected = sizeSelected.length || (lengthSelected && widthSelected); 13416 13417 if (!isSizeSelected) { 13418 dialog.open({ 13419 html: 'Please select a size', 13420 options: { 13421 dialogClass: 'dialog-alert', 13422 draggable: false 13423 } 13424 }); 13425 isVariantSelected = false; 13426 } 13427 13428 if (!$('div.product-variations .color.color-options li.selected').length) { 13429 dialog.open({ 13430 html: 'Please select a color', 13431 options: { 13432 dialogClass: 'dialog-alert', 13433 draggable: false 13434 } 13435 }); 13436 isVariantSelected = false; 13437 } 13438 } 13439 13440 if (options.isCartPage || options.isCheckoutPage || isVariantSelected) { 13441 if (pageContext && pageContext.options && pageContext.options.GoogleTagManager && pageContext.options.GoogleTagManager.EnableGoogleAnalytics4) { 13442 var applePayEventData; 13443 var applePayEventOptions; 13444 if (pageContext.type == 'product') { 13445 if (pageContext.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4 && pageContext.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4.items && pageContext.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4.items.length > 0) { 13446 applePayEventData = { 13447 action_name: 'applepay', 13448 action_page_type: 'PDP', 13449 action_value: pageContext.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4.items[0].price, 13450 action_items: [pageContext.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4.items[0].item_id] 13451 } 13452 } 13453 } else if (pageContext.type == 'cart') { 13454 applePayEventData = { 13455 action_name: 'applepay', 13456 action_page_type: 'Cart' 13457 } 13458 applePayEventOptions = { 13459 DecorateDataLayerWithCartTotal: true, 13460 DecorateDataLayerWithCartTotalKey: 'action_value', 13461 DecorateDataLayerWithProductData: true, 13462 DecorateDataLayerWithProductDataKey: 'action_items' 13463 } 13464 } else if (pageContext.type == 'onepcheckout_groups') { 13465 applePayEventData = { 13466 action_name: 'applepay', 13467 action_page_type: 'Checkout' 13468 } 13469 applePayEventOptions = { 13470 DecorateDataLayerWithCartTotal: true, 13471 DecorateDataLayerWithCartTotalKey: 'action_value', 13472 DecorateDataLayerWithProductData: true, 13473 DecorateDataLayerWithProductDataKey: 'action_items' 13474 } 13475 } 13476 if (applePayEventData) { 13477 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', applePayEventData, applePayEventOptions); 13478 } 13479 } 13480 13481 applePaySession = new ApplePaySession(14, buffer['applePayRequest']); 13482 applePaySession.onvalidatemerchant = validateMerchant; 13483 applePaySession.onshippingcontactselected = shippingContactSelected; 13484 applePaySession.onshippingmethodselected = shippingMethodSelected; 13485 applePaySession.onpaymentmethodselected = paymentMethodSelected; 13486 applePaySession.oncouponcodechanged = couponCodeChanged; 13487 applePaySession.onpaymentauthorized = paymentAuthorized; 13488 applePaySession.oncancel = cancel; 13489 applePaySession.begin(); 13490 } 13491 }); 13492} 13493 13494function validateMerchant(event) { 13495 fetch(Urls.ApplePay.ValidateMerchant, getFetchOptions('POST', event)) 13496 .then(function(response) { 13497 return response.json(); 13498 }) 13499 .then(function(response) { 13500 applePaySession.completeMerchantValidation(response); 13501 }) 13502 .catch(function(error) { 13503 console.error('ApplePay-ValidateMerchant', error); 13504 }); 13505} 13506 13507function shippingContactSelected(event) { 13508 fetch(Urls.ApplePay.ShippingContactSelected, getFetchOptions('POST', event)) 13509 .then(function(response) { 13510 return response.json(); 13511 }) 13512 .then(function(response) { 13513 applePaySession.completeShippingContactSelection(response); 13514 if (!options || !options.ProductId) { 13515 $(document).trigger('Cart.Update'); 13516 } 13517 }) 13518 .catch(function(error) { 13519 console.error('ApplePay-ShippingContactSelected', error); 13520 }); 13521} 13522 13523function shippingMethodSelected(event) { 13524 fetch(Urls.ApplePay.ShippingMethodSelected, getFetchOptions('POST', event)) 13525 .then(function(response) { 13526 return response.json(); 13527 }) 13528 .then(function(response) { 13529 applePaySession.completeShippingMethodSelection(response); 13530 if (!options || !options.ProductId) { 13531 $(document).trigger('Cart.Update'); 13532 } 13533 }) 13534 .catch(function(error) { 13535 console.error('ApplePay-ShippingMethodSelected', error); 13536 }); 13537} 13538 13539function paymentMethodSelected(event) { 13540 fetch(Urls.ApplePay.PaymentMethodSelected, getFetchOptions('POST', event)) 13541 .then(function(response) { 13542 return response.json(); 13543 }) 13544 .then(function(response) { 13545 applePaySession.completePaymentMethodSelection(response); 13546 }) 13547 .catch(function(error) { 13548 console.error('ApplePay-PaymentMethodSelected', error); 13549 }); 13550} 13551 13552function couponCodeChanged(event) { 13553 fetch(Urls.ApplePay.CouponCodeChanged) 13554 .then(function(response) { 13555 return response.json(); 13556 }) 13557 .then(function(response) { 13558 applePaySession.completeCouponCodeChange(response); 13559 }) 13560 .catch(function(error) { 13561 console.error('ApplePay-CouponCodeChanged', error); 13562 }); 13563} 13564 13565function paymentAuthorized(event) { 13566 fetch(Urls.ApplePay.PaymentAuthorized, getFetchOptions('POST', event)) 13567 .then(function(response) { 13568 return response.json(); 13569 }) 13570 .then(function(response) { 13571 if (response.status == 'success') { 13572 applePaySession.completePayment(ApplePaySession.STATUS_SUCCESS); 13573 } else { 13574 applePaySession.completePayment(ApplePaySession.STATUS_FAILURE); 13575 } 13576 }) 13577 .then(function(response) { 13578 if (event.payment) { 13579 if (event.payment.billingContact) { 13580 var billingAddressObject = {}; 13581 billingAddressObject.FirstName = event.payment.billingContact.givenName; 13582 billingAddressObject.LastName = event.payment.billingContact.familyName; 13583 billingAddressObject.PrimaryLine = event.payment.billingContact.addressLines[0] || ''; 13584 billingAddressObject.SecondaryLine = event.payment.billingContact.addressLines[1] || ''; 13585 billingAddressObject.StateCode = event.payment.billingContact.administrativeArea; 13586 billingAddressObject.PostalCode = event.payment.billingContact.postalCode; 13587 billingAddressObject.City = event.payment.billingContact.locality; 13588 13589 if (event.payment.shippingContact && event.payment.shippingContact.phone) { 13590 billingAddressObject.Phone = event.payment.shippingContact.phone.replace('+',''); 13591 } 13592 13593 if (options.isCheckoutPage) { 13594 $(document).trigger('SetAddressFromAddressVerification', $.extend(billingAddressObject, { AddressType: 'billing', DisableSubmitPayment: true, SkipUseBillingAsShipping: true })); 13595 } 13596 } 13597 13598 if (event.payment.shippingContact) { 13599 var shippingAddressObject = {}; 13600 shippingAddressObject.FirstName = event.payment.shippingContact.givenName; 13601 shippingAddressObject.LastName = event.payment.shippingContact.familyName; 13602 if (event.payment.shippingContact.addressLines) { 13603 shippingAddressObject.PrimaryLine = event.payment.shippingContact.addressLines[0] || ''; 13604 shippingAddressObject.SecondaryLine = event.payment.shippingContact.addressLines[1] || ''; 13605 shippingAddressObject.StateCode = event.payment.shippingContact.administrativeArea; 13606 shippingAddressObject.PostalCode = event.payment.shippingContact.postalCode; 13607 shippingAddressObject.City = event.payment.shippingContact.locality; 13608 } 13609 13610 if (event.payment.shippingContact.phoneNumber) { 13611 shippingAddressObject.Phone = event.payment.shippingContact.phoneNumber.replace('+',''); 13612 } 13613 13614 if (event.payment.shippingContact.emailAddress) { 13615 shippingAddressObject.Email = event.payment.shippingContact.emailAddress; 13616 } 13617 13618 if (options.isCheckoutPage) { 13619 $(document).trigger('SetAddressFromAddressVerification', $.extend(shippingAddressObject, { AddressType: '
13619shipping', DisableSubmitPayment: true })); 13620 } 13621 } 13622 } 13623 13624 if (options.ProductId) { 13625 fetch(Urls.ApplePay.Confirmation, getFetchOptions('GET')) 13626 .then(function(response) { 13627 response.text().then(function(text) { 13628 dialog.open({ 13629 html: text, 13630 options: { 13631 dialogClass: 'pt_order-confirmation', 13632 open: function() { 13633 $('body').addClass('dialog-open'); 13634 OrderConfirmation.init(); 13635 var dataLayerOptions = { 13636 PaymentMethod: 'Apple Pay' 13637 }; 13638 $(document).off('click.OrderConfirmationModalClose').on('click.OrderConfirmationModalClose', '.ui-dialog.pt_order-confirmation .btn.continue', function(event) { 13639 event.preventDefault(); 13640 dialog.close(); 13641 }); 13642 GoogleTagManagerClient.PushDataLayerForDataLayerType('ViewOrderConfirmation', null, dataLayerOptions).then(function() { 13643 $(document).trigger('ProductDetailPage.AddToCartOptionsSelect', { ProductId: $('#pid').val(), StoreId: $('.bopis-add-to-cart-options-container .selected-store').attr('store-id') }); 13644 }); 13645 }, 13646 close: function(event, ui) { 13647 $('body').removeClass('dialog-open'); 13648 } 13649 } 13650 }); 13651 }); 13652 }) 13653 .catch(function(error) { 13654 console.error('ApplePay-Confirmation', error); 13655 }); 13656 } else if (options.isCheckoutPage) { 13657 $(document).trigger('Cart.Update'); 13658 } else { 13659 window.location = Urls.onePage; 13660 } 13661 13662 }) 13663 .catch(function(error) { 13664 console.error('ApplePay-PaymentAuthorized', error); 13665 }); 13666} 13667 13668function cancel(event) { 13669 fetch(Urls.ApplePay.Cancel, getFetchOptions('POST')) 13670 .then(function() { 13671 // applePaySession.abort(); 13672 if (options.isCheckoutPage) { 13673 $(document).trigger('Cart.Update'); 13674 } 13675 }) 13676 .catch(function(error) { 13677 console.error('ApplePay-Cancel', error); 13678 }); 13679} 13680 13681function getApplePayPaymentRequest(data) { 13682 var urlSearchParameters; 13683 if (data && data.ProductId) { 13684 urlSearchParameters = new URLSearchParams(); 13685 urlSearchParameters.append('pid', data.ProductId); 13686 if (data.StoreId) { 13687 urlSearchParameters.append('storeid', data.StoreId); 13688 } 13689 var bopisAddToCartOption = $('.bopis-add-to-cart-options-container').find('input[name="AddToCartOption"]:checked').val(); 13690 if (bopisAddToCartOption) { 13691 urlSearchParameters.append('addtocartoption', bopisAddToCartOption); 13692 } 13693 } 13694 13695 fetch(Urls.ApplePay.GetRequest + (urlSearchParameters ? '?' + urlSearchParameters : '')) 13696 .then(function(response) { 13697 return response.json(); 13698 }) 13699 .then(function(applePayRequest) { 13700 buffer['applePayRequest'] = applePayRequest; 13701 }) 13702 .catch(function(error) { 13703 console.error('ApplePay-GetRequest', error); 13704 }); 13705} 13706 13707function getFetchOptions(method, body) { 13708 var fetchOptions = { 13709 credentials: 'include' 13710 }; 13711 if (method) { 13712 fetchOptions.method = method; 13713 } 13714 if (body) { 13715 fetchOptions.headers = { 13716 'Content-Type': 'application/json', 13717 'Accept': 'application/json' 13718 } 13719 fetchOptions.body = JSON.stringify(filterEvent(body)); 13720 } 13721 13722 return fetchOptions; 13723} 13724 13725function filterEvent(event) { 13726 var eventFiltered = {}; 13727 for (var property in event) { 13728 if (!Event.prototype.hasOwnProperty(property)) { 13729 eventFiltered[property] = event[property]; 13730 } 13731 } 13732 return eventFiltered; 13733} 13734},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../dialog":36,"../orderconfirmation":71}],54:[function(require,module,exports){ 13735'use strict'; 13736 13737var _ = require('lodash'); 13738var loadingIndicator = require('../../components/LoadingIndicator'); 13739var giftCardBalanceInquiryDialog = require('../../components/GiftCardBalanceInquiryDialog'); 13740var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 13741var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 13742var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 13743var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 13744var opcpayment = require('./opcpayment'); 13745 13746exports.initialize = initialize; 13747 13748var $giftCardPaymentContainer = $('[payment-method="SVS_Gift_Card"]'); 13749var $giftCardPaymentForm = $giftCardPaymentContainer.find('form'); 13750var $giftCardPaymentCardNumber = $giftCardPaymentContainer.find('input[name$="giftCard_number"]'); 13751var $giftCardPaymentPinNumber = $giftCardPaymentContainer.find('input[name$="giftCard_pin"]'); 13752var $giftCardPaymentMessage = $giftCardPaymentContainer.find('.messages'); 13753var $giftCardPaymentErrorMessage = $giftCardPaymentContainer.find('span.error'); 13754var $giftCardPaymentApplied = $giftCardPaymentContainer.find('.form-giftcards-applied'); 13755var $giftCardPaymentApplyButton = $giftCardPaymentContainer.find('.apply'); 13756var giftCardValidator; 13757var giftCardRecaptcha; 13758var options = {}; 13759var loaded = {}; 13760 13761function renderRecaptcha() { 13762 if (loaded.Recaptcha && $giftCardPaymentApplyButton.length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForGiftCards && options.Recaptcha.GoogleSiteKey) { 13763 giftCardRecaptcha = grecaptcha.render('svs-gift-card-apply-button', { 13764 sitekey: options.Recaptcha.GoogleSiteKey, 13765 callback: submitGiftCard, 13766 badge: 'bottomleft' 13767 }); 13768 } 13769} 13770 13771function initialize(optionsParameter) { 13772 options = optionsParameter || {}; 13773 13774 renderRecaptcha(); 13775 $(document).on('Recaptcha.Loaded', function(event) { 13776 if (!loaded.Recaptcha) { 13777 loaded.Recaptcha = true; 13778 renderRecaptcha(); 13779 } 13780 }); 13781 13782 $giftCardPaymentContainer.on('click', '.apply:not([loading])', function(event) { 13783 event.preventDefault(); 13784 13785 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForGiftCards || !options.Recaptcha.GoogleSiteKey) { 13786 $(document).trigger('GiftCard.Apply'); 13787 } 13788 }); 13789 13790 $(document).on('GiftCard.Apply', function(event) { 13791 event.preventDefault(); 13792 13793 if (parseFloat($('[balance-due]').first().attr('balance-due')) <= 0) { 13794 $giftCardPaymentErrorMessage.html(Resources.RewardsCredit.NoBalanceDue).show(); 13795 13796 if (giftCardRecaptcha != undefined) { 13797 grecaptcha.reset(giftCardRecaptcha); 13798 } 13799 } else { 13800 $giftCardPaymentErrorMessage.html('').hide(); 13801 giftCardValidator = $giftCardPaymentForm.validate(); 13802 $.validator.addMethod('giftCardNumberLength', ValidationHelper.ValidateGiftCardNumberLength, Resources.Validation.Messages.GiftCard.Number.Length); 13803 $.validator.addMethod('giftCardNumberValues', ValidationHelper.ValidateGiftCardNumberValues, Resources.Validation.Messages.GiftCard.Number.Values); 13804 $giftCardPaymentCardNumber.rules('add', ValidationRules.GiftCard.Number); 13805 $giftCardPaymentPinNumber.rules('add', ValidationRules.GiftCard.Pin); 13806 giftCardValidator.form(); 13807 13808 // Adding ADA compliance error messages for giftCardPayment section 13809 if ($giftCardPaymentForm.find('.field.error').length > 0) { 13810 $('.payment-declined').remove(); 13811 var giftCardPaymentFormErrorMessages = opcpayment.getErrorMessages($giftCardPaymentForm); 13812 var giftCardPaymentFormErrorBox = opcpayment.errorBox('
13812Cannot Proceed', 'Please fix the following errors:', giftCardPaymentFormErrorMessages); 13813 if (giftCardPaymentFormErrorBox) { 13814 $giftCardPaymentApplied.after(giftCardPaymentFormErrorBox); 13815 } 13816 } 13817 13818 if (Urls && Urls.GiftCard.Apply && giftCardValidator.valid()) { 13819 var giftCardRowContainerHtml = _.template($('#template-gift-card-row-container').html(), TemplateConstants.Lodash.Settings)(); 13820 var $giftCardPaymentAppliedGiftCard = $(giftCardRowContainerHtml).appendTo($giftCardPaymentApplied); 13821 13822 $giftCardPaymentApplyButton.loading(options.LoadingIndicator || { 13823 IsImageShown: false, 13824 Label: Resources.Loading.Processing 13825 }); 13826 if (!options.LoadingIndicator) { 13827 $giftCardPaymentAppliedGiftCard.loading(options.LoadingIndicator || { 13828 Label: Resources.Loading.GiftCard.Applying 13829 }); 13830 } 13831 13832 var giftCardPaymentCardNumber = $giftCardPaymentCardNumber.val().match(/(\d)/g); 13833 if (giftCardPaymentCardNumber && giftCardPaymentCardNumber.length) { 13834 giftCardPaymentCardNumber = giftCardPaymentCardNumber.join(''); 13835 } 13836 13837 $.ajax({ 13838 method: 'POST', 13839 url: Urls.GiftCard.Apply, 13840 contentType: 'application/json', 13841 data: JSON.stringify({ 13842 number: giftCardPaymentCardNumber, 13843 pin: $giftCardPaymentPinNumber.val(), 13844 amount: null 13845 }), 13846 dataType: 'json', 13847 success: function (data) { 13848 if ($giftCardPaymentApplyButton.attr('loading')) { 13849 $giftCardPaymentApplyButton.loading('destroy'); 13850 } 13851 if ($giftCardPaymentAppliedGiftCard.attr('loading')) { 13852 $giftCardPaymentAppliedGiftCard.loading('destroy'); 13853 } 13854 13855 if (data.success) { 13856 $giftCardPaymentCardNumber.val(''); 13857 $giftCardPaymentPinNumber.val(''); 13858 13859 if (data.amountApplied && data.amountApplied.value > 0) { 13860 $giftCardPaymentApplied.find('[data-id="' + data.id + '"]').remove(); 13861 $giftCardPaymentAppliedGiftCard.attr('data-id', data.id); 13862 13863 var giftCardRowContentHtml = _.template($('#template-gift-card-row-content').html(), TemplateConstants.Lodash.Settings)({ 13864 cardNumber: data.number, 13865 amountApplied: data.amountApplied.displayValue 13866 }); 13867 13868 $giftCardPaymentAppliedGiftCard.html(giftCardRowContentHtml); 13869 } 13870 13871 if (data.message) { 13872 $giftCardPaymentErrorMessage.html(data.message).show(); 13873 } 13874 13875 if (options.StoreUIVersion == '2024Redesign') { 13876 location.reload(); 13877 } else { 13878 $(document).trigger('Cart.Update'); 13879 } 13880 } else { 13881 if (data.message == 'Invalid Message') { 13882 data.message = Resources.Error.Generic; 13883 } 13884 13885 $giftCardPaymentAppliedGiftCard.remove(); 13886 $giftCardPaymentErrorMessage.html(data.message || Resources.Error.Generic).show(); 13887 } 13888 13889 if (giftCardRecaptcha != undefined) { 13890 grecaptcha.reset(giftCardRecaptcha); 13891 } 13892 13893 var dataObject = { 13894 value: data.amountApplied.value, 13895 payment_type: 'Gift Card SVS' 13896 } 13897 GoogleTagManagerClient.PushDataLayerForDataLayerType('AddPaymentInfo', dataObject); 13898 }, 13899 error: function() { 13900 $giftCardPaymentApplyButton.loading('destroy'); 13901 $giftCardPaymentAppliedGiftCard.remove(); 13902 $giftCardPaymentErrorMessage.html(Resources.Error.Generic).show(); 13903 13904 if (giftCardRecaptcha != undefined) { 13905 grecaptcha.reset(giftCardRecaptcha); 13906 } 13907 }, 13908 complete: function(data, status, xhr) { 13909 if (data.status == 302 && data.responseText) { 13910 location.href = data.responseText; 13911 } 13912 } 13913 }); 13914 } else { 13915 if (giftCardRecaptcha != undefined) { 13916 grecaptcha.reset(giftCardRecaptcha); 13917 } 13918 } 13919 } 13920 }); 13921 13922 $(document).off('mousedown.GiftCardPaymentPanel').on('mousedown.GiftCardPaymentPanel', function (event) { 13923 if (giftCardValidator && $(event.target).closest($giftCardPaymentContainer).length == 0) { 13924 giftCardValidator.resetForm(); 13925 $giftCardPaymentErrorMessage.html('').hide(); 13926 } 13927 }); 13928 13929 $(document).on('CartData.Update', function (event, data) { 13930 $('[has-gift-cards]').attr('has-gift-cards', data.HasGiftCards || false); 13931 $('[has-gift-cards-only]').attr('has-gift-cards-only', data.HasGiftCardsOnly || false); 13932 13933 if (data.HasGiftCards && !data.AllowGiftCardPurchaseWithGiftCard) { 13934 $giftCardPaymentMessage.html(Resources.GiftCard.GiftCardPurchaseWithGiftCardNotAllowed); 13935 $giftCardPaymentContainer.attr('status', 'locked'); 13936 } else { 13937 $giftCardPaymentMessage.html(''); 13938 $giftCardPaymentContainer.attr('status', 'active'); 13939 } 13940 }); 13941 13942 $(document).on('GiftCard.Clear', function () { 13943 $giftCardPaymentApplied.html(''); 13944 $('.order-balance-due').html(''); 13945 }); 13946 13947 $giftCardPaymentContainer.on('click', '.remove:not([loading])', function (event) { 13948 event.preventDefault(); 13949 13950 var $giftCardRow = $(this).closest('.form-giftcard-applied'); 13951 $giftCardRow.loading(options.LoadingIndicator || { 13952 Label: Resources.Loading.GiftCard.Removing 13953 }); 13954 $giftCardPaymentErrorMessage.html('').hide(); 13955 13956 $.ajax({ 13957 url : Urls.GiftCard.Remove, 13958 type : 'POST', 13959 contentType: 'application/json', 13960 data: JSON.stringify({ 13961 id: $giftCardRow.data('id') 13962 }), 13963 dataType : 'json', 13964 success : function(data) { 13965 $giftCardRow.loading('destroy'); 13966 13967 if (data.success) { 13968 $giftCardRow.remove(); 13969 13970 if (options.StoreUIVersion == '2024Redesign') { 13971 location.reload(); 13972 } else { 13973 $(document).trigger('Cart.Update'); 13974 } 13975 } else { 13976 $giftCardPaymentErrorMessage.html(data.error || Resources.Error.Generic).show(); 13977 } 13978 }, 13979 error: function() { 13980 $giftCardRow.loading('destroy'); 13981 $giftCardPaymentErrorMessage.html(Resources.Error.Generic).show(); 13982 } 13983 }); 13984 }); 13985 13986 $(document).on('click.BalanceInquiry', '[payment-method="SVS_Gift_Card"] .balance-inquiry a', function (event) { 13987 event.preventDefault(); 13988 giftCardBalanceInquiryDialog.initialize(); 13989 }); 13990 13991 $(document).on('click', '.form-label.expander', function(){ 13992 $('form.svs-gift-card-information').slideToggle(); 13993 $giftCardPaymentContainer.toggleClass('svs-collapsed'); 13994 }); 13995} 13996 13997},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../components/GiftCardBalanceInquiryDialog":21,"../../components/LoadingIndicator":25,"./opcpayment":65,"lodash":133}],55:[function(require,module,exports){ 13998'use strict'; 13999/* global Resources, Urls */ 14000 14001var _ = require('lodash'); 14002var loadingIndicator = require('../../components/LoadingIndicator'); 14003var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 14004var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 14005var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 14006var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 14007var opcpayment = require('./opcpayment'); 14008var util = require('../../util'); 14009var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 14010 14011exports.initialize = initialize; 14012 14013var $loyaltyPaymentContainer = $('[payment-method="LOYALTY_CREDIT"]'); 14014var $loyaltyPaymentsForm = $loyaltyPaymentContainer.find('form'); 14015var $loyaltyPaymentsApplied = $loyaltyPaymentContainer.find('.loyalty-applied'); 14016var $loyaltyPaymentInput = $loyaltyPaymentContainer.find('#dwfrm_billing_loyalty_loyaltyNumber'); 14017var $loyaltyPhoneNumberInput = $loyaltyPaymentContainer.find('#dwfrm_billing_loyalty_loyaltyPhoneNumber'); 14018var $loyaltyZipCodeInput = $loyaltyPaymentContainer.find('#dwfrm_billing_loyalty_loyaltyZipCode'); 14019var $loyaltyPaymentSecondaryContainer = $loyaltyPaymentContainer.find('.loyalty-secondary'); 14020var $loyaltyPaymentSecondarySelect = $loyaltyPaymentContainer.find('#loyalty-secondary-select'); 14021var $loyaltyPaymentErrorMessage = $loyaltyPaymentContainer.find('span.error'); 14022var loyaltyCreditValidator; 14023var loyaltyCreditRowTemplate = _.template($('#template-loyalty-credit-row').html(), TemplateConstants.Lodash.Settings); 14024var loyaltyCreditRecaptcha; 14025var options = {}; 14026var loaded = {}; 14027 14028function renderRecaptcha() { 14029 if (loaded.Recaptcha && $('#loyalty-credit-add-button').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForloyaltyCredit && options.Recaptcha.GoogleSiteKey) { 14030 loyaltyCreditRecaptcha = grecaptcha.render('loyalty-credit-add-button', { 14031 sitekey: options.Recaptcha.GoogleSiteKey, 14032 callback: submitLoyaltyCredit, 14033 badge: 'bottomleft' 14034 }); 14035 } 14036} 14037 14038function initialize(optionsParameter) { 14039 options = optionsParameter || {}; 14040 var currentSite = ''; 14041 if ($(".logo.shep").length > 0){ 14042 currentSite = Resources.LoyaltyCredit.NotOptedInSHEP; 14043 } 14044 if ($(".logo.co").length > 0){ 14045 currentSite = Resources.LoyaltyCredit.NotOptedInCO; 14046 } 14047 14048 renderRecaptcha(); 14049 $(document).on('Recaptcha.Loaded', function(event) { 14050 if (!loaded.Recaptcha) { 14051 loaded.Recaptcha = true; 14052 renderRecaptcha(); 14053 } 14054 }); 14055 14056 if ($(".loyalty-row[status='applied']").length > 0){ 14057 $loyaltyPaymentsForm.hide(); 14058 } 14059 14060 if ($loyaltyPaymentSecondarySelect.closest('.opc-summary').length > 0) { 14061 $loyaltyPaymentSecondarySelect.selectmenu({ 14062 width: '100%', 14063 appendTo: '[payment-method="LOYALTY_CREDIT"] .loyalty-secondary', 14064 change: function(event, ui) { 14065 $loyaltyPaymentSecondaryContainer.attr('secondary', ui && ui.item && ui.item.value ? ui.item.value : ''); 14066 } 14067 }); 14068 } 14069 14070 $loyaltyPaymentContainer.on('click', '.reset', function(event) { 14071 event.preventDefault(); 14072 resetSecondarySelect(); 14073 }); 14074 14075 $loyaltyPaymentContainer.on('click', '.add', function(event) { 14076 event.preventDefault(); 14077 14078 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForRe
14078wardsCredit || !options.Recaptcha.GoogleSiteKey) { 14079 $(document).trigger('LoyaltyCredit.Add'); 14080 } 14081 }); 14082 14083 $(document).on('LoyaltyCredit.Add', function(event, data) { 14084 event.preventDefault(); 14085 14086 if (parseFloat($('[balance-due]').first().attr('balance-due')) <= 0) { 14087 $loyaltyPaymentErrorMessage.html(Resources.LoyaltyCredit.NoBalanceDue).show(); 14088 } else { 14089 var loyaltySecondaryFactor = $loyaltyPaymentSecondaryContainer.attr('secondary'); 14090 loyaltyCreditValidator = $loyaltyPaymentsForm.validate(); 14091 $loyaltyPaymentInput.rules('add', ValidationRules.LoyaltyCredit.Number); 14092 14093 switch (loyaltySecondaryFactor) { 14094 case "zipcode": 14095 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_POSTAL_CODE); 14096 $loyaltyZipCodeInput.rules('add', ValidationRules.ZipCode); 14097 break; 14098 14099 default: 14100 break; 14101 } 14102 14103 loyaltyCreditValidator.form(); 14104 14105 // Adding ADA compliance error messages for giftCardPayment section 14106 if ($loyaltyPaymentsForm.find('.field.error').length > 0) { 14107 $('.payment-declined').remove(); 14108 var loyaltyPaymentFormErrorMessages = opcpayment.getErrorMessages($loyaltyPaymentsForm); 14109 var loyaltyPaymentFormErrorBox = opcpayment.errorBox('
14109Cannot Proceed', 'Please fix the following errors:', loyaltyPaymentFormErrorMessages); 14110 if (loyaltyPaymentFormErrorBox) { 14111 $loyaltyPaymentsApplied.after(loyaltyPaymentFormErrorBox); 14112 } 14113 } 14114 14115 if (Urls && Urls.checkLoyalty && loyaltyCreditValidator.valid()) { 14116 $loyaltyPaymentsForm.hide(); 14117 14118 var $loyaltyCreditRow = $(loyaltyCreditRowTemplate()); 14119 $loyaltyCreditRow = $loyaltyCreditRow.appendTo($loyaltyPaymentsApplied); 14120 $loyaltyCreditRow.attr('status', 'pending'); 14121 $loyaltyCreditRow.find('.basketLoyaltyNumber').html(util.getMaskedNumber($loyaltyPaymentInput.val(), 4, 'xxxx... ')); 14122 14123 $loyaltyCreditRow.find('.btn').loading({IsLabelShown: false}); 14124 $loyaltyCreditRow.find('.form-controls').loading({Label: Resources.Loading.LoyaltyCredit.Loading}); 14125 14126 $.ajax({ 14127 url: Urls.checkLoyalty, 14128 type: 'POST', 14129 data: { 14130 csrf_token: $loyaltyPaymentContainer.find('input[name="csrf_token"]').val(), 14131 loyaltyNumber: $loyaltyPaymentInput.val(), 14132 loyaltyPhoneNumber: $loyaltyPhoneNumberInput.val(), 14133 loyaltyZipCode: $loyaltyZipCodeInput.val() 14134 }, 14135 dataType: 'json', 14136 success: function(data) { 14137 $loyaltyPaymentErrorMessage.html('').hide(); 14138 14139 $loyaltyCreditRow.find('.btn').loading('destroy'); 14140 $loyaltyCreditRow.find('.form-controls').loading('destroy'); 14141 14142 if (data.error !== 'undefined' && data.error === true) { 14143 $loyaltyCreditRow.remove(); 14144 $loyaltyPaymentsForm.show(); 14145 $loyaltyPaymentErrorMessage.html(data.errorMsg).show(); 14146 } else if (!data.optinStatus) { 14147 $loyaltyPaymentContainer.attr('has-loyaltynumber', 'false'); 14148 $loyaltyCreditRow.attr('status', 'message'); 14149 $loyaltyCreditRow.find('.message').html(currentSite); 14150 } else if (parseFloat(data.creditAmount) <= 0) { 14151 $loyaltyPaymentContainer.attr('has-loyaltynumber', 'true'); 14152 $loyaltyCreditRow.attr('status', 'message'); 14153 $loyaltyCreditRow.find('.message').html(Resources.LoyaltyCredit.NoBalanceAvailable); 14154 } else { 14155 $loyaltyPaymentContainer.attr('has-loyaltynumber', 'true'); 14156 $loyaltyPaymentContainer.attr('data-loyalty', data.optIn); 14157 $loyaltyCreditRow.find('.basketLoyaltyAmount').html(data.creditAmountFormatted); 14158 14159 var details = ''; 14160 var vouchers = data.creditVouchers; 14161 14162 vouchers.reverse().forEach(function(voucher){ 14163 details += '<div class="voucher"><span class="reward-amount"><b>$'+voucher.rewardAmount+'</b></span><span class="expiration"><i>Expires '+voucher.expirationDate+'</i></span></div>'; 14164 }); 14165 14166 $loyaltyCreditRow.find('.vouchers').html(details); 14167 } 14168 14169 if (loyaltyCreditRecaptcha != undefined) { 14170 grecaptcha.reset(loyaltyCreditRecaptcha); 14171 } 14172 }, 14173 error: function() { 14174 $loyaltyCreditRow.remove(); 14175 $loyaltyPaymentsForm.show(); 14176 $loyaltyPaymentErrorMessage.html(Resources.Error.Generic).show(); 14177 14178 if (loyaltyCreditRecaptcha != undefined) { 14179 grecaptcha.reset(loyaltyCreditRecaptcha); 14180 } 14181 }, 14182 complete: function(data, status, xhr) { 14183 if (data.status == 302 && data.responseText) { 14184 location.href = data.responseText; 14185 } 14186 } 14187 }); 14188 } 14189 } 14190 }); 14191 14192 $loyaltyPaymentContainer.on('click', '.apply', function(event) { 14193 event.preventDefault(); 14194 14195 var $loyaltyCreditRow = $(this).closest('.loyalty-row'); 14196 14197 $loyaltyCreditRow.find('.basketLoyaltyAmount').addClass('hide'); 14198 $loyaltyCreditRow.find('.voucher').addClass('hide'); 14199 $loyaltyCreditRow.find('.btn').loading({IsLabelShown: false}); 14200 $loyaltyCreditRow.find('.form-controls').loading({Label: Resources.Loading.LoyaltyCredit.Applying}); 14201 14202 $.ajax({ 14203 url: Urls.applyLoyalty, 14204 type: 'POST', 14205 data: { 14206 csrf_token: $loyaltyPaymentContainer.find('input[name="csrf_token"]').val(), 14207 loyaltyNumber: $loyaltyPaymentInput.val(), 14208 loyaltyPhoneNumber: $loyaltyPhoneNumberInput.val(), 14209 loyaltyZipCode: $loyaltyZipCodeInput.val() 14210 }, 14211 dataType: 'json', 14212 success: function(data) { 14213 $loyaltyPaymentErrorMessage.html('').hide(); 14214 14215 $loyaltyCreditRow.find('.btn').loading('destroy');
14216 $loyaltyCreditRow.find('.form-controls').loading('destroy'); 14217 14218 if (data.error !== 'undefined' && data.error === true) { 14219 $loyaltyCreditRow.attr('status', 'message'); 14220 $loyaltyPaymentInput.val(''); 14221 $loyaltyCreditRow.remove(); 14222 $loyaltyPaymentsForm.show(); 14223 $loyaltyPaymentErrorMessage.html(data.errorMsg).show(); 14224 } else { 14225 $loyaltyCreditRow.attr('status', 'applied'); 14226 $loyaltyPaymentsForm.hide(); 14227 $loyaltyCreditRow.find('.voucher').removeClass('hide'); 14228 $loyaltyCreditRow.find('.basketLoyaltyNumber').html(util.getMaskedNumber(data.loyaltyNumber, 4, 'xxxx... ')); 14229 $loyaltyCreditRow.find('.basketLoyaltyAmount').removeClass('hide').html(data.loyaltyCreditUsedFormatted).attr('label', Resources.LoyaltyCredit.RewardApplied); 14230 14231 var dataObject = { 14232 value: data.rewardsCreditUsed, 14233 payment_type: 'Loyalty' 14234 } 14235 GoogleTagManagerClient.PushDataLayerForDataLayerType('AddPaymentInfo', dataObject); 14236 14237 $(document).trigger('Cart.Update'); 14238 } 14239 }, 14240 error: function() { 14241 $loyaltyCreditRow.attr('status', 'message'); 14242 $loyaltyPaymentErrorMessage.html(Resources.Error.Generic).show(); 14243 resetForm(true); 14244 }, 14245 complete: function(data, status, xhr) { 14246 if (data.status == 302 && data.responseText) { 14247 location.href = data.responseText; 14248 } 14249 } 14250 }); 14251 }); 14252 14253 $loyaltyPaymentContainer.on('click LoyaltyCredit.Remove', '.remove', function(event, data) { 14254 event.preventDefault(); 14255 14256 var $loyaltyCreditRow = $(this).closest('.loyalty-row'); 14257 $loyaltyCreditRow.find('.basketLoyaltyAmount').addClass('hide'); 14258 $loyaltyCreditRow.find('.voucher').addClass('hide'); 14259 $loyaltyCreditRow.find('.btn').loading({IsLabelShown: false}); 14260 $loyaltyCreditRow.find('.form-controls').loading({Label: Resources.Loading.LoyaltyCredit.Removing}); 14261 14262 var payload = { 14263 loyaltyNumber: $('input#dwfrm_billing_loyalty_loyaltyNumber').val() 14264 } 14265 14266 if (data && data.ResetSessionData) { 14267 payload.resetSessionData = true 14268 } 14269 14270 $.ajax({ 14271 url: Urls.removeLoyalty, 14272 type: 'POST', 14273 dataType: 'json', 14274 data: payload, 14275 success: function() { 14276 $loyaltyPaymentErrorMessage.html('').hide(); 14277 14278 if ($loyaltyCreditRow.find('.btn[loading]').length > 0) { 14279 $loyaltyCreditRow.find('.btn').loading('destroy'); 14280 } 14281 if ($loyaltyCreditRow.find('.form-controls[loading]').length > 0) { 14282 $loyaltyCreditRow.find('.form-controls').loading('destroy'); 14283 } 14284 14285 if ($loyaltyPaymentContainer.attr('has-loyaltynumber') !== 'true') { 14286 $loyaltyPaymentInput.val(''); 14287 $loyaltyPaymentsForm.show(); 14288 $loyaltyCreditRow.attr('status', 'form'); 14289 $loyaltyPaymentsApplied.html(''); 14290 } else { 14291 $loyaltyCreditRow.attr('status', 'pending'); 14292 $loyaltyCreditRow.find('.voucher').removeClass('hide'); 14293 $loyaltyCreditRow.find('.basketLoyaltyAmount').removeClass('hide').attr('label', Resources.LoyaltyCredit.Reward); 14294 } 14295 14296 $(document).trigger('Cart.Update'); 14297 }, 14298 error: function() { 14299 $loyaltyCreditRow.find('.btn').loading('destroy'); 14300 $loyaltyCreditRow.find('.form-controls').loading('destroy'); 14301 14302 $loyaltyPaymentErrorMessage.html(Resources.Error.Generic).show(); 14303 } 14304 }); 14305 }); 14306 14307 $loyaltyPaymentContainer.on('click', '.change', function(event) { 14308 event.preventDefault(); 14309 14310 $loyaltyPaymentContainer.attr('has-loyaltynumber', 'false'); 14311 if ($loyaltyPaymentsApplied.find('.loyalty-row').attr('status') === 'applied') { 14312 $loyaltyPaymentContainer.find('.remove').trigger('LoyaltyCredit.Remove'); 14313 } 14314 resetForm(); 14315 }); 14316 14317 $(document).off('mousedown.LoyaltyCreditPaymentPanel').on('mousedown.LoyaltyCreditPaymentPanel', function (event) { 14318 if (loyaltyCreditValidator && $(event.target).closest($loyaltyPaymentContainer).length == 0) { 14319 loyaltyCreditValidator.resetForm(); 14320 $loyaltyPaymentErrorMessage.html('').hide(); 14321 } 14322 }); 14323 14324 $(document).on('LoyaltyCredit.Clear', function(event) { 14325 event.preventDefault(); 14326 resetForm(); 14327 }); 14328 14329 $loyaltyPaymentContainer.on('click', '.reset', function(event) { 14330 event.preventDefault(); 14331 $loyaltyPaymentsForm.show(); 14332 $loyaltyPhoneNumberInput.val(''); 14333 $loyaltyZipCodeInput.val(''); 14334 }); 14335 14336 if ($loyaltyPaymentContainer.attr('has-loyaltynumber') === 'true' && $loyaltyPaymentsApplied.find('.loyalty-row').length == 0 && $('[checkout-mode]').attr('checkout-mode') != 'echo') { 14337 $(document).trigger('LoyaltyCredit.Add', { Registered: true }); 14338 } 14339} 14340 14341function resetForm(showErrorMessage) { 14342 if (loyaltyCreditValidator) { 14343 loyaltyCreditValidator.resetForm(); 14344 } 14345 14346 if (!showErrorMessage) { 14347 $loyaltyPaymentErrorMessage.html('').hide(); 14348 } 14349 14350 var $loyaltyCreditRow = $loyaltyPaymentsApplied.find('.loyalty-row'); 14351 if ($loyaltyPaymentContainer.attr('has-loyaltynumber') !== 'true') { 14352 $loyaltyPaymentInput.val(''); 14353 $loyaltyPhoneNumberInput.val(''); 14354 $loyaltyZipCodeInput.val(''); 14355 14356 $loyaltyPaymentsForm.show(); 14357 $loyaltyPaymentsApplied.html(''); 14358 } else { 14359 $loyaltyCreditRow.find('.basketLoyaltyAmount').attr('label', Resources.LoyaltyCredit.Reward); 14360 } 14361 14362 resetSecondarySelect(); 14363} 14364 14365function resetSecondarySelect() { 14366 $loyaltyPaymentSecondarySelect.prop('selectedIndex', 0); 14367 if ($loyaltyPaymentSecondarySelect.closest('.opc-summary').length > 0) { 14368 $loyaltyPaymentSecondarySelect.selectmenu('refresh'); 14369 } 14370 $loyaltyPaymentSecondaryContainer.attr('secondary', ''); 14371} 14372},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../components/LoadingIndicator":25,"../../util":102,"./opcpayment":65,"lodash":133}],56:[function(require,module,exports){ 14373'use strict'; 14374 14375var _ = require('lodash'); 14376var loadingIndicator = require('../../components/LoadingIndicator'); 14377var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 14378var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 14379 14380exports.initialize = initialize; 14381 14382var $paymentContainer = $('[payment-method="B2B_Payment_Voucher"]'); 14383var $paymentForm = $paymentContainer.find('form'); 14384var $paymentVoucherNumber = $paymentContainer.find('input[name="paymentvouchercode"]'); 14385var $paymentMessage = $paymentContainer.find('.messages'); 14386var $paymentErrorMessage = $paymentContainer.find('span.error'); 14387var $paymentsApplied = $paymentContainer.find('.form-payments-applied'); 14388var $paymentApplyButton = $paymentContainer.find('.apply'); 14389var validator; 14390var recaptcha; 14391var options = {}; 14392var loaded = {}; 14393 14394function renderRecaptcha() { 14395 if (loaded.Recaptcha && $paymentApplyButton.length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForPaymentVouchers && options.Recaptcha.GoogleSiteKey) { 14396 recaptcha = grecaptcha.render('payment-voucher-apply-button', { 14397 sitekey: options.Recaptcha.GoogleSiteKey, 14398 callback: submitPaymentVoucher, 14399 badge: 'bottomleft' 14400 }); 14401 } 14402} 14403 14404function initialize(optionsParameter) { 14405 options = optionsParameter || {}; 14406 14407 renderRecaptcha(); 14408 $(document).on('Recaptcha.Loaded', function(event) { 14409 if (!loaded.Recaptcha) { 14410 loaded.Recaptcha = true; 14411 renderRecaptcha(); 14412 } 14413 }); 14414 14415 $paymentContainer.on('click', '.apply:not([loading])', function (event) { 14416 event.preventDefault(); 14417 14418 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForPaymentVouchers || !options.Recaptcha.GoogleSiteKey) { 14419 $(document).trigger('PaymentVoucher.Apply'); 14420 } 14421 }); 14422 14423 $(document).on('PaymentVoucher.Apply', function(event) { 14424 event.preventDefault(); 14425 14426 if (parseFloat($('[balance-due]').first().attr('balance-due')) <= 0) { 14427 $paymentErrorMessage.html(Resources.PaymentVoucher.NoBalanceDue).show(); 14428 14429 if (recaptcha != undefined) { 14430 grecaptcha.reset(recaptcha); 14431 } 14432 } else { 14433 $paymentErrorMessage.html('').hide(); 14434 validator = $paymentForm.validate(); 14435 $paymentVoucherNumber.rules('add', ValidationRules.PaymentVoucher.Number); 14436 validator.checkForm(); 14437 14438 if (Urls && Urls.PaymentVoucher.Apply && validator.valid()) { 14439 var rowContainerHtml = _.template($('#template-paymentvoucher-row-container').html(), TemplateConstants.Lodash.Settings)(); 14440 var $paymentApplied = $(rowContainerHtml).appendTo($paymentsApplied); 14441 14442 $paymentApplyButton.loading({ 14443 IsImageShown: true, 14444 IsLabelShown: false 14445 }); 14446 $paymentApplied.loading({ 14447 Label: Resources.Loading.PaymentVoucher.Applying 14448 }); 14449 14450 $.ajax({ 14451 method: 'POST', 14452 url: Urls.PaymentVoucher.Apply, 14453 contentType: 'application/json', 14454 data: JSON.stringify({ 14455 number: $paymentVoucherNumber.val(), 14456 amount: null 14457 }), 14458 dataType: 'json', 14459 success: function (data) { 14460 $paymentApplyButton.loading('destroy'); 14461 $paymentApplied.loading('destroy'); 14462 14463 if (data.success) { 14464 $paymentVoucherNumber.val(''); 14465 14466 if (data.amountApplied && data.amountApplied.value > 0) { 14467 $paymentsApplied.find('[data-id="' + data.id + '"]').remove(); 14468 $paymentApplied.attr('data-id', data.id); 14469 14470 var rowContentHtml = _.template($('#template-paymentvoucher-row-content').html(), TemplateConstants.Lodash.Settings)({ 14471 paymentNumber: data.number, 14472 amountApplied: data.amountApplied.displayValue 14473 }); 14474 14475 $paymentApplied.html(rowContentHtml); 14476 } 14477 14478 if (data.message) { 14479 $paymentErrorMessage.html(data.message).show(); 14480 } 14481 14482 $(document).trigger('Cart.Update'); 14483 } else { 14484 if (data.message == 'Invalid Message') { 14485 data.message = Resources.Error.Generic; 14486 } 14487 14488 $paymentApplied.remove(); 14489 $paymentErrorMessage.html(data.message || Resources.Error.Generic).show(); 14490 } 14491 14492 if (recaptcha != undefined) { 14493 grecaptcha.reset(recaptcha); 14494 } 14495 }, 14496 error: function() { 14497 $paymentApplyButton.loading('destroy'); 14498 $paymentApplied.remove(); 14499 $paymentErrorMessage.html(Resources.Error.Generic).show(); 14500 14501 if (recaptcha != undefined) { 14502 grecaptcha.reset(recaptcha); 14503 } 14504 } 14505 }); 14506 } else { 14507 if (recaptcha != undefined) { 14508 grecaptcha.reset(recaptcha); 14509 } 14510 } 14511 } 14512 }); 14513 14514 $(document).off('mousedown.paymentPanel').on('mousedown.paymentPanel', function (event) { 14515 if (validator && $(event.target).closest($paymentContainer).length == 0) { 14516 validator.resetForm(); 14517 $paymentErrorMessage.html('').hide(); 14518 } 14519 }); 14520 14521 $(document).on('CartData.Update', function (event, data) { 14522 $('[has-gift-cards]').attr('has-gift-cards', data.HasGiftCards || false); 14523 $('[has-gift-cards-only]').attr('has-gift-cards-only', data.HasGiftCardsOnly || false); 14524 14525 if (data.HasGiftCards && !data.AllowpurchaseWithGiftCard) { 14526 $paymentMessage.html(Resources.GiftCard.purchaseWithGiftCardNotAllowed); 14527 $paymentContainer.attr('status', 'locked'); 14528 } else { 14529 $paymentMessage.html(''); 14530 $paymentContainer.attr('status', 'active'); 14531 } 14532 }); 14533 14534 $paymentContainer.on('click', '.remove:not([loading])', function (event) { 14535 event.preventDefault(); 14536 14537 var $row = $(this).closest('.form-payment-applied'); 14538 $row.loading({ 14539 Label: Resources.Loading.GiftCard.Removing 14540 }); 14541 $paymentErrorMessage.html('').hide(); 14542 14543 $.ajax({ 14544 url : Urls.PaymentVoucher.Remove, 14545 type : 'POST', 14546 contentType: 'application/json', 14547 data: JSON.stringify({ 14548 id: $row.data('id') 14549 }), 14550 dataType : 'json', 14551 success : function(data) { 14552 $row.loading('destroy'); 14553 14554 if (data.success) { 14555 $row.remove(); 14556 14557 $(document).trigger('Cart.Update'); 14558 } else { 14559 $paymentErrorMessage.html(data.error || Resources.Error.Generic).show(); 14560 } 14561 }, 14562 error: function() { 14563 $row.loading('destroy'); 14564 $paymentErrorMessage.html(Resources.Error.Generic).show(); 14565 } 14566 }); 14567 }); 14568} 14569 14570},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../components/LoadingIndicator":25,"lodash":133}],57:[function(require,module,exports){ 14571'use strict'; 14572/* global Resources, Urls */ 14573 14574var _ = require('lodash'); 14575var loadingIndicator = require('../../components/LoadingIndicator'); 14576var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 14577var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 14578var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 14579var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 14580var opcpayment = require('./opcpayment'); 14581var util = require('../../util'); 14582 14583exports.initialize = initialize; 14584 14585var $rewardsPaymentContainer = $('[payment-method="REWARDS_CREDIT"][has-rewardsnumber]'); 14586var $rewardsPaymentsForm = $rewardsPaymentContainer.find('form'); 14587var $rewardsPaymentsApplied = $rewardsPaymentContainer.find('.rewards-applied'); 14588var $rewardsPaymentInput = $rewardsPaymentContainer.find('#dwfrm_billing_rewards_rewardsNumber'); 14589var $rewardsEmailInput = $rewardsPaymentContainer.find('#dwfrm_billing_rewards_rewardsEmail'); 14590var $rewardsPhoneNumberInput = $rewardsPaymentContainer.find('#dwfrm_billing_rewards_rewardsPhoneNumber'); 14591var $rewardsZipCodeInput = $rewardsPaymentContainer.find('#dwfrm_billing_rewards_rewardsZipCode'); 14592var $rewardsPaymentSecondaryContainer = $rewardsPaymentContainer.find('.rewards-secondary'); 14593var $rewardsPaymentSecondarySelect = $rewardsPaymentContainer.find('#rewards-secondary-select'); 14594var $rewardsPaymentErrorMessage = $rewardsPaymentContainer.find('span.error'); 14595var rewardsCreditValidator; 14596var rewardsCreditRowTemplate = _.template($('#template-rewards-credit-row').html(), TemplateConstants.Lodash.Settings); 14597var rewardsCreditRecaptcha; 14598var options = {}; 14599var loaded = {}; 14600 14601function renderRecaptcha() { 14602 if (loaded.Recaptcha && $('#rewards-credit-add-button').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForRe
14602wardsCredit && options.Recaptcha.GoogleSiteKey) { 14603 rewardsCreditRecaptcha = grecaptcha.render('rewards-credit-add-button', { 14604 sitekey: options.Recaptcha.GoogleSiteKey, 14605 callback: submitRewardsCredit, 14606 badge: 'bottomleft' 14607 }); 14608 } 14609} 14610 14611function initialize(optionsParameter) { 14612 options = optionsParameter || {}; 14613 14614 renderRecaptcha(); 14615 $(document).on('Recaptcha.Loaded', function(event) { 14616 if (!loaded.Recaptcha) { 14617 loaded.Recaptcha = true; 14618 renderRecaptcha(); 14619 } 14620 }); 14621 14622 if ($rewardsPaymentSecondarySelect.closest('.opc-summary').length > 0) { 14623 $rewardsPaymentSecondarySelect.selectmenu({ 14624 width: '100%', 14625 appendTo: '[payment-method="REWARDS_CREDIT"] .rewards-secondary', 14626 change: function(event, ui) { 14627 $rewardsPaymentSecondaryContainer.attr('secondary', ui && ui.item && ui.item.value ? ui.item.value : ''); 14628 } 14629 }); 14630 } 14631 14632 $rewardsPaymentContainer.on('click', '.reset', function(event) { 14633 event.preventDefault(); 14634 resetSecondarySelect(); 14635 }); 14636 14637 $rewardsPaymentContainer.on('click', '.add', function(event) { 14638 event.preventDefault(); 14639 14640 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForRewardsCredit || !options.Recaptcha.GoogleSiteKey) { 14641 $(document).trigger('RewardsCredit.Add'); 14642 } 14643 }); 14644 14645 $(document).on('RewardsCredit.Add', function(event, data) { 14646 event.preventDefault(); 14647 14648 if (parseFloat($('[balance-due]').first().attr('balance-due')) <= 0) { 14649 $rewardsPaymentErrorMessage.html(Resources.RewardsCredit.NoBalanceDue).show(); 14650 } else { 14651 var rewardsSecondaryFactor = $rewardsPaymentSecondaryContainer.attr('secondary'); 14652 rewardsCreditValidator = $rewardsPaymentsForm.validate(); 14653 $rewardsPaymentInput.rules('add', ValidationRules.RewardsCredit.Number); 14654 14655 switch (rewardsSecondaryFactor) { 14656 case "zipcode": 14657 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_POSTAL_CODE); 14658 $rewardsZipCodeInput.rules('add', ValidationRules.ZipCode); 14659 break; 14660 14661 default: 14662 break; 14663 } 14664 14665 rewardsCreditValidator.form(); 14666 14667 // Adding ADA compliance error messages for giftCardPayment section 14668 if ($rewardsPaymentsForm.find('.field.error').length > 0) { 14669 $('.payment-declined').remove(); 14670 var rewardsPaymentFormErrorMessages = opcpayment.getErrorMessages($rewardsPaymentsForm); 14671 var rewardsPaymentFormErrorBox = opcpayment.errorBox('
14671Cannot Proceed', 'Please fix the following errors:', rewardsPaymentFormErrorMessages); 14672 if (rewardsPaymentFormErrorBox) { 14673 $rewardsPaymentsApplied.after(rewardsPaymentFormErrorBox); 14674 } 14675 } 14676 14677 if (Urls && Urls.checkRewards && rewardsCreditValidator.valid()) { 14678 $rewardsPaymentsForm.hide(); 14679 14680 var $rewardsCreditRow = $(rewardsCreditRowTemplate()); 14681 $rewardsCreditRow = $rewardsCreditRow.appendTo($rewardsPaymentsApplied); 14682 $rewardsCreditRow.attr('status', 'pending'); 14683 $rewardsCreditRow.find('.basketRewardNumber').html(util.getMaskedNumber($rewardsPaymentInput.val(), 4, 'xxxx... ')); 14684 14685 $rewardsCreditRow.find('.btn').loading({IsLabelShown: false}); 14686 $rewardsCreditRow.find('.form-controls').loading({Label: Resources.Loading.RewardsCredit.Loading}); 14687 14688 $.ajax({ 14689 url: data && data.Registered ? Urls.checkRewardsForRegistered : Urls.checkRewards, 14690 type: 'POST', 14691 data: { 14692 csrf_token: $rewardsPaymentContainer.find('input[name="csrf_token"]').val(), 14693 rewardsNumber: $rewardsPaymentInput.val(), 14694 rewardsEmail: $rewardsEmailInput.val(), 14695 rewardsPhoneNumber: $rewardsPhoneNumberInput.val(), 14696 rewardsZipCode: $rewardsZipCodeInput.val() 14697 }, 14698 dataType: 'json', 14699 success: function(data) { 14700 $rewardsPaymentErrorMessage.html('').hide(); 14701 14702 if ($rewardsCreditRow.find('.btn[loading]').length > 0) { 14703 $rewardsCreditRow.find('.btn').loading('destroy'); 14704 } 14705 if ($rewardsCreditRow.find('.form-controls[loading]').length > 0) { 14706 $rewardsCreditRow.find('.form-controls').loading('destroy'); 14707 } 14708 14709 if (data && data.error !== 'undefined' && data.error === true) { 14710 $rewardsCreditRow.remove(); 14711 $rewardsPaymentsForm.show(); 14712 $rewardsPaymentErrorMessage.html(data.errorMsg).show(); 14713 } else if (data && parseFloat(data.creditAmount) <= 0) { 14714 $rewardsPaymentContainer.attr('has-rewardsnumber', 'true'); 14715 $rewardsCreditRow.attr('status', 'message'); 14716 $rewardsCreditRow.find('.message').html(Resources.RewardsCredit.NoBalanceAvailable); 14717 } else if (data && data.creditAmountFormatted) { 14718 $rewardsPaymentContainer.attr('has-rewardsnumber', 'true'); 14719 $rewardsCreditRow.find('.basketRewardAmount').html(data.creditAmountFormatted.replace('.00', '')); 14720 $rewardsCreditRow.find('.expiration-date').html(data.creditExpirationDate); 14721 } 14722 14723 if (rewardsCreditRecaptcha != undefined) { 14724 grecaptcha.reset(rewardsCreditRecaptcha); 14725 } 14726 }, 14727 error: function() { 14728 $rewardsCreditRow.remove(); 14729 $rewardsPaymentsForm.show(); 14730 $rewardsPaymentErrorMessage.html(Resources.Error.Generic).show(); 14731 14732 if (rewardsCreditRecaptcha != undefined) { 14733 grecaptcha.reset(rewardsCreditRecaptcha); 14734 } 14735 }, 14736 complete: function(data, status, xhr) { 14737 if (data.status == 302 && data.responseText) { 14738 location.href = data.responseText; 14739 } 14740 } 14741 }); 14742 } 14743 } 14744 }); 14745 14746 $rewardsPaymentContainer.on('click', '.apply', function(event) { 14747 event.preventDefault(); 14748 14749 var $rewardsCreditRow = $(this).closest('.reward-row'); 14750 14751 $rewardsCreditRow.find('.btn').loading({IsLabelShown: false}); 14752 $rewardsCreditRow.find('.form-controls').loading({Label: Resources.Loading.RewardsCredit.Applying}); 14753 14754 $.ajax({ 14755 url: Urls.applyRewards, 14756 type: 'POST', 14757 data: { 14758 csrf_token: $rewardsPaymentContainer.find('input[name="csrf_token"]').val(), 14759 rewardsNumber: $rewardsPaymentInput.val(), 14760 rewardsEmail: $rewardsEmailInput.val(), 14761 rewardsPhoneNumber: $rewardsPhoneNumberInput.val(), 14762 rewardsZipCode: $rewardsZipCodeInput.val() 14763 }, 14764 dataType: 'json', 14765 success: function(data) { 14766 $rewardsPaymentErrorMessage.html('').hide(); 14767 if ($rewardsCreditRow.find('.btn[loading]').length > 0) { 14768 $rewardsCreditRow.find('.btn').loading('destroy'); 14769 } 14770 if ($rewardsCreditRow.find('.form-controls[loading]').length > 0) { 14771 $rewardsCreditRow.find('.form-controls').loading('destroy'); 14772 } 14773 14774 if (data.error !== 'undefined' && data.error === true) { 14775 $rewardsCreditRow.attr('status', 'message'); 14776 $rewardsPaymentInput.val(''); 14777 $rewardsCreditRow.remove(); 14778 $rewardsPaymentsForm.show(); 14779 $rewardsPaymentErrorMessage.html(data.errorMsg).show(); 14780 } else { 14781 $rewardsCreditRow.attr('status', 'applied'); 14782 $rewardsCreditRow.find('.basketRewardNumber').html(util.getMaskedNumber(data.rewardsNumber, 4, 'xxxx... ')); 14783 $rewardsCreditRow.find('.basketRewardAmount').html(data.rewardsCreditUsedFormatted).attr('label', Resources.RewardsCredit.RewardApplied); 14784 $rewardsCreditRow.find('.expiration-date').html(data.creditExpirationDate); 14785 14786 var dataObject = { 14787 value: data.rewardsCreditUsed, 14788 payment_type: 'B Rewarded' 14789 } 14790 GoogleTagManagerClient.PushDataLayerForDataLayerType('AddPaymentInfo', dataObject); 14791 $(document).trigger('Cart.Update'); 14792 } 14793 }, 14794 error: function() { 14795 $rewardsCreditRow.attr('status', 'message'); 14796 $rewardsPaymentErrorMessage.html(Resources.Error.Generic).show(); 14797 resetForm(true); 14798 },
14799 complete: function(data, status, xhr) { 14800 if (data.status == 302 && data.responseText) { 14801 location.href = data.responseText; 14802 } 14803 } 14804 }); 14805 }); 14806 14807 $rewardsPaymentContainer.on('click RewardsCredit.Remove', '.remove', function(event, data) { 14808 event.preventDefault(); 14809 14810 var $rewardsCreditRow = $(this).closest('.reward-row'); 14811 $rewardsCreditRow.find('.btn').loading({IsLabelShown: false}); 14812 $rewardsCreditRow.find('.form-controls').loading({Label: Resources.Loading.RewardsCredit.Removing}); 14813 14814 var payload = { 14815 rewardsNumber: $('input#dwfrm_billing_rewards_rewardsNumber').val() 14816 } 14817 14818 if (data && data.ResetSessionData) { 14819 payload.resetSessionData = true 14820 } 14821 14822 $.ajax({ 14823 url: Urls.removeRewards, 14824 type: 'POST', 14825 dataType: 'json', 14826 data: payload, 14827 success: function() { 14828 $rewardsPaymentErrorMessage.html('').hide(); 14829 14830 if ($rewardsCreditRow.find('.btn[loading]').length > 0) { 14831 $rewardsCreditRow.find('.btn').loading('destroy'); 14832 } 14833 if ($rewardsCreditRow.find('.form-controls[loading]').length > 0) { 14834 $rewardsCreditRow.find('.form-controls').loading('destroy'); 14835 } 14836 14837 if ($rewardsPaymentContainer.attr('has-rewardsnumber') !== 'true') { 14838 $rewardsPaymentInput.val(''); 14839 $rewardsPaymentsForm.show(); 14840 $rewardsCreditRow.attr('status', 'form'); 14841 $rewardsPaymentsApplied.html(''); 14842 } else { 14843 $rewardsCreditRow.attr('status', 'pending'); 14844 $rewardsCreditRow.find('.basketRewardAmount').attr('label', Resources.RewardsCredit.Reward); 14845 } 14846 14847 $(document).trigger('Cart.Update'); 14848 }, 14849 error: function() { 14850 if ($rewardsCreditRow.find('.btn[loading]').length > 0) { 14851 $rewardsCreditRow.find('.btn').loading('destroy'); 14852 } 14853 if ($rewardsCreditRow.find('.form-controls[loading]').length > 0) { 14854 $rewardsCreditRow.find('.form-controls').loading('destroy'); 14855 } 14856 14857 $rewardsPaymentErrorMessage.html(Resources.Error.Generic).show(); 14858 } 14859 }); 14860 }); 14861 14862 $rewardsPaymentContainer.on('click', '.change', function(event) { 14863 event.preventDefault(); 14864 14865 $rewardsPaymentContainer.attr('has-rewardsnumber', 'false'); 14866 if ($rewardsPaymentsApplied.find('.reward-row').attr('status') === 'applied') { 14867 $rewardsPaymentContainer.find('.remove').trigger('RewardsCredit.Remove'); 14868 } 14869 resetForm(); 14870 }); 14871 14872 $(document).off('mousedown.RewardsCreditPaymentPanel').on('mousedown.RewardsCreditPaymentPanel', function (event) { 14873 if (rewardsCreditValidator && $(event.target).closest($rewardsPaymentContainer).length == 0) { 14874 rewardsCreditValidator.resetForm(); 14875 $rewardsPaymentErrorMessage.html('').hide(); 14876 } 14877 }); 14878 14879 $(document).on('RewardsCredit.Clear', function(event) { 14880 event.preventDefault(); 14881 resetForm(); 14882 }); 14883 14884 $rewardsPaymentContainer.on('click', '.reset', function(event) { 14885 event.preventDefault(); 14886 $rewardsPaymentsForm.show(); 14887 $rewardsPhoneNumberInput.val(''); 14888 $rewardsZipCodeInput.val(''); 14889 }); 14890 14891 if (($rewardsPaymentContainer.attr('has-rewardsnumber') === 'true' && ($rewardsPhoneNumberInput.val() || $rewardsZipCodeInput.val())) && $rewardsPaymentsApplied.find('.reward-row').length == 0 && $('[checkout-mode]').attr('checkout-mode') != 'echo') { 14892 $(document).trigger('RewardsCredit.Add', { Registered: true }); 14893 } 14894} 14895 14896function resetForm(showErrorMessage) { 14897 if (rewardsCreditValidator) { 14898 rewardsCreditValidator.resetForm(); 14899 } 14900 14901 if (!showErrorMessage) { 14902 $rewardsPaymentErrorMessage.html('').hide(); 14903 } 14904 14905 var $rewardsCreditRow = $rewardsPaymentsApplied.find('.reward-row'); 14906 if ($rewardsPaymentContainer.attr('has-rewardsnumber') !== 'true') { 14907 $rewardsPaymentInput.val(''); 14908 $rewardsPhoneNumberInput.val(''); 14909 $rewardsZipCodeInput.val(''); 14910 14911 $rewardsPaymentsForm.show(); 14912 $rewardsPaymentsApplied.html(''); 14913 } else { 14914 $rewardsCreditRow.find('.basketRewardAmount').attr('label', Resources.RewardsCredit.Reward); 14915 } 14916 14917 resetSecondarySelect(); 14918} 14919 14920function resetSecondarySelect() { 14921 $rewardsPaymentSecondarySelect.prop('selectedIndex', 0); 14922 if ($rewardsPaymentSecondarySelect.closest('.opc-summary').length > 0) { 14923 $rewardsPaymentSecondarySelect.selectmenu('refresh'); 14924 } 14925 $rewardsPaymentSecondaryContainer.attr('secondary', ''); 14926} 14927},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../components/LoadingIndicator":25,"../../util":102,"./opcpayment":65,"lodash":133}],58:[function(require,module,exports){ 14928'use strict'; 14929 14930var _ = require('lodash'); 14931var loadingIndicator = require('../../components/LoadingIndicator'); 14932var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 14933var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 14934 14935exports.initialize = initialize; 14936 14937var $paymentContainer = $('[payment-method="Workforce_Voucher"]'); 14938var $paymentForm = $paymentContainer.find('form'); 14939var $paymentMessage = $paymentContainer.find('.messages'); 14940var $paymentErrorMessage = $paymentContainer.find('span.error'); 14941var $paymentsApplied = $paymentContainer.find('.form-payments-applied'); 14942var recaptcha; 14943var options = {}; 14944var loaded = {}; 14945 14946function renderRecaptcha() { 14947 if (loaded.Recaptcha && options && options.Recaptcha && options.Recaptcha.EnabledForPaymentVouchers && options.Recaptcha.GoogleSiteKey) { 14948 recaptcha = grecaptcha.render('payment-voucher-apply-button', { 14949 sitekey: options.Recaptcha.GoogleSiteKey, 14950 callback: submitPaymentVoucher, 14951 badge: 'bottomleft' 14952 }); 14953 } 14954} 14955 14956function initialize(optionsParameter) { 14957 options = optionsParameter || {}; 14958 14959 renderRecaptcha(); 14960 $(document).on('Recaptcha.Loaded', function(event) { 14961 if (!loaded.Recaptcha) { 14962 loaded.Recaptcha = true; 14963 renderRecaptcha(); 14964 } 14965 }); 14966 14967 $paymentContainer.on('click', '.apply:not([loading]):not([disabled])', function (event) { 14968 event.preventDefault(); 14969 14970 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForPaymentVouchers || !options.Recaptcha.GoogleSiteKey) { 14971 $(document).trigger('WorkforceVoucher.Apply', event); 14972 } 14973 }); 14974 14975 $(document).on('WorkforceVoucher.Apply', function(event, data) { 14976 event.preventDefault(); 14977 var $this = $(data.target); 14978 var $voucher = $this.closest('[voucher-id'); 14979 14980 if (parseFloat($('[balance-due]').first().attr('balance-due')) <= 0) { 14981 $paymentErrorMessage.html(Resources.PaymentVoucher.NoBalanceDue).show(); 14982 14983 if (recaptcha != undefined) { 14984 grecaptcha.reset(recaptcha); 14985 } 14986 } else { 14987 $paymentErrorMessage.html('').hide(); 14988 14989 if (Urls.Workforce && Urls.Workforce.Vouchers && Urls.Workforce.Vouchers.PaymentPanel && Urls.Workforce.Vouchers.PaymentPanel.Apply) { 14990 $this.loading({ 14991 IsImageShown: true, 14992 IsLabelShown: false 14993 }); 14994 14995 $.ajax({ 14996 method: 'POST', 14997 url: Urls.Workforce.Vouchers.PaymentPanel.Apply, 14998 contentType: 'application/json', 14999 data: JSON.stringify({ 15000 id: $voucher.attr('voucher-id') 15001 }), 15002 dataType: 'json', 15003 success: function (data) { 15004 $this.loading('destroy'); 15005 15006 if (data.success) { 15007 if (data.amountApplied && data.amountApplied.value > 0) { 15008 $voucher.attr('is-applied', 'true'); 15009 } 15010 15011 if (data.message) { 15012 $paymentErrorMessage.html(data.message).show(); 15013 } 15014 15015 $(document).trigger('Cart.Update'); 15016 } else { 15017 if (data.message == 'Invalid Message') { 15018 data.message = Resources.Error.Generic; 15019 } 15020 15021 $paymentErrorMessage.html(data.message || Resources.Error.Generic).show(); 15022 } 15023 15024 if (recaptcha != undefined) { 15025 grecaptcha.reset(recaptcha); 15026 } 15027 }, 15028 error: function() { 15029 $this.loading('destroy'); 15030 $paymentErrorMessage.html(Resources.Error.Generic).show(); 15031 15032 if (recaptcha != undefined) { 15033 grecaptcha.reset(recaptcha); 15034 } 15035 } 15036 }); 15037 } else { 15038 if (recaptcha != undefined) { 15039 grecaptcha.reset(recaptcha); 15040 } 15041 } 15042 } 15043 }); 15044 15045 $(document).off('mousedown.paymentPanel').on('mousedown.paymentPanel', function (event) { 15046 if ($(event.target).closest($paymentContainer).length == 0) { 15047 $paymentErrorMessage.html('').hide(); 15048 } 15049 }); 15050 15051 $(document).on('CartData.Update', function (event, data) { 15052 $('[has-gift-cards]').attr('has-gift-cards', data.HasGiftCards || false); 15053 $('[has-gift-cards-only]').attr('has-gift-cards-only', data.HasGiftCardsOnly || false); 15054 15055 if (data.HasGiftCards && !data.AllowpurchaseWithGiftCard) { 15056 $paymentMessage.html(Resources.GiftCard.purchaseWithGiftCardNotAllowed); 15057 $paymentContainer.attr('status', 'locked'); 15058 } else { 15059 $paymentMessage.html(''); 15060 $paymentContainer.attr('status', 'active'); 15061 } 15062 }); 15063 15064 $paymentContainer.on('click', '.remove:not([loading])', function (event) { 15065 event.preventDefault(); 15066 15067 var $this = $(this); 15068 var $voucher = $this.closest('.workforce-voucher'); 15069 $this.loading({ 15070 IsImageShown: true, 15071 IsLabelShown: false 15072 }); 15073 $paymentErrorMessage.html('').hide(); 15074 15075 $.ajax({ 15076 url: Urls.Workforce.Vouchers.PaymentPanel.Remove, 15077 type: 'POST', 15078 contentType: 'application/json', 15079 data: JSON.stringify({ 15080 id: $voucher.attr('voucher-id') 15081 }), 15082 dataType : 'json', 15083 success : function(data) { 15084 $this.loading('destroy'); 15085 15086 if (data.success) { 15087 $voucher.attr('is-applied', 'false'); 15088 $(document).trigger('Cart.Update'); 15089 } else { 15090 $paymentErrorMessage.html(data.error || Resources.Error.Generic).show(); 15091 } 15092 }, 15093 error: function() { 15094 $this.loading('destroy'); 15095 $paymentErrorMessage.html(Resources.Error.Generic).show(); 15096 } 15097 }); 15098 }); 15099} 15100 15101},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../components/LoadingIndicator":25,"lodash":133}],59:[function(require,module,exports){ 15102'use strict'; 15103 15104var util = require('../../util'); 15105var shipping = require('./shipping'); 15106 15107/** 15108 * @function 15109 * @description Selects the first address from the list of addresses 15110 */ 15111exports.init = function () { 15112 var $form = $('.address'); 15113 // select address from list 15114 $('select[name$="_addressList"]', $form).on('change', function () { 15115 var selected = $(this).children(':selected').first(); 15116 var selectedAddress = $(selected).data('address'); 15117 if (!selectedAddress) { return; } 15118 util.fillAddressFields(selectedAddress, $form); 15119 shipping.updateShippingMethodList(); 15120 // re-validate the form 15121 $form.validate().form(); 15122 }); 15123}; 15124 15125},{"../../util":102,"./shipping":66}],60:[function(require,module,exports){ 15126'use strict'; 15127 15128var ajax = require('../../ajax'); 15129var formPrepare = require('./formPrepare'); 15130var giftcard = require('../../giftcard'); 15131var util = require('../../util'); 15132 15133var PaymentMethodConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').PaymentMethods; 15134 15135/** 15136 * @function 15137 * @description Fills the Credit Card form with the passed data-
15137parameter and clears the former cvn input 15138 * @param {Object} data The Credit Card data (holder, type, masked number, expiration month/year) 15139 */ 15140function setCCFields(data) { 15141 var $creditCard = $('[data-method="' + PaymentMethodConstants.CreditCard + '"]'); 15142 $creditCard.find('input[name$="creditCard_owner"]').val(data.holder).trigger('change'); 15143 $creditCard.find('select[name$="_type"]').val(data.type).trigger('change'); 15144 $creditCard.find('input[name*="_creditCard_number"]').val(data.maskedNumber).trigger('change'); 15145 $creditCard.find('[name$="_month"]').val(data.expirationMonth).trigger('change'); 15146 $creditCard.find('[name$="_year"]').val(data.expirationYear).trigger('change'); 15147 $creditCard.find('input[name$="_cvn"]').val('').trigger('change'); 15148} 15149 15150/** 15151 * @function 15152 * @description Updates the credit card form with the attributes of a given card 15153 * @param {String} cardID the credit card ID of a given card 15154 */ 15155function populateCreditCardForm(cardID) { 15156 // load card details 15157 var url = util.appendParamToURL(Urls.billingSelectCC, 'creditCardUUID', cardID); 15158 ajax.getJson({ 15159 url: url, 15160 callback: function (data) { 15161 if (!data) { 15162 window.alert(Resources.CC_LOAD_ERROR); 15163 return false; 15164 } 15165 setCCFields(data); 15166 } 15167 }); 15168} 15169 15170 15171function populatePrivateLabelCardForm(cardID) { 15172 // load card details 15173 var url = util.appendParamToURL(Urls.billingSelectPrivateLabel, 'creditCardUUID', cardID); 15174 ajax.getJson({ 15175 url: url, 15176 callback: function (data) { 15177 if (!data) { 15178 window.alert(Resources.CC_LOAD_ERROR); 15179 return false; 15180 } 15181 var $privateLabelCard = $('[data-method="' + PaymentMethodConstants.AllianceData + '"]'); 15182 $privateLabelCard.find('input[name*="_privateLabelCredit_number"]').val(data.maskedNumber).trigger('change'); 15183 } 15184 }); 15185} 15186 15187 15188/** 15189 * @function 15190 * @description Changes the payment method form depending on the passed paymentMethodID 15191 * @param {String} paymentMethodID the ID of the payment method, to which the payment method form should be changed to 15192 */ 15193function updatePaymentMethod(paymentMethodID) { 15194 var $paymentMethods = $('.payment-method'); 15195 $paymentMethods.removeClass('payment-method-expanded'); 15196 15197 var $selectedPaymentMethod = $paymentMethods.filter('[data-method="' + paymentMethodID + '"]'); 15198 if ($selectedPaymentMethod.length === 0) { 15199 $selectedPaymentMethod = $('[data-method="Custom"]'); 15200 } 15201 $selectedPaymentMethod.addClass('payment-method-expanded'); 15202 15203 // ensure checkbox of payment method is checked 15204 $('input[name$="_selectedPaymentMethodID"]').removeAttr('checked'); 15205 $('input[value=' + paymentMethodID + ']').prop('checked', 'checked'); 15206 15207 formPrepare.validateForm(); 15208} 15209 15210/** 15211 * @function 15212 * @description loads billing address, Gift Certificates, Coupon and Payment methods 15213 */ 15214exports.init = function () { 15215 var $checkoutForm = $('.checkout-billing'); 15216 var $addGiftCert = $('#add-giftcert'); 15217 var $giftCertCode = $('input[name$="_giftCertCode"]'); 15218 var $addCoupon = $('#add-coupon'); 15219 var $couponCode = $('input[name$="_couponCode"]'); 15220 var $selectPaymentMethod = $('.payment-method-options'); 15221 var selectedPaymentMethod = $selectPaymentMethod.find(':checked').val(); 15222 15223 formPrepare.init({ 15224 formSelector: 'form[id$="billing"]', 15225 continueSelector: '[name$="billing_save"]' 15226 }); 15227 15228 // default payment method to 'CREDIT_CARD' 15229 updatePaymentMethod((selectedPaymentMethod) ? selectedPaymentMethod : PaymentMethodConstants.CreditCard); 15230 $selectPaymentMethod.on('click', 'input[type="radio"]', function () { 15231 updatePaymentMethod($(this).val()); 15232 }); 15233 15234 // select credit card from list 15235 var $creditCardList = $('#creditCardList'); 15236 $creditCardList.on('change', function () { 15237 var cardUUID = $(this).val(); 15238 if (!cardUUID) {return;} 15239 populateCreditCardForm(cardUUID); 15240 15241 // remove server side error 15242 $('.required.error').removeClass('error'); 15243 $('.error-message').remove(); 15244 }); 15245 15246 //preselect default credit card 15247 if($creditCardList.length > 0){ 15248 $creditCardList.find('option').eq(1).prop('selected', true); 15249 $creditCardList.trigger('change'); 15250 } 15251 15252 15253 // select private label card from list 15254 var $privateLabelCardList = $('#privateLabelCardList'); 15255 $privateLabelCardList.on('change', function () {
15256 var cardUUID = $(this).val(); 15257 if (!cardUUID) {return;} 15258 populatePrivateLabelCardForm(cardUUID); 15259 15260 // remove server side error 15261 $('.required.error').removeClass('error'); 15262 $('.error-message').remove(); 15263 }); 15264 15265 // preselect default private label card 15266 if($privateLabelCardList.length > 0){ 15267 $privateLabelCardList.find('option').eq(1).prop('selected', true); 15268 $privateLabelCardList.trigger('change'); 15269 } 15270 15271 $('#check-giftcert').on('click', function (e) { 15272 e.preventDefault(); 15273 var $balance = $('.balance'); 15274 if ($giftCertCode.length === 0 || $giftCertCode.val().length === 0) { 15275 var error = $balance.find('span.error'); 15276 if (error.length === 0) { 15277 error = $('<span>').addClass('error').appendTo($balance); 15278 } 15279 error.html(Resources.GIFT_CERT_MISSING); 15280 return; 15281 } 15282 15283 giftcard.checkBalance($giftCertCode.val(), function (data) { 15284 if (!data || !data.giftCertificate) { 15285 $balance.html(Resources.GIFT_CERT_INVALID).removeClass('success').addClass('error'); 15286 return; 15287 } 15288 $balance.html(Resources.GIFT_CERT_BALANCE + ' ' + data.giftCertificate.balance).removeClass('error').addClass('success'); 15289 }); 15290 }); 15291 15292 $addGiftCert.on('click', function (e) { 15293 e.preventDefault(); 15294 var code = $giftCertCode.val(), 15295 $error = $checkoutForm.find('.giftcert-error'); 15296 if (code.length === 0) { 15297 $error.html(Resources.GIFT_CERT_MISSING); 15298 return; 15299 } 15300 15301 var url = util.appendParamsToUrl(Urls.redeemGiftCert, {giftCertCode: code, format: 'ajax'}); 15302 $.getJSON(url, function (data) { 15303 var fail = false; 15304 var msg = ''; 15305 if (!data) { 15306 msg = Resources.BAD_RESPONSE; 15307 fail = true; 15308 } else if (!data.success) { 15309 msg = data.message.split('<').join('<').split('>').join('>'); 15310 fail = true; 15311 } 15312 if (fail) { 15313 $error.html(msg); 15314 return; 15315 } else { 15316 window.location.assign(Urls.billing); 15317 } 15318 }); 15319 }); 15320 15321 $addCoupon.on('click', function (e) { 15322 e.preventDefault(); 15323 var $error = $checkoutForm.find('.coupon-error'), 15324 code = $couponCode.val(); 15325 if (code.length === 0) { 15326 $error.html(Resources.COUPON_CODE_MISSING); 15327 return; 15328 } 15329 15330 var url = util.appendParamsToUrl(Urls.addCoupon, {couponCode: code, format: 'ajax'}); 15331 $.getJSON(url, function (data) { 15332 var fail = false; 15333 var msg = ''; 15334 if (!data) { 15335 msg = Resources.BAD_RESPONSE; 15336 fail = true; 15337 } else if (!data.success) { 15338 msg = data.message.split('<').join('<').split('>').join('>'); 15339 fail = true; 15340 } 15341 if (fail) { 15342 $error.html(msg); 15343 return; 15344 } 15345 15346 //basket check for displaying the payment section, if the adjusted total of the basket is 0 after applying the coupon 15347 //this will force a page refresh to display the coupon message based on a parameter message 15348 if (data.success && data.baskettotal === 0) { 15349 window.location.assign(Urls.billing); 15350 } 15351 }); 15352 }); 15353 15354 // trigger events on enter 15355 $couponCode.on('keydown', function (e) { 15356 if (e.which === 13) { 15357 e.preventDefault(); 15358 $addCoupon.click(); 15359 } 15360 }); 15361 $giftCertCode.on('keydown', function (e) { 15362 if (e.which === 13) { 15363 e.preventDefault(); 15364 $addGiftCert.click(); 15365 } 15366 }); 15367}; 15368 15369},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants":117,"../../ajax":3,"../../giftcard":38,"../../util":102,"./formPrepare":61}],61:[function(require,module,exports){ 15370'use strict'; 15371 15372var _ = require('lodash'); 15373 15374var $form, $continue, $requiredInputs, validator; 15375 15376var hasEmptyRequired = function () { 15377 // filter out only the visible fields 15378 var requiredValues = $requiredInputs.filter(':visible').map(function () { 15379 return $(this).val(); 15380 }); 15381 return _(requiredValues).contains(''); 15382}; 15383 15384var validateForm = function () { 15385 // only validate form when all required fields are filled to avoid 15386 // throwing errors on empty form 15387 if (!validator) { 15388 return; 15389 } 15390 if (!hasEmptyRequired()) { 15391 if (validator.form()) { 15392 $continue.removeAttr('disabled'); 15393 } 15394 } else { 15395 $continue.attr('disabled', 'disabled'); 15396 } 15397}; 15398 15399var validateEl = function () { 15400 if ($(this).val() === '') { 15401 $continue.attr('disabled', 'disabled'); 15402 } else { 15403 // enable continue button on last required field that is valid 15404 // only validate single field 15405 if (validator.element(this) && !hasEmptyRequired()) { 15406 $continue.removeAttr('disabled'); 15407 } else { 15408 $continue.attr('disabled', 'disabled'); 15409 } 15410 } 15411}; 15412 15413var init = function (opts) { 15414 if (!opts.formSelector || !opts.continueSelector) { 15415 throw new Error('Missing form and continue action selectors.'); 15416 } 15417 $form = $(opts.formSelector); 15418 $continue = $(opts.continueSelector); 15419 validator = $form.validate(); 15420 $requiredInputs = $('.required', $form).find(':input'); 15421 validateForm(); 15422 // start listening 15423 $requiredInputs.on('change', validateEl); 15424 $requiredInputs.filter('input').on('keyup', _.debounce(validateEl, 200)); 15425}; 15426 15427exports.init = init; 15428exports.validateForm = validateForm; 15429exports.validateEl = validateEl; 15430 15431},{"lodash":133}],62:[function(require,module,exports){ 15432'use strict'; 15433 15434var address = require('./address'), 15435 billing = require('./billing'), 15436 multiship = require('./multiship'), 15437 shipping = require('./shipping'); 15438 15439/** 15440 * @function Initializes the page events depending on the checkout stage (shipping/billing) 15441 */ 15442exports.init = function () { 15443 address.init(); 15444 if ($('.checkout-shipping').length > 0) {
15445 shipping.init(); 15446 } else if ($('.checkout-multi-shipping').length > 0) { 15447 multiship.init(); 15448 } else { 15449 billing.init(); 15450 } 15451 15452 //if on the order review page and there are products that are not available diable the submit order button 15453 if ($('.order-summary-footer').length > 0) { 15454 if ($('.notavailable').length > 0) { 15455 $('.order-summary-footer .submit-order .button-fancy-large').attr('disabled', 'disabled'); 15456 } 15457 } 15458}; 15459 15460},{"./address":59,"./billing":60,"./multiship":63,"./shipping":66}],63:[function(require,module,exports){ 15461'use strict'; 15462 15463var address = require('./address'), 15464 formPrepare = require('./formPrepare'), 15465 dialog = require('../../dialog'), 15466 util = require('../../util'); 15467 15468/** 15469 * @function 15470 * @description Initializes gift message box for multiship shipping, the message box starts off as hidden and this will display it if the radio button is checked to yes, also added event handler to listen for when a radio button is pressed to display the message box 15471 */ 15472function initMultiGiftMessageBox() { 15473 $.each($('.item-list'), function () { 15474 var $this = $(this); 15475 var $giftMessage = $this.find('.gift-message-text'); 15476 15477 //handle initial load 15478 $giftMessage.toggleClass('hidden', $('input[name$="_isGift"]:checked', this).val() !== 'true'); 15479 15480 //set event listeners 15481 $this.on('change', function () { 15482 $giftMessage.toggleClass('hidden', $('input[name$="_isGift"]:checked', this).val() !== 'true'); 15483 }); 15484 }); 15485} 15486 15487 15488/** 15489 * @function 15490 * @description capture add edit adddress form events 15491 */ 15492function addEditAddress(target) { 15493 var $addressForm = $('form[name$="multishipping_editAddress"]'), 15494 $addressDropdown = $addressForm.find('select[name$=_addressList]'), 15495 $addressList = $addressForm.find('.address-list'), 15496 add = true, 15497 selectedAddressUUID = $(target).parent().siblings('.select-address').val(); 15498 15499 $addressDropdown.on('change', function (e) { 15500 e.preventDefault(); 15501 var selectedAddress = $addressList.find('select').val(); 15502 if (selectedAddress !== 'newAddress') { 15503 selectedAddress = $.grep($addressList.data('addresses'), function (add) { 15504 return add.UUID === selectedAddress; 15505 })[0]; 15506 add = false; 15507 // proceed to fill the form with the selected address 15508 util.fillAddressFields(selectedAddress, $addressForm); 15509 } else { 15510 //reset the form if the value of the option is not a UUID 15511 $addressForm.find('.input-text, .input-select').val(''); 15512 } 15513 }); 15514 15515 $addressForm.on('click', '.cancel', function (e) { 15516 e.preventDefault(); 15517 dialog.close(); 15518 }); 15519 15520 $addressForm.on('submit', function (e) { 15521 e.preventDefault(); 15522 $.getJSON(Urls.addEditAddress, $addressForm.serialize(), function (response) { 15523 if (!response.success) { 15524 // @TODO: figure out a way to handle error on the form 15525 return; 15526 } 15527 var address = response.address, 15528 $shippingAddress = $(target).closest('.shippingaddress'), 15529 $select = $shippingAddress.find('.select-address'), 15530 $selected = $select.find('option:selected'), 15531 newOption = '<option value="' + address.UUID + '">' + 15532 ((address.ID) ? '(' + address.ID + ')' : address.firstName + ' ' + address.lastName) + ', ' + 15533 address.address1 + ', ' + address.city + ', ' + address.stateCode + ', ' + address.postalCode + 15534 '</option>'; 15535 dialog.close(); 15536 if (add) { 15537 $('.shippingaddress select').removeClass('no-option').append(newOption); 15538 $('.no-address').hide(); 15539 } else { 15540 $('.shippingaddress select').find('option[value="' + address.UUID + '"]').html(newOption); 15541 } 15542 // if there's no previously selected option, select it 15543 if ($selected.length === 0 || $selected.val() === '') { 15544 $select.find('option[value="' + address.UUID + '"]').prop('selected', 'selected').trigger('change'); 15545 } 15546 }); 15547 }); 15548 15549 //preserve the uuid of the option for the hop up form 15550 if (selectedAddressUUID) { 15551 //update the form with selected address 15552 $addressList.find('option').each(function () { 15553 //check the values of the options 15554 if ($(this).attr('value') === selectedAddressUUID) { 15555 $(this).prop('selected', 'selected'); 15556 $addressDropdown.trigger('change'); 15557 } 15558 }); 15559 } 15560} 15561 15562/** 15563 * @function 15564 * @description shows gift message box in multiship, and if the page is the multi shipping address page it will call initmultishipshipaddress() to initialize the form 15565 */ 15566exports.init = function () { 15567 initMultiGiftMessageBox(); 15568 if ($('.cart-row .shippingaddress .select-address').length > 0) { 15569 formPrepare.init({ 15570 continueSelector: '[name$="addressSelection_save"]', 15571 formSelector: '[id$="multishipping_addressSelection"]' 15572 }); 15573 }
15574 $('.edit-address').on('click', 'a', function (e) { 15575 dialog.open({url: this.href, options: {open: function () { 15576 address.init(); 15577 addEditAddress(e.target); 15578 }}}); 15579 }); 15580}; 15581 15582},{"../../dialog":36,"../../util":102,"./address":59,"./formPrepare":61}],64:[function(require,module,exports){ 15583/* 15584 * Previously called opcaddress_enhanced.js 15585 * Removed the "_enhanced" from the file name to keep things consistent. 15586 * 15587 * BOOT-6833 - Eliminate old feature flags & unused JS files 15588 */ 15589 15590'use strict'; 15591 15592var _ = require('lodash'); 15593var ajax = require('../../ajax'); 15594var dialog = require('../../dialog'); 15595var findMoreStores = require('../../findMoreStores'); 15596var tooltip = require('../../tooltip'); 15597var util = require('../../util'); 15598var TPromise = require('promise'); 15599var AddressAutocompleteDialog; 15600var AddressVerificationDialog; 15601var AddressVerificationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper'); 15602var CheckoutConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants'); 15603var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 15604var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 15605var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 15606var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 15607var ValidationSettings = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 15608 15609var shippingMethods; 15610var isStoreShippingAddressOnly; 15611var options = {}; 15612var dataBuffer = {}; 15613// Matches cart.js's loadingIndicatorSettings exactly - the same fullscreen loader shown for 15614// Save/setOPCAddress, reused here for "Use My Location" so both dialogs stay consistent. 15615var loadingIndicatorSettings = { 15616 IsLabelShown: false, 15617 CssClass: 'fullscreen', 15618 BackgroundColor: 'transparent' 15619}; 15620 15621var billingAddressFormContainerSelector = '.billing-address-form'; 15622var $billingAddressFormContainer = $(billingAddressFormContainerSelector); 15623var billingAddressFormSelector = '#billingAddressForm'; 15624var $billingAddressForm = $(billingAddressFormSelector); 15625var shippingAddressSectionSelector = '.form-checkout.shipping-address-section'; 15626var $shippingAddressSection = $(shippingAddressSectionSelector); 15627var shippingAddressFormContainerSelector = '.shipping-address-form'; 15628var $shippingAddressFormContainer = $(shippingAddressFormContainerSelector); 15629var shippingAddressFormSelector = '#shippingAddressForm'; 15630var $shippingAddressForm = $(shippingAddressFormSelector); 15631var paymentFormContainerSelector = '.payment-section'; 15632var $paymentFormContainer = $(paymentFormContainerSelector); 15633var paymentFormSelector = '#paymentSection'; 15634var $paymentForm = $(paymentFormSelector); 15635var $sectionCheckout = $('.section-checkout'); 15636var $shippingMethodList = $('.form-checkout.payment-section #shipping-method-list'); 15637 15638var shippingAddressFormValidator; 15639var billingAddressFormValidator; 15640 15641function initializeEvents() { 15642 $(document).ready(function() { 15643 if (!SitePreferences.PROMOTIONAL_SMS) { 15644 $('#billingAddressForm').find('[field="promotionalsms"]').hide(); 15645 } else { 15646 if ($('.promotionalSMSLabel').length) { 15647 var promoSMSLabelText = $('.promotionalSMSLabel').html(); 15648 $('#billingAddressForm [field="promotionalsms"] label span').html(promoSMSLabelText); 15649 } 15650 } 15651 }); 15652 15653 $sectionCheckout.on('click', '.find-more-stores a', function () { 15654 findMoreStores.initialize({ view: 'checkout', storeQuery: StoreQueryFilters.ShipToStoreEnabled }); 15655 }); 15656 15657 $(document).on('click', '.international-checkout', function() { 15658 location.reload(); 15659 }); 15660 15661 $(document).on('change', 'form [id*="_country"]', function () { 15662 var $this = $(this); 15663 var $form = $this.closest('form'); 15664 var $stateDropdown = $form.find('[id*="states_state"]'); 15665 15666 renderOptions('#' + $stateDropdown.attr('id'), '#' + $this.attr('id')); 15667 15668 var $initialState = $form.find('.initial-state'); 15669 var initialStateValue = $initialState.val(); 15670 var $selectedStateOption = $stateDropdown.find('option[value="' + initialStateValue + '"]'); 15671 if ($selectedStateOption.length > 0) { 15672 $stateDropdown.val(initialStateValue); 15673 $selectedStateOption.prop('selected', true); 15674 } 15675 15676 if ($form.attr('id') == $shippingAddressForm.attr('id') && $this.val()) { 15677 if ($this.val().toUpperCase() == SiteConstants.CountryCodes.UnitedStates) { 15678 $('#shipping-international-info').hide(); 15679 } else { 15680 $('#shipping-international-info').show(); 15681 } 15682 } 15683 }); 15684 15685 $(document).on('change', 'form [id*="_postal"]', function () { 15686 var $this = $(this); 15687 $this.val($this.val().toUpperCase()); 15688 }); 15689 15690 $('.shipping-same').on('click', function(){ 15691 if($('.shipping-same').is(':checked')){ 15692 $('input[name$="_useAsShippingAddress"]').prop('checked', true); 15693 } else { 15694 $('input[name$="_useAsShippingAddress"]').prop('checked', false); 15695 } 15696 }); 15697 15698 $('.add-diff').on('click', function(){ 15699 $('input[name$="_useAsShippingAddress"]').prop('checked', false); 15700 }); 15701
15702 $billingAddressFormContainer.on('click', '.edit-address-det', function (e) { 15703 e.preventDefault(); 15704 editBillingAddress(); 15705 }); 15706 15707 $billingAddressFormContainer.on('click', '.cancel-address-det', function (e) { 15708 e.preventDefault(); 15709 15710 $('.bill-address-fields').addClass('collapsed').hide(); 15711 $('.billing-select-address').show(); 15712 15713 $('.billing-address-preview').show(); 15714 $('.billing-address-data.form-info').show(); 15715 15716 $billingAddressForm.hide(); 15717 $shippingAddressFormContainer.show(); 15718 15719 $shippingAddressSection.addClass('active').find('.shipping-address-cont').removeClass('hidden'); 15720 15721 if ($shippingAddressSection.attr('panel-mode') != 'view') { 15722 $shippingAddressForm.show(); 15723 } else { 15724 $shippingAddressForm.hide(); 15725 $('.form-checkout.payment-section').addClass('active').find('.shipping-payment-cont').removeClass('hidden'); 15726 } 15727 15728 if ($('.shipping-methods-section .shipping-restrictions').length == 0) { 15729 $('.payment-methods-section').show(); 15730 } 15731 }); 15732 15733 $('.shipping-address-section').on('click', '.edit-address-det', function (e) { 15734 e.preventDefault(); 15735 editShippingAddress(); 15736 }); 15737 15738 $('.shipping-address-section').on('click', '.add-address-det', function (e) { 15739 e.preventDefault(); 15740 15741 writeShippingAddressFormToBuffer(); 15742 15743 $('.form-checkout.shipping-address-section').attr('panel-mode', 'add'); 15744 $shippingAddressFormContainer.data('hidden-editable', true).hide(); 15745 $('.shipping-address-data').hide(); 15746 $shippingAddressFormContainer.show(); 15747 15748 $shippingAddressForm.removeClass('add edit').addClass('add'); 15749 $shippingAddressForm.find('input[name="action"]').val('add'); 15750 15751 $billingAddressForm.hide(); 15752 $('.billing-address-data.form-info').css('display', 'block'); 15753 $('.form-checkout.payment-section').removeClass('active').find('.shipping-payment-cont').addClass('hidden'); 15754 15755 var $shippingAddressFormFields = $shippingAddressForm.find('.editaddress-shipping'); 15756 $('.editaddress-shipping .initial-state').val(''); 15757 15758 $('.shipping-select-address').hide(); 15759 $('.editaddress-shipping').removeClass('collapsed'); 15760 $('#dwfrm_singleshipping_addressList').val(''); 15761 15762 $shippingAddressFormFields.find('input:text, input:password, input:file, textarea').val(''); 15763 $shippingAddressFormFields.find('option[default]').prop('selected', true); 15764 $shippingAddressFormFields.find('input:checkbox, input:radio').not('[name*="shippingAddress_addToAddressBook"]').removeAttr('checked'); 15765 15766 $('#dwfrm_shippingaddress_country').trigger('change'); 15767 }); 15768 15769 $('.shipping-address-section').on('click', '.cancel-address-det', function (e) { 15770 e.preventDefault(); 15771 15772 writeBufferToShippingAddressForm(); 15773 submitShipping(true); 15774 }); 15775 15776 $('.single.shipping-address-type-selector input').on('click', function () { 15777 var shippingAddressType = $(this).val(); 15778 shippingAddressFormValidator.form(); 15779 $('.form-checkout.shipping-address-section').attr('panel-mode', 'blank'); 15780 $('.shipping-address-cont span.error').remove(); 15781 $('.shipping-address-cont input, .shipping-address-cont select').removeClass('error'); 15782 15783 if (shippingAddressType == SiteConstants.AddressTypes.Customer) { 15784 $shippingAddressForm.find('.formfield input[type="text"], .formfield select').not('[disabled]').not('#dwfrm_shippingaddress_myStoreID').val(''); 15785 $('.form-checkout.shipping-address-section').attr('shipping-address-type', 'my-address').attr('value', 'false'); 15786 15787 if ($('#dwfrm_multipleshipping_addressList option').length > 0 || dataBuffer.shippingAddressFields && dataBuffer.shippingAddressFields['dwfrm_shippingaddress_firstName']) { 15788 writeBufferToShippingAddressForm(); 15789 15790 if ($shippingAddressForm.valid()) { 15791 $('.shipping-address-data.form-info').html('').append(buildDetailsBlockForForm($shippingAddressForm)); 15792 $('.shipping-address-data').show(); 15793 15794 $shippingAddressForm.hide(); 15795 $('.payment-section').addClass('active'); 15796 $('.shipping-payment-cont').removeClass('hidden'); 15797 $('.shipping-address-cont').removeClass('hidden'); 15798 $shippingAddressForm.data('shipping-filled', true); 15799 } 15800 15801 if ($('#dwfrm_multipleshipping_addressList option').length > 0) { 15802 $('#dwfrm_multipleshipping_addressList').trigger('change'); 15803 } 15804 } else { 15805 $shippingAddressForm.find('.formfield option[default]').prop('selected', true); 15806 $shippingAddressForm.data('shipping-filled', false); 15807 $('.form-checkout.address-section').attr('panel-mode', 'view'); 15808 15809 $shippingAddressFormContainer.data('hidden-editable', true).hide(); 15810 $('.shipping-address-data.form-info').hide(); 15811 $shippingAddressFormContainer.show(); 15812 $shippingAddressForm.removeClass('add edit').addClass('edit'); 15813 $shippingAddressForm.find('input[name="action"]').val('edit'); 15814 15815 $('.editaddress-shipping').removeClass('collapsed'); 15816 setShipToStore(false); 15817 } 15818 15819 setShipToStore(isShipToStoreEnabled()); 15820 $('.shipping-address-cont').removeClass('hidden'); 15821 15822 if (shippingAddressFormValidator.checkForm()) { 15823 setOPCAddress(shippingAddressFormSelector, 'dwfrm_shippingaddress_saveopcaddress').then(function (data) { 15824 handleShippingRestrictions(data); 15825 $('.payment-section').addClass('active'); 15826 $('.shipping-payment-cont').removeClass('hidden'); 15827 15828 updateShippingMethodList($shippingAddressForm, true, null); 15829 }); 15830 } else { 15831 updateShippingMethodList($shippingAddressForm, true, null); 15832 $('.payment-section').removeClass('active'); 15833 $('.shipping-payment-cont').addClass('hidden'); 15834 } 15835 15836 $('.billing-address-data.form-info').css('display', 'block'); 15837 15838 if ($('.multiple.select-address option').length > 0) { 15839 $('.multiple.select-address').show(); 15840 } else { 15841 $('.multiple.select-address').hide(); 15842 } 15843 15844 $('.single.select-address').hide(); 15845 } else if (shippingAddressType == SiteConstants.AddressTypes.Store) { 15846 $shippingAddressForm.hide(); 15847 $('.editaddress-shipping').addClass('collapsed'); 15848 $('.multiple.select-address').hide(); 15849 $('.single.select-address').show(); 15850 $('#mystores_addressList').trigger('change'); 15851 } 15852 }); 15853 15854 $('select[name$="_addressList"]', $billingAddressForm).on('change', function () { 15855 var selected = $(this).children(':selected').first(); 15856 var selectedAddress = $(selected).data('address'); 15857 15858 if (!selectedAddress) { return; } 15859 15860 util.fillAddressFields(selectedAddress, $billingAddressForm); 15861 billingAddressFormValidator.form(); 15862 }); 15863 15864 $('select[name$="_addressList"]', $shippingAddressForm).on('change', function () { 15865 var selected = $(this).children(':selected').first(); 15866 var selectedAddress = $(selected).data('address'); 15867 15868 if (!selectedAddress) { return; } 15869 15870 util.fillAddressFields(selectedAddress, $shippingAddressForm); 15871 shippingAddressFormValidator.form(); 15872 }); 15873 15874 $('#submitBilling').on('click', function(e){ 15875 e.preventDefault(); 15876 submitBilling(); 15877 }); 15878 15879 $('#submitShipping').on('click', function(e) { 15880 e.preventDefault(); 15881 submitShipping(); 15882 }); 15883 15884 $('.toggle.top, .toggle.bottom').on('click', function(e){ 15885 e.preventDefault(); 15886 $('#internationalinfo').slideToggle(); 15887 }); 15888 15889 if (options && options.Lob && options.Lob.AddressAutocomplete.Enabled) { 15890 $(document).off('keyup.AddressAutocomplete').on('keyup.AddressAutocomplete', billingAddressFormSelector + ' input[type="text"], ' + shippingAddressFormSelector + ' input[type="text"]', function (event) { 15891 var $this = $(this); 15892 var $form = $this.closest('form'); 15893 var formValidator = $form.validate(); 15894 15895 if (event.keyCode == 8 || event.keyCode == 46) { 15896 $this.parent().find('.address-autocomplete-dialog').remove(); 15897 } else if (!formValidator.checkForm() && $this.attr('id').indexOf('_address1') >= 0) { 15898 var addressAutocompleteHandler = function (addressAutocompleteData) { 15899 AddressAutocompleteDialog.initialize(options, addressAutocompleteData); 15900 } 15901 15902 AddressVerificationHelper.AutocompleteAddress($form, $this, options).then(addressAutocompleteHandler); 15903 } else { 15904 $this.parent().find('.address-autocomplete-dialog').remove(); 15905 } 15906 }); 15907 15908 $(document).off('SetAddressFromAddressAutocomplete').on('SetAddressFromAddressAutocomplete', function (event, data) { 15909 AddressVerificationHelper.SetAddressFromAddressVerificationDialog(data.$form, data.Address); 15910 }); 15911 } 15912 15913 if (options && options.Lob && options.Lob.AddressVerification.Enabled) { 15914 $(document).off('SetAddressFromAddressVerification').on('SetAddressFromAddressVerification', function (event, addressData) { 15915 if (addressData.AddressType == 'billing') { 15916 AddressVerificationHelper.SetAddressFromAddressVerificationDialog($billingAddressForm, addressData); 15917 submitBilling(true, addressData.SkipUseBillingAsShipping); 15918 } else if (addressData.AddressType == 'shipping') { 15919 AddressVerificationHelper.SetAddressFromAddressVerificationDialog($shippingAddressForm, addressData); 15920 submitShipping(false, true); 15921 } 15922 }); 15923 } 15924
15925 $(document).on('opc.SetShippingAddress', function (e, address) { 15926 var templateSettings = { 15927 interpolate: /{{([\s\S]+?)}}/g 15928 }; 15929 15930 var template = _.template($('#template-address-selector-option').html(), templateSettings); 15931 15932 address.ID = address.key; 15933 if (address.isMyStore && !address.myStoreID && address.storeId) { 15934 address.myStoreID = address.storeId; 15935 } 15936 15937 var templateData = _.extend(address, { 15938 id: address.UUID, 15939 cssClass: 'find-more-store-option', 15940 selected: 'selected', 15941 text: address.labelText 15942 }); 15943 15944 var $addressList = $('#mystores_addressList'); 15945 15946 var addressIndexInList = null; 15947 $addressList.find('option').each(function (index, object) { 15948 if (address.ID == $(object).val()) { 15949 addressIndexInList = index; 15950 return false; 15951 } 15952 }); 15953 15954 if (addressIndexInList) { 15955 $addressList.prop('selectedIndex', addressIndexInList); 15956 } else { 15957 dataBuffer['mystores_addressList'] = dataBuffer['mystores_addressList'].filter(function (address) { 15958 return !address.isTemporary; 15959 }); 15960 15961 address.isTemporary = true; 15962 dataBuffer['mystores_addressList'].push(address); 15963 dataBuffer['store_name_lookup'][address.firstName] = address.fullName; 15964 15965 $addressList.find('.find-more-store-option').remove(); 15966 $addressList.prepend(template(templateData)).prop('selectedIndex', 0); 15967 } 15968 15969 $('#mystores_addressList').trigger('change'); 15970 }); 15971 15972 $(document).on('change', '#dwfrm_multipleshipping_addressList, #mystores_addressList', function (e) { 15973 var $this = $(this); 15974 var actionName = 'dwfrm_shippingaddress_saveopcaddress'; 15975 $('.shipping-address-cont span.error').remove(); 15976 $('.shipping-address-cont input, .shipping-address-cont select').removeClass('error'); 15977 15978 var $target = $(e.currentTarget); 15979 var selectedAddress; 15980 if ($target && $target.attr('id')) { 15981 var dataBufferForAddressList = dataBuffer[$target.attr('id')]; 15982 if (dataBufferForAddressList) { 15983 selectedAddress = dataBufferForAddressList.filter(function (address) { 15984 return address.UUID == $target.val(); 15985 })[0]; 15986 } 15987 } 15988 15989 if (!selectedAddress) { 15990 return false; 15991 } 15992 15993 var isStoreAddress = false; 15994 var storeId; 15995 if (selectedAddress.hasOwnProperty('isMyStore') && selectedAddress.myStoreID) { 15996 isStoreAddress = selectedAddress.isMyStore; 15997 storeId = selectedAddress.myStoreID; 15998 } 15999 16000 setShipToStore(isStoreAddress); 16001 16002 if (isStoreAddress) { 16003 $shippingAddressForm.find('.formfield.myStoreID input').val(storeId); 16004 } else { 16005 $shippingAddressForm.find('.formfield input[type="text"], .formfield select').not('[disabled]').not('#dwfrm_shippingaddress_myStoreID').val(''); 16006 util.fillAddressFields(selectedAddress, $shippingAddressForm); 16007 } 16008 $this.find('option.placeholder').remove(); 16009 16010 setOPCAddress(shippingAddressFormSelector, actionName).then(function (data) { 16011 handleShippingRestrictions(data); 16012 $shippingAddressForm.data('shipping-filled', true); 16013 $shippingAddressForm.hide(); 16014 $('.shipping-address-data.form-info').html('').append(buildDetailsBlockForAddress(selectedAddress, false, false, 'shippingAddressForm')); 16015 $('.shipping-address-data').show(); 16016 16017 if (billingAddressFormValidator.valid()) { 16018 $('.shipping-payment-cont').removeClass('hidden'); 16019 $('.payment-section').addClass('active'); 16020 } else { 16021 $('.shipping-payment-cont').addClass('hidden'); 16022 $('.payment-section').removeClass('active'); 16023 $('.billing-address-data.form-info').hide(); 16024 16025 $billingAddressFormContainer.show(); 16026 $billingAddressFormContainer.find('input.required.field.error').eq(0).focus(); 16027 } 16028 16029 updateShippingMethodList($shippingAddressForm, true, isStoreAddress); 16030 }.bind(this)); 16031 }); 16032 16033 $('#dwfrm_billing_addressList').on('change', function() { 16034 $('.custom-email-error').remove(); 16035 var isEmailValid = util.validateEmail($('#dwfrm_billingaddress_email').val()); 16036 16037 if ($(this).val() && billingAddressFormValidator.valid() && isEmailValid) { 16038 $billingAddressForm.hide(); 16039 $('.billing-address-data').html('').append(buildDetailsBlockForForm($billingAddressForm)).show(); 16040 $('.shipping-address-cont').removeClass('hidden'); 16041 $('.shipping-address-section').addClass('active'); 16042 $('.form-checkout.address-section').attr('panel-mode', 'view').attr('value', 'true'); 16043 } else { 16044 editBillingAddress(); 16045 $('.shipping-address-cont').addClass('hidden'); 16046 $('.shipping-address-section').removeClass('active'); 16047 } 16048 }); 16049 16050 function renderZipSearchResults($storeSelector, stores) { 16051 var $results = $storeSelector.find('.zip-search-results'); 16052 $results.empty(); 16053
16054 stores.forEach(function (store) { 16055 var $option = $('<label class="store-option"></label>'); 16056 var $radio = $('<input type="radio" name="ZipSearchStoreId" />').val(store.StoreId); 16057 var $radioCircle = $('<span class="radio-circle"></span>'); 16058 var $details = $('<span class="store-details-text"></span>'); 16059 16060 $details.append($('<span class="store-name"></span>').text(store.Name)); 16061 $details.append($('<span class="store-address"></span>').text( 16062 store.Address1 + ', ' + store.City + ', ' + store.StateCode + ' ' + store.PostalCode 16063 )); 16064 16065 $option.append($details).append($radio).append($radioCircle); 16066 $results.append($option); 16067 }); 16068 16069 $results.off('click.ShipToStore.PickResult').on('click.ShipToStore.PickResult', '.store-option', function () { 16070 $results.find('.store-option').removeClass('selected'); 16071 var $checkedRadio = $(this).addClass('selected').find('input[name="ZipSearchStoreId"]').prop('checked', true); 16072 $storeSelector.data('pendingStoreId', $checkedRadio.val()); 16073 }); 16074 16075 // The results list just grew the dialog's content height - re-center it vertically now 16076 // that it's taller, same trick repSelectionsModal.js uses (reassert the current position 16077 // option to force jQuery UI to recompute it). 16078 if ($storeSelector.dialog('instance')) { 16079 $storeSelector.dialog('option', 'position', $storeSelector.dialog('option', 'position')); 16080 } 16081 } 16082 16083 function openShipToStoreDialog($shippingMethod) { 16084 // Cached on $shippingMethod (never relocated) rather than re-found via .find() every time - 16085 // once .store-selector has been dialog-ified once, it no longer lives inside 16086 // [shipping-method] until destroyed, so a plain .find() here would come up empty on any 16087 // open after the first. 16088 var $storeSelector = $shippingMethod.data('storeSelectorDialog') || $shippingMethod.find('.store-selector'); 16089 $shippingMethod.data('storeSelectorDialog', $storeSelector); 16090 16091 // Destroy any stale instance from a previous open here, rather than inside that instance's 16092 // own close callback (kept that way for safety, though the actual "second open does 16093 // nothing" bug turned out to be in dialog.js's close() calling methods on a stale singleton 16094 // reference - see dialog.js). 16095 if ($storeSelector.dialog('instance')) { 16096 $storeSelector.dialog('destroy'); 16097 $storeSelector.hide(); 16098 } 16099 16100 // Snapshot the currently-committed store so Cancel can revert to it. 16101 $storeSelector.data('originalSelectValue', $storeSelector.find('select').val()); 16102 16103 // Deliberately not calling the shared dialog.close() here - this function already destroys 16104 // its own prior instance of THIS element above; the shared singleton's close() would instead 16105 // dismiss whatever unrelated dialog (cookie consent, quickview, etc.) happens to be open 16106 // elsewhere on the page at the moment this one opens. 16107 dialog.create({ 16108 target: $storeSelector, 16109 options: { 16110 title: 'Change Ship-to-Store', 16111 dialogClass: 'ship-to-store-dialog', 16112 width: 480, 16113 open: function () { 16114 $('.ui-widget-overlay').addClass('rep-selections-overlay'); 16115 }, 16116 close: function () { 16117 $('.ui-widget-overlay').removeClass('rep-selections-overlay'); 16118 // destroy() deliberately NOT called here - see the guard at the top of this 16119 // function instead, which runs it safely on the NEXT open (a fresh call stack, 16120 // not nested inside this close event). 16121 } 16122 } 16123 }); 16124 $storeSelector.dialog('open'); 16125 } 16126 16127 $(document).off('click.ShipToStore.Change').on('click.ShipToStore.Change', '[shipping-method] .store-details .change', function (e) { 16128 openShipToStoreDialog($(this).closest('[shipping-method]')); 16129 }); 16130 16131 // Scoped to .store-selector itself, NOT [shipping-method] - once the dialog opens, jQuery UI 16132 // relocates .store-selector out from under [shipping-method] (appends it near <body>), which 16133 // breaks any selector requiring that outer ancestor. .store-selector still travels with its 16134 // own descendants regardless of where it currently sits, so scoping to it directly is safe. 16135 $(document).off('change.ShipToStore.SelectStore').on('change.ShipToStore.SelectStore', '.store-selector select', function (e) { 16136 var $storeSelector = $(this).closest('.store-selector'); 16137 $storeSelector.find('.zip-search-results .store-option').removeClass('selected');
16138 $storeSelector.find('.zip-search-results input[name="ZipSearchStoreId"]').prop('checked', false); 16139 $storeSelector.data('pendingStoreId', $(this).val()); 16140 }); 16141 16142 // Mirrors repSelectionsModal.js's showZipError/clearZipError exactly - error text comes from the 16143 // error span's own data-error-message (set in the template), not a hardcoded JS string, and the 16144 // error state clears live as the rep types, not just on the next submit attempt. 16145 function showZipError($zip, $error) { 16146 $zip.addClass('error'); 16147 $error.text($error.data('errorMessage')).addClass('visible'); 16148 } 16149 16150 function clearZipError($zip, $error) { 16151 $zip.removeClass('error'); 16152 $error.removeClass('visible'); 16153 } 16154 16155 $(document).off('input.ShipToStore.ZipSearch').on('input.ShipToStore.ZipSearch', '.store-selector .zip-search-input', function (e) { 16156 var $zipSearchForm = $(this).closest('.zip-search-form'); 16157 clearZipError($(this), $zipSearchForm.find('.error')); 16158 }); 16159 16160 // .zip-search-form is a <div>, not a <form> - this content sits inside checkout's own outer 16161 // form, and a nested <form> start tag is silently dropped by the browser's HTML parser (nested 16162 // forms are invalid HTML), leaving a submit button with nothing to submit. So this triggers on 16163 // the Search button's click and the zip field's Enter key directly, rather than a form submit. 16164 function runZipSearch($zipSearchForm) { 16165 var $storeSelector = $zipSearchForm.closest('.store-selector'); 16166 var $zip = $zipSearchForm.find('.zip-search-input'); 16167 var $error = $zipSearchForm.find('.error'); 16168 var $searchButtonContainer = $zipSearchForm.find('.btn-store-search-container'); 16169 16170 clearZipError($zip, $error); 16171 16172 if ($.trim($zip.val()).length !== 5) { 16173 showZipError($zip, $error); 16174 return; 16175 } 16176 16177 $searchButtonContainer.loading(); 16178 16179 $.ajax({ 16180 url: Urls.searchStoresByZip, 16181 type: 'GET', 16182 dataType: 'json', 16183 data: { Zip: $.trim($zip.val()) } 16184 }).done(function (result) { 16185 if (result && result.Success && result.Stores && result.Stores.length > 0) { 16186 clearZipError($zip, $error); 16187 renderZipSearchResults($storeSelector, result.Stores); 16188 } else { 16189 $storeSelector.find('.zip-search-results').empty(); 16190 showZipError($zip, $error); 16191 } 16192 }).fail(function () { 16193 $storeSelector.find('.zip-search-results').empty(); 16194 showZipError($zip, $error); 16195 }).always(function () { 16196 if ($searchButtonContainer.attr('loading')) { 16197 $searchButtonContainer.loading('destroy'); 16198 } 16199 }); 16200 } 16201 16202 $(document).off('click.ShipToStore.ZipSearch').on('click.ShipToStore.ZipSearch', '.store-selector .zip-search-form .store-search', function (e) { 16203 e.preventDefault(); 16204 runZipSearch($(this).closest('.zip-search-form')); 16205 }); 16206 16207 $(document).off('keydown.ShipToStore.ZipSearch').on('keydown.ShipToStore.ZipSearch', '.store-selector .zip-search-input', function (e) { 16208 if (e.key === 'Enter' || e.keyCode === 13) { 16209 e.preventDefault(); 16210 runZipSearch($(this).closest('.zip-search-form')); 16211 } 16212 }); 16213 16214 $(document).off('click.ShipToStore.Geolocation').on('click.ShipToStore.Geolocation', '.store-selector .geolocation', function (e) { 16215 var $geolocationLink = $(this); 16216 var $storeSelector = $geolocationLink.closest('.store-selector'); 16217 var $zip = $storeSelector.find('.zip-search-input'); 16218 var $error = $storeSelector.find('.zip-search-form .error'); 16219 16220 if (!navigator.geolocation) { 16221 return; 16222 } 16223 16224 // Same fullscreen loader Save/setOPCAddress() uses, for consistency - no bespoke 16225 // modal-scoped spinner treatment. 16226 $('body').loading(loadingIndicatorSettings); 16227 16228 navigator.geolocation.getCurrentPosition(function (position) { 16229 $.ajax({ 16230 url: Urls.searchStoresByZip, 16231 type: 'GET', 16232 dataType: 'json', 16233 data: { Latitude: position.coords.latitude, Longitude: position.coords.longitude } 16234 }).done(function (result) { 16235 if (result && result.Success && result.Stores && result.Stores.length > 0) { 16236 clearZipError($zip, $error); 16237 renderZipSearchResults($storeSelector, result.Stores); 16238 } else { 16239 $storeSelector.find('.zip-search-results').empty(); 16240 showZipError($zip, $error); 16241 } 16242 }).fail(function () { 16243 $storeSelector.find('.zip-search-results').empty(); 16244 showZipError($zip, $error); 16245 }).always(function () { 16246 if ($('body').attr('loading')) { 16247 $('body').loading('destroy'); 16248 } 16249 }); 16250 }, function () { 16251 showZipError($zip, $error); 16252 if ($('body').attr('loading')) { 16253 $('body').loading('destroy'); 16254 } 16255 }); 16256 }); 16257 16258 $(document).off('click.ShipToStore.Apply').on('click.ShipToStore.Apply', '.store-selector .apply', function (e) { 16259 var $storeSelector = $(this).closest('.store-selector'); 16260 var storeId = $storeSelector.data('pendingStoreId') || $storeSelector.find('select').val(); 16261 16262 $storeSelector.dialog('close'); 16263 if ($storeSelector.dialog('instance')) { 16264 $storeSelector.dialog('destroy'); 16265 } 16266 $storeSelector.hide(); 16267 16268 if (!storeId) { 16269 return; 16270 } 16271 16272 $shippingAddressForm.find('.formfield.myStoreID input').val(storeId); 16273 16274 setOPCAddress(shippingAddressFormSelector, 'dwfrm_shippingaddress_saveopcaddress').then(function (data) { 16275 updateShippingMethodList($shippingAddressForm, true); 16276 }); 16277 }); 16278 16279 $(document).off('click.ShipToStore.Cancel').on('click.ShipToStore.Cancel', '.store-selector .cancel', function (e) { 16280 var $storeSelector = $(this).closest('.store-selector'); 16281 16282 // Revert anything touched during this open - the select and any zip-search pick - so 16283 // nothing from a canceled interaction lingers into a later Apply. 16284 var originalValue = $storeSelector.data('originalSelectValue'); 16285 if (originalValue !== undefined) { 16286 $storeSelector.find('select').val(originalValue); 16287 } 16288 $storeSelector.removeData('pendingStoreId'); 16289 $storeSelector.find('.zip-search-results').empty(); 16290 $storeSelector.find('.zip-search-input').val('');
16291 clearZipError($storeSelector.find('.zip-search-input'), $storeSelector.find('.zip-search-form .error')); 16292 16293 $storeSelector.dialog('close'); 16294 if ($storeSelector.dialog('instance')) { 16295 $storeSelector.dialog('destroy'); 16296 } 16297 $storeSelector.hide(); 16298 }); 16299 16300 $(document).off('click.ShippingMethod.Select').on('click.ShippingMethod.Select', 'input[name*="_shippingMethodID"]', function (event) { 16301 var $this = $(this); 16302 var $shippingMethod = $this.closest('[shipping-method]'); 16303 var $shipment = $this.closest('form'); 16304 16305 if ($shippingMethod.attr('status') == 'disabled') { 16306 event.preventDefault(); 16307 } else { 16308 selectShippingMethod($shipment.attr('shipment'), $this.val(), $shippingMethod.attr('is-ship-to-store') == 'true', $shippingMethod); 16309 } 16310 }); 16311 16312 $(document).off('focus.AutofillHandler').on('focus.AutofillHandler', 'div.billing-address-form input[type="text"], div.shipping-address-form input[type="text"]', function (event) { 16313 var $this = $(this); 16314 var $form = $this.closest('form'); 16315 var autofillCount = $form.find('input:-webkit-autofill').length; 16316 16317 if (window.innerWidth <= 768) { 16318 if (autofillCount == 0) { 16319 $form.attr('auto-filled', false); 16320 } 16321 16322 if ($form.attr('auto-filled') != 'true') { 16323 dataBuffer.AutofillDetectorInterval = setInterval(function() { 16324 autofillCount = $form.find('input:-webkit-autofill').length; 16325 if (autofillCount > 0 && $form.attr('auto-filled') != 'true') { 16326 $form.attr('auto-filled', true); 16327 $this.attr('inputmode', 'none'); 16328 $this.trigger('blur'); 16329 setTimeout(function() { 16330 $this.removeAttr('inputmode'); 16331 }, 250); 16332 } 16333 }, 250); 16334 } 16335 } 16336 }); 16337} 16338 16339$(document).off('blur.AutofillHandler').on('blur.AutofillHandler', 'div.billing-address-form input[type="text"], div.shipping-address-form input[type="text"]', function (event) { 16340 if (dataBuffer && dataBuffer.AutofillDetectorInterval) { 16341 clearInterval(dataBuffer.AutofillDetectorInterval); 16342 } 16343}); 16344 16345function initializeUserInterface() { 16346 $('#dwfrm_shippingaddress_ID').val(''); 16347 $('.form-checkout.address-section').attr('panel-mode', 'blank'); 16348 $('.form-checkout.shipping-address-section').attr('panel-mode', 'blank').attr('value', 'false'); 16349 16350 var billingAddress = getAddressFromForm($billingAddressForm); 16351 var shippingAddress = getAddressFromForm($shippingAddressForm); 16352 var $billingSavedAddrDropdown = $('#dwfrm_billing_addressList'); 16353 var didBillingAddressSuccessHandlerRun = false; 16354 var didShippingAddressSuccessHandlerRun = false; 16355 16356 $('#dwfrm_billingaddress_country').trigger('change'); 16357 $('#dwfrm_shippingaddress_country').trigger('change'); 16358 16359 $.validator.addMethod('requiredExcludingPunctuation', ValidationHelper.ValidateRequiredExcludingPunctuation, Resources.INVALID_VALUE); 16360 $.validator.addMethod('postalCode', ValidationHelper.ValidatePostalCode, Resources.INVALID_POSTAL_CODE); 16361 $.validator.addMethod('postOfficeBoxOnly', ValidationHelper.ValidateAddressForPostOfficeBoxOnly, Resources.INVALID_POST_OFFICE_BOX_ONLY); 16362 16363 billingAddressFormValidator = $billingAddressForm.validate(); 16364 billingAddressFormValidator.settings.ignore = [":not(.required)"]; 16365 billingAddressFormValidator.settings.onfocusout = ValidationSettings.Checkout.onfocusout; 16366 billingAddressFormValidator.settings.errorPlacement = ValidationSettings.Checkout.errorPlacement; 16367 $billingAddressForm.find('input[name$="_firstName"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16368 $billingAddressForm.find('input[name$="_lastName"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16369 $billingAddressForm.find('input[name$="_address1"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16370 $billingAddressForm.find('input[name$="_address1"]').rules('add', ValidationRules.ValidateAddressForPostOfficeBoxOnly); 16371 $billingAddressForm.find('input[name$="_address2"]').rules('add', ValidationRules.ValidateAddressForPostOfficeBoxOnly); 16372 $billingAddressForm.find('input[name$="_city"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16373 $billingAddressForm.find('input[name$="_postal"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16374 16375 shippingAddressFormValidator = $shippingAddressForm.validate(); 16376 shippingAddressFormValidator.settings.ignore = [":not(.required)"]; 16377 shippingAddressFormValidator.settings.onfocusout = ValidationSettings.Checkout.onfocusout; 16378 shippingAddressFormValidator.settings.errorPlacement = ValidationSettings.Checkout.errorPlacement; 16379 $shippingAddressForm.find('input[name$="_firstName"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16380 $shippingAddressForm.find('input[name$="_lastName"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16381 $shippingAddressForm.find('input[name$="_address1"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16382 $shippingAddressForm.find('input[name$="_address1"]').rules('add', ValidationRules.ValidateAddressForPostOfficeBoxOnly); 16383 $shippingAddressForm.find('input[name$="_address2"]').rules('add', ValidationRules.ValidateAddressForPostOfficeBoxOnly); 16384 $shippingAddressForm.find('input[name$="_city"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16385 $shippingAddressForm.find('input[name$="_postal"]').rules('add', ValidationRules.RequiredExcludingPunctuation); 16386 16387 if (!billingAddress.address1 && $billingSavedAddrDropdown.find('option').length && $billingSavedAddrDropdown.val()) { 16388 $billingSavedAddrDropdown.trigger('change'); 16389 } else { 16390 if (billingAddressFormValidator.checkForm()) { 16391 $billingAddressForm.find('input.shipping-same').prop('checked', false); 16392 $billingAddressForm.find('input.shipping-newsletter-signup').prop('checked', false); 16393 didBillingAddressSuccessHandlerRun = billingAddressSuccessHandler(null, true); 16394 } else { 16395 editBillingAddress(); 16396 } 16397 } 16398 16399 renderMyStoresAddressSelector(); 16400 var $shippingSavedAddrDropdown = $('#dwfrm_multipleshipping_addressList'); 16401 if (billingAddressFormValidator.checkForm() && !didBillingAddressSuccessHandlerRun) { 16402 if (!shippingAddress.address1 && $shippingSavedAddrDropdown.find('option').length && $shippingSavedAddrDropdown.val()) { 16403 $shippingSavedAddrDropdown.trigger('change'); 16404 } else { 16405 if (shippingAddressFormValidator.checkForm()) { 16406 didShippingAddressSuccessHandlerRun = shippingAddressSuccessHandler(true); 16407 verifyShipping(); 16408 } else { 16409 editShippingAddress(); 16410 } 16411 } 16412 } 16413 16414 $('.form-checkout.shipping-address-section .select-address.multiple').show(); 16415 $('.address-section').addClass('active'); 16416 16417 if (didBillingAddressSuccessHandlerRun && shippingAddressFormValidator.checkForm() && window.innerWidth <= 767) { 16418 setTimeout(function() { 16419 $([document.documentElement, document.body]).scrollTop($('.form-checkout.payment-section').offset().top - $('.header-wrapper').height() + 20); 16420 }, 1000); 16421 } 16422} 16423 16424function billingAddressSuccessHandler(responseData, skipUpdateShippingMethodList, isVerified, skipUseBillingAsShipping) { 16425 var $shippingSavedAddrDropdown = $('#dwfrm_multipleshipping_addressList'); 16426 var shippingAddress = getAddressFromForm($shippingAddressForm); 16427 16428 $billingAddressForm.hide(); 16429 $('.form-checkout.address-section').attr('panel-mode', 'view').attr('value', 'true'); 16430 $('.billing-address-data').html('').append(buildDetailsBlockForForm($billingAddressForm)).show(); 16431 $('.shipping-address-cont').removeClass('hidden'); 16432 16433 if (responseData && responseData.status == 'success' && !skipUseBillingAsShipping && ($('#isShippingAddressSameAsBillingAddress').prop('checked') || $('[has-store-pickup-shipment-only]').attr('has-store-pickup-shipment-only') == 'true')) { 16434 populateBillingAddressFormToShippingAddressForm(); 16435 } 16436 16437 if (responseData && responseData.status == 'shippingAddressValidationError') { 16438 editShippingAddress(); 16439 } else if (!skipUseBillingAsShipping && ($('#isShippingAddressSameAsBillingAddress').prop('checked') || $('[has-store-pickup-shipment-only]').attr('has-store-pickup-shipment-only') == 'true')) { 16440 $('.shipping-address-data.form-info').html('').append(buildDetailsBlockForForm($shippingAddressForm)); 16441 $('.shipping-address-data').show(); 16442 16443 $shippingAddressForm.hide(); 16444 $shippingAddressForm.data('shipping-filled', true); 16445 $paymentFormContainer.addClass('active'); 16446 $('.shipping-payment-cont').removeClass('hidden'); 16447 submitShipping(null, isVerified); 16448 } else if (shippingAddressFormValidator.checkForm()) { 16449 shippingAddressSuccessHandler(skipUpdateShippingMethodList); 16450 } else if (!shippingAddress.address1 && $shippingSavedAddrDropdown.find('option').length && $shippingSavedAddrDropdown.val()) { 16451 $shippingSavedAddrDropdown.trigger('change'); 16452 } else { 16453 editShippingAddress(); 16454 } 16455 16456 $('.shipping-address-section').addClass('active').show(); 16457 16458 if (!skipUpdateShippingMethodList) { 16459 updateShippingMethodList($shippingAddressForm, true); 16460 } 16461 16462 if ($shippingAddressForm.data('shipping-filled') == true) { 16463 $paymentFormContainer.addClass('active').find('.shipping-payment-cont').removeClass('hidden'); 16464 $shippingAddressForm.hide(); 16465 $('.shipping-address-data').show(); 16466 } 16467 16468 if (window.innerWidth <= 767) { 16469 $(window).scrollTop($('.shipping-address-section').offset().top - $('.header-wrapper').height()); 16470 } 16471 16472 return true; 16473} 16474 16475function shippingAddressSuccessHandler(skipUpdateShippingMethodList, isCancel, isVerified) { 16476 var selectedAddressID; 16477 var currentAddressIDs = []; 16478 var $shippingSelect = $('#dwfrm_multipleshipping_addressList'); 16479 var $blankOption = $('<option>', { 'class': 'placeholder', 'value': '', 'text': Resources.OPC_SELECT_ADDR }); 16480 16481 $('.select-address.address-selector select option').map(function() { currentAddressIDs.push($(this).val()); }); 16482 16483 if ($shippingAddressForm.hasClass('add') || ($shippingAddressForm.hasClass('edit') && !$shippingAddressForm.find('.set-default-shipping input').prop('checked'))) { 16484 selectedAddressID = "new"; 16485 $shippingAddressForm.find('input[name$="_ID"]').val(''); 16486 16487 if ($shippingSelect.find('option.placeholder').length == 0) {
16488 $shippingSelect.prepend($blankOption).prop('selectedIndex', 0); 16489 } 16490 } else { 16491 selectedAddressID = $('.select-address.address-selector select').val(); 16492 } 16493 16494 writeShippingAddressFormToBuffer(); 16495 var panelMode = $shippingAddressSection.attr('panel-mode'); 16496 $shippingAddressForm.removeClass('add edit'); 16497 $('.form-checkout.shipping-address-section').attr('panel-mode', 'view'); 16498 16499 var renderAddressSelectorCallback = function (data) { 16500 $shippingAddressForm.data('shipping-filled', true); 16501 $shippingAddressForm.hide(); 16502 $shippingAddressForm.find('input[name="action"]').val(''); 16503 16504 if (!isCancel && (panelMode == 'add' || panelMode == 'edit')) { 16505 if ($shippingSelect.find('option.placeholder').length == 0) { 16506 $shippingSelect.prepend($blankOption).prop('selectedIndex', 0); 16507 } 16508 if (data && data.selectedAddressID) { 16509 $shippingSelect.val(data.selectedAddressID).val(data.selectedAddressID).prop('selectedIndex', $shippingSelect.find('option:selected').index()); 16510 } else if (data && !data.selectedAddressID) { 16511 $shippingSelect.prop('selectedIndex', 0); 16512 } 16513 } 16514 16515 $('.shipping-address-data.form-info').html('').append(buildDetailsBlockForForm($shippingAddressForm)); 16516 $('.shipping-address-data').show(); 16517 if (!isVerified) { 16518 verifyShipping(isCancel, isVerified); 16519 } 16520 16521 if (billingAddressFormValidator.checkForm()) { 16522 $('.shipping-payment-cont').removeClass('hidden'); 16523 $('.payment-section').addClass('active'); 16524 } else { 16525 $('.shipping-payment-cont').addClass('hidden'); 16526 $('.payment-section').removeClass('active'); 16527 $('.billing-address-data.form-info').hide(); 16528 16529 var formBody = $('.billing-address-form'); 16530 formBody.show(); 16531 formBody.find('input.required.field.error').eq(0).focus(); 16532 } 16533 16534 if (!skipUpdateShippingMethodList) { 16535 updateShippingMethodList($shippingAddressForm, true, null, true); 16536 } 16537 } 16538 16539 var isAuthenticated = $sectionCheckout.attr('is-authenticated') == "true"; 16540 if (isAuthenticated) { 16541 renderAddressSelector({ 16542 container: '.select-address.address-selector', 16543 el: '.select-address.address-selector .field-wrapper', 16544 id: 'dwfrm_multipleshipping_addressList', 16545 selected: selectedAddressID, 16546 currentAddresses: currentAddressIDs, 16547 callback: renderAddressSelectorCallback 16548 }); 16549 } else { 16550 renderAddressSelectorCallback(); 16551 } 16552 16553 if (window.innerWidth <= 767) { 16554 $(window).scrollTop($('.payment-section').offset().top - $('.header-wrapper').height()); 16555 } 16556 16557 return true; 16558} 16559 16560function submitBilling(isVerified, skipUseBillingAsShipping) { 16561 $('#submitBilling').attr('disabled', true); 16562 if ($('.billing-address-type-selector input[value=1]').prop('checked') && $('#dwfrm_billing_addressList').val() == '') { 16563 $('#submitBilling').attr('disabled', false); 16564 return; 16565 } 16566 16567 if ($('#isShippingAddressSameAsBillingAddress').is(':checked') || $('[has-store-pickup-shipment-only]').attr('has-store-pickup-shipment-only') == 'true') { 16568 $('input[name$="_useAsShippingAddress"]').prop('checked', true); 16569 } else { 16570 $('input[name$="_useAsShippingAddress"]').prop('checked', false); 16571 } 16572 16573 billingAddressFormValidator.form(); 16574 $('.custom-email-error').remove(); 16575 16576 var isEmailValid = util.validateEmail($('#dwfrm_billingaddress_email').val()); 16577 if (billingAddressFormValidator.valid() && isEmailValid) { 16578 $billingAddressForm = $(billingAddressFormSelector); 16579 $billingAddressFormContainer.find('.validation-error-container').removeAttr('role').hide(); 16580 verifyBilling(null, isVerified, skipUseBillingAsShipping); 16581 } else { 16582 $billingAddressFormContainer.find('.validation-error-container').attr('role','alert').show(); 16583 $('#submitBilling').attr('disabled', false); 16584 if (!isEmailValid && billingAddressFormValidator.valid()) { 16585 $('#dwfrm_billingaddress_email').addClass('error').parent().append('<span class="error custom-email-error">' + Resources.VALIDATE_EMAIL + '</span>'); 16586 } 16587 $('.billing-address-type-selector input[value="2"]').trigger('click', [true]); 16588 } 16589} 16590 16591function verifyBilling(isCancel, isVerified, skipUseBillingAsShipping) { 16592 var addressDeliverable = function () { 16593 setOPCAddress(billingAddressFormSelector, $('#selectOpcAddress').attr('name'), skipUseBillingAsShipping).then(function (data) { 16594 billingAddressSuccessHandler(data, null, true, skipUseBillingAsShipping); 16595 $('#submitBilling').attr('disabled', false); 16596 }); 16597 } 16598 16599 var addressNotDeliverable = function (addressVerifyData) {
16600 AddressVerificationDialog.initialize(options, 'billing', addressVerifyData); 16601 $('#submitBilling').attr('disabled', false); 16602 } 16603 16604 // Transactional SMS 16605 var populateSMSphone = function () { 16606 if (SitePreferences.TRANSACTIONAL_SMS) { 16607 var billingPhone = $billingAddressForm.find('[id*="_phone"]').val(); 16608 $('.order-transactional-sms-phone input[id*="transactionalsms_smsPhone"]').val(billingPhone).trigger('input'); 16609 } 16610 } 16611 16612 var country = $billingAddressForm.find('[id*="_country"]').val(); 16613 if (!isVerified && options && options.Lob && options.Lob.AddressVerification.Enabled && country.toUpperCase() == 'US') { 16614 AddressVerificationHelper.VerifyAddress($billingAddressForm, options).then(addressDeliverable, addressNotDeliverable); 16615 } else { 16616 addressDeliverable(); 16617 } 16618 populateSMSphone(); 16619} 16620 16621function submitShipping(isCancel, isVerified) { 16622 $('#submitShipping').attr('disabled', true); 16623 $('.shipping-address-cont span.error').remove(); 16624 $('.shipping-address-cont input, .shipping-address-cont select').removeClass('error'); 16625 16626 shippingAddressFormValidator.form(); 16627 if ($shippingAddressForm.valid()) { 16628 $shippingAddressFormContainer.find('.validation-error-container').removeAttr('role').hide(); 16629 verifyShipping(isCancel, isVerified); 16630 } else { 16631 $shippingAddressFormContainer.find('.validation-error-container').attr('role','alert').show(); 16632 $('#submitShipping').attr('disabled', false); 16633 } 16634} 16635 16636function verifyShipping(isCancel, isVerified) { 16637 var addressDeliverable = function () { 16638 setOPCAddress(shippingAddressFormSelector, $('#submitShipping').attr('name')).then(function (data) { 16639 var isShippingRestricted = handleShippingRestrictions(data); 16640 $('#submitShipping').attr('disabled', false); 16641 if (!isShippingRestricted) { 16642 shippingAddressSuccessHandler(false, isCancel, true); 16643 $('.payment-methods-section').show(); 16644 } 16645 }); 16646 } 16647 16648 var addressNotDeliverable = function (addressVerifyData) { 16649 AddressVerificationDialog.initialize(options, 'shipping', addressVerifyData); 16650 $('#submitShipping').attr('disabled', false); 16651 } 16652 16653 var country = $shippingAddressForm.find('[id*="_country"]').val(); 16654 if (!isVerified && options && options.Lob && options.Lob.AddressVerification.Enabled && country.toUpperCase() == 'US') { 16655 AddressVerificationHelper.VerifyAddress($shippingAddressForm, options).then(addressDeliverable, addressNotDeliverable); 16656 } else { 16657 addressDeliverable(); 16658 } 16659} 16660 16661function writeBufferToAddressForm(name, $selector) { 16662 if (dataBuffer[name]) { 16663 $selector.each(function (index, element) { 16664 var $field = $(element); 16665 $field.val(dataBuffer[name][$field.attr('name')] || ''); 16666 }); 16667 16668 if (name == 'shippingAddressFields') { 16669 var $form = $('.shipping-address-form'); 16670 var $countryDropdown = $form.find('[id*="_country"]'); 16671 var $stateDropdown = $form.find('[id*="states_state"]'); 16672 renderOptions('#' + $stateDropdown.attr('id'), '#' + $countryDropdown.attr('id')); 16673 16674 if ($('#dwfrm_shippingaddress_states_state').length > 0 && dataBuffer['shippingAddressFields']['dwfrm_shippingaddress_states_state']) { 16675 $('#dwfrm_shippingaddress_states_state').val(dataBuffer['shippingAddressFields']['dwfrm_shippingaddress_states_state']); 16676 } 16677 } 16678 } 16679} 16680 16681function writeBufferToShippingAddressForm() { 16682 var $shippingAddressFields = $shippingAddressForm.find('.formfield input[type="text"], .formfield select').not('[disabled]').not('#dwfrm_shippingaddress_myStoreID'); 16683 writeBufferToAddressForm('shippingAddressFields', $shippingAddressFields); 16684} 16685 16686function writeAddressFormToBuffer(name, $selector, doClear) { 16687 $selector.each(function (index, element) { 16688 var $field = $(element); 16689 16690 if ($field.val()) { 16691 if (!dataBuffer[name]) { 16692 dataBuffer[name] = {}; 16693 } 16694 16695 dataBuffer[name][$field.attr('name')] = $field.val(); 16696 } 16697 }); 16698 16699 if (doClear) { 16700 $selector.val(''); 16701 $selector.find('option[default]').prop('selected', true); 16702 } 16703} 16704 16705function writeShippingAddressFormToBuffer(doClear) { 16706 var $shippingAddressFields = $shippingAddressForm.find('.formfield input[type="text"], .formfield select').not('[disabled]').not('#dwfrm_shippingaddress_myStoreID'); 16707 writeAddressFormToBuffer('shippingAddressFields', $shippingAddressFields, doClear); 16708} 16709 16710/** 16711 * create address object from form 16712 * @param $form 16713 * @returns Address Object 16714 */ 16715function getAddressFromForm($form) { 16716 return { 16717 ID: util.htmlEncode($form.find('input[name$="_ID"]').val()), 16718 isStore: util.htmlEncode($form.find('input[name$="_isStore"]').prop('checked')), 16719 firstName: util.htmlEncode($form.find('input[name$="_firstName"]').val()), 16720 lastName: util.htmlEncode($form.find('input[name$="_lastName"]').val()), 16721 address1: util.htmlEncode($form.find('input[name$="_address1"]').val()), 16722 address2: util.htmlEncode($form.find('input[name$="_address2"]').val()), 16723 address3: util.htmlEncode($form.find('input[name$="_address3"]').val()), 16724 countryCode: util.htmlEncode($form.find('select[id$="_country"]').val()), 16725 stateCode: util.htmlEncode($form.find('select[id$="_state"]').val()), 16726 postalCode: $form.find('input[name$="_postal"]').val() ? util.htmlEncode($form.find('input[name$="_postal"]').val().toUpperCase()) : '', 16727 city: util.htmlEncode($form.find('input[name$="_city"]').val()), 16728 phone: util.htmlEncode($form.find('input[name$="_phone"]').val()), 16729 email: util.htmlEncode($form.find('input[name$="_email"]').val()) 16730 }; 16731} 16732 16733function populateBillingAddressFormToShippingAddressForm() { 16734 var billingAddress = getAddressFromForm($billingAddressForm); 16735 16736 $shippingAddressForm.find('input[name$="_ID"]').val(''); 16737 $shippingAddressForm.find('input[name$="_firstName"]').val(billingAddress.firstName).trigger('change'); 16738 $shippingAddressForm.find('input[name$="_lastName"]').val(billingAddress.lastName).trigger('change'); 16739 $shippingAddressForm.find('input[name$="_address1"]').val(billingAddress.address1).trigger('change'); 16740 $shippingAddressForm.find('input[name$="_address2"]').val(billingAddress.address2).trigger('change'); 16741 $shippingAddressForm.find('input[name$="_address3"]').val(billingAddress.address3).trigger('change'); 16742 $shippingAddressForm.find('input[name$="_postal"]').val(billingAddress.postalCode).trigger('change'); 16743 $shippingAddressForm.find('input[name$="_city"]').val(billingAddress.city).trigger('change'); 16744 $shippingAddressForm.find('select[id$=country]').val(billingAddress.countryCode).trigger('change'); 16745 $shippingAddressForm.find('select[id$=state]').val(billingAddress.stateCode).trigger('change'); 16746 $shippingAddressForm.find('input[name$="_phone"]').val(billingAddress.phone).trigger('change'); 16747 16748 if ($('#dwfrm_multipleshipping_addressList').find('option.placeholder').length == 0) { 16749 $('#dwfrm_multipleshipping_addressList').prepend('<option class="placeholder">' + Resources.OPC_SELECT_ADDR + '</option>').prop('selectedIndex', 0); 16750 } 16751} 16752 16753function buildDetailsBlockForForm($form, isCompact, hideNickname) { 16754 var address = getAddressFromForm($form); 16755 for (var addressKey in address) { 16756 if (address[addressKey] != null && address[addressKey].search(/\^/) != -1) { 16757 address[addressKey] = address[addressKey].replace(/\^/gi,"'"); 16758 } 16759 } 16760 16761 return buildDetailsBlockForAddress(address, isCompact, hideNickname, $form.attr('id')); 16762} 16763 16764function buildDetailsBlockForAddress(address, isCompact, hideNickname, formId) { 16765 var shippingAddressType = getShippingAddressType(); 16766 var htmlText = $('<div/>
16766', {"class": "address-details-st"}); 16767 var header = isCompact ? '' : formId == 'billingAddressForm' ? '<h6>Billing Recipient</h6>' : formId == 'shippingAddressForm' ? '<h6>Ship To:</h6>' : ''; 16768 var editButton = (!isCompact && !shippingAddressType || shippingAddressType == SiteConstants.AddressTypes.Customer) ? '<p class="text-right edit-address-container"><a class="edit-address-det" tabindex="0">Edit<span class="visually-hidden"> Address Information</span></a></p>' : ''; 16769 var addNewButton = ''; 16770 var addressNickname = ''; 16771 16772 if (formId == 'shippingAddressForm') { 16773 if (address.address1 && !hideNickname) { 16774 if (address.ID && !address.myStoreID) { 16775 addressNickname = address.ID; 16776 } else if (formId == 'shippingAddressForm' && shippingAddressType == SiteConstants.AddressTypes.Customer && dataBuffer['dwfrm_multipleshipping_addressList']) { 16777 var selectedAddressFromDropdown = dataBuffer['dwfrm_multipleshipping_addressList'].filter(function (addressOption) { 16778 return addressOption.UUID == $('#dwfrm_multipleshipping_addressList').val(); 16779 }); 16780 16781 if (selectedAddressFromDropdown.length > 0 && selectedAddressFromDropdown[0].displayValue && $('[has-warehouse-shipment]').attr('has-warehouse-shipment') == 'true') { 16782 util.fillAddressFields(selectedAddressFromDropdown[0], $('#shippingAddressForm')); 16783 writeShippingAddressFormToBuffer(); 16784 addressNickname = selectedAddressFromDropdown[0].displayValue; 16785 } 16786 } 16787 16788 if (addressNickname) { 16789 addressNickname = '<span class="address-nickname">' + addressNickname + '</span>'; 16790 } 16791 16792 $('.form-checkout.shipping-address-section').attr('panel-mode', 'view').attr('value', 'true'); 16793 } 16794 16795 if (!isCompact && shippingAddressType == SiteConstants.AddressTypes.Customer) { 16796 addNewButton = '<p class="add-address-container"><a class="add-address-det" tabindex="0">+ Add New Address</a></p>'; 16797 } 16798 } 16799 16800 var htmlcontent = ''; 16801 if (address.address1) { 16802 htmlcontent += header; 16803 htmlcontent += '<div class="address" tabindex="0"><div>' + (address.myStoreID ? address.fullName : address.firstName) + ' ' + address.lastName + addressNickname + ' </div>'; 16804 htmlcontent += '<div>' + address.address1 + ' </div>'; 16805 if (address.address2) { 16806 htmlcontent += '<div>' + address.address2 + ' </div>'; 16807 } 16808 16809 if (address.address3) { 16810 htmlcontent += '<div>' + address.address3 + ' </div>'; 16811 } 16812 16813 htmlcontent += '<div>' + address.city; 16814 16815 if (address.stateCode && address.stateCode.toUpperCase() != 'OTHER') { 16816 htmlcontent += ' ' + address.stateCode; 16817 } 16818 16819 htmlcontent += ' ' + address.postalCode; 16820 htmlcontent += ' ' + address.countryCode + '</div>'; 16821 if (address.phone) { 16822 htmlcontent += '<div>' + address.phone + '</div>'; 16823 } 16824 16825 if (address.email) { 16826 htmlcontent += '<div class="billing-email-address">' + address.email + '</div>'; 16827 } 16828 htmlcontent += '</div>'; 16829 16830 if (formId != 'shippingAddressForm' || (!options || !options.Workforce || !options.Workforce.HasForceShippingAddress)) { 16831 htmlcontent += editButton; 16832 } 16833 if (formId == 'shippingAddressForm' && (!options || !options.Workforce || !options.Workforce.HasForceShippingAddress)) { 16834 htmlcontent += addNewButton; 16835 } 16836 } 16837 16838 htmlText.html(htmlcontent); 16839 16840 return htmlText; 16841} 16842 16843/** 16844 * @function 16845 * @description Helper method which constructs a URL for an AJAX request using the 16846 * entered address information as URL request parameters. 16847 */ 16848function getShippingMethodURL($form, url, extraParams) { 16849 var params = { 16850 isStore: $form.find('input[name$="_isStore"]').prop('checked'), 16851 myStoreID: $form.find('input[name$="_myStoreID"]').val(), 16852 address1: $form.find('input[name$="_address1"]').val(), 16853 address2: $form.find('input[name$="_address2"]').val(), 16854 address3: $form.find('input[name$="_address3"]').val(), 16855 countryCode: $form.find('select[id$="_country"]').val(), 16856 stateCode: $form.find('select[id$="_state"]').val(), 16857 postalCode: $form.find('input[name$="_postal"]').val(), 16858 city: $form.find('input[name$="_city"]').val() 16859 }; 16860 16861 return util.appendParamsToUrl(url, $.extend(params, extraParams)); 16862} 16863 16864function updateShippingMethodList($form, doUpdateSummary, isMyStore, do
16864DataLayerPush, $selectedShippingMethod) { 16865 if (!$shippingMethodList || $shippingMethodList.length === 0) { return; } 16866 16867 var shippingMethodListData = { 16868 selectedPaymentMethod: $paymentForm.find('input[name*="_selectedPaymentMethodID"]').val() 16869 } 16870 16871 var $shipToStoreOptionInAddressPanel = $('.single.shipping-address-type-selector'); 16872 if ($shipToStoreOptionInAddressPanel.length > 0) { 16873 if ($shipToStoreOptionInAddressPanel.find('input:checked').val() == SiteConstants.AddressTypes.Store) { 16874 shippingMethodListData.ShipToStoreOnly = true; 16875 16876 if (dataBuffer[CheckoutConstants.User.SelectedStoreShippingMethod]) { 16877 shippingMethodListData.SelectShippingMethod = dataBuffer[CheckoutConstants.User.SelectedStoreShippingMethod]; 16878 } 16879 } else if ($shipToStoreOptionInAddressPanel.find('input:checked').val() == SiteConstants.AddressTypes.Customer) { 16880 shippingMethodListData.ShipToStoreExclude = true; 16881 16882 if (dataBuffer[CheckoutConstants.User.SelectedCustomerShippingMethod]) { 16883 shippingMethodListData.SelectShippingMethod = dataBuffer[CheckoutConstants.User.SelectedCustomerShippingMethod]; 16884 } 16885 } 16886 } 16887 16888 if (isMyStore) { 16889 shippingMethodListData.ShipToStoreOnly = true; 16890 } 16891 16892 var shippingMethodListUrl = getShippingMethodURL($form, Urls.shippingMethodsList); 16893 $shippingMethodList.load(shippingMethodListUrl, shippingMethodListData, function () { 16894 var selectedStore = $shippingAddressForm.find('.formfield.myStoreID input').val(); 16895 var $shipToStoreShippingMethods; 16896 if (options && options.AgentStore && options.AgentStore.StoreShippingAddressOnly) { 16897 $shipToStoreShippingMethods = $('[shipping-method]'); 16898 } else { 16899 $shipToStoreShippingMethods = $('[shipping-method][is-ship-to-store="true"]'); 16900 } 16901 16902 if ($shipToStoreShippingMethods.length > 0) { 16903 var selectedStoreFromShippingMethod = $shipToStoreShippingMethods.find('.store-selector select').val(); 16904 16905 if (selectedStoreFromShippingMethod && selectedStoreFromShippingMethod != selectedStore && $shipToStoreShippingMethods.find('.input-radio').is(':checked')) { 16906 selectedStore = selectedStoreFromShippingMethod; 16907 $shippingAddressForm.find('.formfield.myStoreID input').val(selectedStore); 16908 setOPCAddress(shippingAddressFormSelector, 'dwfrm_shippingaddress_saveopcaddress').then(function (data) { }); 16909 } 16910 16911 buildShipToStoreDetails($shipToStoreShippingMethods); 16912 } 16913 16914 if (selectedStore && dataBuffer && dataBuffer['mystores_addressList']) { 16915 var selectedStoreInBuffer = dataBuffer['mystores_addressList'].filter(function (address) { 16916 return address.myStoreID == selectedStore; 16917 })[0]; 16918 16919 if (selectedStoreInBuffer && selectedStoreInBuffer.UUID != $('#mystores_addressList').val()) { 16920 $('#mystores_addressList').val(selectedStoreInBuffer.UUID); 16921 var shippingAddressType = getShippingAddressType(); 16922 if (shippingAddressType == SiteConstants.AddressTypes.Store) { 16923 $('#mystores_addressList').trigger('change'); 16924 doUpdateSummary = false; 16925 } 16926 } 16927 } 16928 $shippingMethodList.fadeIn('fast'); 16929 16930 if (doUpdateSummary) { 16931 updateSummary(); 16932 } 16933 16934 tooltip.init({ 16935 items: '.shipping-method-tooltip', 16936 tooltipClass: 'shipping-method-tooltip' 16937 }, $('[shipping-method]')); 16938 tooltip.init({ 16939 items: '.tooltip.RewardsCredit', 16940 tooltipClass: 'RewardsCredit' 16941 }, $('[payment-method="REWARDS_CREDIT"]')); 16942 tooltip.init({ 16943 items: '.tooltip.LoyaltyCredit', 16944 tooltipClass: 'LoyaltyCredit' 16945 }, $('[payment-method="LOYALTY_CREDIT"]')); 16946 tooltip.init({ 16947 items: '.tooltip' 16948 }, $('.form-row.cvn')); 16949 16950 var isStoreAddress = isShipToStoreEnabled(); 16951 setShipToStore(isStoreAddress); 16952 16953 if (doDataLayerPush) { 16954 pushDataLayerForShippingMethods($shippingMethodList, $selectedShippingMethod); 16955 } 16956 }); 16957} 16958 16959/** 16960 * @function 16961 * @description updates the order summary based on a possibly recalculated basket after a shipping promotion has been applied 16962 */ 16963function updateSummary() { 16964 $(document).trigger('Cart.Update', { 16965 'EventTriggers': { 16966 'update-shipping': false 16967 } 16968 }); 16969} 16970 16971function getShippingAddressType() { 16972 var shippingAddressType = $('.single.shipping-address-type-selector input:checked').val(); 16973 if (!shippingAddressType) { 16974 shippingAddressType = SiteConstants.AddressTypes.Customer; 16975 } 16976 return shippingAddressType; 16977} 16978 16979function renderMyStoresAddressSelector(parameters) { 16980 var templateSettings = { 16981 interpolate: /{{([\s\S]+?)}}/g 16982 }; 16983 16984 var templates = []; 16985 templates['option'] = _.template($('#template-address-selector-option').html(), templateSettings); 16986 16987 $.ajax({ 16988 method: 'POST', 16989 url: Urls.getMyStoresAddressList, 16990 contentType: 'application/json', 16991 data: JSON.stringify({ storeQuery: StoreQueryFilters.ShipToStoreEnabled }), 16992 dataType: 'json', 16993 success: function(data) { 16994 var html = []; 16995 html['options'] = ''; 16996 16997 dataBuffer['mystores_addressList'] = data.addresses; 16998 dataBuffer['store_name_lookup'] = {}; 16999 data.addresses.map(function (element) { 17000 dataBuffer['store_name_lookup'][element.myStoreID] = element.fullName; 17001 }); 17002 17003 var isStoreAddressSelected = false;
17004 for (var index = 0; index < data.addresses.length; index++) { 17005 var address = data.addresses[index]; 17006 17007 if (address.isSelected) { 17008 isStoreAddressSelected = true; 17009 } 17010 17011 var optionData = _.extend(address, { 17012 id: address.UUID, 17013 cssClass: '', 17014 selected: address.isSelected ? 'selected' : '', 17015 text: address.labelText 17016 }); 17017 17018 optionData.ID = address.myStoreID; 17019 html['options'] += templates['option'](optionData); 17020 } 17021 17022 $('#mystores_addressList').html(html['options']); 17023 17024 if (isStoreAddressSelected) { 17025 setShipToStore(true); 17026 $('.single.shipping-address-type-selector input[value="' + SiteConstants.AddressTypes.Store + '"]').click(); 17027 } 17028 17029 if (parameters && parameters.callback) { 17030 parameters.callback(); 17031 } 17032 } 17033 }); 17034} 17035 17036function renderAddressSelector(parameters) { 17037 var templateSettings = { 17038 interpolate: /{{([\s\S]+?)}}/g 17039 }; 17040 17041 var templates = []; 17042 templates['selector'] = _.template($('#template-address-selector').html(), templateSettings); 17043 templates['option'] = _.template($('#template-address-selector-option').html(), templateSettings); 17044 17045 $.ajax({ 17046 method: 'POST', 17047 url: Urls.getAddressList, 17048 contentType: 'application/json', 17049 data: JSON.stringify({ storeQuery: StoreQueryFilters.ShipToStoreEnabled }), 17050 dataType: 'json', 17051 success: function(data) { 17052 var html = []; 17053 var hasAddressBookAddresses = false; 17054 var selectedAddressID = null; 17055 17056 dataBuffer[parameters.id] = data.addresses; 17057 17058 var isAddressSelectedInData = false; 17059 for (var index = 0; index < data.addresses.length; index++) { 17060 var address = data.addresses[index]; 17061 17062 if (address.isSelected) { 17063 isAddressSelectedInData = true; 17064 selectedAddressID = address.ID; 17065 break; 17066 } 17067 } 17068 17069 html['options'] = ''; 17070 for (var index = 0; index < data.addresses.length; index++) { 17071 var address = data.addresses[index]; 17072 17073 if (address.isShippingAddress) { 17074 var addressId = address.key ? address.key : address.ID; 17075 var isSelected = false; 17076 17077 if (!$shippingAddressForm.find('input[name$="_address1"]').val() && $('[has-warehouse-shipment]').attr('has-warehouse-shipment') == 'true') { 17078 if (!isAddressSelectedInData) { 17079 if (!selectedAddressID && parameters.currentAddresses && parameters.currentAddresses.length > 0 && parameters.currentAddresses.indexOf(address.UUID) >= 0) { 17080 isSelected = true; 17081 selectedAddressID = address.ID; 17082 } else if (!selectedAddressID && parameters.selected && address.ID == parameters.selected && parameters.selected != "new") { 17083 isSelected = true; 17084 selectedAddressID = address.ID; 17085 } else if (!selectedAddressID && address.ID == $('#dwfrm_multipleshipping_addressList:visible option').val() && parameters.selected != "new") { 17086 isSelected = true; 17087 selectedAddressID = address.ID; 17088 } else if (!selectedAddressID && address.isDefault && parameters.selected != "new") { 17089 isSelected = true; 17090 selectedAddressID = address.ID; 17091 } 17092 } 17093 } 17094 17095 var optionData = _.extend(address, { 17096 id: address.UUID, 17097 cssClass: '', 17098 selected: isSelected || address.isSelected ? 'selected' : '', 17099 text: '(' + (!address.displayValue ? addressId : address.displayValue) + ') ' + address.labelText 17100 }); 17101 17102 if (!address.isMyStore) { 17103 hasAddressBookAddresses = true; 17104 } 17105 17106 html['options'] += templates['option'](optionData); 17107 } 17108 } 17109 17110 if (hasAddressBookAddresses) { 17111 html['selector'] = templates['selector']({ 17112 id: parameters.id, 17113 options: html['options'] 17114 }); 17115 17116 var $html = $(html['selector']); 17117 17118 if (isSelected || address.isSelected) { 17119 $html.find('option.placeholder').remove(); 17120 } 17121 17122 $(parameters.el).html($html); 17123 $(parameters.container).show(); 17124 } else { 17125 $(parameters.container).hide(); 17126 } 17127 17128 if (parameters && parameters.callback) { 17129 parameters.callback({ 17130 selectedAddressID: selectedAddressID, 17131 isSelected: isSelected, 17132 optionData: optionData 17133 }); 17134 } 17135 } 17136 }); 17137} 17138 17139function editBillingAddress() { 17140 $('.bill-address-fields').removeClass('collapsed').show(); 17141 $('.billing-select-address').hide(); 17142 17143 $('.billing-address-preview').hide(); 17144 $('.billing-address-data.form-info').hide(); 17145 17146 $billingAddressFormContainer.show(); 17147 $billingAddressForm.show(); 17148 17149 $shippingAddressFormContainer.data('hidden-editable', $('.shipping-address-data.form-info').html().length ? true : false).hide(); 17150 17151 $('.form-checkout.shipping-address-section').removeClass('active').find('.shipping-address-cont').addClass('hidden'); 17152 $('.form-checkout.payment-section').removeClass('active').find('.shipping-payment-cont').addClass('hidden'); 17153} 17154 17155function editShippingAddress() { 17156 writeShippingAddressFormToBuffer(); 17157 openShippingAddressForm(); 17158} 17159 17160function openShippingAddressForm() { 17161 $('.form-checkout.shipping-address-section').attr('panel-mode', 'edit'); 17162 $shippingAddressFormContainer.data('hidden-editable', true).hide(); 17163 $('.shipping-address-data').hide(); 17164 $shippingAddressFormContainer.show(); 17165 $shippingAddressForm.removeClass('add edit').addClass('edit'); 17166 $shippingAddressForm.find('input[name="action"]').val('edit'); 17167 17168 $billingAddressForm.hide(); 17169 $('.billing-address-data.form-info').css('display', 'block'); 17170 $('.form-checkout.payment-section').removeClass('active').find('.shipping-payment-cont').addClass('hidden'); 17171 17172 $('.shipping-select-address').hide(); 17173 $('.editaddress-shipping').removeClass('collapsed'); 17174} 17175 17176function setShipToStore(isStoreAddress) { 17177 $sectionCheckout.attr('is-my-store', isStoreAddress); 17178 $('#dwfrm_shippingaddress_isStore').prop('checked', isStoreAddress); 17179} 17180 17181function isShipToStoreEnabled() { 17182 return $('#dwfrm_shippingaddress_isStore').prop('checked'); 17183} 17184 17185function buildShipToStoreDetails($shippingMethods) { 17186 $shippingMethods.each(function(index, element) { 17187 var $shippingMethod = $(element); 17188 var $selectedStore = $shippingMethod.find('.store-selector option:checked'); 17189 var storeSelectorCount = $shippingMethod.find('.store-selector option').length; 17190 var storeData = $selectedStore.data('address'); 17191 if (storeData) { 17192 var storeHtml = ''; 17193 if (storeData.name) { 17194 storeHtml += '<p>' + storeData.name + '</p>'; 17195 } 17196 if (storeData.address1) { 17197 storeHtml += '<p>' + storeData.address1 + '</p>'; 17198 } 17199 if (storeData.address2) { 17200 storeHtml += '<p>' + storeData.address2 + '</p>'; 17201 } 17202 if (storeData.city || storeData.state || storeData.postalCode) { 17203 storeHtml += '<p>' + storeData.city + ', ' + storeData.state + ' ' + storeData.postalCode + '</p>'; 17204 } 17205 17206 if (storeSelectorCount > 1 && !isStoreShippingAddressOnly) { 17207 storeHtml += '<a class="action change" tabindex="0">Change Store</a>'; 17208 } 17209 17210 $shippingMethod.find('.store-details').html(storeHtml); 17211 } 17212 }); 17213} 17214 17215/** 17216 * @function 17217 * @description selects a shipping method for the default shipment and updates the summary section on the right hand side 17218 * @param 17219 */ 17220function selectShippingMethod(shipmentID, shippingMethodID, isShipToStore, $selectedShippingMethod) { 17221 var shippingAddressType = getShippingAddressType(); 17222 if (shippingAddressType == SiteConstants.AddressTypes.Customer) { 17223 dataBuffer[CheckoutConstants.User.SelectedCustomerShippingMethod] = shippingMethodID; 17224 } else if (shippingAddressType == SiteConstants.AddressTypes.Store) { 17225 dataBuffer[CheckoutConstants.User.SelectedStoreShippingMethod] = shippingMethodID; 17226 } 17227 17228 if (isShipToStore || isStoreShippingAddressOnly) { 17229 setShipToStore(true); 17230 } else { 17231 setShipToStore(false); 17232 } 17233 17234 // attempt to set shipping method 17235 var url = getShippingMethodURL($shippingAddressForm, Urls.selectShippingMethodsList, {shipmentID: shipmentID, shippingMethodID: shippingMethodID}); 17236 ajax.getJson({ 17237 url: url, 17238 callback: function (data) { 17239 // display promotion in UI and update the summary section, 17240 // if some promotions were applied 17241 $('.shippingpromotions').empty(); 17242 17243 $('[name*="_shippingMethodID"]').prop('disabled', false); 17244 updateShippingMethodList($shippingAddressForm, true, null, true, $selectedShippingMethod); 17245 } 17246 }); 17247} 17248 17249/** 17250 * @description Make the AJAX request to set address data 17251 * @param {Element} form The form element that present address object 17252 * @param {Element} Action name to apply to form 17253 * @returns {Promise} 17254 */ 17255var setOPCAddress = function (form, name, skipUseBillingAsShipping) { 17256 var $form = $(form); 17257 var url = (form == '#billingAddressForm') ? Urls.setOpcAddress : $form.attr('action'); 17258 var sanitizedFormData = {}; 17259 var serializedFormDataArray = $form.serializeArray(); 17260 var hasCountryField = false;
17261 for (var serializedFormDataKey in serializedFormDataArray) { 17262 var serializedFormElement = serializedFormDataArray[serializedFormDataKey]; 17263 if (skipUseBillingAsShipping && serializedFormElement.name == 'dwfrm_billingaddress_useAsShippingAddress') { 17264 sanitizedFormData[serializedFormElement.name] = false; 17265 } else if (skipUseBillingAsShipping && serializedFormElement.name == 'isShippingAddressSameAsBillingAddress') { 17266 sanitizedFormData[serializedFormElement.name] = 'off'; 17267 } else if (serializedFormElement && serializedFormElement.name && sanitizedFormData[serializedFormElement.name]) { 17268 sanitizedFormData[serializedFormElement.name] += ',' + serializedFormElement.value; 17269 } else { 17270 sanitizedFormData[serializedFormElement.name] = serializedFormElement.value; 17271 } 17272 if (serializedFormElement && serializedFormElement.name && serializedFormElement.name.indexOf('_country') < 0) { 17273 hasCountryField = true; 17274 } 17275 } 17276 if (hasCountryField) { 17277 var $countryField = $form.find('[name$="_country"]'); 17278 sanitizedFormData[$countryField.attr('name')] = $countryField.val(); 17279 } 17280 sanitizedFormData[name] = name; 17281 17282 return new Promise(function (resolve, reject) { 17283 $.ajax({ 17284 type: 'POST', 17285 url: util.ajaxUrl(url), 17286 data: sanitizedFormData, 17287 success: function(data) { 17288 resolve(data); 17289 }, 17290 error: function(data) { 17291 reject(data); 17292 } 17293 }); 17294 }); 17295}; 17296 17297function pushDataLayerForShippingMethods($shippingMethodList, $selectedShippingMethod) { 17298 var $selectedShippingMethods; 17299 if ($selectedShippingMethod) { 17300 $selectedShippingMethods = $selectedShippingMethod; 17301 } else { 17302 $selectedShippingMethods = $shippingMethodList.find('input[type="radio"]:checked'); 17303 } 17304 $selectedShippingMethods.each(function(index, element) { 17305 var $this = $(this); 17306 var $shippingMethod = $this.closest('[shipping-method]'); 17307 var dataObject = { 17308 value: parseFloat($shippingMethod.attr('amount')), 17309 shipping_tier: $shippingMethod.attr('shipping-method') 17310 } 17311 17312 GoogleTagManagerClient.PushDataLayerForDataLayerType('AddShippingInfo', dataObject, { ContainerSelector: '.order-item[shipment="' + $shippingMethod.closest('form').attr('shipment') + '"]' }).catch(function() {}); 17313 }); 17314} 17315 17316function handleShippingRestrictions(data) { 17317 $('.shipping-address-cont').find('> .error').remove(); 17318 var hasShippingRestrictions = data.status == 'shippingRestrictionsError'; 17319 if (hasShippingRestrictions) { 17320 openRestrictionsPopup(data); 17321 } 17322 17323 return hasShippingRestrictions; 17324} 17325 17326function openRestrictionsPopup(data) { 17327 var payload = JSON.parse(data.payload); 17328 var popup = require('../../popup'); 17329 17330 var restrictionList = ''; 17331 if (payload.list && payload.list.length > 0) { 17332 var list = $.map(payload.list, function (el) { 17333 var restrictionName = el.name ? el.name + ':<br/>' : ''; 17334 17335 return '<li>' + restrictionName + el.message + '</li>'; 17336 }).join(''); 17337 17338 restrictionList = '<ul class="shipping-restrictions-popup__list">' + list + '</ul>'; 17339 } 17340 17341 popup.init({ 17342 title: payload.title, 17343 content: payload.message + restrictionList 17344 }).showPopup(); 17345} 17346 17347function renderOptions(optionParent, optionsStoreId) { 17348 var optionsHtml; 17349 var optionsStoreOptions = $(optionsStoreId + ' option:selected').data('options'); 17350 var statesList; 17351 17352 if (optionsStoreOptions) { 17353 statesList = JSON.parse(optionsStoreOptions.replace(/\'/g, '\"')); 17354 17355 if (statesList.length > 1) { 17356 optionsHtml += '<option value="">' + Resources.SelectPlaceholder + '</option>'; 17357 } 17358 17359 statesList.forEach(function (state) { 17360 optionsHtml += '<option class="select-option" label="' + state.label + '" value="' + state.code + '">' + state.label + '</option>'; 17361 }); 17362 17363 var $optionParent = $(optionParent); 17364 $optionParent.empty().append(optionsHtml); 17365 17366 if (statesList.length <= 1) { 17367 $optionParent.prop('selectedIndex', statesList.length - 1); 17368 $optionParent.removeClass('required'); 17369 $optionParent.closest('.formfield').hide(); 17370 } else { 17371 $optionParent.addClass('required'); 17372 $optionParent.closest('.formfield').show(); 17373 } 17374 } 17375} 17376 17377$(document).on('update-shipping', function() { 17378 if ($('.shipping-methods-section').length == 0) { return; } 17379 updateShippingMethodList($shippingAddressForm); 17380}); 17381 17382exports.init = function (optionsParameter) { 17383 options = optionsParameter || {}; 17384 17385 if (options && options.Lob && options.Lob.AddressVerification.Enabled) { 17386 AddressVerificationDialog = require('../../Lob/AddressVerification/AddressVerificationDialog'); 17387 } 17388 17389 if (options && options.Lob && options.Lob.AddressAutocomplete.Enabled) { 17390 AddressAutocompleteDialog = require('../../Lob/AddressAutocomplete/AddressAutocompleteDialog'); 17391 } 17392 17393 isStoreShippingAddressOnly = !!(options && options.AgentStore && options.AgentStore.StoreShippingAddressOnly); 17394 if (isStoreShippingAddressOnly) { 17395 setShipToStore(true); 17396 } 17397 initializeEvents(); 17398 initializeUserInterface(); 17399}; 17400 17401exports.updateSummary = updateSummary; 17402},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper":112,"../../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants":113,"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../Lob/AddressAutocomplete/AddressAutocompleteDialog":1,"../../Lob/AddressVerification/AddressVerificationDialog":2,"../../ajax":3,"../../dialog":36,"../../findMoreStores":37,"../../popup":83,"../../tooltip":101,"../../util":102,"lodash":133,"promise":134}],65:[function(require,module,exports){ 17403'use strict'; 17404 17405var $errorBox = $('<div />', { 'id': 'errorBoxOPC', 'class': 'payment-declined p-2 mt-2', 'role': 'alert', 'tabindex': '0' }); 17406var $errorBoxIcon = $('<i />', { 'class': 'fa fa-exclamation-triangle', 'role': 'presentation' }); 17407var $errorBoxHeadline = $('<span />', { 'class': 'opc-error-box-headline' }); 17408var $errorBoxMessage = $('<span />', { 'class': 'opc-error-box-message' }); 17409 17410function getErrorMessage(fieldType) { 17411 var errorMessage; 17412 switch (true) { 17413 case (fieldType.indexOf('_loyaltyNumber') > -1): 17414 errorMessage = window.Resources.OPC_LOYALTY_NUMBER_ERROR; 17415 break; 17416 case (fieldType.indexOf('_loyaltyZipCode') > -1): 17417 errorMessage = window.Resources.OPC_LOYALTY_ZIP_ERROR; 17418 break; 17419 case (fieldType.indexOf('_loyaltyPhoneNumber') > -1): 17420 errorMessage = window.Resources.OPC_LOYALTY_PHONE_ERROR; 17421 break; 17422 case (fieldType.indexOf('_rewardsNumber') > -1): 17423 errorMessage = window.Resources.OPC_REWARDS_NUMBER_ERROR; 17424 break; 17425 case (fieldType.indexOf('_rewardsZipCode') > -1): 17426 errorMessage = window.Resources.OPC_REWARDS_ZIP_ERROR; 17427 break; 17428 case (fieldType.indexOf('_rewardsPhoneNumber') > -1): 17429 errorMessage = window.Resources.OPC_REWARDS_PHONE_ERROR; 17430 break; 17431 case (fieldType.indexOf('_giftCard_number') > -1): 17432 errorMessage = window.Resources.OPC_GIFT_CARD_ERROR; 17433 break; 17434 case (fieldType.indexOf('_giftCard_pin') > -1):
17435 errorMessage = window.Resources.OPC_GIFT_CARD_PIN_ERROR; 17436 break; 17437 case (fieldType.indexOf('_privateLabelCredit_number') > -1): 17438 errorMessage = window.Resources.OPC_PRIVATE_LABEL_ERROR; 17439 break; 17440 case (fieldType.indexOf('_creditCard_owner') > -1): 17441 errorMessage = window.Resources.OPC_CARD_OWNER_ERROR; 17442 break; 17443 case (fieldType.indexOf('_creditCard_number') > -1): 17444 errorMessage = window.Resources.OPC_CARD_NUMBER_ERROR; 17445 break; 17446 case (fieldType.indexOf('_creditCard_cvn') > -1): 17447 errorMessage = window.Resources.OPC_SECURITY_CODE_ERROR; 17448 break; 17449 case (fieldType.indexOf('_transactionalsms_smsPhone') > -1): 17450 errorMessage = window.Resources.TRANSACTIONAL_SMS_MISSING_ERROR; 17451 break; 17452 default: 17453 return; 17454 } 17455 return errorMessage; 17456} 17457 17458function getPaymentFormErrorMessages($form) { 17459 if (!$form || $form.length == 0 || $form.find('.field.error').length == 0) { 17460 return; 17461 } 17462 var errorsList = new Array(); 17463 $form.find('.field.error').each(function (index, element) { 17464 var errorMessage = getErrorMessage($(element).attr('name')); 17465 if (errorMessage) { 17466 errorsList.push(errorMessage); 17467 } 17468 }); 17469 return errorsList; 17470} 17471 17472function paymentErrorBox(headline, message, errorItems) { 17473 $errorBox.html(''); 17474 17475 if (!headline || !message) { 17476 return; 17477 } 17478 17479 $errorBoxHeadline.html(' ' + headline + ': '); 17480 $errorBoxMessage.html(message + ' '); 17481 $errorBox.append($errorBoxIcon).append($errorBoxHeadline).append($errorBoxMessage); 17482 17483 if (errorItems && errorItems.length > 0) { 17484 for (var i = 0; i < errorItems.length; i++) { 17485 var $newErrorItem = errorListItem(errorItems[i]); 17486 $errorBox.append($newErrorItem); 17487 } 17488 } 17489 17490 return $errorBox; 17491} 17492 17493function errorListItem(errorMsg) { 17494 var $errorListItem = $('<span />', { 'class': 'opc-error-box-item' }); 17495 $errorListItem.html(errorMsg + ' '); 17496 17497 return $errorListItem; 17498} 17499 17500exports.getErrorMessages = getPaymentFormErrorMessages; 17501exports.errorBox = paymentErrorBox; 17502},{}],66:[function(require,module,exports){ 17503'use strict'; 17504 17505var ajax = require('../../ajax'), 17506 formPrepare = require('./formPrepare'), 17507 progress = require('../../progress'), 17508 tooltip = require('../../tooltip'), 17509 util = require('../../util'); 17510 17511var shippingMethods; 17512/** 17513 * @function 17514 * @description Initializes gift message box, if shipment is gift 17515 */ 17516function giftMessageBox() { 17517 // show gift message box, if shipment is gift 17518 $('.gift-message-text').toggleClass('hidden', $('input[name$="_shippingAddress_isGift"]:checked').val() !== 'true'); 17519} 17520 17521/** 17522 * @function 17523 * @description updates the order summary based on a possibly recalculated basket after a shipping promotion has been applied 17524 */ 17525function updateSummary() { 17526 var $summary = $('#secondary.summary'); 17527 // indicate progress 17528 progress.show($summary); 17529 17530 // load the updated summary area 17531 $summary.load(Urls.summaryRefreshURL, function () { 17532 // hide edit shipping method link 17533 $summary.fadeIn('fast'); 17534 $summary.find('.checkout-mini-cart .minishipment .header a').hide(); 17535 $summary.find('.order-totals-table .order-shipping .label a').hide(); 17536 $(document).trigger('update-summary'); 17537 }); 17538} 17539 17540/** 17541 * @function 17542 * @description Helper method which constructs a URL for an AJAX request using the 17543 * entered address information as URL request parameters. 17544 */ 17545function getShippingMethodURL(url, extraParams) { 17546 var $form = $('.address'); 17547 var params = { 17548 address1: $form.find('input[name$="_address1"]').val(), 17549 address2: $form.find('input[name$="_address2"]').val(), 17550 address3: $form.find('input[name$="_address3"]').val(), 17551 countryCode: $form.find('select[id$="_country"]').val(), 17552 stateCode: $form.find('select[id$="_state"]').val(), 17553 postalCode: $form.find('input[name$="_postal"]').val(), 17554 city: $form.find('input[name$="_city"]').val() 17555 }; 17556 return util.appendParamsToUrl(url, $.extend(params, extraParams)); 17557} 17558 17559/** 17560 * @function 17561 * @description selects a shipping method for the default shipment and updates the summary section on the right hand side 17562 * @param 17563 */ 17564function selectShippingMethod(shippingMethodID) { 17565 // nothing entered 17566 if (!shippingMethodID) { 17567 return; 17568 } 17569 // attempt to set shipping method 17570 var url = getShippingMethodURL(Urls.selectShippingMethodsList, {shippingMethodID: shippingMethodID}); 17571 ajax.getJson({ 17572 url: url, 17573 callback: function (data) { 17574 updateSummary(); 17575 if (!data || !data.shippingMethodID) {
17576 window.alert('Couldn\'t select shipping method.'); 17577 return false; 17578 } 17579 // display promotion in UI and update the summary section, 17580 // if some promotions were applied 17581 $('.shippingpromotions').empty(); 17582 17583 // TODO the for loop below isn't doing anything? 17584 // if (data.shippingPriceAdjustments && data.shippingPriceAdjustments.length > 0) { 17585 // var len = data.shippingPriceAdjustments.length; 17586 // for (var i=0; i < len; i++) { 17587 // var spa = data.shippingPriceAdjustments[i]; 17588 // } 17589 // } 17590 } 17591 }); 17592} 17593 17594/** 17595 * @function 17596 * @description Make an AJAX request to the server to retrieve the list of applicable shipping methods 17597 * based on the merchandise in the cart and the currently entered shipping address 17598 * (the address may be only partially entered). If the list of applicable shipping methods 17599 * has changed because new address information has been entered, then issue another AJAX 17600 * request which updates the currently selected shipping method (if needed) and also updates 17601 * the UI. 17602 */ 17603function updateShippingMethodList() { 17604 var $shippingMethodList = $('#shipping-method-list'); 17605 if (!$shippingMethodList || $shippingMethodList.length === 0) { return; } 17606 var url = getShippingMethodURL(Urls.shippingMethodsJSON); 17607 17608 ajax.getJson({ 17609 url: url, 17610 callback: function (data) { 17611 if (!data) { 17612 window.alert('Couldn\'t get list of applicable shipping methods.'); 17613 return false; 17614 } 17615 if (shippingMethods && shippingMethods.toString() === data.toString()) { 17616 // No need to update the UI. The list has not changed. 17617 return true; 17618 } 17619 17620 // We need to update the UI. The list has changed. 17621 // Cache the array of returned shipping methods. 17622 shippingMethods = data; 17623 // indicate progress 17624 progress.show($shippingMethodList); 17625 17626 // load the shipping method form 17627 var smlUrl = getShippingMethodURL(Urls.shippingMethodsList); 17628 $shippingMethodList.load(smlUrl, function () { 17629 $shippingMethodList.fadeIn('fast'); 17630 // rebind the radio buttons onclick function to a handler. 17631 $shippingMethodList.find('[name$="_shippingMethodID"]').click(function () { 17632 selectShippingMethod($(this).val()); 17633 }); 17634 17635 // update the summary 17636 updateSummary(); 17637 progress.hide(); 17638 tooltip.init(); 17639 //if nothing is selected in the shipping methods select the first one 17640 if ($shippingMethodList.find('.input-radio:checked').length === 0) { 17641 $shippingMethodList.find('.input-radio:first').prop('checked', 'checked'); 17642 } 17643 }); 17644 } 17645 }); 17646} 17647 17648exports.init = function () { 17649 formPrepare.init({ 17650 continueSelector: '[name$="shippingAddress_save"]', 17651 formSelector:'[id$="singleshipping_shippingAddress"]' 17652 }); 17653 $('input[name$="_shippingAddress_isGift"]').on('click', giftMessageBox); 17654 17655 $('.address').on('change', 17656 'input[name$="_addressFields_address1"], input[name$="_addressFields_address2"], input[name$="_addressFields_address3"], select[name$="_addressFields_states_state"], input[name$="_addressFields_city"], input[name$="_addressFields_zip"]', 17657 updateShippingMethodList 17658 ); 17659 17660 giftMessageBox(); 17661 updateShippingMethodList(); 17662}; 17663 17664exports.updateShippingMethodList = updateShippingMethodList; 17665 17666},{"../../ajax":3,"../../progress":86,"../../tooltip":101,"../../util":102,"./formPrepare":61}],67:[function(require,module,exports){ 17667'use strict'; 17668 17669var _ = require('lodash'); 17670var AddressAutocompleteDialog; 17671var AddressVerificationDialog; 17672var AddressVerificationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper'); 17673var ApplePay = require('./checkout/ApplePay'); 17674var CheckoutConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants'); 17675var GiftCard = require('./checkout/GiftCardPaymentPanel'); 17676var loadingIndicator = require('../components/LoadingIndicator'); 17677var PaymentMethodConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').PaymentMethods; 17678var RewardsCredit = require('./checkout/RewardsCredit'); 17679var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 17680var TemplateConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 17681var tooltip = require('../tooltip'); 17682var TPromise = require('promise'); 17683var util = require('../util'); 17684var ValidationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 17685var ValidationRules = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 17686var ValidationSettings = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 17687 17688var checkoutFormSelector = '#checkout-form'; 17689var $checkoutForm = $(checkoutFormSelector); 17690var creditCardTypeListSelector = '.payment-card-list'; 17691var $creditCardTypeList = $(creditCardTypeListSelector); 17692var creditCardNumberInputSelector = '.formfield.card-number input'; 17693var $creditCardNumberInput = $(creditCardNumberInputSelector); 17694var creditCardExpirationMonthInputSelector = '.monthfield input'; 17695var $creditCardExpirationMonthInput = $(creditCardExpirationMonthInputSelector);
17696var creditCardExpirationYearInputSelector = '.yearfield input'; 17697var $creditCardExpirationYearInput = $(creditCardExpirationYearInputSelector); 17698var creditCardCVVInputSelector = '.form-row.cvn input'; 17699var $creditCardCVVInput = $(creditCardCVVInputSelector); 17700var addressInputSelector = '.formfield.address1 input'; 17701var $addressInput = $(addressInputSelector); 17702var submitPaymentSelector = '#submitOPCPayment'; 17703var $submitPayment = $(submitPaymentSelector); 17704var $rewardsAccordion = $('.rewards'); 17705var $rewardsPaymentContainer = $rewardsAccordion.find('[payment-method="REWARDS_CREDIT"]'); 17706var $rewardsForm = $rewardsPaymentContainer.find('.rewards-form'); 17707var $rewardsApplied = $rewardsPaymentContainer.find('.rewards-applied'); 17708 17709var options = {}; 17710var dataBuffer = {}; 17711 17712function initialize(options) { 17713 $.validator.addMethod('requiredExcludingPunctuation', ValidationHelper.ValidateRequiredExcludingPunctuation, Resources.INVALID_VALUE); 17714 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_ZIP_CODE); 17715 $.validator.addMethod('postalCode', ValidationHelper.ValidatePostalCode, Resources.INVALID_POSTAL_CODE); 17716 var checkoutFormValidator = $checkoutForm.validate(); 17717 checkoutFormValidator.settings.onfocusout = ValidationSettings.Checkout.onfocusout; 17718 checkoutFormValidator.settings.errorPlacement = ValidationSettings.Checkout.errorPlacement; 17719 if ($checkoutForm.find('select[name$="_country"]').val() == 'US') { 17720 $checkoutForm.find('input[name$="_postal"]').rules('add', ValidationRules.ZipCode); 17721 } else { 17722 $checkoutForm.find('input[name$="_postal"]').rules('add', ValidationRules.PostalCode); 17723 } 17724 17725 $(document).on('click', submitPaymentSelector, function(event) { 17726 event.preventDefault(); 17727 17728 var addressDeliverable = function () { 17729 submitPayment(); 17730 } 17731 17732 var addressNotDeliverable = function (addressVerifyData) { 17733 AddressVerificationDialog.initialize(options, 'billing', addressVerifyData); 17734 } 17735 17736 if (options && options.Lob && options.Lob.AddressVerification.Enabled) { 17737 AddressVerificationHelper.VerifyAddress($checkoutForm, options).then(addressDeliverable, addressNotDeliverable); 17738 } else { 17739 addressDeliverable(); 17740 } 17741 }); 17742 17743 if (options && options.Lob && options.Lob.AddressAutocomplete.Enabled) { 17744 $checkoutForm.off('keyup.AddressAutocomplete').on('keyup.AddressAutocomplete', 'input[type="text"]', function (event) { 17745 var $this = $(this); 17746 var $form = $this.closest('form'); 17747 var formValidator = $form.validate(); 17748 17749 if (event.keyCode == 8 || event.keyCode == 46) { 17750 $this.parent().find('.address-autocomplete-dialog').remove(); 17751 } else if (!formValidator.checkForm() && ($this.attr('id').indexOf('_address1') >= 0 || $this.attr('id').indexOf('_address2') >= 0)) { 17752 var addressAutocompleteHandler = function (addressAutocompleteData) { 17753 AddressAutocompleteDialog.initialize(options, addressAutocompleteData); 17754 } 17755 17756 AddressVerificationHelper.AutocompleteAddress($form, $this, options).then(addressAutocompleteHandler); 17757 } else { 17758 $this.parent().find('.address-autocomplete-dialog').remove(); 17759 } 17760 }); 17761 17762 $(document).off('SetAddressFromAddressAutocomplete').on('SetAddressFromAddressAutocomplete', function (event, data) { 17763 AddressVerificationHelper.SetAddressFromAddressVerificationDialog(data.$form, data.Address); 17764 $checkoutForm.find('#dwfrm_billing_billingAddress_email_emailAddress, input.phone, input.postal').trigger('blur.RewardsAccountSearch'); 17765 }); 17766 } 17767 17768 if (options && options.Lob && options.Lob.AddressVerification.Enabled) { 17769 $(document).off('SetAddressFromAddressVerification').on('SetAddressFromAddressVerification', function (event, addressData) { 17770 AddressVerificationHelper.SetAddressFromAddressVerificationDialog($checkoutForm, addressData); 17771 if (!addressData.DisableSubmitPayment) { 17772 submitPayment(); 17773 } 17774 }); 17775 } 17776 17777 $checkoutForm.off('blur.RewardsAccountSearch').on('blur.RewardsAccountSearch', '#dwfrm_billing_billingAddress_email_emailAddress, input.phone, input.postal', function(event) { 17778 if (dataBuffer['RewardsAccountSearchRequest'] && dataBuffer['RewardsAccountSearchRequest'].readyState !== 4) { 17779 dataBuffer['RewardsAccountSearchRequest'].abort(); 17780 dataBuffer['RewardsAccountSearchRequest'] = null; 17781 } 17782 17783 var $this = $(this); 17784 var field = $this.closest('[field]').attr('field'); 17785 var value = $this.val(); 17786 if (field && value) { 17787 if (!dataBuffer['RewardsData']) { 17788 dataBuffer['RewardsData'] = {}; 17789 } 17790 dataBuffer['RewardsData'][field] = value; 17791 17792 switch (field) { 17793 case 'emailAddress': 17794 $rewardsForm.find('#dwfrm_billing_rewards_rewardsEmail').val(value); 17795 break; 17796 case 'phone': 17797 $rewardsForm.find('.field.phonenumber').val(value); 17798 break; 17799 case 'postal': 17800 $rewardsForm.find('.field.zipcode').val(value); 17801 break; 17802 } 17803 17804 var isRewardsDataReady = dataBuffer['RewardsData']['emailAddress'] && dataBuffer['RewardsData']['phone'] && dataBuffer['RewardsData']['postal']; 17805 var isRewardsNumberFieldEmpty = !$rewardsForm.find('#dwfrm_billing_rewards_rewardsNumber').val();
17806 if (isRewardsDataReady && isRewardsNumberFieldEmpty) { 17807 var payload = { 17808 EmailAddress: dataBuffer['RewardsData']['emailAddress'], 17809 PhoneNumber: dataBuffer['RewardsData']['phone'], 17810 ZipCode: dataBuffer['RewardsData']['postal'], 17811 } 17812 17813 if ($rewardsForm.find('#dwfrm_billing_rewards_rewardsNumber').val()) { 17814 payload.RewardsNumber = $rewardsForm.find('#dwfrm_billing_rewards_rewardsNumber').val(); 17815 } 17816 17817 dataBuffer['RewardsAccountSearchRequest'] = $.ajax({ 17818 type: 'POST', 17819 url: Urls.searchForRewards, 17820 contentType: 'application/json', 17821 dataType: 'json', 17822 data: JSON.stringify(payload), 17823 success: function(data) { 17824 renderRewardsData(data); 17825 }, 17826 complete: function(xhr) { 17827 17828 } 17829 }); 17830 } 17831 } 17832 }); 17833 17834 $rewardsForm.off('keyup.RewardsReset change.RewardsReset').on('keyup.RewardsReset change.RewardsReset', 'input', function(event) { 17835 var isRewardsFormPopulated = false; 17836 $rewardsForm.find('input').each(function() { 17837 if ($(this).val()) { 17838 isRewardsFormPopulated = true; 17839 } 17840 }); 17841 if (isRewardsFormPopulated) { 17842 $rewardsForm.find('.btn.reset-echo').removeAttr('disabled'); 17843 } else { 17844 $rewardsForm.find('.btn.reset-echo').attr('disabled', 'true'); 17845 } 17846 }); 17847 17848 $rewardsForm.off('click.RewardsReset').on('click.RewardsReset', '.btn.reset-echo', function(event) { 17849 event.preventDefault(); 17850 17851 if ($rewardsApplied.find('.reward-row[status="applied"]').length > 0) { 17852 $rewardsApplied.find('.reward-row[status="applied"] .btn.remove').trigger('RewardsCredit.Remove', { ResetSessionData: true }); 17853 } else { 17854 $.ajax({ 17855 url: Urls.resetRewardsSessionData, 17856 type: 'POST' 17857 }); 17858 } 17859 $rewardsApplied.html(''); 17860 $rewardsForm.find('input').val(''); 17861 $rewardsForm.find('.btn.reset-echo').attr('disabled', 'true'); 17862 $rewardsForm.find('[match]').removeAttr('match'); 17863 $rewardsAccordion.removeAttr('rewards-found'); 17864 }); 17865 17866 $(document).off('RewardsAccountSearch').on('RewardsAccountSearch', function(event) { 17867 searchRewards(); 17868 }); 17869 17870 updateCart('dwfrm_cart_updateCart'); 17871 17872 $rewardsForm.off('click.RewardsAccountSearch').on('click.RewardsAccountSearch', '.btn.search-echo', function(event) { 17873 event.preventDefault(); 17874 searchRewards(); 17875 }); 17876 17877 $creditCardNumberInput.off('keydown.CreditCardNumberHandler').on('keydown.CreditCardNumberHandler', function(event) { 17878 $creditCardTypeList.val(''); 17879 }); 17880 17881 $creditCardNumberInput.off('keyup.CreditCardNumberHandler').on('keyup.CreditCardNumberHandler', function(event) { 17882 var $this = $(this); 17883 var creditCardNumber = $this.val(); 17884 17885 var selectedCard = util.getCreditCardType(creditCardNumber); 17886 if (selectedCard) { 17887 if ($creditCardNumberInput.filter(':visible').length < 1) { 17888 $creditCardNumberInput.val(creditCardNumber); 17889 } 17890 17891 $('input[name*="_creditCard_type"]').val(selectedCard.PaymentCard); 17892 $('input[name*="_selectedPaymentMethodID"]').val(selectedCard.PaymentMethod); 17893 $creditCardTypeList.find('input[type="radio"][value="' + selectedCard.PaymentCardDisplayKey + '"]').first().prop('checked', true).trigger('change', { doReset: false }); 17894 var $paymentCardImage = $creditCardTypeList.find('input[value="' + selectedCard.PaymentCardDisplayKey + '"]'); 17895 var paymentCardImageUrl; 17896 if ($paymentCardImage && $paymentCardImage.length > 0) { 17897 paymentCardImageUrl = $paymentCardImage.attr('payment-card-image'); 17898 } 17899 17900 if (paymentCardImageUrl) { 17901 $creditCardNumberInput.css('background-image', 'url(' + paymentCardImageUrl + ')'); 17902 } 17903 17904 if (creditCardNumber.length >= 16) { 17905 $creditCardExpirationMonthInput.focus(); 17906 } 17907 if (selectedCard.PaymentMethod == 'Alliance_Data') { 17908 $('.formfield.card-name').hide(); 17909 $('.formfield.card-name input').removeClass('required'); 17910 $('.card-expiration-and-cvn').addClass('number-only'); 17911 $('.card-expiration-and-cvn input').removeClass('required'); 17912 } 17913 } else { 17914 $creditCardTypeList.find('input').prop('checked', false); 17915 $creditCardTypeList.find('option').prop('selected', false); 17916 $creditCardNumberInput.css('background-image', ''); 17917 $('.formfield.card-name').show(); 17918 $('.formfield.card-name input').addClass('required'); 17919 $('.card-expiration-and-cvn').removeClass('number-only'); 17920 $('.card-expiration-and-cvn input').addClass('required'); 17921 } 17922 }); 17923
17924 $creditCardExpirationMonthInput.off('keydown.FieldBlock').on('keypress.FieldBlock', function(event) { 17925 if ($(this).val().length >= 2) { 17926 event.preventDefault(); 17927 event.stopPropagation(); 17928 } 17929 }); 17930 17931 $creditCardExpirationMonthInput.off('keyup.FieldShift').on('keyup.FieldShift', function(event) { 17932 if ($(this).val().length >= 2) { 17933 $creditCardExpirationYearInput.focus(); 17934 } 17935 }); 17936 17937 $creditCardExpirationYearInput.off('keydown.FieldBlock').on('keypress.FieldBlock', function(event) { 17938 if ($(this).val().length >= 2) { 17939 event.preventDefault(); 17940 event.stopPropagation(); 17941 } 17942 }); 17943 17944 $creditCardExpirationYearInput.off('keyup.FieldShift').on('keyup.FieldShift', function(event) { 17945 if ($(this).val().length >= 2) { 17946 $creditCardCVVInput.focus(); 17947 } 17948 }); 17949 17950 $creditCardCVVInput.off('keyup.FieldShift').on('keyup.FieldShift', function(event) { 17951 var cvvLength = $('input[name*="_creditCard_type"]').val() == 'Amex' ? 4 : 3; 17952 17953 if ($(this).val().length >= cvvLength) { 17954 $addressInput.focus(); 17955 } 17956 }); 17957 17958 $(document).on('click', '.accordion-head', function(event) { 17959 $(this).toggleClass('active'); 17960 }); 17961 17962 $(document).off('click', 'button[name$="addCoupon"]').on('click', 'button[name$="addCoupon"]', function (event) { 17963 event.preventDefault(); 17964 17965 var $this = $(this); 17966 var $container = $this.closest('.cart-coupon-code'); 17967 var $applyButton = $container.find('.btn-coupon-code'); 17968 $('.error.coupon-error').text(''); 17969 17970 (function() { 17971 $applyButton.loading({ 17972 IsLabelShown: false, 17973 BackgroundColor: 'transparent' 17974 }); 17975 17976 return TPromise.resolve($.ajax({ 17977 type: 'POST', 17978 url: util.ajaxUrl(Urls.onePageSubmit), 17979 data: { 17980 dwfrm_cart_addCoupon: 'dwfrm_cart_addCoupon', 17981 dwfrm_cart_couponCode: $('.accordion.coupon #dwfrm_cart_couponCode').val(), 17982 respType: 'json' 17983 } 17984 })); 17985 }()).then(function (response) { 17986 if (response.success && response.success !== CheckoutConstants.ResponseCodes.AlreadyInBasket) { 17987 $(document).trigger('Cart.Update'); 17988 } else { 17989 var message = response.success == CheckoutConstants.ResponseCodes.AlreadyInBasket ? Resources.COUPON_ADD_ERROR_DUP : Resources.COUPON_ADD_ERROR; 17990 $('<span/>', {'class': 'error coupon-error', 'text': message}).insertAfter('.accordion.coupon .cart-coupon-code .pcode-coupon'); 17991 if ($applyButton.attr('loading')) { 17992 $applyButton.loading('destroy'); 17993 } 17994 } 17995 }); 17996 }); 17997 17998 $(document).off('click', 'button[name$="deleteCoupon"]').on('click', 'button[name$="deleteCoupon"]', function (event) { 17999 event.preventDefault(); 18000 18001 var $this = $(this); 18002 var $container = $this.closest('.coupon'); 18003 var name = $this.attr('name'); 18004 (function(){ 18005 $container.loading({ 18006 IsLabelShown: false, 18007 BackgroundColor: 'transparent' 18008 }); 18009 18010 return TPromise.resolve($.ajax({ 18011 type: 'POST', 18012 url: util.ajaxUrl(Urls.onePageSubmit), 18013 data: $('form#cart-items-form').serialize() + '&' + name + '=' + name + '&respType=json' 18014 })); 18015 }()).then(function (response) { 18016 $(document).trigger('Cart.Update'); 18017 }); 18018 }); 18019 18020 $(document).off('click', '.order-total-payments [payment-method] .remove').on('click', '.order-total-payments [payment-method] .remove', function (e) { 18021 var paymentInstrumentUUID = $(e.currentTarget).closest('[payment-method').attr('uuid'); 18022 18023 if (paymentInstrumentUUID) { 18024 var requestPayload = { 18025 UUID: paymentInstrumentUUID 18026 } 18027 18028 $.ajax({ 18029 url: Urls.removePaymentInstrument, 18030 type: 'POST', 18031 contentType: 'application/json', 18032 data: JSON.stringify(requestPayload), 18033 dataType: 'json', 18034 success: function(data) { 18035 location.reload(); 18036 } 18037 }); 18038 } 18039 }); 18040 18041 $(document).on('change', '.formfield.country select', function (event) { 18042 var $this = $(this); 18043 var $country = $this.find('option:selected'); 18044 var country = $country.val(); 18045 var stateListData = $country.data('options'); 18046 var stateList; 18047 if (stateListData) { 18048 try { 18049 stateList = JSON.parse(stateListData.replace(/\'/g, '\"')); 18050 } catch (exception) { } 18051 18052 if (stateList) { 18053 var $form = $this.closest('fieldset'); 18054 var stateListHtml; 18055 var postalCodePlaceholder; 18056 if (country == 'US') { 18057 stateListHtml = '<option class="select-option" label="State" selected disabled>State</option>'; 18058 postalCodePlaceholder = 'ZIP Code'; 18059 $form.find('input[name$="_postal"]').rules('remove', 'postalCode zipCode'); 18060 $form.find('input[name$="_postal"]').rules('add', ValidationRules.ZipCode); 18061 } else if (country == 'CA') { 18062 stateListHtml = '<option class="select-option" label="Province" selected disabled>Province</option>'; 18063 postalCodePlaceholder = 'Postal Code'; 18064 $form.find('input[name$="_postal"]').rules('remove', 'postalCode zipCode'); 18065 $form.find('input[name$="_postal"]').rules('add', ValidationRules.PostalCode); 18066 } else { 18067 stateListHtml = '<option class="select-option" label="Province/State" selected disabled>Province/State</option>'; 18068 postalCodePlaceholder = 'Postal Code'; 18069 $form.find('input[name$="_postal"]').rules('remove', 'postalCode zipCode'); 18070 $form.find('input[name$="_postal"]').rules('add', ValidationRules.PostalCode); 18071 } 18072 for (var stateListKey in stateList) { 18073 var state = stateList[stateListKey]; 18074 stateListHtml += '<option class="select-option" label="' + state.label + '" value="' + state.code + '">' + state.label + '</option>'; 18075 } 18076 $form.find('.formfield.state select').html(stateListHtml); 18077 $form.find('.formfield.zip input').attr('placeholder', postalCodePlaceholder); 18078 } 18079 } 18080 }); 18081 18082 $(document).off('Cart.Update').on('Cart.Update', function (event, data) { 18083 updateCart('dwfrm_cart_updateCart', data); 18084 }); 18085 18086 searchRewards(); 18087 updateCart('dwfrm_cart_updateCart'); 18088} 18089 18090var updateCartBuffer; 18091var updateCartXmlHttpRequestBuffer; 18092function updateCart(triggerElementName, options, isCartPage) { 18093 if (updateCartXmlHttpRequestBuffer) {
18094 for (var updateCartXmlHttpRequestKey in updateCartXmlHttpRequestBuffer) { 18095 var updateCartXmlHttpRequest = updateCartXmlHttpRequestBuffer[updateCartXmlHttpRequestKey]; 18096 18097 if (updateCartXmlHttpRequest.readyState !== 4) { 18098 updateCartXmlHttpRequest.abort(); 18099 } 18100 } 18101 } 18102 updateCartXmlHttpRequestBuffer = []; 18103 updateCartBuffer = []; 18104 18105 getCartHtml(triggerElementName, options, isCartPage); 18106 if (!isCartPage) { 18107 getOrderSummaryCalloutHtml(triggerElementName, options, isCartPage); 18108 } 18109} 18110 18111function getCartHtml(triggerElementName, options, isCartPage) { 18112 var $form = $('#checkout-form'); 18113 updateCartBuffer['Cart'] = null; 18114 18115 updateCartXmlHttpRequestBuffer['getCartHtml'] = $.ajax({ 18116 url: Urls.onePageSubmit, 18117 type: "POST", 18118 data: triggerElementName + '=' + triggerElementName + '&selectedPaymentMethod=' + $('input[name*="_selectedPaymentMethodID"]').val() + '&format=ajax', 18119 success : function (data) { 18120 updateCartBuffer['Cart'] = data; 18121 getCartData(triggerElementName, options, isCartPage); 18122 updateCartRender(triggerElementName, options, isCartPage); 18123 } 18124 }); 18125} 18126 18127function getOrderSummaryCalloutHtml(triggerElementName, options, isCartPage) { 18128 updateCartBuffer['OrderSummaryCallout'] = null; 18129 18130 updateCartXmlHttpRequestBuffer['getOrderSummaryCalloutHtml'] = $.ajax({ 18131 url: Urls.getOrderSummaryCalloutContentSlot, 18132 dataType: 'html', 18133 success: function (data) { 18134 updateCartBuffer['OrderSummaryCallout'] = data; 18135 updateCartRender(triggerElementName, options, isCartPage); 18136 } 18137 }); 18138} 18139 18140function getCartData(triggerElementName, options, isCartPage) { 18141 updateCartBuffer['CartData'] = null; 18142 18143 updateCartXmlHttpRequestBuffer['getCartData'] = $.ajax({ 18144 url : Urls.getCartData, 18145 type : "POST", 18146 data: { 18147 isCart: isCartPage 18148 }, 18149 success : function (data) { 18150 $('[has-local-delivery-shipment]').attr('has-local-delivery-shipment', data.HasLocalDeliveryShipment || false); 18151 $('[has-physical-shipment]').attr('has-physical-shipment', data.HasPhysicalShipment || false); 18152 $('[has-warehouse-shipment]').attr('has-warehouse-shipment', data.HasWarehouseShipment || false); 18153 $('[has-warehouse-shipment]').attr('has-shipping-methods', data.ShippingMethods ? data.ShippingMethods.join(' ') : false); 18154 $('[has-subscription-products]').attr('has-subscription-products', data.HasSubscriptionProducts || false); 18155 $('[has-gift-cards]').attr('has-gift-cards', data.HasGiftCards || false); 18156 $('[has-gift-cards-only]').attr('has-gift-cards-only', data.HasGiftCardsOnly || false); 18157 $('[has-store-pickup-shipment]').attr('has-store-pickup-shipment', (data.Bopis && data.Bopis.HasStorePickupShipment) || false); 18158 $('[has-store-pickup-shipment-only]').attr('has-store-pickup-shipment-only', (data.Bopis && data.Bopis.HasStorePickupShipmentOnly) || false); 18159 $(document).trigger('CartData.Update', data); 18160 18161 updateCartBuffer['CartData'] = data; 18162 if (data.Bopis) { 18163 updateCartBuffer['Bopis'] = data.Bopis; 18164 } 18165 18166 if (!data.IsGlobaleValidOrInactive) { 18167 $('.section-checkout').addClass('global-e-validation-error'); 18168 $('.section-checkout').find('.cart-errors').addClass('active'); 18169 } else { 18170 $('.section-checkout').removeClass('global-e-validation-error'); 18171 $('.section-checkout').find('.cart-errors').removeClass('active'); 18172 } 18173 18174 if (data.ShippingRestrictions && data.ShippingRestrictions.Status == 'shippingRestrictionsError') { 18175 if (isCartPage) { 18176 $('.opclogin-buttons').addClass('hide'); 18177 } else { 18178 $('.payment-methods-section').hide(); 18179 } 18180 } else { 18181 if (isCartPage) { 18182 $('.opclogin-buttons').removeClass('hide'); 18183 $('.guest-checkout .error-form').remove(); 18184 } else { 18185 $('.payment-methods-section').show(); 18186 } 18187 } 18188 18189 handleOrderTotal(triggerElementName, options, isCartPage); 18190 } 18191 }); 18192} 18193 18194function handleOrderTotal(triggerElementName, options, isCartPage) { 18195 updateCartBuffer['PaymentInstrumentHtml'] = null; 18196 var removeAction = '<a class="remove">Remove</a>'; 18197 18198 if (updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length > 0) { 18199 updateCartBuffer['PaymentInstrumentHtml'] = ''; 18200 18201 for (var paymentInstrumentKey in updateCartBuffer['CartData'].OrderTotal.paymentInstruments) { 18202 var paymentInstrument = updateCartBuffer['CartData'].OrderTotal.paymentInstruments[paymentInstrumentKey]; 18203 var paymentInstrumentUUIDAttribute = 'uuid="' + paymentInstrument.UUID + '"'; 18204 18205 switch (paymentInstrument.paymentMethod.Id) { 18206 case PaymentMethodConstants.RewardsCredit: 18207 updateCartBuffer['PaymentInstrumentHtml'] += '<div ' + paymentInstrumentUUIDAttribute + ' payment-method="' + paymentInstrument.paymentMethod.Id + '" allow-remove="' + paymentInstrument.allowRemove + '">' + 18208 '<span class="label"><span class="name">B Rewarded</span> <span class="number">Reward</span></span>' + 18209 '<span class="value">' + paymentInstrument.amountDisplay + '</span>' + 18210 '</div>'; 18211 break; 18212 18213 default: 18214 updateCartBuffer['PaymentInstrumentHtml'] += '<div ' + paymentInstrumentUUIDAttribute + ' payment-method="' + paymentInstrument.paymentMethod.Id + '" allow-remove="' + paymentInstrument.allowRemove + '">' + 18215 '<span class="label"><span class="name">' + paymentInstrument.paymentMethod.Name + '</span> <span class="number">' + paymentInstrument.numberLastFour + '</span>' + removeAction + '</span>' + 18216 '<span class="value">' + paymentInstrument.amountDisplay + '</span>' + 18217 '</div>'; 18218 break; 18219 } 18220 } 18221 } else { 18222 $(document).trigger('GiftCard.Clear'); 18223 $(document).trigger('RewardsCredit.Clear'); 18224 } 18225 18226 if (updateCartBuffer['CartData'].OrderTotal.balance < updateCartBuffer['CartData'].OrderTotal.total) { 18227 updateCartBuffer['BalanceDueHtml'] = '<span class="label">Balance Due</span>' + 18228 '<span class="value">' + updateCartBuffer['CartData'].OrderTotal.balanceDisplay + '</span>'; 18229 } 18230 18231 updateCartRender(triggerElementName, options, isCartPage); 18232} 18233 18234function updateCartRender(triggerElementName, options, isCartPage) { 18235 if (updateCartBuffer['Cart'] && (isCartPage || (updateCartBuffer['OrderSummaryCallout'] && updateCartBuffer['CartData']))) { 18236 var $basketContainerHtml = $(updateCartBuffer['Cart']); 18237 18238 if (updateCartBuffer['CartData'] && updateCartBuffer['CartData'].OrderTotal) { 18239 $basketContainerHtml.find('.order-total-price .value').html(updateCartBuffer['CartData'].OrderTotal.totalDisplay); 18240 $('.payment-section .order-total-price .value').html(updateCartBuffer['CartData'].OrderTotal.totalDisplay); 18241 18242 if (updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length > 0) { 18243 $basketContainerHtml.find('.order-totals-table').attr('payments-applied', updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length); 18244 $('.payment-section').attr('payments-applied', updateCartBuffer['CartData'].OrderTotal.paymentInstruments.length); 18245 } else { 18246 $basketContainerHtml.find('.order-totals-table').removeAttr('payments-applied'); 18247 $('.payment-section').removeAttr('payments-applied'); 18248 } 18249 18250 $basketContainerHtml.find('.order-totals-table').attr('balance-due', updateCartBuffer['CartData'].OrderTotal.balance); 18251 $('#wrapper').attr('balance-due', updateCartBuffer['CartData'].OrderTotal.balance); 18252 $('.payment-section').attr('balance-due', updateCartBuffer['CartData'].OrderTotal.balance); 18253 18254 if (updateCartBuffer['CartData'].OrderTotal.balance > 0) { 18255 $('.payment-method-options').show(); 18256 $('.payment-section-footer[data-method="PayPal"] button').hide(); 18257 } else { 18258 $('.payment-method-options').hide(); 18259 $('.payment-section-footer[data-method="PayPal"] button').show(); 18260 } 18261 18262 if (updateCartBuffer['BalanceDueHtml']) { 18263 $basketContainerHtml.find('.order-balance-due').html(updateCartBuffer['BalanceDueHtml']); 18264 $('.payment-section .order-balance-due').html(updateCartBuffer['BalanceDueHtml']); 18265 } else { 18266 $('.payment-section .order-balance-due').html(''); 18267 } 18268 18269 if (updateCartBuffer['PaymentInstrumentHtml']) { 18270 $basketContainerHtml.find('.order-total-payments').html(updateCartBuffer['PaymentInstrumentHtml']); 18271 $('.payment-section .order-total-payments').html(updateCartBuffer['PaymentInstrumentHtml']); 18272 } else { 18273 $('.payment-section .order-total-payments').html(''); 18274 } 18275 } 18276 18277 $('.accordion.coupon .cart-coupon-code').html($basketContainerHtml.find('.cart
18277-coupon-code').first().html()); 18278 $('.basket-container').html($basketContainerHtml); 18279 18280 if (updateCartBuffer['CartData']) { 18281 var orderTotalForAffirm = updateCartBuffer['CartData'].OrderTotal.balance; 18282 if (!orderTotalForAffirm && updateCartBuffer['CartData'].OrderTotal.adjustedMerchandizeTotalPrice) { 18283 orderTotalForAffirm = updateCartBuffer['CartData'].OrderTotal.adjustedMerchandizeTotalPrice; 18284 } 18285 18286 if ('affirm' in window && 'ui' in affirm && 'refresh' in affirm.ui && orderTotalForAffirm >= updateCartBuffer['CartData'].AffirmMinimumOrderTotal) { 18287 $('.affirm-product-modal').attr('data-amount', orderTotalForAffirm * 100); 18288 affirm.ui.refresh(); 18289 } else { 18290 $('.affirm-product-modal').attr('data-amount', 5000); 18291 } 18292 } 18293 18294 if ($('.basket-container').find('.product-availability-list .not-available').length > 0) { 18295 $('#submitOPCPayment, #submitOPCPaymentPrivateLabel').attr('disabled', 'disabled'); 18296 $('#errorBoxOPC').remove(); 18297 $('#submitOPCPayment').after('<div id="errorBoxOPC" class="p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>' + Resources.Validation.Messages.Products.Availability + ':</b> ' + Resources.Validation.Messages.Products.AvailabilityExceeded + '</div>'); 18298 } else if (updateCartBuffer['Bopis'] && updateCartBuffer['Bopis'].NumberOfBopisStoresInCart > updateCartBuffer['Bopis'].MaximumNumberOfBopisStoresInCart) { 18299 $('#submitOPCPayment, #submitOPCPaymentPrivateLabel').attr('disabled', 'disabled'); 18300 $('#errorBoxOPC').remove(); 18301 $('#submitOPCPayment').after('<div id="errorBoxOPC" class="p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>' + Resources.Validation.Messages.General.CartLimit + ':</b> ' + Resources.Validation.Messages.Bopis.MaximumStoresExceeded + '</div>'); 18302 } else { 18303 $('#submitOPCPayment, #submitOPCPaymentPrivateLabel').removeAttr('disabled'); 18304 $('#errorBoxOPC').remove(); 18305 } 18306 18307 if (updateCartBuffer['OrderSummaryCallout']) { 18308 $('.callout-ordersummary').html(updateCartBuffer['OrderSummaryCallout']); 18309 } 18310 18311 if ($('.banner-cart-holder .btn-minicart').length > 0) { 18312 $.ajax({url : Urls.cartMiniCart, data : {desktop: '1'}, dataType: 'html', success : function(data) { 18313 $('.banner-cart-holder').html(data); 18314 }}); 18315 18316 $.ajax({url : Urls.cartMiniCart, dataType: 'html', success : function(data) { 18317 var parentMiniCart = $(".top-banner-inner-links #mini-cart"); 18318 18319 if (parentMiniCart.length > 0) { 18320 parentMiniCart.html(data); 18321 } 18322 }}); 18323 } 18324 18325 $.ajax({url: Urls.cartItemQuantity, data: {desktop: '1'}, dataType: 'html', success: function (data) { 18326 $('.confirmation-message .item-count').html(data); 18327 18328 var quantity = parseInt($('.confirmation-message .item-count').find('span').text(), 10); 18329 if (!quantity) { 18330 $('.checkout-buttons.mobile-only').hide(); 18331 } 18332 }}); 18333 18334 18335 if (triggerElementName.indexOf('deleteProduct') > -1) { 18336 $(document).trigger('refresh-required'); 18337 } 18338 18339 if (!options || !options.EventTriggers || options.EventTriggers['update-summary']) { 18340 $(document).trigger('update-summary'); 18341 } 18342 18343 if (!options || !options.EventTriggers || options.EventTriggers['update-shipping']) { 18344 $(document).trigger('update-shipping'); 18345 } 18346 18347 $('[minimum-cart-total], [maximum-cart-total]').each(function(index, element) { 18348 var $this = $(this); 18349 var paymentMethodCartTotalMinimum = parseFloat($this.attr('minimum-cart-total')); 18350 var paymentMethodCartTotalMaximum = parseFloat($this.attr('maximum-cart-total')); 18351 18352 var isCartTotalMinimumValid = false; 18353 if (isNaN(paymentMethodCartTotalMinimum) || updateCartBuffer['CartData'].OrderTotal.balance >= paymentMethodCartTotalMinimum) { 18354 isCartTotalMinimumValid = true; 18355 } 18356 18357 var isCartTotalMaximumValid = false; 18358 if (isNaN(paymentMethodCartTotalMaximum) || updateCartBuffer['CartData'].OrderTotal.balance <= paymentMethodCartTotalMaximum) { 18359 isCartTotalMaximumValid = true; 18360 } 18361 18362 if (isCartTotalMinimumValid && isCartTotalMaximumValid) { 18363 $this.closest('.payment-method-option').attr('valid-for-balance-due', 'true'); 18364 } else { 18365 $this.closest('.payment-method-option').attr('valid-for-balance-due', 'false'); 18366 } 18367 }); 18368 18369 if (updateCartBuffer['CartData'] && !updateCartBuffer['CartData'].HasPhysicalShipment && $('.single.shipping-address-type-selector input
18369:checked').val() != SiteConstants.AddressTypes.Customer) { 18370 $('.single.shipping-address-type-selector input[value="' + SiteConstants.AddressTypes.Customer + '"]').click(); 18371 } 18372 18373 tooltip.init({ 18374 items: '.shipping-method-tooltip', 18375 tooltipClass: 'shipping-method-tooltip' 18376 }, $('[shipping-method]')); 18377 18378 tooltip.init({ 18379 items: '.tooltip' 18380 }); 18381 18382 triggerSrFocus(); 18383 $(document).trigger('QuantityStepper.TargetFocus'); 18384 $(document).trigger('Cart.UpdateSuccess'); 18385 } 18386} 18387 18388function triggerSrFocus() { 18389 $('[role="alert"]').last().focus(); 18390} 18391 18392function submitPayment(data) { 18393 $submitPayment.loading({ 18394 IsImageShown: false, 18395 Label: Resources.Loading.Checkout.PlacingOrder 18396 }); 18397 $submitPayment.attr('disabled', true); 18398 $('#errorBoxOPC').remove(); 18399 18400 $checkoutForm.validate().form(); 18401 18402 if ($checkoutForm.valid()) { 18403 setOPCPaymentData($checkoutForm, $submitPayment.attr('name')).then(function(response) { 18404 var data; 18405 try { 18406 data = JSON.parse(response); 18407 } catch (e) { 18408 data = response; 18409 } 18410 18411 if (data.hasOwnProperty('status') && data.status === 'success') { 18412 window.location.href = Urls.confirmationPage; 18413 } else if (data.hasOwnProperty('status') && data.status === 'affirmRedirect') { 18414 var _affirm_config = { 18415 public_api_key: data.affirm.PublicApiKey, 18416 script: data.affirm.Script 18417 }; 18418 (function(l,g,m,e,a,f,b){var d,c=l[m]||{},h=document.createElement(f),n=document.getElementsByTagName(f)[0],k=function(a,b,c){return function(){a[b]._.push([c,arguments])}};c[e]=k(c,e,"set");d=c[e];c[a]={};c[a]._=[];d._=[];c[a][b]=k(c,a,b);a=0;for(b="set add save post open empty reset on off trigger ready setProduct".split(" ");a<b.length;a++)d[b[a]]=k(c,e,b[a]);a=0;for(b=["get","token","url","items"];a<b.length;a++)d[b[a]]=function(){};h.async=!0;h.src=g[f];n.parentNode.insertBefore(h,n);delete g[f];d(g);l[m]=c})(window,_affirm_config,"affirm","checkout","ui","script","ready"); 18419 18420 affirm.checkout(JSON.parse(data.affirm.AffirmCheckout)); 18421 affirm.checkout.post(); 18422 affirm.ui.ready( 18423 function() { 18424 affirm.ui.error.on("close", function(){ 18425 // window.location.replace(data.affirm.RedirectUrl); 18426 }); 18427 } 18428 ); 18429 } else if (data.hasOwnProperty('status') && data.status === 'shippingRestrictionsError'){ 18430 var popup = require('../popup'); 18431 var payload = JSON.parse(data.payload); 18432 18433 var list = $.map(payload.list, function (el) { 18434 return '<li>' + el.name + ':<br>' + el.message + '</li>'; 18435 }).join(''); 18436 18437 popup.init({ 18438 title: payload.title, 18439 content: payload.message + '<ul class="shipping-restrictions-popup__list">' + list + '</ul>', 18440 }).showPopup(); 18441 } else if (data.hasOwnProperty('status') && data.status === 'ValidationError') { 18442 var message = data.hasOwnProperty('message') ? data.message : Resources.Checkout.Confirm.Error.Generic; 18443 $submitPayment.after('<div id="errorBoxOPC" class="payment-declined p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>Validation Error:</b> ' + message + '</div>'); 18444 } else { 18445 var message = data.hasOwnProperty('message') ? data.message : Resources.Checkout.Confirm.Error.Generic; 18446 $submitPayment.after('<div id="errorBoxOPC" class="payment-declined p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>Payment Declined:</b> ' + message + '</div>'); 18447 } 18448 18449 $submitPayment.loading('destroy'); 18450 $submitPayment.attr('disabled', false); 18451 }).catch(function(response) { 18452 if (response.status == 302 && response.responseText) { 18453 location.href = response.responseText; 18454 } 18455 }); 18456 } else { 18457 $submitPayment.loading('destroy'); 18458 $submitPayment.attr('disabled', false); 18459 } 18460} 18461 18462var setOPCPaymentData = function ($form, name) { 18463 var payload = $form.serialize() + '&' + name + '=' + name; 18464 var $checkoutVariables = $('.button-and-terms input[type="hidden"]'); 18465 $checkoutVariables.each(function() { 18466 var $this = $(this); 18467 payload += '&' + $this.attr('name') + '=' + $this.val(); 18468 }); 18469 18470 return TPromise.resolve($.ajax({ 18471 type: 'POST', 18472 url: util.ajaxUrl(Urls.setOpcAddress), 18473 data: payload 18474 })); 18475}; 18476 18477function searchRewards() { 18478 if (dataBuffer['RewardsAccountSearchRequest'] && dataBuffer['RewardsAccountSearchRequest'].readyState !== 4) { 18479 dataBuffer['RewardsAccountSearchRequest'].abort(); 18480 dataBuffer['RewardsAccountSearchRequest'] = null; 18481 } 18482 $rewardsApplied.html(''); 18483 18484 var payload = { 18485 EmailAddress: $rewardsForm.find('#dwfrm_billing_rewards_rewardsEmail').val(), 18486 PhoneNumber: $rewardsForm.find('.field.phonenumber').val(), 18487 ZipCode: $rewardsForm.find('.field.zipcode').val(), 18488 } 18489 18490 if ($rewardsForm.find('#dwfrm_billing_rewards_rewardsNumber').val()) { 18491 payload.RewardsNumber = $rewardsForm.find('#dwfrm_billing_rewards_rewardsNumber').val(); 18492 } 18493 18494 $('.btn.search-echo').loading({ 18495 IsLabelShown: false,
18496 BackgroundColor: 'transparent' 18497 }); 18498 18499 dataBuffer['RewardsAccountSearchRequest'] = $.ajax({ 18500 type: 'POST', 18501 url: Urls.searchForRewards, 18502 contentType: 'application/json', 18503 dataType: 'json', 18504 data: JSON.stringify(payload), 18505 success: function(data) { 18506 renderRewardsData(data); 18507 }, 18508 complete: function(xhr) { 18509 if ($('.btn.search-echo').attr('loading')) { 18510 $('.btn.search-echo').loading('destroy'); 18511 } 18512 } 18513 }); 18514} 18515 18516function renderRewardsData(data) { 18517 if (data.Match && data.Rewards) { 18518 if (data.Rewards.rewardsNumber) { 18519 $rewardsForm.find('#dwfrm_billing_rewards_rewardsNumber').val(data.Rewards.rewardsNumber); 18520 } else { 18521 $rewardsForm.find('#dwfrm_billing_rewards_rewardsNumber').val(''); 18522 } 18523 if (data.Rewards.email) { 18524 $rewardsForm.find('#dwfrm_billing_rewards_rewardsEmail').val(data.Rewards.email); 18525 } else { 18526 $rewardsForm.find('#dwfrm_billing_rewards_rewardsEmail').val(''); 18527 } 18528 if (data.Rewards.phone) { 18529 $rewardsForm.find('.field.phonenumber').val(data.Rewards.phone); 18530 } else { 18531 $rewardsForm.find('.field.phonenumber').val(''); 18532 } 18533 if (data.Rewards.zipValue) { 18534 $rewardsForm.find('.field.zipcode').val(data.Rewards.zipValue); 18535 } else { 18536 $rewardsForm.find('.field.zipcode').val(''); 18537 } 18538 18539 if (data.Match.RewardsEmail) { 18540 $rewardsForm.find('.rewards-email-container').attr('match', 'true'); 18541 } else { 18542 $rewardsForm.find('.rewards-email-container').attr('match', 'false'); 18543 } 18544 if (data.Match.RewardsPhone) { 18545 $rewardsForm.find('.input-container.phone').attr('match', 'true'); 18546 } else { 18547 $rewardsForm.find('.input-container.phone').attr('match', 'false'); 18548 } 18549 if (data.Match.RewardsZip) { 18550 $rewardsForm.find('.input-container.zip').attr('match', 'true'); 18551 } else { 18552 $rewardsForm.find('.input-container.zip').attr('match', 'false'); 18553 } 18554 18555 var rewardsRowTemplate = _.template($('#template-rewards-credit-row-echo').html(), TemplateConstants.Lodash.Settings); 18556 var status = ''; 18557 var message = ''; 18558 if (parseFloat(data.Rewards.creditAmount) <= 0) { 18559 status = 'message'; 18560 message = 'no rewards available'; 18561 } else if ($rewardsForm.closest('[is-applied]').attr('is-applied') == 'true') { 18562 status = 'applied'; 18563 } else { 18564 status = 'pending'; 18565 } 18566 18567 var additionalData = '<table class="rewards-information">' + 18568 '<tr><td>Address</td><td>' + data.Rewards.address + '</td></tr>' + 18569 '<tr><td>City</td><td>' + data.Rewards.city + '</td></tr>' + 18570 '<tr><td>State</td><td>' + data.Rewards.state + '</td></tr>' + 18571 '<tr><td>Zip</td><td>' + data.Rewards.zipValue + '</td></tr>' + 18572 '<tr><td>Country</td><td>' + data.Rewards.country + '</td></tr>' + 18573 '<tr><td>Phone</td><td>' + data.Rewards.phone + '</td></tr>' + 18574 (data.Rewards.rewardsStatus ? '<tr><td>Rewards Status</td><td>' + data.Rewards.rewardsStatus.charAt(0).toUpperCase() + data.Rewards.rewardsStatus.slice(1) + '</td></tr>' : '') + 18575 '</table><table class="rewards-points">' + 18576 '<tr><td>Points</td><td>' + data.Rewards.pointBalance + '</td></tr>' + 18577 '</table>'; 18578 18579 $rewardsApplied.html(rewardsRowTemplate({ 18580 Status: status, 18581 RewardsNumber: data.Rewards.rewardsNumber, 18582 Name: data.Rewards.fullName, 18583 Email: data.Rewards.email, 18584 RewardsAvailable: data.Rewards.creditAmountFormatted.replace('.00', ''), 18585 RewardsExpirationDate: data.Rewards.creditExpirationDate || 'n/a', 18586 Message: message, 18587 AdditionalData: additionalData 18588 })); 18589 if ($rewardsAccordion.find('header .rewards-points').length) { 18590 $rewardsAccordion.find('header .rewards-points').text(data.Rewards.pointBalance); 18591 } 18592 18593 $rewardsAccordion.attr('rewards-found', 'true'); 18594 $rewardsForm.find('.btn.reset-echo').removeAttr('disabled'); 18595 if (!$('.accordion.rewards .accordion-head').hasClass('active')) { 18596 $('.accordion.rewards .accordion-head').addClass('active'); 18597 } 18598 } else { 18599 $rewardsAccordion.removeAttr('rewards-found'); 18600 $rewardsApplied.html('<p class="no-results">no rewards found</p>'); 18601 } 18602} 18603 18604exports.init = function (optionsParameter) { 18605 options = optionsParameter; 18606 18607 if (options && options.Lob && options.Lob.AddressVerification.Enabled) { 18608 AddressVerificationDialog = require('../../../../app_storefront_core/cartridge/js/Lob/AddressVerification/AddressVerificationDialog'); 18609 } 18610 18611 if (options && options.Lob && options.Lob.AddressAutocomplete.Enabled) { 18612 AddressAutocompleteDialog = require('../../../../app_storefront_core/cartridge/js/Lob/AddressAutocomplete/AddressAutocompleteDialog'); 18613 } 18614 18615 GiftCard.initialize($.extend({ LoadingIndicator: { 18616 IsLabelShown: false,
18617 BackgroundColor: 'transparent' 18618 }}, options)); 18619 18620 RewardsCredit.initialize($.extend({ LoadingIndicator: { 18621 IsLabelShown: false, 18622 BackgroundColor: 'transparent' 18623 }}, options)); 18624 18625 ApplePay.initialize(options); 18626 18627 initialize(options); 18628}; 18629},{"../../../../app_storefront_core/cartridge/js/Lob/AddressAutocomplete/AddressAutocompleteDialog":1,"../../../../app_storefront_core/cartridge/js/Lob/AddressVerification/AddressVerificationDialog":2,"../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper":112,"../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants":113,"../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants":117,"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../components/LoadingIndicator":25,"../popup":83,"../tooltip":101,"../util":102,"./checkout/ApplePay":53,"./checkout/GiftCardPaymentPanel":54,"./checkout/RewardsCredit":57,"lodash":133,"promise":134}],68:[function(require,module,exports){ 18630'use strict'; 18631 18632var addProductToCart = require('./product/addToCart'), 18633 ajax = require('../ajax'), 18634 page = require('../page'), 18635 productTile = require('../product-tile'), 18636 quickview = require('../quickview'); 18637 18638/** 18639 * @private 18640 * @function 18641 * @description Binds the click events to the remove-link and quick-view button 18642 */ 18643function initializeEvents() { 18644 $('#compare-table').on('click', '.remove-link', function (e) { 18645 e.preventDefault(); 18646 ajax.getJson({ 18647 url: this.href, 18648 callback: function () { 18649 page.refresh(); 18650 } 18651 }); 18652 }) 18653 .on('click', '.open-quick-view', function (e) { 18654 e.preventDefault(); 18655 var url = $(this).closest('.product').find('.thumb-link').attr('href'); 18656 quickview.show({ 18657 url: url, 18658 source: 'quickview' 18659 }); 18660 }); 18661 18662 $('#compare-category-list').on('change', function () { 18663 $(this).closest('form').submit(); 18664 }); 18665} 18666 18667exports.init = function () { 18668 productTile.init(); 18669 initializeEvents(); 18670 addProductToCart(); 18671}; 18672 18673},{"../ajax":3,"../page":46,"../product-tile":84,"../quickview":88,"./product/addToCart":72}],69:[function(require,module,exports){ 18674'use strict'; 18675 18676var util = require('../util'); 18677var page = require('../page'); 18678var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 18679 18680function initializeEvents(){ 18681}; 18682 18683exports.init = function () { 18684 initializeEvents(); 18685}; 18686 18687},{"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../page":46,"../util":102}],70:[function(require,module,exports){ 18688'use strict'; 18689 18690var quickview = require('../quickview'); 18691var bonusProductsView = require('../bonus-products-view'); 18692var TPromise = require('promise'); 18693var util = require('../util'); 18694var addresses = require('./checkout/opcaddress'); 18695var formPrepare = require('./checkout/formPrepare'); 18696var cart = require('./cart'); 18697var opcpayment = require('./checkout/opcpayment'); 18698var loadingIndicator = require('../components/LoadingIndicator'); 18699var GiftCard = require('./checkout/GiftCardPaymentPanel'); 18700var GoogleTagManagerClient = require('../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 18701var PaymentVoucherPaymentPanel; 18702var WorkforceVoucherPaymentPanel; 18703var recaptcha = require('../components/Recaptcha'); 18704var RewardsCredit = require('./checkout/RewardsCredit'); 18705var LoyaltyCredit = require('./checkout/LoyaltyCredit'); 18706var CheckoutConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants'); 18707var PaymentMethodConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').PaymentMethods; 18708var BopisProductLineItemHelper = require('../bopis/components/ProductLineItemHelper'); 18709var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 18710 18711var cartItemsFormSelector = 'form#cart-items-form'; 18712var billingAddressFormSelector = '#billingAddressForm'; 18713var $billingAddressForm = $(billingAddressFormSelector); 18714var shippingAddressFormSelector = '#shippingAddressForm'; 18715var $shippingAddressForm = $(shippingAddressFormSelector); 18716var paymentSectionSelector = '.form-checkout.payment-section'; 18717var $paymentSection = $(paymentSectionSelector); 18718var paymentFormSelector = '#paymentSection'; 18719var $paymentForm = $(paymentFormSelector); 18720var creditCardSaveCheckboxContainerSelector = 'div[field="saveCard"]'; 18721var $creditCardSaveCheckboxContainer = $(creditCardSaveCheckboxContainerSelector); 18722var creditCardSaveCheckboxSelector = '#dwfrm_billing_paymentMethods_credit
18722Card_saveCard'; 18723var $creditCardSaveCheckbox = $(creditCardSaveCheckboxSelector); 18724var submitPaymentSelector = '#submitOPCPayment'; 18725var $submitPayment = $(submitPaymentSelector); 18726var basketContainerSelector = '.basket-container'; 18727var $basketContainer = $(basketContainerSelector); 18728 18729var placeOrderRecaptcha; 18730var options = {}; 18731var loaded = {}; 18732 18733// Credit Card inputs & formatting 18734var creditCardListSelector = '.payment-card-list select, .payment-card-list input[type="radio"]'; 18735var $creditCardList = $(creditCardListSelector); 18736var savedCreditCardListSelector = '#creditCardList'; 18737var $savedCreditCardList = $(savedCreditCardListSelector); 18738var privateLabelCardNumberInputSelector = 'input[name*="_privateLabelCredit_number"]'; 18739var creditCardNumberInputSelector = 'input[name*="_creditCard_number"]'; 18740var $creditCardNumberInput = $(creditCardNumberInputSelector); 18741var $creditCardImage = $('<div />', { 'class': 'cc-image' }); 18742 18743/** 18744 * @description Events should be divided to modules. This allows reinitialize events by sections after partial reload 18745 * @private 18746 * @function 18747 * @description Initializes events for the gift registration 18748 */ 18749function initializeEvents(options) { 18750 initializeCartEvents(options); 18751 initializePaymentMethodsEvents(); 18752 initializeCheckoutEvents(); 18753 18754 renderRecaptcha(); 18755 $(document).on('Recaptcha.Loaded', function(event) { 18756 if (!loaded.Recaptcha) { 18757 loaded.Recaptcha = true; 18758 renderRecaptcha(); 18759 } 18760 }); 18761} 18762 18763function initializeCartEvents(options) { 18764 $(document).on('click', 'a.add-to-wishlist', function (e) { 18765 /*remove next line to use default dw wishlist functionality*/ 18766 return false; 18767 e.preventDefault(); 18768 18769 if (Customer.authenticated == true) { 18770 // post form here 18771 } else { 18772 $('html, body').animate({ scrollTop: $('.login-form').eq(0).offset().top}, 1000); 18773 } 18774 }); 18775 18776 if (SitePreferences.ALTERNATE_PICKUP_ENABLED) { 18777 renderAlternatePickup(); 18778 } 18779 18780 $paymentForm.on('change', '[name$="_creditCard_type"]', function() { 18781 $submitPayment.removeAttr('disabled'); 18782 $(this).closest('div.form-row').find('div.field-wrapper.error').remove(); 18783 }); 18784 18785 $(document).on('click', submitPaymentSelector, function(e) { 18786 e.preventDefault(); 18787 18788 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForPlaceOrder) { 18789 submitPayment(); 18790 } 18791 }); 18792 18793 $(document).on('Checkout.SubmitPayment', function (event, data) { 18794 if ((options && options.Recaptcha && options.Recaptcha.EnabledForPlaceOrder) || (data && data.SubmitPaymentForBopis)) { 18795 submitPayment(data); 18796 } 18797 }); 18798 18799 var getCreditCardInfo = function (id) { 18800 return TPromise.resolve($.ajax({ 18801 type: 'GET', 18802 url: util.ajaxUrl(Urls.billingGetCreditCard), 18803 data: { creditCardUUID: id } 18804 })); 18805 }; 18806 18807 $(document).on('change', savedCreditCardListSelector, function() { 18808 var creditCardUUID = $(this).val(); 18809 18810 if (creditCardUUID.length <= 0) { 18811 return; 18812 } 18813 18814 getCreditCardInfo(creditCardUUID).then(function (data) { 18815 if (data && data.hasOwnProperty('maskedNumber')) { 18816 var $paymentMethodGroup = $('[payment-method-group="' + PaymentMethodConstants.CreditCard + '"]'); 18817 var $paymentMethod = $paymentMethodGroup.find('.payment-method[payment-method="' + data.paymentMethod + '"]'); 18818 18819 var paymentMethodRadioToSelect = data.paymentMethod == PaymentMethodConstants.CreditCard ? data.type : data.paymentMethod; 18820 $paymentMethodGroup.find('input[type="radio"][value="' + paymentMethodRadioToSelect + '"]').first().prop('checked', true).trigger('change', { doReset: false }); 18821 18822 if ($paymentMethod.find('[id*="_creditCard_owner"]').length > 0 && data.hasOwnProperty('holder')) { 18823 $paymentMethod.find('[id*="_creditCard_owner"]').val(data.holder).valid(); 18824 } 18825 18826 $('.pt_onepcheckout input[name*="_creditCard_type"]').val(data.type); 18827 $paymentMethod.find('[id*="_number"]').val(data.maskedNumber).valid(); 18828 $paymentMethod.find(creditCardNumberInputSelector).val(data.maskedNumber); 18829 $creditCardNumberInput.data('isMaskedSavedCard', true); 18830 18831 if ($paymentMethod.find('[id*="_creditCard_expiration_month"]').length > 0 && data.hasOwnProperty('expirationMonth')) { 18832 $paymentMethod.find('[id*="_creditCard_expiration_month"]').val(data.expirationMonth).trigger('change'); 18833 } 18834 18835 if ($paymentMethod.find('[id*="_creditCard_expiration_year"]').length > 0 && data.hasOwnProperty('expirationYear')) { 18836 $paymentMethod.find('[id*="_creditCard_expiration_year"]').val(data.expirationYear).trigger('change'); 18837 } 18838 18839 if ($paymentMethod.find('[id*="_creditCard_cvn"]').length > 0) { 18840 $paymentMethod.find('[id*="_creditCard_cvn"]').val(''); 18841 } 18842 18843 $creditCardSaveCheckboxContainer.hide(); 18844 } 18845 }.bind(this)); 18846 }); 18847 18848 if ($savedCreditCardList.length > 0 && ($('.pt_onepcheckout input[name*="_selectedPaymentMethodID"]').val() == PaymentMethodConstants.CreditCard || $('.pt_onepcheckout input[name*="_selectedPaymentMethodID"]').val() == PaymentMethodConstants.AllianceData)) { 18849 $savedCreditCardList.find('option').eq(1).prop('selected', true); 18850 $savedCreditCardList.trigger('change'); 18851 $creditCardSaveCheckboxContainer.hide(); 18852 } else { 18853 $creditCardSaveCheckboxContainer.show(); 18854 } 18855 18856 addresses.init(options); 18857 cart.init(options); 18858} 18859 18860function initializeCheckoutEvents() { // Events that are order-level or checkout-level without being specific to payments or cart 18861 18862 // Transactional SMS 18863 if (SitePreferences.TRANSACTIONAL_SMS) { 18864 if (SitePreferences.JQUERY_MASK) { 18865 $('.order-transactional-sms-phone [id*="transactionalsms_smsPhone"]').mask('(000) 000-0000'); 18866 } 18867 18868 var $smsPhoneField = $paymentForm.find('input[id*="transactionalsms_smsPhone"]'); 18869 $smsPhoneField.rules('add', { 18870 required: { 18871 depends: function(element) { 18872 // Returns true if the checkbox is checked, making the mobile phone required. 18873 // Otherwise, returns false, and the field is not required. 18874 return $('.order-transactional-sms [id*="transactionalsms_smsOptin"]').is(":checked"); 18875 } 18876 }, 18877 messages: { 18878 required: "Please enter a valid phone number to receive order updates." 18879 } 18880 }); 18881 $smsPhoneField.attr('inputmode','numeric'); 18882 18883 // Use 'active' class to check/uncheck the opt-in box here since we can't use conditionals in XML files and checkbox is defaulted to fal
18883se 18884 if ($('.order-transactional-sms-container').hasClass('active')) { 18885 $('.order-transactional-sms input[id*="transactionalsms_smsOptin"]').prop('checked', true); 18886 getBillingPhoneForSMS(); 18887 } else { 18888 $('.order-transactional-sms input[id*="transactionalsms_smsOptin"]').prop('checked', false); 18889 } 18890 18891 $(document).off('click', '.order-transactional-sms .transactional-sms-toggle').on('click', '.order-transactional-sms .transactional-sms-toggle', function (e) { 18892 $(this).closest('.order-transactional-sms').find('input[id*="transactionalsms_smsOptin"]').trigger('click'); 18893 }); 18894 18895 $(document).off('change', '.order-transactional-sms input[id*="transactionalsms_smsOptin"]').on('change', '.order-transactional-sms input[id*="transactionalsms_smsOptin"]', function (e) { 18896 if ($(this).is(':checked')) { 18897 $(this).closest('.order-transactional-sms-container').addClass('active'); 18898 if ($('.order-transactional-sms-phone input[id*="transactionalsms_smsPhone"]').val().trim() <= 0) { 18899 getBillingPhoneForSMS(); 18900 } 18901 } else { 18902 $(this).closest('.order-transactional-sms-container').removeClass('active'); 18903 var $smsPhone = $('.order-transactional-sms-phone input[id*="transactionalsms_smsPhone"]'); 18904 var $errorSpan = $smsPhone.next('span.error'); 18905 $smsPhone.removeClass("error").val(''); // remove error and clear field if toggled off 18906 $errorSpan.remove(); 18907 } 18908 }); 18909 18910 $(document).off('change', '.order-transactional-sms-phone input[id*="transactionalsms_smsPhone"]').on('change', '.order-transactional-sms-phone input[id*="transactionalsms_smsPhone"]', function (e) { 18911 $paymentForm.validate().element('input[id*="transactionalsms_smsPhone"]'); 18912 }); 18913 } 18914 18915} 18916 18917function getBillingPhoneForSMS() { 18918 var billingPhone = $('#billingAddressForm').find('[id*="_phone"]').val(); 18919 if (billingPhone) { 18920 $('.order-transactional-sms-phone input[id*="transactionalsms_smsPhone"]').val(billingPhone).trigger('input'); 18921 } 18922} 18923 18924function renderAlternatePickup() { 18925 $(document).off('click', 'button.alt-pickup-button').on('click', 'button.alt-pickup-button', function (e) { 18926 e.preventDefault(); 18927 $('#alt-pickup-modal').addClass('active-modal').show(); 18928 $('fieldset span').removeClass('error-msg'); 18929 $('.one-required').removeClass('error'); 18930 }); 18931 18932 $(document).off('click', '#alt-pickup-modal .close-modal').on('click', '#alt-pickup-modal .close-modal', function (e) { 18933 e.preventDefault(); 18934 $('#alt-pickup-modal').removeClass('active-modal').hide(); 18935 }); 18936 18937 $(document).on('focus', 'input[name="firstName"]', function () { 18938 $('.firstname-error').removeClass('error-msg'); 18939 }); 18940 18941 $(document).on('focus', 'input[name="lastName"]', function () { 18942 $('.lastname-error').removeClass('error-msg'); 18943 }); 18944 18945 $(document).on('focus', 'input[name="email"]', function () { 18946 $('.email-error').removeClass('error-msg'); 18947 $('.one-required').removeClass('error'); 18948 }); 18949 18950 $(document).on('focus', 'input[name="phone"]', function () { 18951 $('.phone-error').removeClass('error-msg'); 18952 $('.one-required').removeClass('error'); 18953 }); 18954 18955 $(document).off('click', 'button#altPickupSubmit').on('click', 'button#altPickupSubmit', function (e) { 18956 e.preventDefault(); 18957 18958 var isFirstNameValid = true; 18959 var firstName = $('input[name="firstName"]').val(); 18960 var regexName = /^[a-z ,.'-]+$/i; 18961 if (firstName.length == 0 || firstName.match(regexName) == null) { 18962 isFirstNameValid = false; 18963 $('.firstname-error').addClass('error-msg'); 18964 } 18965 18966 var isLastNameValid = true; 18967 var lastName =$('input[name="lastName"]').val(); 18968 if (lastName.length == 0 || lastName.match(regexName) == null) { 18969 isLastNameValid = false; 18970 $('.lastname-error').addClass('error-msg'); 18971 } 18972 18973 var isEmailValid = true; 18974 var email = $('input[name="email"]').val(); 18975 var regexEmail = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/g; 18976 if (email.length > 0 && email.match(regexEmail) == null) { 18977 isEmailValid = false; 18978 $('.email-error').addClass('error-msg'); 18979 } 18980 18981 var isPhoneValid = true; 18982 var phone = $('input[name="phone"]').val().replace(/\D/g, ''); 18983 var regexPhone = /^\+?\(?([0-9][0-8][0-9])\)?[\-\. ]?([2-9][0-9]{2})[\-\. ]?([0-9]{4})(\s*x[0-9]+)?$/g; 18984 if (phone.length > 0 && phone.match(regexPhone) == null) { 18985 isPhoneValid = false;
18986 $('.phone-error').addClass('error-msg'); 18987 } 18988 18989 if (email.length == 0 && phone.length == 0) { 18990 $('.one-required').addClass('error'); 18991 isEmailValid = false; 18992 isPhoneValid = false; 18993 } 18994 18995 if (!isEmailValid || !isPhoneValid) { 18996 return; 18997 } 18998 18999 if (isFirstNameValid && isLastNameValid && (isEmailValid || isPhoneValid)) { 19000 var cleanPhone = phone.replace(/\D/g, ''); 19001 var shipmentID = $('.alternate-pickup').closest("form").attr('shipment'); 19002 19003 $.ajax({ 19004 url: Urls.setAlternatePickup, 19005 type: "get", 19006 data: { 19007 shipmentID: shipmentID, 19008 altPickupFirstName: firstName, 19009 altPickupLastName: lastName, 19010 altPickupEmail: email, 19011 altPickupPhone: cleanPhone 19012 }, 19013 success: function (response) { 19014 var data = JSON.parse(response); 19015 19016 if (data.status == 'success') { 19017 $('span.alt-person').attr('data-firstname', firstName).attr('data-lastname', lastName).attr('data-email', email).attr('data-phone', cleanPhone); 19018 displayAlternatePickup (firstName + ' ' + lastName) 19019 $('#alt-pickup-modal').removeClass('active-modal').hide(); 19020 } 19021 }, 19022 error: function(jqXHR, textStatus, errorThrown) { 19023 console.log(textStatus, errorThrown); 19024 } 19025 }); 19026 } 19027 }); 19028} 19029 19030function displayAlternatePickup (fullName) { 19031 $('.alternate-pickup span.alt-person').text(fullName); 19032 $('span.alt-header').show(); 19033 $('button.alt-pickup-button').text('UPDATE'); 19034} 19035 19036function renderRecaptcha() { 19037 if (loaded.Recaptcha && $('#submitOPCPayment').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForPlaceOrder && options.Recaptcha.GoogleSiteKey && placeOrderRecaptcha == undefined) { 19038 placeOrderRecaptcha = grecaptcha.render('submitOPCPayment', { 19039 'sitekey': options.Recaptcha.GoogleSiteKey, 19040 'callback': submitPayment, 19041 'badge': 'bottomleft' 19042 }); 19043 } 19044} 19045 19046function submitPaymentRecaptchaError() { 19047 if (loaded.Recaptcha && $('#submitOPCPayment').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForPlaceOrder && options.Recaptcha.GoogleSiteKey && placeOrderRecaptcha != undefined) { 19048 grecaptcha.reset(placeOrderRecaptcha); 19049 renderRecaptcha(); 19050 } 19051} 19052 19053function submitPayment(data) { 19054 var balanceDue = parseFloat($paymentSection.attr('balance-due')); 19055 $submitPayment.loading({ 19056 IsImageShown: false, 19057 Label: Resources.Loading.Checkout.PlacingOrder 19058 }); 19059 $submitPayment.attr('disabled', true); 19060 $('#errorBoxOPC').remove(); 19061 19062 $billingAddressForm.validate().form(); 19063 $shippingAddressForm.validate().form(); 19064 19065 // Remove CC formatting right before order is placed so server-side doesn't reject it 19066 // Don't strip formatting if it's a saved credit card 19067 if (SitePreferences.CREDIT_CARD_FORMATTING_ENABLED && SitePreferences.JQUERY_MASK) { 19068 if (!$creditCardNumberInput.data('isMaskedSavedCard') && $creditCardNumberInput.data('mask')) { 19069 $creditCardNumberInput.val($creditCardNumberInput.cleanVal()); 19070 } 19071 } 19072 19073 var $creditCardType = $paymentForm.find('[name$="_creditCard_type"]:checked').val(); 19074 if (balanceDue > 0) { 19075 $paymentForm.validate().form(); 19076 19077 if (typeof $creditCardType === 'undefined') { 19078 $paymentForm.find('[name$="_creditCard_type"]').closest('div.form-row').find('div.field-wrapper.error').remove(); 19079 19080 setTimeout(function(){ 19081 $paymentForm.find('[name$="_creditCard_type"]').closest('div.form-row').append('<div class="field-wrapper error" style="height:0px;"><span class="error">' + Resources.REQUIRED_FIELD + '</span></div>'); 19082 }, 50); 19083 } 19084 } 19085 19086 // check first if addresses are valid 19087 var isBillingAddressValid = false; 19088 var isShippingAddressValid = false; 19089 19090 $billingAddressForm.validate().settings.ignore = []; 19091 $shippingAddressForm.validate().settings.ignore = []; 19092 19093 if ($billingAddressForm.valid()) { 19094 isBillingAddressValid = true; 19095 } else { 19096 $('.billing-address-data.form-info').hide(); 19097 19098 $billingAddressForm.show(); 19099 $billingAddressForm.find('input.required.field.error').eq(0).focus(); 19100 } 19101 19102 if ($shippingAddressForm.valid() || ($shippingAddressForm.find('.formfield.isStore input').prop('checked') && $shippingAddressForm.find('.formfield.myStoreID input').val())) { 19103 isShippingAddressValid = true; 19104 } else { 19105 $('.shipping-address-data.form-info').hide(); 19106 19107 $shippingAddressForm.show(); 19108 $shippingAddressForm.find('input.required.field.error').eq(0).focus(); 19109 } 19110 19111 var isBopisValid = false;
19112 if (data && data.SubmitPaymentForBopis) { 19113 isBopisValid = data.IsBopisInventoryValid; 19114 } else { 19115 var $bopisProductLineItems = $(cartItemsFormSelector).find('.bopis-product-line-item[sku][store]'); 19116 19117 if ($bopisProductLineItems.length > 0) { 19118 BopisProductLineItemHelper.ValidateProductLineItems($(cartItemsFormSelector).find('.bopis-product-line-item[sku][store]'), { SuccessEvent: 'Checkout.SubmitPayment' }); 19119 } else { 19120 isBopisValid = true; 19121 } 19122 } 19123 19124 // Transactional SMS 19125 if (SitePreferences.TRANSACTIONAL_SMS) { 19126 var $transactionalSMSPhone = $('.order-transactional-sms-phone [id*="transactionalsms_smsPhone"]'); 19127 if ($transactionalSMSPhone.data('mask')) { 19128 $transactionalSMSPhone.val($transactionalSMSPhone.cleanVal()); 19129 } 19130 } 19131 19132 if (isBillingAddressValid && isShippingAddressValid && isBopisValid && $('#shipping-method-list input:checked').length && (balanceDue == 0 || $paymentForm.valid())) { 19133 var $paymentFormToSet = $paymentForm.clone(); 19134 var actionName = $submitPayment.attr('name'); 19135 19136 var selectedPaymentMethodId = $paymentForm.find('input[name*="selectedPaymentMethodID"]').val(); 19137 $paymentFormToSet.find('div[payment-method]').not('div[payment-method="' + selectedPaymentMethodId + '"]').remove(); 19138 19139 $paymentFormToSet.find('select').each(function (index) { 19140 $(this).val($paymentForm.find('#' + $(this).attr('id')).val()); 19141 }); 19142 19143 setOPCPaymentData($paymentFormToSet, actionName).then(function(response) { 19144 var data; 19145 try { 19146 data = JSON.parse(response); 19147 } catch (e) { 19148 data = response; 19149 } 19150 19151 if (data.hasOwnProperty('status') && data.status === 'success') { 19152 19153 var dataObject = { 19154 value: balanceDue, 19155 payment_type: selectedPaymentMethodId 19156 } 19157 GoogleTagManagerClient.PushDataLayerForDataLayerType('AddPaymentInfo', dataObject).then(function() { 19158 if (options.CheckoutMode == 'MobileApp') { 19159 window.location.href = Urls.confirmationPageForMobileApp; 19160 } else { 19161 window.location.href = Urls.confirmationPage; 19162 } 19163 }).catch(function() { 19164 if (options.CheckoutMode == 'MobileApp') { 19165 window.location.href = Urls.confirmationPageForMobileApp; 19166 } else { 19167 window.location.href = Urls.confirmationPage; 19168 } 19169 }); 19170 } else if (data.hasOwnProperty('status') && data.status === 'affirmRedirect') { 19171 var _affirm_config = { 19172 public_api_key: data.affirm.PublicApiKey, 19173 script: data.affirm.Script 19174 }; 19175 (function(l,g,m,e,a,f,b){var d,c=l[m]||{},h=document.createElement(f),n=document.getElementsByTagName(f)[0],k=function(a,b,c){return function(){a[b]._.push([c,arguments])}};c[e]=k(c,e,"set");d=c[e];c[a]={};c[a]._=[];d._=[];c[a][b]=k(c,a,b);a=0;for(b="set add save post open empty reset on off trigger ready setProduct".split(" ");a<b.length;a++)d[b[a]]=k(c,e,b[a]);a=0;for(b=["get","token","url","items"];a<b.length;a++)d[b[a]]=function(){};h.async=!0;h.src=g[f];n.parentNode.insertBefore(h,n);delete g[f];d(g);l[m]=c})(window,_affirm_config,"affirm","checkout","ui","script","ready"); 19176 19177 affirm.checkout(JSON.parse(data.affirm.AffirmCheckout)); 19178 affirm.checkout.post(); 19179 affirm.ui.ready( 19180 function() { 19181 affirm.ui.error.on("close", function(){ 19182 // window.location.replace(data.affirm.RedirectUrl); 19183 }); 19184 } 19185 ); 19186 } else if (data.hasOwnProperty('status') && data.status === 'shippingRestrictionsError') { 19187 var popup = require('../popup'); 19188 var payload = JSON.parse(data.payload); 19189 19190 var list = $.map(payload.list, function (el) { 19191 return '<li>' + el.name + ':<br>' + el.message + '</li>'; 19192 }).join(''); 19193 19194 popup.init({ 19195 title: payload.title, 19196 content: payload.message + '<ul class="shipping-restrictions-popup__list">' + list + '</ul>', 19197 }).showPopup(); 19198 } else if (data.hasOwnProperty('status') && data.status === 'BillingAddressError') { 19199 var message = data.hasOwnProperty('message') ? data.message : Resources.Checkout.Confirm.Error.Generic; 19200 $submitPayment.after('<div id="errorBoxOPC" class="payment-declined p-2 mt-2"><i class="fa fa-exclamation-triangle"></i> <b>Billing Address Error:</b> ' + message + '</div>'); 19201 } else if (data.hasOwnProperty('status') && data.status === 'ShippingAddressError') { 19202 var message = data.hasOwnProperty('message') ? data.message : Resources.Checkout.Confirm.Error.Generic; 19203 $submitPayment.after('<div id="errorBoxOPC" class="payment-declined p-2 mt-2"><i class="fa fa-exclamation-triangle"></i> <b>Shipping Address Error:</b> ' + message + '</div>'); 19204 } else if (data.hasOwnProperty('status') && data.status === 'ValidationError') { 19205 var message = data.hasOwnProperty('message') ? data.message : Resources.Checkout.Confirm.Error.Generic; 19206 $submitPayment.after('<div id="errorBoxOPC" class="payment-declined p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>Validation Error:</b> ' + message + '</div>'); 19207 } else { 19208 var message = data.hasOwnProperty('message') ? data.message : Resources.Checkout.Confirm.Error.Generic; 19209 $submitPayment.after('<div id="errorBoxOPC" class="payment-declined p-2 mt-2" role="alert" tabindex="0"><i class="fa fa-exclamation-triangle"></i> <b>Payment Declined:</b> ' + message + '</div>'); 19210 } 19211 19212 $submitPayment.loading('destroy'); 19213 $submitPayment.attr('disabled', false); 19214 submitPaymentRecaptchaError(); 19215 }).catch(function(response) { 19216 if (response.status == 302 && response.responseText) { 19217 location.href = response.responseText; 19218 } 19219 }); 19220 } else { 19221 $submitPayment.loading('destroy'); 19222 $submitPayment.attr('disabled', false); 19223 19224 // Adding ADA compliance error messages for submitPayment section 19225 $paymentForm.validate().form(); 19226 if ($paymentForm.find('.field.error').length > 0) { 19227 $('.payment-declined').remove(); 19228 var paymentFormErrorMessages = opcpayment.getErrorMessages($paymentForm);
19229 var paymentFormErrorBox = opcpayment.errorBox('Cannot Proceed', 'Please fix the following errors:', paymentFormErrorMessages); 19230 if (paymentFormErrorBox) { 19231 $submitPayment.after(paymentFormErrorBox); 19232 } 19233 } 19234 19235 submitPaymentRecaptchaError(); 19236 } 19237} 19238 19239function initializePaymentMethodsEvents() { 19240 paymentMethodDomChanges(); 19241 19242 $(document).on('change', creditCardListSelector, function (e, options) { 19243 var $this = $(this); 19244 var hiddenSelectedValue = $('.pt_onepcheckout input[name*="_selectedPaymentMethodID"]').val(); 19245 19246 options = options != undefined ? options : {}; 19247 options.doReset = options.doReset != undefined ? options.doReset : true; 19248 19249 var selectedCreditCardType = $this.val(); 19250 19251 if (selectedCreditCardType) { 19252 var selectedPaymentMethodId = $this.attr('payment-method') || $this.find(':selected').attr('payment-method'); 19253 var selectedPaymentCardImageUrl = $this.attr('payment-card-image') || $this.find(':selected').attr('payment-card-image'); 19254 19255 $paymentForm.attr('selected-payment-method', selectedPaymentMethodId).attr('selected-card-type', selectedCreditCardType); 19256 $this.closest('[payment-method-group]').attr('payment-method', selectedPaymentMethodId); 19257 19258 $('.pt_onepcheckout input[name*="_selectedPaymentMethodID"]').val(selectedPaymentMethodId); 19259 19260 if (!$('[payment-method="' + selectedPaymentMethodId + '"].payment-method').hasClass('payment-method-expanded')) { 19261 $('.payment-method').removeClass('payment-method-expanded').hide(); 19262 $('[payment-method="' + selectedPaymentMethodId + '"].payment-method').addClass('payment-method-expanded').show(); 19263 } 19264 19265 $('.payment-card-list.grid').find('[payment-card]').hide(); 19266 $('.payment-card-list.grid').find('[payment-card="' + selectedCreditCardType + '"]').show(); 19267 19268 $(creditCardListSelector).filter('input[value="' + selectedCreditCardType + '"]').prop('checked', true); 19269 $(creditCardListSelector).find('option[value="' + selectedCreditCardType + '"]').prop('selected', true); 19270 19271 // Legacy code? Are we still trying to allow logged-in customer to save credit card info to their account at checkout? 19272 if (hiddenSelectedValue == PaymentMethodConstants.CreditCard || hiddenSelectedValue == PaymentMethodConstants.AllianceData) { 19273 $creditCardSaveCheckboxContainer.hide(); 19274 } else { 19275 $creditCardSaveCheckboxContainer.show(); 19276 } 19277 19278 $paymentForm.find('[payment-method-group="' + PaymentMethodConstants.CreditCard + '"] .cc-image').css('background-image', 'url(' + selectedPaymentCardImageUrl + ')'); 19279 19280 if (options.doReset) { 19281 resetCreditCardFields($('[payment-method="' + selectedPaymentMethodId + '"].payment-method')); 19282 $savedCreditCardList.val(''); 19283 } 19284 } 19285 }); 19286 19287 $(document).on('click', paymentFormSelector + ' .payment-method-group-selector', function (e) { 19288 var paymentMethodGroupId = $(this).val(); 19289 19290 if (paymentMethodGroupId) { 19291 $paymentForm.attr('selected-payment-method-group', paymentMethodGroupId); 19292 19293 $('.pt_onepcheckout input[name*="_selectedPaymentMethodID"]').val($('[payment-method-group="' + paymentMethodGroupId + '"]').attr('payment-method')); 19294 19295 $('[payment-method-group]').hide().removeClass('expanded'); 19296 $('[payment-method-group="' + paymentMethodGroupId + '"]').show().addClass('expanded'); 19297 19298 if ($('[payment-method-group="' + paymentMethodGroupId + '"]').find('.payment-method-expanded').length < 1) { 19299 var $defaultPaymentMethod; 19300 if (paymentMethodGroupId == PaymentMethodConstants.CreditCard) { 19301 // Clear form error messages before re-drawing CC fields - not to be confused with jquery validation, which is separate 19302 $('[payment-method-group="' + paymentMethodGroupId + '"]').find('.error').removeClass('error'); 19303 $('[payment-method-group="' + paymentMethodGroupId + '"]').find('.error-message').html('').removeClass('error-message'); 19304 $defaultPaymentMethod = $('[payment-method="' + paymentMethodGroupId + '"].payment-method'); 19305 } else { 19306 $defaultPaymentMethod = $('[payment-method-group="' + paymentMethodGroupId + '"]').find('.payment-method').first(); 19307 } 19308 $defaultPaymentMethod.addClass('payment-method-expanded').show(); 19309 if ($defaultPaymentMethod.attr('payment-card-image')) { 19310 $defaultPaymentMethod.find('.cc-image').css('background-image', 'url(' + $defaultPaymentMethod.attr('payment-card-image') + ')'); 19311 } 19312 } 19313 19314 if (window.innerWidth <= 767) { 19315 $([document.documentElement, document.body]).animate({ 19316 // scrollTop: $('.payment-method-expanded').closest('.payment-method-option').offset().top - $('.top-banner').height() + 20 19317 scrollTop: $('#paymentSection').offset().top - $('.top-banner').height() - 15 19318 }, 250); 19319 } 19320 19321 // addresses.updateSummary(); 19322 } 19323 }); 19324 19325 $(document).on('input blur', creditCardNumberInputSelector, function(event) {
19326 var creditCardNumber = $creditCardNumberInput.val().replace(/\s/g, ''); 19327 var selectedCard; 19328 19329 if (creditCardNumber.length > 0) { 19330 selectedCard = util.getCreditCardType(creditCardNumber); 19331 if (selectedCard) { 19332 var $selectedCardNumberInput = $('[payment-method-group="' + PaymentMethodConstants.CreditCard + '"] [payment-method="' + selectedCard.PaymentMethod + '"] [credit-card-number-input]'); 19333 if ($selectedCardNumberInput.filter(':visible').length < 1) { 19334 $selectedCardNumberInput.val(creditCardNumber); 19335 } 19336 $('.pt_onepcheckout input[name*="_creditCard_type"]').val(selectedCard.PaymentCard); 19337 $creditCardList.filter('input[type="radio"][value="' + selectedCard.PaymentCardDisplayKey + '"]').first().prop('checked', true).trigger('change', { doReset: false }); 19338 } else { 19339 $('.cc-cardlist-select :input').removeAttr('checked').removeAttr('selected').val(''); 19340 $('.payment-card-list.grid').find('[payment-card]').show(); 19341 $creditCardList.filter('input').prop('checked', false); 19342 $creditCardList.find('option').prop('selected', false); 19343 $paymentForm.find('[payment-method-group="' + PaymentMethodConstants.CreditCard + '"] .cc-image').css('background-image', ''); 19344 19345 var isMaskedSavedCard = $creditCardNumberInput.data('isMaskedSavedCard') || false; 19346 if (isMaskedSavedCard) { 19347 var newInput = event.originalEvent.data || ''; 19348 creditCardNumber = newInput; // Update the variable with the new value 19349 $creditCardNumberInput.data('isMaskedSavedCard', false).val(newInput); // Update credit card number field 19350 } 19351 } 19352 if (SitePreferences.CREDIT_CARD_FORMATTING_ENABLED && SitePreferences.JQUERY_MASK) { 19353 var newType = creditCardNumber.startsWith('34') || creditCardNumber.startsWith('37') ? 'amex' : 'standard'; 19354 var currentType = $creditCardNumberInput.data('cardType'); 19355 if (!currentType || currentType != newType) { 19356 $creditCardNumberInput.data('cardType', newType); 19357 $creditCardNumberInput.unmask(); 19358 19359 if (newType === 'amex') { 19360 $creditCardNumberInput.mask('0000 000000 00000'); 19361 } else { 19362 $creditCardNumberInput.mask('0000 0000 0000 0000'); 19363 } 19364 } 19365 } 19366 $creditCardSaveCheckboxContainer.show(); 19367 19368 } 19369 }); 19370 19371 $(document).on('click', '.add-new-card', function(e) { 19372 e.preventDefault(); 19373 19374 resetCreditCardFields($(this).closest('[payment-method]')); 19375 $('#opc-cc-list :input').removeAttr('checked'); 19376 $('.cc-cardlist-select :input').removeAttr('checked').removeAttr('selected').val(''); 19377 $('.cc-image').css('background-image', 'none'); 19378 $creditCardNumberInput.val(''); 19379 paymentMethodDomChanges(); 19380 }); 19381 19382 $(document).on('click', '.payment-method-option.accordion .form-label', function () { 19383 $(this).closest('.accordion').toggleClass('open'); 19384 }); 19385 19386 $(document).off('Onepcheckout.PaymentFormFieldValidation').on('Onepcheckout.PaymentFormFieldValidation', function() { 19387 // Destroy any previous validators for the $paymentForm before reinitializing due to redraw of checkout 19388 $paymentForm.validate().destroy(); 19389 // Don't use .form() or any other validator method here because it will auto-check the form immediately, but we want to just attach the listeners 19390 $paymentForm.validate(validator.settings); 19391 }); 19392} 19393 19394function paymentMethodDomChanges() { 19395 var combinedSelectors = [creditCardNumberInputSelector, privateLabelCardNumberInputSelector].join(); 19396 var $fieldContainer = $(combinedSelectors).parent(); 19397 19398 if ($fieldContainer.find('.cc-image').length == 0) { 19399 $fieldContainer.append($creditCardImage); 19400 } 19401} 19402 19403function resetCreditCardFields($paymentMethod) { 19404 $paymentMethod.find('input[name*="_owner"]').val(''); 19405 $paymentMethod.find('input[name*="_number"]').val(''); 19406 $paymentMethod.find('input[name*="_cvn"]').val(''); 19407 $paymentMethod.find('input[name*="_month"]').val(''); 19408 $paymentMethod.find('input[name*="_year"]').val(''); 19409 $paymentMethod.find('input[name="cc-number-mask"]').val(''); 19410} 19411 19412/** 19413 * @description Make the AJAX request to set cart data 19414 * @param {Element} form The form element that present address object 19415 * @param {Element} Action name to apply to form 19416 * @returns {Promise} 19417 */ 19418var setOPCPaymentData = function (formSelector, name) { 19419 var $form = $(formSelector); 19420 19421 return TPromise.resolve($.ajax({ 19422 type: 'POST', 19423 url: util.ajaxUrl(Urls.setOpcAddress), 19424 data: $form.serialize() + '&' + name + '=' + name 19425 })); 19426}; 19427 19428exports.init = function (optionsParameter) { 19429 options = optionsParameter; 19430 19431 if (options && options.Recaptcha && (options.Recaptcha.EnabledForPlaceOrder || options.Recaptcha.EnabledForRe
19431wardsCredit || options.Recaptcha.EnabledForGiftCards)) { 19432 recaptcha.initialize(); 19433 } 19434 if (options.B2B && options.B2B.Enabled) { 19435 PaymentVoucherPaymentPanel = require('./checkout/PaymentVoucherPaymentPanel'); 19436 PaymentVoucherPaymentPanel.initialize(); 19437 } 19438 if (pageContext && pageContext.site && pageContext.site == SiteConstants.SiteIds.BootBarnWorkforceUS) { 19439 WorkforceVoucherPaymentPanel = require('./checkout/WorkforceVouchersPaymentPanelClient'); 19440 WorkforceVoucherPaymentPanel.initialize(); 19441 } 19442 GiftCard.initialize(options); 19443 RewardsCredit.initialize(options); 19444 LoyaltyCredit.initialize(options); 19445 initializeEvents(options); 19446}; 19447},{"../../../../bc_sheplersbootbarn_core/cartridge/js/CheckoutConstants":113,"../../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants":117,"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../bonus-products-view":6,"../bopis/components/ProductLineItemHelper":11,"../components/LoadingIndicator":25,"../components/Recaptcha":29,"../popup":83,"../quickview":88,"../util":102,"./cart":50,"./checkout/GiftCardPaymentPanel":54,"./checkout/LoyaltyCredit":55,"./checkout/PaymentVoucherPaymentPanel":56,"./checkout/RewardsCredit":57,"./checkout/WorkforceVouchersPaymentPanelClient":58,"./checkout/formPrepare":61,"./checkout/opcaddress":64,"./checkout/opcpayment":65,"promise":134}],71:[function(require,module,exports){ 19448'use strict'; 19449 19450var tooltip = require('../tooltip'); 19451var page = require('../page'); 19452 19453var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 19454 19455var options = {}; 19456var buffer = {}; 19457 19458function triggerReactWebviewEvent() { 19459 if ('ReactNativeWebView' in window) { 19460 window.ReactNativeWebView.postMessage(JSON.stringify({ action: 'order-page' })); 19461 } 19462} 19463 19464function initializePriceSpiderOrderTracking() { 19465 $(document).on('DataLayer.OrderComplete', function (event, data) { 19466 if (data && data.dataLayer) { 19467 var dataLayer = data.dataLayer; 19468 var psrid = sessionStorage.getItem('psrid'); 19469 if (psrid && dataLayer && 'event' in dataLayer && dataLayer.event == 'purchase') { 19470 var itemsTitle = []; 19471 var itemsPrice = []; 19472 var itemsQuantity = []; 19473 var itemsSku = []; 19474 var itemsManufacturer = []; 19475 var itemElements = dataLayer.items; 19476 for (var i = 0; i < itemElements.length; i++) { 19477 itemsTitle.push(itemElements[i].item_name); 19478 itemsQuantity.push(itemElements[i].quantity); 19479 itemsPrice.push(itemElements[i].price); 19480 itemsSku.push(itemElements[i].item_id); 19481 itemsManufacturer.push(itemElements[i].item_brand); 19482 } 19483 var order = pswtb.purchaseTracking.createOrder(); 19484 order.currencyCode = dataLayer.currency; 19485 order.purchaseTotal = dataLayer.value; 19486 var itemsDetails = []; 19487 for (var y = 0; y < itemsTitle.length; y++) { 19488 itemsDetails.push({ 19489 "productName": itemsTitle[y], 19490 "quantity": itemsQuantity[y], 19491 "unitPrice": itemsPrice[y] / itemsQuantity[y], 19492 "manufacturer": itemsManufacturer[y], 19493 "sku": itemsSku[y] 19494 }); 19495 } 19496 order.details = itemsDetails; 19497 order.redirectToken = psrid; 19498 order.submit(); 19499 } 19500 } 19501 }); 19502} 19503 19504function initializeVWOOrderTracking() { 19505 buffer['items'] = null; 19506 if (SitePreferences.VWO_ENABLED && SitePreferences.VWO_PURCHASE_TRACKING_ENABLED) { 19507 buffer['vwoLoadedInterval'] = setInterval(triggerVWOOrderTracking, 100); 19508 19509 $(document).on('DataLayer.OrderComplete', function (event, data) { 19510 var items = []; 19511 var paymentMethods = ''; 19512 if (data && data.dataLayer) { 19513 var dataLayer = data.dataLayer; 19514 if (data && data.options && data.options.PaymentMethod) { 19515 paymentMethods = data.options.PaymentMethod; 19516 } else if (data && data.options && data.options.PaymentMethods) { 19517 paymentMethods = data.options.PaymentMethods.join(' | '); 19518 } else if (pageContext.PaymentMethods) { 19519 paymentMethods = pageContext.PaymentMethods.join(' | '); 19520 } 19521 for (var itemKey in dataLayer.items) { 19522 var item = dataLayer.items[itemKey]; 19523 var revenue = item.price; 19524 var price = revenue; 19525 if (item.discount) { 19526 price += item.discount; 19527 } 19528 items.push({ 19529 "price": price.toFixed(2), 19530 "item": item.item_id, 19531 "paymentMethod": paymentMethods, 19532 "registeredUser": Customer.registered, 19533 "revenue": revenue 19534 }); 19535 } 19536 } 19537 19538 if (items && items.length > 0) { 19539 buffer['items'] = items; 19540 triggerVWOOrderTracking(); 19541 } 19542 }); 19543 } 19544} 19545 19546function triggerVWOOrderTracking() { 19547 if (buffer['items'] && window.VWO && window.VWO.event && typeof window.VWO.event == 'function') { 19548 clearInterval(buffer['vwoLoadedInterval']); 19549 for (var itemIndex = 0; itemIndex < buffer['items'].length; itemIndex++) { 19550 var item = buffer['items'][itemIndex];
19551 VWO.event("purchase", item); 19552 } 19553 } 19554} 19555 19556function initializeTatariOrderTracking() { 19557 if (SitePreferences.TATARI_ENABLED) { 19558 $(document).on('DataLayer.OrderComplete', function (event, data) { 19559 var maximumAttempts = 50; 19560 var retryDelay = 100; 19561 var attempts = 0; 19562 19563 var items = []; 19564 if (data && data.dataLayer) { 19565 var orderData = data.dataLayer; 19566 var orderTotal = orderData.value; 19567 var orderCurrency = orderData.currency; 19568 var orderID = orderData.transaction_id; 19569 19570 for (var itemKey in orderData.items) { 19571 var item = orderData.items[itemKey]; 19572 var price = item.price; 19573 19574 items.push({ 19575 "name": item.item_name, 19576 "price": price.toFixed(2), 19577 "quantity": item.quantity, 19578 "productID": item.item_id, 19579 "category": item.item_category + " " + item.item_category2 19580 }); 19581 } 19582 } 19583 19584 if (items && items.length > 0) { 19585 function sendTatariPurchase() { 19586 if ( window.tatari && typeof window.tatari.purchase === 'function') { 19587 window.tatari.purchase({ 19588 total: orderTotal, 19589 currency: orderCurrency, 19590 orderId: orderID, 19591 items: items, 19592 newPurchase: true 19593 }); 19594 19595 window.console.log( 19596 'Tatari purchase sent for order:', 19597 orderID 19598 ); 19599 19600 return; 19601 } 19602 19603 attempts += 1; 19604 19605 if (attempts < maximumAttempts) { 19606 window.setTimeout(sendTatariPurchase, retryDelay); 19607 } else { 19608 window.console.error( 19609 'Tatari purchase was not sent: ' + 19610 'tatari.purchase did not become available.' 19611 ); 19612 } 19613 } 19614 19615 sendTatariPurchase(); 19616 } 19617 }); 19618 } 19619} 19620 19621function initializeConfirmationRegistration() { 19622 var existingCustomer = $('.order-billing-name').attr('has-profile'); 19623 var notRewardsCustomer = $('.order-billing-name').attr('has-rewards'); 19624 var rewardsAdded = $('.rewards-added').data('rewards'); 19625 var firstName = $('input[name="dwfrm_profile_customer_firstname"]').val(); 19626 var lastName = $('input[name="dwfrm_profile_customer_lastname"]').val(); 19627 var email = $('input[name="dwfrm_profile_customer_email"]').val(); 19628 var zip = $('input[name="dwfrm_profile_customer_zip"]').val(); 19629 var phone = $('input[name="dwfrm_profile_customer_phone"]').val(); 19630 var cleanPhone = ''; 19631 if (phone) { 19632 cleanPhone = phone.replace(/\D/g, ''); 19633 } 19634 var city = $('.billing-info .city').text().replace(',',''); 19635 var state = $('.billing-info .state').text(); 19636 var country = $('.billing-info .order-billing-country').text(); 19637 var orderNo = $('.orderdetail-section .sectionheader h3').text().replace("Order Number: ",""); 19638 19639 $(document).ready(function() { 19640 if(notRewardsCustomer === "false"){ 19641 if (!rewardsAdded || rewardsAdded == '') { 19642 $.ajax({ 19643 type: 'post', 19644 url: Urls.createRewardsAccount, 19645 contentType: 'application/json', 19646 data: JSON.stringify({ 19647 firstName: firstName, 19648 lastName: lastName, 19649 emailAddress: email, 19650 phoneNumber: cleanPhone, 19651 zipCode: zip, 19652 birthDate: '01/01/1900', 19653 autoEnroll: true, 19654 existingCustomer: existingCustomer 19655 }), 19656 success: function (data) { 19657 console.log('Rewards account created.'); 19658 } 19659 }); 19660 } 19661 } 19662 }); 19663 $(document).on('focus', 'input[name^="dwfrm_profile_login_password_"]', function () { 19664 $('.register-errors span').addClass('hidden'); 19665 $('.password-holder').removeClass('error'); 19666 }); 19667 $(document).off('click', 'button.confirmation-register').on('click', 'button.confirmation-register', function (e) { 19668 e.preventDefault(); 19669 $('.register-errors span').addClass('hidden'); 19670 $('.password-holder').removeClass('error'); 19671 19672 var isPasswordValid = true; 19673 var password = $('input[name^="dwfrm_profile_login_password_"]').val(); 19674 var regexPassword = /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*()_+={}\[\]:;"'<>,.?\/\\~-])[A-Za-z\d!@#$%^&*()_+={}\[\]:;"'<>,.?\/\\~-]{8,20}$/g; 19675 if (password.length == 0 || password.match(regexPassword) == null) { 19676 isPasswordValid = false; 19677 $('.register-errors span.format-error').removeClass('hidden'); 19678 $('.password-holder').addClass('error'); 19679 } 19680 19681 if (isPasswordValid) { 19682 $.ajax({ 19683 url: Urls.registerAccount, 19684 type: "get", 19685 data: { 19686 registerFirstName: firstName, 19687 registerLastName: lastName, 19688 registerEmail: email, 19689 registerZip: zip, 19690 registerPhone: cleanPhone,
19691 registerOrderNo: orderNo, 19692 registerPassword: password 19693 }, 19694 success: function (response) { 19695 var data = JSON.parse(response); 19696 19697 if (data.status == 'success') { 19698 var auth_data = { 19699 email: email 19700 } 19701 var contact_data = { 19702 'channels': { 19703 'email': { 19704 'address': email 19705 } 19706 }, 19707 'first_name': firstName, 19708 'last_name': lastName, 19709 'phone': cleanPhone, 19710 'postal_code': zip, 19711 'source_create': 'confirmation', 19712 'geo_location': { 19713 'postal_code': zip, 19714 'country': country, 19715 'state': state, 19716 'city': city 19717 } 19718 }; 19719 var loginProperties = { 19720 "email": email 19721 }; 19722 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 19723 crdl([ 19724 ['contact', auth_data, contact_data], 19725 ['event', 'account_create'], 19726 ['event', 'login', loginProperties] 19727 ]); 19728 } 19729 } 19730 if ($('body').attr('checkout-mode') == 'mobileapp') { 19731 window.location.href = "bootbarn://account"; 19732 } else { 19733 window.location.href = Urls.account; 19734 } 19735 }, 19736 error: function(jqXHR, textStatus, errorThrown) { 19737 console.log(textStatus, errorThrown); 19738 } 19739 }); 19740 } 19741 }); 19742} 19743 19744exports.init = function (optionsParameter) { 19745 options = optionsParameter; 19746 19747 tooltip.init({ 19748 items: '.tooltip' 19749 }); 19750 triggerReactWebviewEvent(); 19751 initializePriceSpiderOrderTracking(); 19752 initializeVWOOrderTracking(); 19753 initializeTatariOrderTracking(); 19754 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 19755 initializeConfirmationRegistration(); 19756 } 19757} 19758},{"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../page":46,"../tooltip":101}],72:[function(require,module,exports){ 19759'use strict'; 19760 19761var _ = require('lodash'); 19762var ajax = require('../../ajax'); 19763var AddressAutocompleteDialog; 19764var AddressVerificationDialog; 19765var AddressVerificationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper'); 19766var dialog = require('../../dialog'); 19767var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 19768var minicart = require('../../minicart'); 19769var page = require('../../page'); 19770var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 19771var TPromise = require('promise'); 19772var util = require('../../util'); 19773var ValidationHelper = require('../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper'); 19774var ValidationRules = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 19775var ValidationSettings = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 19776 19777var options = {}; 19778var dataBuffer = {}; 19779 19780/** 19781 * Wraps the dialog close functionality in a function so that we can hook into the transitionEnd event 19782 * to fire the close event on the dialog. 19783 * This allows for an animation to complete before the dialog is closed and removed from the dom 19784 */ 19785 var closeAddToCartModal = function () { 19786 // save overaly for class additions
19787 var $overlay = $('.add-to-cart-modal-wrapper').parent().find('.ui-widget-overlay'); 19788 19789 // hook into transition end 19790 if (pageContext.site === SiteConstants.SiteIds.BootBarnRspUS) { 19791 var currentModal = $('#dialog-container'); 19792 if (currentModal.dialog('isOpen')) { 19793 currentModal.dialog('close'); 19794 } 19795 } else { 19796 $('.add-to-cart-modal-wrapper').one('transitionend webkitTransitionEnd oTransitionEnd', function (e) { 19797 var currentModal = $(this).find('#dialog-container'); 19798 if (currentModal.dialog('isOpen')) { 19799 currentModal.dialog('close'); 19800 } 19801 }); 19802 } 19803 19804 $overlay.removeClass('show'); 19805 $('.add-to-cart-modal-wrapper').removeClass('show'); 19806} 19807 19808/** 19809 * @description Make the AJAX request to add an item to cart 19810 * @param {Element} form The form element that contains the item quantity and ID data 19811 * @returns {Promise} 19812 */ 19813var addItemToCart = function (form) { 19814 var $form = $(form), 19815 $qty = $form.find('input[name="Quantity"]'); 19816 if ($qty.length === 0 || isNaN($qty.val()) || parseInt($qty.val(), 10) === 0) { 19817 $qty.val('1'); 19818 } 19819 return TPromise.resolve($.ajax({ 19820 type: 'POST', 19821 url: util.ajaxUrl(Urls.addProduct), 19822 data: $form.serialize() 19823 })); 19824}; 19825 19826/** 19827 * @description Handler to handle the add to cart event 19828 */ 19829var addToCart = function(event, data) { 19830 event.preventDefault(); 19831 var $html = $('html'); 19832 var $container = $('#wrapper'); 19833 var $form = $('.pdpForm'); 19834 var sizeSelected = $('div.product-variations .size.size-options li.selected'); 19835 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 19836 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 19837 var isSizeSelected = sizeSelected.length || (lengthSelected && widthSelected); 19838 19839 if (!isSizeSelected) { 19840 dialog.open({ 19841 html: 'Please select a size', 19842 options: { 19843 dialogClass: 'dialog-alert', 19844 draggable: false 19845 } 19846 }); 19847 return false; 19848 } 19849 19850 if (!$('div.product-variations .color.color-options li.selected').length) { 19851 dialog.open({ 19852 html: 'Please select a color', 19853 options: { 19854 dialogClass: 'dialog-alert', 19855 draggable: false 19856 } 19857 }); 19858 return false; 19859 } 19860 19861 var isBopis = false; 19862 var $bopisAddToCartOptions = $('.bopis-add-to-cart-options-container'); 19863 var $bopisAddToCartOption; 19864 if ($bopisAddToCartOptions.length > 0) { 19865 if (pageContext.site === SiteConstants.SiteIds.BootBarnRspUS) { 19866 $bopisAddToCartOptions.find('input[name="AddToCartOption"]').prop('checked', false); 19867 $(event.currentTarget).closest('li').find('input[name="AddToCartOption"]').prop('checked', true); 19868 $bopisAddToCartOptions = $('.bopis-add-to-cart-options-container'); 19869 } 19870 $bopisAddToCartOption = $bopisAddToCartOptions.find('input[name="AddToCartOption"]:checked'); 19871 var $bopisAddToCartLabel = $bopisAddToCartOption.closest('li'); 19872 var $bopisOptionalMessage = $bopisAddToCartLabel.find('.add-to-cart-optional-message'); 19873 if ($bopisOptionalMessage.length > 0) { 19874 dataBuffer['OptionalMessage'] = $bopisOptionalMessage.first().html().trim(); 19875 } 19876 19877 var $bopisAddToCartOptionsEnabled = $bopisAddToCartOptions.find('input[name="AddToCartOption"]:not([disabled])'); 19878 if ($bopisAddToCartOptionsEnabled.length == 0) { 19879 dialog.open({ 19880 html: 'This item is not available for your selected options.', 19881 options: { 19882 dialogClass: 'dialog-alert', 19883 draggable: false 19884 } 19885 }); 19886 return false; 19887 } 19888 } 19889 19890 if ($(event.currentTarget).hasClass('bopis') || (data && data.bopis)) { 19891 isBopis = true; 19892 } else if ($bopisAddToCartOptions.length > 0) { 19893 var bopisShippingOption = $bopisAddToCartOption.val(); 19894 if (bopisShippingOption == 'delivery') { 19895 $(document).trigger('Bopis.LocalDelivery.Display', { OptionalMessage: dataBuffer['OptionalMessage'] }); 19896 return false; 19897 } else if (bopisShippingOption == 'shiptostorepickup') { 19898 isBopis = true; 19899 data = data || {}; 19900 data.bopisStore = $bopisAddToCartOptions.find('.selected-store[store-id]').attr('store-id'); 19901 data.shippingOption = bopisShippingOption; 19902 } else if (bopisShippingOption == 'pickup') { 19903 isBopis = true; 19904 var storeData; 19905 var $storeData = $bopisAddToCartOptions.find('.selected-store[store-data]'); 19906 if ($storeData.length > 0) { 19907 storeData = JSON.parse($storeData.attr('store-data')) 19908 data = data || {}; 19909 data.bopisStore = storeData.location.code;
19910 data.quantityAvailable = storeData.detail.quantity; 19911 data.shippingOption = bopisShippingOption; 19912 } 19913 } 19914 } 19915 19916 var $bopisStore; 19917 if (isBopis) { 19918 $bopisStore = $('input[name="Bopis_StoreSearch_StoreId"]:checked'); 19919 $('.product-add-to-cart input[name="bopis_store"]').val(data.bopisStore ? data.bopisStore : $bopisStore.val()); 19920 $('.product-add-to-cart input[name="bopis_quantity_available"]').val(data.quantityAvailable != undefined ? data.quantityAvailable : $bopisStore.attr('quantity-available')); 19921 $('.product-add-to-cart input[name="bopis_shipping_option"]').val(data.shippingOption ? data.shippingOption : ''); 19922 $('.product-add-to-cart input[name="bopis_delivery_address"]').val(data.deliveryAddress ? data.deliveryAddress : ''); 19923 $('.product-add-to-cart input[name="bopis_delivery_note"]').val(data.deliveryNote ? data.deliveryNote : ''); 19924 $('.product-add-to-cart input[name="bopis_delivery_gift_message"]').val(data.giftMessage ? data.giftMessage : ''); 19925 $('.option-dropdown select[name*="_Bopis"]').val('Yes'); 19926 } else { 19927 $('.product-add-to-cart input[name="bopis_store"]').val(''); 19928 $('.product-add-to-cart input[name="bopis_quantity_available"]').val(''); 19929 $('.product-add-to-cart input[name="bopis_shipping_option"]').val(''); 19930 $('.product-add-to-cart input[name="bopis_delivery_address"]').val(''); 19931 $('.option-dropdown select[name*="_Bopis"]').val('No'); 19932 } 19933 19934 $('.product-add-to-cart input[name="channel"]').val(data && data.channel ? data.channel : ''); 19935 if (data && 'csrf_token' in data && data.csrf_token) { 19936 $('#csrftoken').val(data.csrf_token); 19937 } 19938 19939 if (sizeSelected.hasClass("tempselection")) { 19940 sizeSelected.addClass('enterSelected'); 19941 sizeSelected.trigger('click'); 19942 sizeSelected.find('.swatchanchor').trigger('click'); 19943 setTimeout( function(){$("#add-to-cart").click()}, 100 ); 19944 return false; 19945 } 19946 19947 if (typeof dataLayer !== 'undefined') { 19948 var qty = $('.pt_product-details .pdpForm .product-add-to-cart select[id=Quantity]').val(); 19949 var variationAttr = $('.product-variations').data('attributes'); 19950 var sizeAttrValue = variationAttr.size.displayValue; 19951 if (sizeAttrValue == '' || sizeAttrValue == null ) { 19952 if (sizeSelected.hasClass("tempselection") && sizeSelected.find('a.swatchanchor').data() != null ) { 19953 sizeSelected.addClass('enterSelected'); 19954 var sizeObjRef = sizeSelected.find('a.swatchanchor').data(); 19955 sizeAttrValue = sizeObjRef.sizeName; 19956 sizeSelected.find('a.swatchanchor').trigger('click'); 19957 } 19958 } 19959 19960 var googleTagManagerAddToCartDeliveryMethod = 'shiptoaddress'; 19961 if (data && data.shippingOption) { 19962 switch (data.shippingOption) { 19963 case 'pickup': 19964 googleTagManagerAddToCartDeliveryMethod = 'storepickup'; 19965 break; 19966 case 'delivery': 19967 googleTagManagerAddToCartDeliveryMethod = 'samedaydelivery'; 19968 break; 19969 case 'ship': 19970 googleTagManagerAddToCartDeliveryMethod = 'shiptoaddress'; 19971 break; 19972 default: 19973 googleTagManagerAddToCartDeliveryMethod = data.shippingOption; 19974 break; 19975 } 19976 } 19977 GoogleTagManagerClient.PushDataLayerForDataLayerType('AddToCart', { deliverymethod: googleTagManagerAddToCartDeliveryMethod}); 19978 19979 for (var i=0; i < dataLayer.length; i++) { 19980 if (dataLayer[i].event == 'pdpDisplay') { 19981 var selectedItem = dataLayer[i].ecommerce.detail.products[0]; 19982 var itemPrice = (selectedItem.silhouette == 'Gift Card') ? parseInt((variationAttr.size.value).replace('$','')) : selectedItem.price; 19983 var skuID = $('#pid').val(); 19984 var image = $('.product-primary-image [class*="-slide"] .primary-image.first').find('a').attr('href'); 19985 if (!image || image == undefined || image == null) { 19986 image = $('.product-primary-image [class*="-slide"] .primary-image.first').find('img').attr('src'); 19987 } 19988 19989 if (SitePreferences.CORDIAL_ENABLED) { 19990 var properties = { 19991 'productID': selectedItem.id 19992 }; 19993 19994 var cart_data = [{ 19995 'productID': selectedItem.id, 19996 'sku': skuID, 19997 'category': (selectedItem.category).replace(/\\/g, ""), 19998 'name': (selectedItem.name).replace(/\\/g, ""), 19999 'qty': qty, 20000 'itemPrice': itemPrice, 20001 'images': [image], 20002 'url':$(location).attr("href").split("?utm")[0].split("#utm")[0].split("&utm")[0], 20003 'attr': { 20004 'manufacturer': selectedItem.brand, 20005 'color': variationAttr.color.displayValue, 20006 'size': variationAttr.size.displayValue 20007 } 20008 }]; 20009 20010 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 20011 crdl([ 20012 ['cart', 'update'], 20013 ['cartitem', 'add' , cart_data], 20014 ['event', 'cart', properties] 20015 ]); 20016 } 20017 } 20018 20019 var dateTime = Math.floor(Date.now() / 1000); 20020 var eventID = 'addtocart-' + selectedItem.id + '-' + dateTime; 20021 20022 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS && SitePreferences.PINTEREST_ENABLED) { 20023 pintrk('track', 'addtocart', { 20024 event_id: eventID, 20025 value: itemPrice * qty, 20026 order_quantity: qty, 20027 currency: $('meta[itemprop="priceCurrency"]').attr('content'), 20028 line_items: [ 20029 { 20030 product_name: (selectedItem.name).replace(/\\/g, ""), 20031 product_id: selectedItem.id, 20032 product_category: (selectedItem.category).replace(/\\/g, ""), 20033 product_variant_id: skuID, 20034 product_price: itemPrice, 20035 product_quantity: qty, 20036 product_brand: selectedItem.brand 20037 } 20038 ] 20039 }); 20040 } 20041 20042 if (SitePreferences.PIXLEE_ENABLED) { 20043 if (typeof pixlee_analytics !== 'undefined') { 20044 pixlee_analytics.events.trigger('add:to:cart', { 20045 'product_sku': selectedItem.id, 20046 'price': itemPrice, 20047 'quantity': qty, 20048 'currency': $('meta[itemprop="priceCurrency"]').attr('content') 20049 }); 20050 } 20051 } 20052 } 20053 } 20054 } 20055 20056 addItemToCart($form).then(function (response) { 20057 $.ajax({url : Urls.cartItemCount, method: 'POST', dataType: 'json', success : function(data) { 20058 if (data && data.ProductCount != undefined) { 20059 $('.btn-minicart span').html(Math.round(data.ProductCount)); 20060 } 20061 }}); 20062 var $uuid = $form.find('input[name="uuid"]'); 20063 if ($uuid.length > 0 && $uuid.val().length > 0) { 20064 page.refresh(); 20065 } else if(SitePreferences.REDIRECT_TO_CART && (!pageContext.options || pageContext.options.StoreUIVersion != '2024Redesign')){ 20066 var redirectUrl = (SitePreferences.HIDE_BASKET) ? Urls.onePage : Urls.cartShow; 20067 window.location.href = redirectUrl; 20068 } else { 20069 if (SitePreferences.ADD_TO_CART_MODAL || (pageContext.options && pageContext.options.StoreUIVersion == '2024Redesign')) { 20070 var qtyAdded = $('.pt_product-details .pdpForm .product-add-to-cart select[id=Quantity]').val(); 20071 $.ajax({ 20072 url: Urls.addToCartModalDisplay, 20073 data: { 20074 storeuiversion: pageContext && pageContext.options && pageContext.options.StoreUIVersion ? pageContext.options.StoreUIVersion : null, 20075 shippingoption: bopisShippingOption 20076 }, 20077 dataType: 'html', 20078 success: function(modalContent) { 20079 if (modalContent.length > 0) { 20080 var $modalContent = $(modalContent); 20081 var $recsContent; 20082 if (pageContext.site === SiteConstants.SiteIds.SheplersUS) { 20083 $recsContent = $('#best_selling_products.accordion.product-recommendations').removeClass('accordion'); 20084 } else if (pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 20085 $recsContent = $('.recomm-prod-pdp-a2c-slot .accordion.product-recommendations').removeClass('accordion'); 20086 } else { 20087 $recsContent = $('.main .accordion.product-recommendations').removeClass('accordion'); 20088 } 20089 $recsContent.find('.accordion-head').removeClass('accordion-head'); 20090 $recsContent.find('.accordion-body').removeClass('accordion-body'); 20091 20092 if ($recsContent.find('.slick-list').length > 0) { 20093 var $recommendationsContentHtml = $($recsContent[0].outerHTML); 20094 var $recommendationsSlides = $recommendationsContentHtml.find('.slide'); 20095 var recommendationsSlidesHtml = ''; 20096 $recommendationsSlides.each(function(index, element) {
20097 recommendationsSlidesHtml += $(this)[0].outerHTML; 20098 }); 20099 $recommendationsContentHtml.find('.slides').html(recommendationsSlidesHtml); 20100 $recommendationsContentHtml.find('.slides').removeClass('slick-initialized slick-slider'); 20101 $recommendationsContentHtml.find('.slide').removeClass('slick-slide slick-current slick-active slick-cloned').css('width', ''); 20102 $modalContent.find('.product-recommendations-container').html($recommendationsContentHtml); 20103 } 20104 20105 if (dataBuffer['OptionalMessage']) { 20106 var optionalMessageHtml = '<div class="add-to-cart-modal-optional-message">' + dataBuffer['OptionalMessage'] + '</div>'; 20107 $modalContent.find('.added-message').append(optionalMessageHtml); 20108 } 20109 $modalContent.attr('bopis-shipping-option', bopisShippingOption); 20110 20111 var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; 20112 20113 dialog.open({ 20114 html: $modalContent, 20115 options: { 20116 dialogClass: 'add-to-cart-modal', 20117 draggable: false, 20118 resizable: false, 20119 width: 1090, 20120 open: function(event, ui) { 20121 dataBuffer['wrapperScrollTop'] = scrollTop; 20122 dataBuffer['wrapperMarginTop'] = $container.css('margin-top'); 20123 $container.attr('buffer-scrollTop', scrollTop); 20124 20125 $container.css('margin-top', parseFloat($container.css('margin-top')) - scrollTop); 20126 document.body.scrollTop = document.documentElement.scrollTop = 0; 20127 $html.addClass('scroll-lock'); 20128 $('.add-to-cart-modal').wrap('<div class="add-to-cart-modal-wrapper"></div>'); 20129 20130 // add wrapper to close button 20131 $('.add-to-cart-modal-wrapper').off('click.Dialog.CloseButtons').on('click.Dialog.CloseButtons', '.ui-dialog-titlebar-close, .btn.continue-shopping', function(event) { 20132 closeAddToCartModal(); 20133 }); 20134 20135 // add 'show' class to overlay for nice animate in
20136 var $overlay = $('.add-to-cart-modal-wrapper').parent().find('.ui-widget-overlay'); 20137 $overlay.addClass('add-to-cart-overlay'); 20138 $overlay.addClass('show'); 20139 20140 $('.add-to-cart-modal-wrapper').off('click.Dialog.Close').on('click.Dialog.Close', function(event) { 20141 // only call this block if the ui-widget background is clicked 20142 if ($(event.target).closest('.add-to-cart-modal').length <= 0 && $(event.target).closest('.address-autocomplete-dialog').length <= 0) { 20143 closeAddToCartModal(); 20144 } 20145 }); 20146 20147 if (parseFloat($('.add-to-cart-modal').css('top')) < 0) { 20148 $('.add-to-cart-modal').css('top', '0'); 20149 } 20150 20151 // move title from main content to top of the modal 20152 var $addMessage = $('.add-to-cart-modal-content .main-content .added-message'); 20153 if ($addMessage.length > 0) { 20154 $('.add-to-cart-modal-content').prepend($addMessage); 20155 } 20156 20157 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 20158 var fulfillmentType = $('.bopis-add-to-cart-options-container').find('input[name="AddToCartOption"]:checked').val(); 20159 var isBopis = fulfillmentType && (fulfillmentType == 'shiptostorepickup' || fulfillmentType == 'pickup'); 20160 var bopisStoreName = ''; 20161 var bopisStoreAddress = ''; 20162 if (isBopis) { 20163 bopisStoreName = $('.bopis-add-to-cart-options-store-selector .selected-store').attr('store-name'); 20164 bopisStoreAddress = $('.bopis-add-to-cart-options-store-selector .selected-store').attr('store-address'); 20165 if (bopisStoreAddress && bopisStoreAddress.length > 0) { 20166 $('.modal-mini-cart-store-message-container').removeClass('d-none'); 20167 $('.modal-mini-cart-store-message-container').find('.modal-mini-cart-store-details').html('<strong>' +bopisStoreName+ '</strong><br />' +bopisStoreAddress); 20168 } 20169 } 20170 } 20171 20172 var $containers = $('.add-to-cart-modal').find('.accordion, .section-offers'); 20173 if ($containers.length > 0) { 20174 $containers.each(function() { 20175 var $container = $(this); 20176 if ($container.find('.product-tile').length > 0) { 20177 var $containerHeader = $container.find('.accordion-head h5, .section-head h2').first(); 20178 var $containerHeaderCheck = $containerHeader.find('span'); 20179 if ($containerHeaderCheck.length > 0) { 20180 $containerHeader = $containerHeaderCheck; 20181 } 20182 20183 if ($containerHeader.length > 0) { 20184 var dataObject = { 20185 promotion_id: 'addtocartmodal', 20186 promotion_name: 'Add to Cart Modal' 20187 20188 } 20189 20190 GoogleTagManagerClient.PushDataLayerForDataLayerType('ViewPromotion', dataObject, { Container: $container }); 20191 } 20192 } 20193 }); 20194 } 20195 20196 if (pageContext.site === SiteConstants.SiteIds.BootBarnRspUS) { 20197 $.validator.addMethod('requiredExcludingPunctuation', ValidationHelper.ValidateRequiredExcludingPunctuation, Resources.INVALID_VALUE); 20198 $.validator.addMethod('zipCode', ValidationHelper.ValidateZipCode, Resources.INVALID_ZIP_CODE); 20199 $.validator.addMethod('postalCode', ValidationHelper.ValidatePostalCode, Resources.INVALID_POSTAL_CODE); 20200 var $addToCartModalForm = $('.add-to-cart-modal-wrapper form'); 20201 var addToCartModalFormValidator = $addToCartModalForm.validate(); 20202 addToCartModalFormValidator.settings.onfocusout = ValidationSettings.Checkout.onfocusout; 20203 addToCartModalFormValidator.settings.errorPlacement = ValidationSettings.Checkout.errorPlacement; 20204 if ($addToCartModalForm.find('select[name$="_country"]').val() == 'US') { 20205 $addToCartModalForm.find('input[name$="_postalCode"]').rules('add', ValidationRules.ZipCode); 20206 } else { 20207 $addToCartModalForm.find('input[name$="_postalCode"]').rules('add', ValidationRules.PostalCode); 20208 } 20209 20210 if (pageContext.options && pageContext.options.Lob && pageContext.options.Lob.AddressAutocomplete.Enabled) { 20211 AddressAutocompleteDialog = require('../../Lob/AddressAutocomplete/AddressAutocompleteDialog'); 20212 $(document).on('keyup.AddressAutocomplete', 'input[type="text"]', function (event) { 20213 var $this = $(this); 20214 var $form = $this.closest('form'); 20215 20216 if (event.keyCode == 8 || event.keyCode == 46) { 20217 $this.parent().find('.address-autocomplete-dialog').remove(); 20218 } else if ($this.attr('id').indexOf('_address1') >= 0 || $this.attr('id').indexOf('_city') >= 0 || $this.attr('id').indexOf('_postalCode') >= 0) { 20219 var addressAutocompleteHandler = function (addressAutocompleteData) { 20220 AddressAutocompleteDialog.initialize(pageContext.options, addressAutocompleteData); 20221 } 20222 20223 AddressVerificationHelper.AutocompleteAddress($form, $this, pageContext.options).then(addressAutocompleteHandler); 20224 } else { 20225 $this.parent().find('.address-autocomplete-dialog').remove(); 20226 } 20227 }); 20228 20229 $(document).on('SetAddressFromAddressAutocomplete', function (event, data) { 20230 AddressVerificationHelper.SetAddressFromAddressVerificationDialog(data.$form, data.Address); 20231 }); 20232 } 20233 20234 // if (pageContext.options && pageContext.options.Lob && pageContext.options.Lob.AddressVerification.Enabled) { 20235 // AddressVerificationDialog = require('../../Lob/AddressVerification/AddressVerificationDialog'); 20236 // $(document).off('click.AddToCartGoToCart').on('click.AddToCartGoToCart', '.add-to-cart-modal-wrapper .btn.go-to-cart', function (event) { 20237 // event.preventDefault(); 20238 // event.stopImmediatePropagation(); 20239 20240 // var $addToCartModalForm = $(this).closest('.add-to-cart-modal-wrapper form'); 20241 // var addressDeliverable = function ($form) {
20242 // submitForm(); 20243 // } 20244 20245 // var addressNotDeliverable = function (addressVerifyData) { 20246 // AddressVerificationDialog.initialize($.extend({ 20247 // $form: $addToCartModalForm, 20248 // successCallback: submitForm, 20249 // continueCallback: submitForm 20250 // }, pageContext.options), 'shipping', addressVerifyData); 20251 // } 20252 // AddressVerificationHelper.VerifyAddress($addToCartModalForm, pageContext.options).then(addressDeliverable, addressNotDeliverable); 20253 // }); 20254 20255 // $(document).off('SetAddressFromAddressVerification').on('SetAddressFromAddressVerification', function (event, data) { 20256 // AddressVerificationHelper.SetAddressFromAddressVerificationDialog(data.$form, data); 20257 // }); 20258 // } 20259 20260 $(document).on('change', '.add-to-cart-modal-wrapper #dwfrm_shippingaddress_country', function (event) { 20261 var $this = $(this); 20262 var $country = $this.find('option:selected'); 20263 var country = $country.val(); 20264 var stateListData = $country.data('options'); 20265 var stateList; 20266 if (stateListData) { 20267 try { 20268 stateList = JSON.parse(stateListData.replace(/\'/g, '\"')); 20269 } catch (exception) { } 20270 20271 if (stateList) { 20272 var stateListHtml; 20273 var postalCodeType; 20274 var postalCodePlaceholder; 20275 if (country == 'US') { 20276 stateListHtml = '<option class="select-option" label="State" selected disabled>State</option>'; 20277 postalCodeType = 'number'; 20278 postalCodePlaceholder = 'zip code'; 20279 $addToCartModalForm.find('input[name$="_postalCode"]').rules('add', 'postalCode zipCode'); 20280 $addToCartModalForm.find('input[name$="_postalCode"]').rules('remove', ValidationRules.ZipCode); 20281 } else if (country == 'CA') { 20282 stateListHtml = '<option class="select-option" label="Province" selected disabled>Province</option>'; 20283 postalCodeType = 'text'; 20284 postalCodePlaceholder = 'postal code'; 20285 $addToCartModalForm.find('input[name$="_postalCode"]').rules('remove', 'postalCode zipCode'); 20286 $addToCartModalForm.find('input[name$="_postalCode"]').rules('add', ValidationRules.PostalCode); 20287 } else { 20288 stateListHtml = '<option class="select-option" label="Province/State" selected disabled>Province/State</option>'; 20289 postalCodeType = 'text'; 20290 postalCodePlaceholder = 'postal code'; 20291 $addToCartModalForm.find('input[name$="_postalCode"]').rules('remove', 'postalCode zipCode'); 20292 $addToCartModalForm.find('input[name$="_postalCode"]').rules('add', ValidationRules.PostalCode); 20293 } 20294 for (var stateListKey in stateList) { 20295 var state = stateList[stateListKey]; 20296 stateListHtml += '<option class="select-option" label="' + state.label + '" value="' + state.code + '">' + state.label + '</option>'; 20297 } 20298 $('.add-to-cart-modal-wrapper #dwfrm_shippingaddress_states_state').html(stateListHtml); 20299 $('.add-to-cart-modal-wrapper #addtocartmodal_postalCode').attr('type', postalCodeType); 20300 $('.add-to-cart-modal-wrapper #addtocartmodal_postalCode').attr('placeholder', postalCodePlaceholder); 20301 } 20302 } 20303 }); 20304 20305 $(document).off('click.AddToCartGoToCart').on('click.AddToCartGoToCart', '.add-to-cart-modal-wrapper .btn.go-to-cart', function (event) { 20306 event.preventDefault(); 20307 event.stopImmediatePropagation(); 20308 20309 if (addToCartModalFormValidator.valid()) { 20310 $addToCartModalForm.trigger('submit'); 20311 } else { 20312 $addToCartModalForm.find('input.required.field.error').eq(0).focus(); 20313 } 20314 }); 20315 } 20316 20317 $('.add-to-cart-modal-wrapper').addClass('show'); 20318 }, 20319 close: function(event, ui) { 20320 var $html = $('html'); 20321 var $container = $('#wrapper'); 20322 20323 $html.removeClass('scroll-lock'); 20324 20325 if (dataBuffer['wrapperScrollTop'] > 0) { 20326 document.body.scrollTop = document.documentElement.scrollTop = dataBuffer['wrapperScrollTop']; 20327 } 20328 $container.css('margin-top', parseFloat(dataBuffer['wrapperMarginTop'])); 20329 20330 $('.add-to-cart-modal').unwrap(); 20331 } 20332 } 20333 }); 20334 20335 $('.add-to-cart-modal .added-message .count').text('Item'); 20336 } 20337 } 20338 }); 20339 } 20340 if ( $('.banner-cart-holder .btn-minicart').length > 0 ) { 20341 $.ajax({ 20342 url : Urls.cartMiniCart, 20343 data : {desktop: '1'}, 20344 dataType: 'html', 20345 success : function(data) { 20346 $('.banner-cart-holder .btn-minicart').remove(); 20347 $('.banner-cart-holder').append(data); 20348 } 20349 }); 20350 $.ajax({ 20351 url : Urls.cartMiniCart, 20352 dataType: 'html', 20353 success : function(data) { 20354 var parentMiniCart = $('.top-banner-inner-links #mini-cart'); 20355 if (parentMiniCart.length > 0) { 20356 $('.top-banner-inner-links #mini-cart a.mini-cart-link').remove(); 20357 parentMiniCart.append(data); 20358 } 20359 } 20360 }); 20361 } 20362 // do not close quickview if adding individual item that is part of product set 20363 // @TODO should notify the user some other way that the add action has completed successfully 20364 if (!$(this).hasClass('sub-product-item')) { 20365 dialog.close(); 20366 } 20367 if(SitePreferences.ADD_TO_CART_MODAL != true){ 20368 minicart.show(response); 20369 } 20370 } 20371 }.bind(this)); 20372 20373}; 20374 20375/** 20376 * @description Handler to handle the add all items to cart event 20377 */ 20378var addAllToCart = function (e) { 20379 e.preventDefault(); 20380 var $productForms = $('#product-set-list').find('form').toArray(); 20381 TPromise.all(_.map($productForms, addItemToCart)) 20382 .then(function (responses) { 20383 dialog.close(); 20384 // show the final response only, which would include all the other items 20385 minicart.show(responses[responses.length - 1]); 20386 }); 20387}; 20388 20389/** 20390 * @function 20391 * @description Binds the click event to a given target for the add-to-cart handling 20392 */ 20393module.exports = function () { 20394 $('.add-to-cart[disabled]').attr('title', $('.availability-msg').text()); 20395 $('.product-detail').on('click', '.add-to-cart:not([disabled]):not([loading])', addToCart); 20396 $(document).on('ProductDetailPage.Bopis.AddItemToCart', addItemToCart); 20397 $(document).on('ProductDetailPage.Bopis.AddToCart', addToCart); 20398 $('#add-all-to-cart').on('click', addAllToCart); 20399}; 20400 20401},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/AddressVerification/AddressVerificationHelper":112,"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../../../../bc_sheplersbootbarn_core/cartridge/scripts/util/ValidationHelper":124,"../../Lob/AddressAutocomplete/AddressAutocompleteDialog":1,"../../ajax":3,"../../dialog":36,"../../minicart":45,"../../page":46,"../../util":102,"lodash":133,"promise":134}],73:[function(require,module,exports){ 20402'use strict'; 20403 20404var ajax = require('../../ajax'), 20405 util = require('../../util'); 20406 20407var updateContainer = function (data) { 20408 var $availabilityMsg = $('#pdpMain .availability .availability-msg'); 20409 var message; // this should be lexically scoped, when `let` is supported (ES6) 20410 if (!data) { 20411 $availabilityMsg.html(Resources.ITEM_STATUS_NOTAVAILABLE); 20412 return; 20413 } 20414 $availabilityMsg.empty(); 20415 // Look through levels ... if msg is not empty, then create span el 20416 if (data.levels.IN_STOCK > 0) { 20417 if (data.levels.PREORDER === 0 && data.levels.BACKORDER === 0 && data.levels.NOT_AVAILABLE === 0) { 20418 // Just in stock 20419 message = Resources.IN_STOCK; 20420 } else { 20421 // In stock with conditions ... 20422 message = data.inStockMsg; 20423 } 20424 $availabilityMsg.append('<p class="in-stock-msg">' + message + '</p>'); 20425 } 20426 if (data.levels.PREORDER > 0) { 20427 if (data.levels.IN_STOCK === 0 && data.levels.BACKORDER === 0 && data.levels.NOT_AVAILABLE === 0) { 20428 message = Resources.PREORDER; 20429 } else { 20430 message = data.preOrderMsg; 20431 } 20432 $availabilityMsg.append('<p class="preorder-msg">' + message + '</p>'); 20433 } 20434 if (data.levels.BACKORDER > 0) { 20435 if (data.levels.IN_STOCK === 0 && data.levels.PREORDER === 0 && data.levels.NOT_AVAILABLE === 0) { 20436 message = Resources.BACKORDER; 20437 } else { 20438 message = data.backOrderMsg; 20439 } 20440 $availabilityMsg.append('<p class="backorder-msg">' + message + '</p>'); 20441 } 20442 if (data.inStockDate !== '') { 20443 $availabilityMsg.append('<p class="in-stock-date-msg">' + String.format(Resources.IN_STOCK_DATE, data.inStockDate) + '</p>'); 20444 } 20445 if (data.levels.NOT_AVAILABLE > 0) { 20446 if (data.levels.PREORDER === 0 && data.levels.BACKORDER === 0 && data.levels.IN_STOCK === 0) { 20447 message = Resources.NOT_AVAILABLE; 20448 } else { 20449 message = Resources.REMAIN_NOT_AVAILABLE; 20450 } 20451 $availabilityMsg.append('<p class="not-available-msg">' + message + '</p>'); 20452 } 20453}; 20454 20455var getAvailability = function () { 20456 ajax.getJson({ 20457 url: util.appendParamsToUrl(Urls.getAvailability, { 20458 pid: $('#pid').val(), 20459 Quantity: $(this).val() 20460 }), 20461 //callback: updateContainer 20462 }); 20463}; 20464 20465module.exports = function () { 20466 $('#pdpMain').on('change', '.pdpForm input[name="Quantity"]', getAvailability); 20467}; 20468 20469},{"../../ajax":3,"../../util":102}],74:[function(require,module,exports){ 20470'use strict'; 20471var dialog = require('../../dialog'); 20472var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 20473var util = require('../../util'); 20474 20475var zoomMediaQuery = matchMedia('(min-width: 960px)'); 20476 20477/**
20478 * @description Enables the zoom viewer on the product detail page 20479 * @param zmq {Media Query List} 20480 */ 20481var loadZoom = function (zmq) { 20482 var $imgZoom = $('#pdpMain .main-image'), 20483 hiresUrl; 20484 if (!zmq) { 20485 zmq = zoomMediaQuery; 20486 } 20487 if ($imgZoom.length === 0 || dialog.isActive() || util.isMobile() || !zoomMediaQuery.matches) { 20488 // remove zoom 20489 $imgZoom.trigger('zoom.destroy'); 20490 return; 20491 } 20492 hiresUrl = $imgZoom.attr('href'); 20493 20494 if (hiresUrl && hiresUrl !== 'null' && hiresUrl.indexOf('noimagelarge') === -1 && zoomMediaQuery.matches) { 20495 $imgZoom.zoom({ 20496 url: hiresUrl 20497 }); 20498 } 20499}; 20500 20501zoomMediaQuery.addListener(loadZoom); 20502 20503/** 20504 * @description Sets the main image attributes and the href for the surrounding <a> tag 20505 * @param {Object} atts Object with url, alt, title and hires properties 20506 */ 20507var setMainImage = function (atts) { 20508 $('#pdpMain .primary-image').attr({ 20509 src: atts.url, 20510 alt: atts.alt, 20511 title: atts.title 20512 }); 20513 if (!dialog.isActive() && !util.isMobile()) { 20514 $('#pdpMain .main-image').attr('href', atts.hires); 20515 } 20516 loadZoom(); 20517}; 20518 20519/** 20520 * @description Replaces the images in the image container, for eg. when a different color was clicked. 20521 */ 20522 20523var replaceImages = function () { 20524 20525 var $newImages = $('#update-images'), 20526 $win = $(window), 20527 $imageContainer, 20528 $header, 20529 $promosClone, 20530 $promosCloneMobile, 20531 newImage = new Image(); 20532 20533 if ($win.width() <= 1024) { 20534 $header = $('#pdpMain .product-image-container').find('header').clone(); 20535 } 20536 if ($newImages.length === 0) { return; } 20537 20538 // product container classes to handle styles while image is loading 20539 $('#pdpMain .product-image-container').addClass('loading-image'); 20540 newImage.src = $newImages.find('.product-primary-image [class*="slide"]').first().find('img').attr('src'); 20541 newImage.onload = function() { 20542 $('#pdpMain .product-image-container').removeClass('loading-image'); 20543 } 20544 20545 var attachPromosMobile = function() { 20546 if (pageContext.site === SiteConstants.SiteIds.SheplersUS || pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 20547 var $imageContainerMobile = $('#pdpMain .product-image-container'); 20548 } else { 20549 var $imageContainerMobile = $('#pdpMain .product-image-container-mobile'); 20550 } 20551 var $promoMessagesMobile = $('#pdpMain .product-image-container-mobile .promo-messages'), 20552 $promosCloneMobile = $promoMessagesMobile.find('.promo-messages').clone(); 20553 20554 if ($promoMessagesMobile.is(':empty') && $promosCloneMobile.length > 0) { 20555 $imageContainerMobile.html($newImages.html()); 20556 $("<div class='promo-messages'></div>").prependTo($imageContainerMobile); 20557 $promosCloneMobile.prependTo($promoMessagesMobile); 20558 } 20559 else { 20560 $imageContainerMobile.html($newImages.html()); 20561 $promosCloneMobile.prependTo($imageContainerMobile); 20562 } 20563 }; 20564 20565 var attachPromosDesktop = function() { 20566 var $imageContainer = $('#pdpMain .product-image-container'), 20567 $promoMessages = $('#pdpMain .product-image-container .promo-messages'), 20568 $promosClone = $promoMessages.clone(); 20569 20570 //window.console.log("$promoMessages: ",$promoMessages.length, " $promosClone.length: ", $promosClone.length); 20571 20572 if ($promoMessages.is(':empty') && $promosClone.length > 0) { 20573 $imageContainer.html($newImages.html()); 20574 $("<div class='promo-messages'></div>").prependTo($imageContainer); 20575 $promosClone.prependTo($promoMessages); 20576 } 20577 else { 20578 $imageContainer.html($newImages.html()); 20579 $promosClone.prependTo($imageContainer); 20580 } 20581 }; 20582 20583 if ($win.width() <= 767 ) { 20584 attachPromosMobile(); 20585 } 20586 else { 20587 attachPromosDesktop(); 20588 } 20589 20590 $newImages.remove(); 20591 loadZoom(); 20592}; 20593 20594/* @module image 20595 * @description this module handles the primary image viewer on PDP 20596 **/ 20597 20598/** 20599 * @description by default, this function sets up zoom and event handler for thumbnail click 20600 **/ 20601module.exports = function () { 20602 if (dialog.isActive() || util.isMobile()) { 20603 $('#pdpMain .main-image').removeAttr('href'); 20604 } 20605 loadZoom(); 20606 // handle product thumbnail click event 20607 $('#pdpMain').on('click', '.productthumbnail', function () { 20608 // switch indicator 20609 $(this).closest('.product-thumbnails').find('.thumb.selected').removeClass('selected'); 20610 $(this).closest('.thumb').addClass('selected'); 20611 20612 setMainImage($(this).data('lgimg')); 20613 }); 20614};
20615module.exports.loadZoom = loadZoom; 20616module.exports.setMainImage = setMainImage; 20617module.exports.replaceImages = replaceImages; 20618 20619},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../dialog":36,"../../util":102}],75:[function(require,module,exports){ 20620'use strict'; 20621 20622var ApplePay = require('../checkout/ApplePay'); 20623var dialog = require('../../dialog'); 20624var productStoreInventory = require('../../storeinventory/product'); 20625var tooltip = require('../../tooltip'); 20626var util = require('../../util'); 20627var addToCart = require('./addToCart'); 20628var availability = require('./availability'); 20629var image = require('./image'); 20630var video = require('./video'); 20631var productSet = require('./productSet'); 20632var variant = require('./variant'); 20633var recaptcha = require('../../components/Recaptcha'); 20634var recentlyViewedProducts = require('../../components/RecentlyViewedProducts'); 20635var relevantProductRecommendations = require('../../components/RelevantProductRecommendations'); 20636var sameDayShippingCountdown = require('../../components/SameDayShippingCountdown'); 20637var ShopPay = require('../../../../../int_shoppay_sfra/cartridge/client/default/js/cart/initShopPayCart'); 20638var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 20639 20640var options = {}; 20641var loaded = {}; 20642var dataBuffer = {}; 20643 20644/** 20645 * @description Initialize product detail page with reviews, recommendation and product navigation. 20646 */ 20647function initializeDom(options) { 20648 tooltip.init(); 20649 20650 var $sameDayShippingCountdownContainer = $('.same-day-shipping-countdown'); 20651 if ($sameDayShippingCountdownContainer.length > 0) { 20652 sameDayShippingCountdown.initialize($sameDayShippingCountdownContainer, options.SameDayShipping); 20653 } 20654 20655 $('.accordion').each(function() { 20656 var $this = $(this); 20657 if (!$this.hasClass('product-features') || window.innerWidth <= 768) { 20658 $this.find('.accordion-head').addClass('active'); 20659 $this.find('.accordion-body').css('display', 'block'); 20660 } 20661 }); 20662} 20663 20664/** 20665 * @description Initialize event handlers on product detail page 20666 */ 20667function initializeEvents(options) { 20668 var $pdpMain = $('#pdpMain'); 20669 20670 addToCart(); 20671 availability(); 20672 image(); 20673 video(); 20674 productSet(); 20675 20676 if (SitePreferences.STORE_PICKUP) { 20677 productStoreInventory.init(); 20678 } 20679 20680 $(document).on('click', '.product-swatches-accordion-button', function () { 20681 var $accordion = $(this).closest('.accordion'); 20682 20683 if ($accordion.length > 0) { 20684 $accordion.toggleClass('active'); 20685 } 20686 }); 20687 20688 // Add to Wishlist and Add to Gift Registry links behaviors 20689 $pdpMain.on('click', '[data-action="gift-registry"]', function () { 20690 var data = util.getQueryStringParams($('.pdpForm').serialize()); 20691 if (data.cartAction) { 20692 delete data.cartAction; 20693 } 20694 var url = util.appendParamsToUrl(this.href, data); 20695 this.setAttribute('href', url); 20696 }); 20697 20698 // product options 20699 $pdpMain.on('change', '.product-options select', function () { 20700 var salesPrice = $pdpMain.find('.product-add-to-cart .price-sales'); 20701 var selectedItem = $(this).children().filter(':selected').first(); 20702 salesPrice.text(selectedItem.data('combined')); 20703 }); 20704 20705 // prevent default behavior of thumbnail link and add this Button 20706 $pdpMain.on('click', '.thumbnail-link, .unselectable a', function (e) { 20707 e.preventDefault(); 20708 }); 20709 20710 $pdpMain.on('click', 'a.size-chart-link', function (e) { 20711 e.preventDefault(); 20712 dialog.open({ 20713 url: $(e.target).attr('href') 20714 }); 20715 }); 20716 20717 // Technology Features Tooltip 20718 // $('.list-product-info figure img').each(function() { 20719 // var $img = $(this), 20720 // $target = $img.parents('li').first().find('.tooltip-content img'); 20721 20722 // $target.attr("src", $img.data('hover')).attr("alt", $img.attr("alt")).attr("width", "236px"); 20723 // }); 20724 20725 // $('.list-product-info').tooltip({ 20726 // items: 'li', 20727 // tooltipClass: 'techfeature-tooltip', 20728 // track: true, 20729 // content: function () { 20730 // return $(this).find('.tooltip-content').html(); 20731 // } 20732 // }); 20733 20734 20735 $(document).on('click','.searchagain-btn',function() { 20736 $('#dialog-container .findStore-result').hide(); 20737 $('#dialog-container .ui-dialog-footer').show(); 20738 $('.ui-dialog').css({'height' : '230px !important','top':'260px !important'}); 20739 }); 20740 20741 $(document).on('click','.find-store-btn',function() { 20742 dialog.open({ 20743 html:($('.findStoreDialog').html()).replace(/select-holder/g,''), 20744 callback: function() { 20745 $(document).on('click','.findstore-formContainer .findStore-btn',function() { 20746 var zipcode = $('#dialog-container input.zipcode').val(), 20747 radius = $('#dialog-container select.radius').val(), 20748 postalcode = $('#dialog-container .postalcode select').val(), 20749 statecode = $('#dialog-container .statecode select').val(), 20750 pid = $('#dialog-container #pid').val(), 20751 values = { 20752 pid : pid, 20753 zipCode : zipcode,
20754 radius : radius, 20755 statecode : statecode, 20756 postalcode : postalcode 20757 }; 20758 20759 $.ajax({ 20760 url: Urls.storeavailability, 20761 type: "GET", 20762 data: values , 20763 success: function (response) { 20764 $('#dialog-container .findStore-result').show(); 20765 $('#dialog-container .ui-dialog-footer').hide(); 20766 $('#dialog-container .findStore-result').html(response).text(); 20767 20768 }, 20769 error: function(jqXHR, textStatus, errorThrown) { 20770 console.log(textStatus, errorThrown); 20771 } 20772 }); 20773 }); 20774 }, 20775 options: { 20776 title: Resources.FINDSTORE_TITLE 20777 }, 20778 }); 20779 return false; 20780 }); 20781 20782 $(document).off('RecentlyViewedProducts.Done').on('RecentlyViewedProducts.Done', function(event) { 20783 loaded.RecentlyViewedProducts = true; 20784 addPromotionDataLayers(); 20785 }); 20786 20787 $(document).off('EinsteinProductRecommendations.Done').on('EinsteinProductRecommendations.Done', function(event) { 20788 loaded.EinsteinProductRecommendations = true; 20789 addPromotionDataLayers(); 20790 }); 20791 20792 $(document).off('RelevantProductRecommendations.Done').on('RelevantProductRecommendations.Done', function(event) { 20793 loaded.RelevantProductRecommendations += 1; 20794 addPromotionDataLayers(); 20795 }); 20796 20797 $(document).off('SFCCProductRecommendations.Done').on('SFCCProductRecommendations.Done', function(event) { 20798 loaded.SFCCProductRecommendations = true; 20799 addPromotionDataLayers(); 20800 }); 20801} 20802 20803function addPromotionDataLayers() { 20804 if (loaded.RecentlyViewedProducts && loaded.EinsteinProductRecommendations && loaded.SFCCProductRecommendations && loaded.RelevantProductRecommendations == dataBuffer['RelevantProductRecommendationsCount']) { 20805 $(document).trigger('GoogleTagManager.AddPromotionDataLayers'); 20806 } 20807} 20808 20809var product = { 20810 initializeEvents: initializeEvents, 20811 init: function (optionsParameter) { 20812 options = optionsParameter; 20813 loaded = { 20814 RecentlyViewedProducts: false, 20815 EinsteinProductRecommendations: false, 20816 RelevantProductRecommendations: 0 20817 }; 20818 dataBuffer = { 20819 RelevantProductRecommendationsCount: 0 20820 }; 20821 20822 if (options && options.RecentlyViewedProducts) { 20823 recentlyViewedProducts.initialize(options.RecentlyViewedProducts); 20824 } else { 20825 loaded.RecentlyViewedProducts = true; 20826 } 20827 20828 if (!options || !options.EinsteinProductRecommendations) { 20829 loaded.EinsteinProductRecommendations = true; 20830 } 20831 20832 if (options && options.RelevantProductRecommendations) { 20833 dataBuffer['RelevantProductRecommendationsCount'] = options.RelevantProductRecommendations.Containers.length; 20834 relevantProductRecommendations.initialize(options.RelevantProductRecommendations); 20835 } 20836 20837 variant.initialize(options); 20838 20839 initializeDom(options); 20840 initializeEvents(options); 20841 ApplePay.initialize(options); 20842 } 20843}; 20844 20845module.exports = product; 20846 20847},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../int_shoppay_sfra/cartridge/client/default/js/cart/initShopPayCart":126,"../../components/Recaptcha":29,"../../components/RecentlyViewedProducts":30,"../../components/RelevantProductRecommendations":31,"../../components/SameDayShippingCountdown":32,"../../dialog":36,"../../storeinventory/product":98,"../../tooltip":101,"../../util":102,"../checkout/ApplePay":53,"./addToCart":72,"./availability":73,"./image":74,"./productSet":76,"./variant":77,"./video":78}],76:[function(require,module,exports){ 20848'use strict'; 20849 20850var ajax = require('../../ajax'), 20851 tooltip = require('../../tooltip'), 20852 util = require('../../util'); 20853 20854module.exports = function () { 20855 var $addToCart = $('#add-to-cart'), 20856 $addAllToCart = $('#add-all-to-cart'), 20857 $productSetList = $('#product-set-list'); 20858 20859 var updateAddToCartButtons = function () { 20860 if ($productSetList.find('.add-to-cart[disabled]').length > 0) { 20861 $addAllToCart.attr('disabled', 'disabled'); 20862 // product set does not have an add-to-cart button, but product bundle does 20863 $addToCart.attr('disabled', 'disabled'); 20864 } else { 20865 $addAllToCart.removeAttr('disabled'); 20866 $addToCart.removeAttr('disabled'); 20867 } 20868 }; 20869 20870 if ($productSetList.length > 0) { 20871 updateAddToCartButtons(); 20872 } 20873 // click on swatch for product set 20874 $productSetList.on('click', '.product-set-item .swatchanchor', function (e) { 20875 e.preventDefault(); 20876 if ($(this).parents('li').hasClass('unselectable')) { return; } 20877 var url = Urls.getSetItem + this.search; 20878 var $container = $(this).closest('.product-set-item'); 20879 var qty = $container.find('form input[name="Quantity"]').first().val(); 20880 20881 ajax.load({ 20882 url: util.appendParamToURL(url, 'Quantity', isNaN(qty) ? '1' : qty), 20883 target: $container, 20884 callback: function () { 20885 updateAddToCartButtons(); 20886 tooltip.init(); 20887 } 20888 }); 20889 }); 20890}; 20891 20892},{"../../ajax":3,"../../tooltip":101,"../../util":102}],77:[function(require,module,exports){ 20893'use strict'; 20894 20895var _ = require('lodash'); 20896var ajax = require('../../ajax'); 20897var image = require('./image'); 20898var GoogleTagManagerClient = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 20899var productStoreInventory = require('../../storeinventory/product'); 20900var rating = require('../../rating'); 20901var tooltip = require('../../tooltip'); 20902var util = require('../../util'); 20903var bopisAddToCartOptions = require('../../bopis/components/AddToCartOptions'); 20904var bopisStoreSearch = require('../../bopis/components/StoreSearch'); 20905var wishlist = require('../../wishlist'); 20906var sliders = require('../../sliders'); 20907var imageGallery; 20908 20909var SiteConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 20910var TemplateConstants = require('../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 20911 20912var html = {}; 20913var data = {}; 20914var loaded = {}; 20915var options; 20916 20917function initializeDom() { 20918 loaded['content'] = true; 20919 20920 updateCSRFToken(); 20921 20922 var selectorPayload = util.getQueryStringParams($('.pdpForm').serialize()); 20923 20924 var queryStringParameters = util.getQueryStringParams(util.getQueryString(util.appendParamsToUrl(window.location.toString(), selectorPayload))); 20925 for (var parameter in queryStringParameters) { 20926 selectorPayload[parameter] = queryStringParameters[parameter]; 20927 } 20928 20929 var sizeValue = util.getPreferenceValueFromWindowLocation('size'); 20930 if (sizeValue) { 20931 selectorPayload.setSize = sizeValue; 20932 } 20933 20934 buildSelectors(selectorPayload); 20935 $('.btn.add-to-cart').removeAttr('disabled').removeAttr('loading').find('.loading-indicator-container').remove(); 20936} 20937 20938function updateProductInfo() { 20939 $('li.selected-value').each(function() { 20940 var $selectedItem = $(this); 20941 $selectedItem.parents('.attribute').first().find('.label .current, .select-dropdown .select-text').html($selectedItem.html()); 20942 }); 20943} 20944 20945function reloadSubdimensionsWidget(subdimensionHTML) { 20946 $('#tt-subdimension-teaser').html(subdimensionHTML); 20947} 20948 20949function updateCSRFToken() { 20950 $.ajax({ 20951 method: 'get', 20952 url: Urls.CSRFToken.Get, 20953 dataType: 'json', 20954 success: function(response) { 20955 $('#csrftoken').val(response.token); 20956 } 20957 }); 20958} 20959 20960function updatePid() { 20961 if (data['pid']) { 20962 $('#pid').val(data['pid']); 20963 } 20964} 20965 20966function buildSelectors(payload) { 20967 loaded['selectors'] = false;
20968 20969 if (!payload) { 20970 payload = util.getQueryStringParams($('.pdpForm').serialize()); 20971 } 20972 20973 var templates = []; 20974 templates['variations'] = _.template($('#template-variations').html(), TemplateConstants.Lodash.Settings); 20975 templates['variationSelector'] = _.template($('#template-variations-selector').html(), TemplateConstants.Lodash.Settings); 20976 templates['variationSelectorAttributeGuide'] = _.template($('#template-variations-attribute-guide').html(), TemplateConstants.Lodash.Settings); 20977 templates['variationSelectorDropdown'] = _.template($('#template-variations-selector-dropdown').html(), TemplateConstants.Lodash.Settings); 20978 templates['variationSelectorDropdownOption'] = _.template($('#template-variations-selector-dropdown-option').html(), TemplateConstants.Lodash.Settings); 20979 templates['variationSelectorDropdownOptionSelected'] = _.template($('#template-variations-selector-dropdown-option-selected').html(), TemplateConstants.Lodash.Settings); 20980 templates['variationSelectorSwatch'] = _.template($('#template-variations-selector-swatch').html(), TemplateConstants.Lodash.Settings); 20981 templates['variationSelectorSwatchOption'] = _.template($('#template-variations-selector-swatch-option').html(), TemplateConstants.Lodash.Settings); 20982 templates['variationSelectorSwatchOptionUnselectable'] = _.template($('#template-variations-selector-swatch-option-unselectable').html(), TemplateConstants.Lodash.Settings); 20983 20984 data['attributeGuides'] = {}; 20985 20986 $.ajax({ 20987 method: 'post', 20988 url: Urls.getVariationAttributes, 20989 data: payload, 20990 dataType: 'json', 20991 success: function(response) { 20992 html['variationSelectors'] = ''; 20993 data['IsRestrictedByGlobale'] = response.IsRestrictedByGlobale; 20994 20995 // Color Swatch Length Check 20996 var isMultiSwatch; 20997 if (response && 'variations' in response && response.variations.length) { 20998 isMultiSwatch = response.variations.filter(function(variantGroup) { 20999 if (variantGroup && 'type' in variantGroup && 'values' in variantGroup) { 21000 return variantGroup.type == 'swatch' && variantGroup.values.length > 1; // Check for multiple color swatches 21001 } 21002 }); 21003 } 21004 var hasSizeAttribute = false; 21005 if (response && 'variations' in response && response.variations.length) { 21006 hasSizeAttribute = response.variations.filter(function(variantGroup) { 21007 if (variantGroup && 'productVariationAttribute' in variantGroup && 'values' in variantGroup) { 21008 return variantGroup.productVariationAttribute == 'size' && variantGroup.values.length > 1; 21009 } 21010 }); 21011 } 21012 21013 var variations; 21014 if (hasSizeAttribute) { 21015 variations = response.variations; 21016 } else { 21017 variations = response.variations; 21018 } 21019 for (var variation in response.variations) { 21020 var variationData = response.variations[variation]; 21021 var variationDataValueSelected = null; 21022 21023 html['variationSelectorWidgetOptions'] = ''; 21024 21025 for (var variationValue in variationData.values) { 21026 var variationDataValue = variationData.values[variationValue]; 21027 var variationDataValueTemplate; 21028 var variationText = (variationDataValue.attribute === 'size') ? variationDataValue.text.replace(' 1/2', '\u00BD') : variationDataValue.text; 21029 var variationReviewsWidget = (variationDataValue.attribute === 'size' && SitePreferences.TURNTO_ENABLED && SitePreferences.TURNTO_SUBDIMENSIONS_ENABLED) ? '<div id="tt-subdimension-teaser"></div>' : ''; 21030 var widthDescription = variationDataValue.widthDescription ? '<span class="width-description">' + variationDataValue.widthDescription + '</span>' : ''; 21031 var optionAriaLabel = variationDataValue.value; 21032 if (variationDataValue.shipping) { 21033 optionAriaLabel += + ' - ' + variationDataValue.shipping; 21034 } 21035 21036 var variationDataValuePayload = { 21037 attribute: variationDataValue.attribute, 21038 valueId: variationDataValue.valueId, 21039 value: variationDataValue.value, 21040 title: variationDataValue.title, 21041 optionAriaLabel: optionAriaLabel, 21042 text: variationText, 21043 widthDescription: widthDescription, 21044 stock: variationDataValue.stock, 21045 shipping: variationDataValue.shipping, 21046 isSameDayShippingWindow: variationDataValue.isSameDayShippingWindow, 21047 quantitySourceType: variationDataValue.quantitySourceType, 21048 href: variationDataValue.href, 21049 selectable: variationDataValue.selectable ? 'selectable' : 'unselectable', 21050 selected: variationDataValue.selected ? 'selected' : '', 21051 swatchImageUrl: variationDataValue.images.swatch.url, 21052 largeSwatchImageUrl: variationDataValue.images.largeSwatch.url, 21053 hrefAttribute: variationDataValue.selectable ? 'href' : 'xhref' 21054 }; 21055 21056 if (variationData.type == 'swatch') { 21057 if (variationDataValue.selectable) { 21058 variationDataValueTemplate = templates['variationSelectorSwatchOption']; 21059 21060 variationDataValuePayload.imageLarge = JSON.stringify({ 21061 url: variationDataValue.images.large.url, 21062 title: variationDataValue.images.large.title, 21063 alt: variationDataValue.images.large.alt, 21064 hires: variationDataValue.images.hires.url 21065 }); 21066 } else { 21067 variationDataValueTemplate = templates['variationSelectorSwatchOptionUnselectable']; 21068 } 21069 } else { 21070 variationDataValueTemplate = templates['variationSelectorDropdownOption']; 21071 21072 if (variationDataValue.selected) { 21073 variationDataValueSelected = variationDataValue; 21074 } 21075 } 21076 21077 html['variationSelectorWidgetOptions'] += variationDataValueTemplate(variationDataValuePayload); 21078 } 21079 21080 // Add color swatch length boolean to template data 21081 if (variationData.type == 'swatch') { 21082 html['variationSelectorWidget'] = templates['variationSelectorSwatch']({ 21083 attribute: variationData.productVariationAttribute, 21084 options: html['variationSelectorWidgetOptions'], 21085 multiSwatchDisplay: isMultiSwatch.length > 0 ? 'd-block' : 'd-none' 21086 }); 21087 } else { 21088 var placeholder = variationData.label.placeholder, 21089 ariaLabel = variationData.label.placeholder; 21090
21091 if (pageContext.site === SiteConstants.SiteIds.CountryOutfittersUS && variationData.productVariationAttribute === 'size' && variationDataValueSelected === null) { 21092 placeholder += ' (' + variationData.label.message + ')'; 21093 } 21094 21095 if (variationDataValueSelected) { 21096 var variationSelectedText = (variationData.productVariationAttribute === 'size') ? variationDataValueSelected.text.replace(' 1/2', '\u00BD') : variationDataValueSelected.text; 21097 var widthDescription = variationDataValueSelected.widthDescription ? '<span class="width-description">' + variationDataValueSelected.widthDescription + '</span>' : ''; 21098 21099 placeholder = templates['variationSelectorDropdownOptionSelected']({ 21100 text: variationSelectedText, 21101 widthDescription: widthDescription, 21102 stock: variationDataValueSelected.stock, 21103 shipping: variationDataValueSelected.shipping, 21104 isSameDayShippingWindow: variationDataValueSelected.isSameDayShippingWindow, 21105 quantitySourceType: variationDataValueSelected.quantitySourceType 21106 }); 21107 21108 ariaLabel = 'Currently Selected: ' + variationDataValueSelected.value; 21109 if (variationDataValueSelected.shipping) { 21110 ariaLabel += ' - ' + variationDataValueSelected.shipping; 21111 } 21112 } 21113 21114 // Add color swatch length boolean to template data 21115 html['variationSelectorWidget'] = templates['variationSelectorDropdown']({ 21116 attribute: variationData.productVariationAttribute, 21117 text: placeholder, 21118 ariaLabel: ariaLabel, 21119 options: html['variationSelectorWidgetOptions'], 21120 multiSwatchDisplay: isMultiSwatch.length > 0 ? 'd-block' : 'd-none' 21121 }); 21122 } 21123 21124 html['attributeGuide'] = ''; 21125 if (variationData.attributeGuide) { 21126 data['attributeGuides'][variationData.productVariationAttribute] = variationData.attributeGuide; 21127 html['attributeGuide'] = templates['variationSelectorAttributeGuide'](_.extend(variationData.attributeGuide, { Attribute: variationData.productVariationAttribute })); 21128 } 21129 21130 html['variationSelector'] = templates['variationSelector']({ 21131 attribute: variationData.productVariationAttribute, 21132 label: { 21133 text: variationData.label.text, 21134 message: variationData.label.message 21135 }, 21136 selector: html['variationSelectorWidget'], 21137 reviewsWidget: variationReviewsWidget, 21138 guide: html['attributeGuide'] 21139 }); 21140 21141 html['variationSelectors'] += html['variationSelector']; 21142 } 21143 21144 html['selectors'] = templates['variations']({ 21145 selectors: html['variationSelectors'] 21146 }); 21147 21148 data['selected'] = response.selected; 21149 data['pid'] = response.pid; 21150 21151 loaded['selectors'] = true; 21152 renderVariationUpdates(); 21153 } 21154 }); 21155} 21156 21157function setAlternates() { 21158 $('ul.alternate-items li').sort(function(a,b) { return $(a).data('id') - $(b).data('id'); }).appendTo('.alternate-items'); 21159 var altType = $('ul.alternate-items').data('alternate'); 21160 var altDefault = $('ul.alternate-items').data('default'); 21161 var alternates = []; 21162 21163 var isSubscriptionProduct = $('.pdp-main').hasClass('subscription-product-template'); 21164 var colorSelected = $('.color-options .selected a'); 21165 var sizeSelected = $('.size-options .selected a').data('size-id'); 21166 21167 if (colorSelected && isSubscriptionProduct) { 21168 alternates.push({'altID': $(colorSelected).parent('.selected').data('id'), 'altValue': $(colorSelected).attr('data-color-name')}); 21169 } 21170 $('ul.alternate-items li').each(function(i, elem) { 21171 alternates.push({'altID': $(elem).data('id'), 'altValue': $(elem).text().split('-')[1]}); 21172 }); 21173 21174 if (sizeSelected && sizeSelected.length > 0 && $('.alternate').length > 0){ 21175 updateAlternates(sizeSelected); 21176 } else if (alternates && alternates.length > 0){ 21177 $.ajax({ 21178 url: Urls.getItemAlternates, 21179 dataType: 'JSON', 21180 method: 'POST', 21181 data: { 21182 'alternates': JSON.stringify(alternates) 21183 }, 21184 success : function(data) { 21185 var altSwatches = ''; 21186 var alternate = data.result; 21187 21188 $.each(alternate, function(i, e){ 21189 var id = alternate[i].id; 21190 var type = altType ? altType : 'Color'; 21191 var value = alternate[i].value; 21192 var image = alternate[i].image; 21193 var url = $('.alternate-items li[data-id='+id+']').data('url'); 21194 var altHidden = 'show-content'; 21195 if ( i >= 11 ){ 21196 altHidden = 'hidden-content'; 21197 } 21198 if ( isSubscriptionProduct && id == $(colorSelected).parent('.selected').data('id') ){ 21199 $(colorSelected).css('background', 'url('+image+')'); 21200 } else { 21201 altSwatches += '<li class="unselectable alternate ' + altHidden + '" data-id="'+id+'" data-type="'+altType+'" data-value="'+value+'"><a class="swatchanchor" href="'+url+'" title="Select '+altType+': '+value+'" value="'+value+'" style="background: url('+image+'?sw=70&sh=70&sm=fit); background-repeat: no-repeat; background-size: contain; background-position: center;"><span class="visually-hidden">Select '+altType+':'+value+'</span></a></li>'; 21202 } 21203 }); 21204 21205 if (altSwatches.length > 0 ){ 21206 $('.color.color-options').removeClass('color-d-none').append(altSwatches).find('li').sort(function(a,b) { return $(a).data('id') - $(b).data('id'); }).appendTo('.color-options'); 21207 if (altType && altDefault){ 21208 $('.color-options .selected').attr('data-type',altType).attr('data-value',altDefault).find('a.swatchanchor').attr('title','Select '+altType+': '+altDefault); 21209 var newText = '<span class="text">'+altType+'<span class="separator">:</span> <span class="current color-current">'+altDefault+'</span></span>'; 21210 $('.attribute-color .text').html(newText); 21211 } 21212 } 21213 21214 if (sizeSelected && sizeSelected.length > 0){ 21215 updateAlternates(sizeSelected); 21216 } 21217 21218 var altHiddenCount = $('.hidden-content').length; 21219 var altHiddenToggle = '+ ' + altHiddenCount; 21220 if (altHiddenCount > 0){ 21221 $('.hidden-content').hide(); 21222 $('.color.color-options').append('<button class="altButton">' + altHiddenToggle + '</button>'); 21223 } 21224 21225 $('button.altButton').on('click', function(e){ 21226 e.preventDefault(); 21227 $(this).closest('.color-options').find('.hidden-content').toggle(); 21228 $('.altButton').hide(); 21229 }) 21230 21231 $(".color-options li").hover(function(){ 21232 var altTitle = $(this).data('type'); 21233 var altValue = $(this).data('value'); 21234 var newText = '<span class="text">'+altType+'<span class="separator">:</span> <span class="current color-current">'+altValue+'</span></span>'; 21235 $('.attribute-color .text').html(newText); 21236 }, function(){ 21237 var altTitle = $('.color-options .selected').data('type'); 21238 var altValue = $('.color-options .selected').data('value'); 21239 var newText = '<span class="text">'+altType+'<span class="separator">:</span> <span class="current color-current">'+altValue+'</span></span>'; 21240 $('.attribute-color .text').html(newText); 21241 }); 21242 } 21243 }); 21244 } 21245} 21246 21247function updateAlternates(sizeSelected) { 21248 var altupdates = []; 21249 $('ul.color-options li').each(function(i, elem) { 21250 altupdates.push(String($(elem).data('id'))); 21251 }); 21252 21253 if(altupdates && altupdates.length > 0){ 21254 $.ajax({ 21255 url: Urls.updateItemAlternates, 21256 dataType: 'JSON', 21257 method: 'POST', 21258 data: { 21259 'altupdates': JSON.stringify(altupdates), 21260 'size': sizeSelected 21261 }, 21262 success : function(data) { 21263 var alternate = data.result; 21264 21265 $.each(alternate, function(i, e){ 21266 var id = alternate[i].id; 21267 var appendURL = alternate[i].appendURL; 21268 var sizeAvailable = !alternate[i].sizeAvailable; 21269 var oldURL = $('ul.color-options li[data-id='+id+'] a').attr('href'); 21270 var newURL = oldURL + appendURL; 21271 $('ul.color-options li.alternate[data-id="'+id+'"] a').attr('href',newURL); 21272 if(appendURL == null || (typeof appendURL === "string" && appendURL.trim().length === 0)){ 21273 $('ul.color-options li[data-id='+id+'] a').addClass('no-size'); 21274 } 21275 }); 21276 } 21277 }); 21278 } 21279} 21280 21281function renderVariationUpdates() { 21282 if (loaded['content'] && loaded['selectors']) { 21283 renderSelectors(); 21284 updatePid(); 21285 setAlternates(); 21286 21287 $(document).trigger('SameDayShippingCountdown.Update'); 21288 21289 var sizeSelected = $('div.product-variations .size.size-options li.selected'); 21290 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 21291 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 21292 var isSizeSelected = sizeSelected.length || (lengthSelected && widthSelected); 21293 var isColorSelected = $('div.product-variations .color.color-options li.selected').length; 21294 21295 updateWishlistButton(sizeSelected); 21296 21297 if (isSizeSelected) { 21298 $('.attribute-size').addClass('size-selected'); 21299 } else { 21300 $('.attribute-size').removeClass('size-selected'); 21301 } 21302 if (isSizeSelected && isColorSelected) { 21303 $('.btn.store-search').removeAttr('disabled'); 21304 21305 $(document).trigger('ProductDetailPage.Variant.Selected'); 21306 $(document).trigger('ProductDetailPage.Variant.AddToCartOptions'); 21307 $(document).trigger('ProductDetailPage.Variant.StoreSearch'); 21308 $(document).trigger('Currency.Update', $('#product-content')); 21309 } 21310 21311 var $selectableCount = 0; 21312 $('.product-options .attribute-size .select-dropdown ul.size-options li, .product-options .attribute-size .select-dropdown ul.length-options li').each(function() { 21313 var $selectClass = $(this).attr('class').replace('selected','').trim(); 21314 if( $selectClass == 'selectable'){ 21315 $selectableCount++; 21316 } 21317 }); 21318 21319 if (data['IsRestrictedByGlobale'] || $selectableCount == 0) { 21320 $('.same-day-shipping-countdown').addClass('hidden'); 21321 $('.product-options .attribute-size .select-dropdown').css({"pointer-events": "none", "cursor": "default"}); 21322 $('.product-variation').addClass('not-available'); 21323 if ($('.color-options .selectable').length > 1 || $('.alternate-items li').length > 1) { 21324 $('.product-variation').addClass('colors-selectable'); 21325 } 21326 if (data['IsRestrictedByGlobale']) { 21327 $('.product-globale-unavailable').removeClass('hidden'); 21328 } else if ($selectableCount == 0) { 21329 $('.product-out-of-stock').removeClass('hidden'); 21330 } 21331 } 21332 21333 $(document).trigger('ProductDetailPage.Variant.Updated', { ProductId: data['pid'] }); 21334 } 21335} 21336
21337function renderSelectors() { 21338 $('.product-variations').html(html['selectors']); 21339 $('.product-variations').attr('data-attributes', JSON.stringify(data['selected'])); 21340 checkForSelectedSwatch($('.product-variations')); 21341 21342 $('.attribute-guide-link').fancybox(); 21343} 21344 21345function checkForSelectedSwatch($container) { 21346 var swatchIsSelected = $container.find('.color-options .selectable.selected').length > 0; 21347 if (!swatchIsSelected) { 21348 $container.find('.color-options .selectable:first-child>.swatchanchor').mouseenter(); 21349 } 21350} 21351 21352/** 21353 * @description update product content with new variant from href, load new content to #product-content panel 21354 * @param {String} href - url of the new product variant 21355 **/ 21356var updateContent = function (href) { 21357 loaded['content'] = false; 21358 $('.btn.add-to-cart').attr('disabled', 'disabled').loading(); 21359 var bopisStoreSearchPostalCode = $('.bopis-store-search input[name="Bopis_StoreSearch_postalCode"]').val(); 21360 var $pdpForm = $('.pdpForm'); 21361 var qty = $pdpForm.find('select[name="Quantity"]').first().val(); 21362 var subdimensionHTML = $('#tt-subdimension-teaser').html(); 21363 var reloadSubdimension = $('.tt-w-dim-teaser__item').length > 0 ? true : false; 21364 var params = { 21365 Quantity: isNaN(qty) ? '1' : qty, 21366 format: 'ajax', 21367 productlistid: $pdpForm.find('input[name="pid"]').first().val(), 21368 BopisEnabled: $('.bopis-store-search').length > 0 ? true : false, 21369 Token: $('.bopis-store-search input[name="csrf_token"]').val() 21370 }; 21371 21372 buildSelectors(util.getQueryStringParams(util.getQueryString(util.appendParamsToUrl(href, params)))); 21373 $.ajax({ 21374 method: 'GET', 21375 url: util.appendParamsToUrl(href, params), 21376 complete: function(html) { 21377 loaded['content'] = true; 21378 $('#product-content').html(html.responseText); 21379 renderVariationUpdates(); 21380 21381 if (bopisStoreSearchPostalCode) { 21382 $('.bopis-store-search input[name="Bopis_StoreSearch_postalCode"]').val(bopisStoreSearchPostalCode); 21383 } 21384 21385 if (SitePreferences.STORE_PICKUP) { 21386 productStoreInventory.init(); 21387 } 21388 image.replaceImages(); 21389 tooltip.init(); 21390 // rating.init(); 21391 updateProductInfo(); 21392 if (reloadSubdimension){ 21393 reloadSubdimensionsWidget(subdimensionHTML); 21394 } 21395 initializeImageGallery(); 21396 updateCSRFToken(); 21397 // GoogleTagManagerClient.PushDataLayerForDataLayerType('ViewItem'); 21398 21399 setTimeout(function(){$(document).trigger('update-review-text');}, 500); 21400 21401 if ('affirm' in window && 'ui' in affirm && 'refresh' in affirm.ui) { 21402 affirm.ui.refresh(); 21403 } 21404 21405 var variantSelected = isVariantSelected(); 21406 if ($('.bopis-store-search').length > 0 || $('.bopis-add-to-cart-options-container').length > 0) { 21407 if (variantSelected) { 21408 options.Bopis.IsVariantSelected = true; 21409 } 21410 initializeBopis(); 21411 } 21412 21413 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS) { 21414 updateAddToCartRecommendations(); 21415 } 21416 $('.btn.add-to-cart').removeAttr('disabled').removeAttr('loading').find('.loading-indicator-container').remove(); 21417 } 21418 }); 21419}; 21420 21421function isVariantSelected() { 21422 var sizeSelected = $('div.product-variations .size.size-options li.selected').length; 21423 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 21424 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 21425 var colorSelected = $('div.product-variations .color.color-options li.selected').length; 21426 21427 return (sizeSelected || (lengthSelected && widthSelected)) && colorSelected; 21428} 21429 21430function updateAddToCartRecommendations() { 21431 var intervalCount = 0; 21432 var addToCartRecommendationsCheck = setInterval(function() { 21433 if ( $('.recomm-prod-pdp-a2c-slot .accordion.product-recommendations').length > 0 ) { 21434 clearInterval(addToCartRecommendationsCheck); 21435 initSlider(); 21436 return; 21437 } 21438 21439 if (intervalCount === 50) { 21440 clearInterval(addToCartRecommendationsCheck); 21441 return; 21442 } 21443 21444 intervalCount++; 21445 }, 200); 21446 21447 function initSlider() { 21448 sliders.init('.recomm-prod-pdp-a2c-slot .accordion.product-recommendations .slides', {breakpoints: {0: {slidesToShow: 1, arrows: true, dots: true}, 768: {slidesToShow: 3, arrows: true, dots: false}, 1024: {slidesToShow: 4, arrows: true, dots: false}}}, true); 21449 } 21450} 21451 21452function sizeMenuOpenClose(event, el, open) { 21453 var $this = el; 21454 var $container = $this.closest('.select-dropdown'); 21455 var $menu = $container.find('.select-dropdown-inner'); 21456 21457 if (open) { 21458 $this.addClass('active'); 21459 $menu.addClass('expand'); 21460 $menu.find('li.selectable a').removeAttr('tabindex'); 21461 } else { 21462 $this.removeClass('active'); 21463 $menu.removeClass('expand'); 21464 $menu.find('li.selectable a').attr('tabindex', '-1'); 21465 if ($menu.find('.tempselection').length > 0) { 21466 $menu.find('.tempselection').removeClass('selected tempselection'); 21467 } 21468 if (event.keyCode) { 21469 $container.addClass('focus-visible-indicator').focus(); 21470 } 21471 } 21472 21473 if ($menu.hasClass('expand')) { 21474 scrollToCurrentSize(); 21475 setTimeout(function(){ 21476 $menu.addClass('expand-close'); 21477 }, 100); 21478 } else { 21479 $menu.removeClass('expand-close'); 21480 } 21481} 21482 21483function selectSizeOption(el) { 21484 var $selected = $(el); 21485 21486 $selected 21487 .addClass('selected') 21488 .siblings() 21489 .removeClass('selected'); 21490 21491 $selected 21492 .closest('.select-dropdown-inner') 21493 .removeClass('expand') 21494 .removeClass('expand-close') 21495 .prev('.select-text') 21496 .removeClass('active'); 21497} 21498 21499function updateWishlistButton(sizeSelected) { 21500 var variantId = $('#pid').val(); 21501 var isWishlistItem = wishlist.checkWishlistForItem(variantId); 21502 var sizeText = ''; 21503 21504 if (sizeSelected) { 21505 sizeText = sizeSelected.find('.size').text(); 21506 } 21507 if (isWishlistItem) { 21508 wishlist.prepareWishlistRemoveUI($('.pdp-main .wishlist-item-status-button'), sizeText); 21509 } else { 21510 wishlist.prepareWishlistAddUI($('.pdp-main .wishlist-item-status-button'), null, sizeText); 21511 } 21512} 21513 21514function initializeEvents () { 21515 var $pdpMain = $('#pdpMain'); 21516 21517 // hover on swatch - should update main image with swatch image. 21518// $pdpMain.off('mouseenter.Variant.SwatchAnchor').on('mouseenter.Variant.SwatchAnchor', '.color>li>.swatchanchor', function (e) { 21519// e.preventDefault(); 21520// if ($(this).parents('li').hasClass('unselectable')) { return; } 21521// if ($(this).parents('li').hasClass('selected')) { return; } 21522// updateContent(this.href); 21523// }); 21524 21525 // click on swatch - should update main image with swatch image. 21526 $pdpMain.off('click.Variant.SwatchAnchor').on('click.Variant.SwatchAnchor', '.product-detail .swatchanchor', function (e) { 21527 e.preventDefault(); 21528 var didReload = false;
21529 if ($(this).parents('li').hasClass('unselectable')) { 21530 if ($(this).parents('li').hasClass('alternate')) { 21531 var altUrlLoad = $(this).attr('href'); 21532 window.location.href = altUrlLoad; 21533 } 21534 21535 $('li.drop-down-select-value').each(function() { 21536 var $selectedItem = $(this); 21537 $selectedItem.siblings('li.selected-value').html($selectedItem.html()); 21538 $selectedItem.parents('.attribute').first().find('.label .current, .select-dropdown .select-text').html($selectedItem.html()); 21539 if ( $selectedItem.parents('.select-dropdown-inner') != null ) { 21540 $selectedItem.parents('.select-dropdown-inner').find( 'li.selected' ).removeClass('selected'); 21541 } 21542 }); 21543 if ( $(this).attr('xhref') != null ) { 21544 updateContent($(this).attr('xhref')); 21545 didReload = true; 21546 } else { return; } 21547 } 21548 if ( !didReload ) { 21549 var link = this; 21550 if (!link.href) { 21551 link = $(this).parent()[0]; 21552 } 21553 updateContent(link.href); 21554 } 21555 }); 21556 21557 // change drop down variation attribute - should replace product content with new variant 21558 $pdpMain.off('change.Variant.VariationSelect').on('change.Variant.VariationSelect', '.variation-select', function () { 21559 if ($(this).val().length === 0) { return; } 21560 updateContent($(this).val()); 21561 }); 21562 21563 // Custom Select Dropdown 21564 $pdpMain.off('click.Variant.Selector.Expand').on('click.Variant.Selector.Expand', '.select-dropdown .select-text', function (event) { 21565 event.preventDefault(); 21566 var $this = $(this); 21567 var toggleOpen = !$this.hasClass('active'); 21568 sizeMenuOpenClose(event, $this, toggleOpen); 21569 }); 21570 21571 $(document).off('click.Variant.General.Close').on('click.Variant.General.Close', function(event) { 21572 $('div.product-variations ul.select-dropdown-inner.expand-close').each(function () { 21573 $(this).siblings('.select-text').trigger('click'); 21574 }); 21575 }); 21576 21577 $pdpMain.off('click.Variant.Selector.Select').on('click.Variant.Selector.Select', '.select-dropdown .selectable', function(event) { 21578 event.preventDefault(); 21579 selectSizeOption(this); 21580 }); 21581 21582 // Color Options 21583 $pdpMain.off('click.Variant.Color.Select').on('click.Variant.Color.Select', '.color-options a', function (event) { 21584 event.preventDefault(); 21585 21586 var nameColor = $(this).data('color-name'); 21587 21588 $(this) 21589 .parent() 21590 .addClass('selected') 21591 .siblings() 21592 .removeClass('selected'); 21593 21594 $(this) 21595 .closest('.attribute') 21596 .find('.color-current') 21597 .text(nameColor); 21598 }); 21599 21600 $(document).on('keyup', 'div.product-variations div.select-dropdown', function(e) { 21601 var $listContainer = $(this), 21602 $listParent = $listContainer.children('ul.select-dropdown-inner'), 21603 $defaultTextElement = $listContainer.children('.select-text'), 21604 $sizeList = $listParent.find('li.selectable'), 21605 $selected = $sizeList.filter('.selected'), 21606 isMenuOpen = $listParent.hasClass('expand'); 21607 21608 antiHover.init($listParent.width(), $listParent.height()); 21609 21610 if (e.shiftKey && e.keyCode == 9 && isMenuOpen) { // Tab backwards 21611 selectOptionKeydown(e, 'up', isMenuOpen); 21612 } else { 21613 switch(e.keyCode) { 21614 case 38: // Up Arrow 21615 selectOptionKeydown(e, 'up', isMenuOpen); 21616 break; 21617 case 40: // Down Arrow 21618 if (!isMenuOpen) { 21619 sizeMenuOpenClose(e, $defaultTextElement, true); 21620 } 21621 selectOptionKeydown(e, 'down', isMenuOpen); 21622 break; 21623 case 9: // Tab forwards 21624 if (isMenuOpen) { 21625 selectOptionKeydown(e, 'down', isMenuOpen); 21626 } 21627 break; 21628 case 27: // Escape key 21629 if (isMenuOpen) { 21630 sizeMenuOpenClose(e, $defaultTextElement, false); 21631 } 21632 break; 21633 case 13: // Enter key 21634 $listContainer.find('.select-text').toggleClass('active'); 21635 $listParent.toggleClass('expand').toggleClass('expand-close').toggleClass('size-d-none'); 21636 $sizeList.find('a[tabindex]').length > 0 ? $sizeList.find('a').removeAttr('tabindex') : $sizeList.find('a').attr('tabindex', '-1'); 21637 if (!$selected) { 21638 $defaultTextElement.trigger('click'); 21639 } else { 21640 $selected.find('a.swatchanchor').trigger('click'); 21641 } 21642 break; 21643 } 21644 } 21645 }); 21646 21647 $(document).off('mousemove.Variant.AntiHover').on('mousemove.Variant.AntiHover', '#anti-hover', function(e) { 21648 antiHover.moveremove(parseInt(e.clientX), parseInt(e.clientY)); 21649 }); 21650 21651 var swatches = $('div.product-variation ul.color-options li.selectable'); 21652 if (swatches.length && !swatches.is('.selected')) { 21653 setColor(); 21654 } 21655 21656 updateProductInfo(); 21657 initializeImageGallery(); 21658}; 21659 21660function setColor(){ 21661 var d = new $.Deferred(); 21662 21663 setTimeout(function(){ 21664 var swatches = $('div.product-variation ul.color-options li.selectable'); 21665 if (swatches.length && !swatches.is('.selected')) { 21666 swatches.first().find('a').trigger('click'); 21667 setTimeout(function(){d.resolve()}, 150); 21668 } 21669 21670 }, 50); 21671 21672 return d.promise() 21673} 21674 21675var antiHover = { 21676 $antiHover: null, 21677 posX: 0, 21678 posY: 0, 21679 remove: function() { 21680 if (this.$antiHover) this.$antiHover.remove(); 21681 this.posX = 0; 21682 this.posY = 0; 21683 }, 21684 moveremove: function(x, y) { 21685 this.posX = (this.posX == 0) ? x : this.posX; 21686 this.posY = (this.posY == 0) ? y : this.posY; 21687 if (this.posX != x || this.posY != y) { 21688 $('div.product-variations ul.select-dropdown-inner li.selectable').removeClass('selected'); 21689 this.remove(); 21690 } 21691 }, 21692 check: function() { 21693 return (this.$antiHover && this.$antiHover.length); 21694 }, 21695 init: function(w, h) { 21696 this.remove(); 21697 $('.value.select-dropdown').append('<div style="position: absolute;" id="anti-hover"></div>'); 21698 this.$antiHover = $('#anti-hover'); 21699 this.$antiHover 21700 .css('z-index', 1000) 21701 .css('height', h) 21702 .css('width', w); 21703 } 21704 21705}; 21706 21707function selectOptionKeydown(e, action, isMenuOpen) { 21708 e.preventDefault(); 21709 21710 var $listParent = $('div.product-variations ul.select-dropdown-inner'), 21711 $listContainer = $listParent.closest('.select-dropdown'), 21712 $defaultTextElement = $listContainer.children('.select-text'), 21713 $sizeList = $listParent.find('li.selectable'), 21714 $selected = $sizeList.filter('.selected'), 21715 height = parseInt($sizeList.first().css('height').replace(/px/, '')), 21716 $current; 21717 21718 if ($selected.length <= 0) { 21719 $selected = $listParent.find('.focus-visible-indicator').closest('li.selectable') ? $selected : null; 21720 } 21721 if (!$selected || !$selected.length) {
21722 $current = $sizeList.eq(0); 21723 } else if (action == 'up') { 21724 if ($selected.is(':first-child')) { 21725 $current = $sizeList.eq(0); 21726 // If this is first list item, and user pressed Up Arrow, then we need to close the menu 21727 sizeMenuOpenClose(e, $defaultTextElement, false); 21728 } else { 21729 $current = $selected.prev(); 21730 } 21731 } else { 21732 if (!$selected.next().hasClass('selectable')) { 21733 $current = $sizeList.last(); 21734 // If this is last list item, and user pressed Down Arrow, then we need to close the menu 21735 sizeMenuOpenClose(e, $defaultTextElement, false); 21736 } else { 21737 $current = $selected.next(); 21738 } 21739 } 21740 21741 var listParentTop = 0; 21742 var listParentBottom = listParentTop + $listParent.height(); 21743 var currentTop = $current.position().top; 21744 var currentBottom = currentTop + $current.height(); 21745 var faultPx = 10; 21746 if (currentBottom + faultPx > listParentBottom) { 21747 $listParent.scrollTop(parseInt($listParent.scrollTop()) + height); 21748 } else if (currentTop < listParentTop) { 21749 $listParent.scrollTop(parseInt($listParent.scrollTop()) - height); 21750 } 21751 21752 //$current.parents('.attribute').first().find('.label .current, .select-dropdown .select-text').html($current.find('a').html()); 21753 $sizeList.removeClass('selected tempselection'); 21754 $current.addClass('selected tempselection').find('a').addClass('focus-visible-indicator').focus(); 21755 // Needed to combat auto-scroll behavior that happens in previous line when focus added to <a> 21756 if ($current.is(':first-child')) { 21757 $listParent.scrollTop(0); 21758 } 21759} 21760 21761function scrollToCurrentSize() { 21762 var $listParent = $('div.product-variations ul.select-dropdown-inner'), 21763 $sizeList = $listParent.find('li.selectable'), 21764 $selected = $sizeList.filter('.selected'), 21765 height = $sizeList.first().css('height').replace(/px/, ''); 21766 21767 if ($selected) { 21768 $listParent.scrollTop(height * $sizeList.index($selected)); 21769 } 21770} 21771 21772function initializeImageGallery() { 21773 var params; 21774 if (SitePreferences.PRIMARY_PRODUCT_SLIDER == 'swiperJS') { 21775 imageGallery = require('../../components/ImageGallery/Swiper'); 21776 if (SitePreferences.PRIMARY_PRODUCT_SLIDER_CONFIG) { 21777 params = JSON.parse(SitePreferences.PRIMARY_PRODUCT_SLIDER_CONFIG); 21778 } 21779 } else { 21780 imageGallery = require('../../components/ImageGallery/SlickAndImgViewer2'); 21781 } 21782 imageGallery.initialize(params); 21783} 21784 21785function initializeBopis() { 21786 if ($('.bopis-add-to-cart-options-container').length > 0) { 21787 bopisAddToCartOptions.initialize($('.bopis-add-to-cart-options-container'), $.extend(options.Bopis, { Channel: options.Channel, ProductId: options.ProductId, StoreUIVersion: options.StoreUIVersion })); 21788 } 21789 21790 if ($('.bopis-store-search').length > 0) { 21791 bopisStoreSearch.initialize($('.bopis-store-search'), $.extend(options.Bopis, { Channel: options.Channel })); 21792 } 21793} 21794 21795function initialize(optionsParameter) { 21796 options = optionsParameter; 21797 initializeDom(); 21798 initializeEvents(); 21799 initializeBopis(); 21800} 21801 21802var variant = { 21803 initialize: initialize, 21804 initializeDom: initializeDom, 21805 initializeEvents: initializeEvents 21806}; 21807 21808module.exports = variant; 21809},{"../../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../../ajax":3,"../../bopis/components/AddToCartOptions":7,"../../bopis/components/StoreSearch":13,"../../components/ImageGallery/SlickAndImgViewer2":23,"../../components/ImageGallery/Swiper":24,"../../rating":89,"../../sliders":95,"../../storeinventory/product":98,"../../tooltip":101,"../../util":102,"../../wishlist":105,"./image":74,"lodash":133}],78:[function(require,module,exports){ 21810'use strict'; 21811var direction, videoCount, width, height, videoCounter = 0, posValue = 0, lastCounter = 0, arrowPos; 21812 21813var setCarousel = function(){ 21814 videoCount = $('.video-container ul li').length; 21815 width = $('.video-container').width(); 21816 height = width * 315 / 420; 21817 $('.youtube-video iframe').css({'width': width + 'px','height': height + 'px'}); 21818 width += 40; 21819 arrowPos = height / 2 - 20; 21820 $('.video-container .arrows .arrow').css('top', arrowPos + 'px'); 21821}; 21822 21823var arrowClick = function(arrow){ 21824 direction = arrow.hasClass('left') ? 'left' : 'right'; 21825 lastCounter = videoCounter; 21826 if(direction == 'right'){ 21827 if(videoCounter == (videoCount - 1)){ 21828 posValue = 0; 21829 videoCounter = 0; 21830 } 21831 else{ 21832 videoCounter++; 21833 posValue = videoCounter * width; 21834 } 21835 } 21836 else{ 21837 if(videoCounter == 0){ 21838 posValue = (videoCount - 1) * width; 21839 videoCounter = videoCount - 1; 21840 } 21841 else{ 21842 videoCounter--; 21843 posValue = videoCounter * width; 21844 } 21845 } 21846 $('.video-container ul').animate({'left':'-' + posValue + 'px'}, 'fast'); 21847 var iframe = $('.youtube-video iframe:eq('+ lastCounter +')'); 21848 $(iframe).attr('src', $(iframe).attr('src')); 21849}; 21850 21851module.exports = function () { 21852 setCarousel(); 21853 $('.video-container .arrows .arrow').on('click', function(){ 21854 arrowClick($(this)); 21855 }); 21856}; 21857},{}],79:[function(require,module,exports){ 21858'use strict'; 21859 21860var addProductToCart = require('./product/addToCart'), 21861 ajax = require('../ajax'), 21862 quickview = require('../quickview'), 21863 util = require('../util'); 21864 21865/** 21866 * @function 21867 * @description Loads address details to a given address and fills the address form 21868 * @param {String} addressID The ID of the address to which data will be loaded 21869 */ 21870function populateForm(addressID, $form) { 21871 // load address details 21872 var url = Urls.giftRegAdd + addressID; 21873 ajax.getJson({ 21874 url: url, 21875 callback: function (data) { 21876 if (!data || !data.address) { 21877 window.alert(Resources.REG_ADDR_ERROR); 21878 return false;
21879 } 21880 // fill the form 21881 $form.find('[name$="_addressid"]').val(data.address.ID); 21882 $form.find('[name$="_firstname"]').val(data.address.firstName); 21883 $form.find('[name$="_lastname"]').val(data.address.lastName); 21884 $form.find('[name$="_address1"]').val(data.address.address1); 21885 $form.find('[name$="_address2"]').val(data.address.address2); 21886 $form.find('[name$="_city"]').val(data.address.city); 21887 $form.find('[name$="_country"]').val(data.address.countryCode).trigger('change'); 21888 $form.find('[name$="_postal"]').val(data.address.postalCode); 21889 $form.find('[name$="_state"]').val(data.address.stateCode); 21890 $form.find('[name$="_phone"]').val(data.address.phone); 21891 // $form.parent('form').validate().form(); 21892 } 21893 }); 21894} 21895 21896/** 21897 * @private 21898 * @function 21899 * @description Initializes events for the gift registration 21900 */ 21901function initializeEvents() { 21902 var $eventAddressForm = $('form[name$="_giftregistry"]'), 21903 $beforeAddress = $eventAddressForm.find('fieldset[name="address-before"]'), 21904 $afterAddress = $eventAddressForm.find('fieldset[name="address-after"]'); 21905 21906 $('.usepreevent').on('click', function () { 21907 // filter out storefront toolkit 21908 $(':input', $beforeAddress).not('[id^="ext"]').not('select[name$="_addressBeforeList"]').each(function () { 21909 var fieldName = $(this).attr('name'), 21910 $afterField = $afterAddress.find('[name="' + fieldName.replace('Before', 'After') + '"]'); 21911 $afterField.val($(this).val()).trigger('change'); 21912 }); 21913 }); 21914 $eventAddressForm.on('change', 'select[name$="_addressBeforeList"]', function () { 21915 var addressID = $(this).val(); 21916 if (addressID.length === 0) { return; } 21917 populateForm(addressID, $beforeAddress); 21918 }) 21919 .on('change', 'select[name$="_addressAfterList"]', function () { 21920 var addressID = $(this).val(); 21921 if (addressID.length === 0) { return; } 21922 populateForm(addressID, $afterAddress); 21923 }); 21924 21925 $('form[name$="_giftregistry_items"]').on('click', '.item-details a', function (e) { 21926 e.preventDefault(); 21927 var productListID = $('input[name=productListID]').val(); 21928 quickview.show({ 21929 url: e.target.href, 21930 source: 'giftregistry', 21931 productlistid: productListID 21932 }); 21933 }); 21934 21935} 21936 21937exports.init = function () { 21938 initializeEvents(); 21939 addProductToCart(); 21940 21941 util.setDeleteConfirmation('.item-list', String.format(Resources.CONFIRM_DELETE, Resources.TITLE_GIFTREGISTRY)); 21942}; 21943 21944},{"../ajax":3,"../quickview":88,"../util":102,"./product/addToCart":72}],80:[function(require,module,exports){ 21945'use strict'; 21946 21947var compareWidget = require('../compare-widget'); 21948var dialog = require('../dialog'); 21949var GoogleTagManagerClient = require('../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 21950var loadingIndicator = require('../components/LoadingIndicator'); 21951var productTile = require('../product-tile'); 21952var page = require('../page'); 21953var sizeRefinements = require('../size-refinements'); 21954var styleCounts = require('../style-counts'); 21955var util = require('../util'); 21956var wishlist = require('../wishlist'); 21957var sliders = require('../sliders'); 21958 21959var ImageConstants; 21960 21961var RefinementUIVersionConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/RefinementConstants').RefinementsUIVersions; 21962var SiteConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 21963var ValidationSettings = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Settings; 21964var ValidationRules = require('../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants').Rules; 21965 21966var options; 21967var dataBuffer = []; 21968var $html = $('html'); 21969var $refinementsInner = $('.refinements'); 21970var refinementsExpanded; 21971var refinementsViewAll; 21972var loadingIndicatorSettings; 21973 21974var $bootFinderEmailForm; 21975var bootFinderEmailValidator; 21976 21977var previousSortApplied; 21978 21979/** 21980 * @private 21981 * @function 21982 * @description replaces breadcrumbs, lefthand nav and product listing with ajax and puts a loading indicator over the product listing 21983 */ 21984function updateProductListing(url, callback, isLoadMore) { 21985 if (!url || url === window.location.href) { 21986 if ($('body').attr('loading')) { 21987 $('body').loading('destroy'); 21988 } 21989 if ($('.apply-refinements').hasClass('loading')) { 21990 $('.apply-refinements').loading('destroy'); 21991 } 21992 if (typeof callback == 'function') { 21993 callback(); 21994 } 21995 return; 21996 } 21997 21998 if (options.StoreUIVersion == '2024Redesign' || (options && options.Pagination && options.Pagination.Mode == 'LoadMore')) { 21999 $('.btn.load-more').loading({ IsImageShown: false }); 22000 } 22001 22002 updateInventoryMessages(url); 22003 saveExpandedRefinements(); 22004 22005 $.ajax({ 22006 url: util.appendParamToURL(url, 'format', 'ajax'), 22007 type: 'GET', 22008 success: function(data) { 22009 $('body').removeClass('refinements-mobile-scroll-lock').css('top', ''); 22010 if ($('body').attr('loading') == 'loading') { 22011 $('body').loading('destroy'); 22012 } 22013 22014 history.pushState({}, '', url); 22015 var $content = $(data); 22016 var $productGrid = $content.find('#search-result-items'); 22017 var productTileCount = $productGrid.find('.grid-tile').length + $('#search-result-items').find('.grid-tile').length; 22018 var productTotalCount = parseInt($content.find('.search-result-options.bottom .count').text().replace(/\D/g, ''), 10); 22019 dataBuffer['PaginationCount'] = productTotalCount; 22020 if (isLoadMore) { 22021 dataBuffer['PaginationIndex'] += options.Pagination.Size; 22022 $('#search-result-items').append($productGrid.html()); 22023 $('.search-result-options .display-count').text(productTileCount); 22024 22025 if (productTileCount >= dataBuffer['PaginationCount']) { 22026 $('.btn.load-more').hide(); 22027 } else { 22028 $('.btn.load-more').show(); 22029 } 22030 22031 if (options.StoreUIVersion == '2024Redesign' || (options && options.Pagination && options.Pagination.Mode == 'LoadMore')) { 22032 $('.btn.load-more').loading('destroy'); 22033 } 22034 } else { 22035 dataBuffer['PaginationIndex'] = 0; 22036 $('#main').html($content); 22037 22038 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS || pageContext.site === SiteConstants.SiteIds.BootBarnWorkforceUS) { 22039 $('#grid-sort-header').selectmenu({ 22040 'width': 205 22041 }); 22042 } 22043 22044 if ('variantInventoryMessagingUrl' in page && page.variantInventoryMessagingUrl) { 22045 showVariantInventoryMessaging(); 22046 } 22047 22048 if ($('#primary').length > 0) { 22049 $('html,body').animate({ 22050 scrollTop: $('#primary').offset().top 22051 }, 1000); 22052 } 22053 } 22054 22055 if (options.Pagination && options.Pagination.Mode == 'EndlessScroll') { 22056 if (productTileCount >= dataBuffer['PaginationCount']) { 22057 $(document).off('scroll.EndlessScroll'); 22058 dataBuffer['EndlessScrollInitialized'] = false;
22059 } else if (!dataBuffer['EndlessScrollInitialized']) { 22060 initializeEndlessScroll(); 22061 } 22062 } 22063 22064 $refinementsInner = $('.refinements'); 22065 redrawUpdatedRefinementHandling($content, url); 22066 compareWidget.init(); 22067 productTile.init(); 22068 sizeRefinements.init(); 22069 initializeRefinementControls(); 22070 redrawShopMyStore(); 22071 sliders.initializeCategorySliders('.main-content .category-landing-slider:not(.slick-initialized)'); 22072 wishlist.renderAllWishlistButtons(); 22073 22074 if ('affirm' in window && 'ui' in affirm && 'refresh' in affirm.ui) { 22075 affirm.ui.refresh(); 22076 } 22077 22078 $(document).trigger('CategoryHeaderSliders.Initialize'); 22079 $(document).trigger('EinsteinProductRecommendations.Initialize'); 22080 if ($('#categoryTitle').length > 0) { 22081 setTimeout(function(){window.top.document.title = $('#categoryTitle').data('title');}, 3000); 22082 } 22083 22084 initializeThumbDataLayer(url); 22085 22086 if (options.StyleCountCache) { 22087 styleCounts.render(options.StyleCountCache); 22088 } 22089 22090 if (callback && typeof callback == 'function') { 22091 callback(); 22092 } 22093 }, 22094 complete: function(data, status, xhr) { 22095 if ((data.status == 301 || data.status == 302) && data.responseText) { 22096 location.href = data.responseText; 22097 } 22098 } 22099 }); 22100} 22101 22102function updateInventoryMessages(url, callback) { 22103 var urlParams = util.getQueryStringParams(url); 22104 22105 var inventoryLinkUrl = Urls.getInventoryLink; 22106 for (var urlParameter in urlParams) { 22107 if (urlParams[urlParameter]) { 22108 inventoryLinkUrl = util.appendParamToURL(inventoryLinkUrl, urlParameter, urlParams[urlParameter]); 22109 } 22110 } 22111 22112 $.post(inventoryLinkUrl, function(data) { 22113 var dataObj = JSON.parse(data); 22114 22115 if (dataObj.status && dataObj.url.length) { 22116 var newUrl = dataObj.url; 22117 22118 if (urlParams.hasOwnProperty('start') && urlParams.start > 0) { 22119 newUrl = util.appendParamToURL(newUrl, 'start', urlParams.start); 22120 } 22121 22122 if (urlParams.hasOwnProperty('sz')) { 22123 newUrl = util.appendParamToURL(newUrl, 'sz', urlParams.sz); 22124 } 22125 22126 page.variantInventoryMessagingUrl = newUrl; 22127 } 22128 22129 typeof callback == 'function' && callback(); 22130 }); 22131} 22132 22133function getUrlParams(url) { 22134 var vars = {}; 22135 22136 var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) { 22137 vars[key] = value; 22138 }); 22139 22140 return vars; 22141} 22142 22143function initializeThumbDataLayer(url) { 22144 var data = {}; 22145 22146 var currentCategoryId = $('.currCGID').val(); 22147 if (currentCategoryId && currentCategoryId != 'null') { 22148 data.cgid = currentCategoryId; 22149 } 22150 22151 if (getUrlParams(url)['sz']) { 22152 data.sz = getUrlParams(url)['sz']; 22153 } 22154 22155 if (getUrlParams(url)['start']) { 22156 data.start = getUrlParams(url)['start']; 22157 } 22158 22159 if (getUrlParams(url)['q']) { 22160 data.q = decodeURIComponent(getUrlParams(url)['q']); 22161 } 22162 22163 if (getUrlParams(url)['srule']) { 22164 data.srule = decodeURIComponent(getUrlParams(url)['srule']); 22165 } 22166 22167 for (var preferenceIndex = 1; preferenceIndex < 9; preferenceIndex++) { 22168 if (getUrlParams(url)['prefn' + preferenceIndex]) { 22169 data['prefn' + preferenceIndex] = decodeURIComponent(getUrlParams(url)['prefn' + preferenceIndex]); 22170 } 22171 22172 if (getUrlParams(url)['prefv' + preferenceIndex]) { 22173 data['prefv' + preferenceIndex] = decodeURIComponent(getUrlParams(url)['prefv' + preferenceIndex]); 22174 } 22175 } 22176 22177 GoogleTagManagerClient.PushDataLayerForPage(pageContext); 22178} 22179 22180function filterRefinements(container, filterText) { 22181 container.find('.checks label').each(function() { 22182 var $filter = $(this); 22183 if (filterText === "") { 22184 // Reset filter 22185 $filter.parent().show(); 22186 } 22187 else { 22188 var labelText = $filter.html().trim().toUpperCase(); 22189 if (labelText.indexOf(filterText) > -1) { 22190 $filter.parent().show(); 22191 } 22192 else { 22193 $filter.parent().hide(); 22194 } 22195 } 22196 }); 22197} 22198 22199/** 22200 * @private 22201 * @function 22202 * @description Initializes the following search refinement controls:<br/> 22203 * <p>scroll bar</p> 22204 * <p>section dropdowns</p> 22205 * <p>range slider</p> 22206 * <p>textbox filter</p> 22207 */ 22208function initializeRefinementControls() { 22209 if ($('.refinements .refinement:visible').length > 2) { 22210 $('.refinements .show-all-refinements').addClass('active'); 22211 } 22212 22213 if ($('.refinement input:checked, .refinement [refinement-value].modified:not(:checked)').length > 0) { 22214 $('.refinements').addClass('refinements-applied'); 22215 } 22216 22217 // handle toggle refinement blocks 22218 $(document).off('click.RefinementToggle').on('click.RefinementToggle', '.refinement:not(.disabled) .toggle', function (event) { 22219 var $this = $(this); 22220 var $refinementBody = $this.parent().find('.refinement-body'); 22221 22222 if (!$this.hasClass('expanded')) { 22223 $this.attr('aria-expanded', 'true').closest('.refinement').addClass('expanded'); 22224 } else { 22225 $this.attr('aria-expanded', 'false').closest('.refinement').removeClass('expanded'); 22226 22227 } 22228 $this.toggleClass('expanded'); 22229 if ($this.hasClass('expanded')) { 22230 $refinementBody.stop().show(); 22231 } else { 22232 $refinementBody.stop().hide(); 22233 } 22234 22235 if ($('.refinement.expanded').length > 0) { 22236 $('.refinements').addClass('refinement-expanded'); 22237 } else { 22238 $('.refinements').removeClass('refinement-expanded'); 22239 } 22240 22241 if ($this.closest('.show-all-refinements').length > 0) { 22242 $this.parent().toggleClass('expanded'); 22243 return; 22244 } 22245 22246 saveExpandedRefinements(); 22247 if (options.StoreUIVersion == '2024Redesign') {
22248 updateSelectedRefinements(); 22249 } 22250 $(document).trigger('StickyRefinements.Refresh'); 22251 22252 setTimeout(function(){ 22253 var cssClass = $this.parent().attr('class'); 22254 var refinementGroup = $.trim(cssClass.replace(/refinement/, '')); 22255 refGroupsStates.saveState(refinementGroup, $this.hasClass('expanded')); 22256 }.bind(this), 30); 22257 }); 22258 22259 $('.refinement .form-row input[type=text]').on('input', function() { 22260 var $input = $(this); 22261 22262 window.clearTimeout($input.data("timeout")); 22263 $input.data("timeout", setTimeout(function () { 22264 filterRefinements($input.parents('.refinement').first(), $input.val().trim().toUpperCase()); 22265 }, 1000)); 22266 }); 22267 22268 // ADA compliance attribute 22269 $('li.more-link-container').closest('ul').attr('aria-live', 'polite'); 22270 22271 priceSlider(); 22272} 22273 22274/** 22275 * @private 22276 * @function 22277 * @description Initializes events for the following elements:<br/> 22278 * <p>refinement blocks</p> 22279 * <p>updating grid: refinements, pagination, breadcrumb</p> 22280 * <p>item click</p> 22281 * <p>sorting changes</p> 22282 */ 22283function initializeEvents() { 22284 /* 22285 * Added a JS for search result page to prevent refinement from having a margin-top even the header is not showing 22286 */ 22287 if ((options.RefinementsUIVersion != RefinementUIVersionConstants.Updated) && window.innerWidth < 767) { 22288 if($(".search-phrase-container").length) { 22289 $('.pt_product-search-result #secondary .refinements-inner').css({'margin-top': '60px'}); 22290 } 22291 } 22292 22293 $(window).on('resize', function() { 22294 if ((options.RefinementsUIVersion == RefinementUIVersionConstants.Updated) && window.innerWidth > 767) { 22295 $('.modified').removeClass('modified').prop('checked', !$('.modified').prop('checked')); 22296 } 22297 }); 22298 22299 $(document).ready(function() { 22300 $("body").delegate(".product-swatches-all", "click", function() { 22301 $(this).parent().find(".swatch-list li").removeClass('hide'); 22302 }); 22303 22304 previousSortApplied = $('#grid-sort-header').find('option:selected').text(); 22305 }); 22306 22307 var $main = $('#main'); 22308 // compare checked 22309 $main.on('click', 'input[type="checkbox"].compare-check', function () { 22310 var cb = $(this); 22311 var tile = cb.closest('.product-tile'); 22312 22313 var func = this.checked ? compareWidget.addProduct : compareWidget.removeProduct; 22314 var itemImg = tile.find('.product-image a img').first(); 22315 func({ 22316 itemid: tile.data('itemid'), 22317 uuid: tile[0].id, 22318 img: itemImg, 22319 cb: cb 22320 }); 22321 }); 22322 22323 $(document).off('click.Toggle.Refinements').on('click.Toggle.Refinements', '.toggle-refinements', function(event) { 22324 event.preventDefault(); 22325 toggleRefinements(); 22326 }); 22327 22328 $main.off('click.Toggle.Sorting').on('click.Toggle.Sorting', '.toggle-sort', function(event) { 22329 event.preventDefault(); 22330 22331 $('.sort-by.modal').toggle(); 22332 $('.sort-by.modal').toggleClass('open'); 22333 $('#search-result').toggleClass('active'); 22334 22335 }); 22336 22337 $main.off('click.Select.Sorting').on('click.Select.Sorting', '.sort-by.modal input', function(event) { 22338 event.stopImmediatePropagation(); 22339 22340 var $this = $(this); 22341 $('.sort-by.modal').toggle(); 22342 $('.sort-by.modal').toggleClass('open'); 22343 $('body').loading(loadingIndicatorSettings); 22344 updateProductListing($this.val()); 22345 }); 22346 22347 // handle events for updating grid 22348 $main.on('click', '.refinements-head a, .refinements-inner a:not(.skip-to-next), .pagination-bar a, .breadcrumb-refinement-value a', function (e) { 22349 var $this = $(this); 22350 22351 if (!$this.hasClass('ref-filter') && checkForUpdatedRefinementHandling()) { 22352 e.preventDefault(); 22353 var refinementValue = $this.attr('value'); 22354 22355 $this.closest('.refinement-body-inner').find('li[refinement-value="' + refinementValue + '"], a[value="' + refinementValue + '"]').toggleClass('modified'); 22356 redrawUpdatedRefinementHandling(); 22357 return; 22358 } 22359 22360 // don't intercept for category and folder refinements, as well as unselectable 22361 if ($this.parents('.category-refinement').length > 0 || $this.parents('.folder-refinement').length > 0 || $this.parent().hasClass('unselectable')) { 22362 return; 22363 } 22364 e.preventDefault(); 22365 22366 var activeRefinementsCount = $('[refinement-value].selected').length - $('.swatches[class*="popular-"] [refinement-value].selected').length; 22367 if ($this.parent().hasClass('selected') && activeRefinementsCount == 1 && options.CategoryLandingPageContent && options.CategoryLandingPageContent.Url) { 22368 location.href = options.CategoryLandingPageContent.Url; 22369 return; 22370 } 22371 22372 if ($this.hasClass('breadcrumb-element') && $this.attr('href') != null) { 22373 location.href = this.href; 22374 return; 22375 } 22376 22377 // hide or show/expand all refinement items 22378 if ($this.hasClass('ref-filter')) { 22379 var ref = '[refinement-id="' + $(this).data('ref') + '"]'; 22380 $(ref).find('.toggleable').toggleClass('hidden'); 22381 if ($this.hasClass('more-link')) { 22382 $this.parents('li').hide().closest('.refinement').addClass('more-expanded'); 22383 $this.parents('li').nextAll(':visible').first().find('label').addClass('focus-visible-indicator').focus(); 22384 } else { 22385 $(ref).find('.more-link').parents('li').show().closest('.refinement').removeClass('more-expanded'); 22386 $(ref).find('.more-link').parents('li').prevAll(":visible").first().find('label').addClass('focus-visible-indicator').focus(); 22387 } 22388 saveExpandedRefinements(); 22389 return; 22390 } 22391 22392 if ($this.length > 0 && !$('html').hasClass('size-mobile')) { 22393 $('body').loading(loadingIndicatorSettings); 22394 } 22395 22396 if (SitePreferences.GA_NEW_ACTIONS_ENABLED) { 22397 var refinementId = $this.closest('[refinement-id]').attr('refinement-id') || null; 22398 var refinementValue = $this.attr('value') ? $this.attr('value').replace('"'," INCH") : null; 22399 if (refinementId && refinementValue) { 22400 var refinementAnalyticsTaggingData = { 22401 'action_name': 'filter', 22402 'action_page_type': 'plp', 22403 'action_value': refinementId, 22404 'action_items': refinementValue 22405 }; 22406 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', refinementAnalyticsTaggingData); 22407 } 22408 } 22409 22410 updateProductListing(this.href); 22411 22412 var selection = $('div.product-selections ul li'); 22413 var refGroup = $(selection[selection.length-2]).find('span:first').data('refgroup-id'); 22414 if (refGroup && refGroup.length > 0 && refGroupsStates.checkState(refGroup)) { 22415 $('#refinements-inner .refinement.'+refGroup+' button')[0].click(); 22416 } 22417 }); 22418 22419 // handle events item click. append params. 22420 $main.on('click', '.product-tile a:not("#quickviewbutton")', function () { 22421 var a = $(this); 22422 // get current page refinement values 22423 var wl = window.location; 22424 22425 var qsParams = (wl.search.length > 1) ? util.getQueryStringParams(wl.search.substr(1)) : {}; 22426 var hashParams = (wl.hash.length > 1) ? util.getQueryStringParams(wl.hash.substr(1)) : {}; 22427 22428 // merge hash params with querystring params 22429 var params = $.extend(hashParams, qsParams); 22430 if (!params.start) { 22431 params.start = 0; 22432 } 22433 // get the index of the selected item and save as start parameter 22434 var tile = a.closest('.product-tile'); 22435 var idx = tile.data('idx') ? + tile.data('idx') : 0; 22436 22437 // convert params.start to integer and add index 22438 params.start = (+params.start) + (idx + 1); 22439 // set the hash and allow normal action to continue 22440 a[0].hash = $.param(params); 22441 }); 22442 22443 // handle sorting change 22444 $main.on('change', '.sort-by select', function (e) { 22445 e.preventDefault(); 22446 22447 if ($('html').hasClass('size-mobile')) { 22448 var isSortingChanged = false;
22449 var $sortingRule = $('.modal.open .sort-by option:checked'); 22450 if ($sortingRule && $sortingRule.length > 0) { 22451 isSortingChanged = !$sortingRule.attr('selected'); 22452 } 22453 22454 if (isSortingChanged || $refinementsInner.find('[refinement-value].modified, .list-selections .value.pending-clear').length > 0) { 22455 $refinementsInner.addClass('refinements-modified'); 22456 $('.refinements-inner-container-footer .apply-refinements').removeClass('disabled'); 22457 } else { 22458 $refinementsInner.removeClass('refinements-modified'); 22459 $('.refinements-inner-container-footer .apply-refinements').addClass('disabled'); 22460 } 22461 } else { 22462 $('body').loading(loadingIndicatorSettings); 22463 var selectedSort = $(this).find('option:selected').val(); 22464 22465 if (SitePreferences.GA_NEW_ACTIONS_ENABLED) { 22466 var newSortValue = $(this).find('option:selected').text(); 22467 var oldSortValue = previousSortApplied ? previousSortApplied : 'Top Sellers'; 22468 if (newSortValue && oldSortValue) { 22469 var sortAnalyticsTaggingData = { 22470 'action_name': 'sort', 22471 'action_page_type': 'plp', 22472 'action_value': newSortValue, 22473 'action_items': 'from ' + oldSortValue 22474 }; 22475 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', sortAnalyticsTaggingData); 22476 } 22477 previousSortApplied = newSortValue; 22478 } 22479 22480 if ($(this).attr('id') == 'mobile-sort'){ 22481 updateProductListing(selectedSort); 22482 } else { 22483 if (checkForUpdatedRefinementHandling()) { 22484 updateProductListing(selectedSort); 22485 } else { 22486 document.location.href = selectedSort; 22487 } 22488 } 22489 } 22490 }); 22491 22492 $('.search-result-page').on('click', '#grid-sort-header-menu li', function () { 22493 $('.sort-by select').prop('selectedIndex', $(this).index()).first().trigger('change'); 22494 }); 22495 22496 $main.on('change', '.items-per-page select', function () { 22497 var refineUrl = $(this).find('option:selected').val(); 22498 if (refineUrl === 'INFINITE_SCROLL') { 22499 $('html').addClass('infinite-scroll').removeClass('disable-infinite-scroll'); 22500 } else { 22501 $('html').addClass('disable-infinite-scroll').removeClass('infinite-scroll'); 22502 updateProductListing(refineUrl); 22503 } 22504 }); 22505 22506 $main.on('click', '.mobile-refinements .toggle-button', function() { 22507 if (pageContext.site === SiteConstants.SiteIds.SheplersUS && options.RefinementsUIVersion != RefinementUIVersionConstants.Updated) { 22508 if ($(this).hasClass('sort-by-toggle')) { 22509 22510 //Ensure both sort-by and refinements aren't open simultaneously 22511 $('#secondary.refinements').removeClass('active'); 22512 $('.mobile-refinements .refine-toggle').removeClass('active'); 22513 22514 //container for new sorting options 22515 var sortByOptionsContainer = $('.mobile-refinements .sort-by-options'); 22516 if(sortByOptionsContainer.html().length < 1) { 22517 22518 //sort-by form for reference and pulling options 22519 var currentSortByOptions = $('.mobile-refinements #sort-by #grid-sort-header option'); 22520 22521 sortByOptionsContainer.append("<ul class='sort-by-list'></ul>"); 22522 22523 //create new list with data linked to form 22524 currentSortByOptions.each(function() { 22525 var selectedValue = $(this).prop('selected'); 22526 22527 if (typeof selectedValue !== typeof undefined && selectedValue !== false) { 22528 var newOption = '<li class="selectable-option selected" data-option-for="' + $(this).attr('value') + '">' + $(this).text() + '</li>'; 22529 sortByOptionsContainer.find('ul').append(newOption); 22530 } else { 22531 var newOption = '<li class="selectable-option" data-option-for="' + $(this).attr('value') + '">' + $(this).text() + '</li>'; 22532 sortByOptionsContainer.find('ul').append(newOption); 22533 } 22534 }); 22535 22536 } 22537 //toggle sort-by options to active state 22538 $('.mobile-refinements .sort-by-options').toggleClass('active'); 22539 $(this).toggleClass('active'); 22540 } else if ($(this).hasClass('refine-toggle')) { 22541 //Ensure both sort-by and refinements aren't open simultaneously 22542 $('.mobile-refinements .sort-by-options').removeClass('active'); 22543 $('.mobile-refinements .sort-by-toggle').removeClass('active'); 22544 //toggle refinements options to active state 22545 $('#secondary.refinements').toggleClass('active'); 22546 $(this).toggleClass('active'); 22547 } 22548 } 22549 }); 22550 $main.on('click', '.sort-by-options .sort-by-list .selectable-option', function() { 22551 if (pageContext.site === SiteConstants.SiteIds.SheplersUS) { 22552 //set correct sort-by form option as selected 22553 var optionValue = $(this).attr('data-option-for'); 22554 $('.mobile-refinements .sort-by#sort-by form #grid-sort-header option[value="'+optionValue+'"]').prop('selected', true); 22555 //Trigger form change to fire sort-by change watcher 22556 $('.mobile-refinements .sort-by#sort-by form #grid-sort-header option').change(); 22557 } 22558 }); 22559 22560 // refinement checkboxes 22561 $main.on('click', '.refinement .checks input', function (event) { 22562 var $this = $(this); 22563 var $refinement = $this.closest('[refinement-value]'); 22564 if ($refinement.length > 0 && !$('html').hasClass('size-mobile')) { 22565 $('body').loading(loadingIndicatorSettings); 22566 } 22567 22568 if ($this.closest('.refinement.sort-by').length > 0) { 22569 $this.closest('.refinement-body').find('[refinement-value] input').not($this).removeClass('modified').prop('checked', false); 22570 $this.toggleClass('modified'); 22571 }
22572 if (checkForUpdatedRefinementHandling()) { 22573 var refinementValue = $this.val().replace(' INCH','\\"'); 22574 if ($this.closest('[is-price-refinement="true"]').length > 0) { 22575 $('[is-price-refinement="true"] input').not($this).prop('checked', false).removeAttr('checked').removeClass('modified'); 22576 $refinement.toggleClass('modified'); 22577 } else { 22578 var $equalValueInputs = $this.closest('.refinement-body').find('[refinement-value="' + refinementValue + '"]'); 22579 $equalValueInputs.toggleClass('modified'); 22580 $equalValueInputs.not($this).prop('checked', $this.prop('checked')); 22581 } 22582 redrawUpdatedRefinementHandling(); 22583 return; 22584 } 22585 22586 if (SitePreferences.GA_NEW_ACTIONS_ENABLED && $this.is(':checked')) { 22587 var refinementId = $this.closest('[refinement-id]').attr('refinement-id') || null; 22588 var refinementValue = $this.val() ? $this.val().replace('"'," INCH") : null; 22589 if (refinementId && refinementValue) { 22590 var refinementAnalyticsTaggingData = { 22591 'action_name': 'filter', 22592 'action_page_type': 'plp', 22593 'action_value': refinementId, 22594 'action_items': refinementValue 22595 }; 22596 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', refinementAnalyticsTaggingData); 22597 } 22598 } 22599 22600 var url = $(this).parents('li').first().find('.hidden-refinement-link-container > a').first().attr('href'); 22601 22602 updateProductListing(url); 22603 }); 22604 22605 $main.on('keyup', '.refinement .checks label', function (event) { 22606 if (event.keyCode == 13) { 22607 $(this).siblings('input').trigger('click'); 22608 } 22609 }); 22610 22611 $main.on('click', '.result-options .switch input[name="field-switch"]', function () { 22612 if (checkForUpdatedRefinementHandling()) { 22613 updateProductListing($(this).parents('.switch').find('.visually-hidden input[name="field-true"] + a').first().attr('href')); 22614 } else { 22615 document.location = $(this).parents('.switch').find('.visually-hidden input[name="field-true"] + a').first().attr('href'); 22616 } 22617 }); 22618 22619 $(document).on('click', '.list-selections li:not(.pending-selections) a.close-btn, .clear-all .close-btn', function (e) { 22620 e.preventDefault(); 22621 22622 var $this = $(this); 22623 if ($this.closest('.value').hasClass('applied') && $this.closest('.modal').length > 0) { 22624 $this.closest('.value').toggleClass('pending-clear'); 22625 redrawUpdatedRefinementHandling(); 22626 return; 22627 } 22628 22629 $('body').loading(loadingIndicatorSettings); 22630 var activeRefinementsCount = $('[refinement-value].selected').length - $('.swatches[class*="popular-"] [refinement-value].selected').length; 22631 if (activeRefinementsCount == 1 && options.CategoryLandingPageContent && options.CategoryLandingPageContent.Url) { 22632 location.href = options.CategoryLandingPageContent.Url; 22633 return; 22634 } 22635 22636 var href = $this.attr('href'); 22637 if (href == null || href == 'null') { 22638 var search = document.location.search; 22639 updateProductListing(document.location.pathname + search.substr(0, search.indexOf('&'))); 22640 } else { 22641 updateProductListing(href); 22642 } 22643 }); 22644 22645 $(document).on('click', '.list-selections li.pending-selections a.close-btn', function (e) { 22646 e.preventDefault(); 22647 22648 var pendingRefinementId = $(this).closest('[data-refgroup-id]').attr('data-refgroup-id'); 22649 var pendingRefinementValue = $(this).closest('span').attr('refinement-value'); 22650 var selector = '[refinement-id="' + pendingRefinementId + '"] ul [refinement-value="' + pendingRefinementValue + '"]'; 22651 22652 var $pendingRefinementInput = $refinementsInner.find(selector); 22653 if ($pendingRefinementInput.find('input').length > 0) { 22654 $pendingRefinementInput.find('input').click(); 22655 } else if ($pendingRefinementInput.find('a').length > 0) { 22656 $pendingRefinementInput.find('a').click(); 22657 } 22658 }); 22659 22660 $main.on('click', '.product-swatches-accordion-button', function () { 22661 var $accordion = $(this).closest('.accordion'); 22662 22663 if ($accordion.length > 0) { 22664 $accordion.toggleClass('active'); 22665 } 22666 }); 22667 22668 $(document).off('click.ShopMyStore', '.shop-my-store .checkbox-toggle input').on('click.ShopMyStore', '.shop-my-store .checkbox-toggle input', function(event) { 22669 var $this = $(this); 22670 22671 var url; 22672 if ($this.prop('checked')) { 22673 url = $this.attr('href-refine'); 22674 } else { 22675 url = $this.attr('href-relax'); 22676 $('body').attr('is-shop-my-store-active', false); 22677 } 22678 22679 if (url) { 22680 $('.shop-my-store .checkbox-toggle').loading({ IsLabelShown: false, IsImageShown: false }); 22681 $('body').loading(loadingIndicatorSettings); 22682 22683 GoogleTagManagerClient.PushDataLayerForDataLayerType('ShopYourStore', { enabled: $this.prop('checked') }); 22684 22685 url = util.appendParamToURL(url, 'shopmystore', $this.prop('checked')); 22686 updateProductListing(url); 22687 } else { 22688 event.preventDefault(); 22689 } 22690 }); 22691 22692 $(document).off('ShopMyStore.Update').on('ShopMyStore.Update', function(event, storeId) { 22693 if ($('.shop-my-store .checkbox-toggle input').prop('checked')) { 22694 var url = location.protocol + '//' + location.hostname + location.pathname; 22695 var queryStringParameters = util.getQueryStringParams(location.search); 22696 for (var queryStringParameterKey in queryStringParameters) { 22697 var queryStringParameterValue = queryStringParameters[queryStringParameterKey]; 22698 if (queryStringParameterValue && queryStringParameterValue.indexOf('availableStores') > -1) { 22699 var refinementIndex; 22700 var refinementIndexMatch = queryStringParameterKey.match(/prefn([0-9])+/); 22701 if (refinementIndexMatch && refinementIndexMatch.length > 1) { 22702 refinementIndex = refinementIndexMatch[1]; 22703 } 22704 } 22705 } 22706 22707 if (refinementIndex && storeId) { 22708 queryStringParameters['prefv' + refinementIndex] = storeId; 22709 } 22710 22711 for (var queryStringParameterKey in queryStringParameters) { 22712 var queryStringParameterValue = queryStringParameters[queryStringParameterKey]; 22713 if (queryStringParameterKey != 'start' && queryStringParameterKey != 'sz') { 22714 url = util.appendParamToURL(url, queryStringParameterKey, queryStringParameterValue); 22715 } 22716 } 22717 22718 $('body').loading({ 22719 IsImageShown: false, 22720 Content: '<h6>Hold Your Horses!</h6><p>Your selections are loading...</p>', 22721 CssClass: 'shopyourstore',
22722 BackgroundColor: 'transparent' 22723 }); 22724 22725 updateProductListing(url); 22726 } else { 22727 if (pageContext.site != SiteConstants.SiteIds.BootBarnUS || !SitePreferences.MOBILE_NAV_REDESIGN || window.innerWidth > 1024) { 22728 redrawShopMyStore(); 22729 } 22730 } 22731 }); 22732 22733 searchStores(); 22734 initializeRefinementControls(); 22735 if (pageContext.site === SiteConstants.SiteIds.BootBarnUS || pageContext.site === SiteConstants.SiteIds.BootBarnWorkforceUS) { 22736 $('#grid-sort-header').selectmenu({ 22737 'width': 205 22738 }); 22739 } 22740 22741 $main.on('click', '.apply-refinements:not(.disabled)', function(event) { 22742 event.preventDefault(); 22743 $(this).attr('data-apply-refinements','true'); 22744 22745 var pendingRefinementsDelta = $('#secondary [refinement-value]:not(.selected):not([class*="popular"]).modified').length - $('#secondary [refinement-value].selected:not([class*="popular"]).modified').length; 22746 var activeRefinementsCount = $('#secondary [refinement-value].selected').length - $('#secondary .swatches[class*="popular-"] [refinement-value].selected').length - $('#secondary .list-selections .pending-clear').length + pendingRefinementsDelta; 22747 if (activeRefinementsCount == 0 && options.CategoryLandingPageContent && options.CategoryLandingPageContent.Url) { 22748 location.href = options.CategoryLandingPageContent.Url; 22749 return; 22750 } 22751 22752 if (SitePreferences.GA_NEW_ACTIONS_ENABLED) { 22753 var $refinement = $('.refinements').find('[refinement-id]:not(.sort-by)'); 22754 var $selectedRefinements = $refinement.find('ul:not([class*="popular"]) li[refinement-value]:not(.selected).modified, ul:not([class*="popular"]) li[refinement-value].selected:not(.modified)'); 22755 if ($selectedRefinements.length > 0) { 22756 var refinementId, refinementValue; 22757 $selectedRefinements.each(function () { 22758 refinementId = $(this).closest('[refinement-id]').attr('refinement-id'); 22759 refinementValue = refinementId.toUpperCase() == 'PRICE' ? $(this).find('.refinement-label').text().replace(/\s+/g, ' ').trim() : $(this).attr('refinement-value').replace(' INCH','"'); 22760 if (refinementId && refinementValue) { 22761 var refinementAnalyticsTaggingData = { 22762 'action_name': 'filter', 22763 'action_page_type': 'plp', 22764 'action_value': refinementId, 22765 'action_items': refinementValue 22766 }; 22767 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', refinementAnalyticsTaggingData); 22768 } 22769 }); 22770 } 22771 22772 // The newSortValue will only be populated if a change to sort has occurred, and GA tagging only gets fired if newSortValue has data 22773 var newSortValue = $('#mobile-sort option:checked').length > 0 ? $('#mobile-sort option:checked')[0].label : null; 22774 var oldSortValue = previousSortApplied ? previousSortApplied : 'Top Sellers'; 22775 if (newSortValue && oldSortValue) { 22776 var sortAnalyticsTaggingData = { 22777 'action_name': 'sort', 22778 'action_page_type': 'plp', 22779 'action_value': newSortValue, 22780 'action_items': 'from ' + oldSortValue 22781 }; 22782 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', sortAnalyticsTaggingData); 22783 } 22784 previousSortApplied = newSortValue; 22785 } 22786 22787 $('body').loading(loadingIndicatorSettings); 22788 updateProductListing(buildUrlForSelectedRefinements(null, null, false, true)); 22789 }); 22790 22791 $main.on('click', '.clear-refinements:not(.disabled)', function(event) { 22792 event.preventDefault(); 22793 22794 var $this = $(this); 22795 var href = $this.attr('href'); 22796 var $refinementsModalProductSelections = $('.refinements-inner-container-header .product-selections'); 22797 22798 if ($refinementsModalProductSelections.find('.list-selections .value.applied').length > 0) { 22799 if (checkForUpdatedRefinementHandling()) { 22800 $('.clear-refinements').loading({ 22801 IsImageShown: false 22802 }); 22803 updateProductListing($(this).attr('href')); 22804 } else { 22805 document.location = $(this).attr('href'); 22806 } 22807 } else { 22808 $('.refinement[uuid]').find('li[refinement-value]:not(.selected).modified').removeClass('modified'); 22809 $('.refinement[uuid]').find('li[refinement-value]:not(.selected)').find('input
22809:checked').prop('checked', false); 22810 redrawUpdatedRefinementHandling(); 22811 } 22812 }); 22813 22814 $(document).on('click', '#main .btn.load-more:not(.disabled)', function(event) { 22815 event.preventDefault(); 22816 var $loadMoreButton = $(this); 22817 22818 // Let's disable the button after first click, so that functionality can complete before being re-enabled 22819 $loadMoreButton.addClass('disabled'); 22820 22821 loadMore(function() { 22822 // Use the callback function to re-enable the Load More button 22823 $loadMoreButton.removeClass('disabled'); 22824 }); 22825 }); 22826 22827 $(document).on('click', '[refinement-open], [filter-open]', function(event) { 22828 var $this = $(this); 22829 var refinementId = $this.attr('refinement-open') || $this.attr('filter-open'); 22830 if (refinementId && $('#attribute-refinement-control-button-' + refinementId).length > 0) { 22831 toggleRefinements(); 22832 $('#attribute-refinement-control-button-' + refinementId).click(); 22833 } 22834 }); 22835} 22836 22837function loadMore(callback) { 22838 if (!dataBuffer['PaginationIndex']) { 22839 dataBuffer['PaginationIndex'] = options.Pagination.Start; 22840 } 22841 if (!dataBuffer['PaginationCount']) { 22842 dataBuffer['PaginationCount'] = options.Pagination.Count; 22843 } 22844 22845 var url = document.location.href; 22846 var currentQueryStringParameters = util.getQueryStringParams(util.getQueryString(url)); 22847 if (currentQueryStringParameters['start']) { 22848 url = util.removeParamFromURL(url, 'start'); 22849 } 22850 url = util.appendParamToURL(url, 'start', dataBuffer['PaginationIndex'] + options.Pagination.Size); 22851 22852 updateProductListing(url, callback, true); 22853} 22854 22855function toggleBodyScrollLock() { 22856 var $body = $('body'); 22857 var bodyScrollLockClass = 'refinements-mobile-scroll-lock'; 22858 22859 if ($body.hasClass(bodyScrollLockClass)) { 22860 $body.removeClass(bodyScrollLockClass); 22861 $body.css('top', ''); 22862 document.body.scrollTop = document.documentElement.scrollTop = dataBuffer['scrollTop']; 22863 } else { 22864 var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; 22865 dataBuffer['scrollTop'] = scrollTop; 22866 $body.css('top', 0 - scrollTop); 22867 $body.addClass(bodyScrollLockClass); 22868 } 22869} 22870 22871function buildUrlForSelectedRefinements(baseUrl, urlForParameters, includeCategory, includeSort) { 22872 var refinementValuesBuffer = {}; 22873 22874 $refinementsInner.find('[refinement-id]:not(.price-refinement):not(.sort-by)').each(function() { 22875 var $refinement = $(this); 22876 var $selectedRefinements = $refinement.find('li[refinement-value]:not(.selected).modified, li[refinement-value].selected:not(.modified)'); 22877 22878 if ($selectedRefinements.length > 0) { 22879 var refinementId = $refinement.attr('refinement-id'); 22880 var mappedRefinementId; 22881 if (refinementId != 'availableStores' && refinementId.indexOf('availableStores') == 0) { 22882 mappedRefinementId = 'availableStores'; 22883 } else { 22884 mappedRefinementId = refinementId; 22885 } 22886 22887 if (!refinementValuesBuffer[mappedRefinementId]) { 22888 refinementValuesBuffer[mappedRefinementId] = []; 22889 } 22890 22891 $selectedRefinements.each(function () { 22892 var value = $(this).attr('refinement-value').replace(' INCH','"'); 22893 var isNewValue = true; 22894 for (var index = 0; index < refinementValuesBuffer[mappedRefinementId].length; index++) { 22895 if (refinementValuesBuffer[mappedRefinementId][index] == value) { 22896 isNewValue = false; 22897 } 22898 } 22899 22900 if (isNewValue && $refinementsInner.find('.list-selections [data-refgroup-id="' + refinementId + '"] [value="' + $(this).attr('refinement-value').replace(/["']/g, "") + '"].pending-clear').length == 0) { 22901 refinementValuesBuffer[mappedRefinementId].push(value); 22902 } 22903 }); 22904 } 22905 }); 22906 22907 var url = baseUrl || options.SearchUrl; 22908 var currentCategoryId = $('.currCGID').val(); 22909 if (includeCategory && currentCategoryId && currentCategoryId != 'null') { 22910 url = util.removeParamFromURL(url, 'cgid'); 22911 url = util.appendParamToURL(url, 'cgid', $('.currCGID').val()); 22912 } 22913 22914 var currentQueryString = util.getQueryString(urlForParameters || document.location.href); 22915 var currentQueryStringParameters = util.getQueryStringParams(currentQueryString); 22916 if (currentQueryStringParameters['q']) { 22917 url = util.removeParamFromURL(url, 'q'); 22918 url = util.appendParamToURL(url, 'q', options.SearchPhrase); 22919 } 22920 22921 if (currentQueryStringParameters['srule']) { 22922 url = util.removeParamFromURL(url, 'srule'); 22923 url = util.appendParamToURL(url, 'srule', currentQueryStringParameters['srule']); 22924 } 22925 22926 var availableStoresValue; 22927 var activeRefinementIndex = 1; 22928 while (url.indexOf('prefn' + activeRefinementIndex) >= 0) { 22929 if (currentQueryStringParameters['prefn' + activeRefinementIndex] == 'availableStores') { 22930 availableStoresValue = currentQueryStringParameters['prefv' + activeRefinementIndex]; 22931 } 22932 22933 url = util.removeParamFromURL(url, 'prefn' + activeRefinementIndex); 22934 url = util.removeParamFromURL(url, 'prefv' + activeRefinementIndex); 22935 activeRefinementIndex++; 22936 } 22937 22938 var availableStoresRefinementIndex; 22939 for (var currentQueryStringParameterKey in currentQueryStringParameters) { 22940 var currentQueryStringParameterValue = currentQueryStringParameters[currentQueryStringParameterKey]; 22941 if (currentQueryStringParameterValue && currentQueryStringParameterValue.indexOf('availableStores') > -1) { 22942 var refinementIndexMatch = currentQueryStringParameterKey.match(/prefn([0-9])+/); 22943 if (refinementIndexMatch && refinementIndexMatch.length > 1) { 22944 availableStoresRefinementIndex = refinementIndexMatch[1]; 22945 } 22946 } 22947 } 22948 22949 if (!availableStoresValue && availableStoresRefinementIndex) { 22950 availableStoresValue = currentQueryStringParameters['prefv' + availableStoresRefinementIndex]; 22951 } 22952 22953 if (availableStoresValue && !refinementValuesBuffer['availableStores']) { 22954 refinementValuesBuffer['availableStores'] = []; 22955 refinementValuesBuffer['availableStores'].push(availableStoresValue); 22956 } 22957 22958 var activeRefinementIndex = 1; 22959 for (var refinementId in refinementValuesBuffer) { 22960 if (refinementId && refinementValuesBuffer[refinementId].length > 0) { 22961 url = util.appendParamToURL(url, 'prefn' + activeRefinementIndex, refinementId); 22962 url = util.appendParamToURL(url, 'prefv' + activeRefinementIndex, refinementValuesBuffer[refinementId].join('|')); 22963 activeRefinementIndex++; 22964 } 22965 } 22966 22967 if ($('[is-price-refinement="true"] input:checked').length > 0 || SitePreferences.PRICE_SLIDER_ENABLED) { 22968 var currentWindowUrlQS = util.getQueryString(window.location.href);
22969 var urlParams = util.getQueryStringParams(currentWindowUrlQS); // Get url parameters in object format 22970 var $refinementPrice = $('[is-price-refinement="true"] input:checked').closest('[is-price-refinement="true"]'); 22971 22972 url = util.removeParamFromURL(url, 'pmin'); 22973 url = util.removeParamFromURL(url, 'pmax'); 22974 22975 if (SitePreferences.PRICE_SLIDER_ENABLED) { 22976 if ($('html').hasClass('size-mobile')) { 22977 url = initMobilePriceSlider(url); 22978 } else { 22979 if (urlParams.pmin) { 22980 url = util.appendParamToURL(url, 'pmin', urlParams.pmin); 22981 } 22982 if (urlParams.pmax) { 22983 url = util.appendParamToURL(url, 'pmax', urlParams.pmax); 22984 } 22985 } 22986 } else { 22987 if ($refinementPrice.attr('pmin')) { 22988 url = util.appendParamToURL(url, 'pmin', $refinementPrice.attr('pmin')); 22989 } 22990 if ($refinementPrice.attr('pmax')) { 22991 url = util.appendParamToURL(url, 'pmax', $refinementPrice.attr('pmax')); 22992 } 22993 } 22994 } 22995 22996 if (includeSort && checkForUpdatedRefinementHandling()) { 22997 url = util.removeParamFromURL(url, 'srule'); 22998 22999 var $sortingRule = $refinementsInner.find('.sort-by option:checked, .sort-by input:checked'); 23000 if ($sortingRule && $sortingRule.length > 0) { 23001 var sortingRule = $sortingRule.attr('sorting-rule'); 23002 if ($sortingRule.attr('default') != 'true') { 23003 url = util.appendParamToURL(url, 'srule', sortingRule); 23004 } 23005 } 23006 } 23007 23008 return url; 23009} 23010 23011function checkForUpdatedRefinementHandling() { 23012 if ((options.RefinementsUIVersion == RefinementUIVersionConstants.Updated) && $html.hasClass('size-mobile') && (pageContext.site != SiteConstants.SiteIds.BootBarnRspUS || options.StoreUIVersion == '2024Redesign')) { 23013 return true; 23014 } 23015 23016 return false; 23017} 23018 23019function redrawUpdatedRefinementHandling($contentParameter, urlForParameters) { 23020 var $content; 23021 if ($contentParameter && $contentParameter.length > 0) { 23022 $content = $contentParameter.find('.refinements'); 23023 } 23024 if (!$content || $content.length == 0) { 23025 $content = $refinementsInner; 23026 } 23027 23028 //updateMultiPriceRefinements($content, urlForParameters); 23029 updateRefinementCounts($content, urlForParameters); 23030 if (options.StoreUIVersion == '2024Redesign') { 23031 updateSelectedRefinements(); 23032 } 23033 updatePendingRefinements(); 23034 23035 var isSortingChanged = false; 23036 var $sortingRule = $('.modal.open .sort-by option:checked, .modal.open .sort-by input:checked'); 23037 if ($sortingRule && $sortingRule.length > 0) { 23038 isSortingChanged = !$sortingRule.attr('selected'); 23039 } 23040 23041 if (isSortingChanged || $content.find('[refinement-value].modified, .list-selections .value.pending-clear').length > 0) { 23042 $content.addClass('refinements-modified'); 23043 $('.refinements-inner-container-footer .apply-refinements').removeClass('disabled'); 23044 } else { 23045 $content.removeClass('refinements-modified'); 23046 $('.refinements-inner-container-footer .apply-refinements').addClass('disabled'); 23047 } 23048 23049 if ($('[is-price-refinement="true"] input:checked').length > 0) { 23050 $content.addClass('price-selected'); 23051 } else { 23052 $content.removeClass('price-selected'); 23053 } 23054 23055 var $refinementsModalProductSelections = $('.refinements-inner-container-header .product-selections'); 23056 if (($refinementsModalProductSelections.find('.list-selections .value.applied').length + $refinementsModalProductSelections.find('.list-selections > .pending-selections > span').length) > 0) { 23057 $refinementsModalProductSelections.show(); 23058 $('.refinements-inner-container-footer .clear-refinements').removeClass('disabled'); 23059 } else { 23060 $refinementsModalProductSelections.hide(); 23061 $('.refinements-inner-container-footer .clear-refinements').addClass('disabled'); 23062 } 23063 var $productSelectionContainer; 23064 if (pageContext.site === SiteConstants.SiteIds.SheplersUS) { 23065 $productSelectionContainer = $('.primary-content > .sort-and-refine > .product-selections'); 23066 } else { 23067 $productSelectionContainer = $('.primary-content > .product-selections'); 23068 } 23069 23070 if ($productSelectionContainer.find('.list-selections .value.applied').length > 0) { 23071 $productSelectionContainer.show(); 23072 } else { 23073 $productSelectionContainer.hide(); 23074 } 23075} 23076 23077function updateSelectedRefinements() { 23078 var $refinements = $refinementsInner.find('.refinement[uuid].expanded'); 23079 $refinements.each(function() { 23080 var $refinement = $(this); 23081
23082 var $selectedRefinementsContainer = $refinement.find('.toggle').find('.list-selections'); 23083 if (!$selectedRefinementsContainer || !$selectedRefinementsContainer.length) { 23084 $refinement.find('.toggle').append('<div class="product-selections"><ul class="list-selections"/></div>'); 23085 $selectedRefinementsContainer = $refinement.find('.toggle .list-selections'); 23086 } 23087 23088 var $selectedRefinementsValues; 23089 if (options.StoreUIVersion == '2024Redesign') { 23090 $selectedRefinementsValues = $refinement.find('ul:not(.popular)').find('li[refinement-value].selected'); 23091 } else { 23092 $selectedRefinementsValues = $refinement.find('ul:not(.popular)').find('li[refinement-value].selected, input:checked:not(.modified)'); 23093 } 23094 var selectedRefinementsBuffer = []; 23095 $selectedRefinementsValues.each(function(index, element) { 23096 var $this = $(this); 23097 var selectedRefinementId = $this.closest('[refinement-id]').attr('refinement-id'); 23098 var selectedRefinementValue = $this.closest('[refinement-value]').attr('refinement-value'); 23099 var selectedRefinementText = $this.closest('[refinement-value]').attr('display-value') || selectedRefinementValue; 23100 23101 if (!selectedRefinementsBuffer[selectedRefinementId]) { 23102 selectedRefinementsBuffer[selectedRefinementId] = []; 23103 } 23104 23105 var isNewValue = true; 23106 for (var index = 0; index < selectedRefinementsBuffer[selectedRefinementId].length; index++) { 23107 if (selectedRefinementsBuffer[selectedRefinementId][index].Value == selectedRefinementValue) { 23108 isNewValue = false; 23109 } 23110 } 23111 23112 if (isNewValue) { 23113 selectedRefinementsBuffer[selectedRefinementId].push({ 23114 Text: selectedRefinementText, 23115 Value: selectedRefinementValue 23116 }); 23117 } 23118 }); 23119 23120 var selectedRefinementsHtml = ''; 23121 for (var selectedRefinementElement in selectedRefinementsBuffer) { 23122 var selectedRefinement = selectedRefinementsBuffer[selectedRefinementElement]; 23123 23124 var selectedRefinementValuesHtml = ''; 23125 for (var selectedRefinementDataElement in selectedRefinement) { 23126 var selectedRefinementData = selectedRefinement[selectedRefinementDataElement]; 23127 var selectedRefinementText = selectedRefinementData.Text; 23128 var selectedRefinementValue = selectedRefinementData.Value; 23129 23130 if (selectedRefinementValuesHtml) { 23131 selectedRefinementValuesHtml += '<span class="delimiter">,</span>'; 23132 } 23133 23134 var selectedRefinementDisplayValue = selectedRefinementValue; 23135 if (selectedRefinementElement == 'Price') { 23136 selectedRefinementDisplayValue = $refinementsInner.find('[refinement-id="' + selectedRefinementElement + '"]').attr('display-value'); 23137 } else if (selectedRefinementElement == 'size') { 23138 selectedRefinementDisplayValue = 'Size ' + selectedRefinementDisplayValue; 23139 } 23140 23141 selectedRefinementValuesHtml += '<span class="value" refinement-value="' + selectedRefinementValue + '">' + 23142 selectedRefinementText + 23143 '<a class="close-btn"><i class="fa fa-close"></i></a>' + 23144 '</span>'; 23145 } 23146 23147 selectedRefinementsHtml += '<span data-refgroup-id="' + selectedRefinementElement + '">' + 23148 '<span class="key">' + selectedRefinementElement + '</span>' + 23149 '<span class="colon">:</span>' + 23150 selectedRefinementValuesHtml + 23151 '</span>'; 23152 } 23153 23154 $selectedRefinementsContainer.html(selectedRefinementsHtml); 23155 }); 23156} 23157 23158function updatePendingRefinements() { 23159 var $pendingRefinementsContainer; 23160 if (options.StoreUIVersion == '2024Redesign') { 23161 var $selectedRefinementsContainer = $refinementsInner.find('.refinement.expanded .toggle').find('.product-selections'); 23162 if (!$selectedRefinementsContainer || !$selectedRefinementsContainer.length) { 23163 $refinementsInner.find('.refinement.expanded .toggle').append('<div class="product-selections"><ul class="list-selections"/></div>'); 23164 } 23165 23166 $pendingRefinementsContainer = $refinementsInner.find('.refinement.expanded .toggle').find('.pending-selections'); 23167 if (!$pendingRefinementsContainer || !$pendingRefinementsContainer.length) { 23168 $refinementsInner.find('.refinement.expanded .toggle .list-selections').append('<li class="pending-selections"/>'); 23169 $pendingRefinementsContainer = $refinementsInner.find('.refinement.expanded .toggle .list-selections .pending-selections'); 23170 } 23171 } else { 23172 $pendingRefinementsContainer = $refinementsInner.find('.pending-selections'); 23173 } 23174 23175 var $pendingRefinementsValues; 23176 if (options.StoreUIVersion == '2024Redesign') { 23177 $pendingRefinementsValues = $('.refinement[uuid].expanded ul:not(.popular)').find('li[refinement-value]:not(.selected).modified, input.modified:not([checked="checked"])'); 23178 } else { 23179 $pendingRefinementsValues = $('.refinement[uuid] ul:not(.popular)').find('li[refinement-value]:not(.selected).modified'); 23180 } 23181 var pendingRefinementsBuffer = []; 23182 23183 $pendingRefinementsValues.each(function(index, element) { 23184 var $this = $(this);
23185 var pendingRefinementId = $this.closest('[refinement-id]').attr('refinement-id'); 23186 var pendingRefinementValue = $this.closest('[refinement-value]').attr('refinement-value'); 23187 var pendingRefinementText = $this.closest('[refinement-value]').attr('display-value') || pendingRefinementValue; 23188 23189 if (!pendingRefinementsBuffer[pendingRefinementId]) { 23190 pendingRefinementsBuffer[pendingRefinementId] = []; 23191 } 23192 23193 var isNewValue = true; 23194 for (var index = 0; index < pendingRefinementsBuffer[pendingRefinementId].length; index++) { 23195 if (pendingRefinementsBuffer[pendingRefinementId][index].Value == pendingRefinementValue) { 23196 isNewValue = false; 23197 } 23198 } 23199 23200 if (isNewValue) { 23201 pendingRefinementsBuffer[pendingRefinementId].push({ 23202 Text: pendingRefinementText, 23203 Value: pendingRefinementValue 23204 }); 23205 } 23206 }); 23207 23208 var pendingRefinementsHtml = ''; 23209 for (var pendingRefinementElement in pendingRefinementsBuffer) { 23210 var pendingRefinement = pendingRefinementsBuffer[pendingRefinementElement]; 23211 23212 var pendingRefinementValuesHtml = ''; 23213 for (var pendingRefinementDataElement in pendingRefinement) { 23214 var pendingRefinementData = pendingRefinement[pendingRefinementDataElement]; 23215 var pendingRefinementText = pendingRefinementData.Text; 23216 var pendingRefinementValue = pendingRefinementData.Value; 23217 23218 if (pendingRefinementValuesHtml) { 23219 pendingRefinementValuesHtml += '<span class="delimiter">,</span>'; 23220 } 23221 23222 var pendingRefinementDisplayValue = pendingRefinementValue; 23223 if (pendingRefinementElement == 'Price') { 23224 pendingRefinementDisplayValue = $refinementsInner.find('[refinement-id="' + pendingRefinementElement + '"]').attr('display-value'); 23225 } else if (pendingRefinementElement == 'size') { 23226 pendingRefinementDisplayValue = 'Size ' + pendingRefinementDisplayValue; 23227 } 23228 23229 pendingRefinementValuesHtml += '<span class="value" refinement-value="' + pendingRefinementValue + '">' + 23230 pendingRefinementText + 23231 '<a class="close-btn"><i class="fa fa-close"></i></a>' + 23232 '</span>'; 23233 } 23234 23235 pendingRefinementsHtml += '<span data-refgroup-id="' + pendingRefinementElement + '">' + 23236 '<span class="key">' + pendingRefinementElement + '</span>' + 23237 '<span class="colon">:</span>' + 23238 pendingRefinementValuesHtml + 23239 '</span>'; 23240 } 23241 23242 $pendingRefinementsContainer.html(pendingRefinementsHtml); 23243} 23244 23245function updateRefinementCounts($contentParameter, urlForParameters) { 23246 var url = buildUrlForSelectedRefinements(Urls.getRefinementCounts, null, true); 23247 var $content = $contentParameter || $(document); 23248 var $refinements = $content.find('.refinement[uuid]'); 23249 var $refinementProductCount = $content.find('.refinement button .product-count'); 23250 $refinementProductCount.loading(); 23251 23252 var refinementGroups = []; 23253 var refinementGroupIndex = 0; 23254 var refinementGroupSizeLimit = 2000; 23255 var refinementGroupSizeCurrent = 0; 23256 $.each($refinements, function(index, element) { 23257 var $refinement = $(element); 23258 var refinementValueCount = $refinement.find('[refinement-value]').length; 23259 if ((refinementValueCount + refinementGroupSizeCurrent) >= refinementGroupSizeLimit) { 23260 refinementGroupIndex++; 23261 refinementGroupSizeCurrent = 0; 23262 } 23263 23264 if (!refinementGroups[refinementGroupIndex]) { 23265 refinementGroups[refinementGroupIndex] = $refinement; 23266 } else { 23267 refinementGroups[refinementGroupIndex] = refinementGroups[refinementGroupIndex].add($refinement); 23268 } 23269 23270 refinementGroupSizeCurrent += refinementValueCount; 23271 }); 23272 23273 dataBuffer['updateRefinementCountsRefinementGroupIndex'] = 0; 23274 dataBuffer['updateRefinementCountsRefinementGroupCount'] = refinementGroups.length; 23275 23276 $.each(refinementGroups, function(index, element) { 23277 var $refinementGroup = $(element); 23278 updateRefinementCountsForRefinements(url, $refinementGroup); 23279 }); 23280} 23281 23282function updateRefinementCountsForRefinements(url, $refinements) { 23283 var refinementIds = $refinements.map(function(index, element) { 23284 return $(element).attr('refinement-id'); 23285 }).get(); 23286 23287 if (refinementIds) { 23288 var $refinementProductCount = $refinements.find('button .product-count'); 23289 $refinementProductCount.loading(); 23290 23291 if (dataBuffer['updateRefinementCountsRefinementGroupCount'] && dataBuffer['updateRefinementCountsRefinementGroupCount'] > 1) { 23292 url = util.appendParamToURL(url, 'refinements', refinementIds.join()); 23293 } 23294 23295 $.ajax({ 23296 type: 'get', 23297 url: url, 23298 success: function(data) { 23299 $refinements.each(function(index, element) { 23300 var $refinement = $(element); 23301 if (data) { 23302 var refinementId = $refinement.attr('refinement-id'); 23303 var $refinementValues = $refinement.find('ul li[refinement-value]'); 23304 if (data.Refinements[refinementId]) { 23305 $.each($refinementValues, function(index, element) { 23306 var $refinementValue = $(element); 23307 var refinementValue = $refinementValue.attr('refinement-value'); 23308 var refinementHtml = data.Refinements[refinementId][refinementValue] ? data.Refinements[refinementId][refinementValue] : '0'; 23309 refinementHtml += '<span class="visually-hidden"> Product Count</span>'; 23310 23311 if ($refinementValue.find('input[type="checkbox"]').prop('checked') || data.Refinements[refinementId][refinementValue]) { 23312 $refinementValue.attr('refinement-count', data.Refinements[refinementId][refinementValue]).find('.refinement-label').html(refinementValue).find('.refinement-count').html(refinementHtml); 23313 } else { 23314 $refinementValue.attr('refinement-count', 0).find('.refinement-label').html(refinementValue).find('.refinement-count').html(refinementHtml); 23315 } 23316 }); 23317 23318 var $popularRefinementValues = $refinement.find('ul.popular-sizes, ul.popular').find('li[refinement-value]'); 23319 var $popularRefinementValuesChecksContainer = $refinement.find('.checks-container.popular'); 23320 var hasPopularRefinementValues = $popularRefinementValues.filter(':not([refinement-count="0"])').length > 0 || $popularRefinementValues.filter(':not([refinement-count="0"])').find('input
23320:checked').length > 0; 23321 if (hasPopularRefinementValues) { 23322 $popularRefinementValuesChecksContainer.show(); 23323 } else { 23324 $popularRefinementValuesChecksContainer.hide(); 23325 } 23326 23327 var $normalRefinementValues = $refinement.find('ul:not(.popular-sizes):not(.popular)').find('li[refinement-value]'); 23328 var $normalRefinementValuesChecksContainer = $refinement.find('.checks-container:not(.popular)'); 23329 var hasNormalRefinementValues = $normalRefinementValues.filter(':not([refinement-count="0"])').length > 0 || $normalRefinementValues.filter(':not([refinement-count="0"])').find('input:checked').length > 0; 23330 if (hasNormalRefinementValues) { 23331 $normalRefinementValuesChecksContainer.show(); 23332 } else { 23333 $normalRefinementValuesChecksContainer.hide(); 23334 } 23335 23336 /* --- Price slider modifications --- */ 23337 var hasPriceSlider = SitePreferences.PRICE_SLIDER_ENABLED && (refinementId == 'Price' || refinementId == 'ref-postDiscountPrice'); 23338 if (hasPriceSlider) { 23339 var pageUrl = util.getQueryString(window.location.href); 23340 if (pageUrl) { 23341 var hasPriceAttributes = pageUrl.indexOf('pmin') > -1 || pageUrl.indexOf('pmax') > -1; 23342 var isMobile = $('html').hasClass('size-mobile'); 23343 if (hasPriceAttributes && !isMobile) { 23344 $('.price-refinement').find('.refinement-body').show(); 23345 } else { 23346 $('.price-refinement').find('.refinement-body').hide(); 23347 } 23348 } 23349 } 23350 23351 if (hasNormalRefinementValues || hasPopularRefinementValues || hasPriceSlider) { 23352 $refinement.removeClass('hidden'); 23353 } else { 23354 $refinement.addClass('hidden'); 23355 } 23356 } else { 23357 $refinement.addClass('hidden'); 23358 } 23359 } else { 23360 if ($refinement.find('ul.checks, ul.swatches').find('li').length == 0) { 23361 $refinement.addClass('hidden'); 23362 } else { 23363 $refinement.removeClass('hidden'); 23364 } 23365 } 23366 $refinement.removeAttr('loading'); 23367 updateMoreLess($refinement); 23368 }); 23369 }, 23370 complete: function() { 23371 dataBuffer['updateRefinementCountsRefinementGroupIndex']++; 23372 // ADA compliance - for easier readability for screen readers 23373 $('.refinements .selected[refinement-value] span.refinement-label').prepend('<span class="visually-hidden">Currently Selected: </span>'); 23374 if ($refinementProductCount.attr('loading')) { 23375 $refinementProductCount.loading('destroy'); 23376 } 23377 updateRefinementCountsComplete(); 23378 } 23379 }); 23380 } 23381} 23382 23383function updateRefinementCountsComplete() { 23384 if (dataBuffer['updateRefinementCountsRefinementGroupIndex'] == dataBuffer['updateRefinementCountsRefinementGroupCount']) { 23385 updateProductCountInHeader(); 23386 updateRefinementsInHeader(); 23387 } 23388} 23389 23390function updateProductCountInHeader() { 23391 var $refinementsProductCount = $('.refinements .slot-grid-subheader .product-count span'); 23392 var $headerProductCount = $('.top-banner .slot-grid-subheader .product-count span'); 23393 23394 if ($refinementsProductCount.length > 0 && $headerProductCount.length > 0) { 23395 $headerProductCount.text($refinementsProductCount.text()); 23396 } 23397} 23398 23399function updateRefinementsInHeader() { 23400 var $refinementsRefinements = $('.primary-content .product-selections'); 23401 var $headerRefinements = $('.top-banner .product-selections'); 23402 23403 if ($refinementsRefinements.length > 0 && $headerRefinements.length > 0) { 23404 $headerRefinements.html($refinementsRefinements.html()); 23405 } 23406} 23407 23408function updateMoreLess($refinement) { 23409 var refinementId = $refinement.attr('refinement-id'); 23410 var $refinementValuesContainer = $refinement.find('ul:not(.popular-sizes):not(.popular)'); 23411 var $refinementContainer = $refinementValuesContainer.closest('.refinement-body-inner'); 23412 var $moreLink = $refinementValuesContainer.find('.ref-filter.more-link').closest('li').detach().first(); 23413 var $refinementValues = $refinementValuesContainer.find('li[refinement-value]'); 23414 var $refinementValuesVisible = $refinementValues.filter(':not([refinement-count="0"])'); 23415 23416 if (!$refinement.hasClass('more-expanded') && $moreLink.length > 0) { 23417 var moreLessCount; 23418 if ((pageContext.site == SiteConstants.SiteIds.BootBarnUS || pageContext.site == SiteConstants.SiteIds.SheplersUS) && $refinement.attr('refinement-id') && $refinement.attr('refinement-id').toLowerCase() == 'size') { 23419 moreLessCount = 12; 23420 } else if (pageContext.site == SiteConstants.SiteIds.BootBarnRspUS && options.StoreUIVersion == '2024Redesign') { 23421 moreLessCount = 100000; 23422 } else { 23423 moreLessCount = 9; 23424 } 23425 23426 if ($refinementValuesVisible.length > moreLessCount) { 23427 var moreLessIndex = $refinementValuesVisible.index($refinementValuesVisible.eq(moreLessCount)); 23428 $refinementValuesVisible.slice(0, moreLessIndex).removeClass('toggleable hidden'); 23429 $refinementValuesVisible.slice(moreLessIndex, $refinementValues.length).addClass('toggleable hidden'); 23430 $refinementValuesVisible.eq(moreLessIndex - 1).after($moreLink); 23431 $refinementValuesContainer.find('.more-link-container').show(); 23432 $refinementContainer.find('.less-refinement').show(); 23433 } else { 23434 $refinementValuesVisible.removeClass('toggleable hidden'); 23435 $refinementValuesVisible.eq($refinementValuesVisible.length - 1).after($moreLink); 23436 $refinementValuesContainer.find('.more-link-container').hide(); 23437 $refinementContainer.find('.less-refinement').hide(); 23438 } 23439 } 23440 23441 if (!$('html').hasClass('size-mobile') || window.innerWidth > 767) { 23442 if (refinementsExpanded) { 23443 if (refinementsExpanded.indexOf(refinementId) > -1) { 23444 $refinement.addClass('expanded'); 23445 $refinement.find('.toggle').addClass('expanded'); 23446 $refinement.find('.refinement-body').show(); 23447 } else { 23448 $refinement.removeClass('expanded'); 23449 $refinement.find('.toggle').removeClass('expanded'); 23450 $refinement.find('.refinement-body').hide(); 23451 } 23452 } 23453 if ($('.refinement.expanded').length > 0) { 23454 $('.refinements').addClass('refinement-expanded'); 23455 } else { 23456 $('.refinements').removeClass('refinement-expanded'); 23457 } 23458 23459 if (refinementsViewAll && $refinementValuesVisible.length > moreLessCount) { 23460 if (refinementsViewAll.indexOf(refinementId) > -1) { 23461 $refinement.addClass('more-expanded'); 23462 $refinement.find('.toggleable').removeClass('hidden'); 23463 $refinement.find('.more-link-container').css('display', 'none'); 23464 $refinement.find('.less-refinement.toggleable').removeClass('hidden'); 23465 } else { 23466 $refinement.removeClass('more-expanded'); 23467 $refinement.find('.more-link-container').css('display', 'list-item'); 23468 $refinement.find('.less-refinement.toggleable').addClass('hidden'); 23469 } 23470 } 23471 } 23472} 23473 23474var refGroupsStates = { 23475 cookieRefGroupsKey: 'refgroup', 23476 saveState: function(refgroup, visible) { 23477 if (this.getCookie('dw_cookies_accepted')) { 23478 var getRefGroupCookie = this.getCookie(this.cookieRefGroupsKey) || '{}'; 23479 var getRefGroupObj = JSON.parse(getRefGroupCookie); 23480 getRefGroupObj[refgroup] = visible; 23481 getRefGroupCookie = JSON.stringify(getRefGroupObj); 23482 this.setCookie('refgroup', getRefGroupCookie); 23483 } 23484 }, 23485 checkState: function(refgroup) { 23486 if (this.getCookie('dw_cookies_accepted')) { 23487 var getRefGroupCookie = this.getCookie(this.cookieRefGroupsKey); 23488 if (getRefGroupCookie) { 23489 var getRefGroupObj = JSON.parse(getRefGroupCookie); 23490 if (getRefGroupObj[refgroup] != undefined) { 23491 return getRefGroupObj[refgroup]; 23492 } 23493 } 23494 } 23495 return true; 23496 }, 23497 getCookie: function (key) { 23498 var cookies = document.cookie.split(';'); 23499 for (var i = 0; i < cookies.length; i++) { 23500 var tokens = cookies[i].split('='); 23501 var cookieKey = tokens[0].trim(); 23502 if (cookieKey === key) { 23503 return tokens[1]; 23504 } 23505 } 23506 return ''; 23507 }, 23508 setCookie: function(key, value, minutes) { 23509 var date = new Date(); 23510 date.setTime(date + (minutes * 60 * 1000)); 23511 document.cookie = key + '=' + value + '; expires=' + date.toGMTString() + '; path=/'; 23512 } 23513} 23514 23515function searchStores() { 23516 var searchStoresQuery = $('.search-stores-query'); 23517 23518 $('.go-find-stores').on('click', function (e) { 23519 var el = $(e.target), 23520 data = { 23521 typeKey: el.attr('type') 23522 }; 23523 23524 if (el.attr('type') === 'geo') { 23525 if (navigator.geolocation) { 23526 navigator.geolocation.getCurrentPosition(function(position) { 23527 data.longitude = position.coords.longitude; 23528 data.latitude = position.coords.latitude; 23529 23530 searchStoresAJAX(data); 23531 }); 23532 } else { 23533 alert('Your browser not supported geolocation'); 23534 } 23535 } else { 23536 data.searchKey = searchStoresQuery.val().trim(); 23537 23538 var geocoder = new google.maps.Geocoder(); 23539 geocoder.geocode( { 'address': searchStoresQuery.val().trim()}, function(results, status) { 23540 if (status == google.maps.GeocoderStatus.OK) { 23541 data.longitude = results[0].geometry.location.lng(); 23542 data.latitude = results[0].geometry.location.lat(); 23543 23544 searchStoresAJAX(data); 23545 } else { 23546 alert("Geocode was not successful for the following reason: " + status); 23547 } 23548 }); 23549 } 23550 }); 23551} 23552 23553function searchStoresAJAX(params) { 23554 $.ajax({ 23555 type: 'get', 23556 url: Urls.searchStores, 23557 data: params, 23558 23559 success: function (data) { 23560 var popupList = $('.category-popup-list-stores'); 23561 23562 $('.grid-page-storeselector-popup').dialog('close'); 23563 popupList 23564 .html(data) 23565 .dialog({ 23566 width: 450, 23567 autoOpen: false, 23568 modal: true, 23569 resizable: false 23570 }); 23571 23572 popupList.parent().find('.ui-dialog-title').html(data.match(/Stores near.{0,}/mi)[0].replace('</span>', '')); 23573 popupList.dialog('open'); 23574 } 23575 }); 23576} 23577 23578function showVariantInventoryMessaging() { 23579 if (options && options.Bopis && options.Bopis.IsLocationSearchFiltered) { 23580 return; 23581 } 23582 23583 $.ajax({ 23584 dataType: 'json', 23585 url: page.variantInventoryMessagingUrl, 23586 async: true 23587 }) 23588 // success 23589 .done(function (values) { 23590 if (values) {
23591 values.forEach(function(val, idx) { 23592 var $tile = $('[data-itemid="' + val.masterProductID + '"]'); 23593 if ($tile.length > 0) { 23594 if ( typeof val.urlHash != 'undefined' ) { 23595 var filterP = val.urlHash.replace('#','').split('=')[0]; 23596 var rr = new RegExp("prefn[0-9]="+filterP); 23597 if ( location.href.match(rr) ) { 23598 if (pageContext.site === SiteConstants.SiteIds.SheplersUS) { 23599 //Put the inventory message in the product badge if variantWhsInStock is false 23600 var productBadge = $tile.find('.product-badge.whs-in-stock'); 23601 if (val.variantWhsInStock == 'true') { 23602 productBadge.show(); 23603 } else if (val.dropshipLead <= 10) { 23604 productBadge.text(val.inventoryMsg); 23605 productBadge.removeClass('whs-in-stock').addClass('availability-msg').show(); 23606 } 23607 23608 } else { 23609 var $msg = $('<div />').attr('class', 'availability-msg').text(val.inventoryMsg); 23610 $tile.find('.product-pricing').append($msg); 23611 if (val.variantWhsInStock == 'true') { 23612 $tile.find('.whs-in-stock').show(); 23613 } 23614 } 23615 } 23616 } 23617 } 23618 }); 23619 } 23620 }) 23621 .fail(function (xhr, textStatus) { 23622 if (textStatus === 'parsererror') { 23623 console.log('Inventory Messaging Error ' + Resources.BAD_RESPONSE); 23624 } 23625 }); 23626} 23627 23628function saveScrollPosition() { 23629 if (sessionStorage) { 23630 $(document).off('scroll.ScrollPositionSave').on('scroll.ScrollPositionSave', function(event) { 23631 var categoryId = $('.currCGID').val(); 23632 var sessionStorageScrollPosition; 23633 try { 23634 sessionStorageScrollPosition = JSON.parse(sessionStorage.ScrollPosition); 23635 } catch(exception) {} 23636 if (!sessionStorageScrollPosition || typeof sessionStorageScrollPosition != 'object' || !sessionStorageScrollPosition[categoryId]) { 23637 sessionStorageScrollPosition = {}; 23638 } 23639 sessionStorageScrollPosition[categoryId] = $(window).scrollTop(); 23640 sessionStorage.ScrollPosition = JSON.stringify(sessionStorageScrollPosition); 23641 }); 23642 } 23643} 23644 23645function loadScrollPosition() { 23646 if (sessionStorage) { 23647 var categoryId = $('.currCGID').val(); 23648 var sessionStorageScrollPosition; 23649 try { 23650 sessionStorageScrollPosition = JSON.parse(sessionStorage.ScrollPosition); 23651 } catch(exception) {} 23652 if (sessionStorageScrollPosition && typeof sessionStorageScrollPosition == 'object' && sessionStorageScrollPosition[categoryId]) { 23653 $(window).scrollTop(sessionStorageScrollPosition[categoryId]); 23654 } 23655 } 23656} 23657 23658function initializeStickyRefinements() { 23659 $(document).off('scroll.StickyRefinements StickyRefinements.Refresh').on('scroll.StickyRefinements StickyRefinements.Refresh', function(event) { 23660 var $refinements = $('#secondary'); 23661 var $primary = $('#primary'); 23662 23663 if ($('html').hasClass('size-mobile') || window.innerWidth <= 767) { 23664 $refinements.css('transform', ''); 23665 $refinements.scrollTop(0); 23666 $refinements.height('auto'); 23667 } else { 23668 var documentScrollTop = parseInt($(document).scrollTop(), 10); 23669 var documentScrollDelta = 0; 23670 if (dataBuffer['documentScrollTop']) { 23671 documentScrollDelta = documentScrollTop - dataBuffer['documentScrollTop']; 23672 } 23673 var windowHeight = parseInt($(window).height(), 10); 23674 var windowBottom = documentScrollTop + windowHeight; 23675 var refinementsScrollHeight = parseInt($refinements[0].scrollHeight, 10); 23676 var refinementsOffsetTop = parseInt($refinements.offset().top, 10); 23677 var refinementsOffsetBottom = parseInt($refinements.offset().top + refinementsScrollHeight, 10); 23678 var primaryTop = parseInt($primary.offset().top, 10); 23679 var primaryBottom = primaryTop + parseInt($primary.outerHeight(), 10); 23680 var documentScrollTopFromPrimaryTop = documentScrollTop - primaryTop; 23681 if (documentScrollTopFromPrimaryTop < 0) { 23682 documentScrollTopFromPrimaryTop = 0; 23683 } 23684 var windowBottomFromPrimaryBottom = windowBottom - primaryBottom; 23685 if (windowBottomFromPrimaryBottom < 0) { 23686 windowBottomFromPrimaryBottom = 0; 23687 } 23688 var refinementsOffsetTopNew; 23689 var refinementsOffsetBottomNew; 23690 if (documentScrollDelta) { 23691 refinementsOffsetTopNew = refinementsOffsetTop + documentScrollDelta; 23692 refinementsOffsetBottomNew = refinementsOffsetTopNew + refinementsScrollHeight; 23693 } 23694 23695 var refinementsTranslateY; 23696 if ($refinements.outerHeight() >= $primary.outerHeight()) { 23697 refinementsTranslateY = 0; 23698 } else if (documentScrollDelta >= 0) { 23699 refinementsTranslateY = refinementsOffsetTop - primaryTop; 23700 23701 if ($refinements.hasClass('top')) { 23702 $('body').removeClass('sticky-refinements'); 23703 $refinements.removeClass('top bottom'); 23704 refinementsTranslateY = refinementsTranslateY - documentScrollDelta; 23705 } 23706 23707 if (refinementsOffsetBottom >= primaryBottom) { 23708 $('body').removeClass('sticky-refinements'); 23709 $refinements.removeClass('top bottom'); 23710 refinementsTranslateY = primaryBottom - primaryTop - refinementsScrollHeight; 23711 } else if (refinementsOffsetBottom < windowBottom && primaryBottom >= windowBottom) { 23712 if (refinementsScrollHeight > windowHeight) { 23713 $('body').addClass('sticky-refinements'); 23714 $refinements.removeClass('top bottom'); 23715 $refinements.addClass('bottom'); 23716 } else if (documentScrollTop >= primaryTop) { 23717 $('body').addClass('sticky-refinements'); 23718 $refinements.removeClass('top bottom'); 23719 $refinements.addClass('top'); 23720 } 23721 } else if (refinementsOffsetBottom < windowBottom && primaryBottom < windowBottom) { 23722 if ((documentScrollTop + refinementsScrollHeight) > primaryBottom) { 23723 $('body').removeClass('sticky-refinements'); 23724 $refinements.removeClass('top bottom'); 23725 refinementsTranslateY = primaryBottom - primaryTop - refinementsScrollHeight; 23726 } else { 23727 $('body').addClass('sticky-refinements'); 23728 $refinements.removeClass('top bottom'); 23729 $refinements.addClass('top'); 23730 } 23731 } 23732 } else if (documentScrollDelta < 0) { 23733 refinementsTranslateY = refinementsOffsetTop - primaryTop; 23734 23735 if ($refinements.hasClass('bottom')) { 23736 $('body').removeClass('sticky-refinements'); 23737 $refinements.removeClass('top bottom'); 23738 refinementsTranslateY = refinementsTranslateY - documentScrollDelta; 23739 } 23740 23741 if (refinementsOffsetTop <= primaryTop && documentScrollTop <= primaryTop) { 23742 $('body').removeClass('sticky-refinements'); 23743 $refinements.removeClass('top bottom'); 23744 refinementsTranslateY = 0; 23745 } else if (refinementsOffsetBottom >= primaryBottom && refinementsOffsetTop <= documentScrollTop) { 23746 $('body').removeClass('sticky-refinements'); 23747 $refinements.removeClass('top bottom'); 23748 refinementsTranslateY = primaryBottom - primaryTop - refinementsScrollHeight; 23749 } else if (refinementsOffsetTop >= documentScrollTop && refinementsOffsetTop > primaryTop) { 23750 $('body').addClass('sticky-refinements'); 23751 $refinements.removeClass('top bottom'); 23752 $refinements.addClass('top'); 23753 } 23754 } 23755 23756 if (refinementsTranslateY != undefined) { 23757 $refinements.css('transform', 'translateY(' + refinementsTranslateY + 'px)'); 23758 } 23759 23760 dataBuffer['documentScrollTop'] = documentScrollTop; 23761 } 23762 }); 23763} 23764 23765function initializeStickySubheader() { 23766 $(document).off('scroll.StickySubheader').on('scroll.StickySubheader', function(event) { 23767 var $slotGridSubheader = $('.slot-grid-subheader'); 23768 var $slotGridSubheaderFixed = $('.slot-grid-subheader-fixed'); 23769 if ($slotGridSubheader.length > 0 && $slotGridSubheaderFixed.length > 0) { 23770 var $primary = $('#primary'); 23771 var documentScrollTop = $(document).scrollTop(); 23772 var windowHeight = $(window).height(); 23773 var windowBottom = documentScrollTop + windowHeight; 23774 var primaryTop = $primary.offset().top; 23775 var primaryBottom = primaryTop + $primary.outerHeight(); 23776 23777 if (primaryBottom < windowBottom) { 23778 $slotGridSubheaderFixed.addClass('hidden'); 23779 } else if ($slotGridSubheader.offset().top < documentScrollTop) { 23780 $slotGridSubheaderFixed.removeClass('hidden'); 23781 } else { 23782 $slotGridSubheaderFixed.addClass('hidden'); 23783 } 23784 } 23785 }); 23786} 23787 23788function initializeRefinementFilterByText() { 23789 $(document).off('keyup.RefinementFilterText').on('keyup.RefinementFilterText', '.refinement .refinement-filter-text input', function(event) { 23790 var $this = $(this); 23791 var filterText = $this.val(); 23792 var filterTextRegEx; 23793 var $container = $this.closest('.refinement-filter-text'); 23794 var $reset = $container.find('a.reset'); 23795 var $noResults = $container.find('.no-results'); 23796 var $refinement = $this.closest('.refinement'); 23797 var $refinementValues = $this.closest('.checks-container').find('[refinement-value]:not([refinement-count="0"])'); 23798 23799 if (filterText) { 23800 filterTextRegEx = new RegExp('^' + filterText + '| ' + filterText, 'gi'); 23801 $reset.addClass('show'); 23802 $refinement.addClass('filter-text'); 23803 $refinementValues.each(function(index, element) { 23804 var $refinementValue = $(this); 23805 if ($refinementValue.attr('refinement-value').match(filterTextRegEx)) { 23806 $refinementValue.addClass('filter-text-show'); 23807 } else { 23808 $refinementValue.removeClass('filter-text-show').hide(); 23809 } 23810 }); 23811 if ($refinementValues.filter(':visible').length == 0) { 23812 $noResults.find('span').text(filterText); 23813 $noResults.show().attr('tabindex', '0'); 23814 } else { 23815 $noResults.hide().removeAttr('tabindex'); 23816 } 23817 } else { 23818 $reset.removeClass('show'); 23819 $refinement.removeClass('filter-text'); 23820 $refinementValues.removeClass('filter-text-show').css('display', ''); 23821 $noResults.hide().removeAttr('tabindex'); 23822 } 23823 }); 23824 23825 $(document).off('click.RefinementFilterTextReset').on('click.RefinementFilterTextReset', '.refinement .refinement-filter-text a.reset', function(event) { 23826 var $this = $(this); 23827 var $container = $this.closest('.refinement-filter-text'); 23828 var $noResults = $container.find('.no-results'); 23829 var $refinement = $this.closest('.refinement'); 23830 var $refinementValues = $this.closest('.checks-container').find('[refinement-value]'); 23831 23832 $this.removeClass('show'); 23833 $refinement.removeClass('filter-text'); 23834 $refinement.find('.refinement-filter-text input').val(''); 23835 $refinementValues.removeClass('filter-text-show').css('display', ''); 23836 $noResults.hide().removeAttr('tabindex'); 23837 }); 23838} 23839 23840function saveExpandedRefinements() { 23841 refinementsExpanded = $('.refinements [refinement-id].expanded').map(function(index, element) { 23842 return $(this).attr('refinement-id'); 23843 }).get(); 23844 23845 refinementsViewAll = $('.refinements [refinement-id].more-expanded').map(function(index, element) { 23846 return $(this).attr('refinement-id'); 23847 }).get(); 23848} 23849 23850function redrawShopMyStore() { 23851 $.ajax({ 23852 method: 'GET', 23853 url: util.appendParamToURL(Urls.Stores.GetShopMyStorePanel + location.search, 'cgid', $('.currCGID').val()), 23854 dataType: 'html', 23855 success: function(data) { 23856 $('.shop-my-store').replaceWith(data); 23857 updateShopMyStore(); 23858 } 23859 }); 23860} 23861 23862function updateShopMyStore() { 23863 if ($('.shop-my-store-toggle input:checked').length > 0) { 23864 $('body').attr('is-shop-my-store-active', true); 23865 } else { 23866 $('body').attr('is-shop-my-store-active', false); 23867 } 23868} 23869 23870function initializeRangefinderEvents() { 23871 $(document).off('click.RefinementFilterTextReset').on('click.RefinementFilterTextReset', '.product-tile a', function(event) { 23872 event.preventDefault(); 23873 23874 var $this = $(this); 23875 var $product = $this.closest('[data-itemid]'); 23876 if ($product.length > 0) { 23877 $('body').loading(loadingIndicatorSettings); 23878 dialog.open({ 23879 url: util.appendParamToURL(Urls.productDetail, 'pid', $product.attr('data-itemid')), 23880 callback: function() { 23881 $('body').loading('destroy'); 23882 } 23883 }); 23884 } 23885 }); 23886} 23887 23888function initializeBootFinderEvents() { 23889 var $bootFinderResultsBanner = $('.bootfinder-resultsbanner'); 23890 if ($bootFinderResultsBanner && $bootFinderResultsBanner.length) { 23891 $bootFinderEmailForm = $bootFinderResultsBanner.find('form.email'); 23892 bootFinderEmailValidator = $bootFinderEmailForm.validate(ValidationSettings.Global); 23893 bootFinderEmailValidator.settings.onfocusout = ValidationSettings.Global.onfocusout; 23894 bootFinderEmailValidator.settings.errorPlacement = ValidationSettings.Global.errorPlacement; 23895 $bootFinderEmailForm.find('input[name="email"]').rules('add', $.extend(ValidationRules.Email, { 23896 required: true, 23897 messages: { 23898 required: $.validator.format('Please enter an email address.') 23899 } 23900 })); 23901 $bootFinderEmailForm.find('input[name="useragreement"]').rules('add', { 23902 required: true, 23903 messages: { 23904 required: $.validator.format('Please agree to the terms and conditions.') 23905 } 23906 }); 23907 23908 $(document).off('click.BootFinderResultsEmail').on('click.BootFinderResultsEmail', '.bootfinder-resultsbanner .btn.send-results-email', function(event) { 23909 event.preventDefault(); 23910 23911 if ($bootFinderEmailForm && $bootFinderEmailForm.valid()) { 23912 var $this = $(this); 23913 var $container = $this.closest('form'); 23914 $container.loading($.extend(loadingIndicatorSettings, { 23915 IsLabelShown: true, 23916 Content: 'Sending Email...' 23917 })); 23918 var urlParameters = util.getQueryStringParams(window.location.href); 23919 var bootFinderSendResultsEmailUrl = Urls.BootFinder.SendResultsEmail; 23920 bootFinderSendResultsEmailUrl = util.appendParamToURL(bootFinderSendResultsEmailUrl, 'cgid', $('.currCGID').val()); 23921 for (var urlParameter in urlParameters) { 23922 if (urlParameters[urlParameter]) { 23923 bootFinderSendResultsEmailUrl = util.appendParamToURL(bootFinderSendResultsEmailUrl, urlParameter, urlParameters[urlParameter]); 23924 } 23925 } 23926 var payload = { 23927 email: $container.find('input[type="email"]').val(), 23928 url: util.removeParamFromURL(window.location.href, 'bootfinderviewresults') 23929 } 23930 $.ajax({ 23931 type: 'post', 23932 url: bootFinderSendResultsEmailUrl, 23933 data: payload, 23934 success: function(data) { 23935 $container.loading('destroy'); 23936 if (data && data.success) { 23937 $container.find('.validation-error-container').html('<span class="error">Email sent!</span>'); 23938 } else { 23939 $container.find('.validation-error-container').html('<span class="error">An error occurred sending the email. Please try again.</span>'); 23940 } 23941 } 23942 }); 23943 } 23944 }); 23945 } 23946} 23947 23948function initializeEndlessScroll() { 23949 var productTileCount = $('#search-result-items').find('.grid-tile').length; 23950 var productTotalCount = parseInt($('.search-result-options.bottom .count').text().replace(/\D/g, ''), 10); 23951 var $endlessScrollWaypointCheck = $('.endless-scroll-waypoint'); 23952 if (productTileCount < productTotalCount && $endlessScrollWaypointCheck && $endlessScrollWaypointCheck.length > 0) { 23953 $(document).off('scroll.EndlessScroll').on('scroll.EndlessScroll', function(event) { 23954 var windowHeight = $(window).height(); 23955 var documentScrollTop = $(document).scrollTop(); 23956 var windowBottom = documentScrollTop + windowHeight; 23957 var $endlessScrollWaypoint = $('.endless-scroll-waypoint'); 23958 var endlessScrollWaypointPosition = $endlessScrollWaypoint.offset().top; 23959 23960 if (windowBottom > endlessScrollWaypointPosition) { 23961 if (!$endlessScrollWaypoint.attr('loading')) { 23962 $endlessScrollWaypoint.loading();
23963 loadMore(function() { 23964 $endlessScrollWaypoint.loading('destroy'); 23965 }); 23966 } 23967 } 23968 }); 23969 dataBuffer['EndlessScrollInitialized'] = true; 23970 } 23971} 23972 23973function getDecodedNumber(stringNumber) { 23974 var decodedNumber = decodeURIComponent(stringNumber); 23975 var cleanedNumber = parseInt(decodedNumber.replace(/,/g, '')); 23976 return cleanedNumber; 23977} 23978 23979function priceSlider() { 23980 if (!SitePreferences.PRICE_SLIDER_ENABLED) { 23981 return; 23982 } else { 23983 $(document).ready(function() { 23984 var maxProductPrice = 1200; // Set default value of slider max to $1200. This gets overwritten later in code depending on returned results. 23985 var urlQueryString = util.getQueryString(window.location.href); 23986 var urlParams = util.getQueryStringParams(urlQueryString); // Get url parameters in object format 23987 var hasCategory = ['cgid'] in urlParams; 23988 var hasQuery = ['q'] in urlParams; 23989 var hiddenFieldCategoryId = $('.currCGID').val(); 23990 var sliderMinValue = 0; 23991 var sliderMaxValue = maxProductPrice; 23992 var psmi = urlParams.psmi; 23993 var convertedPrices; 23994 23995 if (urlParams.pmin) { 23996 urlParams.pmin = getDecodedNumber(urlParams.pmin); // Remove commas from price minimum and transform string into integer 23997 if (urlParams.pmin < 0) { 23998 urlParams.pmin = 0; 23999 } 24000 } 24001 if (urlParams.pmax) { 24002 urlParams.pmax = getDecodedNumber(urlParams.pmax); // Remove commas from price maximum and transform string into integer 24003 if (urlParams.pmax < urlParams.pmin) { 24004 urlParams.pmax = urlParams.pmin; 24005 } 24006 // Needed because server-side will only return products less than priceMax, not equal to. Add 1 to get products equal to. 24007 if (!psmi || psmi != 'true') { 24008 urlParams.pmax = urlParams.pmax + 1; 24009 } 24010 } 24011 if (!hasQuery && !hasCategory && hiddenFieldCategoryId) { 24012 // If url params don't have a cgid or a query, try grabbing cgid from hidden field on page to use for productSearchModel 24013 urlParams.cgid = hiddenFieldCategoryId; 24014 } 24015 24016 // Use server-side script to get highest priced product, and to get GLOBALE prices if applicable 24017 var modifiedUrl = util.appendParamsToUrl(Urls.Search.GetPriceSliderPrices, urlParams); 24018 $.ajax({ 24019 type: 'POST', 24020 url: modifiedUrl, 24021 contentType: 'application/json', 24022 data: JSON.stringify({ 24023 sliderMin: sliderMinValue, 24024 sliderMax: sliderMaxValue, 24025 priceSliderSortingRule: 'price-high-to-low' 24026 }), 24027 success: function(response) { 24028 if (!response || response.status == 'ERROR') { 24029 // Error handling 24030 } else { 24031 try { 24032 maxProductPrice = response.convertedSliderPmax.convertedValue; 24033 convertedPrices = response; 24034 } catch(e) { 24035 24036 } 24037 } 24038 initializePriceSlider(maxProductPrice, convertedPrices, psmi); 24039 } 24040 }); 24041 }); 24042 } 24043} 24044 24045function initializePriceSlider(maxProductPrice, convertedPrices, psmi) { 24046 var $priceSlider = $('#price-slider'); 24047 var $priceSliderContainer = $priceSlider.closest('.price-slider-parent'); 24048 var isMobile = $('html').hasClass('size-mobile'); 24049 var sliderBottomValue = 0; 24050 var sliderTopValue = maxProductPrice ? (Math.ceil(maxProductPrice / 5) * 5) : 1200; 24051 var userPmin = 0; 24052 var userPmax = sliderTopValue; 24053 var convertedSymbol, convertedSliderMin, convertedSliderMax, convertedUserMin, convertedUserMax, convertedSliderRange, convertedPriceRange; 24054 24055 // Null checks 24056 if (!convertedPrices) { 24057 convertedSymbol = '$'; 24058 convertedSliderMin = sliderBottomValue; 24059 convertedSliderMax = sliderTopValue; 24060 convertedUserMin = userPmin; 24061 convertedUserMax = userPmax; 24062 } else { 24063 convertedSymbol = convertedPrices.convertedSliderPmax.convertedSymbol; 24064 convertedSliderMin = convertedPrices.convertedSliderPmin.convertedValue; 24065 convertedSliderMax = convertedPrices.convertedSliderPmax.convertedValue; 24066 convertedUserMin = convertedPrices.convertedUserPmin.convertedValue; 24067 convertedUserMax = convertedPrices.convertedUserPmax.convertedValue; 24068 } 24069 24070 // If slider instance is already initialized, go ahead and destroy before creating a new initialization 24071 if ($priceSlider.slider('instance')) { 24072 $('#price-slider').slider('destroy'); 24073 } 24074 24075 // Checks rounded pricing against converted pricing 24076 if (sliderTopValue != convertedSliderMax) { 24077 // Do this check before the rounded up value is applied to convertedSliderMax 24078 if (convertedUserMax == convertedSliderMax) { 24079 convertedUserMax = sliderTopValue; 24080 } 24081 // Now update convertedSliderMax to rounded value 24082 convertedSliderMax = sliderTopValue; 24083 } 24084 // If we have a pmin or pmax applied, then ensure that the price refinment bucket is expanded 24085 if ((convertedUserMin != convertedSliderMin) || (convertedUserMax != convertedSliderMax)) { 24086 if (!isMobile && !$('.price-refinement').hasClass('expanded')) { 24087 $('.price-refinement').addClass('expanded'); 24088 } 24089 // If we somehow have a greater userPmax than highestPricedProduct in category, go ahead and revert userPmax to highestPricedProduct value 24090 if (convertedUserMax > convertedSliderMax) { 24091 convertedUserMax = convertedSliderMax; 24092 } 24093 } 24094 // Update the DOM attributes with conversion factor to use when price slider is modified 24095 var conversionFactor = 1; 24096 if (convertedPrices) { 24097 conversionFactor = convertedPrices.convertedSliderPmax.defaultValue / convertedPrices.convertedSliderPmax.convertedValue; 24098 } 24099 $priceSliderContainer.attr('data-currency-conversion-factor', conversionFactor.toString()); 24100 24101 24102 // Initialize price slider 24103 $('#price-slider').slider({ 24104 range: true, 24105 min: convertedSliderMin, 24106 max: convertedSliderMax, 24107 values: [ convertedUserMin, convertedUserMax ], 24108 slide: function(event, ui) { 24109 // On slide event, grab user input for pmin/pmax and apply to slider text, plus input fields 24110 convertedUserMin = ui.values[0]; 24111 convertedUserMax = ui.values[1]; 24112 convertedPriceRange = convertedSymbol + convertedUserMin + ' - ' + convertedSymbol + convertedUserMax; 24113 convertedSliderRange = convertedSymbol + convertedSliderMin + ' - ' + convertedSymbol + convertedSliderMax; 24114 $('.price-range-amount').text(convertedPriceRange).attr('data-currency-symbol', convertedSymbol); 24115 $('#price-slider > .ui-slider-range').attr('title', 'Applied Price Range: ' + convertedPriceRange); 24116 $('#price-slider').attr('title', 'Max Range: ' + convertedSliderRange); 24117 $('[data-name="price-input-min"] .price-input-currency-symbol').html(convertedSymbol); 24118 $('[data-name="price-input-max"] .price-input-currency-symbol').html(convertedSymbol); 24119 $('#price-input-min').val(convertedUserMin); 24120 $('#price-input-max').val(convertedUserMax); 24121 }, 24122 stop: function(event, ui) { 24123 setTimeout(() => { 24124 convertedUserMin = ui.values[0]; 24125 convertedUserMax = ui.values[1]; 24126 if (!isMobile) { // Desktop 24127 triggerPriceSlider(convertedUserMin, convertedUserMax); 24128 } else { //Mobile 24129 priceSliderInputs(convertedUserMin, convertedUserMax, isMobile); 24130 } 24131 }, 750); // 0.75 seconds 24132 } 24133 }); 24134 24135 // For slider initialization, grab slider min and max and apply values to slider text and inputs, so everything matches at time of first load 24136 convertedUserMin = $('#price-slider').slider('values', 0); 24137 convertedUserMax = $('#price-slider').slider('values', 1); 24138 convertedPriceRange = convertedSymbol + convertedUserMin + ' - ' + convertedSymbol + convertedUserMax; 24139 convertedSliderRange = convertedSymbol + convertedSliderMin + ' - ' + convertedSymbol + convertedSliderMax; 24140 $('.price-range-amount').text(convertedPriceRange).attr('data-currency-symbol', convertedSymbol); 24141 $('#price-slider > .ui-slider-range').attr('title', 'Applied Price Range: ' + convertedPriceRange); 24142 $('#price-slider').attr('title', 'Max Range: ' + convertedSliderRange); 24143 $('[data-name="price-input-min"] .price-input-currency-symbol').html(convertedSymbol); 24144 $('[data-name="price-input-max"] .price-input-currency-symbol').html(convertedSymbol); 24145 $('#price-input-min').val(convertedUserMin); 24146 $('#price-input-max').val(convertedUserMax); 24147 24148 // Price inputs 24149 $(document).off('keypress', '.price-input-container input').on('keypress', '.price-input-container input', function(e) { 24150 $('.price-inputs-apply-button button').css('display','block'); 24151 }).off('click', '.price-inputs-apply-button button').on('click', '.price-inputs-apply-button button', function(e) { 24152 priceSliderInputs(convertedSliderMin, convertedSliderMax, isMobile); 24153 }) 24154} 24155 24156function priceSliderGoogleAnalyticsTagging() { 24157 if (SitePreferences.GA_NEW_ACTIONS_ENABLED) { 24158 var refinementId = $('#price-slider').closest('[refinement-id]').attr('refinement-id') || null; 24159 var refinementValue = $('#price-slider').closest('.price-slider-parent').find('.price-range-header .price-range-amount').text() || null; 24160 if (refinementId && refinementValue) { 24161 var refinementAnalyticsTaggingData = { 24162 'action_name': 'filter', 24163 'action_page_type': 'plp', 24164 'action_value': refinementId, 24165 'action_items': refinementValue 24166 }; 24167 GoogleTagManagerClient.PushDataLayerForDataLayerType('Event', refinementAnalyticsTaggingData); 24168 } 24169 } 24170} 24171 24172function initMobilePriceSlider(url) { 24173 var isPriceSlider = SitePreferences.PRICE_SLIDER_ENABLED && $('#price-slider').slider('instance'); 24174 var isMobile = $('html').hasClass('size-mobile'); 24175 var $applyRefinementsBtn = $('.apply-refinements:not(.disabled)'); 24176 var isButtonClick = $applyRefinementsBtn.length > 0 && $applyRefinementsBtn[0].hasAttribute('data-apply-refinements') && $applyRefinementsBtn.attr('data-apply-refinements') == 'true'; 24177 24178 if (isPriceSlider && isMobile && isButtonClick) { 24179 var isPriceSliderChanged = ($('#price-slider').slider('option', 'min') != $('#price-slider').slider('values', 0) || $('#price-slider').slider('option', 'max') != $('#price-slider').slider('values', 1)) || false; 24180 if (isPriceSliderChanged) { 24181 var userPriceMin = $('#price-slider').slider('values', 0); 24182 var userPriceMax = $('#price-slider').slider('values', 1); 24183 $applyRefinementsBtn.attr('data-apply-refinements','false'); 24184 return triggerPriceSlider(userPriceMin, userPriceMax, url); 24185 } else { 24186 return url; 24187 } 24188 } else { 24189 return url; 24190 } 24191} 24192
24193function priceSliderInputs(sliderBottomValue, sliderTopValue, isMobile) { 24194 // Input fields 24195 var inputPmin = $('#price-input-min').val() ? parseInt($('#price-input-min').val()) : sliderBottomValue; 24196 var inputPmax = $('#price-input-max').val() ? parseInt($('#price-input-max').val()) : sliderTopValue; 24197 if (inputPmin < 0) { 24198 inputPmin = 0; 24199 $('.price-input-min').val(inputPmin); 24200 } 24201 if (inputPmax > sliderTopValue) { 24202 inputPmax = sliderTopValue; 24203 $('#price-input-max').val(inputPmax); 24204 } 24205 // Update the price slider values based on the input fields 24206 var $priceSlider = $('#price-slider').slider('instance'); 24207 if ($priceSlider) { 24208 $('#price-slider').slider({ 24209 values: [ inputPmin, inputPmax ] 24210 }); 24211 } 24212 // Update the price slider text range with correct currency symbol 24213 var convertedSymbol = $('.price-range-amount').attr('data-currency-symbol'); 24214 var convertedPriceRange = convertedSymbol + inputPmin + ' - ' + convertedSymbol + inputPmax; 24215 $('.price-range-amount').text(convertedPriceRange); 24216 24217 if (!isMobile || pageContext.site == SiteConstants.SiteIds.BootBarnRspUS) { 24218 // Desktop 24219 triggerPriceSlider(inputPmin, inputPmax); 24220 } else { 24221 // Mobile 24222 if ($priceSlider) { 24223 var isPriceSliderChanged = ($('#price-slider').slider('option', 'min') != $('#price-slider').slider('values', 0) || $('#price-slider').slider('option', 'max') != $('#price-slider').slider('values', 1)) || false; 24224 if (isPriceSliderChanged) { 24225 $('.refinements').addClass('refinements-modified'); 24226 $('.refinements-inner-container-footer .apply-refinements').removeClass('disabled'); 24227 } else { 24228 $('.refinements').removeClass('refinements-modified'); 24229 $('.refinements-inner-container-footer .apply-refinements').addClass('disabled'); 24230 } 24231 } 24232 } 24233} 24234 24235function toggleRefinements() { 24236 if (!$('.refinements-inner-container').hasClass('open')) { 24237 $('.refinements-inner-container').find('.toggle.expanded, .toggle.selected, .refinement.expanded').removeClass('expanded selected'); 24238 $('.refinements').removeClass('refinement-expanded'); 24239 $('.refinement-body').hide(); 24240 } 24241 24242 toggleBodyScrollLock(); 24243 $('.refinements-inner-container').toggleClass('open'); 24244 redrawUpdatedRefinementHandling(); 24245} 24246 24247// Expects numbers as parameters, not strings 24248function triggerPriceSlider(priceMin, priceMax, passedUrl) { 24249 try { 24250 var url = passedUrl; 24251 if (!passedUrl || pageContext.site == SiteConstants.SiteIds.BootBarnRspUS) { 24252 $('body').loading(loadingIndicatorSettings); 24253 url = window.location.href; 24254 } 24255 24256 // Take user local currency and revert it back to U.S. (merchant site currency) before running the search query 24257 var currencyConversionFactor = parseFloat($('#price-slider').closest('.price-slider-parent').attr('data-currency-conversion-factor')); 24258 var revertedPmin = priceMin * currencyConversionFactor; 24259 var revertedPmax = priceMax * currencyConversionFactor; 24260 revertedPmax = revertedPmax + 1; // Needed because server-side will only return products less than priceMax, not equal to. Add 1 to get products equal to. 24261 24262 url = util.removeParamFromURL(url, 'pmin'); 24263 url = util.removeParamFromURL(url, 'pmax'); 24264 url = util.removeParamFromURL(url, 'psmi'); 24265 url = util.appendParamToURL(url, 'pmin', revertedPmin.toFixed()); 24266 url = util.appendParamToURL(url, 'pmax', revertedPmax.toFixed()); 24267 url = util.appendParamToURL(url, 'psmi', 'true'); 24268 24269 priceSliderGoogleAnalyticsTagging(); 24270 24271 if (!passedUrl || pageContext.site == SiteConstants.SiteIds.BootBarnRspUS) { 24272 updateProductListing(url); 24273 } else { 24274 return url; 24275 } 24276 } catch (e) { 24277 $('body').loading('destroy'); 24278 } 24279} 24280 24281exports.init = function (optionsParameter) { 24282 options = optionsParameter || {}; 24283 24284 ImageConstants = pageContext.site === SiteConstants.SiteIds.CountryOutfittersUS ? require('../../../../app_storefront_countryoutfitters/cartridge/js/ImageConstants') : require('../../../../bc_sheplersbootbarn_core/cartridge/js/ImageConstants'); 24285 24286 compareWidget.init(); 24287 if ('variantInventoryMessagingUrl' in page && page.variantInventoryMessagingUrl) { 24288 var urlParams = util.getQueryStringParams(window.location.search.substr(1));
24289 if(urlParams.hasOwnProperty('start') && urlParams.start > 0){ 24290 updateInventoryMessages(window.location.href, showVariantInventoryMessaging); 24291 } else { 24292 showVariantInventoryMessaging(); 24293 } 24294 } 24295 24296 productTile.init(); 24297 sizeRefinements.init(); 24298 initializeEvents(); 24299 updateShopMyStore(); 24300 sliders.initializeCategorySliders('.main-content .category-landing-slider:not(.slick-initialized)'); 24301 initializeRefinementFilterByText(); 24302 if (pageContext.site == SiteConstants.SiteIds.BootBarnUS) { 24303 initializeBootFinderEvents(); 24304 } 24305 loadScrollPosition(); 24306 saveScrollPosition(); 24307 if (pageContext.site == SiteConstants.SiteIds.CountryOutfittersUS) { 24308 initializeStickyRefinements(); 24309 // initializeStickySubheader(); 24310 } 24311 24312 loadingIndicatorSettings = { 24313 IsLabelShown: false, 24314 CssClass: 'fullscreen', 24315 BackgroundColor: 'transparent' 24316 }; 24317 24318 if (pageContext.site == SiteConstants.SiteIds.Rangefinder) { 24319 initializeRangefinderEvents(); 24320 } 24321 24322 if (options) { 24323 if (options.StyleCountCache) { 24324 styleCounts.render(options.StyleCountCache); 24325 } 24326 24327 if (options.RefinementsUIVersion == RefinementUIVersionConstants.Updated) { 24328 updateRefinementCounts(); 24329 if (options.StoreUIVersion == '2024Redesign') { 24330 updateSelectedRefinements(); 24331 updatePendingRefinements(); 24332 } 24333 24334 var $productSelectionContainer; 24335 if (pageContext.site === SiteConstants.SiteIds.SheplersUS) { 24336 $productSelectionContainer = $('.primary-content > .sort-and-refine > .product-selections'); 24337 } else { 24338 $productSelectionContainer = $('.primary-content > .product-selections') 24339 } 24340 24341 if ($productSelectionContainer.find('.list-selections .value.applied').length > 0) { 24342 $productSelectionContainer.show(); 24343 } else { 24344 $productSelectionContainer.hide(); 24345 } 24346 } 24347 24348 if (options.Pagination && options.Pagination.Mode == 'EndlessScroll') { 24349 initializeEndlessScroll(); 24350 } 24351 } 24352}; 24353 24354},{"../../../../app_storefront_countryoutfitters/cartridge/js/ImageConstants":106,"../../../../bc_sheplersbootbarn_core/cartridge/js/ImageConstants":116,"../../../../bc_sheplersbootbarn_core/cartridge/js/RefinementConstants":118,"../../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../../bc_sheplersbootbarn_core/cartridge/js/ValidationConstants":122,"../../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"../compare-widget":15,"../components/LoadingIndicator":25,"../dialog":36,"../page":46,"../product-tile":84,"../size-refinements":93,"../sliders":95,"../style-counts":99,"../util":102,"../wishlist":105}],81:[function(require,module,exports){ 24355'use strict'; 24356 24357var LocationSearch = require('../../../../app_storefront_core/cartridge/js/bopis/components/LocationSearch'); 24358 24359exports.init = function (options) { 24360 var loadingIndicatorSettings = { 24361 IsLabelShown: false, 24362 CssClass: 'fullscreen', 24363 BackgroundColor: 'transparent' 24364 }; 24365 24366 if ($('.pt_storefront .search-stores').length > 0) { 24367 var locationSearch = new LocationSearch(); 24368 $(document).off('click.Storefront.StoreSearch').on('click.Storefront.StoreSearch', '.pt_storefront .search-stores:not(.disabled)', function(event) { 24369 event.preventDefault(); 24370 24371 locationSearch.initialize($('.location-search-dialog'), options); 24372 $('.location-search-dialog').trigger('LocationSearch.FormSubmit'); 24373 }); 24374 } 24375 24376 $('.pt_storefront .section .btn:not(.search-stores):not(.reopen-rep-selections)').off('click.LoadingIndicator').on('click.LoadingIndicator', function() { 24377 $('body').loading(loadingIndicatorSettings); 24378 }); 24379}; 24380},{"../../../../app_storefront_core/cartridge/js/bopis/components/LocationSearch":10}],82:[function(require,module,exports){ 24381'use strict'; 24382 24383var _ = require('lodash'); 24384var loadingIndicator = require('../components/LoadingIndicator'); 24385var GeolocationHelper = require('../../../../bc_sheplersbootbarn_core/cartridge/js/Geolocation/GeolocationHelper'); 24386var shopYourStoreDialog = require('../bopis/components/ShopYourStoreDialog'); 24387var TemplateConstants = require('../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants'); 24388var tooltip = require('../tooltip'); 24389var util = require('../util'); 24390 24391var options; 24392var dataBuffer; 24393var inputSearchTimer; 24394 24395var $container; 24396var $content; 24397var $useMyLocationButton; 24398var $searchButton; 24399var $locationSearchResults; 24400var locationSearchResultContainerTemplate; 24401var locationSearchResultItemTemplate; 24402 24403function initializeEvents() { 24404 $(document).off('click.ShopYourStoreDialog').on('click.ShopYourStoreDialog', '.shop-store-inventory', function(event) { 24405 event.preventDefault(); 24406 24407 var $this = $(this); 24408 var $store = $this.closest('[store-id]'); 24409 shopYourStoreDialog.initialize({ 24410 StoreId: $store.attr('store-id'), 24411 StoreName: $store.attr('store-name') 24412 }); 24413 $this.attr('aria-expanded', 'true'); 24414 // Last button triggered 24415 $this.attr('lastTrigger', 'true'); 24416 }); 24417 24418 $(document).on('dialogclose', '#shop-your-store-dialog-container', function() { 24419 var $lastButton = $('.shop-store-inventory[lastTrigger="true"]'); 24420 if ($lastButton) { 24421 // Focus on last button triggered 24422 $lastButton.attr('aria-expanded', 'false').removeAttr('lastTrigger').focus(); 24423 } 24424 }); 24425 24426 $('.pt_store-locator').off('click.UseMyLocation').on('click.UseMyLocation', '.use-my-location', function (event) { 24427 event.preventDefault(); 24428 24429 dataBuffer.limit = window.outerWidth >= 1024 ? 10 : 5; 24430 dataBuffer.offset = 0; 24431 dataBuffer.query = ''; 24432 $('.store-filter-container [type="text"]').val(''); 24433 24434 $useMyLocationButton.loading(); 24435 $locationSearchResults.html(''); 24436 $locationSearchResults.loading(); 24437 GeolocationHelper.GetPosition().then(function(position) { 24438 dataBuffer.position = position; 24439 getStoreList(); 24440 }).catch(function() { 24441 if ($locationSearchResults.attr('loading')) { 24442 $locationSearchResults.loading('destroy'); 24443 } 24444 }); 24445 }); 24446 24447 $('.pt_store-locator').off('submit.Search').on('submit.Search', '.store-filter-container form', function (event) { 24448 event.preventDefault(); 24449 search(); 24450 }); 24451 24452 $('.pt_store-locator').off('click.Search').on('click.Search', '.store-filter-container .btn.btn-primary', function (event) { 24453 event.preventDefault(); 24454 search(); 24455 }); 24456 24457 $('.pt_store-locator').off('click.LoadMore').on('click.LoadMore', '.location-search-results .load-more', function (event) { 24458 event.preventDefault(); 24459 24460 var $this = $(this); 24461 dataBuffer.limit = window.outerWidth >= 1024 ? 10 : 5; 24462 dataBuffer.offset += dataBuffer.limit; 24463 $this.parent().loading(); 24464 GeolocationHelper.GetPosition().then(function(position) { 24465 dataBuffer.position = position; 24466 getStoreList(); 24467 }).catch(function() { 24468 if ($locationSearchResults.attr('loading')) { 24469 $locationSearchResults.loading('destroy'); 24470 } 24471 }); 24472 }); 24473
24474 // Append "shop my store" url parameters to store ads 24475 setTimeout(function() { 24476 if ($('.store-locator-detail-form').length > 0) { 24477 var storeID = $('[store-id]').attr('store-id'); 24478 if (storeID) { 24479 $('.store-page-bopis-container .content-tiles-slider header').hide(); 24480 $('.store-page-bopis-container .content-tiles-slider .swiper-wrapper .swiper-slide, .store-brands.store-page-section .brands-slider .swiper-wrapper .swiper-slide').each(function() { 24481 var $slide = $(this); 24482 var slideUrl = $slide.find('a').attr('href'); 24483 if (slideUrl) { 24484 var newUrl = util.appendParamsToUrl(slideUrl, { 24485 'prefn1': 'availableStores', 24486 'prefv1': storeID, 24487 'shopmystore': 'true' 24488 }); 24489 $slide.find('a').attr('href', newUrl); 24490 } 24491 }); 24492 } 24493 } 24494 }, 1000); // start after 1sec 24495} 24496 24497function search() { 24498 dataBuffer.limit = window.outerWidth >= 1024 ? 10 : 5; 24499 dataBuffer.offset = 0; 24500 dataBuffer.query = $('.store-filter-container [type="text"]').val(); 24501 24502 $searchButton.loading(); 24503 $locationSearchResults.html(''); 24504 $locationSearchResults.loading(); 24505 GeolocationHelper.GetPosition().then(function(position) { 24506 dataBuffer.position = position; 24507 getStoreList(); 24508 }).catch(function() { 24509 if ($locationSearchResults.attr('loading')) { 24510 $locationSearchResults.loading('destroy'); 24511 } 24512 }); 24513} 24514 24515function getStoreList() { 24516 var geolocationPosition; 24517 if (dataBuffer.position && dataBuffer.position.coords) { 24518 geolocationPosition = { 24519 coords: { 24520 accuracy: dataBuffer.position.coords.accuracy, 24521 latitude: dataBuffer.position.coords.latitude, 24522 longitude: dataBuffer.position.coords.longitude 24523 }, 24524 timestamp: dataBuffer.position.timestamp 24525 }; 24526 } 24527 24528 var payload = { 24529 Source: 'StoreLocatorPage', 24530 GeolocationPosition: geolocationPosition 24531 }; 24532 if (dataBuffer.query != undefined) { 24533 payload.Query = dataBuffer.query; 24534 } 24535 if (dataBuffer.limit != undefined) { 24536 payload.Limit = dataBuffer.limit; 24537 } 24538 if (dataBuffer.offset != undefined) { 24539 payload.Offset = dataBuffer.offset; 24540 } 24541 24542 $.ajax({ 24543 method: 'POST', 24544 url: Urls.Bopis.GetStoresForGeolocationPosition, 24545 contentType: 'application/json', 24546 data: JSON.stringify(payload), 24547 dataType: 'json', 24548 success: function(data) { 24549 renderStoreList(data); 24550 }, 24551 error: function() { 24552 24553 } 24554 }); 24555} 24556
24557function renderStoreList(data) { 24558 var locationData; 24559 if (data && data.ServiceSuccessfullyCalled && data.InquiryResult && data.InquiryResult.data && data.InquiryResult.data.length > 0) { 24560 locationData = data.InquiryResult.data; 24561 } 24562 24563 $container.attr('state', 'result'); 24564 if (locationData && locationData.length > 0) { 24565 locationData = locationData.sort(function(left, right) { 24566 return left.distance - right.distance; 24567 }); 24568 24569 dataBuffer['StoresDisplayed'] = []; 24570 $container.attr('result-count', locationData.length); 24571 24572 var storeListHtml = ''; 24573 $locationSearchResults.find('.no-results').remove(); 24574 for (var locationElement in locationData) { 24575 var location = locationData[locationElement]; 24576 24577 if (location && !dataBuffer['StoresDisplayed'][location.code] && location.StoreInfo.StateCodeParsed && location.StoreInfo.PostalCode) { 24578 var storePhone = ''; 24579 var storeOpenUntil = ''; 24580 if (location.StoreInfo) { 24581 if (location.StoreInfo.Phone) { 24582 storePhone = location.StoreInfo.Phone; 24583 } 24584 if (location.StoreInfo.OpenUntil) { 24585 storeOpenUntil = location.StoreInfo.OpenUntil; 24586 } 24587 } 24588 24589 var storeInventoryLink = ''; 24590 if (location.StoreInfo.StoreInventoryLink) { 24591 storeInventoryLink = '<button class="shop-store-inventory" aria-controls="shop-your-store-dialog-container" aria-haspopup="dialog" aria-expanded="false">' + Resources.Stores.ShopStoreInventory + '</button>'; 24592 } 24593 24594 var directionsLink = ''; 24595 if (location.StoreInfo.DirectionsUrl) { 24596 directionsLink = '<a class="directions" href="' + location.StoreInfo.DirectionsUrl + '" target="_blank">Directions</a>'; 24597 } 24598 24599 storeListHtml += locationSearchResultItemTemplate({ 24600 StoreId: location.code, 24601 StoreName: location.StoreInfo.Name, 24602 Distance: location.StoreInfo.Distance.toFixed(1) + ' mi', 24603 Html: '<a href="' + Urls.storeDetails + '?StoreID=' + location.code + '">' + location.StoreInfo.Name + '</a><br/>' + 24604 location.StoreInfo.Address1 + '<br/>' + 24605 location.StoreInfo.City + ', ' + location.StoreInfo.StateCodeParsed + ' ' + location.StoreInfo.PostalCode.substr(0, 5) + '<br/>' + 24606 storePhone + '<br/>' + 24607 storeOpenUntil, 24608 DirectionsLink: directionsLink, 24609 StoreInventoryLink: storeInventoryLink 24610 }); 24611 } 24612 24613 dataBuffer['StoresDisplayed'][location.code] = true; 24614 } 24615 if (data.InquiryResult.meta && data.InquiryResult.meta.page < data.InquiryResult.meta.pages) { 24616 storeListHtml += '<li class="load-more-container"><a class="load-more">Load More</a></li>'; 24617 } 24618 24619 var resultHtml = locationSearchResultContainerTemplate({ 24620 Html: storeListHtml 24621 }); 24622 $locationSearchResults.find('.load-more-container').remove(); 24623 $locationSearchResults.append(resultHtml); 24624 } else { 24625 $container.attr('result-count', '0'); 24626 $locationSearchResults.html('<li class="no-results">No stores found! Please try a different search.</li>'); 24627 } 24628 24629 if ($useMyLocationButton.attr('loading')) { 24630 $useMyLocationButton.loading('destroy'); 24631 } 24632 if ($searchButton.attr('loading')) { 24633 $searchButton.loading('destroy'); 24634 } 24635 if ($locationSearchResults.attr('loading')) { 24636 $locationSearchResults.loading('destroy'); 24637 } 24638} 24639 24640exports.init = function (optionsParameter) { 24641 options = optionsParameter || {}; 24642 dataBuffer = { 24643 offset: 0 24644 }; 24645 24646 $container = $('#stores_main'); 24647 $content = $container.find('.content'); 24648 $useMyLocationButton = $('.store-filter-container .use-my-location'); 24649 $searchButton = $('.store-filter-container .btn.btn-primary'); 24650 $locationSearchResults = $('.location-search-results'); 24651 locationSearchResultContainerTemplate = _.template($('#template-bopis-result-container').html(), TemplateConstants.Lodash.Settings); 24652 locationSearchResultItemTemplate = _.template($('#template-bopis-result-item-store-locator').html(), TemplateConstants.Lodash.Settings); 24653 24654 initializeEvents(); 24655 tooltip.init({ items: '.tooltip' }); 24656}; 24657},{"../../../../bc_sheplersbootbarn_core/cartridge/js/Geolocation/GeolocationHelper":115,"../../../../bc_sheplersbootbarn_core/cartridge/js/TemplateConstants":121,"../bopis/components/ShopYourStoreDialog":12,"../components/LoadingIndicator":25,"../tooltip":101,"../util":102,"lodash":133}],83:[function(require,module,exports){ 24658'use strict'; 24659 24660module.exports = { 24661 24662 elementPrefix: 'shipping-restrictions-popup', 24663 element: null, 24664 defaultTitle: '', 24665 defaultContent: '', 24666 24667 init: function (options) { 24668 if (!$( '.' + this.elementPrefix ).length) { 24669 $('body').append('<div class="' + this.elementPrefix + '"><div class="' + this.elementPrefix + '__popup"><h2 class="' + this.elementPrefix + '__h2"></h2><a class="' + this.elementPrefix + '__close" href="#">×</a><div class="' + this.elementPrefix + '__content"></div></div></div>'); 24670 this.element = $( '.' + this.elementPrefix ); 24671 var el = this; 24672 this.element.find('.' + this.elementPrefix + '__close').on('click', function (e) { 24673 el.hidePopup(e); 24674 }); 24675 } 24676 this.element.find('.' + this.elementPrefix + '__h2').html(options.title || this.defaultTitle); 24677 this.element.find('.' + this.elementPrefix + '__content').html(options.content || this.defaultContent); 24678 return this; 24679 }, 24680 24681 showPopup: function () { 24682 this.element.addClass(this.elementPrefix + '__visible'); 24683 return this; 24684 }, 24685 24686 hidePopup: function (e) { 24687 e.preventDefault(); 24688 this.element.removeClass(this.elementPrefix + '__visible'); 24689 }, 24690}; 24691 24692},{}],84:[function(require,module,exports){ 24693'use strict'; 24694 24695var imagesLoaded = require('imagesloaded'); 24696var util = require('./util'); 24697 24698exports.syncHeightOfTiles = syncHeightOfTiles; 24699 24700var windowWidth; 24701 24702function gridViewToggle() { 24703 $('.toggle-grid').on('click', function () { 24704 $('.search-result-content').toggleClass('wide-tiles'); 24705 $(this).toggleClass('wide'); 24706 }); 24707} 24708 24709/** 24710 * @private 24711 * @function 24712 * @description line clamping for product tile product titles. 24713 */ 24714 24715 function clampProductTileTitles() { 24716 $('h6.product-name .name-link').each(function(index, clampTitle) { 24717 $clamp(clampTitle, { 24718 clamp: 2, 24719 useNativeCLamp: false 24720 }); 24721 }); 24722 } 24723 24724 function initializeSwatches() { 24725 $('.grid-tile').each(function(index, element) { 24726 $(element).find('.yes-alts ul.swatch-list li').each(function(i, elem) { 24727 var altDisplay = 'show-content'; 24728 if ( i >= 4 ){ 24729 altDisplay = 'hidden-content'; 24730 } 24731 $(elem).addClass(altDisplay); 24732 }); 24733 var altHiddenCount = $(element).find('.hidden-content').length; 24734 var altHiddenToggle = '+ ' + altHiddenCount; 24735 var altButtonExists = $(element).find('.altButton').length; 24736 if (altHiddenCount > 0){ 24737 $(element).find('.hidden-content').hide(); 24738 if (altButtonExists == 0){ 24739 $(element).find('.yes-alts ul.swatch-list').append('<button class="altButton">' + altHiddenToggle + '</button>'); 24740 } else { 24741 $(element).find('.altButton').text(altHiddenToggle); 24742 } 24743 } 24744 }); 24745 } 24746 24747/** 24748 * @private 24749 * @function 24750 * @description Initializes events on the product-tile for the following elements: 24751 * - swatches 24752 * - thumbnails 24753 */ 24754function initializeEvents() { 24755 gridViewToggle(); 24756 initializeSwatches(); 24757 24758 $(document).ready(function() { 24759 $('#search-result-items .grid-tile').each(function() { 24760 var $gridItem = $(this), 24761 $primaryColor = $gridItem.data('primary-color'), 24762 $thumb = $gridItem.find('.product-image .thumb-link img').eq(0), 24763 $thumblink = $gridItem.find('.product-image a.thumb-link').eq(0), 24764 $namelink = $gridItem.find('.product-content .product-name a.name-link').eq(0); 24765 $gridItem.find('.product-content .product-swatches .swatch-list li').each(function() { 24766 var $currswatch = $(this), 24767 $currhref = $currswatch.find('a.swatch').attr('href'), 24768 $currcolor = $currswatch.data('color'); 24769 if ($primaryColor == $currcolor) { 24770 var $data = $currswatch.find('.swatch-image').data('thumb'); 24771 24772 if ($thumblink.attr('selected-locations')) { 24773 $currhref = util.appendParamToURL($currhref, 'selectedLocations', $thumblink.attr('selected-locations')); 24774 } 24775 24776 $namelink.attr('href', $currhref); 24777 $thumblink.attr('href', $currhref); 24778 24779 if ($data) { 24780 $thumb.attr({ 24781 src: $data.src, 24782 alt: $data.alt, 24783 title: $data.title 24784 }); 24785 } 24786 } 24787 }) 24788 }); 24789 24790 $(window).off('load.ProductTile resize.ProductTile').on('load.ProductTile resize.ProductTile', function () { 24791 if (windowWidth != $(window).width()) { 24792 syncHeightOfTiles(); 24793 } 24794 }); 24795 24796 imagesLoaded($('#search-result-items .grid-tile')).on('done', function () { 24797 syncHeightOfTiles(); 24798 }); 24799 }); 24800 24801 $('.swatch-list .swatch').on('click', function (event) { 24802 event.preventDefault(); 24803 24804 // get current thumb details 24805 var $tile = $(this).closest('.product-tile'), 24806 $thumb = $tile.find('.product-image .thumb-link img').eq(0), 24807 data = $(this).children('.swatch-image').filter(':first').data('thumb'), 24808 current = $thumb.data('current'); 24809 24810 // If this is the first time, then record the current img 24811 if (!current) { 24812 $thumb.data('current', { 24813 src: $thumb[0].src, 24814 alt: $thumb[0].alt, 24815 title: $thumb[0].title 24816 }); 24817 } 24818 24819 // Set the tile image to the values provided on the swatch data attributes 24820 if (data) { 24821 $thumb.attr({ 24822 src: data.src, 24823 alt: data.alt, 24824 title: data.title 24825 }); 24826 } 24827 }); 24828 24829 clampProductTileTitles(); 24830} 24831 24832function syncHeightOfTiles() { 24833 var $tiles = $('.tiles-container .product-tile'); 24834 if ($tiles.length === 0) { return; } 24835 24836 $tiles.find('.product-image .thumb-link').syncHeightToAverage(); 24837 $tiles.each(function (idx) { 24838 $(this).data('idx', idx); 24839 }); 24840} 24841 24842exports.init = function () { 24843 windowWidth = $(window).width(); 24844 24845 initializeEvents(); 24846}; 24847 24848},{"./util":102,"imagesloaded":132}],85:[function(require,module,exports){ 24849'use strict'; 24850 24851module.exports = { 24852 24853 init: function (options) { 24854 if ($('.rotate-3d__img').length) { 24855 $('.rotate-3d__container').prepend('<a href="#" class="rotate-3d__rotate rotate-3d__rotateLeft"> </a><a href="#" class="rotate-3d__rotate rotate-3d__rotateRight"> </a>'); 24856 $('.rotate-3d__rotateLeft').on('click', function (e) { 24857 e.preventDefault(); 24858 $('.rotate-3d__img').trigger("stepLeft"); 24859 }); 24860 $('.rotate-3d__rotateRight').on('click', function (e) { 24861 e.preventDefault(); 24862 $('.rotate-3d__img').trigger("stepRight"); 24863 }); 24864 } 24865 return this; 24866 }, 24867 24868}; 24869 24870},{}],86:[function(require,module,exports){ 24871'use strict'; 24872 24873var $loader; 24874 24875/** 24876 * @function 24877 * @description Shows an AJAX-loader on top of a given container 24878 * @param {Element} container The Element on top of which the AJAX-Loader will be shown 24879 */ 24880var show = function (container, displayInLine) { 24881 var target = (!container || $(container).length === 0) ? $('body') : $(container); 24882 $loader = $loader || $('.loader'); 24883 24884 if ($loader.length === 0) {
24885 $loader = $('<div/>').addClass('loader') 24886 .append($('<div/>').addClass('loader-indicator'), $('<div/>').addClass('loader-bg')); 24887 } 24888 24889 if (displayInLine) { 24890 $loader.css('display', 'inline-block'); 24891 } else { 24892 $loader.css('display', 'block'); 24893 } 24894 return $loader.appendTo(target); 24895}; 24896/** 24897 * @function 24898 * @description Hides an AJAX-loader 24899 */ 24900var hide = function () { 24901 if ($loader) { 24902 $loader.hide(); 24903 } 24904}; 24905 24906exports.show = show; 24907exports.hide = hide; 24908 24909},{}],87:[function(require,module,exports){ 24910'use strict'; 24911 24912var page = require('./page'); 24913var DataLayerConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/DataLayerConstants'); 24914var GoogleTagManagerClient = require('../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 24915var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 24916 24917var isCheckout, isEchoCart, fnUpdateCart, fnRenderCart, $focusedElement; 24918var loadingIndicatorSettings = { 24919 IsLabelShown: false, 24920 CssClass: 'fullscreen', 24921 BackgroundColor: 'transparent' 24922}; 24923 24924function updateStepperQtyUI($this, increment) { 24925 var $quantityStepper = increment != undefined ? $this.parent('.quantity-stepper') : $this; 24926 var $input = $quantityStepper.find('input.input-text'); 24927 var quantity = parseInt($input.val()); 24928 // Only increment or decrement quantity if a boolean was passed into the function 24929 if (increment != undefined) { 24930 increment ? quantity++ : quantity--; 24931 } 24932 24933 // Enable or Disable the plus/minus signs on the quantity stepper 24934 var $incButton = $quantityStepper.find('button.increase.plus'); 24935 var $decButton = $quantityStepper.find('button.decrease.minus'); 24936 24937 if (quantity <= 1) { 24938 $decButton.addClass('disabled').attr('disabled', 'disabled'); 24939 $incButton.removeClass('disabled').removeAttr('disabled'); 24940 } else if (quantity > 1) { 24941 $decButton.removeClass('disabled').removeAttr('disabled'); 24942 $incButton.removeClass('disabled').removeAttr('disabled'); 24943 } 24944 24945 // Update the value of the quantity stepper 24946 $input.attr('quantity-buffer', quantity); 24947 $input.val(quantity); 24948} 24949 24950function updateMiniCartUI(increment, $lineItem) { 24951 var $miniCartElm = $('.mini-cart .minicart-quantity').length > 0 ? $('.mini-cart .minicart-quantity') : $('.mini-cart .btn-minicart .btn-minicart-qty'); 24952 var miniCartTotal; 24953 if ($miniCartElm.length > 0) { 24954 miniCartTotal = parseInt($miniCartElm.html().trim()); 24955 } 24956 24957 if ((increment != null && typeof increment === "boolean") && !$lineItem) { 24958 increment ? miniCartTotal++ : miniCartTotal--; 24959 } else if ((increment == null || typeof increment != "boolean") && $lineItem) { 24960 var itemQty = parseInt($lineItem.find('.opc-qty').val()); 24961 miniCartTotal = itemQty && typeof itemQty == 'number' && itemQty > 0 ? miniCartTotal - itemQty : miniCartTotal; 24962 $lineItem.remove(); 24963 } 24964 24965 // Update the basket quantity on the main navigation bar > minicart icon 24966 miniCartTotal >= 1 ? $miniCartElm.html(miniCartTotal) : $miniCartElm.html(0); 24967 24968 // Update the minicart modal, if it's currently open 24969 if ($('.add-to-cart-modal').length > 0) { 24970 var productRecommendationsHtml = $('.add-to-cart-modal .main-content .product-recommendations-container').html(); 24971 $.ajax({url : Urls.addToCartModalDisplay, dataType: 'html', success : function(modalContent) { 24972 if (modalContent.length > 0) { 24973 $('.add-to-cart-modal .ui-dialog-content').html(modalContent); 24974 $('.add-to-cart-modal-content .main-content .product-recommendations-container').append(productRecommendationsHtml); 24975 // Reference addToCart.js > addItemToCart() > line 314 (Move title from main content to top of the modal) 24976 if ($('.add-to-cart-modal-content').length > 0) { 24977 var $addMessage = $('.add-to-cart-modal-content .main-content .added-message'); 24978 // Reference addToCart.js > addItemToCart() > line 377 (Inserts the word 'Item' into the minicart title) 24979 $('.add-to-cart-modal-content .added-message .count').text('Item'); 24980 if ($addMessage.length > 0) { 24981 $('.add-to-cart-modal-content').prepend($addMessage); 24982 } 24983 } 24984 } 24985 }}); 24986 } 24987} 24988 24989function updateCartTotals() { 24990 if (isCheckout && fnUpdateCart) { 24991 fnUpdateCart($('.update-cart-button').attr('name')); 24992 } 24993 if (isEchoCart && fnRenderCart) { 24994 fnRenderCart(); 24995 } 24996} 24997 24998function removeFromCartDataLayer($this) { 24999 try { 25000 var $item = $this.closest('[data-uuid]'); 25001 if ($item) { 25002 var productID = $item.attr('data-productid'); 25003 var $element, uaObject, ga4Object, productDataForUniversalAnalytics, productDataForGoogleAnalytics4; 25004 $('.add-to-cart-analytics-container').each(function(idx, elm) { 25005 $element = $(elm); 25006 if ($element) { 25007 uaObject = JSON.parse($element.attr('data-product-gtm-json')); 25008 ga4Object = JSON.parse($element.attr('data-product-ga4-json')); 25009
25010 if (uaObject && uaObject.skuid && uaObject.skuid == productID) { 25011 productDataForUniversalAnalytics = uaObject; 25012 productDataForGoogleAnalytics4 = ga4Object; 25013 } 25014 } 25015 }); 25016 25017 if (productDataForUniversalAnalytics && productDataForGoogleAnalytics4) { 25018 var dataObject = { 25019 UniversalAnalytics: { 25020 ecommerce: { 25021 remove: { 25022 products: [productDataForUniversalAnalytics] 25023 } 25024 } 25025 }, 25026 GoogleAnalytics4: { 25027 value: productDataForGoogleAnalytics4.price, 25028 items: [productDataForGoogleAnalytics4] 25029 } 25030 } 25031 25032 GoogleTagManagerClient.PushDataLayerForDataLayerType('RemoveFromCart', dataObject); 25033 } 25034 } 25035 } catch(e) { 25036 } 25037} 25038 25039function quantityDatalayerEvents($this, eventType, quantity) { 25040 try { 25041 var $item = $this.closest('[data-uuid]'); 25042 if ($item) { 25043 var eventName; 25044 var ecommerceKey; 25045 if (eventType == DataLayerConstants.EventTypes.Minus) { 25046 eventName = DataLayerConstants.Events.Cart.RemoveFromCart.Name; 25047 ecommerceKey = 'remove'; 25048 } else { 25049 eventName = DataLayerConstants.Events.Cart.AddToCart.Name; 25050 ecommerceKey = 'add'; 25051 } 25052 var productID = $item.attr('data-productid'); 25053 var $element, uaObject, ga4Object, productDataForUniversalAnalytics, productDataForGoogleAnalytics4; 25054 $('.add-to-cart-analytics-container').each(function(idx, elm) { 25055 $element = $(elm); 25056 if ($element) { 25057 uaObject = JSON.parse($element.attr('data-product-gtm-json')); 25058 ga4Object = JSON.parse($element.attr('data-product-ga4-json')); 25059 25060 if (uaObject && uaObject.skuid && uaObject.skuid == productID) { 25061 productDataForUniversalAnalytics = uaObject; 25062 productDataForGoogleAnalytics4 = ga4Object; 25063 } 25064 } 25065 }); 25066 25067 if (productDataForUniversalAnalytics && productDataForGoogleAnalytics4) { 25068 if (quantity) { 25069 productDataForUniversalAnalytics.quantity = quantity; 25070 productDataForGoogleAnalytics4.quantity = quantity; 25071 } 25072 25073 var dataObject = { 25074 UniversalAnalytics: { 25075 ecommerce: {} 25076 }, 25077 GoogleAnalytics4: { 25078 value: productDataForGoogleAnalytics4.price, 25079 items: [productDataForGoogleAnalytics4] 25080 } 25081 } 25082 25083 dataObject.UniversalAnalytics.ecommerce[ecommerceKey] = { 25084 products: [productDataForUniversalAnalytics] 25085 } 25086 25087 GoogleTagManagerClient.PushDataLayerForDataLayerType(eventName, dataObject); 25088 } 25089 } 25090 } catch(e) { 25091 } 25092} 25093 25094function quantityChangeEvents($this, quantity, increment) { 25095 var eventType = increment ? DataLayerConstants.EventTypes.Plus : DataLayerConstants.EventTypes.Minus; 25096 quantityDatalayerEvents($this, eventType, quantity); 25097} 25098 25099function spinnerClear() { 25100 var spinnerTimer; 25101 var timerIncrement = isCheckout || isEchoCart ? 5000 : 2000; 25102 25103 clearTimeout(spinnerTimer); 25104 spinnerTimer = setTimeout(function() { 25105 if ($('body').attr('loading')) { 25106 $('body').loading('destroy'); 25107 } 25108 }, timerIncrement); 25109} 25110 25111function initialize(updateCart, renderCart) { 25112 isCheckout = (pageContext && pageContext.type == 'cart' || pageContext.type == 'onepcheckout_groups') || (page.ns && page.ns == 'cart' || page.ns == 'onepcheckout_groups'); 25113 isEchoCart = (pageContext && 'type' in pageContext && pageContext.type == 'cart_echo') || (page.ns && page.ns == 'cart_echo'); 25114 fnUpdateCart = updateCart && typeof updateCart === 'function' ? updateCart : null; 25115 fnRenderCart = renderCart && typeof renderCart === 'function' ? renderCart : null; 25116 25117 // Remove Button 25118 $(document).off('click.QuantityStepper.ProductRemove').on('click.QuantityStepper.ProductRemove', '.quantity-stepper-remove .remove', function (event) { 25119 event.preventDefault(); 25120 25121 var $this = $(this); 25122 var $itemRow = $this.closest('[data-uuid]'); 25123 var isMiniCart = $itemRow.attr('class').indexOf('mini-cart') > -1; 25124 25125 $('body').loading(loadingIndicatorSettings); 25126 $.ajax({ 25127 type: 'POST', 25128 url: Urls.Cart.RemoveProduct, 25129 contentType: 'application/json', 25130 data: JSON.stringify({ 25131 ProductLineItemUUID: $itemRow.data('uuid'), 25132 }), 25133 dataType: 'json', 25134 complete: function(xhr) { 25135 try { 25136 updateCartTotals(); 25137 removeFromCartDataLayer($this); 25138 if (isMiniCart) { 25139 updateMiniCartUI(null, $itemRow); 25140 } 25141 spinnerClear(); 25142 } catch(e) { 25143 console.log(e); 25144 $('body').loading('destroy'); 25145 } 25146 } 25147 }); 25148 }); 25149 25150 // Plus/Minus Qty Buttons 25151 $(document).off('click.QuantityStepper.QuantityChange').on('click.QuantityStepper.QuantityChange', '.quantity-stepper button:not(".disabled")', function (event) { 25152 event.preventDefault(); 25153 25154 var $stepperButton = $(this); 25155 var isIncrement = $stepperButton.hasClass('increase'); 25156 var cartQtyUrl = isIncrement ? Urls.Cart.AddProductQuantity : Urls.Cart.RemoveProductQuantity; 25157 25158 $focusedElement = $stepperButton; 25159 $('body').loading(loadingIndicatorSettings); 25160 $.ajax({ 25161 type: 'POST', 25162 url: cartQtyUrl, 25163 contentType: 'application/json', 25164 data: JSON.stringify({ 25165 ProductLineItemUUID: $(this).closest('[data-uuid]').data('uuid'), 25166 Quantity: 1 25167 }), 25168 dataType: 'json', 25169 complete: function(xhr) { 25170 try { 25171 updateStepperQtyUI($stepperButton, isIncrement); 25172 updateMiniCartUI(isIncrement); 25173 updateCartTotals(); 25174 quantityChangeEvents($stepperButton, 1, isIncrement); 25175 spinnerClear(); 25176 } catch(e) { 25177 console.log(e); 25178 $('body').loading('destroy'); 25179 } 25180 } 25181 }); 25182 }); 25183 25184 // Input event event is reliable and fires after any user action that modifies the input field, including: ke
25184yup, paste or change 25185 $(document).off('input.QuantityStepper.QuantityChange').on('input.QuantityStepper.QuantityChange', '.quantity-stepper input[name$=_quantity]', function (event) { 25186 var args = { 25187 element: $(this), 25188 value: $(this).val(), 25189 event: 'input' 25190 }; 25191 $(document).trigger('QuantityStepper.InputChange', args); 25192 }); 25193 25194 $(document).off('blur.QuantityStepper.InputBlur').on('blur.QuantityStepper.InputBlur', '.quantity-stepper input[name$=_quantity]', function (event) { 25195 var args = { 25196 element: $(this), 25197 value: $(this).val(), 25198 event: 'blur' 25199 }; 25200 $(document).trigger('QuantityStepper.InputChange', args); 25201 }); 25202 25203 // Custom-Named event for the keyboard or paste input for quantity field 25204 $(document).off('QuantityStepper.InputChange').on('QuantityStepper.InputChange', function (event, args) { 25205 var $this = $(args.element); 25206 var triggerEvent = args.event; 25207 var numericValue = parseInt(args.value); 25208 if (isNaN(numericValue) || numericValue <= 0 || numericValue === parseInt($this.attr('quantity-buffer'))) { 25209 if (triggerEvent === 'blur') { 25210 $this.val($this.attr('quantity-buffer')); 25211 } else { 25212 if (args.value != '') { 25213 $this.val($this.attr('quantity-buffer')); 25214 } 25215 } 25216 } else { 25217 var quantityDelta = numericValue - parseInt($this.attr('quantity-buffer')); 25218 var isIncrement = quantityDelta < 0 ? false : quantityDelta > 0 ? true : null; 25219 if (isIncrement != null) { 25220 var cartQtyUrl = isIncrement ? Urls.Cart.AddProductQuantity : Urls.Cart.RemoveProductQuantity; 25221 25222 $('body').loading(loadingIndicatorSettings); 25223 $.ajax({ 25224 type: 'POST', 25225 url: cartQtyUrl, 25226 contentType: 'application/json', 25227 data: JSON.stringify({ 25228 ProductLineItemUUID: $this.closest('[data-uuid]').data('uuid'), 25229 Quantity: Math.abs(quantityDelta) 25230 }), 25231 dataType: 'json', 25232 complete: function(xhr) { 25233 try { 25234 updateStepperQtyUI($this, isIncrement); 25235 updateMiniCartUI(isIncrement); 25236 updateCartTotals(); 25237 quantityChangeEvents($this, Math.abs(quantityDelta), isIncrement); 25238 $this.attr('quantity-buffer', numericValue); 25239 spinnerClear(); 25240 } catch(e) { 25241 console.log(e); 25242 $('body').loading('destroy'); 25243 } 25244 } 25245 }); 25246 } 25247 $focusedElement = $this; 25248 } 25249 }); 25250 25251 $(document).off('QuantityStepper.TargetFocus').on('QuantityStepper.TargetFocus', function () { 25252 if ($focusedElement) { 25253 $focusedElement.focus(); 25254 } 25255 }); 25256} 25257 25258exports.init = initialize; 25259},{"../../../bc_sheplersbootbarn_core/cartridge/js/DataLayerConstants":114,"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"./page":46}],88:[function(require,module,exports){ 25260'use strict'; 25261 25262var dialog = require('./dialog'), 25263 product = require('./pages/product'), 25264 util = require('./util'), 25265 _ = require('lodash'); 25266 25267 25268var makeUrl = function (url, source, productListID) { 25269 if (source) { 25270 url = util.appendParamToURL(url, 'source', source); 25271 } 25272 if (productListID) { 25273 url = util.appendParamToURL(url, 'productlistid', productListID); 25274 } 25275 return url; 25276}; 25277 25278var removeParam = function (url) { 25279 if (url.indexOf('?') !== -1) { 25280 return url.substring(0, url.indexOf('?')); 25281 } else { 25282 return url; 25283 } 25284}; 25285 25286var quickview = { 25287 init: function () { 25288 if (!this.exists()) {
25289 this.$container = $('<div/>').attr('id', 'QuickViewDialog').appendTo(document.body); 25290 } 25291 this.productLinks = $('#search-result-items .thumb-link').map(function (index, thumbLink) { 25292 return $(thumbLink).attr('href'); 25293 }); 25294 }, 25295 25296 setup: function (qvUrl) { 25297 25298 product.initializeEvents(); 25299 25300 }, 25301 25302 /** 25303 * @param {Number} step - How many products away from current product to navigate to. Negative number means navigate backward 25304 */ 25305 navigateQuickview: function (step) { 25306 // default step to 0 25307 this.productLinkIndex += (step ? step : 0); 25308 var url = makeUrl(this.productLinks[this.productLinkIndex], 'quickview'); 25309 dialog.replace({ 25310 url: url, 25311 callback: this.setup.bind(this, url) 25312 }); 25313 }, 25314 25315 /** 25316 * @description show quick view dialog 25317 * @param {Object} options 25318 * @param {String} options.url - url of the product details 25319 * @param {String} options.source - source of the dialog to be appended to URL 25320 * @param {String} options.productlistid - to be appended to URL 25321 * @param {Function} options.callback - callback once the dialog is opened 25322 */ 25323 show: function (options) { 25324 var url; 25325 if (!this.exists()) { 25326 this.init(); 25327 } 25328 url = makeUrl(options.url, options.source, options.productlistid); 25329 25330 dialog.open({ 25331 target: this.$container, 25332 url: url, 25333 options: { 25334 width: 1068, 25335 title: Resources.QUICK_VIEW_POPUP, 25336 open: function () { 25337 this.setup(url); 25338 if (typeof options.callback === 'function') { options.callback(); } 25339 }.bind(this) 25340 } 25341 }); 25342 }, 25343 exists: function () { 25344 return this.$container && (this.$container.length > 0); 25345 } 25346}; 25347 25348module.exports = quickview; 25349 25350},{"./dialog":36,"./pages/product":75,"./util":102,"lodash":133}],89:[function(require,module,exports){ 25351'use strict'; 25352 25353/** 25354 * copied from https://github.com/darkskyapp/string-hash 25355 */ 25356function hashFn(str) { 25357 var hash = 5381, 25358 i = str.length; 25359 25360 while (i) { 25361 hash = (hash * 33) ^ str.charCodeAt(--i); 25362 } 25363 /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed 25364 * integers. Since we want the results to be always positive, convert the 25365 * signed int to an unsigned by doing an unsigned bitshift. */ 25366 return hash >>> 0; 25367} 25368 25369/** 25370 * Create rating based on hash ranging from 2-5 25371 * @param pid 25372 */ 25373function getRating(pid) { 25374 return hashFn(pid.toString()) % 30 / 10 + 2; 25375} 25376 25377module.exports = { 25378 init: function () { 25379 $('.variant-info .product-review').each(function (index, review) { 25380 var pid = $(review).data('pid'); 25381 if (!pid) { 25382 return; 25383 } 25384 // rating range from 2 - 5 25385 var rating = getRating(pid); 25386 var baseRating = Math.floor(rating); 25387 var starsCount = 0; 25388 for (var i = 0; i < baseRating; i++) { 25389 $('.rating', review).append('<i class="fa fa-star"></i>'); 25390 starsCount++; 25391 } 25392 // give half star for anything in between 25393 if (rating > baseRating) { 25394 $('.rating', review).append('<i class="fa fa-star-half-o"></i>'); 25395 starsCount++; 25396 } 25397 if (starsCount < 5) { 25398 for (var j = 0; j < 5 - starsCount; j++) { 25399 $('.rating', review).append('<i class="fa fa-star-o"></i>'); 25400 } 25401 } 25402 }); 25403 } 25404}; 25405 25406},{}],90:[function(require,module,exports){ 25407'use strict'; 25408 25409/* ------------------------- 25410 * REGISTER 25411 * ------------------------- 25412 */ 25413 25414var alert = require('./alert'); 25415var dialog = require('./dialog'); 25416var loadingIndicator = require('./components/LoadingIndicator'); 25417var wishlist = require('./wishlist'); 25418 25419var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 25420 25421var options = {}; 25422var loadingIndicatorSettings = { 25423 IsLabelShown: false, 25424 CssClass: 'fullscreen',
25425 BackgroundColor: 'transparent' 25426}; 25427 25428function errorHandling(data, dialogTitle, dialogHtml) { 25429 if (data && typeof data === 'object' && 'message' in data) { 25430 console.log(data.message); 25431 } 25432 dialog.open({ 25433 html: dialogHtml, 25434 options: { 25435 title: dialogTitle, 25436 draggable: false, 25437 open: function(event, ui) { 25438 $('body').addClass('dialog-open'); 25439 }, 25440 close: function(event, ui) { 25441 $('body').removeClass('dialog-open'); 25442 } 25443 } 25444 }); 25445} 25446 25447function validateRegistrationForm($form) { 25448 var rewardsFormFields = { 25449 email: $form.find('#dwfrm_rewardsregistration_rewardscustomer_email'), 25450 firstName: $form.find('#dwfrm_rewardsregistration_rewardscustomer_firstname'), 25451 lastName: $form.find('#dwfrm_rewardsregistration_rewardscustomer_lastname'), 25452 phone: $form.find('#dwfrm_rewardsregistration_rewardscustomer_phone'), 25453 zip: $form.find('#dwfrm_rewardsregistration_rewardscustomeraddress_zipcode').length > 0 ? $form.find('#dwfrm_rewardsregistration_rewardscustomeraddress_zipcode') : $form.find('#dwfrm_rewardsregistration_rewardscustomer_zipcode'), 25454 birthMonth: $form.find('#dwfrm_rewardsregistration_rewardscustomer_birthday_month'), 25455 birthDay: $form.find('#dwfrm_rewardsregistration_rewardscustomer_birthday_day') 25456 } 25457 if ($form.find('input[name*="dwfrm_rewardsregistration_rewardscustomer_password"]').length > 0) { 25458 rewardsFormFields.password = $form.find('input[name*="dwfrm_rewardsregistration_rewardscustomer_password"]'); 25459 } 25460 var registrationFormFields = { 25461 email: $form.find('#dwfrm_profile_customer_email'), 25462 confirmEmail: $form.find('#dwfrm_profile_customer_emailconfirm'), 25463 firstName: $form.find('#dwfrm_profile_customer_firstname'), 25464 lastName: $form.find('#dwfrm_profile_customer_lastname') 25465 } 25466 if ($form.find('input[name*="dwfrm_profile_login_password_"]').length > 0) { 25467 registrationFormFields.password = $form.find('input[name*="dwfrm_profile_login_password_"]'); 25468 } 25469 if ($form.find('input[name*="dwfrm_profile_login_passwordconfirm"]').length > 0) { 25470 registrationFormFields.confirmPassword = $form.find('input[name*="dwfrm_profile_login_passwordconfirm"]'); 25471 } 25472 var checkFormFields = $form.attr('id') == 'dwfrm_rewardsregistration' ? rewardsFormFields : registrationFormFields; 25473 var formValidation = new Array(); 25474 var regexEmail = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/g; 25475 var regexPhone = /^\+?\(?([0-9][0-8][0-9])\)?[\-\. ]?([2-9][0-9]{2})[\-\. ]?([0-9]{4})(\s*x[0-9]+)?$/g; 25476 var regexZip = /^(\d{5})(-\d{4})?$/g; 25477 var regexPassword = /^(?=.*?[A-z])(?=.*?[0-9])(?=.*?[#?!\=\/\,\.\~\`\(\)\{\}\[\]\\@_$%^&*-]).{8,20}$/g; 25478 25479 for (var fieldName in checkFormFields) { 25480 var fieldValue = checkFormFields[fieldName].length ? checkFormFields[fieldName].val().trim() : null; 25481 25482 if (fieldValue != null && fieldValue.length > 0) { 25483 if (fieldName == 'email' || fieldName == 'confirmEmail') { 25484 if (String(fieldValue).match(regexEmail) == null) { 25485 formValidation.push(false); 25486 checkFormFields[fieldName].addClass('error'); 25487 var emailFormatErrorClass = fieldName == 'email' ? 'span.invalid-email-format' : 'span.invalid-email-confirm-format'; 25488 $('.registration-dialog-error[data-relation="'+fieldName+'"]').find(emailFormatErrorClass).removeClass('d-none'); 25489 } 25490 if (fieldName == 'confirmEmail' && (fieldValue != checkFormFields['email'].val().trim())) { 25491 formValidation.push(false); 25492 checkFormFields[fieldName].addClass('error'); 25493 $('.registration-dialog-error[data-relation="'+fieldName+'"]').find('span.invalid-email-confirm-mismatch').removeClass('d-none'); 25494 } 25495 } 25496 if (fieldName == 'phone') { 25497 if (String(fieldValue).match(regexPhone) == null) { 25498 formValidation.push(false); 25499 checkFormFields[fieldName].addClass('error'); 25500 $('.registration-dialog-error[data-relation="'+fieldName+'"]').find('span.invalid-phone-format').removeClass('d-none'); 25501 } 25502 } 25503 if (fieldName == 'zip') { 25504 if (String(fieldValue).match(regexZip) == null) { 25505 formValidation.push(false); 25506 checkFormFields[fieldName].addClass('error'); 25507 $('.registration-dialog-error[data-relation="'+fieldName+'"]').find('span.invalid-zip-format').removeClass('d-none'); 25508 } 25509 } 25510 if (fieldName == 'password' || fieldName == 'confirmPassword') { 25511 if (String(fieldValue).match(regexPassword) == null) { 25512 formValidation.push(false); 25513 checkFormFields[fieldName].addClass('error'); 25514 var passwordFormatErrorClass = fieldName == 'password' ? 'span.invalid-password-format' : 'span.invalid-password-confirm-format'; 25515 $('.registration-dialog-error[data-relation="'+fieldName+'"]').find(passwordFormatErrorClass).removeClass('d-none'); 25516 } 25517 if (fieldName == 'confirmPassword' && (fieldValue != checkFormFields['password'].val().trim())) { 25518 formValidation.push(false); 25519 checkFormFields[fieldName].addClass('error'); 25520 $('.registration-dialog-error[data-relation="'+fieldName+'"]').find('span.invalid-password-confirm-mismatch').removeClass('d-none'); 25521 } 25522 } 25523 } else { 25524 formValidation.push(false); 25525 checkFormFields[fieldName].addClass('error'); 25526 $('.registration-dialog-error[data-relation="'+fieldName+'"]').find('span.invalid-missing-fields').removeClass('d-none'); 25527 } 25528 } 25529 25530 if (formValidation.length > 0) { 25531 return false;
25532 } else { 25533 $form.find('.registration-dialog-error span').addClass('d-none'); 25534 return true; 25535 } 25536} 25537 25538// Cordial rewards registration tracking (BB) 25539function rewardsRegisterCordialEvent($form, isRegisterDialog, callback) { 25540 var birthMonth = $form.find('#dwfrm_rewardsregistration_rewardscustomer_birthday_month').val() ? $form.find('#dwfrm_rewardsregistration_rewardscustomer_birthday_month').val() : ''; 25541 var birthDay = $form.find('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').val() ? $form.find('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').val() : ''; 25542 var birthdate = ''; 25543 if (birthMonth != '') { 25544 birthdate = birthMonth + '/' + birthDay + '/' + '1976'; 25545 } 25546 var rewardsFormFields = { 25547 email: $form.find('#dwfrm_rewardsregistration_rewardscustomer_email').val().trim(), 25548 firstName: $form.find('#dwfrm_rewardsregistration_rewardscustomer_firstname').val().trim(), 25549 lastName: $form.find('#dwfrm_rewardsregistration_rewardscustomer_lastname').val().trim(), 25550 phone: $form.find('#dwfrm_rewardsregistration_rewardscustomer_phone').val().trim(), 25551 zip: $form.find('#dwfrm_rewardsregistration_rewardscustomeraddress_zipcode').length > 0 ? $form.find('#dwfrm_rewardsregistration_rewardscustomeraddress_zipcode').val().trim() : $form.find('#dwfrm_rewardsregistration_rewardscustomer_zipcode').val().trim() 25552 } 25553 var signupEvent = ""; 25554 25555 var auth_data = { 25556 email: rewardsFormFields['email'] 25557 } 25558 var contact_data = { 25559 'channels': { 25560 'email': { 25561 'address': rewardsFormFields['email'] 25562 } 25563 }, 25564 'first_name': rewardsFormFields['firstName'], 25565 'last_name': rewardsFormFields['lastName'], 25566 'phone': rewardsFormFields['phone'], 25567 'postal_code': rewardsFormFields['zip'], 25568 'birthday': birthdate, 25569 'source_create': 'myaccount', 25570 'geo_location': { 25571 'postal_code': rewardsFormFields['zip'] 25572 } 25573 }; 25574 var loginProperties = { 25575 "email": rewardsFormFields['email'], 25576 "loginType": isRegisterDialog ? "registration-dialog" : "regular-registration" 25577 }; 25578 var registerProperties = { 25579 "email": rewardsFormFields['email'], 25580 "registerType": isRegisterDialog ? "registration-dialog" : "regular-registration" 25581 }; 25582 if ($('input#dwfrm_rewardsregistration_receiveRewardsEmail').is(':checked')) { 25583 var contact_data = { 25584 'channels': { 25585 'email': { 25586 'address': rewardsFormFields['email'], 25587 'subscribeStatus': 'subscribed' 25588 } 25589 }, 25590 'first_name': rewardsFormFields['firstName'], 25591 'last_name': rewardsFormFields['lastName'], 25592 'phone': rewardsFormFields['phone'], 25593 'postal_code': rewardsFormFields['zip'], 25594 'birthday': birthdate, 25595 'signup_source': 'rewards', 25596 'source_create': 'myaccount', 25597 'welcome_signup_rewards_online': true, 25598 'geo_location': { 25599 'postal_code': rewardsFormFields['zip'] 25600 } 25601 }; 25602 var properties = { 25603 "signup_source": 'rewards', 25604 "welcome_signup_rewards_online": true 25605 }; 25606 signupEvent = ['event', 'email_signup', properties]; 25607 } 25608 25609 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 25610 crdl([ 25611 ['contact', auth_data, contact_data], 25612 ['event', 'account_create', registerProperties], 25613 ['event', 'login', loginProperties], 25614 signupEvent 25615 ]); 25616 } 25617 if (callback) callback(); 25618} 25619 25620// Cordial registration tracking (SHP and CO) 25621function registerCordialEvent($form, isRegisterDialog, callback) { 25622 var registrationFormFields = { 25623 email: $form.find('#dwfrm_profile_customer_email').val().trim(), 25624 firstName: $form.find('#dwfrm_profile_customer_firstname').val().trim(), 25625 lastName: $form.find('#dwfrm_profile_customer_lastname').val().trim() 25626 } 25627 var loginProperties = { 25628 "email": registrationFormFields['email'], 25629 "loginType": isRegisterDialog ? "registration-dialog" : "registration" 25630 }; 25631 var registerProperties = { 25632 "email": registrationFormFields['email'], 25633 "registerType": isRegisterDialog ? "registration-dialog" : "registration" 25634 }; 25635 var loginEvent = ['event', 'login', loginProperties]; 25636 var signupEvent = ""; 25637 var accountEvent = 'account_create'; 25638 if ($('.profile-header').text().includes('Edit')) { 25639 accountEvent = 'account_edit';
25640 loginEvent = ""; 25641 } 25642 25643 var auth_data = { 25644 email: registrationFormFields['email'] 25645 } 25646 var contact_data = { 25647 'channels': { 25648 'email': { 25649 'address': registrationFormFields['email'] 25650 } 25651 }, 25652 'first_name': registrationFormFields['firstName'], 25653 'last_name': registrationFormFields['lastName'], 25654 'source_create': 'myaccount' 25655 }; 25656 25657 if ($('input#dwfrm_profile_customer_addtoemaillist').is(':checked')) { 25658 var contact_data = { 25659 'channels': { 25660 'email': { 25661 'address': registrationFormFields['email'], 25662 'subscribeStatus': 'subscribed' 25663 } 25664 }, 25665 'first_name': registrationFormFields['firstName'], 25666 'last_name': registrationFormFields['lastName'], 25667 'signup_source': 'myaccount', 25668 'source_create': 'myaccount', 25669 'welcome_signup': true 25670 }; 25671 var properties = { 25672 "signup_source": "myaccount", 25673 "page": "myaccount", 25674 "welcome_signup": true 25675 }; 25676 signupEvent = ['event', 'email_signup', properties]; 25677 } 25678 25679 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 25680 crdl([ 25681 ['contact', auth_data, contact_data], 25682 ['event', accountEvent, registerProperties], 25683 loginEvent, 25684 signupEvent 25685 ]); 25686 } 25687 if (callback) callback(); 25688} 25689 25690/** 25691 * @private 25692 * @function 25693 * @description add rules to code input field 25694 */ 25695function initAddRulesForCodeInput() { 25696 $('form#verify-code').validate(); 25697 $('#verify-code #enter-code').rules('add', { 25698 required: true, 25699 digits: true, 25700 minlength: 6, 25701 messages: {
25702 required: Resources.VALIDATE_CODE, 25703 minlength: Resources.VALIDATE_CODE 25704 }, 25705 normalizer: function(value) { 25706 return $.trim(value); 25707 } 25708 }); 25709} 25710 25711/** 25712 * @private 25713 * @function 25714 * @description init registration button event for registration page and dialog 25715 */ 25716function initRegistrationButton() { 25717 $(document).off('click.Registration').on('click.Registration', '.accountRegisterButton, .saveRewardsRegistration.btn, .confirmationRegisterButton', function(event) { 25718 event.preventDefault(); 25719 event.stopImmediatePropagation(); 25720 var dialogHtml = '<p style="padding: 10px;">Oops, something went wrong with registration. Please try again later.</p>'; 25721 var $registrationButton = $(this); 25722 var $registrationForm = $registrationButton.closest('form[data-form-type="register"]'); 25723 var formUrl = $registrationForm.attr('action'); 25724 var isConfirmationPage = $registrationButton.hasClass('confirmationRegisterButton'); 25725 25726 // Clear previous form errors 25727 $registrationForm.find('input').removeClass('error'); 25728 $registrationForm.find('.registration-dialog-error span').addClass('d-none'); 25729 25730 var isValidForm = validateRegistrationForm($registrationForm); 25731 var isRegisterDialog = formUrl.indexOf('loginDialog') >= 0; 25732 var formData = $registrationForm.serialize(); 25733 formData += '&' + $registrationButton.attr('name') + '=' + $registrationButton.attr('value'); 25734 if (pageContext.options.Token) { 25735 formData += '&csrf_token=' + pageContext.options.Token; 25736 } 25737 25738 // Using AJAX instead of default HTML button submit for registration dialog and "Create an Account" page 25739 if (isValidForm) { 25740 $('body').loading(loadingIndicatorSettings); 25741 if (SitePreferences.RETENTION_COM_ENABLED) { 25742 geq.suppress(); 25743 } 25744 $.ajax({ 25745 type: 'POST', 25746 url: formUrl, 25747 data: formData, 25748 success: function(data, textStatus, jqXHR) { 25749 if (typeof data === 'object' && 'result' in data) { 25750 if (data.result == 'error') { 25751 $('body').loading('destroy'); 25752 if (isRegisterDialog || isConfirmationPage) { 25753 var errorsFound; 25754 if (data.validationErrors) { 25755 errorsFound = JSON.parse(data.validationErrors); 25756 } 25757 if (errorsFound && Object.keys(errorsFound).length > 0) { 25758 for (var fieldName in errorsFound) { 25759 $('[name*="' +fieldName+ '"]').addClass('error'); 25760 $(errorsFound[fieldName]).removeClass('d-none'); 25761 } 25762 } else { 25763 errorHandling(data, 'Register - Error', dialogHtml); 25764 } 25765 } else { 25766 window.location.href = data.registerDialogContinueUrl; 25767 } 25768 } else if (data.result == 'success') { 25769 $('body').loading('destroy'); 25770 // If a rewards account was found in rewards DB, then verify customer and tie newly registered email address to exisitng rewards account 25771 if ('validateCustomer' in data && data.validateCustomer) { 25772 if (SitePreferences.CORDIAL_ENABLED) { 25773 if ($registrationForm.attr('id') == 'dwfrm_rewardsregistration') { 25774 rewardsRegisterCordialEvent($registrationForm, isRegisterDialog); 25775 } else { 25776 registerCordialEvent($registrationForm, isRegisterDialog); 25777 } 25778 } 25779 var newAttributes = { 25780 "data-modal-type": "register", 25781 "data-continue-url": 'registerDialogContinueUrl' in data ? data.registerDialogContinueUrl : '', 25782 "data-first-name": 'customerFirstName' in data ? data.customerFirstName : '', 25783 "data-store-number": 'storeFromProfile' in data ? data.storeFromProfile : '', 25784 "data-cart-quantity": 'cartQuantity' in data ? data.cartQuantity : '' 25785 } 25786 $('.login-dialog-validate-customer').html(data.validateCustomer); 25787 $('.login-dialog-validate-customer').addClass('validate-customer-show follow-account-dialog-path').attr(newAttributes); 25788 // For register-dialog because the validation form is only loaded into page via AJAX, so rules can't be added until form is loaded 25789 initAddRulesForCodeInput(); 25790 } else { 25791 if (isConfirmationPage) { 25792 // Redirect to My Account if this is a registration from order
25792confirmation page 25793 data.registerDialogContinueUrl = Urls.account; 25794 } 25795 if (SitePreferences.CORDIAL_ENABLED) { 25796 if ($registrationForm.attr('id') == 'dwfrm_rewardsregistration') { 25797 rewardsRegisterCordialEvent($registrationForm, isRegisterDialog, function() { 25798 $(document).trigger('PostAjaxAuthenticationActions.Initialize', { results: data, isAccountDialog: isRegisterDialog, displayMessage: 'register' }); 25799 }); 25800 } else { 25801 registerCordialEvent($registrationForm, isRegisterDialog, function() { 25802 $(document).trigger('PostAjaxAuthenticationActions.Initialize', { results: data, isAccountDialog: isRegisterDialog, displayMessage: 'register' }); 25803 }); 25804 } 25805 } else { 25806 $(document).trigger('PostAjaxAuthenticationActions.Initialize', { results: data, isAccountDialog: isRegisterDialog, displayMessage: 'register' }); 25807 } 25808 } 25809 } else { 25810 $('body').loading('destroy'); 25811 errorHandling(data, 'Register - Error', dialogHtml); 25812 } 25813 } else { 25814 $('body').loading('destroy'); 25815 if (isRegisterDialog) { 25816 errorHandling(data, 'Register - Error', dialogHtml); 25817 } else { 25818 window.location.href = location.href; 25819 } 25820 } 25821 }, 25822 error: function(jqXHR, textStatus, errorThrown) { 25823 $('body').loading('destroy'); 25824 if (!isRegisterDialog) { 25825 window.location.href = location.href; 25826 } 25827 } 25828 }); 25829 } 25830 }); 25831} 25832 25833function initializeBirthdayInputs() { 25834 var $birthdayForm = $('#dwfrm_rewardsregistration'); 25835 if ($('#dwfrm_birthday').length >= 1 ){ 25836 var $birthdayForm = $('#dwfrm_birthday'); 25837 } 25838 25839 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').prop('disabled', true); 25840 var longMonths = ['1','3','5','7','8','10','12']; 25841 var febMonth = '2'; 25842 $birthdayForm.on('change', 'select#dwfrm_rewardsregistration_rewardscustomer_birthday_month', function(e) { 25843 $('.birthday.day').removeClass('disabled'); 25844 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').find('option:selected').prop('selected', false); 25845 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day .select-option').prop('disabled', false); 25846 var monthVal = $('#dwfrm_rewardsregistration_rewardscustomer_birthday_month').val(); 25847 if ($.inArray(monthVal, longMonths) === -1) { 25848 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day .select-option[value="31"]').prop('disabled', true); 25849 if (monthVal == febMonth){ 25850 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day .select-option[value="30"]').prop('disabled', true); 25851 } 25852 } 25853 $('#dwfrm_rewardsregistration_rewardscustomer_birthday_day').prop('disabled', false); 25854 }); 25855} 25856 25857/** 25858 * @private 25859 * @function 25860 * @description displays the registration form in the dialog on button click 25861 */ 25862function initRegistrationForm() { 25863 $('body').on('click', '#toggle-registration', function(e) { 25864 e.preventDefault(); 25865 var $dialog = $(this).parents('.login-dialog'); 25866 var $dialogTitlebar = $dialog.find('.ui-dialog-titlebar'); 25867 var $dialogContent = $dialog.find('.ui-dialog-content'); 25868 var $dialogFormsContainer = $dialog.find('.login-dialog-forms-container'); 25869 var calculatedSpacing = $(window).height() * 0.21; 25870 var newDialogHeight = $(window).height() - calculatedSpacing; 25871 var newTopValue = $(window).scrollTop() + (calculatedSpacing * 0.233); 25872 25873 if ($dialogTitlebar && $dialogTitlebar.is(":visible")) { 25874 newDialogHeight = newDialogHeight + $dialogTitlebar.outerHeight(); 25875 } 25876 25877 var paddingTop = '32px'; 25878 var currentSite = pageContext && pageContext.site ? pageContext.site : null; 25879 if ((currentSite && currentSite == SiteConstants.SiteIds.BootBarnUS) || (pageContext && pageContext.isstoresite)) { 25880 paddingTop = '28px'; 25881 } 25882 if (currentSite && currentSite == SiteConstants.SiteIds.BootBarnUS) { 25883 initializeBirthdayInputs(); 25884 } 25885 25886 $('.login-dialog-signin-container, #toggle-registration').hide(); 25887 $('.login-dialog-register-form').addClass('register-form-show'); 25888 $dialog.css({ 25889 'height': newDialogHeight+'px', 25890 'top': newTopValue+'px', 25891 'overflow': 'visible' 25892 }); 25893 $dialogContent.css({ 25894 'height': '100%', 25895 'padding': '0 11px 20px', 25896 'padding-top': paddingTop 25897 }); 25898 $dialogFormsContainer.css('height','100%'); 25899 }); 25900} 25901 25902/** 25903 * @private 25904 * @function 25905 * @description init update button event for edit account page 25906 */ 25907function initRegistrationEdit() { 25908 $('body').on('click', '.accountEditButton', function(e) { 25909 var $registrationButton = $(this); 25910 var $registrationForm = $registrationButton.closest('form[data-form-type="register"]'); 25911 var formUrl = $registrationForm.attr('action'); 25912 var isRegisterDialog = formUrl.indexOf('loginDialog') >= 0; 25913 25914 if (SitePreferences.CORDIAL_ENABLED) { 25915 registerCordialEvent($registrationForm, isRegisterDialog); 25916 } 25917 }); 25918} 25919 25920module.exports = { 25921 init: function (optionsParameter) { 25922 options = optionsParameter; 25923 25924 initRegistrationForm(); 25925 initRegistrationButton(); 25926 initRegistrationEdit(); 25927 } 25928}; 25929},{"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"./alert":4,"./components/LoadingIndicator":25,"./dialog":36,"./wishlist":105}],91:[function(require,module,exports){ 25930'use strict'; 25931 25932var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 25933var util = require('./util'); 25934 25935var siteName; 25936var $win = $(window); 25937var getSuggestionsHttpRequest; 25938var getSuggestionsTimer; 25939var getSuggestionsLastQuery; 25940 25941/** 25942 * @function
25943 * @description Configures parameters and required object instances 25944 */ 25945function init() { 25946 siteName = window.pageContext.site || ''; 25947 25948 $('.top-banner .header-search button[type="submit"]').on('click', function(event) { 25949 event.preventDefault(); 25950 25951 var $this = $(this); 25952 var $searchForm = $this.closest('form'); 25953 var $searchInput = $searchForm.find('[name="q"]'); 25954 var action = $searchForm.attr('action'); 25955 var keyword = $searchInput.val(); 25956 var url = action + "?q=" + keyword; 25957 25958 if (keyword && keyword != $searchInput.attr('placeholder')) { 25959 $searchForm.attr('action', url); 25960 $searchForm.submit(); 25961 } 25962 }); 25963 $('.header-search').on('click.SearchClear', 'button[type="reset"]', function(event) { 25964 event.preventDefault(); 25965 $('.header-search').attr('has-value', 'false'); 25966 $('.header-search input#q, .header-search input#mobile-q').val(''); 25967 $('.header-search input#q:visible, .header-search input#mobile-q:visible').focus(); 25968 }); 25969 $('.top-banner-bar .scan').on('click.SearchClear', 'button[type="reset"]', function(event) { 25970 event.preventDefault(); 25971 $('.top-banner-bar .scan').attr('has-value', 'false'); 25972 $('.top-banner-bar .scan .search-input').val('').focus(); 25973 }); 25974 $(document).on('focus click keyup', '.header-search input#q, .header-search input#mobile-q', function(event) { 25975 var $this = $(this); 25976 var keyword = $this.val(); 25977 $('.header-search').attr('has-value', !!(keyword && keyword.length > 1 && keyword != $this.attr('placeholder'))); 25978 if ((SitePreferences.SEARCH_SUGGESTIONS_ENABLED || (SitePreferences.CIMULATE_ENABLED && SitePreferences.CIMULATE_SEARCH_SUGGESTIONS_ENABLED)) && keyword && keyword.length > 1 && keyword != $this.attr('placeholder')) { 25979 if (getSuggestionsTimer) { 25980 clearTimeout(getSuggestionsTimer); 25981 } 25982 if (keyword == getSuggestionsLastQuery) { 25983 renderSuggestions().catch(promotedSuggestions); 25984 } else { 25985 getSuggestionsTimer = setTimeout(function() { 25986 getSuggestions($this.val()).then(renderSuggestions).catch(promotedSuggestions); 25987 }, 250); 25988 } 25989 } else if (SitePreferences.PROMOTED_SEARCHES) { 25990 promotedSuggestions(); 25991 } 25992 }); 25993 25994 25995 if (siteName == SiteConstants.SiteIds.BootBarnUS) { 25996 $('.header-search').on('click.SearchActive', function() { 25997 $('.header-search').addClass('active'); 25998 }); 25999 26000 $('.header-search input#q').on('focusout', function() { 26001 if (!$(this).val()) { 26002 $('.header-search').removeClass('active'); 26003 } 26004 }); 26005 } 26006 if (SitePreferences.PROMOTED_SEARCHES || SitePreferences.SEARCH_SUGGESTIONS_ENABLED || (SitePreferences.CIMULATE_ENABLED && SitePreferences.CIMULATE_SEARCH_SUGGESTIONS_ENABLED)) { 26007 $(document).on('mouseleave', '.search-suggestions-container, .header-search [name="q"]', function(e) { 26008 var searchHeader = document.querySelector('.header-search'); 26009 if (!searchHeader.contains(e.relatedTarget) && $('.search-suggestions-container').find(e.relatedTarget).length < 1) { 26010 $('.search-suggestions-container').hide(); 26011 } 26012 }); 26013 26014 $(document).on('click', '.close-search-suggestions', function() { 26015 $('.search-suggestions-container').hide(); 26016 }); 26017 26018 $(document).off('SearchBar.Expand').on('SearchBar.Expand', function() { 26019 expand(); 26020 }); 26021 26022 $(document).off('SearchBar.ScrollTop').on('SearchBar.ScrollTop', function() { 26023 scrollTop(); 26024 }); 26025 26026 $(document).off('SearchBar.Hide').on('SearchBar.Hide', function() { 26027 hide(); 26028 }); 26029 } 26030} 26031 26032/** 26033 * @function 26034 * @description 26035 */ 26036function expand() { 26037 $('.top-banner').toggleClass('search-enabled'); 26038 var $target = $('.header-search'); 26039 if (siteName == SiteConstants.SiteIds.CountryOutfittersUS) { 26040 $target = $('.search-holder'); 26041 } 26042 26043 if ((siteName == SiteConstants.SiteIds.SheplersUS || siteName == SiteConstants.SiteIds.CountryOutfittersUS) && $('html').hasClass('size-mobile')) { 26044 $target.css('top', $('.top-banner-bar').outerHeight() + $('.top-banner-inner').outerHeight() - $win.scrollTop()); 26045 } else { 26046 $target.css('top', ''); 26047 } 26048 26049 if (siteName == SiteConstants.SiteIds.SheplersUS) { 26050 $target.find('input[type="text"]').focus(); 26051 } 26052 26053 if ($('.top-banner').hasClass('search-enabled') && $('html').hasClass('size-mobile') && $('.top-banner-bar').attr('data-header-for') == 'bootbarn_us') { 26054 $('#search #q').focus(); 26055 } 26056} 26057 26058/** 26059 * @function 26060 * @description 26061 */ 26062function scrollTop() { 26063 if (siteName == SiteConstants.SiteIds.SheplersUS || siteName == SiteConstants.SiteIds.C
26063ountryOutfittersUS) { 26064 var $target = $('.header-search'); 26065 if (siteName == SiteConstants.SiteIds.CountryOutfittersUS) { 26066 $target = $('.search-holder'); 26067 } 26068 26069 if ($('html').hasClass('size-mobile')) { 26070 $target.css('top', $('.top-banner-bar').outerHeight() + $('.top-banner-inner').outerHeight() - $win.scrollTop()); 26071 } else { 26072 $target.css('top', ''); 26073 } 26074 } 26075} 26076 26077/** 26078 * @function 26079 * @description 26080 */ 26081function hide() { 26082 if($('.header-search').hasClass('show')) { 26083 $('.header-search').removeClass('show'); 26084 if (siteName != SiteConstants.SiteIds.BootBarnRspUS) { 26085 $('.top-banner').removeClass('search-enabled'); 26086 } 26087 } 26088} 26089 26090/** 26091 * @function 26092 * @description trigger promoted suggestions for site search 26093 */ 26094function promotedSuggestions() { 26095 if (getSuggestionsHttpRequest && getSuggestionsHttpRequest.readyState != 4) { 26096 getSuggestionsHttpRequest.abort(); 26097 } 26098 if (getSuggestionsTimer) { 26099 clearTimeout(getSuggestionsTimer); 26100 } 26101 26102 var $container = $('.search-suggestions-container'); 26103 var $suggestionsContentSlot = $container.find('.html-slot-container'); 26104 var isContentPopulated = $suggestionsContentSlot.length > 0; 26105 if (isContentPopulated) { 26106 if ($suggestionsContentSlot.is(':hidden')) { 26107 $suggestionsContentSlot.show(); 26108 } 26109 var $suggestions = $container.find('.search-suggestion-wrapper'); 26110 if ($suggestions.is(':visible')) { 26111 $suggestions.hide(); 26112 } 26113 if ($container.is(':hidden')) { 26114 $container.show(); 26115 } 26116 } else if ($container.is(':visible')) { 26117 $container.hide(); 26118 } 26119} 26120 26121function getSuggestions(query) { 26122 return new Promise(function(resolve, reject) { 26123 if (getSuggestionsHttpRequest && getSuggestionsHttpRequest.readyState != 4) { 26124 getSuggestionsHttpRequest.abort(); 26125 } 26126 26127 if (query) { 26128 getSuggestionsLastQuery = query; 26129 getSuggestionsHttpRequest = $.ajax({ 26130 url: util.appendParamToURL(Urls.searchsuggest, 'q', query), 26131 type: 'GET', 26132 success: function(html) { 26133 if (html) { 26134 resolve(html); 26135 } else { 26136 reject(); 26137 } 26138 }, 26139 error: function() { 26140 reject(); 26141 } 26142 }); 26143 } else { 26144 reject(); 26145 } 26146 }); 26147} 26148
26149function renderSuggestions(html) { 26150 return new Promise(function(resolve, reject) { 26151 var $suggestions; 26152 var $container = $('.search-suggestions-container'); 26153 if ($container.length > 0) { 26154 if (html) { 26155 $suggestions = $container.find('.search-suggestion-wrapper'); 26156 if ($suggestions.length > 0) { 26157 $suggestions[0].outerHTML = html; 26158 } else { 26159 $container.append(html); 26160 } 26161 } 26162 $suggestions = $container.find('.search-suggestion-wrapper'); 26163 if ($suggestions.length > 0) { 26164 var $suggestionsContentSlot = $container.find('.html-slot-container'); 26165 if ($suggestionsContentSlot.is(':visible')) { 26166 $suggestionsContentSlot.hide(); 26167 } 26168 if ($suggestions.is(':hidden')) { 26169 $suggestions.show(); 26170 } 26171 if ($container.is(':hidden')) { 26172 $container.show(); 26173 } 26174 26175 resolve(); 26176 } else { 26177 reject(); 26178 } 26179 } 26180 }); 26181} 26182 26183exports.init = init; 26184},{"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"./util":102}],92:[function(require,module,exports){ 26185'use strict'; 26186 26187/** 26188 * @private 26189 * @function 26190 * @description Binds event to the place holder (.blur) 26191 */ 26192function initializeEvents() { 26193 $('#q').focus(function () { 26194 var input = $(this); 26195 if (input.val() === input.attr('placeholder')) { 26196 input.val(''); 26197 } 26198 }) 26199 .blur(function () { 26200 var input = $(this); 26201 if (input.val() === '' || input.val() === input.attr('placeholder')) { 26202 input.val(input.attr('placeholder')); 26203 } 26204 }) 26205 .blur(); 26206} 26207 26208exports.init = initializeEvents; 26209 26210},{}],93:[function(require,module,exports){ 26211'use strict'; 26212 26213var page = require('./page'); 26214 26215var isTouchMoved = false; 26216var isCurrentTargetSwatch = false; 26217 26218function initializeEvents() { 26219 $(document).off('click.Swatch.Menu.Close').on('click.Swatch.Menu.Close', function (event) { 26220 var $currentTarget = $(event.currentTarget); 26221 26222 if ($currentTarget.closest('.slide-down-swatch').length == 0) { 26223 $('.slide-down-swatch ul').slideUp(); 26224 } 26225 }); 26226 26227 $(document).off('touchstart.Swatch.Menu.Close').on('touchstart.Swatch.Menu.Close', function (event) { 26228 var $currentTarget = $(event.currentTarget); 26229 26230 isTouchMoved = false; 26231 isCurrentTargetSwatch = $currentTarget.closest('.slide-down-swatch').length > 0; 26232 }); 26233 26234 $(document).off('touchmove.Swatch.Menu.Close').on('touchmove.Swatch.Menu.Close', function (event) { 26235 isTouchMoved = true; 26236 }); 26237 26238 $(document).off('touchend.Swatch.Menu.Close').on('touchend.Swatch.Menu.Close', function (event) { 26239 if (!isCurrentTargetSwatch && !isTouchMoved) { 26240 $('.slide-down-swatch ul').slideUp(); 26241 } 26242 }); 26243 26244 $('.swatches.size > li > a.slide-down').on('click', function(event) { 26245 event.preventDefault(); 26246 event.stopPropagation(); 26247 26248 $(this) 26249 .next('ul') 26250 .stop() 26251 .slideToggle() 26252 .parent()
26253 .siblings() 26254 .children('ul') 26255 .slideUp() 26256 .prev('.slide-down'); 26257 }); 26258 26259 // Default selected value as slide down 26260 $('.swatches.size > li > a.slide-down') 26261 .next('ul') 26262 .find('.current') 26263 .closest('ul') 26264 .prev('.slide-down') 26265 .addClass('current') 26266 .closest('li').addClass('active'); 26267 26268 $('.refinements .swatches.size > li.active > ul').slideDown(); 26269 26270 $('.swatches > li.slide-down-swatch > ul').off('click'); 26271 26272 // Remove empty tiles 26273 $('.swatches.size > li > a.slide-down').next('ul').each(function() { 26274 if ($(this).find('li').length === 0) { 26275 $(this).closest('li').remove(); 26276 } 26277 }); 26278} 26279 26280var sizeRefinements = { 26281 init: function() { 26282 initializeEvents(); 26283 } 26284}; 26285 26286module.exports = sizeRefinements; 26287},{"./page":46}],94:[function(require,module,exports){ 26288'use strict'; 26289 26290/* ------------------------- 26291 * ADA Slick Mods 26292 * ------------------------- 26293 */ 26294 26295exports.init = function init () { 26296 $(document).off('SlickSliderAccessibilityMods').on('SlickSliderAccessibilityMods', function(event) { 26297 $('.slick-slider .slick-slide, .slick-slider .slick-active').removeAttr('aria-describedby role tabindex'); 26298 $('.slick-slider .slick-dots button').each(function() { 26299 var buttonVal = $(this).html(); 26300 var addSpan = '<span class="visually-hidden">' + buttonVal + '</span>'; 26301 $(this).html(addSpan); 26302 }); 26303 }); 26304}; 26305},{}],95:[function(require,module,exports){ 26306'use strict'; 26307 26308/* ---------------------------------------- 26309 * -- Sliders -- 26310 * 26311 * Configuration Options: 26312 * loop: BOOLEAN Both; If no option given, programmatically set to true. 26313 * dots: BOOLEAN Both; If no option given, programmatically set to true. 26314 * pagination: OBJECT Swiper only; If no option given, pagination is omitted from slider settings. 26315 * arrows: BOOLEAN Both; If no option given, automatically set to true in widget background. 26316 * arrowsPosition: STRING ['inside' or 'outside'] Swiper only; If no option given, automatically set to the outside. 26317 * navigation: OBJECT Swiper only; If no option given, navigation is omitted from slider settings. 26318 * slidesToShow: NUMBER Both; If no option given, programmatically set to 1. 26319 * slidesToScroll: NUMBER Both; If no option given, programmatically set to 1. 26320 * autoplay: NUMBER Both; When given, number is programmatically set to Autoplay Speed and Autoplay is set to true. If no option given, autoplay is set to false. 26321 * breakpoints: OBJECT Both; Properties are looped over to apply various breakpoint settings. If no option given, breakpoints is omitted from slider settings. 26322 * 26323 * Example Code: 26324 * sliders.init('.some-class-name', 26325 * { 26326 * loop: true, 26327 * dots: true, 26328 * pagination: {el: '.swiper-pagination', clickable: true}, 26329 * arrows: true, 26330 * arrowsPosition: 'inside', 26331 * navigation: {nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev'}, 26332 * slidesToShow: 6, 26333 * slidesToScroll: 1, 26334 * autoplay: 3000, 26335 * breakpoints: {0: {slidesToShow: 1}, 768: {slidesToShow: 3}} 26336 * }); 26337 * 26338 * 26339 * Additional configuration options exist for both sliders, but additional code changes would be needed to include them. 26340 * 26341 * Reference slider documentation: 26342 * 26343 * Swiper documentation - https://swiperjs.com/swiper-api 26344 * Slick documentation - https://kenwheeler.github.io/slick/ 26345 * 26346 * ---------------------------------------- 26347 */ 26348 26349var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 26350 26351exports.init = init; 26352exports.initializeCategorySliders = initializeCategorySliders; 26353exports.initializeRecommendationSlider = initializeRecommendationSlider; 26354 26355function getUniqueNumber() { 26356 var dateObject = new Date(); 26357 var uniqueNumber = dateObject.valueOf(); 26358 var suffixNumber = 1 + Math.floor(Math.random() * 100); 26359 uniqueNumber = uniqueNumber + suffixNumber; 26360 return uniqueNumber; 26361} 26362 26363function convertedSlickBreakpointSize(breakpointSize, breakpointSizeArray) { 26364 var sortedBreakpointSizes = breakpointSizeArray.sort(function (a, b) { return a - b; }); 26365 var convertedBreakpointSize; 26366 26367 if (breakpointSize == 0) { 26368 var mobileMaxSize = sortedBreakpointSizes[sortedBreakpointSizes.indexOf(0) + 1]; 26369 if (mobileMaxSize) { 26370 convertedBreakpointSize = mobileMaxSize - 1; 26371 } else { 26372 convertedBreakpointSize = 767; 26373 } 26374 } else if (breakpointSize == 768) { 26375 var desktopMaxSize = sortedBreakpointSizes[sortedBreakpointSizes.indexOf(768) + 1]; 26376 if (desktopMaxSize) { 26377 convertedBreakpointSize = desktopMaxSize - 1; 26378 } else { 26379 convertedBreakpointSize = 9999; 26380 } 26381 } else { 26382 var breakpointMaxSize = sortedBreakpointSizes[sortedBreakpointSizes.indexOf(breakpointSize) + 1]; 26383 if (breakpointMaxSize) { 26384 convertedBreakpointSize = breakpointMaxSize - 1; 26385 } else { 26386 convertedBreakpointSize = 9999; 26387 } 26388 } 26389 26390 return convertedBreakpointSize; 26391} 26392 26393function initSlick(elementSelector, settings) { 26394 if (!elementSelector) { 26395 return; 26396 } 26397 26398 var sliderSettings = { 26399 infinite: true, 26400 slidesToShow: 1, 26401 slidesToScroll: 1 26402 }; 26403 if (settings) { 26404 if ('loop' in settings) { 26405 sliderSettings.infinite = settings.loop; 26406 } 26407 if ('dots' in settings) { 26408 sliderSettings.dots = settings.dots; 26409 } 26410 if ('arrows' in settings) { 26411 sliderSettings.arrows = settings.arrows; 26412 } 26413 if ('slidesToShow' in settings) { 26414 sliderSettings.slidesToShow = settings.slidesToShow; 26415 } 26416 if ('slidesToScroll' in settings) { 26417 sliderSettings.slidesToScroll = settings.slidesToScroll; 26418 } 26419 if ('autoplay' in settings) { 26420 sliderSettings.autoplay = true; 26421 sliderSettings.autoplaySpeed = settings.autoplay; 26422 } 26423 if ('breakpoints' in settings) { 26424 sliderSettings.responsive = []; 26425 var breakpointSizeArray = Object.keys(settings.breakpoints).map(function (x) { 26426 return parseInt(x); // Extra precaution of sanitizing data for use in mathematical equations 26427 }); 26428 for (var breakpointSize in settings.breakpoints) { 26429 breakpointSize = parseInt(breakpointSize); 26430 var convertedBreakpointSize = convertedSlickBreakpointSize(breakpointSize, breakpointSizeArray); 26431 var breakpointSettingsObject = { 26432 breakpoint: convertedBreakpointSize, 26433 settings: {} 26434 }; 26435 var breakpointSizeSettings = settings.breakpoints[breakpointSize]; 26436 for (var sizeSetting in breakpointSizeSettings) { 26437 if ('loop' == sizeSetting) { 26438 breakpointSettingsObject.settings.infinite = breakpointSizeSettings[sizeSetting]; 26439 } 26440 if ('dots' == sizeSetting) { 26441 breakpointSettingsObject.settings.dots = breakpointSizeSettings[sizeSetting]; 26442 } 26443 if ('arrows' == sizeSetting) { 26444 breakpointSettingsObject.settings.arrows = breakpointSizeSettings[sizeSetting]; 26445 } 26446 if ('slidesToShow' == sizeSetting) { 26447 if (convertedBreakpointSize == 9999) { 26448 sliderSettings.slidesToShow = breakpointSizeSettings[sizeSetting]; 26449 } else { 26450 breakpointSettingsObject.settings.slidesToShow = breakpointSizeSettings[sizeSetting]; 26451 } 26452 } 26453 if ('slidesToScroll' == sizeSetting) { 26454 if (convertedBreakpointSize == 9999) { 26455 sliderSettings.slidesToScroll = breakpointSizeSettings[sizeSetting]; 26456 } else { 26457 breakpointSettingsObject.settings.slidesToScroll = breakpointSizeSettings[sizeSetting]; 26458 } 26459 } 26460 if ('autoplay' == sizeSetting) { 26461 if (convertedBreakpointSize == 9999) { 26462 sliderSettings.autoplay = true; 26463 sliderSettings.autoplaySpeed = breakpointSizeSettings[sizeSetting].autoplay; 26464 } else { 26465 breakpointSettingsObject.settings.autoplay = true; 26466 breakpointSettingsObject.settings.autoplaySpeed = breakpointSizeSettings[sizeSetting]; 26467 } 26468 } 26469 } 26470 //if (convertedBreakpointSize != 9999) { 26471 sliderSettings.responsive.push(breakpointSettingsObject); 26472 //} 26473 } 26474 } 26475 26476 $(elementSelector).slick(sliderSettings); 26477 } else { 26478 $(elementSelector).slick(); 26479 } 26480} 26481 26482function initSwiper(elementSelector, settings, classesForSettings) { 26483 if (!elementSelector) { 26484 return; 26485 } 26486 26487 var sliderSettings = { 26488 loop: true, 26489 spaceBetween: 20, 26490 preventInteractionOnTransition: true, 26491 a11y: { 26492 enabled: true, 26493 firstSlideMessage: 'This is the first slide', 26494 lastSlideMessage: 'This is the last slide' 26495 }, 26496 keyboard: { 26497 enabled: true, 26498 pageUpDown: true 26499 } 26500 }; 26501 if (settings) { 26502 if ('spaceBetween' in settings) { 26503 sliderSettings.spaceBetween = settings.spaceBetween; 26504 } 26505 if ('loop' in settings) { 26506 sliderSettings.loop = settings.loop; 26507 } 26508 if ('pagination' in settings || 'dots' in settings) { 26509 if (settings.pagination) { 26510 if (settings.pagination.el && settings.pagination.el.length > 0) { 26511 sliderSettings.pagination = settings.pagination; 26512 } 26513 } else { 26514 if (settings.dots) { 26515 sliderSettings.pagination = { 26516 el: '.swiper-pagination', 26517 clickable: true 26518 } 26519 } 26520 } 26521 } 26522 if ('navigation' in settings || 'arrows' in settings) { 26523 if (settings.navigation) { 26524 if (settings.navigation.nextEl && settings.navigation.nextEl.length > 0) { 26525 sliderSettings.navigation = settings.navigation; 26526 } 26527 } else { 26528 if (settings.arrows) { 26529 sliderSettings.navigation = { 26530 nextEl: '.swiper-button-next', 26531 prevEl: '.swiper-button-prev' 26532 } 26533 } 26534 } 26535 } 26536 if ('slidesToShow' in settings) { 26537 sliderSettings.slidesPerView = settings.slidesToShow; 26538 } 26539 if ('autoplay' in settings) { 26540 sliderSettings.autoplay = { 26541 delay: settings.autoplay, 26542 disableOnInteraction: true 26543 }; 26544 } 26545 if ('breakpoints' in settings) { 26546 sliderSettings.breakpoints = {}; 26547 for (var breakpointSize in settings.breakpoints) { 26548 breakpointSize = parseInt(breakpointSize); 26549 sliderSettings.breakpoints[breakpointSize] = {}; 26550 var breakpointSizeSettings = settings.breakpoints[breakpointSize]; 26551 for (var sizeSetting in breakpointSizeSettings) { 26552 if ('loop' == sizeSetting) { 26553 sliderSettings.loop = breakpointSizeSettings[sizeSetting]; 26554 } 26555 if ('dots' == sizeSetting && breakpointSizeSettings[sizeSetting] == true) { 26556 sliderSettings.breakpoints[breakpointSize].pagination = { 26557 enabled: breakpointSizeSettings[sizeSetting], 26558 el: '.swiper-pagination', 26559 clickable: true 26560 }; 26561 if (classesForSettings && classesForSettings.pagination) { 26562 sliderSettings.breakpoints[breakpointSize].pagination.el = classesForSettings.pagination; 26563 } 26564 } 26565 if ('arrows' == sizeSetting && breakpointSizeSettings[sizeSetting] == true) { 26566 sliderSettings.breakpoints[breakpointSize].navigation = { 26567 enabled: breakpointSizeSettings[sizeSetting], 26568 nextEl: '.swiper-button-next', 26569 prevEl: '.swiper-button-prev' 26570 }; 26571 if (classesForSettings && classesForSettings.next && classesForSettings.prev) { 26572 sliderSettings.breakpoints[breakpointSize].navigation.nextEl = classesForSettings.next; 26573 sliderSettings.breakpoints[breakpointSize].navigation.prevEl = classesForSettings.prev; 26574 } 26575 } 26576 if ('slidesToShow' == sizeSetting) { 26577 sliderSettings.breakpoints[breakpointSize].slidesPerView = breakpointSizeSettings.slidesToShow; 26578 } 26579 if ('slidesToScroll' == sizeSetting) { 26580 sliderSettings.breakpoints[breakpointSize].slidesPerGroup = breakpointSizeSettings.slidesToScroll; 26581 } 26582 if ('autoplay' in breakpointSizeSettings) { 26583 sliderSettings.autoplay = { 26584 delay: breakpointSizeSettings.autoplay, 26585 disableOnInteraction: true 26586 }; 26587 } else { 26588 sliderSettings.breakpoints[breakpointSize].autoplay = false;
26589 } 26590 } 26591 } 26592 } 26593 } 26594 26595 return new Swiper (elementSelector, sliderSettings); 26596} 26597 26598function formatSlickHTML($element, settings, isEinstein) { 26599 var originalSlideElements = $element.children().toArray(); 26600 var uniqueSlider; 26601 26602 if ($element.attr('id') && $element.attr('id').indexOf('slider-index') > -1) { 26603 uniqueSlider = $element.attr('id'); 26604 } else { 26605 uniqueSlider = 'slider-index-' + getUniqueNumber().toString(); 26606 } 26607 26608 $element.attr('id', uniqueSlider); 26609 26610 // Einstein CQuotient scripts are mixed in with slides at time of slider initialization. Rework the HTML structure. 26611 if (originalSlideElements.length > 0 && isEinstein) { 26612 var modifiedSlideElements = []; 26613 var cqScripts = []; 26614 26615 $.each(originalSlideElements, function(index, element) { 26616 if (element.tagName.toUpperCase() === 'SCRIPT') { 26617 cqScripts.push(element); 26618 } else { 26619 if (element.tagName.toUpperCase() === 'LI') { 26620 modifiedSlideElements.push(element); 26621 } 26622 } 26623 }); 26624 26625 if (cqScripts.length > 0) { 26626 $element.closest('div.slider-clip').append(cqScripts); 26627 } 26628 26629 $element.html(''); 26630 $element.append(modifiedSlideElements); 26631 } 26632 return; 26633} 26634 26635function formatSwiperHTML($element, settings, isEinstein) { 26636 var originalSlideElements = $element.children().toArray(); 26637 var uniqueSlider, sortedSlidesPerViewArray, addSlides, finalSlides; 26638 var isLoop = true; 26639 var slidesPerViewArray = []; 26640 var cqScripts = []; 26641 var modifiedSlideElements = []; 26642 var duplicatedSlideElements = []; 26643 var hasSwiperHTML = $element.hasClass('swiper-full-wrapper') && $element.find('.swiper').length > 0; 26644 var swiperClassesForSettings = {}; 26645 26646 if ($element.attr('id') && $element.attr('id').indexOf('slider-index') > -1) { 26647 uniqueSlider = $element.attr('id'); 26648 } else { 26649 uniqueSlider = 'slider-index-' + getUniqueNumber().toString(); 26650 } 26651 26652 var $swiperParent = $('<div />', { 'class': 'swiper', 'id': uniqueSlider }), 26653 $swiperPagination = $('<div />', { 'class': 'swiper-pagination swiper-pagination-' + uniqueSlider }), 26654 $swiperNavigation = $('<div />', { 'class': 'swiper-navigation-buttons-container' }), 26655 $swiperPrevArrow = $('<div />', { 'class': 'swiper-button-prev swiper-button-prev-' + uniqueSlider }), 26656 $swiperNextArrow = $('<div />', { 'class': 'swiper-button-next swiper-button-next-' + uniqueSlider }), 26657 $swiperWrapper = $('<div />', { 'class': 'swiper-wrapper' }); 26658 26659 if (settings) { 26660 if ('breakpoints' in settings) { 26661 for (var breakpointSize in settings.breakpoints) { 26662 var breakpointSizeSettings = settings.breakpoints[breakpointSize]; 26663 26664 /* --- Swiper Arrows Navigation --- */ 26665 // Swiper does not display arrows by default the way Slick does. We must actively include them to match the defaults of Slick. 26666 var navDisplayClass = breakpointSize == '0' ? 'show-mobile-nav-buttons' : 'show-desktop-nav-buttons'; 26667 $swiperNavigation.addClass(navDisplayClass); 26668 26669 // If arrows were deliberately set to false in settings, that means hide them for all breakpoint sizes. 26670 if ('arrows' in settings) { 26671 if (settings.arrows == false) { 26672 $swiperNavigation.removeClass('show-mobile-nav-buttons show-desktop-nav-buttons'); 26673 } 26674 // Else if arrows were deliberately set to false for specific breakpoint, then hide for that breakpoint. 26675 } else if ('arrows' in breakpointSizeSettings) { 26676 if (breakpointSizeSettings.arrows == false) { 26677 $swiperNavigation.removeClass(navDisplayClass); 26678 } 26679 } 26680 26681 /* --- Swiper Dots Pagination --- */ 26682 // Swiper does not display pagination dots by default the way Slick does. We must actively include them to match the defaults of Slick. 26683 var paginationDisplayClass = breakpointSize == '0' ? 'show-mobile-pagination' : 'show-desktop-pagniation'; 26684 $swiperPagination.addClass(paginationDisplayClass); 26685 26686 // If dots were deliberately set to false in settings, that means hide them for all breakpoint sizes. 26687 if ('dots' in settings) { 26688 if (settings.dots == false) { 26689 $swiperPagination.removeClass('show-mobile-pagination show-desktop-pagniation'); 26690 } 26691 // Else if dots were deliberately set to false for specific breakpoint, then hide for that breakpoint. 26692 } else if ('dots' in breakpointSizeSettings) { 26693 if (breakpointSizeSettings.dots == false) { 26694 $swiperPagination.removeClass(paginationDisplayClass); 26695 } 26696 } 26697 26698 if ('slidesToShow' in breakpointSizeSettings) { 26699 slidesPerViewArray.push(parseInt(breakpointSizeSettings.slidesToShow)); 26700 } 26701 } 26702 } else { 26703 // Swiper does not display arrows by default the way Slick does. We must actively include them to match the defaults of Slick. 26704 $swiperNavigation.addClass('show-mobile-nav-buttons show-desktop-nav-buttons'); 26705 26706 // If arrows were deliberately set to false in settings, that means hide them for all breakpoint sizes. 26707 if ('arrows' in settings) { 26708 if (settings.arrows == false) { 26709 $swiperNavigation.removeClass('show-mobile-nav-buttons show-desktop-nav-buttons'); 26710 } 26711 } 26712 26713 // Swiper does not display pagination dots by default the way Slick does. We must actively include them to match the defaults of Slick. 26714 $swiperPagination.addClass('show-desktop-pagniation show-mobile-pagination'); 26715 26716 // If dots were deliberately set to false in settings, that means hide them for all breakpoint sizes. 26717 if ('dots' in settings) { 26718 if (settings.dots == false) { 26719 $swiperPagination.removeClass('show-desktop-pagniation show-mobile-pagination'); 26720 } 26721 } 26722 } 26723 if ('loop' in settings) { 26724 isLoop = settings.loop; 26725 } 26726 } 26727 26728 // Content overrides for slides to show 26729 if ($element.attr('data-desktop-slides') || $element.attr('data-mobile-slides')) { 26730 if ($element.attr('data-desktop-slides')) { 26731 slidesPerViewArray.push(parseInt($element.attr('data-desktop-slides'))); 26732 } 26733 if ($element.attr('data-mobile-slides')) { 26734 slidesPerViewArray.push(parseInt($element.attr('data-mobile-slides'))); 26735 } 26736 } 26737 26738 if (slidesPerViewArray) { 26739 sortedSlidesPerViewArray = slidesPerViewArray.sort(function (a, b) { return a - b; }); 26740 } 26741 26742 if (!hasSwiperHTML && originalSlideElements.length > 0) { 26743 $element.addClass('swiper-full-wrapper'); 26744
26745 // Einstein CQuotient scripts are mixed in with slides at time of slider initialization. Rework the HTML structure. 26746 if (isEinstein) { 26747 $.each(originalSlideElements, function(index, element) { 26748 if (element.tagName.toUpperCase() === 'SCRIPT') { 26749 cqScripts.push(element); 26750 } else { 26751 var formattedSlide; 26752 if (element.tagName.toUpperCase() === 'DIV') { 26753 formattedSlide = $(element).addClass('swiper-slide'); 26754 } else { 26755 formattedSlide = $('<div />', { 'class': 'swiper-slide' }).html($(element).html()); 26756 } 26757 modifiedSlideElements.push(formattedSlide); 26758 } 26759 }); 26760 } else { 26761 // Proceed to modify regular slide elements (non-Einstein) 26762 modifiedSlideElements = originalSlideElements.map(function(element, index) { 26763 if (element.tagName.toUpperCase() === 'DIV') { 26764 return $(element).addClass('swiper-slide')[0]; 26765 } else { 26766 return $('<div />', { 'class': 'swiper-slide' }).html($(element).html())[0]; 26767 } 26768 }); 26769 } 26770 26771 // Add additional slides (according to lowest common multiple) to fix loop bug in Swiper 26772 if (modifiedSlideElements && sortedSlidesPerViewArray && isLoop) { 26773 var LCM = leastCommonMultiple(sortedSlidesPerViewArray); 26774 if (sortedSlidesPerViewArray.indexOf(LCM) > -1) { 26775 addSlides = (LCM * 2) - modifiedSlideElements.length; 26776 } else { 26777 addSlides = LCM - modifiedSlideElements.length; 26778 } 26779 if (addSlides < 0) { 26780 var HCM = sortedSlidesPerViewArray.reduce(function (a, b) { return a * b; }); 26781 addSlides = HCM - modifiedSlideElements.length; 26782 } 26783 $.each(modifiedSlideElements, function(idx, item) { 26784 if (idx < addSlides) { 26785 duplicatedSlideElements.push($(item).clone()); 26786 } 26787 }); 26788 } 26789 26790 // Create final array of slide elements 26791 finalSlides = $.merge(modifiedSlideElements, duplicatedSlideElements); 26792 26793 // Append new swiper HTML elements to swiper wrapper 26794 $swiperWrapper.append(finalSlides); 26795 $swiperNavigation.append($swiperPrevArrow).append($swiperNextArrow); 26796 $swiperParent.append($swiperWrapper).append($swiperPagination); 26797 26798 // Set slide arrows either inside or outside slider container 26799 var arrowsPosition = settings && 'arrowsPosition' in settings ? settings.arrowsPosition : null; 26800 if (arrowsPosition && arrowsPosition == 'inside') { 26801 $swiperParent.append($swiperNavigation).addClass('swiper-inside-navigation'); 26802 } 26803 26804 // Replace swiper wrapper contents with new HTML 26805 $element.html($swiperParent); 26806 26807 if (!arrowsPosition || arrowsPosition == 'outside') { // If arrows are outside, we have to wait until swiper wrapper has content in line above before we prepend 26808 $element.prepend($swiperNavigation); 26809 } 26810 if (isEinstein && cqScripts.length > 0) { 26811 $element.append(cqScripts); 26812 } 26813 26814 // Grab the unique classes from all the new elements above and return for further use 26815 swiperClassesForSettings.parent = '#' + uniqueSlider; 26816 swiperClassesForSettings.pagination = '.swiper-pagination-' + uniqueSlider; 26817 swiperClassesForSettings.prev = '.swiper-button-prev-' + uniqueSlider; 26818 swiperClassesForSettings.next = '.swiper-button-next-' + uniqueSlider; 26819 } 26820 return swiperClassesForSettings; 26821} 26822 26823function init (elementClass, settings, isEinstein) { 26824 var selector = elementClass; 26825 if (!elementClass || ($(elementClass).length == 0 && elementClass.indexOf(':has') < 0)) { 26826 return; 26827 } 26828 if (SitePreferences.CONTENT_SLOT_SLIDER == 'swiperJS') { 26829 $(elementClass).each(function(n, elm) { 26830 var $element = $(elm); 26831 var hasSwiperHTML = $element.find('.swiper-initialized').length > 0; 26832 26833 if (!hasSwiperHTML) { 26834 var classesForSettings = formatSwiperHTML($element, settings, isEinstein); 26835 if (!settings) { 26836 settings = {}; 26837 } 26838 if (classesForSettings) { 26839 // Override selector class for ID if we have it 26840 selector = classesForSettings.parent ? classesForSettings.parent : selector; 26841 settings.pagination = { 26842 el: classesForSettings.pagination, 26843 clickable: true 26844 }; 26845 settings.navigation = { 26846 nextEl: classesForSettings.next, 26847 prevEl: classesForSettings.prev 26848 }; 26849 26850 // Content overrides for slides to show 26851 if ($element.attr('data-desktop-slides') || $element.attr('data-mobile-slides')) { 26852 if ($element.attr('data-desktop-slides')) { 26853 if (settings.breakpoints && settings.breakpoints[768]) { 26854 settings.breakpoints[768].slidesToShow = parseInt($element.attr('data-desktop-slides')); 26855 } else { 26856 if (!settings.breakpoints) { 26857 settings.breakpoints = { 768: { slidesToShow: parseInt($element.attr('data-desktop-slides')) }}; 26858 } 26859 if (!settings.breakpoints[768]) { 26860 settings.breakpoints[768] = { slidesToShow: parseInt($element.attr('data-desktop-slides')) }; 26861 } 26862 } 26863 } 26864 if ($element.attr('data-mobile-slides')) { 26865 if (settings.breakpoints && settings.breakpoints[0]) { 26866 settings.breakpoints[0].slidesToShow = parseInt($element.attr('data-mobile-slides')); 26867 } else { 26868 if (!settings.breakpoints) { 26869 settings.breakpoints = { 0: { slidesToShow: parseInt($element.attr('data-mobile-slides')) }}; 26870 } 26871 if (!settings.breakpoints[0]) { 26872 settings.breakpoints[0] = { slidesToShow: parseInt($element.attr('data-mobile-slides')) }; 26873 } 26874 } 26875 } 26876 } 26877 } 26878 return initSwiper(selector, settings, classesForSettings); 26879 } 26880 }); 26881 } else { 26882 $(elementClass).each(function(n, elm) { 26883 var $element = $(elm); 26884 var elementIdSelector; 26885 formatSlickHTML($element, settings, isEinstein); 26886 elementIdSelector = '#' + $element.attr('id'); 26887 initSlick(elementIdSelector, settings); 26888 }); 26889 } 26890} 26891 26892function leastCommonMultiple(values) { 26893 function gcd(a, b) { 26894 // Greatest common divisor of 2 integers 26895 return !b ? a : gcd(b, a % b); 26896 } 26897 26898 function lcm(a, b) { 26899 // Least common multiple of 2 integers 26900 return (a * b) / gcd(a, b); 26901 } 26902 26903 var multiple = values[0]; 26904 // Least common multiple of a list of integers
26905 values.forEach(function(n) { 26906 multiple = lcm(multiple, n); 26907 }); 26908 26909 // Return least common multiple for array of values 26910 return multiple; 26911} 26912 26913function initializeCategorySliders(elementClass) { 26914 var $categorySliders = $(elementClass); 26915 if ($categorySliders.length > 0) { 26916 $categorySliders.each(function(index, element) { 26917 var $element = $(element); 26918 var categorySliderOptions = { 26919 breakpoints: {} 26920 }; 26921 var uniqueSlider = 'category-slider-index-' + getUniqueNumber().toString(); 26922 $element.addClass(uniqueSlider); 26923 26924 // Desktop slot config options 26925 var categorySliderDesktopOptions = $element.attr('slider-desktop-options'); 26926 if (categorySliderDesktopOptions) { 26927 categorySliderDesktopOptions = JSON.parse(categorySliderDesktopOptions); 26928 categorySliderOptions.breakpoints[categorySliderDesktopOptions.breakpointSize] = categorySliderDesktopOptions; 26929 } 26930 // Mobile slot config options 26931 var categorySliderMobileOptions = $element.attr('slider-mobile-options'); 26932 if (categorySliderMobileOptions) { 26933 categorySliderMobileOptions = JSON.parse(categorySliderMobileOptions); 26934 categorySliderOptions.breakpoints[categorySliderMobileOptions.breakpointSize] = categorySliderMobileOptions; 26935 } 26936 26937 init('.' + uniqueSlider, categorySliderOptions); 26938 }); 26939 } 26940} 26941 26942function initializeRecommendationSlider() { 26943 initializeSFCCProductRecommendationSliders(); 26944 26945 var attemptNumber = 0; 26946 var sliderInitializedClass = SitePreferences.CONTENT_SLOT_SLIDER == 'swiperJS' ? 'swiper-initialized' : 'slick-initialized'; 26947 var sliderSelector = '.recomm-prod-anchor-slot .product-recommendations .slider-products-primary'; 26948 function recommendationSliderIntervalHandler() { 26949 var recommendationSliderInitialized; 26950 if (SitePreferences.CONTENT_SLOT_SLIDER == 'swiperJS') { 26951 recommendationSliderInitialized = $(sliderSelector).find('.' + sliderInitializedClass).length > 0; 26952 } else { 26953 recommendationSliderInitialized = $(sliderSelector).filter(function(index) { 26954 return $(this).hasClass(sliderInitializedClass); 26955 }).length > 0; 26956 } 26957 26958 attemptNumber++; 26959 if(recommendationSliderInitialized || attemptNumber > 20) { 26960 $(document).trigger('EinsteinProductRecommendations.Done', $('#product-recommendations')); 26961 if (SitePreferences.CONTENT_SLOT_SLIDER == 'imgViewer2Slick') { 26962 $(document).trigger('SlickSliderAccessibilityMods'); 26963 } 26964 clearInterval(timer); 26965 return; 26966 } 26967 $(sliderSelector).trigger('init-slider'); 26968 } 26969 var timer = setInterval(recommendationSliderIntervalHandler, 500); 26970} 26971 26972function initializeSFCCProductRecommendationSliders() { 26973 var attemptNumber = 0; 26974 var sliderInitializedClass = SitePreferences.CONTENT_SLOT_SLIDER == 'swiperJS' ? 'swiper-initialized' : 'slick-initialized'; 26975 var sliderSelector = '.product-recommendations-sfcc .slider-products-primary .slides'; 26976 var recommendationSlidersCount = $(sliderSelector).length; 26977 function recommendationSliderIntervalHandler() { 26978 var recommendationSlidersInitialized; 26979 if (SitePreferences.CONTENT_SLOT_SLIDER == 'swiperJS') { 26980 recommendationSlidersInitialized = $(sliderSelector).find('.' + sliderInitializedClass).length == recommendationSlidersCount; 26981 } else { 26982 recommendationSlidersInitialized = $(sliderSelector).filter(function(index) { 26983 return $(this).hasClass(sliderInitializedClass); 26984 }).length == recommendationSlidersCount; 26985 } 26986 26987 attemptNumber++; 26988 if(recommendationSlidersInitialized || attemptNumber > 20) { 26989 $(document).trigger('SFCCProductRecommendations.Done'); 26990 if (SitePreferences.CONTENT_SLOT_SLIDER == 'imgViewer2Slick') { 26991 $(document).trigger('SlickSliderAccessibilityMods'); 26992 } 26993 clearInterval(timer); 26994 return; 26995 } 26996 $(sliderSelector).trigger('init-slider'); 26997 } 26998 var timer = setInterval(recommendationSliderIntervalHandler, 500); 26999} 27000},{"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120}],96:[function(require,module,exports){ 27001'use strict'; 27002 27003var inventory = require('./'); 27004 27005var cartInventory = { 27006 setSelectedStore: function (storeId) { 27007 var $selectedStore = $('.store-tile.' + storeId), 27008 $lineItem = $('.cart-row[data-uuid="' + this.uuid + '"]'),
27009 storeAddress = $selectedStore.find('.store-address').html(), 27010 storeStatus = $selectedStore.find('.store-status').data('status'), 27011 storeStatusText = $selectedStore.find('.store-status').text(); 27012 this.selectedStore = storeId; 27013 27014 $lineItem.find('.instore-delivery .selected-store-address') 27015 .data('storeId', storeId) 27016 .attr('data-store-id', storeId) 27017 .html(storeAddress); 27018 $lineItem.find('.instore-delivery .selected-store-availability') 27019 .data('status', storeStatus) 27020 .attr('data-status', storeStatus) 27021 .text(storeStatusText); 27022 $lineItem.find('.instore-delivery .delivery-option').removeAttr('disabled').trigger('click'); 27023 }, 27024 cartSelectStore: function (selectedStore) { 27025 var self = this; 27026 inventory.getStoresInventory(this.uuid).then(function (stores) { 27027 inventory.selectStoreDialog({ 27028 stores: stores, 27029 selectedStoreId: selectedStore, 27030 selectedStoreText: Resources.SELECTED_STORE, 27031 continueCallback: function () {}, 27032 selectStoreCallback: self.setSelectedStore.bind(self) 27033 }); 27034 }).done(); 27035 }, 27036 setDeliveryOption: function (value, storeId) { 27037 // set loading state 27038 $('.item-delivery-options') 27039 .addClass('loading') 27040 .children().hide(); 27041 27042 var data = { 27043 plid: this.uuid, 27044 storepickup: (value === 'store' ? true : false) 27045 }; 27046 if (value === 'store') { 27047 data.storepickup = true; 27048 data.storeid = storeId; 27049 } else { 27050 data.storepickup = false; 27051 } 27052 $.ajax({ 27053 url: Urls.setStorePickup, 27054 data: data, 27055 success: function () { 27056 // remove loading state 27057 $('.item-delivery-options') 27058 .removeClass('loading') 27059 .children().show(); 27060 } 27061 }); 27062 }, 27063 init: function () { 27064 var self = this; 27065 $('.item-delivery-options .set-preferred-store').on('click', function (e) { 27066 e.preventDefault(); 27067 self.uuid = $(this).data('uuid'); 27068 var selectedStore = $(this).closest('.instore-delivery').find('.selected-store-address').data('storeId'); 27069 if (!User.zip) { 27070 inventory.zipPrompt(function () { 27071 self.cartSelectStore(selectedStore); 27072 }); 27073 } else { 27074 self.cartSelectStore(selectedStore); 27075 } 27076 }); 27077 $('.item-delivery-options .delivery-option').on('click', function () { 27078 // reset the uuid 27079 var selectedStore = $(this).closest('.instore-delivery').find('.selected-store-address').data('storeId'); 27080 self.uuid = $(this).closest('.cart-row').data('uuid'); 27081 self.setDeliveryOption($(this).val(), selectedStore); 27082 }); 27083 } 27084}; 27085 27086module.exports = cartInventory; 27087 27088},{"./":97}],97:[function(require,module,exports){ 27089'use strict'; 27090 27091var _ = require('lodash'), 27092 dialog = require('../dialog'), 27093 TPromise = require('promise'), 27094 util = require('../util'); 27095 27096var newLine = '\n'; 27097var storeTemplate = function (store, selectedStoreId, selectedStoreText) { 27098 return [ 27099 '<li class="store-tile ' + store.storeId + (store.storeId === selectedStoreId ? ' selected' : '') + '">', 27100 ' <p class="store-address">', 27101 ' ' + store.address1 + '<br/>', 27102 ' ' + store.city + ', ' + store.stateCode + ' ' + store.postalCode, 27103 ' </p>', 27104 ' <p class="store-status" data-status="' + store.statusclass + '">' + store.status + '</p>', 27105 ' <button class="select-store-button" data-store-id="' + store.storeId + '"' + 27106 (store.statusclass !== 'store-in-stock' ? 'disabled="disabled"' : '') + '>', 27107 ' ' + (store.storeId === selectedStoreId ? selectedStoreText : Resources.SELECT_STORE), 27108 ' </button>', 27109 '</li>' 27110 ].join(newLine); 27111}; 27112 27113var storeListTemplate = function (stores, selectedStoreId, selectedStoreText) { 27114 if (stores && stores.length) { 27115 return [ 27116 '<div class="store-list-container">', 27117 '<ul class="store-list">', 27118 _.map(stores, function (store) { 27119 return storeTemplate(store, selectedStoreId, selectedStoreText); 27120 }).join(newLine), 27121 '</ul>', 27122 '</div>', 27123 '<div class="store-list-pagination">', 27124 '</div>' 27125 ].join(newLine); 27126 } else { 27127 return '<div class="no-results">' + Resources.INVALID_ZIP + '</div>'; 27128 } 27129}; 27130 27131var zipPromptTemplate = function () { 27132 return [ 27133 '<div id="preferred-store-panel">', 27134 ' <input type="text" id="user-zip" placeholder="' + Resources.ENTE
27134R_ZIP + '" name="zipCode"/>', 27135 '</div>' 27136 ].join(newLine); 27137}; 27138 27139/** 27140 * @description test whether zipcode is valid for either US or Canada 27141 * @return {Boolean} true if the zipcode is valid for either country, false if it's invalid for both 27142 **/ 27143var validateZipCode = function (zipCode) { 27144 var regexes = { 27145 canada: /^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ]( )?\d[ABCEGHJKLMNPRSTVWXYZ]\d$/i, 27146 usa: /^\d{5}(-\d{4})?$/ 27147 }, 27148 valid = false; 27149 if (!zipCode) { return; } 27150 _.each(regexes, function (re) { 27151 var regexp = new RegExp(re); 27152 valid = regexp.test(zipCode); 27153 }); 27154 return valid; 27155}; 27156 27157var storeinventory = { 27158 zipPrompt: function (callback) { 27159 var self = this; 27160 dialog.open({ 27161 html: zipPromptTemplate(), 27162 options: { 27163 title: Resources.STORE_NEAR_YOU, 27164 width: 500, 27165 buttons: [{ 27166 text: Resources.SEARCH, 27167 click: function () { 27168 var zipCode = $('#user-zip').val(); 27169 if (validateZipCode(zipCode)) { 27170 self.setUserZip(zipCode); 27171 if (callback) { 27172 callback(zipCode); 27173 } 27174 } 27175 } 27176 }], 27177 open: function () { 27178 $('#user-zip').on('keypress', function (e) { 27179 if (e.which === 13) { 27180 // trigger the search button 27181 $('.ui-dialog-buttonset .ui-button').trigger('click'); 27182 } 27183 }); 27184 } 27185 } 27186 }); 27187 }, 27188 getStoresInventory: function (pid) { 27189 return TPromise.resolve($.ajax({ 27190 url: util.appendParamsToUrl(Urls.storesInventory, { 27191 pid: pid, 27192 zipCode: User.zip 27193 }), 27194 dataType: 'json' 27195 })); 27196 }, 27197 /** 27198 * @description open the dialog to select store 27199 * @param {Array} options.stores 27200 * @param {String} options.selectedStoreId 27201 * @param {String} options.selectedStoreText 27202 * @param {Function} options.continueCallback 27203 * @param {Function} options.selectStoreCallback 27204 **/ 27205 selectStoreDialog: function (options) { 27206 var self = this, 27207 stores = options.stores, 27208 selectedStoreId = options.selectedStoreId, 27209 selectedStoreText = options.selectedStoreText, 27210 storeList = storeListTemplate(stores, selectedStoreId, selectedStoreText); 27211 dialog.open({ 27212 html: storeList, 27213 options: { 27214 title: Resources.SELECT_STORE + ' - ' + User.zip, 27215 buttons: [{ 27216 text: Resources.CHANGE_LOCATION, 27217 click: function () { 27218 self.setUserZip(null); 27219 // trigger the event to start the process all over again 27220 $('.set-preferred-store').trigger('click'); 27221 }.bind(this) 27222 }, { 27223 text: Resources.CONTINUE, 27224 click: function () { 27225 if (options.continueCallback) { 27226 options.continueCallback(stores); 27227 } 27228 dialog.close(); 27229 } 27230 }], 27231 open: function () { 27232 $('.select-store-button').on('click', function (e) { 27233 e.preventDefault(); 27234 var storeId = $(this).data('storeId'); 27235 // if the store is already selected, don't select again 27236 if (storeId === selectedStoreId) { return; } 27237 $('.store-list .store-tile.selected').removeClass('selected') 27238 .find('.select-store-button').text(Resources.SELECT_STORE); 27239 $(this).text(selectedStoreText) 27240 .closest('.store-tile').addClass('selected'); 27241 if (options.selectStoreCallback) { 27242 options.selectStoreCallback(storeId); 27243 } 27244 }); 27245 } 27246 } 27247 }); 27248 }, 27249 setUserZip: function (zip) { 27250 User.zip = zip; 27251 27252 $.ajax({ 27253 type: 'POST', 27254 url: Urls.setZipCode, 27255 data: { 27256 zipCode: zip 27257 } 27258 }); 27259 }, 27260 shippingLoad: function () { 27261 var $checkoutForm = $('.address'); 27262 $checkoutForm.off('click'); 27263 $checkoutForm.on('click', 'input[name$="_shippingAddress_isGift"]', function () { 27264 $(this).parent().siblings('.gift-message-text').toggleClass('hidden', $('input[name$="_shippingAddress_isGift"]:checked').val()); 27265 }); 27266 } 27267}; 27268 27269module.exports = storeinventory; 27270 27271},{"../dialog":36,"../util":102,"lodash":133,"promise":134}],98:[function(require,module,exports){ 27272'use strict'; 27273 27274var _ = require('lodash'), 27275 inventory = require('./'); 27276 27277var newLine = '\n'; 27278var pdpStoreTemplate = function (store) { 27279 return [ 27280 '<li class="store-list-item ' + (store.storeId === User.storeId ? ' selected' : '') + '">',
27281 ' <div class="store-address">' + store.address1 + ', ' + store.city + ' ' + store.stateCode + 27282 ' ' + store.postalCode + '</div>', 27283 ' <div class="store-status" data-status="' + store.statusclass + '">' + store.status + '</div>', 27284 '</li>' 27285 ].join(newLine); 27286}; 27287var pdpStoresListingTemplate = function (stores) { 27288 if (stores && stores.length) { 27289 return [ 27290 '<div class="store-list-pdp-container">', 27291 (stores.length > 1 ? ' <a class="stores-toggle collapsed" href="#">' + Resources.SEE_MORE + '</a>' : ''), 27292 ' <ul class="store-list-pdp">', 27293 _.map(stores, pdpStoreTemplate).join(newLine), 27294 ' </ul>', 27295 '</div>' 27296 ].join(newLine); 27297 } 27298}; 27299 27300var storesListing = function (stores) { 27301 // list all stores on PDP page 27302 if ($('.store-list-pdp-container').length) { 27303 $('.store-list-pdp-container').remove(); 27304 } 27305 $('.availability-results').append(pdpStoresListingTemplate(stores)); 27306}; 27307 27308var productInventory = { 27309 setPreferredStore: function (storeId) { 27310 User.storeId = storeId; 27311 $.ajax({ 27312 url: Urls.setPreferredStore, 27313 type: 'POST', 27314 data: {storeId: storeId} 27315 }); 27316 }, 27317 productSelectStore: function () { 27318 var self = this; 27319 inventory.getStoresInventory(this.pid).then(function (stores) { 27320 inventory.selectStoreDialog({ 27321 stores: stores, 27322 selectedStoreId: User.storeId, 27323 selectedStoreText: Resources.PREFERRED_STORE, 27324 continueCallback: storesListing, 27325 selectStoreCallback: self.setPreferredStore 27326 }); 27327 }).done(); 27328 }, 27329 init: function () { 27330 var $availabilityContainer = $('.availability-results'), 27331 self = this; 27332 this.pid = $('input[name="pid"]').val(); 27333 27334 $('#product-content .set-preferred-store').on('click', function (e) { 27335 e.preventDefault(); 27336 if (!User.zip) { 27337 inventory.zipPrompt(function () { 27338 self.productSelectStore(); 27339 }); 27340 } else { 27341 self.productSelectStore(); 27342 } 27343 }); 27344 27345 if ($availabilityContainer.length) { 27346 if (User.storeId) { 27347 inventory.getStoresInventory(this.pid).then(storesListing); 27348 } 27349 27350 // See more or less stores in the listing 27351 $availabilityContainer.on('click', '.stores-toggle', function (e) { 27352 e.preventDefault(); 27353 $('.store-list-pdp .store-list-item').toggleClass('visible'); 27354 if ($(this).hasClass('collapsed')) { 27355 $(this).text(Resources.SEE_LESS); 27356 } else { 27357 $(this).text(Resources.SEE_MORE); 27358 } 27359 $(this).toggleClass('collapsed'); 27360 }); 27361 } 27362 } 27363}; 27364 27365module.exports = productInventory; 27366 27367},{"./":97,"lodash":133}],99:[function(require,module,exports){ 27368'use strict'; 27369 27370var render = function(styleCountCache) { 27371 if (styleCountCache) { 27372 $('[data-link-category]').each(function() { 27373 var categoryId = $(this).data('link-category'); 27374 27375 if (categoryId) { 27376 var categoryRefinements = styleCountCache.CategoryLinks[categoryId]; 27377 if (categoryRefinements && categoryRefinements.count > 0) { 27378 var $styleCount = $(this).find('.style-number'); 27379 var messageTemplate = categoryRefinements.count > 1 ? Resources.STYLE_PLURAL : Resources.STYLE_SINGULAR; 27380 var message = messageTemplate.replace('{0}', categoryRefinements.count); 27381 $styleCount.addClass('visible').text(message); 27382 27383 return; 27384 } 27385 } 27386 27387 $(this).closest('li').remove(); 27388 }); 27389 27390 $('[data-link-attribute-id]').each(function() { 27391 var categoryId = $(this).data('link-cgid'), 27392 refinementId = $(this).data('link-attribute-id'), 27393 refinementValue = $(this).data('link-attribute-value'); 27394 27395 var categoryRefinements = styleCountCache.RefinementLinks[categoryId]; 27396 if (categoryRefinements) { 27397 var attributeRefinements = categoryRefinements[refinementId]; 27398 if (attributeRefinements) { 27399 var attributeRefinement = attributeRefinements[refinementValue]; 27400 27401 if (attributeRefinement && attributeRefinement.count > 0) { 27402 var $styleCount = $(this).find('.style-number'); 27403 var messageTemplate = attributeRefinement.count > 1 ? Resources.STYLE_PLURAL : Resources.STYLE_SINGULAR; 27404 var message = messageTemplate.replace('{0}', attributeRefinement.count); 27405 $styleCount.addClass('visible').text(message); 27406 27407 return; 27408 } 27409 27410 } 27411 } 27412 27413 $(this).closest('li').remove(); 27414 }); 27415 } 27416} 27417 27418module.exports.render = render; 27419},{}],100:[function(require,module,exports){ 27420'use strict'; 27421 27422/** 27423 * Checks the TLS and displays a warning if appropriate 27424 * @function getUserAgent Checks the TLS and displays a warning if appropriate 27425 **/ 27426function getUserAgent() { 27427 // Use an external service to check the TLS of the browser 27428 // NOTE: this implementation uses https://www.howsmyssl.com 27429 // you may also wish to consider the API available at https://www.ssllabs.com/projects/ssllabs-apis/index.html 27430 var url = 'https://www.howsmyssl.com/a/check'; 27431 var cookieName = 'dw_TLSWarning'; 27432 var cookieValue = getCookie(cookieName); 27433 27434 // Test to see if this browser has already been flagged by looking at its cookies 27435 if (!cookieValue) { 27436 getTLS(url, function (message) { 27437 if (message.length > 0) { 27438 showWarning(message[0]); 27439 27440 // the browser is bad - set the cookie to true (for 15 minutes)
27441 setCookie(cookieName, 'true', 15); 27442 } else { 27443 // else the browser is good, set the cookie to false (for 30 days) so we don't check again 27444 setCookie(cookieName, 'false', 60 * 24 * 30); 27445 } 27446 }); 27447 } else if (cookieValue === 'true') { 27448 // if we already know that this is an invalid browser, show the warning 27449 showWarning(Resources.TLS_WARNING); 27450 } 27451} 27452 27453/** 27454 * Calls out to the TLS service and calls the callback with a message (if necessary) 27455 * @function getTLS 27456 * 27457 * @param {string} url - URL of external TLS-checking API 27458 * @param {function} callback - function to call with response 27459 **/ 27460function getTLS(url, callback) { 27461 var message = []; 27462 27463 // First, see if the browser is among the suspect browsers to see if a TLS check is necessary 27464 var userAgent = navigator.userAgent; 27465 27466 /** This list derived from https://www.ssllabs.com/ssltest/clients.html **/ 27467 var badBrowsers = ['MSIE 6.0','MSIE 7.0','MSIE 8.0','MSIE 9.0','MSIE 10.0', 27468 'Android 2.3.7', 'Android 4.0.4', 'Android 4.1.1', 'Android 4.2.2', 'Android 4.3', 27469 'Safari 5.1.9 / OS X 10.6.8', 'Safari 6.0.4 / OS X 10.8.4 ']; 27470 function checkTLSLevel(data) { 27471 // If we can determine the TLS level, check to see if it's less than 1.2 27472 if (parseFloat(data.tls_version.split(' ')[1]) < 1.1) { 27473 message.push(Resources.TLS_WARNING); 27474 callback(message); 27475 27476 //If you want to track statistics on bad TLS hits, include this call 27477 $.ajax({url: Urls.TLSBadTLS}); 27478 } 27479 } 27480 27481 function reportBadBrowser () { 27482 // If the TLS level cannot be determined just report that this browser is suspect 27483 message.push(Resources.TLS_WARNING); 27484 callback(message); 27485 27486 //If you want to track statistics on deprecated browsers, include this call 27487 $.ajax({url: Urls.TLSBadBrowser}); 27488 } 27489 27490 for (var i = 0; i < badBrowsers.length; i++) { 27491 if (userAgent.match(badBrowsers[i])) { 27492 // It's a suspect browser, let's see what it's TLS level is 27493 $.ajax({ 27494 url: url 27495 }).done(checkTLSLevel).fail(reportBadBrowser); 27496 break; 27497 } 27498 } 27499 27500 /** For testing purposes, uncomment this block 27501 message.push(Resources.TLS_WARNING); 27502 **/ 27503 callback(message); 27504} 27505 27506/** 27507 * @function showWarning turns on the browser-compatibility-alert and sets the message 27508 * 27509 * @param {string} message - the message that will be shown upon detection of a bad browser 27510 **/ 27511function showWarning(message) { 27512 $('<div/>').addClass('browser-compatibility-alert').append($('<p/>').addClass('browser-error').html(message)).appendTo('#browser-check'); 27513} 27514 27515/** 27516 * @function getCookie 27517 * 27518 * @param {string} key - The cookie name 27519 * @returns {string} value - the value of the cookie if found, null otherwise 27520 **/ 27521function getCookie(key) { 27522 var cookies = document.cookie.split(';'); 27523 for (var i = 0; i < cookies.length; i++) { 27524 var tokens = cookies[i].split('='); 27525 var cookieKey = tokens[0].trim(); 27526 if (cookieKey === key) { 27527 return tokens[1]; 27528 } 27529 } 27530 return ''; 27531} 27532 27533/** 27534 * @function setCookie 27535 * 27536 * @param {string} key - The cookie name 27537 * @param {string} value - The cookie value 27538 * @param {integer} minutes - The number of minutes to expire the cookie 27539 **/ 27540function setCookie (key, value, minutes) { 27541 var date = new Date(); 27542 date.setTime(date + (minutes * 60 * 1000)); 27543 27544 document.cookie = key + '=' + value + '; expires=' + date.toGMTString() + '; path=/'; 27545} 27546 27547/** 27548 * Export the getUserAgent function 27549 */ 27550 27551exports.getUserAgent = getUserAgent; 27552 27553},{}],101:[function(require,module,exports){ 27554'use strict'; 27555 27556/** 27557 * @function 27558 * @description Initializes the tooltip-content and layout 27559 */ 27560exports.init = function(optionsParameter, $containerParameter) { 27561 var defaultOptions = { 27562 items: '.tooltip', 27563 track: true, 27564 content: function () { 27565 return $(this).find('.tooltip-content').html(); 27566 } 27567 }; 27568 27569 var options; 27570 if (optionsParameter) { 27571 options = $.extend(defaultOptions, optionsParameter); 27572 } else { 27573 options = defaultOptions; 27574 } 27575 27576 var $container; 27577 if ($containerParameter) { 27578 $container = $containerParameter; 27579 } else { 27580 $container = $(document); 27581 } 27582 27583 $container.tooltip(options); 27584 27585 $(document).off('click', '.tooltip').on('click', '.tooltip', function(e) { 27586 e.preventDefault(); 27587 }); 27588 27589 $(document).off('click', '.share-link').on('click', '.share-link', function(e) { 27590 e.preventDefault(); 27591 var target = $(this).data('target'); 27592 if (target) { 27593 $(target).toggleClass('active'); 27594 } 27595 }); 27596}; 27597 27598},{}],102:[function(require,module,exports){ 27599'use strict'; 27600 27601var _ = require('lodash'); 27602var PaymentMethodConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').PaymentMethods; 27603var CreditCardConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').CreditCards; 27604 27605var util = { 27606 /** 27607 * @function
27608 * @description appends the parameter with the given name and value to the given url and returns the changed url 27609 * @param {String} url the url to which the parameter will be added 27610 * @param {String} name the name of the parameter 27611 * @param {String} value the value of the parameter 27612 */ 27613 appendParamToURL: function (url, name, value) { 27614 // quit if the param already exists 27615 if (url.indexOf(name + '=') !== -1) { 27616 return url; 27617 } 27618 var separator = url.indexOf('?') !== -1 ? '&' : '?'; 27619 var anchor = ''; 27620 if (url.indexOf('#') > -1) { 27621 var urlAndAnchor = url.split('#'); 27622 url = urlAndAnchor[0]; 27623 anchor = '#' + urlAndAnchor[1]; 27624 } 27625 return url + separator + name + (value ? '=' + encodeURIComponent(value) : '') + anchor; 27626 }, 27627 27628 /** 27629 * @function 27630 * @description remove the parameter and its value from the given url and returns the changed url 27631 * @param {String} url the url from which the parameter will be removed 27632 * @param {String} name the name of parameter that will be removed from url 27633 */ 27634 removeParamFromURL: function (url, name) { 27635 if (url.indexOf('?') === -1 || url.indexOf(name + '=') === -1) { 27636 return url; 27637 } 27638 var hash; 27639 var params; 27640 var domain = url.split('?')[0]; 27641 var paramUrl = url.split('?')[1]; 27642 var newParams = []; 27643 // if there is a hash at the end, store the hash 27644 if (paramUrl.indexOf('#') > -1) { 27645 hash = paramUrl.split('#')[1] || ''; 27646 paramUrl = paramUrl.split('#')[0]; 27647 } 27648 params = paramUrl.split('&'); 27649 for (var i = 0; i < params.length; i++) { 27650 // put back param to newParams array if it is not the one to be removed 27651 if (params[i].split('=')[0] !== name) { 27652 newParams.push(params[i]); 27653 } 27654 } 27655 var finalUrl = domain; 27656 if (newParams.length > 0) { 27657 finalUrl += '?' + newParams.join('&'); 27658 } 27659 if (hash) { 27660 finalUrl += '#' + hash; 27661 } 27662 return finalUrl; 27663 }, 27664 27665 /** 27666 * @function 27667 * @description appends the parameters to the given url and returns the changed url 27668 * @param {String} url the url to which the parameters will be added 27669 * @param {Object} params 27670 */ 27671 appendParamsToUrl: function (url, params) { 27672 var _url = url; 27673 _.each(params, function (value, name) { 27674 _url = this.appendParamToURL(_url, name, value); 27675 }.bind(this)); 27676 return _url; 27677 }, 27678 /** 27679 * @function 27680 * @description extract the query string from URL 27681 * @param {String} url the url to extra query string from 27682 **/ 27683 getQueryString: function (url) { 27684 var qs; 27685 if (!_.isString(url)) { return; } 27686 var a = document.createElement('a'); 27687 a.href = url; 27688 if (a.search) { 27689 qs = a.search.substr(1); // remove the leading ? 27690 } 27691 return qs; 27692 }, 27693 /** 27694 * @function 27695 * @description 27696 * @param {String} 27697 * @param {String} 27698 */ 27699 elementInViewport: function (el, offsetToTop) { 27700 var top = el.offsetTop, 27701 left = el.offsetLeft, 27702 width = el.offsetWidth, 27703 height = el.offsetHeight; 27704 27705 while (el.offsetParent) { 27706 el = el.offsetParent; 27707 top += el.offsetTop; 27708 left += el.offsetLeft; 27709 } 27710 27711 if (typeof(offsetToTop) !== 'undefined') { 27712 top -= offsetToTop; 27713 } 27714 27715 if (window.pageXOffset !== null) { 27716 return ( 27717 top < (window.pageYOffset + window.innerHeight) && 27718 left < (window.pageXOffset + window.innerWidth) && 27719 (top + height) > window.pageYOffset && 27720 (left + width) > window.pageXOffset 27721 ); 27722 } 27723 27724 if (document.compatMode === 'CSS1Compat') { 27725 return ( 27726 top < (window.document.documentElement.scrollTop + window.document.documentElement.clientHeight) && 27727 left < (window.document.documentElement.scrollLeft + window.document.documentElement.clientWidth) && 27728 (top + height) > window.document.documentElement.scrollTop && 27729 (left + width) > window.document.documentElement.scrollLeft 27730 ); 27731 } 27732 }, 27733 27734 /** 27735 * @function
27736 * @description Appends the parameter 'format=ajax' to a given path 27737 * @param {String} path the relative path 27738 */ 27739 ajaxUrl: function (path) { 27740 return this.appendParamToURL(path, 'format', 'ajax'); 27741 }, 27742 27743 /** 27744 * @function 27745 * @description 27746 * @param {String} url 27747 */ 27748 toAbsoluteUrl: function (url) { 27749 if (url.indexOf('http') !== 0 && url.charAt(0) !== '/') { 27750 url = '/' + url; 27751 } 27752 return url; 27753 }, 27754 /** 27755 * @function 27756 * @description Loads css dynamically from given urls 27757 * @param {Array} urls Array of urls from which css will be dynamically loaded. 27758 */ 27759 loadDynamicCss: function (urls) { 27760 var i, len = urls.length; 27761 for (i = 0; i < len; i++) { 27762 this.loadedCssFiles.push(this.loadCssFile(urls[i])); 27763 } 27764 }, 27765 27766 /** 27767 * @function 27768 * @description Loads css file dynamically from given url 27769 * @param {String} url The url from which css file will be dynamically loaded. 27770 */ 27771 loadCssFile: function (url) { 27772 return $('<link/>').appendTo($('head')).attr({ 27773 type: 'text/css', 27774 rel: 'stylesheet' 27775 }).attr('href', url); // for i.e. <9, href must be added after link has been appended to head 27776 }, 27777 // array to keep track of the dynamically loaded CSS files 27778 loadedCssFiles: [], 27779 27780 /** 27781 * @function 27782 * @description Removes all css files which were dynamically loaded 27783 */ 27784 clearDynamicCss: function () { 27785 var i = this.loadedCssFiles.length; 27786 while (0 > i--) { 27787 $(this.loadedCssFiles[i]).remove(); 27788 } 27789 this.loadedCssFiles = []; 27790 }, 27791 /** 27792 * @function 27793 * @description Extracts all parameters from a given query string into an object 27794 * @param {String} qs The query string from which the parameters will be extracted 27795 */ 27796 getQueryStringParams: function (qs) { 27797 if (!qs || qs.length === 0) { return {}; } 27798 var params = {}, 27799 unescapedQS = unescape(qs); 27800 // Use the String::replace method to iterate over each 27801 // name-value pair in the string. 27802 unescapedQS.replace(new RegExp('([^?=&]+)(=([^&]*))?', 'g'), 27803 function ($0, $1, $2, $3) { 27804 params[$1] = $3; 27805 } 27806 ); 27807 return params; 27808 }, 27809 27810 fillAddressFields: function (address, $form) { 27811 for (var field in address) { 27812 if (field === 'UUID' || field === 'key') { 27813 continue; 27814 } 27815 // if the key in address object ends with 'Code', remove that suffix 27816 // keys that ends with 'Code' are postalCode, stateCode and countryCode 27817 // update the state fields 27818 if (field === 'countryCode') { 27819 $form.find('[name$="country"]').val(address['countryCode'].toUpperCase()).trigger('change'); 27820 // retrigger state selection after country has changed 27821 // this results in duplication of the state code, but is a
27821necessary evil 27822 // for now because sometimes countryCode comes after stateCode 27823 27824 var selectedStateValue = address['stateCode']; 27825 if ($form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').length > 0) { 27826 selectedStateValue = $form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').val(); 27827 } 27828 27829 $form.find('[name$="state"]').val(selectedStateValue); 27830 } else if (field === 'stateCode') { 27831 var selectedStateValue = address['stateCode']; 27832 if ($form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').length > 0) { 27833 selectedStateValue = $form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').val(); 27834 } 27835 27836 $form.find('[name$="state"]').val(selectedStateValue); 27837 } else { 27838 if (address[field] != null) { 27839 $form.find('[name$="_' + field.replace('Code', '') + '"]').val((''+address[field]).replace(/\^/gi,"'")); 27840 } else { 27841 $form.find('[name$="_' + field.replace('Code', '') + '"]').val(address[field]); 27842 } 27843 } 27844 } 27845 }, 27846 /** 27847 * @function 27848 * @description Updates the number of the remaining character 27849 * based on the character limit in a text area 27850 */ 27851 limitCharacters: function () { 27852 $('form').find('textarea[data-character-limit]').each(function () { 27853 var characterLimit = $(this).data('character-limit'); 27854 var charCountHtml = String.format(Resources.CHAR_LIMIT_MSG, 27855 '<span class="char-remain-count">' + characterLimit + '</span>', 27856 '<span class="char-allowed-count">' + characterLimit + '</span>'); 27857 var charCountContainer = $(this).next('div.char-count'); 27858 if (charCountContainer.length === 0) {
27859 charCountContainer = $('<div class="char-count"/>').insertAfter($(this)); 27860 } 27861 charCountContainer.html(charCountHtml); 27862 // trigger the keydown event so that any existing character data is calculated 27863 $(this).change(); 27864 }); 27865 }, 27866 /** 27867 * @function 27868 * @description Binds the onclick-event to a delete button on a given container, 27869 * which opens a confirmation box with a given message 27870 * @param {String} container The name of element to which the function will be bind 27871 * @param {String} message The message the will be shown upon a click 27872 */ 27873 setDeleteConfirmation: function (container, message) { 27874 $(container).on('click', '.delete', function () { 27875 return window.confirm(message); 27876 }); 27877 }, 27878 /** 27879 * @function 27880 * @description Scrolls a browser window to a given x point 27881 * @param {String} The x coordinate 27882 */ 27883 scrollBrowser: function (xLocation) { 27884 $('html, body').animate({scrollTop: xLocation}, 500); 27885 }, 27886 27887 isTouchDevice: function() { 27888 //detect touch-ability (maxTouchPoints for windows surface) 27889 return ('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints > 0); 27890 }, 27891 27892 isMobile: function () { 27893 var mobileAgentHash = ['mobile', 'tablet', 'phone', 'ipad', 'ipod', 'android', 'blackberry', 'windows ce', 'opera mini', 'palm']; 27894 var idx = 0; 27895 var isMobile = false; 27896 var userAgent = (navigator.userAgent).toLowerCase(); 27897 27898 while (mobileAgentHash[idx] && !isMobile) { 27899 isMobile = (userAgent.indexOf(mobileAgentHash[idx]) >= 0); 27900 idx++; 27901 } 27902 return isMobile; 27903 }, 27904 27905 /** 27906 * @function 27907 * @description Validates e-mail address 27908 * @param {String} E-mail address 27909 * @returns {Boolean} 27910 */ 27911 validateEmail: function (email) { 27912 var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 27913 return re.test(email); 27914 }, 27915 27916 /** 27917 * @function 27918 * @description Helper method to encode inputs and prevent xss 27919 * @param {String} input value 27920 * @returns {String} 27921 */ 27922 htmlEncode: function (value) { 27923 if (value) { 27924 return jQuery('<div/>').text(value).html(); 27925 } else { 27926 return ''; 27927 } 27928 }, 27929 27930 /** 27931 * Limits a text input to a defined length. 27932 * @param (String) inputSelector - A jQuery selector for the input to limit. 27933 * @param (Number) lengthLimit - The length to limit the input to. 27934 * @return void 27935 */ 27936 limitInputToLength: function (inputSelector, lengthLimit) { 27937 $(inputSelector).on("keyup click", function () { 27938 if (this.value.length > lengthLimit) { 27939 this.value = this.value.substring(0, lengthLimit); 27940 } 27941 }); 27942 }, 27943 27944 /** 27945 * Detects the credit card type based off of the provided credit card number. 27946 * @param (String) creditCardNumber - The credit card number to detect the type for. 27947 * @return (String) - The type of credit card. 27948 */ 27949 getCreditCardType: function (creditCardNumber) { 27950 creditCardNumber = creditCardNumber.replace(/\D/g, ''); 27951 27952 if (creditCardNumber.length >= 4) { 27953 var creditCardTypes = [ 27954 { 27955 PaymentCard: CreditCardConstants.Visa, 27956 PaymentCardDisplayKey: CreditCardConstants.Visa, 27957 PaymentMethod: PaymentMethodConstants.CreditCard, 27958 Pattern: new RegExp('^4[0-9]{0,}$') 27959 }, 27960 { 27961 PaymentCard: CreditCardConstants.AmericanExpress, 27962 PaymentCardDisplayKey: CreditCardConstants.AmericanExpress, 27963 PaymentMethod: PaymentMethodConstants.CreditCard, 27964 Pattern: new RegExp('^3[47][0-9]{0,}$') 27965 }, 27966 { 27967 PaymentCard: CreditCardConstants.Diners, 27968 PaymentCardDisplayKey: CreditCardConstants.Discover, 27969 PaymentMethod: PaymentMethodConstants.CreditCard, 27970 Pattern: new RegExp('^3(?:0[0-59]{1}|[689])[0-9]{0,}$') 27971 }, 27972 { 27973 PaymentCard: CreditCardConstants.JCB, 27974 PaymentCardDisplayKey: CreditCardConstants.JCB, 27975 PaymentMethod: PaymentMethodConstants.CreditCard, 27976 Pattern: new RegExp('^(?:2131|1800|35)[0-9]{0,}$') 27977 }, 27978 { 27979 PaymentCard: CreditCardConstants.Mastercard, 27980 PaymentCardDisplayKey: CreditCardConstants.Mastercard, 27981 PaymentMethod: PaymentMethodConstants.CreditCard,
27982 Pattern: new RegExp('^(5[1-5])[0-9]{0,}$') 27983 }, 27984 { 27985 PaymentCard: CreditCardConstants.MastercardSeries2, 27986 PaymentCardDisplayKey: CreditCardConstants.Mastercard, 27987 PaymentMethod: PaymentMethodConstants.CreditCard, 27988 Pattern: new RegExp('^(222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$') 27989 }, 27990 { 27991 PaymentCard: CreditCardConstants.Discover, 27992 PaymentCardDisplayKey: CreditCardConstants.Discover, 27993 PaymentMethod: PaymentMethodConstants.CreditCard, 27994 Pattern: new RegExp('^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$') 27995 }, 27996 { 27997 PaymentCard: CreditCardConstants.Maestro, 27998 PaymentCardDisplayKey: CreditCardConstants.Mastercard, 27999 PaymentMethod: PaymentMethodConstants.CreditCard, 28000 Pattern: new RegExp('^(5[06789]|6)[0-9]{0,}$') 28001 }, 28002 { 28003 PaymentCard: CreditCardConstants.BootBarnCredit, 28004 PaymentCardDisplayKey: PaymentMethodConstants.AllianceData, 28005 PaymentMethod: PaymentMethodConstants.AllianceData, 28006 Pattern: new RegExp('^7788[0-9]{0,}$') 28007 } 28008 ] 28009 28010 for (var creditCardTypeKey in creditCardTypes) { 28011 var creditCardType = creditCardTypes[creditCardTypeKey]; 28012 28013 if (creditCardType.Pattern && creditCardNumber.match(creditCardType.Pattern)) { 28014 return creditCardType; 28015 } 28016 } 28017 } 28018 28019 return false; 28020 }, 28021 28022 /** 28023 * Masks a provided number. 28024 * @param (Number or String) number - The number to mask. 28025 * @param (Number) lengthToShow - The length of the number to leave unmasked at end. 28026 * @param (String) maskCharacter - The character to use for masking. Defaults to *. 28027 * @return (String) - The type of credit card. 28028 */ 28029 getMaskedNumber: function (number, lengthToShow, maskPattern) { 28030 if (!number) { 28031 return ''; 28032 } 28033 28034 lengthToShow = lengthToShow || 4; 28035 maskPattern = maskPattern || '*'; 28036 28037 var numberMasked; 28038 if (maskPattern.length > 1) { 28039 numberMasked = maskPattern; 28040 } else if (maskPattern.length >= 1) { 28041 numberMasked = new Array(number.length + 1).join(maskPattern); 28042 } 28043 28044 number += ''; 28045 if (number != null && number != '') { 28046 numberMasked = numberMasked.substr(0, number.length - lengthToShow); 28047 numberMasked += number.substr(number.length - lengthToShow); 28048 } 28049 28050 return numberMasked; 28051 }, 28052 28053 getPreferenceValueFromWindowLocation: function (preferenceName) { 28054 var hash = window.location.hash.substr(1), 28055 preferenceValue = '', 28056 hashTable = hash.split('&').reduce(function (hashTable, item) { 28057 var parts = item.split('='); 28058 hashTable[parts[0]] = decodeURIComponent(parts[1]).replace(/[\+\s]+/g, ' '); 28059 return hashTable; 28060 }, {}); 28061 28062 for (var i = 1; i <= 5; i++){ 28063 if(!hashTable.hasOwnProperty('prefn' + i)){ 28064 break; 28065 } else if(hashTable['prefn' + i] == preferenceName){ 28066 preferenceValue = hashTable['prefv' + i]; 28067 break; 28068 } 28069 } 28070 28071 return preferenceValue; 28072 } 28073}; 28074 28075module.exports = util; 28076 28077},{"../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants":117,"lodash":133}],103:[function(require,module,exports){ 28078'use strict'; 28079 28080var naPhone = /^\+?\(?([0-9][0-8][0-9])\)?[\-\. ]?([2-9][0-9]{2})[\-\. ]?([0-9]{4})(\s*x[0-9]+)?$/; 28081var internationalNumber = /^(?:\s*\+)?[\d\s\.\-\(\)]+$/; 28082var defaultPostal = /^\d{3,7}$/; 28083var regex = { 28084 phone: { 28085 us: naPhone, 28086 ca: internationalNumber, 28087 fr: internationalNumber, 28088 it: internationalNumber, 28089 jp: internationalNumber, 28090 cn: /.*/, 28091 gb: internationalNumber 28092 }, 28093 postal: { 28094 us: /^\d{5}(-\d{4})?$/, 28095 ca: /^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$/i, 28096 fr: /^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$/, 28097 it: /^([0-9]){5}$/, 28098 jp: /^([0-9]){3}[-]([0-9]){4}$/, 28099 cn: /^([0-9]){6}$/, 28100 gb: /^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$/i 28101 }, 28102 notCC: /^(?!(([0-9 -]){13,19})).*$/ 28103}; 28104// global form validator settings 28105var settings = { 28106 errorClass: 'error', 28107 errorElement: 'span', 28108 onkeyup: false, 28109 onfocusout: function (element) { 28110 if (!this.checkable(element)) {
28111 this.element(element); 28112 } 28113 }, 28114 errorPlacement: function (error, element) { 28115 if (element.attr('error-container')) { 28116 error.appendTo($(element.attr('error-container'))); 28117 } else { 28118 error.appendTo(element.parent()); 28119 } 28120 } 28121}; 28122/** 28123 * @function 28124 * @description Validates a given phone number against the countries phone regex 28125 * @param {String} value The phone number which will be validated 28126 * @param {String} el The input field 28127 */ 28128var validatePhone = function (value, el) { 28129 var country = $(el).closest('form').find('.country'); 28130 var countryValue; 28131 if (country.length > 0) { 28132 countryValue = country.val(); 28133 } 28134 28135 if (!countryValue || !regex.phone[country.val().toLowerCase()]) { 28136 return true; 28137 } 28138 28139 var rgx = regex.phone[country.val().toLowerCase()]; 28140 var isOptional = this.optional(el); 28141 var isValid = rgx.test($.trim(value)); 28142 28143 return isOptional || isValid; 28144}; 28145 28146var validatePostal = function (value, el) { 28147 var country = $(el).closest('form').find('.country'); 28148 var countryValue; 28149 if (country.length > 0) { 28150 countryValue = country.val(); 28151 } 28152 28153 if (!countryValue || !regex.postal[country.val().toLowerCase()]) { 28154 return true; 28155 } 28156 28157 var rgx = regex.postal[countryValue.toLowerCase()]; 28158 var isOptional = this.optional(el); 28159 var isValid = rgx.test($.trim(value)); 28160 28161 return isOptional || isValid; 28162}; 28163/** 28164 * @function 28165 * @description Validates that a credit card owner is not a Credit card number 28166 * @param {String} value The owner field which will be validated 28167 * @param {String} el The input field 28168 */ 28169var validateOwner = function (value) { 28170 var isValid = regex.notCC.test($.trim(value)); 28171 return isValid; 28172}; 28173 28174/** 28175 * Add phone validation method to jQuery validation plugin. 28176 * Text fields must have 'phone' css class to be validated as phone 28177 */ 28178$.validator.addMethod('phone', validatePhone, Resources.INVALID_PHONE); 28179$.validator.addMethod('postal', validatePostal, Resources.INVALID_ZIP); 28180 28181/** 28182 * Add CCOwner validation method to jQuery validation plugin. 28183 * Text fields must have 'owner' css class to be validated as not a credit card 28184 */ 28185$.validator.addMethod('owner', validateOwner, Resources.INVALID_OWNER); 28186 28187/** 28188 * Add gift cert amount validation method to jQuery validation plugin. 28189 * Text fields must have 'gift-cert-amont' css class to be validated 28190 */ 28191$.validator.addMethod('gift-cert-amount', function (value, el) { 28192 var isOptional = this.optional(el); 28193 var isValid = (!isNaN(value)) && (parseFloat(value) >= 5) && (parseFloat(value) <= 5000); 28194 return isOptional || isValid; 28195}, Resources.GIFT_CERT_AMOUNT_INVALID); 28196 28197/** 28198 * Add positive number validation method to jQuery validation plugin. 28199 * Text fields must have 'positivenumber' css class to be validated as positivenumber 28200 */ 28201$.validator.addMethod('positivenumber', function (value) { 28202 if ($.trim(value).length === 0) { return true; } 28203 return (!isNaN(value) && Number(value) >= 0); 28204}, Resources.VALIDATE_NUMBER); 28205 28206/** 28207 * Add method to check for email extension when validating emails, 28208 * since default settings don't require an extension 28209 */ 28210$.validator.addMethod("requireEmailExtension", function(value, element) { 28211 if ($.trim(value).length === 0) { return true; } 28212 return /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value); 28213}, Resources.VALIDATE_EMAIL); 28214 28215/* 28216 * Lets you say "at least X inputs that match selector Y must be filled." 28217 * 28218 * The end result is that neither of these inputs: 28219 * 28220 * <input class="productinfo" name="partnumber"> 28221 * <input class="productinfo" name="description"> 28222 * 28223 * ...will validate unless at least one of them is filled. 28224 * 28225 * partnumber: {require_from_group: [1,".productinfo"]}, 28226 * description: {require_from_group: [1,".productinfo"]} 28227 * 28228 * options[0]: number of fields that must be filled in the group 28229 * options[1]: CSS selector that defines the group of conditionally required fields 28230 */ 28231$.validator.addMethod( "require_from_group", function( value, element, options ) { 28232 var $fields = $(options[1], element.form); 28233 var $fieldsFirst = $fields.eq(0);
28234 var validator = $fieldsFirst.data("valid_req_grp") ? $fieldsFirst.data("valid_req_grp") : $.extend({}, this); 28235 var isValid = $fields.filter(function() { 28236 return validator.elementValue(this); 28237 }).length >= options[0]; 28238 28239 // Store the cloned validator for future validation 28240 $fieldsFirst.data("valid_req_grp", validator); 28241 28242 // If element isn't being validated, run each require_from_group field's validation rules 28243 if (!$(element).data("being_validated")) { 28244 $fields.data("being_validated", true); 28245 $fields.each(function() { 28246 validator.element(this); 28247 }); 28248 $fields.data("being_validated", false); 28249 } 28250 return isValid; 28251}, $.validator.format("Please fill at least {0} of these fields.")); 28252 28253$.extend($.validator.messages, { 28254 required: Resources.VALIDATE_REQUIRED, 28255 remote: Resources.VALIDATE_REMOTE, 28256 email: Resources.VALIDATE_EMAIL, 28257 url: Resources.VALIDATE_URL, 28258 date: Resources.VALIDATE_DATE, 28259 dateISO: Resources.VALIDATE_DATEISO, 28260 number: Resources.VALIDATE_NUMBER, 28261 digits: Resources.VALIDATE_DIGITS, 28262 creditcard: Resources.VALIDATE_CREDITCARD, 28263 equalTo: Resources.VALIDATE_EQUALTO, 28264 maxlength: $.validator.format(Resources.VALIDATE_MAXLENGTH), 28265 minlength: $.validator.format(Resources.VALIDATE_MINLENGTH), 28266 rangelength: $.validator.format(Resources.VALIDATE_RANGELENGTH), 28267 range: $.validator.format(Resources.VALIDATE_RANGE), 28268 max: $.validator.format(Resources.VALIDATE_MAX), 28269 min: $.validator.format(Resources.VALIDATE_MIN) 28270}); 28271 28272var validator = { 28273 regex: regex, 28274 settings: settings, 28275 init: function () { 28276 var self = this; 28277 $('form:not(.suppress)').each(function () { 28278 $(this).validate(self.settings); 28279 }); 28280 }, 28281 initForm: function (f) { 28282 $(f).validate(this.settings); 28283 } 28284}; 28285 28286module.exports = validator; 28287 28288},{}],104:[function(require,module,exports){ 28289/* 28290 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 28291 * watermark.js - Create watermarked images with Canvas and JS 28292 * 28293 * Version: 1 (2011-04-04) 28294 * Copyright (c) 2011 Patrick Wied ( http://www.patrick-wied.at ) 28295 * This code is licensed under the terms of the MIT LICENSE 28296 * 28297 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 28298 */ 28299 28300module.exports = function(w){ 28301 var w = window; 28302 var wm = (function(w){ 28303 var doc = w.document, 28304 gcanvas = {}, 28305 gctx = {}, 28306 imgQueue = [], 28307 classNames = ["watermark"], 28308 watermark = false, 28309 watermarkPosition = "bottom-right", 28310 watermarkPath = "watermark.png?"+(+(new Date())), 28311 opacity = (255/(100/50)), // 50% 28312 initCanvas = function(){ 28313 gcanvas = doc.createElement("canvas"); 28314 gcanvas.style.cssText = "display:none;"; 28315 gctx = gcanvas.getContext("2d"); 28316 doc.body.appendChild(gcanvas); 28317 }, 28318 initWatermark = function(){ 28319 watermark = new Image(); 28320 watermark.src = ""; 28321 watermark.src = watermarkPath; 28322 28323 if(opacity != 255){ 28324 if(!watermark.complete) 28325 watermark.onload = function(){ 28326 applyTransparency(); 28327 } 28328 else 28329 applyTransparency(); 28330 28331 28332 }else{ 28333 applyWatermarks(); 28334 } 28335 28336 }, 28337 // function for applying transparency to the watermark 28338 applyTransparency = function(){ 28339 var w = watermark.width || watermark.offsetWidth, 28340 h = watermark.height || watermark.offsetHeight; 28341 setCanvasSize(w, h); 28342 gctx.drawImage(watermark, 0, 0); 28343 28344 var image = gctx.getImageData(0, 0, w, h); 28345 var imageData = image.data, 28346 length = imageData.length; 28347 for(var i=3; i < length; i+=4){ 28348 imageData[i] = (imageData[i]<opacity)?imageData[i]:opacity; 28349 } 28350 image.data = imageData; 28351 gctx.putImageData(image, 0, 0); 28352 watermark.onload = null; 28353 watermark.src = ""; 28354 watermark.src = gcanvas.toDataURL(); 28355 // assign img attributes to the transparent watermark 28356 // because browsers recalculation doesn't work as fast as needed 28357 watermark.width = w; 28358 watermark.height = h; 28359 28360 applyWatermarks(); 28361 }, 28362 configure = function(config){ 28363 if(config["watermark"]) 28364 watermark = config["watermark"]; 28365 if(config["path"]) 28366 watermarkPath = config["path"]; 28367 if(config["position"]) 28368 watermarkPosition = config["position"]; 28369 if(config["opacity"]) 28370 opacity = (255/(100/config["opacity"])); 28371 if(config["classNames"]) 28372 classNames = config["classNames"]; 28373 28374 initCanvas(); 28375 initWatermark(); 28376 } 28377 setCanvasSize = function(w, h){ 28378 gcanvas.width = w; 28379 gcanvas.height = h; 28380 }, 28381 applyWatermark = function(img){
28382 gcanvas.width = img.naturalWidth || img.width || img.offsetWidth; 28383 gcanvas.height = img.naturalHeight || img.height || img.offsetHeight; 28384 gctx.drawImage(img, 0, 0); 28385 var position = watermarkPosition, 28386 x = 0, 28387 y = 0; 28388 if(position.indexOf("top")!=-1) 28389 y = 10; 28390 else if(position.indexOf("middle")!=-1) 28391 y = (gcanvas.height-watermark.height) / 2; 28392 else 28393 y = gcanvas.height-watermark.height-10; 28394 28395 if(position.indexOf("left")!=-1) 28396 x = 10; 28397 else if(position.indexOf("center")!=-1) 28398 x = (gcanvas.width-watermark.width) / 2; 28399 else 28400 x = gcanvas.width-watermark.width-10; 28401 28402 28403 gctx.drawImage(watermark, x, y); 28404 img.onload = null; 28405 28406 img.src = gcanvas.toDataURL(); 28407 28408 }, 28409 applyWatermarks = function(){ 28410 setTimeout(function(){ 28411 for(var i = 0; i < classNames.length; i++){ 28412 var els = doc.getElementsByClassName(classNames[i]), 28413 len = els.length; 28414 while(len--){ 28415 var img = els[len]; 28416 if(img.tagName.toUpperCase() != "IMG" || (img.tagName.toUpperCase() == "IMG" && img.getAttribute('src').indexOf('data:image/png') > -1) || img.naturalWidth == 0) 28417 continue; 28418 28419 if(!img.complete){ 28420 img.onload = function(){ 28421 applyWatermark(this); 28422 }; 28423 }else{ 28424 applyWatermark(img); 28425 } 28426 } 28427 } 28428 },10); 28429 }; 28430 28431 28432 return { 28433 init: function(config){ 28434 configure(config); 28435 } 28436 }; 28437 })(w); 28438 w.wmark = wm; 28439}; 28440},{}],105:[function(require,module,exports){ 28441'use strict'; 28442 28443var dialog = require('./dialog'); 28444var progress = require('./progress'); 28445var loginDialog = require('./loginDialog'); 28446 28447/* ------------------------- 28448 * WISHLIST 28449 * ------------------------- 28450 */ 28451 28452function errorHandling(data, dialogTitle, dialogHtml) { 28453 if (data && typeof data === 'object' && 'message' in data) { 28454 console.log(data.message); 28455 } 28456 dialog.open({ 28457 html: dialogHtml, 28458 options: { 28459 title: dialogTitle, 28460 draggable: false, 28461 open: function(event, ui) { 28462 $('body').addClass('dialog-open'); 28463 }, 28464 close: function(event, ui) { 28465 $('body').removeClass('dialog-open'); 28466 } 28467 } 28468 }); 28469} 28470 28471function updateCSRFToken() { 28472 if (pageContext && pageContext.options) { 28473 $.ajax({ 28474 method: 'get', 28475 url: Urls.CSRFToken.Get, 28476 dataType: 'json', 28477 success: function(response) { 28478 pageContext.options.Token = response.token; 28479 } 28480 }); 28481 } 28482} 28483 28484function checkWishlistForItem(wishlistItemId) { 28485 if ('localStorage' in window && window['localStorage'] !== null && 'WishlistProductIDs' in window.localStorage && window.localStorage.WishlistProductIDs.length > 0) { 28486 var wishlistItems = JSON.parse(window.localStorage.WishlistProductIDs); 28487 var pageType = pageContext && 'type' in pageContext && pageContext.type ? pageContext.type : $('#wrapper').attr('class'); 28488 var isWishlistItem = wishlistItems.filter(function(productObject) { 28489 if (productObject.productID == wishlistItemId) { return true } 28490 // If this is NOT a PDP, then we need to run additional checks to see if Master Product or any of the Variations are in the wishlist 28491 if (pageType != 'product') { 28492 if (productObject.masterID == wishlistItemId) { return true } 28493 if (productObject.variants.indexOf(wishlistItemId) > -1) { return true } 28494 } 28495 }); 28496 return isWishlistItem.length > 0; 28497 } else { 28498 return false; 28499 } 28500} 28501 28502function modifyWishlistInStorage(data) { 28503 if ('localStorage' in window && window['localStorage'] !== null) { 28504 if (!window.localStorage.WishlistProductIDs) { 28505 window.localStorage.WishlistProductIDs = '[]'; 28506 } 28507 var item = 'productData' in data && data.productData.productID ? data.productData.productID : null; 28508 var isDataAction = data.action; 28509 var wishlistItems = JSON.parse(window.localStorage.WishlistProductIDs); 28510 28511 if (item && isDataAction) { 28512 if (isDataAction == 'wishlistItemAdded') { 28513 wishlistItems.push(data.productData); 28514 window.localStorage.WishlistProductIDs = JSON.stringify(wishlistItems); 28515 } 28516 if (isDataAction == 'wishlistItemRemoved' && wishlistItems.length > 0) { 28517 var modifiedWishlist = wishlistItems.filter(function(productObject) { 28518 if (productObject.productID != item) { return true } 28519 }); 28520 window.localStorage.WishlistProductIDs = JSON.stringify(modifiedWishlist); 28521 } 28522 } 28523 } 28524} 28525 28526function addWishlistEvent(event, productID) {
28527 var eventType = "wishlist_" + event; 28528 var url, image; 28529 var images = []; 28530 28531 var thisTile = $('.product-tile[data-itemid="'+productID+'"]'); 28532 var thisItem = JSON.parse($('.productCardMetadata.event-browse[data-pid="'+productID+'"]').attr('data-product-gtm-json')); 28533 if (thisTile.length > 0) { 28534 url = thisTile.find('.thumb-link').attr('href'); 28535 image = thisTile.find('.thumb-link img').attr('src'); 28536 images.push(image); 28537 } else { 28538 var selectedSizeOption = $('div.product-variations .size.size-options li.selected .swatchanchor'); 28539 var selectedSizeUrl = selectedSizeOption.attr('href').replace('Product-Variation', 'Product-Show'); 28540 var selectedSizeValue = selectedSizeOption.attr('data-size-id').replace(/ /g, '%20'); 28541 url = selectedSizeUrl.replace("_size=", "_size="+selectedSizeValue); 28542 $('.product-primary-image [class*="-slide"]').not('.slick-cloned').each(function (index) { 28543 if(index > -1) { 28544 var image = $(this).find('a').attr('href'); 28545 if (!image || image == undefined || image == null) { 28546 image = $(this).find('img').attr('src'); 28547 } 28548 if (images.indexOf(image) === -1) { 28549 images.push(image); 28550 } 28551 } 28552 }); 28553 } 28554 28555 var properties = { 28556 "productID": thisItem["id"], 28557 "productName": thisItem["name"].replace(/\\/g, ""), 28558 "category": thisItem["category"].replace(/\\/g, ""), 28559 "price": thisItem["price"], 28560 "images": images, 28561 "url": url, 28562 "attr": { 28563 "manufacturer": thisItem["brand"] 28564 }, 28565 }; 28566 28567 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 28568 crdl('event', eventType, properties); 28569 } 28570} 28571 28572function prepareWishlistAddUI(buttons, wishlistItemId, sizeText) { 28573 if (!buttons) { 28574 return; 28575 } else { 28576 buttons.each(function(idx, element) { 28577 var $button = $(element); 28578 var addUrl = Urls.wishlistAdd + '?pid=' + $button.attr('data-pid'); 28579 $button.removeClass('wishlist-item-added').addClass('wishlist-item-ready'); 28580 $button.css('display', 'inline-block'); 28581 $button.attr('data-url', addUrl); 28582 $button.attr('data-action', 'AddInternal'); 28583 $button.attr('title', ($button.attr('data-title-add') + ' - ' + sizeText)); 28584 if ($button.attr('id') == 'wishlist-button') { 28585 $button.find('span').html($button.attr('data-add-message')); 28586 } 28587 }); 28588 } 28589 28590 if ($('.pt_wish-list').length > 0 && (wishlistItemId)) { 28591 if ('localStorage' in window && window['localStorage'] !== null && 'WishlistProductIDs' in window.localStorage && window.localStorage.WishlistProductIDs.length > 0) { 28592 var wishlistItems = JSON.parse(window.localStorage.WishlistProductIDs); 28593 var variationModel = wishlistItems.filter(function(productObject) { 28594 if (productObject.productID == wishlistItemId || productObject.masterID == wishlistItemId || productObject.variants.indexOf(wishlistItemId) > -1) { 28595 return productObject; 28596 } 28597 }); 28598 if (variationModel.length) { 28599 var wishlistItemsToRemove = variationModel[0]; 28600 for (var key in wishlistItemsToRemove) { 28601 var value = wishlistItemsToRemove[key]; 28602 // If matching variant or master 28603 if (key == 'productID' || key == 'masterID') { 28604 $('.product-tile[data-itemid="'+value+'"]').parents('li.wishlist-item').remove(); 28605 // Else, check the other variants 28606 } else { 28607 var variants = value.split(','); 28608 var i = 0; 28609 while (i < variants.length) { 28610 var variantID = variants[i]; 28611 $('.product-tile[data-itemid="'+variantID+'"]').parents('li.wishlist-item').remove(); 28612 i++; 28613 } 28614 } 28615 } 28616 // If user removes all shareable products from wishlist, then hide the share toggle and set the wishlist to private 28617 if ($('li.wishlist-item[data-shareable-item="true"]').length < 1) { 28618 $('.wishlist-share-container').hide(); 28619 $('.share-wishlist-toggle input[name="share-wishlist-checkbox"]').prop('checked', false).trigger('change'); 28620 } 28621 if ($('li.wishlist-item').length < 1) { 28622 $('.wishlist-message.empty-wishlist').removeClass('d-none'); 28623 } 28624 } 28625 } 28626 } 28627} 28628 28629function prepareWishlistRemoveUI(buttons, sizeText) { 28630 if (!buttons) { 28631 return; 28632 } else { 28633 buttons.each(function(idx, element) { 28634 var $button = $(element); 28635 var removeUrl = Urls.wishlistRemove + '?pid=' + $button.attr('data-pid'); 28636 $button.removeClass('wishlist-item-ready').addClass('wishlist-item-added'); 28637 $button.css('display', 'inline-block'); 28638 $button.attr('data-url', removeUrl); 28639 $button.attr('data-action', 'RemoveInternal'); 28640 $button.attr('title', ($button.attr('data-title-remove') + ' - ' + sizeText)); 28641 if ($button.attr('id') == 'wishlist-button') { 28642 $button.find('span').html($button.attr('data-remove-message')); 28643 } 28644 }); 28645 } 28646} 28647 28648function renderAllWishlistButtons() { 28649 $('.wishlist-item-status-button').each(function() { 28650 var $button = $(this); 28651 var wishlistItemId = $button.attr('data-pid'); 28652 if (wishlistItemId && wishlistItemId != '') { 28653 var isWishlistItem = checkWishlistForItem(wishlistItemId); 28654 if (isWishlistItem) { 28655 prepareWishlistRemoveUI($button); 28656 } else { 28657 prepareWishlistAddUI($button, wishlistItemId); 28658 } 28659 } 28660 }); 28661} 28662 28663function validateEmailForm($email, $message) { 28664 $('.share-wishlist-menu-popup .error-container').addClass('d-none'); 28665 28666 var regexEmail = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/g; 28667 var regexMessage = /^[A-Za-z0-9 _.,!"'\/()$]*/g; 28668 var email = $email.val().trim(); 28669 var message = $message.val().trim(); 28670 var formValidation = true; 28671 28672 if ((!email || email.length == 0) || String(email).match(regexEmail) == null) { 28673 formValidation = false;
28674 $email.addClass('error'); 28675 $('#share-wishlist-email-popup .invalid-email-format').removeClass('d-none'); 28676 } 28677 if ((!message || message.length == 0) || String(message).match(regexMessage) == null) { 28678 formValidation = false; 28679 $message.addClass('error'); 28680 $('#share-wishlist-email-popup .invalid-email-message-format').removeClass('d-none'); 28681 } 28682 28683 if (!formValidation) { 28684 return false; 28685 } else { 28686 return true; 28687 } 28688} 28689 28690function wishlistPostOrder() { 28691 var orderNo = window.orderNumber; 28692 if (orderNo) { 28693 $.ajax({ 28694 type: 'POST', 28695 url: Urls.wishlistPostOrder, 28696 contentType: 'application/json', 28697 data: JSON.stringify({ 28698 orderNumber: orderNo 28699 }), 28700 error: function(jqXHR, textStatus, errorThrown) { 28701 console.log('Wishlist-PostOrder: Error in removing ordered products from wishlist. ERROR TEXT: '+textStatus+', ERROR THROWN: '+errorThrown+'.'); 28702 }, 28703 success: function(response) { 28704 if (response) { 28705 if (response.result && response.result == 'success') { 28706 if (SitePreferences.CORDIAL_ENABLED && response.removedProducts && response.removedProducts.length > 0) { 28707 $(document).trigger('CordialTagging.WishlistPostOrder', [response.removedProducts, orderNo]); 28708 } 28709 } 28710 } 28711 } 28712 }); 28713 } 28714} 28715 28716function init () { 28717 $(document).ready(function() { 28718 28719 updateCSRFToken(); 28720 28721 /** 28722 * On page load, make AJAX call to get wishlist items and store in localStorage. From localStorage, compare the items being loaded on 28723 * page to see if any are in wishlist, and mark the heart icons accordingly. 28724 */ 28725 if ('localStorage' in window && window['localStorage'] !== null) { 28726 // Only make AJAX call to get wishlist product IDs if customer is logged in 28727 if (Customer.authenticated) { 28728 $.ajax({ 28729 type: 'GET', 28730 url: Urls.wishlistGetItems, 28731 contentType: 'application/json', 28732 error: function(jqXHR, textStatus, errorThrown) { 28733 $('.wishlist-item-status-button').css('display', 'inline-block'); 28734 window.localStorage.WishlistProductIDs = ''; 28735 }, 28736 success: function(response) { 28737 if (response) { 28738 if (typeof response === 'object' && 'wishlist' in response) { 28739 window.localStorage.WishlistProductIDs = JSON.stringify(response.wishlist); 28740 renderAllWishlistButtons(); 28741 } else { 28742 $('.wishlist-item-status-button').css('display', 'inline-block'); 28743 window.localStorage.WishlistProductIDs = ''; 28744 } 28745 } 28746 } 28747 }); 28748 // If guest user, just render the wishlist buttons as empty 28749 } else { 28750 window.localStorage.WishlistProductIDs = ''; 28751 renderAllWishlistButtons(); 28752 } 28753 } 28754 28755 /** 28756 * On click of a wishlist heart button, open a login dialog (if guest user) or add/remove item from wishlist (if logged-in customer) 28757 */ 28758 $('body').on('click', '.wishlist-item-status-button, .wishlist-button', function(event) { 28759 event.preventDefault(); 28760 var $button = $(this); 28761 var wishlistUrl = $button.attr('data-url'); 28762 var wishlistController = $button.attr('data-controller'); 28763 var wishlistAction = $button.attr('data-action'); 28764 var productID = $button.attr('data-pid'); 28765 28766 var isProductPage = $('.pt_product-details').length; 28767 var continueWishlist = true; 28768 28769 if (isProductPage) { 28770 var sizeSelected = $('div.product-variations .size.size-options li.selected'); 28771 var lengthSelected = $('div.product-variations .length.length-options li.selected').length; 28772 var widthSelected = $('div.product-variations .width.width-options li.selected').length; 28773 var isSizeSelected = sizeSelected.length || (lengthSelected && widthSelected); 28774 var isColorSelected = $('div.product-variations .color.color-options li.selected').length; 28775 if (!isSizeSelected) { 28776 alert('Please select a size'); 28777 continueWishlist = false;
28778 } 28779 } 28780 28781 if (continueWishlist) { 28782 //Cordial wishlist add/remove events 28783 if ($button.hasClass('wishlist-item-added')) { 28784 addWishlistEvent('remove', productID); 28785 } else { 28786 addWishlistEvent('add', productID); 28787 } 28788 28789 // WISHLIST REPORTING: Track wishlist-item-status-button clicks (both guest and logged-in users) 28790 $.ajax({ 28791 type: 'POST', 28792 url: Urls.wishlistTrackActions, 28793 contentType: 'application/json', 28794 data: JSON.stringify({ 28795 action: wishlistAction, 28796 pid: productID 28797 }), 28798 error: function(jqXHR, textStatus, errorThrown) { 28799 console.log('Wishlist-TrackActions: Error in incrementing wishlist action counters. ERROR TEXT: '+textStatus+', ERROR THROWN: '+errorThrown+'.'); 28800 }, 28801 success: function(response) { 28802 if (response) {} 28803 } 28804 }); 28805 28806 // If guest user, open a login dialog 28807 if (!Customer.authenticated) { 28808 var params = wishlistUrl.substring(wishlistUrl.indexOf('?'), wishlistUrl.length); 28809 loginDialog.show(function() { 28810 // For reporting 28811 $('.login-dialog-forms-container [data-login-source]').attr('data-login-source', 'wishlist-modal'); 28812 }, wishlistController, wishlistAction, productID, params, wishlistUrl); 28813 // Else, if logged-in user, allow customer to add/remove wishlist item 28814 } else { 28815 $.ajax({ 28816 type: 'GET', 28817 url: wishlistUrl, 28818 contentType: 'application/json', 28819 error: function(jqXHR, textStatus, errorThrown) { 28820 errorHandling(errorThrown, 'Wishlist - Error', '<p style="padding: 10px;">There was a problem handling your request. Please try again later.</p>'); 28821 }, 28822 success: function(response) { 28823 if (response && response.result && response.result == 'success' && response.action) { 28824 modifyWishlistInStorage(response); 28825 if (response.action == 'wishlistItemRemoved') { 28826 var productIdRemoved = response && response.formattedData && response.formattedData.productID ? response.formattedData.productID : null; 28827 prepareWishlistAddUI($button, productIdRemoved); 28828 } else { 28829 prepareWishlistRemoveUI($button); 28830 } 28831 } else { 28832 var dialogHtml = '<p style="padding: 10px;">Unable to modify wishlist at this time. Please try again later.</p>'; 28833 if (response && response.action) { 28834 if (response.action == 'wishlistItemRemoved') { 28835 dialogHtml = '<p style="padding: 10px;">Unable to remove item from wishlist. Please try again later.</p>'; 28836 } else { 28837 dialogHtml = '<p style="padding: 10px;">Unable to add item to wishlist. Please try again later.</p>'; 28838 } 28839 } 28840 errorHandling(null, 'Wishlist - Error', dialogHtml); 28841 } 28842 } 28843 }); 28844 } 28845 } 28846 }); 28847 28848 /** 28849 * Add product to customer's cart when "Add to Cart" button is clicked on Wishlist page 28850 */ 28851 $('body').on('click', '.wishlist-add-to-cart-button', function() { 28852 var $button = $(this); 28853 var productId = $button.attr('data-pid'); 28854 $button.find('span').html(''); 28855 progress.show($button.find('span'), true); 28856 28857 $.ajax({ 28858 type: 'POST', 28859 url: Urls.addProduct, 28860 data: { 28861 pid: productId, 28862 csrf_token: pageContext.options.Token 28863 }, 28864 error: function(jqXHR, textStatus, errorThrown) { 28865 progress.hide(); 28866 $button.find('span').html('Add to Cart'); 28867 errorHandling(errorThrown, 'Wishlist - Error', '<p style="padding: 10px;">Unable to add item to cart. Please try again later.</p>'); 28868 }, 28869 success: function(response) { 28870 var $miniCartElm = $('.mini-cart .minicart-quantity').length > 0 ? $('.mini-cart .minicart-quantity') : $('.mini-cart .btn-minicart .btn-minicart-qty'); 28871 var miniCartTotal; 28872 if ($miniCartElm.length > 0) { 28873 miniCartTotal = parseInt($miniCartElm.html().trim()); 28874 } 28875 miniCartTotal++; 28876 $miniCartElm.html(miniCartTotal); 28877 $button.attr('disabled', true).addClass('disabled'); 28878 $button.find('span').html('<i class="fa fa-check" aria-hidden="true"></i> Item Added'); 28879 28880 // Only fire this AJAX call if the customer successfully added the product to their cart. On error of addProduct, do nothing. 28881 if (Customer.authenticated) { 28882 // WISHLIST REPORTING: Track 'Add to Cart' clicks from wishlist page 28883 $.ajax({ 28884 type: 'GET', 28885 url: Urls.wishlistTrackAddToCart, 28886 contentType: 'application/json', 28887 error: function(jqXHR, textStatus, errorThrown) { 28888 console.log('Wishlist-TrackAddToCart: Error in incrementing wishlist Add-to-Cart counter. ERROR TEXT: '+textStatus+', ERROR THROWN: '+errorThrown+'.'); 28889 }, 28890 success: function(response) { 28891 if (response) {} 28892 } 28893 }); 28894 } 28895 } 28896 }); 28897 28898 var thisItem = $('.product-tile[data-itemid="'+productId+'"]'); 28899 var itemMeta = JSON.parse($('.productCardMetadata.event-browse[data-pid="'+productId+'"]').attr('data-product-gtm-json')); 28900 var image = thisItem.find('.tile-image').attr('src'); 28901 if (!image || image == undefined || image == null) { 28902 image = thisItem.find('video').attr('poster'); 28903 } 28904 28905 if (SitePreferences.CORDIAL_ENABLED) { 28906 var properties = { 28907 'productID': itemMeta["id"] 28908 }; 28909 var cart_data = [{ 28910 'productID': itemMeta["id"], 28911 'sku': itemMeta["skuid"], 28912 'category': itemMeta["category"].replace(/\\/g, ""), 28913 'name': itemMeta["name"].replace(/\\/g, ""), 28914 'qty': '1', 28915 'itemPrice': itemMeta["price"], 28916 'images': [image], 28917 'url': thisItem.find('.thumb-link').attr('href'), 28918 'attr': { 28919 'manufacturer': itemMeta["brand"], 28920 'color': thisItem.find('.product-color').text().replace('Color: ',""), 28921 'size': thisItem.find('.product-size').text().replace('Size: ',"") 28922 } 28923 }]; 28924 28925 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 28926 crdl([ 28927 ['cart', 'update'], 28928 ['cartitem', 'add' , cart_data], 28929 ['event', 'cart', properties] 28930 ]); 28931 } 28932 } 28933 28934 if (SitePreferences.PIXLEE_ENABLED) { 28935 if (typeof pixlee_analytics !== 'undefined') { 28936 pixlee_analytics.events.trigger('add:to:cart', { 28937 'product_sku': itemMeta["id"], 28938 'price': itemMeta["price"], 28939 'quantity': '1', 28940 'currency': 'USD' 28941 }); 28942 } 28943 } 28944 }); 28945 28946 $('body').on('click', '#mobile-share-wishlist-button', function() { 28947 $('.wishlist-share-mobile-container').slideToggle('slow'); 28948 }); 28949 $('body').on('change', '.share-wishlist-toggle input[name="share-wishlist-checkbox"]', function() { 28950 var status = $(this).is(':checked'); 28951 if (status) { 28952 $('#share-wishlist-menu').slideDown('slow').css('display','flex'); 28953 } else { 28954 $('#share-wishlist-menu').slideUp('slow').removeClass('show-share-wishlist-menu').css('display','none'); 28955 } 28956 if (Customer.authenticated) { 28957 var wishlistID = $('input[name="current_wishlist_id"]').val().trim(); 28958 if (wishlistID) { 28959 $.ajax({ 28960 method: 'GET', 28961 url: Urls.wishlistSetPublic, 28962 data: { 28963 WishlistID: wishlistID, 28964 SetPublic: status 28965 } 28966 }).done(function(response) { 28967 if (response.result == 'error') { 28968 errorHandling(null, '', 'Wishlist Share - Error', '<p style="padding: 10px;">Oops, something went wrong and cannot update your Wishlist at this time. Please try again later.</p>'); 28969 } else if (response.result == 'success') { 28970 // No on-screen visuals need to occur 28971 } 28972 }); 28973 } else { 28974 errorHandling(null, '', 'Wishlist Share - Error', '<p style="padding: 10px;">Oops, something went wrong and we could not retrieve your Wishlist. Please try again later.</p>'); 28975 } 28976 } else { 28977 window.location.href = Urls.account; 28978 } 28979 }); 28980 $('body').on('click', '.share-wishlist-menu-popup .close-button', function() { 28981 var $this = $(this); 28982 $this.parents('.share-wishlist-menu-popup').addClass('d-none'); 28983 var shareLink = $this.parents('.share-wishlist-menu-popup').attr('id').indexOf('link-popup') > -1; 28984 if (shareLink) { 28985 $this.siblings('.form-row-button').find('button[name="share-wishlist-link-copy"]').removeClass('btn-complete disabled').html('Copy'); 28986 } 28987 }); 28988 $('body').on('click', 'button[name="share-wishlist-link-copy"]:not(.disabled)', function() { 28989 var $button = $(this); 28990 var wishlistUrl = $('#share-wishlist-link-popup .share-wishlist-url a').html(); 28991 navigator.clipboard.writeText(wishlistUrl); 28992 $button.addClass('btn-complete disabled').html('<i class="fa fa-check" aria-hidden="true"></i> Copied!'); 28993 }); 28994 $('body').on('click', 'button[name="share-wishlist-email-send"]:not(.disabled)', function() { 28995 var $this = $(this); 28996 var $email = $('#wishlist-share-email-input'); 28997 var $message = $('#wishlist-share-email-message'); 28998 var isValidEmailForm = validateEmailForm($email, $message); 28999 if (isValidEmailForm) { 29000 if (Customer.authenticated) { 29001 var wishlistID = $('input[name="current_wishlist_id"]').val().trim(); 29002 if (wishlistID) { 29003 $.ajax({ 29004 method: 'POST', 29005 url: Urls.wishlistShareByEmail, 29006 data: { 29007 WishlistID: wishlistID, 29008 ToEmail: $email.val(), 29009 EmailMessage: $message.val() 29010 } 29011 }).done(function(response) { 29012 if (response.result == 'error') { 29013 errorHandling(null, '', 'Wishlist Share - Error', '<p style="padding: 10px;">Oops, something went wrong and could not send your Wishlist email. Please try again later.</p>'); 29014 } else if (response.result == 'success') { 29015 $this.parents('#share-wishlist-email-popup').addClass('share-wishlist-email-success'); 29016 } 29017 }); 29018 } else { 29019 errorHandling(null, '', 'Wishlist Share - Error', '<p style="padding: 10px;">Oops, something went wrong and we could not retrieve your Wishlist for sharing. Please try again later.</p>'); 29020 } 29021 } else { 29022 window.location.href = Urls.account; 29023 } 29024 } 29025 }); 29026 $('body').on('click', '#share-wishlist-menu .btn-open', function() { 29027 var $button = $(this); 29028 var $sharePopup = $button.siblings('.share-wishlist-menu-popup'); 29029 if ($sharePopup.length) { 29030 $sharePopup.removeClass('d-none share-wishlist-email-success'); 29031 } 29032 }); 29033 }); 29034 29035 // If this is an order confirmation page, kick off wishlist remove products post order 29036 if ($(document).find('.pt_order-confirmation').length > 0) { 29037 wishlistPostOrder(); 29038 } 29039} 29040 29041exports.checkWishlistForItem = checkWishlistForItem; 29042exports.prepareWishlistAddUI = prepareWishlistAddUI; 29043exports.prepareWishlistRemoveUI = prepareWishlistRemoveUI; 29044exports.renderAllWishlistButtons = renderAllWishlistButtons;
29045exports.init = init; 29046},{"./dialog":36,"./loginDialog":44,"./progress":86}],106:[function(require,module,exports){ 29047'use strict'; 29048 29049exports.SlickSlider = { 29050 Options: { 29051 Single: { 29052 accessibility: true, 29053 infinite: true, 29054 dots: false, 29055 arrows: false, 29056 slidesToShow: 1, 29057 slidesToScroll: 1, 29058 responsive: [ 29059 { 29060 breakpoint: 767, 29061 settings: { 29062 dots: true 29063 } 29064 } 29065 ] 29066 }, 29067 Thumbnail: { 29068 accessibility: true, 29069 draggable: true, 29070 infinite: false, 29071 focusOnSelect: false, 29072 dots: false, 29073 arrows: false, 29074 slidesToShow: 7, 29075 slidesToScroll: 7 29076 }, 29077 CategoryLanding: { 29078 accessibility: true, 29079 draggable: true, 29080 infinite: true, 29081 focusOnSelect: false, 29082 dots: false, 29083 arrows: true, 29084 slidesToShow: 4, 29085 slidesToScroll: 4, 29086 responsive: [ 29087 { 29088 breakpoint: 767 29089 }, 29090 { 29091 breakpoint: 1200, 29092 settings: { 29093 slidesToShow: 3, 29094 slidesToScroll: 3 29095 } 29096 } 29097 ] 29098 } 29099 } 29100} 29101},{}],107:[function(require,module,exports){ 29102'use strict'; 29103 29104var _ = require('lodash'); 29105var PaymentMethodConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').PaymentMethods; 29106var CreditCardConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants').CreditCards; 29107 29108var util = { 29109 /** 29110 * @function 29111 * @description appends the parameter with the given name and value to the given url and returns the changed url 29112 * @param {String} url the url to which the parameter will be added 29113 * @param {String} name the name of the parameter 29114 * @param {String} value the value of the parameter 29115 */ 29116 appendParamToURL: function (url, name, value) { 29117 // quit if the param already exists 29118 if (url.indexOf(name + '=') !== -1) { 29119 return url; 29120 } 29121 var separator = url.indexOf('?') !== -1 ? '&' : '?'; 29122 var anchor = ''; 29123 if (url.indexOf('#') > -1) { 29124 var urlAndAnchor = url.split('#'); 29125 url = urlAndAnchor[0]; 29126 anchor = '#' + urlAndAnchor[1]; 29127 } 29128 return url + separator + name + (value ? '=' + encodeURIComponent(value) : '') + anchor; 29129 }, 29130 29131 /** 29132 * @function 29133 * @description remove the parameter and its value from the given url and returns the changed url 29134 * @param {String} url the url from which the parameter will be removed 29135 * @param {String} name the name of parameter that will be removed from url 29136 */ 29137 removeParamFromURL: function (url, name) { 29138 if (url.indexOf('?') === -1 || url.indexOf(name + '=') === -1) { 29139 return url; 29140 } 29141 var hash; 29142 var params; 29143 var domain = url.split('?')[0]; 29144 var paramUrl = url.split('?')[1]; 29145 var newParams = []; 29146 // if there is a hash at the end, store the hash 29147 if (paramUrl.indexOf('#') > -1) { 29148 hash = paramUrl.split('#')[1] || ''; 29149 paramUrl = paramUrl.split('#')[0]; 29150 } 29151 params = paramUrl.split('&'); 29152 for (var i = 0; i < params.length; i++) { 29153 // put back param to newParams array if it is not the one to be removed 29154 if (params[i].split('=')[0] !== name) { 29155 newParams.push(params[i]); 29156 } 29157 } 29158 return domain + '?' + newParams.join('&') + (hash ? '#' + hash : ''); 29159 }, 29160 29161 /** 29162 * @function 29163 * @description appends the parameters to the given url and returns the changed url 29164 * @param {String} url the url to which the parameters will be added 29165 * @param {Object} params 29166 */ 29167 appendParamsToUrl: function (url, params) { 29168 var _url = url; 29169 _.each(params, function (value, name) { 29170 _url = this.appendParamToURL(_url, name, value); 29171 }.bind(this)); 29172 return _url; 29173 }, 29174 /** 29175 * @function 29176 * @description extract the query string from URL 29177 * @param {String} url the url to extra query string from 29178 **/ 29179 getQueryString: function (url) { 29180 var qs; 29181 if (!_.isString(url)) { return; } 29182 var a = document.createElement('a'); 29183 a.href = url; 29184 if (a.search) { 29185 qs = a.search.substr(1); // remove the leading ? 29186 } 29187 return qs; 29188 }, 29189 /** 29190 * @function
29191 * @description 29192 * @param {String} 29193 * @param {String} 29194 */ 29195 elementInViewport: function (el, offsetToTop) { 29196 var top = el.offsetTop, 29197 left = el.offsetLeft, 29198 width = el.offsetWidth, 29199 height = el.offsetHeight; 29200 29201 while (el.offsetParent) { 29202 el = el.offsetParent; 29203 top += el.offsetTop; 29204 left += el.offsetLeft; 29205 } 29206 29207 if (typeof(offsetToTop) !== 'undefined') { 29208 top -= offsetToTop; 29209 } 29210 29211 if (window.pageXOffset !== null) { 29212 return ( 29213 top < (window.pageYOffset + window.innerHeight) && 29214 left < (window.pageXOffset + window.innerWidth) && 29215 (top + height) > window.pageYOffset && 29216 (left + width) > window.pageXOffset 29217 ); 29218 } 29219 29220 if (document.compatMode === 'CSS1Compat') { 29221 return ( 29222 top < (window.document.documentElement.scrollTop + window.document.documentElement.clientHeight) && 29223 left < (window.document.documentElement.scrollLeft + window.document.documentElement.clientWidth) && 29224 (top + height) > window.document.documentElement.scrollTop && 29225 (left + width) > window.document.documentElement.scrollLeft 29226 ); 29227 } 29228 }, 29229 29230 /** 29231 * @function 29232 * @description Appends the parameter 'format=ajax' to a given path 29233 * @param {String} path the relative path 29234 */ 29235 ajaxUrl: function (path) { 29236 return this.appendParamToURL(path, 'format', 'ajax'); 29237 }, 29238 29239 /** 29240 * @function 29241 * @description 29242 * @param {String} url 29243 */ 29244 toAbsoluteUrl: function (url) { 29245 if (url.indexOf('http') !== 0 && url.charAt(0) !== '/') { 29246 url = '/' + url; 29247 } 29248 return url; 29249 }, 29250 /** 29251 * @function 29252 * @description Loads css dynamically from given urls 29253 * @param {Array} urls Array of urls from which css will be dynamically loaded. 29254 */ 29255 loadDynamicCss: function (urls) { 29256 var i, len = urls.length; 29257 for (i = 0; i < len; i++) { 29258 this.loadedCssFiles.push(this.loadCssFile(urls[i])); 29259 } 29260 }, 29261 29262 /** 29263 * @function 29264 * @description Loads css file dynamically from given url 29265 * @param {String} url The url from which css file will be dynamically loaded. 29266 */ 29267 loadCssFile: function (url) { 29268 return $('<link/>').appendTo($('head')).attr({ 29269 type: 'text/css', 29270 rel: 'stylesheet' 29271 }).attr('href', url); // for i.e. <9, href must be added after link has been appended to head 29272 }, 29273 // array to keep track of the dynamically loaded CSS files 29274 loadedCssFiles: [], 29275 29276 /** 29277 * @function 29278 * @description Removes all css files which were dynamically loaded 29279 */ 29280 clearDynamicCss: function () { 29281 var i = this.loadedCssFiles.length; 29282 while (0 > i--) { 29283 $(this.loadedCssFiles[i]).remove(); 29284 } 29285 this.loadedCssFiles = []; 29286 }, 29287 /** 29288 * @function 29289 * @description Extracts all parameters from a given query string into an object 29290 * @param {String} qs The query string from which the parameters will be extracted 29291 */ 29292 getQueryStringParams: function (qs) { 29293 if (!qs || qs.length === 0) { return {}; } 29294 var params = {}, 29295 unescapedQS = decodeURIComponent(qs); 29296 // Use the String::replace method to iterate over each 29297 // name-value pair in the string. 29298 unescapedQS.replace(new RegExp('([^?=&]+)(=([^&]*))?', 'g'), 29299 function ($0, $1, $2, $3) { 29300 params[$1] = $3; 29301 } 29302 ); 29303 return params; 29304 }, 29305 29306 fillAddressFields: function (address, $form) { 29307 for (var field in address) { 29308 if (field === 'UUID' || field === 'key') { 29309 continue; 29310 } 29311 // if the key in address object ends with 'Code', remove that suffix 29312 // keys that ends with 'Code' are postalCode, stateCode and countryCode 29313 // update the state fields 29314 if (field === 'countryCode') { 29315 $form.find('[name$="country"]').val(address['countryCode'].toUpperCase()).trigger('change'); 29316 // retrigger state selection after country has changed 29317 // this results in duplication of the state code, but is a
29317necessary evil 29318 // for now because sometimes countryCode comes after stateCode 29319 29320 var selectedStateValue = address['stateCode']; 29321 if ($form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').length > 0) { 29322 selectedStateValue = $form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').val(); 29323 } 29324 29325 $form.find('[name$="state"]').val(selectedStateValue); 29326 } else if (field === 'stateCode') { 29327 var selectedStateValue = address['stateCode']; 29328 if ($form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').length > 0) { 29329 selectedStateValue = $form.find('[name$="state"] option[label="' + address['stateCode'] + '"]').val(); 29330 } 29331 29332 $form.find('[name$="state"]').val(selectedStateValue); 29333 } else { 29334 if (address[field] != null) { 29335 $form.find('[name$="_' + field.replace('Code', '') + '"]').val((''+address[field]).replace(/\^/gi,"'")); 29336 } else { 29337 $form.find('[name$="_' + field.replace('Code', '') + '"]').val(address[field]); 29338 } 29339 } 29340 } 29341 }, 29342 /** 29343 * @function 29344 * @description Updates the number of the remaining character 29345 * based on the character limit in a text area 29346 */ 29347 limitCharacters: function () { 29348 $('form').find('textarea[data-character-limit]').each(function () { 29349 var characterLimit = $(this).data('character-limit'); 29350 var charCountHtml = String.format(Resources.CHAR_LIMIT_MSG, 29351 '<span class="char-remain-count">' + characterLimit + '</span>', 29352 '<span class="char-allowed-count">' + characterLimit + '</span>'); 29353 var charCountContainer = $(this).next('div.char-count'); 29354 if (charCountContainer.length === 0) {
29355 charCountContainer = $('<div class="char-count"/>').insertAfter($(this)); 29356 } 29357 charCountContainer.html(charCountHtml); 29358 // trigger the keydown event so that any existing character data is calculated 29359 $(this).change(); 29360 }); 29361 }, 29362 /** 29363 * @function 29364 * @description Binds the onclick-event to a delete button on a given container, 29365 * which opens a confirmation box with a given message 29366 * @param {String} container The name of element to which the function will be bind 29367 * @param {String} message The message the will be shown upon a click 29368 */ 29369 setDeleteConfirmation: function (container, message) { 29370 $(container).on('click', '.delete', function () { 29371 return window.confirm(message); 29372 }); 29373 }, 29374 /** 29375 * @function 29376 * @description Scrolls a browser window to a given x point 29377 * @param {String} The x coordinate 29378 */ 29379 scrollBrowser: function (xLocation) { 29380 $('html, body').animate({scrollTop: xLocation}, 500); 29381 }, 29382 29383 isTouchDevice: function() { 29384 return ('ontouchstart' in window || navigator.msMaxTouchPoints); 29385 }, 29386 29387 isMobile: function () { 29388 var mobileAgentHash = ['mobile', 'tablet', 'phone', 'ipad', 'ipod', 'android', 'blackberry', 'windows ce', 'opera mini', 'palm']; 29389 var idx = 0; 29390 var isMobile = false; 29391 var userAgent = (navigator.userAgent).toLowerCase(); 29392 29393 while (mobileAgentHash[idx] && !isMobile) { 29394 isMobile = (userAgent.indexOf(mobileAgentHash[idx]) >= 0); 29395 idx++; 29396 } 29397 return isMobile; 29398 }, 29399 29400 /** 29401 * @function 29402 * @description Validates e-mail address 29403 * @param {String} E-mail address 29404 * @returns {Boolean} 29405 */ 29406 validateEmail: function (email) { 29407 var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 29408 return re.test(email); 29409 }, 29410 29411 /** 29412 * @function 29413 * @description Helper method to encode inputs and prevent xss 29414 * @param {String} input value 29415 * @returns {String} 29416 */ 29417 htmlEncode: function (value) { 29418 if (value) { 29419 return jQuery('<div/>').text(value).html(); 29420 } else { 29421 return ''; 29422 } 29423 }, 29424 29425 /** 29426 * Limits a text input to a defined length. 29427 * @param (String) inputSelector - A jQuery selector for the input to limit. 29428 * @param (Number) lengthLimit - The length to limit the input to. 29429 * @return void 29430 */ 29431 limitInputToLength: function (inputSelector, lengthLimit) { 29432 $(inputSelector).on("keyup click", function () { 29433 if (this.value.length > lengthLimit) { 29434 this.value = this.value.substring(0, lengthLimit); 29435 } 29436 }); 29437 }, 29438 29439 /** 29440 * Detects the credit card type based off of the provided credit card number. 29441 * @param (String) creditCardNumber - The credit card number to detect the type for. 29442 * @return (String) - The type of credit card. 29443 */ 29444 getCreditCardType: function (creditCardNumber) { 29445 creditCardNumber = creditCardNumber.replace(/\D/g, ''); 29446 29447 if (creditCardNumber.length >= 4) { 29448 var creditCardTypes = [ 29449 { 29450 PaymentCard: CreditCardConstants.Visa, 29451 PaymentCardDisplayKey: CreditCardConstants.Visa, 29452 PaymentMethod: PaymentMethodConstants.CreditCard, 29453 Pattern: new RegExp('^4[0-9]{0,}$') 29454 }, 29455 { 29456 PaymentCard: CreditCardConstants.AmericanExpress, 29457 PaymentCardDisplayKey: CreditCardConstants.AmericanExpress, 29458 PaymentMethod: PaymentMethodConstants.CreditCard, 29459 Pattern: new RegExp('^3[47][0-9]{0,}$') 29460 }, 29461 { 29462 PaymentCard: CreditCardConstants.Diners, 29463 PaymentCardDisplayKey: CreditCardConstants.Discover, 29464 PaymentMethod: PaymentMethodConstants.CreditCard, 29465 Pattern: new RegExp('^3(?:0[0-59]{1}|[689])[0-9]{0,}$') 29466 }, 29467 { 29468 PaymentCard: CreditCardConstants.JCB, 29469 PaymentCardDisplayKey: CreditCardConstants.JCB, 29470 PaymentMethod: PaymentMethodConstants.CreditCard, 29471 Pattern: new RegExp('^(?:2131|1800|35)[0-9]{0,}$') 29472 }, 29473 { 29474 PaymentCard: CreditCardConstants.Mastercard, 29475 PaymentCardDisplayKey: CreditCardConstants.Mastercard, 29476 PaymentMethod: PaymentMethodConstants.CreditCard,
29477 Pattern: new RegExp('^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$') 29478 }, 29479 { 29480 PaymentCard: CreditCardConstants.Discover, 29481 PaymentCardDisplayKey: CreditCardConstants.Discover, 29482 PaymentMethod: PaymentMethodConstants.CreditCard, 29483 Pattern: new RegExp('^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$') 29484 }, 29485 { 29486 PaymentCard: CreditCardConstants.Maestro, 29487 PaymentCardDisplayKey: CreditCardConstants.Mastercard, 29488 PaymentMethod: PaymentMethodConstants.CreditCard, 29489 Pattern: new RegExp('^(5[06789]|6)[0-9]{0,}$') 29490 }, 29491 { 29492 PaymentCard: CreditCardConstants.BootBarnCredit, 29493 PaymentCardDisplayKey: PaymentMethodConstants.AllianceData, 29494 PaymentMethod: PaymentMethodConstants.AllianceData, 29495 Pattern: new RegExp('^7788[0-9]{0,}$') 29496 } 29497 ] 29498 29499 for (var creditCardTypeKey in creditCardTypes) { 29500 var creditCardType = creditCardTypes[creditCardTypeKey]; 29501 29502 if (creditCardType.Pattern && creditCardNumber.match(creditCardType.Pattern)) { 29503 return creditCardType; 29504 } 29505 } 29506 } 29507 29508 return false; 29509 }, 29510 29511 /** 29512 * Masks a provided number. 29513 * @param (Number or String) number - The number to mask. 29514 * @param (Number) lengthToShow - The length of the number to leave unmasked at end. 29515 * @param (String) maskCharacter - The character to use for masking. Defaults to *. 29516 * @return (String) - The type of credit card. 29517 */ 29518 getMaskedNumber: function (number, lengthToShow, maskPattern) { 29519 if (!number) { 29520 return ''; 29521 } 29522 29523 lengthToShow = lengthToShow || 4; 29524 maskPattern = maskPattern || '*'; 29525 29526 var numberMasked; 29527 if (maskPattern.length > 1) { 29528 numberMasked = maskPattern; 29529 } else if (maskPattern.length >= 1) { 29530 numberMasked = new Array(number.length + 1).join(maskPattern); 29531 } 29532 29533 number += ''; 29534 if (number != null && number != '') { 29535 numberMasked = numberMasked.substr(0, number.length - lengthToShow); 29536 numberMasked += number.substr(number.length - lengthToShow); 29537 } 29538 29539 return numberMasked; 29540 }, 29541 29542 getPreferenceValueFromWindowLocation: function (preferenceName) { 29543 var hash = window.location.hash.substr(1), 29544 preferenceValue = '', 29545 hashTable = hash.split('&').reduce(function (hashTable, item) { 29546 var parts = item.split('='); 29547 hashTable[parts[0]] = decodeURIComponent(parts[1]).replace(/[\+\s]+/g, ' '); 29548 return hashTable; 29549 }, {}); 29550 29551 for (var i = 1; i <= 5; i++){ 29552 if(!hashTable.hasOwnProperty('prefn' + i)){ 29553 break; 29554 } else if(hashTable['prefn' + i] == preferenceName){ 29555 preferenceValue = hashTable['prefv' + i]; 29556 break; 29557 } 29558 } 29559 29560 return preferenceValue; 29561 } 29562}; 29563 29564module.exports = util; 29565 29566},{"../../../bc_sheplersbootbarn_core/cartridge/js/PaymentInstrumentConstants":117,"lodash":133}],108:[function(require,module,exports){ 29567'use strict'; 29568 29569var naPhone = /^\+?\(?([0-9][0-8][0-9])\)?[\-\. ]?([2-9][0-9]{2})[\-\. ]?([0-9]{4})(\s*x[0-9]+)?$/; 29570var internationalNumber = /^(?:\s*\+)?[\d\s\.\-\(\)]+$/; 29571var defaultPostal = /^\d{3,7}$/; 29572var regex = { 29573 phone: { 29574 us: naPhone, 29575 ca: internationalNumber, 29576 fr: internationalNumber, 29577 it: internationalNumber, 29578 jp: internationalNumber, 29579 cn: /.*/, 29580 gb: internationalNumber 29581 }, 29582 postal: { 29583 us: /^\d{5}(-\d{4})?$/, 29584 ca: /^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$/i, 29585 fr: /^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$/, 29586 it: /^([0-9]){5}$/, 29587 jp: /^([0-9]){3}[-]([0-9]){4}$/, 29588 cn: /^([0-9]){6}$/, 29589 gb: /^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$/i 29590 }, 29591 notCC: /^(?!(([0-9 -]){13,19})).*$/ 29592}; 29593// global form validator settings 29594var settings = { 29595 errorClass: 'error', 29596 errorElement: 'span', 29597 onkeyup: false, 29598 onfocusout: function (element) { 29599 if (!this.checkable(element)) {
29600 this.element(element); 29601 } 29602 }, 29603 errorPlacement: function (error, element) { 29604 error.appendTo(element.parent()); 29605 } 29606}; 29607/** 29608 * @function 29609 * @description Validates a given phone number against the countries phone regex 29610 * @param {String} value The phone number which will be validated 29611 * @param {String} el The input field 29612 */ 29613var validatePhone = function (value, el) { 29614 var country = $(el).closest('form').find('.country'); 29615 if (country.length === 0 || country.val().length === 0 || !regex.phone[country.val().toLowerCase()]) { 29616 return true; 29617 } 29618 29619 var rgx = regex.phone[country.val().toLowerCase()]; 29620 var isOptional = this.optional(el); 29621 var isValid = rgx.test($.trim(value)); 29622 29623 return isOptional || isValid; 29624}; 29625 29626var validatePostal = function (value, el) { 29627 var country = $(el).closest('form').find('.country'); 29628 if (country.length === 0 || country.val().length === 0 || !regex.phone[country.val().toLowerCase()]) { 29629 return true; 29630 } 29631 29632 var rgx = regex.postal[country.val().toLowerCase()]; 29633 var isOptional = this.optional(el); 29634 var isValid = rgx.test($.trim(value)); 29635 29636 return isOptional || isValid; 29637}; 29638/** 29639 * @function 29640 * @description Validates that a credit card owner is not a Credit card number 29641 * @param {String} value The owner field which will be validated 29642 * @param {String} el The input field 29643 */ 29644var validateOwner = function (value) { 29645 var isValid = regex.notCC.test($.trim(value)); 29646 return isValid; 29647}; 29648 29649/** 29650 * Add phone validation method to jQuery validation plugin. 29651 * Text fields must have 'phone' css class to be validated as phone 29652 */ 29653$.validator.addMethod('phone', validatePhone, Resources.INVALID_PHONE); 29654$.validator.addMethod('postal', validatePostal, Resources.INVALID_ZIP); 29655 29656/** 29657 * Add CCOwner validation method to jQuery validation plugin. 29658 * Text fields must have 'owner' css class to be validated as not a credit card 29659 */ 29660$.validator.addMethod('owner', validateOwner, Resources.INVALID_OWNER); 29661 29662/** 29663 * Add gift cert amount validation method to jQuery validation plugin. 29664 * Text fields must have 'gift-cert-amont' css class to be validated 29665 */ 29666$.validator.addMethod('gift-cert-amount', function (value, el) { 29667 var isOptional = this.optional(el); 29668 var isValid = (!isNaN(value)) && (parseFloat(value) >= 5) && (parseFloat(value) <= 5000); 29669 return isOptional || isValid; 29670}, Resources.GIFT_CERT_AMOUNT_INVALID); 29671 29672/** 29673 * Add positive number validation method to jQuery validation plugin. 29674 * Text fields must have 'positivenumber' css class to be validated as positivenumber 29675 */ 29676$.validator.addMethod('positivenumber', function (value) { 29677 if ($.trim(value).length === 0) { return true; } 29678 return (!isNaN(value) && Number(value) >= 0); 29679}, Resources.VALIDATE_NUMBER); 29680 29681/** 29682 * Add method to check for email extension when validating emails, 29683 * since default settings don't require an extension 29684 */ 29685$.validator.addMethod("requireEmailExtension", function(value, element) { 29686 if ($.trim(value).length === 0) { return true; } 29687 return /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value); 29688}, Resources.VALIDATE_EMAIL); 29689 29690/* 29691 * Lets you say "at least X inputs that match selector Y must be filled." 29692 * 29693 * The end result is that neither of these inputs: 29694 * 29695 * <input class="productinfo" name="partnumber"> 29696 * <input class="productinfo" name="description"> 29697 * 29698 * ...will validate unless at least one of them is filled. 29699 * 29700 * partnumber: {require_from_group: [1,".productinfo"]}, 29701 * description: {require_from_group: [1,".productinfo"]} 29702 * 29703 * options[0]: number of fields that must be filled in the group 29704 * options[1]: CSS selector that defines the group of conditionally required fields 29705 */ 29706$.validator.addMethod( "require_from_group", function( value, element, options ) { 29707 var $fields = $(options[1], element.form); 29708 var $fieldsFirst = $fields.eq(0); 29709 var validator = $fieldsFirst.data("valid_req_grp") ? $fieldsFirst.data("valid_req_grp") : $.extend({}, this); 29710 var isValid = $fields.filter(function() { 29711 return validator.elementValue(this); 29712 }).length >= options[0]; 29713 29714 // Store the cloned validator for future validation 29715 $fieldsFirst.data("valid_req_grp", validator); 29716 29717 // If element isn't being validated, run each require_from_group field's validation rules 29718 if (!$(element).data("being_validated")) { 29719 $fields.data("being_validated", true); 29720 $fields.each(function() { 29721 validator.element(this); 29722 }); 29723 $fields.data("being_validated", false); 29724 } 29725 return isValid; 29726}, $.validator.format("Please fill at least {0} of these fields.")); 29727 29728$.extend($.validator.messages, {
29729 required: Resources.VALIDATE_REQUIRED, 29730 remote: Resources.VALIDATE_REMOTE, 29731 email: Resources.VALIDATE_EMAIL, 29732 url: Resources.VALIDATE_URL, 29733 date: Resources.VALIDATE_DATE, 29734 dateISO: Resources.VALIDATE_DATEISO, 29735 number: Resources.VALIDATE_NUMBER, 29736 digits: Resources.VALIDATE_DIGITS, 29737 creditcard: Resources.VALIDATE_CREDITCARD, 29738 equalTo: Resources.VALIDATE_EQUALTO, 29739 maxlength: $.validator.format(Resources.VALIDATE_MAXLENGTH), 29740 minlength: $.validator.format(Resources.VALIDATE_MINLENGTH), 29741 rangelength: $.validator.format(Resources.VALIDATE_RANGELENGTH), 29742 range: $.validator.format(Resources.VALIDATE_RANGE), 29743 max: $.validator.format(Resources.VALIDATE_MAX), 29744 min: $.validator.format(Resources.VALIDATE_MIN) 29745}); 29746 29747var validator = { 29748 regex: regex, 29749 settings: settings, 29750 init: function () { 29751 var self = this; 29752 $('form:not(.suppress)').each(function () { 29753 $(this).validate(self.settings); 29754 }); 29755 }, 29756 initForm: function (f) { 29757 $(f).validate(this.settings); 29758 } 29759}; 29760 29761module.exports = validator; 29762 29763},{}],109:[function(require,module,exports){ 29764'use strict'; 29765 29766/* ------------------------- 29767 * LOGIN 29768 * ------------------------- 29769 */ 29770 29771var loadingIndicator = require('../../../app_storefront_core/cartridge/js/components/LoadingIndicator'); 29772var dialog = require('../../../app_storefront_core/cartridge/js/dialog'); 29773var loginDialog = require('../../../app_storefront_core/cartridge/js/loginDialog'); 29774var recaptcha = require('../../../app_storefront_core/cartridge/js/components/Recaptcha'); 29775var util = require('../../../app_storefront_whip/cartridge/js/util'); //util reference 29776var validator = require('../../../app_storefront_whip/cartridge/js/validator'); 29777 29778var GoogleTagManagerClient = require('../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient'); 29779var SiteConstants = require('../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants'); 29780var TPromise = require('promise'); 29781 29782var dataBuffer = {}; 29783var options = {}; 29784var loaded = {}; 29785var loadingIndicatorSettings = { 29786 IsLabelShown: false, 29787 CssClass: 'fullscreen', 29788 BackgroundColor: 'transparent' 29789}; 29790var opcLoggedInCustomerAddresses = []; 29791 29792/** 29793 * @private 29794 * @function 29795 * @description init events for the loginPage 29796 */ 29797function initLoginEvents() { 29798 //toggle the value of the rememberme checkbox 29799 $(document).on('change', '.login-rememberme input', function () { 29800 if ($(this).prop('checked')) { 29801 $('#rememberme').val('true'); 29802 } else { 29803 $('#rememberme').val('false'); 29804 } 29805 }); 29806 $(document).on('click', '#optin-privacy-policy', function(e) { 29807 e.preventDefault(); 29808 location.href = Urls.privacyPage; 29809 }); 29810 $(document).on('click', '#reward-learn-more', function(e) { 29811 e.preventDefault(); 29812 location.href = Urls.learnFAQ; 29813 }); 29814 $(document).on('click', '.movetoaddr', function(e){ 29815 e.preventDefault(); 29816 $('html, body').animate({ 29817 scrollTop: $('.billing-address-form').eq(0).offset().top 29818 }, 1000); 29819 }); 29820 $(document).on('click', '#attach-rewards-form label', function() { 29821 $('#attach-rewards-form input').removeAttr('checked'); 29822 $(this).siblings('[name="attach-rewards-options"]').attr('checked', 'checked'); 29823 }); 29824} 29825 29826function validateLoginForm($form, checkFields) { 29827 if (!$form || !checkFields) { return false } 29828 29829 var $emailField = $form.find('input[name*="_username"]'); 29830 var $passwordField = $form.find('input[name*="_password"]'); 29831 var emailValue = $emailField.length > 0 ? $emailField.val().trim() : null; 29832 var passwordValue = $passwordField.length > 0 ? $passwordField.val().trim() : null; 29833 var formValidation = true; 29834 29835 for (var i = 0; i < checkFields.length; i++) { 29836 var currentField = checkFields[i]; 29837 29838 if (currentField.toUpperCase() == 'EMAIL' && (!emailValue || emailValue.length == 0)) { 29839 formValidation = false; 29840 $form.find('input[name*="_username"]').addClass('error'); 29841 } 29842 if (currentField.toUpperCase() == 'PASSWORD' && (!passwordValue || passwordValue.length == 0)) { 29843 formValidation = false;
29844 $form.find('input[name*="_password"]').addClass('error'); 29845 } 29846 } 29847 29848 if (!formValidation) { 29849 $form.find('.login-dialog-error .invalid-missing-fields').removeClass('d-none'); 29850 return false; 29851 } else { 29852 $form.find('.login-dialog-error span').addClass('d-none'); 29853 return true; 29854 } 29855} 29856 29857function errorHandling(data, dialogTitle, dialogHtml) { 29858 if (data && typeof data === 'object' && 'message' in data) { 29859 console.log(data.message); 29860 } 29861 dialog.open({ 29862 html: dialogHtml, 29863 options: { 29864 title: dialogTitle, 29865 draggable: false, 29866 open: function(event, ui) { 29867 $('body').addClass('dialog-open'); 29868 }, 29869 close: function(event, ui) { 29870 $('body').removeClass('dialog-open'); 29871 } 29872 } 29873 }); 29874} 29875 29876// Cordial tracking for loginPage and loginDialog 29877function loginCordialAccountEvent($form, isLoginDialog) { 29878 var username = $form.find('input[name*="_username"]').val().trim(); 29879 29880 var auth_data = { 29881 email: username 29882 } 29883 29884 var contact_data = { 29885 'channels': { 29886 'email': { 29887 'address': username 29888 } 29889 } 29890 }; 29891 29892 var properties = { 29893 "email": username, 29894 "loginType": isLoginDialog ? "login-dialog" : "login" 29895 }; 29896 29897 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 29898 crdl([ 29899 ['contact', auth_data, contact_data], 29900 ['event', 'login', properties] 29901 ]); 29902 } 29903} 29904 29905// Cordial password reset - no account event 29906function passwordResetNoAccountCordialEvent(container) { 29907 if (container && $(container).find('.reset-password .no-account').length > 0) { 29908 var email = $('.no-account').text(); 29909 29910 var auth_data = { 29911 email: email 29912 } 29913 var contact_data = { 29914 'channels': { 29915 'email': { 29916 'address': email 29917 } 29918 } 29919 }; 29920 29921 var properties = { 29922 "email": email 29923 }; 29924 29925 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 29926 crdl([ 29927 ['contact', auth_data, contact_data], 29928 ['event', 'reset-password-no-account', properties] 29929 ]); 29930 } 29931 } 29932} 29933 29934function initializeRecaptchaForLogin() { 29935 renderRecaptchaForLogin(); 29936 $(document).on('Account.SubmitLogin', function(event) { 29937 $('#accountLoginButton').click(); 29938 }); 29939} 29940 29941function renderRecaptchaForLogin() { 29942 if (loaded.Recaptcha && $('#accountLoginButton').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForAccountLogin && options.Recaptcha.GoogleSiteKey) { 29943 dataBuffer.LoginRecaptcha = grecaptcha.render('accountLoginButton', { 29944 'sitekey': options.Recaptcha.GoogleSiteKey, 29945 'callback': accountLogin, 29946 'badge': 'bottomleft' 29947 }); 29948 } 29949} 29950 29951function renderRecaptchaForPasswordReset() { 29952 if (loaded.Recaptcha && $('#request-password-send-btn').length > 0 && options && options.Recaptcha && options.Recaptcha.EnabledForPasswordReset && options.Recaptcha.GoogleSiteKey) { 29953 if (dataBuffer.ResetPasswordRecaptcha) { 29954 grecaptcha.reset(dataBuffer.ResetPasswordRecaptcha); 29955 } 29956 29957 dataBuffer.ResetPasswordRecaptcha = grecaptcha.render('request-password-send-btn', { 29958 'sitekey': options.Recaptcha.GoogleSiteKey, 29959 'callback': window.resetPassword, 29960 'badge': 'bottomleft' 29961 }); 29962 } 29963} 29964 29965var updateCustomerDetails = function (form, name) { 29966 var $form = $(form); 29967 29968 return TPromise.resolve($.ajax({ 29969 type: 'POST', 29970 url: util.ajaxUrl(Urls.onePageLogin), 29971 data: $form.serialize() + '&' + name + '=' + name 29972 })); 29973 } 29974 29975function showNotification(text, selector, msgType) { 29976 var $selector = $(selector); 29977 if ($selector.length == 0) { 29978 var $form = $('form.opc-login'), 29979 $selector = $('<span/>', {'class': 'login-notification', 'tabindex': '0'}).wrap('<div class="formfield clearfix error-box"><div class="form-row required"><div class="field-wrapper"></div></div></div>'); 29980 29981 $selector.parent().parent().parent().insertBefore('form.opc-login .form-row-button'); 29982 $selector = $(selector); 29983 } 29984 29985 $selector.removeClass('success error').addClass(msgType).text(text).focus(); 29986} 29987 29988function clearNotification(selector) { 29989 if(selector.length){ 29990 $('.formfield.error-box').remove(); 29991 selector.removeClass('success error'); 29992 } 29993} 29994 29995// GTM and Cordial tagging for cart opc-login 29996function opcLoginTagging($form, callback) { 29997 var email = $form.find('input[name*="username"]').val(); 29998 var auth_data = { 29999 email: email 30000 } 30001 var contact_data = { 30002 'channels': { 30003 'email': { 30004 'address': email 30005 } 30006 } 30007 }; 30008 var properties = { 30009 "email": email 30010 }; 30011 GoogleTagManagerClient.PushDataLayerForDataLayerType('CustomerLogin', { method: 'cart' }).then(function() { 30012 if (SitePreferences.CORDIAL_ENABLED) { 30013 if (typeof crdl !== 'undefined' && typeof crdl === 'function') { 30014 crdl([ 30015 ['contact', auth_data, contact_data],['event', 'login', properties] 30016 ]); 30017 } 30018 } 30019 if (callback) callback(); 30020 }); 30021} 30022 30023/** 30024 * Login reporting - increments counters in custom object 30025 * @param {String} type - login type 30026 * @param {String} source - Source of login, which can be original, cart, cart-modal, or wishlist-modal 30027 */ 30028function trackLoginActions(type, source) { 30029 if (!type || !source) { 30030 return; 30031 } 30032 30033 $.ajax({ 30034 type: 'POST', 30035 url: Urls.loginTracking, 30036 contentType: 'application/json', 30037 data: JSON.stringify({ 30038 type: type, 30039 source: source 30040 }), 30041 error: function(jqXHR, textStatus, errorThrown) { 30042 console.log('Login-TrackActions: Error in incrementing login action counters. ERROR TEXT: '+textStatus+', ERROR THROWN: '+errorThrown+'.'); 30043 }, 30044 success: function(response) { 30045 if (response) {} 30046 } 30047 }); 30048} 30049 30050/** 30051 * @private 30052 * @function 30053 * @description init login button event for the loginPage, loginDialog and checkout login 30054 */ 30055function initLoginButtons() { 30056 $(document).on('click', '#accountLoginButton', function(event) { 30057 event.preventDefault(); 30058 var dialogHtml = '<p style="padding: 10px;">Oops, something went wrong with login. Please try again later.</p>'; 30059 var $accountLoginButton = $(this); 30060 var $accountLoginForm = $accountLoginButton.closest('form#dwfrm_login'); 30061 var formUrl = $accountLoginForm.attr('action');
30062 var validationUrl = $accountLoginForm.attr('validation-url'); 30063 30064 // Clear previous form errors 30065 $accountLoginForm.find('input').removeClass('error'); 30066 $accountLoginForm.find('.login-dialog-error span').addClass('d-none'); 30067 30068 var isValidForm = validateLoginForm($accountLoginForm, ['email']); 30069 var isLoginDialog = formUrl.indexOf('loginDialog') >= 0; 30070 var formData = $accountLoginForm.serialize(); 30071 30072 if (!isLoginDialog) { 30073 $('[data-login-source]').attr('data-login-source', 'original'); // For reporting 30074 } 30075 30076 if (isValidForm) { 30077 $('body').loading(loadingIndicatorSettings); 30078 if (window['ownid'] && typeof window['ownidStartOtp'] === 'function') { 30079 if (formUrl.indexOf('SignUp') >= 0) { 30080 const urlParams = new URLSearchParams(window.location.search); 30081 const companyCode = urlParams.get('cc'); 30082 const companyKey = urlParams.get('key'); 30083 // Make ajax call to check if user exists before starting OTP process 30084 $.ajax({ 30085 type: 'POST', 30086 url: validationUrl, 30087 contentType: 'application/json', 30088 data: JSON.stringify({ 30089 email: $accountLoginForm.find('input[name*="_username"]').val().trim(), 30090 companyCode: companyCode, 30091 companyKey: companyKey 30092 }), 30093 success: function(data) { 30094 console.log('Login AJAX call successful. Data returned: ', data); 30095 if (typeof data === 'object' && 'result' in data) { 30096 $('body').loading('destroy'); 30097 if (data.result == 'error') { 30098 $('.error-form.login-dialog-error').removeClass('d-none'); 30099 $('.error-form.login-dialog-error span').removeClass('d-none'); 30100 $('.error-form.login-dialog-error span').html(data.message ? data.message : 'Login has failed. Please try again.'); 30101 } else { 30102 window.ownidStartOtp(); 30103 setTimeout(() => { $('body').loading('destroy') }, 3000); 30104 } 30105 } else { 30106 $('body').loading('destroy'); 30107 if (isLoginDialog) { 30108 errorHandling(data, 'Login - Error', dialogHtml); 30109 } else { 30110 window.location.href = location.href.split('?')[0]; 30111 } 30112 } 30113 }, 30114 error: function(jqXHR, textStatus, errorThrown) { 30115 console.log('Login Validation AJAX call failed. Error thrown: ', errorThrown); 30116 $('body').loading('destroy'); 30117 return; 30118 } 30119 }); 30120 } else { 30121 window.ownidStartOtp(); 30122 setTimeout(() => { $('body').loading('destroy') }, 3000); 30123 } 30124 } 30125 else { 30126 30127 // Using AJAX instead of default HTML button submit for login page and dialog 30128 $.ajax({ 30129 type: 'POST', 30130 url: formUrl, 30131 data: formData, 30132 success: function(data, textStatus, jqXHR) { 30133 console.log('Login AJAX call successful. Data returned: ', data); 30134 if (data.hideForm) { 30135 $('.form-create-account .form-body').hide(); 30136 } 30137 if (typeof data === 'object' && 'result' in data) { 30138 if (data.result == 'error') { 30139 $('body').loading('destroy'); 30140 $('.error-form.login-dialog-error span').removeClass('d-none'); 30141 if (data.successMessage) { 30142 $('.error-form').addClass('login-dialog-success'); 30143 } else { 30144 $('.error-form').removeClass('login-dialog-success'); 30145 } 30146 $('.error-form.login-dialog-error span').html(data.message ? data.message : 'Login has failed. Please try again.'); 30147 } else if (data.result == 'success' || data.result == 'complete') { 30148 $('body').loading('destroy'); 30149 // 'validateCustomer' property only returns in the data if this is a dialog. Otherwise, rewards validation happens through the URL using loginDialogContinueUrl. 30150 // If this is a rewards customer, and the cusomter account requires validation... 30151 if ('validateCustomer' in data && data.validateCustomer) { 30152 if (SitePreferences.CORDIAL_ENABLED) { 30153 loginCordialAccountEvent($accountLoginForm, isLoginDialog); 30154 } 30155 var newAttributes = { 30156 "data-modal-type": "login", 30157 "data-continue-url": 'loginDialogContinueUrl' in data ? data.loginDialogContinueUrl : '', 30158 "data-first-name": 'customerFirstName' in data ? data.customerFirstName : '', 30159 "data-store-number": 'storeFromProfile' in data ? data.storeFromProfile : '', 30160 "data-cart-quantity": 'cartQuantity' in data ? data.cartQuantity : '' 30161 } 30162 $('.login-dialog-validate-customer').html(data.validateCustomer); 30163 $('.login-dialog-validate-customer').addClass('validate-customer-show follow-account-dialog-path').attr(newAttributes); 30164 // Do this in two places: 30165 // (1) for login-dialog here because the element is only loaded into page via AJAX, 30166 // (2) init of page load for regular rewards verification pages through normal login flow 30167 initAddRulesForCodeInput(); 30168 } else { 30169 // Fire the cordial login event 30170 if (SitePreferences.CORDIAL_ENABLED) { 30171 loginCordialAccountEvent($accountLoginForm, isLoginDialog); 30172 } 30173 trackLoginActions('password', $('[data-login-source]').attr('data-login-source')); 30174 30175 // Handle follow-up actions accordingly 30176 $(document).trigger('PostAjaxAuthenticationActions.Initialize', { results: data, isAccountDialog: isLoginDialog, displayMessage: 'login' }); 30177 } 30178 } else { 30179 $('body').loading('destroy'); 30180 errorHandling(data, 'Login - Error', dialogHtml); 30181 } 30182 } else { 30183 $('body').loading('destroy'); 30184 if (isLoginDialog) { 30185 errorHandling(data, 'Login - Error', dialogHtml); 30186 } else { 30187 window.location.href = location.href.split('?')[0]; 30188 } 30189 } 30190 }, 30191 error: function(jqXHR, textStatus, errorThrown) { 30192 console.log('Login AJAX call failed. Error thrown: ', errorThrown); 30193 $('body').loading('destroy'); 30194 if (!isLoginDialog) { 30195 window.location.href = location.href.split('?')[0]; 30196 } 30197 } 30198 }); 30199 } 30200 } 30201 }); 30202 30203 $(document).on('click', '.opc-login-submit-button', function(event) { 30204 event.preventDefault(); 30205 var $opcLoginButton = $(this); 30206 var $opcLoginForm = $opcLoginButton.closest('form.opc-login'); 30207 var notificationSelector = $('.login-notification'); 30208 30209 $('body').loading(loadingIndicatorSettings); 30210 30211 $('[data-login-source]').attr('data-login-source', 'cart'); // For reporting 30212 $opcLoginForm.validate().form(); 30213 clearNotification(notificationSelector); 30214 updateCustomerDetails($opcLoginForm, $(this).attr('name')).then(function (response) { 30215 if (typeof response != 'object') { 30216 try { 30217 response = JSON.parse(response); 30218 } catch(e) { 30219 console.log(e); 30220 response = {}; 30221 } 30222 } 30223 if ('viewModel' in response && 'Customer' in response.viewM
30223odel && response.viewModel.Customer.authenticated == true) { 30224 Customer.authenticated = response.viewModel.Customer.authenticated; 30225 opcLoggedInCustomerAddresses = response.viewModel.Addresses; 30226 if ('validateCustomer' in response) { 30227 $.ajax({ 30228 type: 'GET', 30229 url: Urls.renderDialogTemplate, 30230 error: function(jqXHR, textStatus, errorThrown) { 30231 $('body').loading('destroy'); 30232 console.log(errorThrown); 30233 }, 30234 success: function(data) { 30235 if (data) { 30236 $('body').loading('destroy'); 30237 opcLoginTagging($opcLoginForm); 30238 var opcLoginContinueUrl = $('#cart-items-form').length ? Urls.onePage : Urls.account; 30239 30240 dialog.open({ 30241 html: data, 30242 options: { 30243 dialogClass: 'login-dialog', 30244 draggable: false, 30245 height: 600, 30246 open: function() { 30247 $('body').addClass('dialog-open'); 30248 $(this).scrollTop(0); 30249 if (SitePreferences.CORDIAL_ENABLED) { 30250 loginCordialAccountEvent($opcLoginForm, false); 30251 } 30252 30253 $('.ui-dialog.login-dialog').css('height', '430px'); 30254 $('.ui-dialog.login-dialog .login-dialog-forms-container').css('margin', '0 -8px'); 30255 $('.login-dialog-register-container').hide(); 30256 30257 var newAttributes = { 30258 "data-modal-type": "login", 30259 "data-continue-url": opcLoginContinueUrl, 30260 "data-first-name": 'customerFirstName' in response ? response.customerFirstName : '', 30261 "data-store-number": 'storeFromProfile' in response ? response.storeFromProfile : '', 30262 "data-cart-quantity": 'cartQuantity' in response ? response.cartQuantity : '', 30263 "data-opc-login": true 30264 } 30265 $('.login-dialog-validate-customer').html(response.validateCustomer); 30266 $('.login-dialog-validate-customer').addClass('validate-customer-show follow-account-dialog-path').attr(newAttributes); 30267 30268 initAddRulesForCodeInput(); 30269 30270 var $passwordReset = $(this).find('.login-dialog-forms-container #password-reset-button'); 30271 $passwordReset.attr('data-target', $passwordReset.attr('data-target') + '?loginDialog=true'); 30272 }, 30273 close: function() { 30274 $('body').removeClass('dialog-open'); 30275 } 30276 } 30277 }); 30278 } 30279 } 30280 }); 30281 } else { 30282 $('body').loading('destroy'); 30283 opcLoginTagging($opcLoginForm); 30284 trackLoginActions('password', $('[data-login-source]').attr('data-login-source')); 30285 location.href = Urls.onePage; 30286 } 30287 } else { 30288 $('body').loading('destroy'); 30289 $('.opc-login .field-wrapper input').addClass('error'); 30290 showNotification(Resources.PWD_EMAIL_ERROR, '.login-notification', 'error'); 30291 } 30292 }.bind(this)); 30293 }); 30294} 30295 30296function callNextController(url, callback) { 30297 $.ajax({ 30298 type: 'GET', 30299 url: url, 30300 contentType: 'application/json', 30301 error: function(jqXHR, textStatus, errorThrown) { 30302 }, 30303 success: function(response) { 30304 if (response) { 30305 if (callback) callback(response); 30306 } 30307 } 30308 }); 30309} 30310 30311/** 30312 * @private 30313 * @function 30314 * @description register on-click event for rewards validation > send code button 30315 * @notes changed the button.on('click') to a document.on('click') for HTML that is dynamically loaded in page with AJAX well after initial page load 30316 */ 30317function initValidateRewardsAccount() { 30318 $(document).on('click', '#validate-account button#send-code', function(event) { 30319 event.preventDefault(); 30320 30321 var $validateAccountForm = $('#validate-account'); 30322 var isAccountDialog = $('.login-dialog-validate-customer').hasClass('follow-account-dialog-path'); 30323 var sendType = $validateAccountForm.find('input[name=validate-account]:checked').attr('id').indexOf('none') > -1 ? 'none' : 'other'; 30324 30325 if (sendType == "none") { 30326 $.ajax({ 30327 type: 'post', 30328 url: Urls.createRewardsAccount, 30329 contentType: 'application/json', 30330 data: JSON.stringify({ 30331 firstName: $('.customer-account .first-name').text(), 30332 lastName: $('.customer-account .last-name').text(), 30333 emailAddress: $('.customer-account .email-address').text(), 30334 phoneNumber: $('.customer-account .phone-number').text(), 30335 zipCode: $('.customer-account .zip-code').text(), 30336 autoEnroll: false 30337 }), 30338 success: function (data) { 30339 console.log('Rewards account created.'); 30340 initVerificationDirection(); 30341 } 30342 }); 30343 } else { 30344 $.ajax({ 30345 url: Urls.sendValidationCode, 30346 dataType: 'JSON', 30347 method: 'POST', 30348 data: { 30349 'sendMethod': $validateAccountForm.find('input[name=validate-account]:checked').val(), 30350 'sendTo': $validateAccountForm.find('input[name=validate-account]:checked').attr('data-value') 30351 }, 30352 success : function(data) { 30353 var resultStatus = 'status' in data && data.status != 'pending' ? true : 'result' in data && 'status' in data.result && data.result.status != 'pending' ? true : false;
30354 if (('error' in data && data.error) || resultStatus) { 30355 $('.further-info').hide(); 30356 $('.verify-form').hide(); 30357 $('.verify-fail').removeClass('hidden'); 30358 } 30359 $('.account-recognized').hide(); 30360 if (isAccountDialog) { 30361 $('.verify-account').removeClass('hidden').addClass('validate-customer-show'); 30362 } else { 30363 $('.verify-account').removeClass('hidden'); 30364 } 30365 $('.' + sendType + '-method').removeClass('hidden'); 30366 }, 30367 complete: function(data, status, xhr) { 30368 if (data.status == 302 && data.responseText) { 30369 location.href = data.responseText; 30370 } 30371 } 30372 }); 30373 } 30374 }); 30375 30376 $(document).on('click', '#attach-rewards-button', function(event) { 30377 event.preventDefault(); 30378 var errorMessage = '<p style="padding: 10px;">Sorry, we were unable to finalize your rewards account updates.</p>'; 30379 var $attachRewardsForm = $('#attach-rewards-form'); 30380 var $selectedOption = $attachRewardsForm.find('input[name=attach-rewards-options]:checked'); 30381 var submittedEmail = $('.login-dialog-passcode-container, .otp-login-form-container').attr('data-email'); 30382 30383 if (!$selectedOption) { 30384 $('.attach-rewards-form-errors').removeClass('d-none'); 30385 return; 30386 } 30387 30388 $.ajax({ 30389 url: Urls.attachRewards, 30390 dataType: 'JSON', 30391 method: 'POST', 30392 data: { 30393 'option': $selectedOption.val(), 30394 'email': submittedEmail 30395 }, 30396 success : function(data) { 30397 if (data && data.result && data.result == 'success') { 30398 console.log('Rewards attachment complete.'); 30399 initVerificationDirection(); 30400 } else { 30401 errorHandling(data, 'Rewards Account - Error', errorMessage); 30402 } 30403 }, 30404 error: function(jqXHR, textStatus, errorThrown) { 30405 errorHandling(data, 'Rewards Account - Error', errorMessage); 30406 } 30407 }); 30408 }); 30409} 30410 30411/** 30412 * @private 30413 * @function 30414 * @description register on-click event for rewards validation > verify code button 30415 */ 30416function initVerifyCodeSent() { 30417 $(document).on('click', '#verify-code button#verify-user', function(event) { 30418 event.preventDefault(); 30419 30420 var $verifyCodeForm = $('#verify-code'); 30421 if (!$verifyCodeForm.valid()) { 30422 return false; 30423 } 30424 30425 $.ajax({ 30426 url: Urls.verifySubmittedCode, 30427 dataType: 'JSON', 30428 method: 'POST', 30429 data: { 30430 'code': $verifyCodeForm.find('input[name=enter-code]', '#verify-code').val(), 30431 'sendTo': $('#validate-account').find('input[name=validate-account]:checked').attr('data-value') 30432 }, 30433 success : function(data) { 30434 if (('error' in data && data.error) || ('status' in data && data.status != 'approved')) { 30435 $('.further-info').hide(); 30436 $('.verify-form').hide(); 30437 $('.verify-fail').removeClass('hidden'); 30438 } else { 30439 console.log('Rewards verification complete.'); 30440 initVerificationDirection(); 30441 } 30442 }, 30443 complete: function(data, status, xhr) { 30444 if (data.status == 302 && data.responseText) { 30445 location.href = data.responseText; 30446 } 30447 } 30448 }); 30449 }); 30450} 30451 30452/** 30453 * @private 30454 * @function 30455 * @description directs the page load or the page redraw after rewards verification screen 30456 */ 30457function initVerificationDirection() { 30458 var $validateDialog = $('.login-dialog-validate-customer'); 30459 var isAccountDialog = $('.login-dialog-validate-customer').hasClass('follow-account-dialog-path'); 30460 var dataModalType, dataNextControllerUrl, dataContinueUrl, dataFirstName, dataStore, dataCartQuantity, isOpcLogin; 30461 30462 if ($validateDialog.length) { 30463 dataModalType = $validateDialog.attr('data-modal-type'); 30464 dataNextControllerUrl = $validateDialog.attr('data-next-controller-url'); 30465 dataContinueUrl = $validateDialog.attr('data-continue-url'); 30466 dataFirstName = $validateDialog.attr('data-first-name'); 30467 dataStore = $validateDialog.attr('data-store-number'); 30468 dataCartQuantity = $validateDialog.attr('data-cart-quantity'); 30469 isOpcLogin = $validateDialog.attr('data-opc-login') == 'true'; 30470 30471 if (isOpcLogin) { 30472 dialog.close(); 30473 location.href = Urls.onePage; 30474 } 30475 if (isAccountDialog) { 30476 if (dataNextControllerUrl) { 30477 callNextController(dataNextControllerUrl, function(response) { 30478 if (response && 'result' in response && (response.result == 'success' || response.result == 'complete')) { 30479 response.customerFirstName = dataFirstName; 30480 response.storeFromProfile = dataStore; 30481 response.cartQuantity = dataCartQuantity; 30482 // Handle follow-up actions accordingly 30483 $(document).trigger('PostAjaxAuthenticationActions.Initialize', { results: response, isAccountDialog: isAccountDialog, displayMessage: dataModalType }); 30484 } 30485 }); 30486 } else { 30487 if (dataContinueUrl) { 30488 location.href = dataContinueUrl; 30489 } else { 30490 location.href = Urls.account; 30491 } 30492 } 30493 } 30494 } else { 30495 location.href = Urls.account; 30496 } 30497} 30498 30499/** 30500 * @private 30501 * @function 30502 * @description add rules to code input field 30503 */ 30504function initAddRulesForCodeInput() { 30505 $('form#verify-code').validate(); 30506 $('#verify-code #enter-code').rules('add', { 30507 required: true, 30508 digits: true, 30509 minlength: 6, 30510 messages: {
30511 required: Resources.VALIDATE_CODE, 30512 minlength: Resources.VALIDATE_CODE 30513 }, 30514 normalizer: function(value) { 30515 return $.trim(value); 30516 } 30517 }); 30518} 30519 30520/** 30521 * @private 30522 * @function 30523 * @description register on-click event for rewards validation > verify code > resend code link 30524 */ 30525function initResendValidationCode() { 30526 $(document).on('click', '.verify-account a.resend-code', function(event) { 30527 event.preventDefault(); 30528 if ($('.login-dialog-validate-customer').hasClass('follow-account-dialog-path')) { 30529 $('.verify-account, .further-info span').addClass('hidden'); 30530 $('.account-recognized').css('left','-9999px').removeClass('hidden').show().addClass('validate-customer-show'); 30531 } else { 30532 location.reload(); 30533 } 30534 }); 30535} 30536 30537/** 30538 * @private 30539 * @function 30540 * @description register on-click events for reset-password flow 30541 */ 30542function initResetPasswordEvents() { 30543 // Show reset password form 30544 $(document).on('click', '#password-reset-button', function(event) { 30545 event.preventDefault(); 30546 var $resetPasswordButton = $(this); 30547 var resetDialogUrl = $resetPasswordButton.attr('data-target'); 30548 var isLoginDialog = resetDialogUrl.indexOf('loginDialog') >= 0; 30549 30550 if (isLoginDialog) { 30551 $('body').loading(loadingIndicatorSettings); 30552 var dialogHtml = '<p style="padding: 10px;">Oops, something went wrong with Password Reset. Please try again later.</p>'; 30553 30554 $.ajax({ 30555 type: 'GET', 30556 url: resetDialogUrl, 30557 success: function(data, textStatus, jqXHR) { 30558 if (typeof data === 'object' && 'result' in data) { 30559 if (data.result == 'complete') { 30560 $('body').loading('destroy'); 30561 // If we received HTML in the data for displaying the reset password form, then dis
30561play it... 30562 if ('resetPasswordForm' in data && data.resetPasswordForm) { 30563 $('.login-dialog-reset-password').html(data.resetPasswordForm); 30564 $('.login-dialog-reset-password').addClass('reset-password-show'); 30565 $('.login-dialog-reset-password').find('#PasswordResetForm').attr('action', $('.login-dialog-reset-password').find('#PasswordResetForm').attr('action') + '?loginDialog=true'); 30566 renderRecaptchaForPasswordReset(); 30567 } else { 30568 $('body').loading('destroy'); 30569 errorHandling(data, 'Reset Password - Error', dialogHtml); 30570 } 30571 } else { 30572 $('body').loading('destroy'); 30573 errorHandling(data, 'Reset Password - Error', dialogHtml); 30574 } 30575 } else { 30576 $('body').loading('destroy'); 30577 if (isLoginDialog) { 30578 errorHandling(data, 'Reset Password - Error', dialogHtml); 30579 } else { 30580 window.location.href = location.href; 30581 } 30582 } 30583 }, 30584 error: function(jqXHR, textStatus, errorThrown) { 30585 $('body').loading('destroy'); 30586 if (!isLoginDialog) { 30587 window.location.href = location.href; 30588 } 30589 } 30590 }); 30591 } else if (SitePreferences.RESET_POPUP_ENABLED) { 30592 dialog.open({ 30593 url: resetDialogUrl, 30594 options: { 30595 dialogClass: 'resetpwdpopup', 30596 width: 385, 30597 open: function () { 30598 renderRecaptchaForPasswordReset(); 30599 $(".reset-password-heading-close-btn, .ui-widget-overlay").on('click',function(){ 30600 $("button.ui-dialog-titlebar-close").click(); 30601 }); 30602 } 30603 } 30604 }); 30605 } else { 30606 window.location.href = resetDialogUrl; 30607 } 30608 }); 30609 30610 // Submit reset password form 30611 $(document).on('click.ResetPassword', '#request-password-send-btn, [name$="_requestpassword_send"]', function(event) { 30612 if (!options || !options.Recaptcha || !options.Recaptcha.EnabledForPasswordReset) { 30613 resetPassword(event, $(this)); 30614 } 30615 }); 30616 30617 $(document).on('Account.ResetPassword', function (event, data) { 30618 resetPassword(event, null, true); 30619 }); 30620} 30621 30622function resetPassword(event, $resetPasswordSendButton, isRecaptchaEvent) { 30623 if (!$resetPasswordSendButton) { 30624 $resetPasswordSendButton = $('#request-password-send-btn'); 30625 } 30626 30627 var $resetPasswordSendForm = $resetPasswordSendButton.closest('form#PasswordResetForm'); 30628 var isLoginDialog = $resetPasswordSendForm.attr('action').indexOf('loginDialog') >= 0; 30629 30630 // Try to prevent the form submission as quickly as possible before doing all of the other logic 30631 if (isLoginDialog || (SitePreferences.RESET_POPUP_ENABLED && dialog.isActive())) { 30632 event.preventDefault(); 30633 } 30634 30635 validator.init(); 30636 var isValidForm = $resetPasswordSendForm.valid(); 30637 30638 if (isValidForm) { 30639 if (isLoginDialog) { 30640 $('body').loading(loadingIndicatorSettings); 30641 var dialogHtml = '<p style="padding: 10px;">Oops, something went wrong with Password Reset. Please try again later.</p>'; 30642 var formData = $resetPasswordSendForm.serialize(); 30643 formData += '&' + $resetPasswordSendButton.attr('name') + '=' + $resetPasswordSendButton.attr('name'); 30644 30645 $.ajax({ 30646 type: 'POST', 30647 url: $resetPasswordSendForm.attr('action'), 30648 data: formData, 30649 success: function(data, textStatus, jqXHR) { 30650 if (typeof data === 'object' && 'result' in data) { 30651 if (data.result == 'complete') { 30652 $('body').loading('destroy'); 30653 // If reset password email was sent, show confirmation within the dialog 30654 if ('resetPasswordConfirmation' in data && data.resetPasswordConfirmation) { 30655 $('.login-dialog-reset-password').html(data.resetPasswordConfirmation); 30656 $('.login-dialog-reset-password').addClass('reset-password-show'); 30657 passwordResetNoAccountCordialEvent('.login-dialog-reset-password'); 30658 } else { 30659 $('body').loading('destroy'); 30660 errorHandling(data, 'Reset Password - Error', dialogHtml); 30661 } 30662 } else { 30663 $('body').loading('destroy'); 30664 errorHandling(data, 'Reset Password - Error', dialogHtml); 30665 } 30666 } else { 30667 $('body').loading('destroy'); 30668 if (isLoginDialog) { 30669 errorHandling(data, 'Reset Password - Error', dialogHtml); 30670 } else { 30671 window.location.href = location.href; 30672 } 30673 } 30674 }, 30675 error: function(jqXHR, textStatus, errorThrown) { 30676 $('body').loading('destroy'); 30677 if (!isLoginDialog) { 30678 window.location.href = location.href; 30679 } 30680 } 30681 }); 30682 } else if (SitePreferences.RESET_POPUP_ENABLED && dialog.isActive()) { 30683 dialog.submit($resetPasswordSendButton.attr('name'), function() { 30684 passwordResetNoAccountCordialEvent('.resetpwdpopup'); 30685 }); 30686 } else if (isRecaptchaEvent) { 30687 $resetPasswordSendForm.append('<input type="hidden" name="' + $resetPasswordSendButton.attr('name') + '" value="' + $resetPasswordSendButton.val() + '"/>') 30688 $resetPasswordSendForm.submit(); 30689 } 30690 } 30691} 30692 30693module.exports = { 30694 init: function (optionsParameter) { 30695 options = optionsParameter; 30696 30697 initLoginEvents(); 30698 if (options && options.Recaptcha && (options.Recaptcha.EnabledForAccountLogin || options.Recaptcha.EnabledForPasswordReset)) { 30699 $(document).on('Recaptcha.Loaded', function(event) { 30700 if (!loaded.Recaptcha) { 30701 loaded.Recaptcha = true; 30702 renderRecaptchaForLogin(); 30703 renderRecaptchaForPasswordReset(); 30704 } 30705 }); 30706 30707 recaptcha.initialize(); 30708 initializeRecaptchaForLogin(); 30709 renderRecaptchaForPasswordReset(); 30710 } 30711 initLoginButtons(); 30712 initValidateRewardsAccount(); 30713 initVerifyCodeSent(); 30714 initResendValidationCode(); 30715 initAddRulesForCodeInput(); 30716 initResetPasswordEvents(); 30717 } 30718}; 30719},{"../../../app_storefront_core/cartridge/js/components/LoadingIndicator":25,"../../../app_storefront_core/cartridge/js/components/Recaptcha":29,"../../../app_storefront_core/cartridge/js/dialog":36,"../../../app_storefront_core/cartridge/js/loginDialog":44,"../../../app_storefront_whip/cartridge/js/util":107,"../../../app_storefront_whip/cartridge/js/validator":108,"../../../bc_sheplersbootbarn_core/cartridge/js/SiteConstants":120,"../../../bc_sheplersbootbarn_core/cartridge/js/util/GoogleTagManagerClient":123,"promise":134}],110:[function(require,module,exports){ 30720module.exports={"NY":{"005":true,"063":true,"100":true,"101":true,"102":true,"103":true,"104":true,"105":true,"106":true,"107":true,"108":true,"109":true,"110":true,"111":true,"112":true,"113":true,"114":true,"115":true,"116":true,"117":true,"118":true,"119":true,"120":true,"121":true,"122":true,"123":true,"124":true,"125":true,"126":true,"127":true,"128":true,"129":true,"130":true,"131":true,"132":true,"133":true,"134":true,"135":true,"136":true,"137":true,"138":true,"139":true,"140":true,"141":true,"142":true,"143":true,"144":true,"145":true,"146":true,"147":true,"148":true,"149":true},"PR":{"006":true,"007":true,"008":true,"009":true},"VI":{"006":true,"007":true,"008":true,"009":true},"MA":{"010":true,"011":true,"012":true,"013":true,"014":true,"015":true,"016":true,"017":true,"018":true,"019":true,"020":true,"021":true,"022":true,"023":true,"024":true,"025":true,"026":true,"027":true,"055":true},"RI":{"028":true,"029":true},"NH":{"030":true,"031":true,"032":true,"033":true,"034":true,"035":true,"036":true,"037":true,"038":true,"039":true},"VT":{"035":true,"036":true,"037":true,"050":true,"051":true,"052":true,"053":true,"054":true,"056":true,"057":true,"058":true,"059":true},"ME":{"039":true,"040":true,"041":true,"042":true,"043":true,"044":true,"045":true,"046":true,"047":true,"048":true,"049":true},"CT":{"060":true,"061":true,"062":true,"063":true,"064":true,"065":true,"066":true,"067":true,"068":true,"069":true},"NJ":{"070":true,"071":true,"072":true,"073":true,"074":true,"075":true,"076":true,"077":true,"078":true,"079":true,"080":true,"081":true,"082":true,"083":true,"084":true,"085":true,"086":true,"087":true,"088":true,"089":true},"AE":{"090":true,"091":true,"092":true,"093":true,"094":true,"095":true,"096":true,"097":true,"098":true,"099":true},"PA":{"150":true,"151":true,"152":true,"153":true,"154":true,"155":true,"156":true,"157":true,"158":true,"159":true,"160":true,"161":true,"162":true,"163":true,"164":true,"165":true,"166":true,"167":true,"168":true,"169":true,"170":true,"171":true,"172":true,"173":true,"174":true,"175":true,"176":true,"177":true,"178":true,"179":true,"180":true,"181":true,"182":true,"183":true,"184":true,"185":true,"186":true,"187":true,"188":true,"189":true,"190":true,"191":true,"192":true,"193":true,"194":true,"195":true,"196":true,"197":true},"DE":{"197":true,"198":true,"199":true},"DC":{"200":true,"202":true,"203":true,"204":true,"205":true},"VA":{"201":true,"220":true,"221":true,"222":true,"223":true,"224":true,"225":true,"226":true,"227":true,"228":true,"229":true,"230":true,"231":true,"232":true,"233":true,"234":true,"235":true,"236":true,"237":true,"238":true,"239":true,"240":true,"241":true,"242":true,"243":true,"244":true,"245":true,"246":true},"MD":{"206":true,"207":true,"208":true,"209":true,"210":true,"211":true,"212":true,"214":true,"215":true,"216":true,"217":true,"218":true,"219":true,"267":true},"WV":{"246":true,"247":true,"248":true,"249":true,"250":true,"251":true,"252":true,"253":true,"254":true,"255":true,"256":true,"257":true,"258":true,"259":true,"260":true,"261":true,"262":true,"263":true,"264":true,"265":true,"266":true,"267":true,"268":true},"NC":{"270":true,"271":true,"272":true,"273":true,"274":true,"275":true,"276":true,"277":true,"278":true,"279":true,"280":true,"281":true,"282":true,"283":true,"284":true,"285":true,"286":true,"287":true,"288":true,"289":true,"297":true},"SC":{"290":true,"291":true,"292":true,"293":true,"294":true,"295":true,"296":true,"297":true,"298":true,"299":true},"GA":{"298":true,"299":true,"300":true,"301":true,"302":true,"303":true,"304":true,"305":true,"306":true,"307":true,"308":true,"309":true,"310":true,"311":true,"312":true,"313":true,"314":true,"315":true,"316":true,"317":true,"318":true,"319":true,"398":true,"399":true},"FL":{"320":true,"321":true,"322":true,"323":true,"324":true,"325":true,"326":true,"327":true,"328":true,"329":true,"330":true,"331":true,"332":true,"333":true,"334":true,"335":true,"336":true,"337":true,"338":true,"339":true,"341":true,"342":true,"344":true,"346":true,"347":true,"349":true},"AA":{"331":true,"340":true},"AP":{"340":true,"962":true,"963":true,"964":true,"965":true,"966":true},"AL":{"350":true,"351":true,"352":true,"354":true,"355":true,"356":true,"357":true,"358":true,"359":true,"360":true,"361":true,"362":true,"363":true,"364":true,"365":true,"366":true,"367":true,"368":true,"369":true},"MS":{"369":true,"370":true,"386":true,"387":true,"388":true,"389":true,"390":true,"391":true,"392":true,"393":true,"394":true,"395":true,"396":true,"397":true},"TN":{"370":true,"371":true,"372":true,"373":true,"374":true,"375":true,"376":true,"377":true,"378":true,"379":true,"380":true,"381":true,"382":true,"383":true,"384":true,"385":true,"386":true,"723":true},"KY":{"400":true,"401":true,"402":true,"403":true,"404":true,"405":true,"406":true,"407":true,"408":true,"409":true,"410":true,"411":true,"412":true,"413":true,"414":true,"415":true,"416":true,"417":true,"418":true,"420":true,"421":true,"422":true,"423":true,"424":true,"425":true,"426":true,"427":true,"471":true},"OH":{"410":true,"430":true,"431":true,"432":true,"433":true,"434":true,"435":true,"436":true,"437":true,"438":true,"439":true,"440":true,"441":true,"442":true,"443":true,"444":true,"445":true,"446":true,"447":true,"448":true,"449":true,"450":true,"451":true,"452":true,"453":true,"454":true,"455":true,"456":true,"457":true,"458":true,"459":true,"470":true,"472":true},"IN":{"424":true,"460":true,"461":true,"462":true,"463":true,"464":true,"465":true,"466":true,"467":true,"468":true,"469":true,"470":true,"471":true,"472":true,"473":true,"474":true,"475":true,"476":true,"477":true,"478":true,"479":true},"MI":{"480":true,"481":true,"482":true,"483":true,"484":true,"485":true,"486":true,"487":true,"488":true,"489":true,"490":true,"491":true,"492":true,"493":true,"494":true,"495":true,"496":true,"497":true,"498":true,"499":true},"IA":{"500":true,"501":true,"502":true,"503":true,"504":true,"505":true,"506":true,"507":true,"508":true,"509":true,"510":true,"511":true,"512":true,"513":true,"514":true,"515":true,"516":true,"520":true,"521":true,"522":true,"523":true,"524":true,"525":true,"526":true,"527":true,"528":true},"NE":{"515":true,"516":true,"680":true,"681":true,"683":true,"684":true,"685":true,"686":true,"687":true,"688":true,"689":true,"690":true,"691":true,"692":true,"693":true},"IL":{"527":true,"600":true,"601":true,"602":true,"603":true,"604":true,"605":true,"606":true,"607":true,"608":true,"609":true,"610":true,"611":true,"612":true,"613":true,"614":true,"615":true,"616":true,"617":true,"618":true,"619":true,"620":true,"622":true,"623":true,"624":true,"625":true,"626":true,"627":true,"628":true,"629":true,"634":true,"635":true},"WI":{"530":true,"531":true,"532":true,"534":true,"535":true,"537":true,"538":true,"539":true,"540":true,"541":true,"542":true,"543":true,"544":true,"545":true,"546":true,"547":true,"548":true,"549":true},"MN":{"540":true,"550":true,"551":true,"553":true,"554":true,"556":true,"557":true,"558":true,"559":true,"560":true,"561":true,"562":true,"563":true,"564":true,"565":true,"566":true,"567":true},"ND":{"567":true,"580":true,"581":true,"582":true,"583":true,"584":true,"585":true,"586":true,"587":true,"588":true},"SD":{"570":true,"571":true,"572":true,"573":true,"574":true,"575":true,"576":true,"577":true},"MT":{"590":true,"591":true,"592":true,"593":true,"594":true,"595":true,"596":true,"597":true,"598":true,"599":true},"MO":{"620":true,"622":true,"630":true,"631":true,"633":true,"634":true,"635":true,"636":true,"637":true,"638":true,"639":true,"640":true,"641":true,"644":true,"645":true,"646":true,"647":true,"648":true,"649":true,"650":true,"651":true,"652":true,"653":true,"654":true,"655":true,"656":true,"657":true,"658":true},"KS":{"660":true,"661":true,"662":true,"664":true,"665":true,"666":true,"667":true,"668":true,"669":true,"670":true,"671":true,"672":true,"673":true,"674":true,"675":true,"676":true,"677":true,"678":true,"679":true},"LA":{"700":true,"701":true,"703":true,"704":true,"705":true,"706":true,"707":true,"708":true,"710":true,"711":true,"712":true,"713":true,"714":true},"AR":{"716":true,"717":true,"718":true,"719":true,"720":true,"721":true,"722":true,"723":true,"724":true,"725":true,"726":true,"727":true,"728":true,"729":true},"OK":{"730":true,"731":true,"734":true,"735":true,"736":true,"737":true,"738":true,"739":true,"740":true,"741":true,"743":true,"744":true,"745":true,"746":true,"747":true,"748":true,"749":true},"TX":{"733":true,"739":true,"750":true,"751":true,"752":true,"753":true,"754":true,"755":true,"756":true,"757":true,"758":true,"759":true,"760":true,"761":true,"762":true,"763":true,"764":true,"765":true,"766":true,"767":true,"768":true,"769":true,"770":true,"771":true,"772":true,"773":true,"774":true,"775":true,"776":true,"777":true,"778":true,"779":true,"780":true,"781":true,"782":true,"783":true,"784":true,"785":true,"786":true,"787":true,"788":true,"789":true,"790":true,"791":true,"792":true,"793":true,"794":true,"795":true,"796":true,"797":true,"798":true,"799":true,"885":true},"CO":{"800":true,"801":true,"802":true,"803":true,"804":true,"805":true,"806":true,"807":true,"808":true,"809":true,"810":true,"811":true,"812":true,"813":true,"814":true,"815":true,"816":true},"WY":{"820":true,"821":true,"822":true,"823":true,"824":true,"825":true,"826":true,"827":true,"828":true,"829":true,"830":true,"831":true,"834":true},"ID":{"832":true,"833":true,"834":true,"835":true,"836":true,"837":true,"838":true,"979":true,"994":true},"WA":{"838":true,"980":true,"981":true,"982":true,"983":true,"984":true,"985":true,
30720"986":true,"988":true,"989":true,"990":true,"991":true,"992":true,"993":true,"994":true},"UT":{"840":true,"841":true,"842":true,"843":true,"844":true,"845":true,"846":true,"847":true},"AZ":{"850":true,"851":true,"852":true,"853":true,"855":true,"856":true,"857":true,"859":true,"860":true,"863":true,"864":true,"865":true},"NM":{"870":true,"871":true,"872":true,"873":true,"874":true,"875":true,"877":true,"878":true,"879":true,"880":true,"881":true,"882":true,"883":true,"884":true},"NV":{"877":true,"889":true,"890":true,"891":true,"893":true,"894":true,"895":true,"897":true,"898":true,"961":true},"CA":{"900":true,"901":true,"902":true,"903":true,"904":true,"905":true,"906":true,"907":true,"908":true,"910":true,"911":true,"912":true,"913":true,"914":true,"915":true,"916":true,"917":true,"918":true,"919":true,"920":true,"921":true,"922":true,"923":true,"924":true,"925":true,"926":true,"927":true,"928":true,"930":true,"931":true,"932":true,"933":true,"934":true,"935":true,"936":true,"937":true,"938":true,"939":true,"940":true,"941":true,"942":true,"943":true,"944":true,"945":true,"946":true,"947":true,"948":true,"949":true,"950":true,"951":true,"952":true,"953":true,"954":true,"955":true,"956":true,"957":true,"958":true,"959":true,"960":true,"961":true},"HI":{"967":true,"968":true},"AS":{"967":true},"GU":{"969":true},"MH":{"969":true},"OR":{"970":true,"971":true,"972":true,"973":true,"974":true,"975":true,"976":true,"977":true,"978":true,"979":true,"986":true},"AK":{"995":true,"996":true,"997":true,"998":true,"999":true}} 30721},{}],111:[function(require,module,exports){ 30722module.exports={"100":"NY","101":"NY","102":"NY","103":"NY","104":"NY","105":"NY","106":"NY","107":"NY","108":"NY","109":"NY","110":"NY","111":"NY","112":"NY","113":"NY","114":"NY","115":"NY","116":"NY","117":"NY","118":"NY","119":"NY","120":"NY","121":"NY","122":"NY","123":"NY","124":"NY","125":"NY","126":"NY","127":"NY","128":"NY","129":"NY","130":"NY","131":"NY","132":"NY","133":"NY","134":"NY","135":"NY","136":"NY","137":"NY","138":"NY","139":"NY","140":"NY","141":"NY","142":"NY","143":"NY","144":"NY","145":"NY","146":"NY","147":"NY","148":"NY","149":"NY","150":"PA","151":"PA","152":"PA","153":"PA","154":"PA","155":"PA","156":"PA","157":"PA","158":"PA","159":"PA","160":"PA","161":"PA","162":"PA","163":"PA","164":"PA","165":"PA","166":"PA","167":"PA","168":"PA","169":"PA","170":"PA","171":"PA","172":"PA","173":"PA","174":"PA","175":"PA","176":"PA","177":"PA","178":"PA","179":"PA","180":"PA","181":"PA","182":"PA","183":"PA","184":"PA","185":"PA","186":"PA","187":"PA","188":"PA","189":"PA","190":"PA","191":"PA","192":"PA","193":"PA","194":"PA","195":"PA","196":"PA","197":"DE","198":"DE","199":"DE","200":"DC","201":"VA","202":"DC","203":"DC","204":"DC","205":"DC","206":"MD","207":"MD","208":"MD","209":"MD","210":"MD","211":"MD","212":"MD","214":"MD","215":"MD","216":"MD","217":"MD","218":"MD","219":"MD","220":"VA","221":"VA","222":"VA","223":"VA","224":"VA","225":"VA","226":"VA","227":"VA","228":"VA","229":"VA","230":"VA","231":"VA","232":"VA","233":"VA","234":"VA","235":"VA","236":"VA","237":"VA","238":"VA","239":"VA","240":"VA","241":"VA","242":"VA","243":"VA","244":"VA","245":"VA","246":"WV","247":"WV","248":"WV","249":"WV","250":"WV","251":"WV","252":"WV","253":"WV","254":"WV","255":"WV","256":"WV","257":"WV","258":"WV","259":"WV","260":"WV","261":"WV","262":"WV","263":"WV","264":"WV","265":"WV","266":"WV","267":"WV","268":"WV","270":"NC","271":"NC","272":"NC","273":"NC","274":"NC","275":"NC","276":"NC","277":"NC","278":"NC","279":"NC","280":"NC","281":"NC","282":"NC","283":"NC","284":"NC","285":"NC","286":"NC","287":"NC","288":"NC","289":"NC","290":"SC","291":"SC","292":"SC","293":"SC","294":"SC","295":"SC","296":"SC","297":"SC","298":"GA","299":"GA","300":"GA","301":"GA","302":"GA","303":"GA","304":"GA","305":"GA","306":"GA","307":"GA","308":"GA","309":"GA","310":"GA","311":"GA","312":"GA","313":"GA","314":"GA","315":"GA","316":"GA","317":"GA","318":"GA","319":"GA","320":"FL","321":"FL","322":"FL","323":"FL","324":"FL","325":"FL","326":"FL","327":"FL","328":"FL","329":"FL","330":"FL","331":"AA","332":"FL","333":"FL","334":"FL","335":"FL","336":"FL","337":"FL","338":"FL","339":"FL","340":"AP","341":"FL","342":"FL","344":"FL","346":"FL","347":"FL","349":"FL","350":"AL","351":"AL","352":"AL","354":"AL","355":"AL","356":"AL","357":"AL","358":"AL","359":"AL","360":"AL","361":"AL","362":"AL","363":"AL","364":"AL","365":"AL","366":"AL","367":"AL","368":"AL","369":"MS","370":"TN","371":"TN","372":"TN","373":"TN","374":"TN","375":"TN","376":"TN","377":"TN","378":"TN","379":"TN","380":"TN","381":"TN","382":"TN","383":"TN","384":"TN","385":"TN","386":"TN","387":"MS","388":"MS","389":"MS","390":"MS","391":"MS","392":"MS","393":"MS","394":"MS","395":"MS","396":"MS","397":"MS","398":"GA","399":"GA","400":"KY","401":"KY","402":"KY","403":"KY","404":"KY","405":"KY","406":"KY","407":"KY","408":"KY","409":"KY","410":"OH","411":"KY","412":"KY","413":"KY","414":"KY","415":"KY","416":"KY","417":"KY","418":"KY","420":"KY","421":"KY","422":"KY","423":"KY","424":"IN","425":"KY","426":"KY","427":"KY","430":"OH","431":"OH","432":"OH","433":"OH","434":"OH","435":"OH","436":"OH","437":"OH","438":"OH","439":"OH","440":"OH","441":"OH","442":"OH","443":"OH","444":"OH","445":"OH","446":"OH","447":"OH","448":"OH","449":"OH","450":"OH","451":"OH","452":"OH","453":"OH","454":"OH","455":"OH","456":"OH","457":"OH","458":"OH","459":"OH","460":"IN","461":"IN","462":"IN","463":"IN","464":"IN","465":"IN","466":"IN","467":"IN","468":"IN","469":"IN","470":"IN","471":"IN","472":"IN","473":"IN","474":"IN","475":"IN","476":"IN","477":"IN","478":"IN","479":"IN","480":"MI","481":"MI","482":"MI","483":"MI","484":"MI","485":"MI","486":"MI","487":"MI","488":"MI","489":"MI","490":"MI","491":"MI","492":"MI","493":"MI","494":"MI","495":"MI","496":"MI","497":"MI","498":"MI","499":"MI","500":"IA","501":"IA","502":"IA","503":"IA","504":"IA","505":"IA","506":"IA","507":"IA","508":"IA","509":"IA","510":"IA","511":"IA","512":"IA","513":"IA","514":"IA","515":"NE","516":"NE","520":"IA","521":"IA","522":"IA","523":"IA","524":"IA","525":"IA","526":"IA","527":"IL","528":"IA","530":"WI","531":"WI","532":"WI","534":"WI","535":"WI","537":"WI","538":"WI","539":"WI","540":"MN","541":"WI","542":"WI","543":"WI","544":"WI","545":"WI","546":"WI","547":"WI","548":"WI","549":"WI","550":"MN","551":"MN","553":"MN","554":"MN","556":"MN","557":"MN","558":"MN","559":"MN","560":"MN","561":"MN","562":"MN","563":"MN","564":"MN","565":"MN","566":"MN","567":"ND","570":"SD","571":"SD","572":"SD","573":"SD","574":"SD","575":"SD","576":"SD","577":"SD","580":"ND","581":"ND","582":"ND","583":"ND","584":"ND","585":"ND","586":"ND","587":"ND","588":"ND","590":"MT","591":"MT","592":"MT","593":"MT","594":"MT","595":"MT","596":"MT","597":"MT","598":"MT","599":"MT","600":"IL","601":"IL","602":"IL","603":"IL","604":"IL","605":"IL","606":"IL","607":"IL","608":"IL","609":"IL","610":"IL","611":"IL","612":"IL","613":"IL","614":"IL","615":"IL","616":"IL","617":"IL","618":"IL","619":"IL","620":"MO","622":"MO","623":"IL","624":"IL","625":"IL","626":"IL","627":"IL","628":"IL","629":"IL","630":"MO","631":"MO","633":"MO","634":"MO","635":"MO","636":"MO","637":"MO","638":"MO","639":"MO","640":"MO","641":"MO","644":"MO","645":"MO","646":"MO","647":"MO","648":"MO","649":"MO","650":"MO","651":"MO","652":"MO","653":"MO","654":"MO","655":"MO","656":"MO","657":"MO","658":"MO","660":"KS","661":"KS","662":"KS","664":"KS","665":"KS","666":"KS","667":"KS","668":"KS","669":"KS","670":"KS","671":"KS","672":"KS","673":"KS","674":"KS","675":"KS","676":"KS","677":"KS","678":"KS","679":"KS","680":"NE","681":"NE","683":"NE","684":"NE","685":"NE","686":"NE","687":"NE","688":"NE","689":"NE","690":"NE","691":"NE","692":"NE","693":"NE","700":"LA","701":"LA","703":"LA","704":"LA","705":"LA","706":"LA","707":"LA","708":"LA","710":"LA","711":"LA","712":"LA","713":"LA","714":"LA","716":"AR","717":"AR","718":"AR","719":"AR","720":"AR","721":"AR","722":"AR","723":"AR","724":"AR","725":"AR","726":"AR","727":"AR","728":"AR","729":"AR","730":"OK","731":"OK","733":"TX","734":"OK","735":"OK","736":"OK","737":"OK","738":"OK","739":"TX","740":"OK","741":"OK","743":"OK","744":"OK","745":"OK","746":"OK","747":"OK","748":"OK","749":"OK","750":"TX","751":"TX","752":"TX","753":"TX","754":"TX","755":"TX","756":"TX","757":"TX","758":"TX","759":"TX","760":"TX","761":"TX","762":"TX","763":"TX","764":"TX","765":"TX","766":"TX","767":"TX","768":"TX","769":"TX","770":"TX","771":"TX","772":"TX","773":"TX","774":"TX","775":"TX","776":"TX","777":"TX","778":"TX","779":"TX","780":"TX","781":"TX","782":"TX","783":"TX","784":"TX","785":"TX","786":"TX","787":"TX","788":"TX","789":"TX","790":"TX","791":"TX","792":"TX","793":"TX","794":"TX","795":"TX","796":"TX","797":"TX","798":"TX","799":"TX","800":"CO","801":"CO","802":"CO","803":"CO","804":"CO","805":"CO","806":"CO","807":"CO","808":"CO","809":"CO","810":"CO","811":"CO","812":"CO","813":"CO","814":"CO","815":"CO","816":"CO","820":"WY","821":"WY","822":"WY","823":"WY","824":"WY","825":"WY","826":"WY","827":"WY","828":"WY","829":"WY","830":"WY","831":"WY","832":"ID","833":"ID","834":"ID","835":"ID","836":"ID","837":"ID","838":"WA","840":"UT","841":"UT","842":"UT","843":"UT","844":"UT","845":"UT","846":"UT","847":"UT","850":"AZ","851":"AZ","852":"AZ","853":"AZ","855":"AZ","856":"AZ","857":"AZ","859":"AZ","860":"AZ","863":"AZ","864":"AZ","865":"AZ","870":"NM","871":"NM","872":"NM","873":"NM","874":"NM","875":"NM","877":"NV","878":"NM","879":"NM","880":"NM","881":"NM","882":"NM","883":"NM","884":"NM","885":"TX","889":"NV","890":"NV","891":"NV","893":"NV","894"
30722:"NV","895":"NV","897":"NV","898":"NV","900":"CA","901":"CA","902":"CA","903":"CA","904":"CA","905":"CA","906":"CA","907":"CA","908":"CA","910":"CA","911":"CA","912":"CA","913":"CA","914":"CA","915":"CA","916":"CA","917":"CA","918":"CA","919":"CA","920":"CA","921":"CA","922":"CA","923":"CA","924":"CA","925":"CA","926":"CA","927":"CA","928":"CA","930":"CA","931":"CA","932":"CA","933":"CA","934":"CA","935":"CA","936":"CA","937":"CA","938":"CA","939":"CA","940":"CA","941":"CA","942":"CA","943":"CA","944":"CA","945":"CA","946":"CA","947":"CA","948":"CA","949":"CA","950":"CA","951":"CA","952":"CA","953":"CA","954":"CA","955":"CA","956":"CA","957":"CA","958":"CA","959":"CA","960":"CA","961":"CA","962":"AP","963":"AP","964":"AP","965":"AP","966":"AP","967":"AS","968":"HI","969":"MH","970":"OR","971":"OR","972":"OR","973":"OR","974":"OR","975":"OR","976":"OR","977":"OR","978":"OR","979":"OR","980":"WA","981":"WA","982":"WA","983":"WA","984":"WA","985":"WA","986":"OR","988":"WA","989":"WA","990":"WA","991":"WA","992":"WA","993":"WA","994":"WA","995":"AK","996":"AK","997":"AK","998":"AK","999":"AK","005":"NY","063":"CT","006":"VI","007":"VI","008":"VI","009":"VI","010":"MA","011":"MA","012":"MA","013":"MA","014":"MA","015":"MA","016":"MA","017":"MA","018":"MA","019":"MA","020":"MA","021":"MA","022":"MA","023":"MA","024":"MA","025":"MA","026":"MA","027":"MA","055":"MA","028":"RI","029":"RI","030":"NH","031":"NH","032":"NH","033":"NH","034":"NH","035":"VT","036":"VT","037":"VT","038":"NH","039":"ME","050":"VT","051":"VT","052":"VT","053":"VT","054":"VT","056":"VT","057":"VT","058":"VT","059":"VT","040":"ME","041":"ME","042":"ME","043":"ME","044":"ME","045":"ME","046":"ME","047":"ME","048":"ME","049":"ME","060":"CT","061":"CT","062":"CT","064":"CT","065":"CT","066":"CT","067":"CT","068":"CT","069":"CT","070":"NJ","071":"NJ","072":"NJ","073":"NJ","074":"NJ","075":"NJ","076":"NJ","077":"NJ","078":"NJ","079":"NJ","080":"NJ","081":"NJ","082":"NJ","083":"NJ","084":"NJ","085":"NJ","086":"NJ","087":"NJ","088":"NJ","089":"NJ","090":"AE","091":"AE","092":"AE","093":"AE","094":"AE","095":"AE","096":"AE","097":"AE","098":"AE","099":"AE"} 30723},{}],112:[function(require,module,exports){ 30724'use strict'; 30725 30726exports.VerifyAddress = verifyAddress; 30727exports.AutocompleteAddress = autocompleteAddress; 30728exports.SetAddressFromAddressVerificationDialog = setAddressFromAddressVerificationDialog; 30729exports.BuildAddressObjectFromCheckoutForm = buildAddressObjectFromCheckoutForm; 30730exports.BuildAddressObjectFromAddressAutocompleteSuggestion = buildAddressObjectFromAddressAutocompleteSuggestion; 30731exports.BuildAddressObjectFromAddressVerifyResponse = buildAddressObjectFromAddressVerifyResponse; 30732exports.CompareAddressObjects = compareAddressObjects; 30733 30734var dataBuffer = {}; 30735 30736function verifyAddress($form, options) { 30737 return new Promise(function(resolve, reject) { 30738 var addressVerificationPayload = { 30739 primary_line: $form.find('input[name$="_address1"]').val() || '', 30740 secondary_line: $form.find('input[name$="_address2"]').val() || '', 30741 city: $form.find('input[name$="_city"]').val() || '', 30742 state: $form.find('select[name$="_state"]').val() || '' 30743 }; 30744 if ($form.find('input[name$="_postal"]').length) { 30745 addressVerificationPayload.zip_code = $form.find('input[name$="_postal"]').val(); 30746 } else if ($form.find('input[name$="_postalCode"]').length) { 30747 addressVerificationPayload.zip_code = $form.find('input[name$="_postalCode"]').val(); 30748 } 30749 addressVerificationPayload[options.CSRFToken.Name] = options.CSRFToken.Token; 30750 30751 $.ajax({ 30752 method: 'POST', 30753 url: Urls.Lob.AddressVerify, 30754 contentType: 'application/json', 30755 data: JSON.stringify(addressVerificationPayload), 30756 dataType: 'json', 30757 success: function(data) { 30758 if (!data || !data.ServiceSuccessfullyCalled) { 30759 resolve(data); 30760 } else { 30761 data.Status = 'deliverable'; 30762 data.Match = true; 30763 if (data.InquiryResult) { 30764 data.AddressOriginal = buildAddressObjectFromCheckoutForm($form); 30765 data.AddressVerified = buildAddressObjectFromAddressVerifyResponse(data); 30766 data.AddressComparison = compareAddressObjects(data.AddressOriginal, data.AddressVerified); 30767 data.Match = data.AddressComparison.Match; 30768 data.Status = data.InquiryResult.deliverability; 30769 } 30770 30771 if (data.Status == 'deliverable' && data.Match) { 30772 resolve(data); 30773 } else { 30774 reject(data); 30775 } 30776 } 30777 }, 30778 error: function(data) { 30779 resolve(data); 30780 }, 30781 }); 30782 }); 30783} 30784 30785function autocompleteAddress($form, $field, options) { 30786 return new Promise(function(resolve, reject) { 30787 var addressAutocompletePayload = { 30788 address_prefix: $form.find('input[name$="_address1"]').val() || '', 30789 city: $form.find('input[name$="_city"]').val() || '', 30790 state: $form.find('select[name$="_state"]').val() || '', 30791 zip_code: $form.find('input[name$="postal"]').val() || $form.find('input[name$="postalCode"]').val() || '' 30792 }; 30793 addressAutocompletePayload[options.CSRFToken.Name] = options.CSRFToken.Token; 30794 30795 if (dataBuffer && dataBuffer['AutocompleteAddressAjax'] && dataBuffer['AutocompleteAddressAjax'].readyState !== 4) { 30796 dataBuffer['AutocompleteAddressAjax'].abort(); 30797 } 30798 30799 dataBuffer['AutocompleteAddressAjax'] = $.ajax({ 30800 method: 'POST', 30801 url: Urls.Lob.AddressAutocomplete, 30802 contentType: 'application/json', 30803 data: JSON.stringify(addressAutocompletePayload), 30804 dataType: 'json', 30805 success: function(data) { 30806 if (!data || !data.ServiceSuccessfullyCalled) { 30807 resolve(data); 30808 } else { 30809 data.$form = $form; 30810 data.$field = $field; 30811 30812 resolve(data); 30813 } 30814 } 30815 }) 30816 }); 30817} 30818 30819function setAddressFromAddressVerificationDialog($form, addressData) { 30820 if (addressData.FirstName) { 30821 $form.find('input[name$="_firstName"]').val(addressData.FirstName); 30822 } 30823 if (addressData.LastName) { 30824 $form.find('input[name$="_lastName"]').val(addressData.LastName); 30825 } 30826 if (addressData.PrimaryLine) { 30827 $form.find('input[name$="_address1"]').val(addressData.PrimaryLine); 30828 $form.find('input[name$="_address2"]').val(addressData.SecondaryLine); 30829 $form.find('input[name$="_city"]').val(addressData.City); 30830 $form.find('select[name$="_state"]').val(addressData.StateCode); 30831 if ($form.find('input[name$="_postal"]').length) { 30832 $form.find('input[name$="_postal"]').val(addressData.PostalCode); 30833 } else if ($form.find('input[name$="_postalCode"]').length) { 30834 $form.find('input[name$="_postalCode"]').val(addressData.PostalCode); 30835 } 30836 if (addressData.CountryCode) { 30837 $form.find('select[name$="_countryCode"]').val(addressData.CountryCode); 30838 } 30839 } 30840 if (addressData.Phone) { 30841 $form.find('input[name$="phone"]').val(addressData.Phone); 30842 } 30843 if (addressData.Email) { 30844 $form.find('input[name$="emailAddress"]').val(addressData.Email); 30845 } 30846} 30847 30848function buildAddressObjectFromCheckoutForm($form) { 30849 var addressObject = {}; 30850 30851 addressObject.PrimaryLine = $form.find('input[name$="_address1"]').val(); 30852 addressObject.SecondaryLine = $form.find('input[name$="_address2"]').val(); 30853 addressObject.City = $form.find('input[name$="_city"]').val(); 30854 addressObject.StateCode = $form.find('select[id$="_state"]').val(); 30855 if ($form.find('input[name$="_postal"]').length) { 30856 addressObject.PostalCode = $form.find('input[name$="_postal"]').val(); 30857 } else if ($form.find('input[name$="_postalCode"]').length) { 30858 addressObject.PostalCode = $form.find('input[name$="_postalCode"]').val(); 30859 } 30860 30861 return addressObject; 30862} 30863 30864function buildAddressObjectFromAddressAutocompleteSuggestion(data) { 30865 var addressObject = {}; 30866 30867 if (data) { 30868 addressObject.PrimaryLine = data.primary_line || ''; 30869 addressObject.SecondaryLine = data.secondary_line || ''; 30870 addressObject.StateCode = data.state || ''; 30871 addressObject.PostalCode = data.zip_code || ''; 30872 addressObject.City = data.city || ''; 30873 } 30874 30875 return addressObject; 30876} 30877 30878function buildAddressObjectFromAddressVerifyResponse(data) { 30879 var addressObject = {}; 30880 30881 if (data && data.InquiryResult) { 30882 addressObject.PrimaryLine = data.InquiryResult.primary_line || ''; 30883 addressObject.SecondaryLine = data.InquiryResult.secondary_line || ''; 30884 addressObject.StateCode = data.InquiryResult.components.state || ''; 30885 addressObject.PostalCode = data.InquiryResult.components.zip_code || ''; 30886 addressObject.City = data.InquiryResult.components.city || ''; 30887 } 30888 30889 return addressObject; 30890} 30891 30892function compareAddressObjects(addressOriginal, addressVerified) { 30893 var addressObject = {}; 30894 30895 if (addressOriginal && addressVerified) { 30896 addressObject.PrimaryLine = compareAddressElement(addressOriginal.PrimaryLine, addressVerified.PrimaryLine); 30897 addressObject.SecondaryLine = compareAddressElement(addressOriginal.SecondaryLine, addressVerified.SecondaryLine); 30898 addressObject.StateCode = compareAddressElement(addressOriginal.StateCode, addressVerified.StateCode); 30899 addressObject.PostalCode = compareAddressElement(addressOriginal.PostalCode, addressVerified.PostalCode); 30900 addressObject.City = compareAddressElement(addressOriginal.City, addressVerified.City); 30901 } 30902 30903 var fieldsDifferent = []; 30904 for (var addressElement in addressObject) { 30905 if (!addressObject[addressElement]) { 30906 fieldsDifferent[fieldsDifferent.length] = addressElement; 30907 } 30908 } 30909 addressObject.FieldsDifferent = fieldsDifferent; 30910 addressObject.Match = fieldsDifferent.length == 0; 30911 30912 return addressObject; 30913} 30914 30915function compareAddressElement(addressElementOriginal, addressElementVerified) { 30916 addressElementOriginal = addressElementOriginal || ''; 30917 addressElementVerified = addressElementVerified || ''; 30918 30919 return addressElementOriginal.trim().toLowerCase() == addressElementVerified.trim().toLowerCase(); 30920} 30921},{}],113:[function(require,module,exports){ 30922'use strict'; 30923 30924exports.ResponseCodes = { 30925 AlreadyInBasket: 'ALREADY_IN_BASKET' 30926} 30927 30928exports.User = { 30929 SelectedCustomerShippingMethod: 'selectedCustomerShippingMethod', 30930 SelectedStoreShippingMethod: 'selectedStoreShippingMethod' 30931} 30932 30933exports.ShippingMethods = { 30934 Bopis: 'Bopis', 30935 LocalDelivery: 'LocalDelivery', 30936 ShipToStore: 'Ship-to-Store', 30937 ShipToStorePickup: 'My_Store_Free_Shipping', 30938 ShipToStorePickupForWhip: 'WHIP FREE Ship-to-store', 30939 Virtual: 'Virtual' 30940} 30941},{}],114:[function(require,module,exports){ 30942'use strict'; 30943 30944exports.Events = { 30945 Cart: { 30946 AddToCart: { 30947 Name: 'AddToCart' 30948 }, 30949 RemoveFromCart: { 30950 Name: 'RemoveFromCart' 30951 } 30952 } 30953} 30954 30955exports.EventTypes = { 30956 Minus: 'minus', 30957 Plus: 'plus' 30958} 30959},{}],115:[function(require,module,exports){ 30960'use strict'; 30961 30962exports.GetPosition = getPosition; 30963 30964function getPosition() { 30965 return new Promise(function(resolve) { 30966 if (navigator.geolocation) { 30967 var geolocationSuccess = function(position) { 30968 resolve(position); 30969 }; 30970 30971 var geolocationError = function() { 30972 resolve(); 30973 }; 30974 30975 navigator.geolocation.getCurrentPosition(geolocationSuccess, geolocationError); 30976 } else { 30977 resolve(); 30978 } 30979 }); 30980} 30981},{}],116:[function(require,module,exports){ 30982'use strict'; 30983 30984exports.SlickSlider = { 30985 Options: { 30986 Single: { 30987 accessibility: true, 30988 infinite: true, 30989 dots: false, 30990 arrows: false, 30991 slidesToShow: 1, 30992 slidesToScroll: 1, 30993 responsive: [ 30994 { 30995 breakpoint: 767, 30996 settings: { 30997 dots: true, 30998 arrows: true 30999 } 31000 }, 31001 { 31002 breakpoint: 1200 31003 } 31004 ] 31005 },
31006 Thumbnail: { 31007 accessibility: true, 31008 draggable: false, 31009 infinite: false, 31010 focusOnSelect: false, 31011 dots: false, 31012 arrows: false, 31013 slidesToShow: 7, 31014 slidesToScroll: 7, 31015 responsive: [ 31016 { 31017 breakpoint: 767 31018 }, 31019 { 31020 breakpoint: 1200, 31021 settings: { 31022 slidesToShow: 4, 31023 slidesToScroll: 4 31024 } 31025 } 31026 ] 31027 }, 31028 CategoryLanding: { 31029 accessibility: true, 31030 draggable: true, 31031 infinite: true, 31032 focusOnSelect: false, 31033 dots: false, 31034 arrows: true, 31035 slidesToShow: 4, 31036 slidesToScroll: 4, 31037 responsive: [ 31038 { 31039 breakpoint: 767 31040 }, 31041 { 31042 breakpoint: 1200, 31043 settings: { 31044 slidesToShow: 3, 31045 slidesToScroll: 3 31046 } 31047 } 31048 ] 31049 } 31050 } 31051} 31052},{}],117:[function(require,module,exports){ 31053'use strict'; 31054 31055exports.PaymentMethods = { 31056 AllianceData: 'Alliance_Data', 31057 ApplePay: 'DW_APPLE_PAY', 31058 BillMeLater: 'BML', 31059 CreditCard: 'CREDIT_CARD', 31060 GiftCertificate: 'GIFT_CERTIFICATE', 31061 PayPal: 'PayPal', 31062 Globale: 'GLOBALE', 31063 RewardsCredit: 'REWARDS_CREDIT', 31064 LoyaltyCredit: 'LOYALTY_CREDIT', 31065 StoredValueSolutions: 'SVS_Gift_Card', 31066 Affirm: 'Affirm', 31067 PaymentVoucher: 'B2B_Payment_Voucher', 31068 ShopPay: 'ShopPay', 31069 WorkforceVoucher: 'Workforce_Voucher' 31070}; 31071 31072exports.CreditCards = { 31073 AmericanExpress: 'Amex', 31074 BootBarnCredit: 'Boot Barn Credit Card', 31075 Discover: 'Discover', 31076 JCB: 'JCB', 31077 Maestro: 'Maestro', 31078 Mastercard: 'Master', 31079 MastercardSeries2: 'Master Series 2', 31080 Visa: 'Visa' 31081}; 31082},{}],118:[function(require,module,exports){ 31083'use strict'; 31084 31085exports.RefinementsUIVersions = { 31086 Updated: 'Updated', 31087 Legacy: 'Legacy' 31088} 31089},{}],119:[function(require,module,exports){ 31090'use strict'; 31091 31092module.exports = { 31093 Validation: { 31094 Email: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/, 31095 OrderNumber: /^[a-zA-Z]{0,6}[-._]{0,1}[0-9]{6,12}$/, 31096 PostalCode: /^[a-zA-Z0-9][a-zA-Z0-9\- ]{0,10}[a-zA-Z0-9]$/, 31097 PostOfficeBox: /((((p[\s\.]?)\s?[o\s][\.]?)\s?)|(post\s?office\s?)|(postal\s?)|(post\s?))((box|bin|b\.?)?\s?((num|number|no|#)\.?)?\s?\d+)/i, 31098 ZipCode: /^[0-9]{5}(-[0-9]{4})*$/, 31099 RequiredExcludingPunctuation: /^[#]*[^_\W]+/, 31100 GiftCardNumberLength: /(\d)/g, 31101 GiftCardNumberValues: /^[-\s0-9]*$/, 31102 } 31103} 31104 31105// Email pattern is from W3C spec, same that jQuery Validate uses: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address 31106// Postal Code pattern is from https://stackoverflow.com/questions/578406/what-is-the-ultimate-postal-code-and-zip-regex 31107// PO Box pattern is modified from https://stackoverflow.com/questions/5680050/po-box-regular-expression-validation 31108},{}],120:[function(require,module,exports){ 31109'use strict'; 31110 31111exports.AddressTypes = { 31112 Customer: 'CustomerAddress', 31113 Store: 'StoreAddress' 31114} 31115 31116exports.CountryCodes = { 31117 UnitedStates: 'US', 31118 Canada: 'CA' 31119} 31120 31121exports.StateCodes = { 31122 NewYork: 'NY' 31123} 31124 31125exports.KeyCodes = { 31126 Enter: 13, 31127 Tab: 9, 31128 ArrowLeft: 37, 31129 ArrowUp: 38, 31130 ArrowRight: 39, 31131 ArrowDown: 40 31132} 31133 31134exports.Responsive = { 31135 Widths: { 31136 Mobile: 767, 31137 Tablet: 1024 31138 } 31139} 31140 31141exports.SiteIds = { 31142 BootBarnUS: 'bootbarn_us', 31143 SheplersUS: 'sheplers_us', 31144 CountryOutfittersUS: 'country_outfitters_us', 31145 BootBarnRspUS: 'bootbarn_rsp_us', 31146 BootBarnPayments: 'bootbarn_payments', 31147 BootBarnB2BUS: 'bootbarn_b2b_us', 31148 Rangefinder: 'rangefinder', 31149 BootBarnWorkforceUS: 'bootbarn_workforce_us' 31150} 31151 31152exports.ProductRecommendationSystems = { 31153 Einstein: 'Einstein', 31154 Relevant: 'Relevant' 31155} 31156},{}],121:[function(require,module,exports){ 31157'use strict'; 31158 31159exports.Lodash = { 31160 Settings: { 31161 interpolate: /{{([\s\S]+?)}}/g 31162 } 31163} 31164},{}],122:[function(require,module,exports){ 31165'use strict'; 31166 31167exports.Settings = { 31168 Global: { 31169 errorClass: 'error', 31170 errorElement: 'span', 31171 onkeyup: false, 31172 errorPlacement: function (error, element) { 31173 var $validationErrorContainer = element.closest('form').find('.validation-error-container'); 31174 if ($validationErrorContainer.length > 0) { 31175 error.appendTo($validationErrorContainer); 31176 } else if (element.attr('error-container')) { 31177 error.appendTo($(element.attr('error-container'))); 31178 } else { 31179 error.appendTo(element.parent()); 31180 } 31181 } 31182 }, 31183 Checkout: { 31184 errorPlacement: function(error, element) { 31185 if (element.attr('error-container')) { 31186 error.appendTo($(element.attr('error-container'))); 31187 } else { 31188 error.appendTo(element.parent()); 31189 } 31190 31191 var $validationErrorContainer = element.closest('form').find('.validation-error-container'); 31192 if ($validationErrorContainer.length > 0) { 31193 var $element = $(element); 31194 var $elementValidationError = $validationErrorContainer.find('.validation-error[field="' + $element.attr('id') + '"]'); 31195 if ($elementValidationError.length <= 0) {
31196 var validationErrorText = $('<span class="validation-error" field="' + $element.attr('id') + '" />').text($element.closest('.formfield').find('label span').text() + ' is required.'); 31197 $validationErrorContainer.append(validationErrorText); 31198 } 31199 } 31200 }, 31201 onfocusout: function(element) { 31202 if (!this.checkable(element)) { 31203 var isElementValid = this.element(element); 31204 var $element = $(element); 31205 var $validationErrorContainer = $element.closest('form').find('.validation-error-container'); 31206 var $elementValidationError = $validationErrorContainer.find('.validation-error[field="' + $element.attr('id') + '"]'); 31207 if (isElementValid && $elementValidationError.length > 0) { 31208 $elementValidationError.remove(); 31209 } else if (!isElementValid && $elementValidationError.length <= 0) { 31210 var validationErrorText = $('<span class="validation-error" field="' + $element.attr('id') + '" />').text($element.closest('.formfield').find('label span').text() + ' is required.'); 31211 $validationErrorContainer.append(validationErrorText); 31212 } 31213 } 31214 } 31215 } 31216} 31217 31218exports.Rules = { 31219 RequiredExcludingPunctuation: { 31220 requiredExcludingPunctuation: true 31221 }, 31222 ValidateAddressForPostOfficeBox: { 31223 postOfficeBox: true 31224 }, 31225 ValidateAddressForPostOfficeBoxOnly: { 31226 postOfficeBoxOnly: true 31227 }, 31228 Email: { 31229 email: true, 31230 minlength: 1 31231 }, 31232 OrderNumber: { 31233 orderNumber: true 31234 }, 31235 PostalCode: { 31236 postalCode: true 31237 }, 31238 PostalCodeAndStateCode: { 31239 postalCode: true, 31240 zipCodeForStateCode: true 31241 }, 31242 ZipCode: { 31243 zipCode: true 31244 }, 31245 ZipCodeAndStateCode: { 31246 zipCode: true, 31247 zipCodeForStateCode: true 31248 }, 31249 StateCodeForCaliforniaStateLine: { 31250 stateCodeForCaliforniaStateLine: true 31251 }, 31252 GiftCard: { 31253 Number: { 31254 required: true, 31255 giftCardNumberLength: true, 31256 giftCardNumberValues: true 31257 }, 31258 Pin: { 31259 required: true, 31260 digits: true, 31261 minlength: 4, 31262 maxlength: 8, 31263 messages: { 31264 minlength: $.validator.format(Resources.Validation.Messages.Numbers.MinimumLength), 31265 maxlength: $.validator.format(Resources.Validation.Messages.Numbers.MaximumLength) 31266 } 31267 } 31268 }, 31269 RewardsCredit: { 31270 Number: { 31271 required: true, 31272 digits: true, 31273 minlength: 16, 31274 maxlength: 16, 31275 messages: { 31276 minlength: $.validator.format(Resources.Validation.Messages.Numbers.MinimumLength), 31277 maxlength: $.validator.format(Resources.Validation.Messages.Numbers.MaximumLength) 31278 } 31279 } 31280 }, 31281 LoyaltyCredit: { 31282 Number: { 31283 required: true, 31284 digits: true, 31285 minlength: 1, 31286 maxlength: 10, 31287 messages: { 31288 minlength: $.validator.format(Resources.Validation.Messages.Numbers.MinimumLength), 31289 maxlength: $.validator.format(Resources.Validation.Messages.Numbers.MaximumLength) 31290 } 31291 } 31292 }, 31293 PaymentVoucher: { 31294 Number: { 31295 required: true, 31296 digits: false, 31297 minlength: 1, 31298 maxlength: 28, 31299 messages: { 31300 minlength: $.validator.format(Resources.Validation.Messages.Numbers.MinimumLength), 31301 maxlength: $.validator.format(Resources.Validation.Messages.Numbers.MaximumLength) 31302 } 31303 } 31304 } 31305} 31306},{}],123:[function(require,module,exports){ 31307'use strict'; 31308 31309exports.PushDataLayerForPage = pushDataLayerForPage; 31310exports.PushDataLayerForDataLayerType = pushDataLayerForDataLayerType; 31311exports.PushDataLayerForEvent = pushDataLayerForEvent; 31312 31313var dataLayerBaseObjects = { 31314 UniversalAnalytics: { 31315 ViewPromotion: { 31316 31317 } 31318 }, 31319 GoogleAnalytics4: { 31320 ViewPromotion: { 31321 event: 'view_promotion' 31322 } 31323 } 31324} 31325 31326function pushDataLayerForPage(page) { 31327 window.dataLayer = window.dataLayer || []; 31328 31329 if (page) { 31330 if (page.options && page.options.GoogleTagManager && page.options.GoogleTagManager.EnableGoogleAnalytics4) { 31331 pushDataLayerForPageForGoogleAnalytics4(page); 31332 } 31333 pushDataLayerForPageForUniversalAnalytics(page); 31334 } 31335} 31336 31337function pushDataLayerForPageForGoogleAnalytics4(page) { 31338 window.dataLayer = window.dataLayer || []; 31339 31340 if (page) { 31341 if (page.options && page.options.GoogleTagManager && page.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4) { 31342 var dataLayer; 31343 if (page.ns == 'orderconfirmation') { 31344 dataLayer = page.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4; 31345 dataLayer.items = getProductDataLayer('data-product-ga4-json'); 31346 pushDataLayer(dataLayer); 31347 $(document).trigger('DataLayer.OrderComplete', { 31348 dataLayer: dataLayer, 31349 options: page.options 31350 }); 31351 } else {
31352 // This should be activated when UA is removed. 31353 // $.ajax({ 31354 // url: Urls.GoogleTagManager.GetDataLayer, 31355 // type: 'POST', 31356 // data: { 31357 // DataLayerType: 'General', 31358 // DataLayerVersion: 'GoogleAnalytics4' 31359 // }, 31360 // dataType: 'json', 31361 // success: function(data) { 31362 // dataLayer = $.extend(page.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4, data); 31363 // window.dataLayer.push(dataLayer); 31364 // }, 31365 // error: function() { 31366 31367 // } 31368 // }); 31369 } 31370 } 31371 31372 if (page.ns != 'orderconfirmation') { 31373 var payload = {}; 31374 31375 var dataLayerPageType; 31376 if (page.options && page.options.GoogleTagManager && page.options.GoogleTagManager.PageType) { 31377 dataLayerPageType = page.options.GoogleTagManager.PageType; 31378 } else { 31379 dataLayerPageType = page.ns; 31380 } 31381 payload.Page = dataLayerPageType; 31382 31383 if (page.options && page.options.GoogleTagManager) { 31384 payload.Options = JSON.stringify(page.options.GoogleTagManager); 31385 payload.DataLayerVersion = 'GoogleAnalytics4'; 31386 } 31387 31388 $.ajax({ 31389 url: Urls.GoogleTagManager.GetDataLayer, 31390 type: 'POST', 31391 data: payload, 31392 dataType: 'json', 31393 success: function(data) { 31394 if (page.options && page.options.GoogleTagManager && page.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4) { 31395 data = $.extend(page.options.GoogleTagManager.DataLayerCacheForGoogleAnalytics4, data); 31396 } 31397 if (page.ns == 'product') { 31398 if (!data.value && data.items && data.items.length > 0) { 31399 data.currency = data.items[0].currency; 31400 data.value = data.items[0].price; 31401 } 31402 } else if (page.ns == 'search') { 31403 data.items = getProductDataLayer('data-product-ga4-json', { Container: $('.search-result-content') }); 31404 } else if (page.ns == 'cart' || page.ns == 'onepcheckout_groups') { 31405 data.items = getProductDataLayer('data-product-ga4-json'); 31406 if (!data.value && data.items && data.items.length > 0) { 31407 var value = 0; 31408 for (var itemKey in data.items) { 31409 var item = data.items[itemKey]; 31410 value += item.price; 31411 } 31412 data.value = value; 31413 } 31414 } 31415 pushDataLayer(data); 31416 }, 31417 error: function() { 31418 31419 } 31420 }); 31421 } 31422 } 31423} 31424 31425function pushDataLayerForPageForUniversalAnalytics(page) { 31426 window.dataLayer = window.dataLayer || []; 31427 31428 if (page) { 31429 if (page.options && page.options.GoogleTagManager && page.options.GoogleTagManager.DataLayerCache) { 31430 var dataLayer; 31431 if (page.ns == 'orderconfirmation') { 31432 dataLayer = page.options.GoogleTagManager.DataLayerCache; 31433 dataLayer.ecommerce = dataLayer.ecommerce || {}; 31434 dataLayer.ecommerce.purchase = dataLayer.ecommerce.purchase || {}; 31435 dataLayer.ecommerce.purchase.products = getProductDataLayer(); 31436 pushDataLayer(dataLayer); 31437 } else { 31438 $.ajax({ 31439 url: Urls.GoogleTagManager.GetDataLayer, 31440 type: 'POST', 31441 data: { 31442 DataLayerType: 'General', 31443 DataLayerVersion: 'UniversalAnalytics' 31444 }, 31445 dataType: 'json', 31446 success: function(data) { 31447 dataLayer = $.extend(page.options.GoogleTagManager.DataLayerCache, data); 31448 pushDataLayer(dataLayer); 31449 }, 31450 error: function() { 31451 31452 } 31453 }); 31454 } 31455 } 31456 31457 if (page.ns != 'orderconfirmation') { 31458 var payload = { 31459 Page: page.ns 31460 } 31461 31462 if (page.options && page.options.GoogleTagManager) { 31463 payload.Options = JSON.stringify(page.options.GoogleTagManager); 31464 payload.DataLayerVersion = 'UniversalAnalytics'; 31465 } 31466 31467 $.ajax({ 31468 url: Urls.GoogleTagManager.GetDataLayer, 31469 type: 'POST', 31470 data: payload, 31471 dataType: 'json', 31472 success: function(data) { 31473 if (page.ns == 'search') { 31474 data.ecommerce = data.ecommerce || {}; 31475 data.ecommerce.impressions = getProductDataLayer(null, { Container: $('.search-result-content') }); 31476 } else if (page.ns == 'product') { 31477 data.ecommerce = data.ecommerce || {}; 31478 data.ecommerce.detail = data.ecommerce.detail || {}; 31479 data.ecommerce.detail.products = getProductDataLayer(); 31480 } else if (page.ns == 'cart' || page.ns == 'onepcheckout_groups') { 31481 data.ecommerce = data.ecommerce || {}; 31482 data.ecommerce.cartContents = getProductDataLayer(); 31483 } 31484 pushDataLayer(data); 31485 }, 31486 error: function() { 31487 31488 } 31489 }); 31490 } 31491 } 31492} 31493 31494function pushDataLayerForDataLayerType(dataLayerType, dataObject, options) { 31495 var dataObject = dataObject || {}; 31496 31497 return new Promise(function(resolve, reject) { 31498 var ajaxCompleteStatus = { 31499 GoogleAnalytics4: '', 31500 UniversalAnalytics: '' 31501 } 31502 31503 var ajaxComplete = function() { 31504 if (ajaxCompleteStatus.UniversalAnalytics == 'success' && ajaxCompleteStatus.GoogleAnalytics4 == 'success') { 31505 resolve(); 31506 } else if (ajaxCompleteStatus.UniversalAnalytics && ajaxCompleteStatus.GoogleAnalytics4 && (ajaxCompleteStatus.UniversalAnalytics == 'error' || ajaxCompleteStatus.GoogleAnalytics4 == 'error')) { 31507 reject(); 31508 } 31509 } 31510 31511 if (dataLayerType != 'Event' && dataLayerType != 'ViewPromotion') { 31512 pushDataLayerForDataLayerTypeForDataLayerVersion(dataLayerType, dataObject.UniversalAnalytics || Object.assign({}, dataObject), 'UniversalAnalytics', options).then(function() { 31513 ajaxCompleteStatus.UniversalAnalytics = 'success'; 31514 ajaxComplete(); 31515 }).catch(function() { 31516 ajaxCompleteStatus.UniversalAnalytics = 'error'; 31517 ajaxComplete(); 31518 }); 31519 } 31520 pushDataLayerForDataLayerTypeForDataLayerVersion(dataLayerType, dataObject.GoogleAnalytics4 || Object.assign({}, dataObject), 'GoogleAnalytics4', options).then(function() { 31521 ajaxCompleteStatus.GoogleAnalytics4 = 'success'; 31522 ajaxComplete(); 31523 }).catch(function() { 31524 ajaxCompleteStatus.GoogleAnalytics4 = 'error'; 31525 ajaxComplete(); 31526 });; 31527 }); 31528} 31529 31530function pushDataLayerForDataLayerTypeForDataLayerVersion(dataLayerType, dataObject, dataLayerVersion, options) { 31531 var dataLayer; 31532 var dataLayerType = dataLayerType || 'General'; 31533 var dataLayerVersion = dataLayerVersion || 'UniversalAnalytics'; 31534 var dataObject = dataObject || {}; 31535 31536 return new Promise(function(resolve, reject) { 31537 if (dataLayerType) { 31538 if (dataLayerBaseObjects[dataLayerVersion] && dataLayerBaseObjects[dataLayerVersion][dataLayerType]) { 31539 dataLayer = $.extend(dataLayerBaseObjects[dataLayerVersion][dataLayerType], dataObject); 31540 dataLayer = buildDataLayer(dataLayerType, dataLayerVersion, dataLayer, options); 31541 pushDataLayer(dataLayer); 31542 resolve(dataLayer); 31543 } else { 31544 var payload = { 31545 DataLayerType: dataLayerType, 31546 DataLayerVersion: dataLayerVersion 31547 } 31548 if (options) { 31549 payload.Options = JSON.stringify(options); 31550 } 31551 $.ajax({ 31552 url: Urls.GoogleTagManager.GetDataLayer, 31553 type: 'POST', 31554 data: payload, 31555 dataType: 'json', 31556 success: function(data) { 31557 if (data && !$.isEmptyObject(data)) { 31558 dataLayer = $.extend(data, dataObject); 31559 dataLayer = buildDataLayer(dataLayerType, dataLayerVersion, dataLayer, options); 31560 pushDataLayer(dataLayer); 31561 31562 if (dataLayerType == 'ViewOrderConfirmation' && dataLayerVersion == 'GoogleAnalytics4') { 31563 $(document).trigger('DataLayer.OrderComplete', { 31564 dataLayer: dataLayer, 31565 options: options 31566 }); 31567 } 31568 } 31569 resolve(dataLayer); 31570 }, 31571 error: function() { 31572 reject(); 31573 } 31574 }); 31575 } 31576 } else { 31577 reject(); 31578 } 31579 }); 31580} 31581 31582function pushDataLayerForEvent(eventName, dataObject, dataLayerType, dataLayerVersion) { 31583 var dataObject = dataObject || {}; 31584 31585 return new Promise(function(resolve, reject) { 31586 if (eventName) { 31587 $.ajax({ 31588 url: Urls.GoogleTagManager.GetDataLayer, 31589 type: 'POST', 31590 data: { 31591 DataLayerType: dataLayerType || 'General', 31592 DataLayerVersion: dataLayerVersion || 'UniversalAnalytics' 31593 }, 31594 dataType: 'json', 31595 success: function(data) { 31596 var dataLayer = $.extend(dataObject, data); 31597 dataLayer.event = eventName; 31598 pushDataLayer(dataLayer); 31599 resolve(dataLayer); 31600 }, 31601 error: function() { 31602 reject(); 31603 } 31604 }); 31605 } else { 31606 reject(); 31607 } 31608 }); 31609} 31610 31611function decorateDataLayerWithProductData(dataLayer, options) { 31612 var universalAnalyticsKey = options && options.UniversalAnalyticsKey ? options.UniversalAnalyticsKey : ''; 31613 31614 if (options && options.DecorateDataLayerWithProductDataKey) { 31615 dataLayer[options.DecorateDataLayerWithProductDataKey] = getProductDataLayer('data-product-ga4-json', options); 31616 } else if (options && options.DataLayerVersion == 'GoogleAnalytics4') { 31617 dataLayer.items = getProductDataLayer('data-product-ga4-json', options); 31618 } else { 31619 dataLayer.ecommerce = dataLayer.ecommerce || {}; 31620 dataLayer.ecommerce[universalAnalyticsKey] = dataLayer.ecommerce[universalAnalyticsKey] || {}; 31621 dataLayer.ecommerce[universalAnalyticsKey].products = getProductDataLayer(null, options); 31622 } 31623} 31624 31625function getProductDataLayer(attributeIdParameter, options) { 31626 var dataLayerProducts = window.dataLayerProducts || []; 31627 var attributeId = attributeIdParameter || 'data-product-gtm-json'; 31628 var container = options && options.Container ? options.Container : ''; 31629 var containerSelector = options && options.ContainerSelector ? options.ContainerSelector : ''; 31630 var filterSelector = options && options.FilterSelector ? options.FilterSelector : ''; 31631 31632 var $productCards; 31633 if (container) { 31634 $productCards = container.find('[' + attributeId + ']' + filterSelector); 31635 } else if (containerSelector) { 31636 $productCards = $(containerSelector).find('[' + attributeId + ']' + filterSelector); 31637 } else { 31638 $productCards = $('[' + attributeId + ']' + filterSelector); 31639 } 31640 $productCards.each(function(index, element) { 31641 var $element = $(element); 31642 31643 var slickIndex = null; 31644 var isValid = true; 31645 if ($element.closest('[data-slick-index]').length > 0) { 31646 slickIndex = parseInt($element.closest('[data-slick-index]').data('slick-index'), 10) + 1; 31647 if (slickIndex < 1) { 31648 isValid = false;
31649 } 31650 } 31651 31652 if (isValid) { 31653 var jsonObject = JSON.parse($element.attr(attributeId)); 31654 if (attributeId == 'data-product-gtm-json') { 31655 jsonObject.position = index; 31656 } else { 31657 jsonObject.index = index; 31658 } 31659 dataLayerProducts.push(jsonObject); 31660 } 31661 }); 31662 31663 return dataLayerProducts; 31664} 31665 31666function buildDataLayer(dataLayerType, dataLayerVersion, dataLayer, options) { 31667 if (dataLayerType == 'AddPaymentInfo') { 31668 decorateDataLayerWithProductData(dataLayer, { 31669 DataLayerVersion: dataLayerVersion, 31670 ContainerSelector: options && options.ContainerSelector ? options.ContainerSelector : '' 31671 }); 31672 } else if (dataLayerType == 'AddShippingInfo') { 31673 decorateDataLayerWithProductData(dataLayer, { 31674 DataLayerVersion: dataLayerVersion, 31675 ContainerSelector: options && options.ContainerSelector ? options.ContainerSelector : '' 31676 }); 31677 } else if (dataLayerType == 'AddToCart') { 31678 if ((dataLayer.event == 'add_to_cart' && (!dataLayer.items || dataLayer.items.length == 0)) || (dataLayer.event == 'addToCart' && (!dataLayer.ecommerce || !dataLayer.ecommerce || !dataLayer.ecommerce.add || !dataLayer.ecommerce.add.products || dataLayer.ecommerce.add.products.length == 0))) { 31679 decorateDataLayerWithProductData(dataLayer, { 31680 DataLayerVersion: dataLayerVersion, 31681 ContainerSelector: options && options.ContainerSelector ? options.ContainerSelector : '', 31682 FilterSelector: '.pdp-browse', 31683 UniversalAnalyticsKey: 'add' 31684 }); 31685 } 31686 if (dataLayer.items && dataLayer.items.length > 0) { 31687 if (!dataLayer.items[0].quantity) { 31688 dataLayer.items[0].quantity = 1; 31689 } 31690 dataLayer.currency = dataLayer.items[0].currency; 31691 dataLayer.value = dataLayer.items[0].price; 31692 } 31693 } else if (dataLayerType == 'RemoveFromCart') { 31694 if (dataLayer.items && dataLayer.items.length > 0) { 31695 if (!dataLayer.items[0].quantity) { 31696 dataLayer.items[0].quantity = 1; 31697 } 31698 dataLayer.currency = dataLayer.items[0].currency; 31699 dataLayer.value = dataLayer.items[0].price; 31700 } 31701 } else if (dataLayerType == 'SelectPromotion') { 31702 decorateDataLayerWithProductData(dataLayer, { 31703 DataLayerVersion: dataLayerVersion, 31704 Container: options && options.Container ? options.Container : '' 31705 }); 31706 } else if (dataLayerType == 'ViewItem') { 31707 decorateDataLayerWithProductData(dataLayer, { 31708 DataLayerVersion: dataLayerVersion, 31709 ContainerSelector: options && options.ContainerSelector ? options.ContainerSelector : '', 31710 FilterSelector: '.pdp-browse', 31711 UniversalAnalyticsKey: 'detail' 31712 }); 31713 } else if (dataLayerType == 'ViewPromotion') { 31714 decorateDataLayerWithProductData(dataLayer, $.extend({ 31715 DataLayerVersion: dataLayerVersion 31716 }, options)); 31717 } else if (options && options.DecorateDataLayerWithProductData) { 31718 decorateDataLayerWithProductData(dataLayer, $.extend({ 31719 DataLayerVersion: dataLayerVersion 31720 }, options)); 31721 } 31722 31723 return dataLayer; 31724} 31725 31726function pushDataLayer(dataLayer) { 31727 var isCartPage = pageContext && pageContext.options && pageContext.options.isCartPage; 31728 var isCheckoutPage = pageContext && pageContext.options && pageContext.options.isCheckoutPage; 31729 var isConfirmationPage = pageContext && pageContext.options && pageContext.options.isConfirmationPage; 31730 var reactDataLayerPages = pageContext && pageContext.options && pageContext.options.MobileApp && pageContext.options.MobileApp.ReactDataLayerPages ? pageContext.options.MobileApp.ReactDataLayerPages : []; 31731 var sendReactEventForCart = isCartPage && reactDataLayerPages.indexOf('Cart') > -1; 31732 var sendReactEventForCheckout = isCheckoutPage && reactDataLayerPages.indexOf('Checkout') > -1; 31733 var sendReactEventForConfirmation = isConfirmationPage && reactDataLayerPages.indexOf('Confirmation') > -1; 31734 31735 if ('ReactNativeWebView' in window && (sendReactEventForCart || sendReactEventForCheckout || sendReactEventForConfirmation)) { 31736 triggerReactWebviewEvent(dataLayer.event, dataLayer); 31737 } else { 31738 window.dataLayer.push(dataLayer); 31739 } 31740} 31741 31742function triggerReactWebviewEvent(action, dataLayer) { 31743 if ('ReactNativeWebView' in window) { 31744 var message = { 31745 action: action 31746 } 31747 if (dataLayer) { 31748 message.dataLayer = dataLayer; 31749 } 31750 31751 window.ReactNativeWebView.postMessage(JSON.stringify(message)); 31752 } 31753} 31754},{}],124:[function(require,module,exports){ 31755'use strict'; 31756 31757var RegexValidationPatterns = require('../../js/RegexPatterns').Validation; 31758var StateToZipCodeMap = require('../../data/StateToZipCodeMap.json'); 31759 31760exports.ValidateRequiredExcludingPunctuation = validateRequiredExcludingPunctuation; 31761exports.ValidateOrderNumber = validateOrderNumber; 31762exports.ValidateAddressForPostOfficeBox = validateAddressForPostOfficeBox; 31763exports.ValidateAddressForPostOfficeBoxOnly = validateAddressForPostOfficeBoxOnly; 31764exports.ValidatePostalCode = validatePostalCode; 31765exports.ValidateZipCode = validateZipCode; 31766exports.ValidateZipCodePrefixForStateCode = validateZipCodePrefixForStateCode;
31767exports.ValidateZipCodePrefixForStateCodeValues = validateZipCodePrefixForStateCodeValues; 31768exports.ValidateStateCodeForCaliforniaStateLine = validateStateCodeForCaliforniaStateLine; 31769exports.ValidateGiftCardNumberLength = validateGiftCardNumberLength; 31770exports.ValidateGiftCardNumberValues = validateGiftCardNumberValues; 31771 31772function validateRequiredExcludingPunctuation(value, element) { 31773 return RegexValidationPatterns.RequiredExcludingPunctuation.test((value + '').trim()); 31774}; 31775 31776function validateOrderNumber(value, element) { 31777 return RegexValidationPatterns.OrderNumber.test((value + '').trim()); 31778}; 31779 31780function validateAddressForPostOfficeBox(value, element) { 31781 return !RegexValidationPatterns.PostOfficeBox.test((value + '').trim()); 31782} 31783 31784function validateAddressForPostOfficeBoxOnly(value, element) { 31785 var address1 = $(element).closest('form').find('input[name$="_address1"]').val(); 31786 var address2 = $(element).closest('form').find('input[name$="_address2"]').val(); 31787 31788 return (!RegexValidationPatterns.PostOfficeBox.test((address1 + '').trim()) && !RegexValidationPatterns.PostOfficeBox.test((address2 + '').trim())) || (!address1 || !address2); 31789} 31790 31791function validatePostalCode(value, element) { 31792 return RegexValidationPatterns.PostalCode.test((value + '').trim()); 31793}; 31794 31795function validateZipCode(value, element) { 31796 return RegexValidationPatterns.ZipCode.test((value + '').trim()); 31797}; 31798 31799function validateZipCodePrefixForStateCode(value, element) { 31800 var zipCodePrefix = value.substr(0,3); 31801 var stateCode = $(element).closest('form').find('select[name$="_states_state"]').val().toUpperCase(); 31802 if (stateCode && StateToZipCodeMap && StateToZipCodeMap[stateCode]) { 31803 return StateToZipCodeMap[stateCode][zipCodePrefix]; 31804 } 31805 31806 return true; 31807}; 31808 31809function validateZipCodePrefixForStateCodeValues(zipCode, stateCode) { 31810 var zipCodePrefix = zipCode.substr(0,3); 31811 if (StateToZipCodeMap && StateToZipCodeMap[stateCode]) { 31812 return StateToZipCodeMap[stateCode][zipCodePrefix]; 31813 } 31814 31815 return true; 31816}; 31817 31818function validateStateCodeForCaliforniaStateLine(value, element) { 31819 var stateCodeForStore = $(element).closest('[store-state]').attr('store-state'); 31820 31821 if ((value != 'CA' && stateCodeForStore != 'CA') || value == stateCodeForStore) { 31822 return true; 31823 } 31824 31825 return false; 31826}; 31827 31828function validateGiftCardNumberLength(value, element) { 31829 var digits = (value + '').trim().match(RegexValidationPatterns.GiftCardNumberLength); 31830 return digits && digits.length == 19; 31831}; 31832 31833function validateGiftCardNumberValues(value, element) { 31834 return RegexValidationPatterns.GiftCardNumberValues.test((value + '').trim()); 31835}; 31836},{"../../data/StateToZipCodeMap.json":110,"../../js/RegexPatterns":119}],125:[function(require,module,exports){ 31837'use strict'; 31838 31839exports.SlickSlider = { 31840 Options: { 31841 Single: { 31842 infinite: true, 31843 dots: false, 31844 arrows: false, 31845 slidesToShow: 1, 31846 slidesToScroll: 1, 31847 responsive: [ 31848 { 31849 breakpoint: 767, 31850 settings: { 31851 dots: true, 31852 arrows: true 31853 } 31854 }, 31855 { 31856 breakpoint: 1200 31857 } 31858 ] 31859 }, 31860 Thumbnail: { 31861 draggable: true, 31862 infinite: false, 31863 focusOnSelect: false, 31864 dots: false, 31865 arrows: false, 31866 slidesToShow: 7, 31867 slidesToScroll: 7, 31868 responsive: [ 31869 { 31870 breakpoint: 767 31871 }, 31872 { 31873 breakpoint: 1200, 31874 settings: { 31875 slidesToShow: 4, 31876 slidesToScroll: 4 31877 } 31878 } 31879 ] 31880 }/*, 31881 CategoryLanding: { 31882 draggable: true, 31883 infinite: true, 31884 focusOnSelect: false, 31885 dots: false, 31886 arrows: true, 31887 slidesToShow: 4, 31888 slidesToScroll: 4, 31889 responsive: [ 31890 { 31891 breakpoint: 767 31892 }, 31893 { 31894 breakpoint: 1200, 31895 settings: { 31896 slidesToShow: 3, 31897 slidesToScroll: 3 31898 } 31899 } 31900 ] 31901 }*/ 31902 } 31903} 31904},{}],126:[function(require,module,exports){ 31905/* Global Variables */ 31906var helper = require('../helpers/shoppayHelper'); 31907var isBuyNow = window.shoppayClientRefs ? window.shoppayClientRefs.constants.isBuyNow : null; 31908var isAATest = window.shoppayClientRefs && window.shoppayClientRefs.preferences.shoppayAATest ? window.shoppayClientRefs.preferences.shoppayAATest : false; 31909var session; 31910 31911$(document).ready(function () { 31912 if (window.ShopPay) { 31913 initShopPayConfig(); 31914 if (window.shoppayClientRefs.preferences.shoppayEmailListenerEnabled && $('.shopify-email-listener').length) { 31915 initShopPayEmailRecognition(); 31916 } 31917 var readyOnPageLoad = helper.isReadyToOrderOnPageLoad(); 31918 if (readyOnPageLoad) { 31919 initShopPayButton(); 31920 var pageLoadData = helper.getInitProductData(); 31921 helper.setInitProductData(pageLoadData); // updates global prod data. 31922 } 31923 31924 /* The below code triggers if a product is a Buy Now item, but is not ready to order on page load 31925 (ex: required product attributes like color or size are not yet chosen). Here, a watcher is set 31926 to capture user interactions when product attributes are selected. Helper scripts will be triggered 31927 by these interactions to determine if the item is ready to order when all required attributes are 31928 selected. 31929 */ 31930 if (isBuyNow && !readyOnPageLoad) { 31931 $(document).on('ProductDetailPage.Variant.Updated', initBuyNow); // receives the Event & Response 31932 } else { 31933 session = initShopPaySession(); 31934 } 31935 } 31936 31937 $(document).on('Cart.UpdateSuccess', function() { 31938 if (window.ShopPay && !isBuyNow) { 31939 if (!session) { 31940 session = initShopPaySession(); 31941 } else { 31942 var paymentRequestResponse = helper.buildPaymentRequest(session); 31943 var responseJSON = paymentRequestResponse ? paymentRequestResponse.responseJSON : null; 31944 31945 if (responseJSON) { 31946 helper.shoppayBtnDisabledStyle(document.getElementById("shop-pay-button-container")); 31947 } 31948 31949 if (responseJSON && !responseJSON.error && responseJSON.paymentRequest !== null) { 31950 session.close(); 31951 session = initShopPaySession(); 31952 } 31953 } 31954 } 31955 }); 31956}); 31957 31958function initShopPayConfig() { 31959 window.ShopPay.PaymentRequest.configure({ 31960 shopId: window.shoppayClientRefs.preferences.shoppayStoreId, 31961 clientId: window.shoppayClientRefs.preferences.shoppayClientId, 31962 debug: window.shoppayClientRefs.preferences.shoppayModalDebugEnabled 31963 }); 31964} 31965 31966function initShopPayButton() { 31967 var paymentSelectors = ['#shop-pay-button-container', '#shop-pay-button-container-mobile', '#shop-pay-button-container-desktop'] 31968 for (var paymentSelectorIndex in paymentSelectors) { 31969 var paymentSelector = paymentSelectors[paymentSelectorIndex]; 31970 if ($(paymentSelector).length > 0) { 31971 window.ShopPay.PaymentRequest.createButton({buyWith: isBuyNow}).render(paymentSelector); 31972 helper.shoppayMutationObserver(paymentSelector); 31973 } 31974 } 31975} 31976 31977 31978function initBuyNow(event) { 31979 if (!session) { 31980 session = initShopPaySession(); 31981 } 31982 helper.setInitProductData({ 31983 pid: $('input#pid').val(), 31984 quantity: 1 31985 }); 31986 initShopPayButton(); 31987} 31988 31989function initShopPayEmailRecognition() { 31990 /* If your checkout is not built with SFRA or you have customized and removed the 'email-guest' 31991 id on the email input you will need to update the id value for emailInputId 31992 31993 Note: A 1.5 second delay has been added before attaching to the email trigger to the email field to 31994 accommodate users who may have incorporated browser autofills. The pop-up will appear if the field 31995 is autofilled with a recognized email address 31996 */ 31997 setTimeout(function() { 31998 $('.shopify-email-listener:visible').each(function() { 31999 window.ShopPay.PaymentRequest.createLogin({emailInputId: $(this).attr('id')}).render('#shop-pay-login-container'); 32000 }); 32001 }, 1500); 32002} 32003 32004$('body').on('cart:update product:afterAddToCart promotion:success', function () { 32005 /* Only interested in cart updates on Cart page (cart updates are not triggered in checkout). Buy Now already 32006 has a separate event handler for changes to attribute selections 32007 */ 32008 if (window.ShopPay && !isBuyNow) { 32009 if (!session) { 32010 session = initShopPaySession(); 32011 } else { 32012 var paymentRequestResponse = helper.buildPaymentRequest(session); 32013 var responseJSON = paymentRequestResponse ? paymentRequestResponse.responseJSON : null; 32014 32015 if (responseJSON) { 32016 helper.shoppayBtnDisabledStyle(document.getElementById("shop-pay-button-container")); 32017 } 32018 32019 if (responseJSON && !responseJSON.error && responseJSON.paymentRequest !== null) { 32020 session.close(); 32021 session = initShopPaySession(); 32022 } 32023 } 32024 } 32025}); 32026 32027 32028function initShopPaySession(paymentRequestInput, readyToOrder) { 32029 var paymentRequest; 32030 var paymentRequestResponse; 32031 var responseJSON; 32032 32033 if (isBuyNow && paymentRequestInput) { 32034 paymentRequest = paymentRequestInput; 32035 } else if (isBuyNow && !paymentRequestInput) { 32036 var productData = helper.getInitProductData(); 32037 if (productData) { 32038 paymentRequestResponse = helper.createResponse(productData, window.shoppayClientRefs.urls.BuyNowData); 32039 if (paymentRequestResponse.exception || paymentRequestResponse.error){ 32040 /* No need to close any session because a session does not exist at this point (has not yet been 32041 initiated). Return to exit function - don't reload the page in case there is a page rendering 32042 issue (will result in infinite reload loop). 32043 */ 32044 return; 32045 } 32046 paymentRequest = paymentRequestResponse.paymentRequest; 32047 responseJSON = paymentRequestResponse ? paymentRequestResponse : null; 32048 } 32049 } else { 32050 paymentRequestResponse = helper.buildPaymentRequest(session); 32051 responseJSON = paymentRequestResponse ? paymentRequestResponse.responseJSON : null; 32052 } 32053 32054 if (paymentRequest || (responseJSON && !responseJSON.error)) { 32055 var initialPaymentRequest = responseJSON && responseJSON.paymentRequest ? window.ShopPay.PaymentRequest.build(responseJSON.paymentRequest) : window.ShopPay.PaymentRequest.build(paymentRequest); 32056 // Enable BuyNow Button Click on PDP if Product is Ready To Order 32057 helper.shoppayBtnDisabledStyle(document.getElementById("shop-pay-button-container"), readyToOrder); 32058 32059 var shoppaySession = window.ShopPay.PaymentRequest.createSession({ 32060 paymentRequest: initialPaymentRequest 32061 }); 32062 32063 if (shoppaySession) { 32064 helper.setSessionListeners(shoppaySession); 32065 $('body').off('product:afterAttributeSelect', initBuyNow); 32066 32067 $('body').on('product:afterAttributeSelect', function(e, response) { 32068 var responseProduct = response.data.product; 32069 if (isBuyNow && responseProduct.buyNow) { 32070 helper.setInitProductData({ 32071 pid: responseProduct.id, 32072 quantity: responseProduct.selectedQuantity, 32073 options: responseProduct.options 32074 }); 32075 if (shoppaySession) { 32076 shoppaySession.close(); 32077 let updatedPaymentRequest = window.ShopPay.PaymentRequest.build(responseProduct.buyNow); 32078 shoppaySession = window.ShopPay.PaymentRequest.createSession({ 32079 paymentRequest: updatedPaymentRequest 32080 }); 32081 32082 helper.setSessionListeners(shoppaySession); 32083 } 32084 32085 } else { 32086 $.ajax({ 32087 url: helper.getUrlWithCsrfToken(window.shoppayClientRefs.urls.GetCartSummary), 32088 type: 'GET', 32089 contentType: 'application/json', 32090 async: false, 32091 success: function (data) { 32092 if (!data.error) { 32093 if (shoppaySession) { 32094 shoppaySession.close(); 32095 } 32096 let paymentRequest = window.ShopPay.PaymentRequest.build(response.product.buyNow); 32097 shoppaySession = window.ShopPay.PaymentRequest.createSession({ 32098 paymentRequest: paymentRequest 32099 }); 32100 helper.setSessionListeners(shoppaySession); 32101 } 32102 }, 32103 error: function (err) { 32104 if (err.responseJSON || err.status !== 200) { 32105 session.close(); 32106 // modal hasn't opened yet so "windowclosed" listener won't fire 32107 window.location.reload(); 32108 return; 32109 } 32110 } 32111 }); 32112 } 32113 }); 32114 } 32115 32116 return shoppaySession; 32117 } 32118} 32119 32120module.exports = { 32121 initShopPaySession: initShopPaySession 32122}; 32123},{"../helpers/shoppayHelper":127}],127:[function(require,module,exports){ 32124/* eslint-disable no-unused-vars */ 32125/* Global Variables */ 32126let checkoutUrl = null; 32127let observer; 32128let orderConfirmationData; 32129let productData = {}; 32130let reloadOnClose = true; 32131let sourceIdentifier = null; 32132const technicalErrorMsg = window.shoppayClientRefs ? window.shoppayClientRefs.constants.technicalError : null; 32133let token = null; 32134 32135/** 32136 * Add csrf token param to url 32137 * @param {string} url - source url 32138 * @param {string} basketId - UUID of the temporary basket in the session, if applicable 32139 * @returns {string} - url with csrf_token param 32140 */ 32141function getUrlWithCsrfToken(url, basketId) { 32142 const urlInstance = new URL(url, location.origin); 32143 32144 urlInstance.searchParams.append('csrf_token', getCsrfToken()); 32145 32146 if (basketId) { 32147 urlInstance.searchParams.append('basketId', basketId); 32148 } 32149 32150 return urlInstance.toString(); 32151} 32152 32153/** 32154 * Get CSRF Token 32155 * @returns {string} - csrf token value 32156 */ 32157function getCsrfToken() { 32158 let $element = document.querySelector('[data-csrf-token]'); 32159 32160 if ($element && $element.attributes['data-csrf-token'] && $element.attributes['data-csrf-token'].value) { 32161 return $element.attributes['data-csrf-token'].value; 32162 } 32163 32164 return ''; 32165} 32166 32167/** 32168 * Get Init Product Data (page load and captures data available on page load
32168) 32169 * @returns {Object} - productData with the following structure: { pid: prodId, quantity: selectedQuantity, options: selectedOptions } 32170 */ 32171function getInitProductData() { 32172 let productData = null; 32173 let $element = document.querySelector('[data-buy-now-init]'); 32174 if ($element && $element.attributes['data-buy-now-init'] && $element.attributes['data-buy-now-init'].value) { 32175 productData = JSON.parse($element.attributes['data-buy-now-init'].value); 32176 } 32177 return productData; 32178} 32179 32180/** 32181 * Set Init Product Data 32182 * @param {Object} data - accepts product data obj & updates global productData variable: { pid: prodId, quantity: selectedQuantity, options: selectedOptions } 32183 */ 32184function setInitProductData(data) { 32185 productData = data; 32186} 32187 32188/** 32189 * Sets Up ShopPay listener Events 32190 * @param {Object} session - Accepts the Shop Pay session object and establishes necessary event listeners on the session. 32191 */ 32192function setSessionListeners(session) { 32193 session.addEventListener("sessionrequested", function (ev) { 32194 let sessionPaymentRequest; 32195 if (window.shoppayClientRefs.constants.isBuyNow) { 32196 $.ajax({ 32197 url: getUrlWithCsrfToken(window.shoppayClientRefs.urls.PrepareBasket), 32198 method: 'POST', 32199 async: false, 32200 data: JSON.stringify(productData), 32201 contentType: 'application/json', 32202 success: function (data) { 32203 if (!data.error) { 32204 sessionPaymentRequest = data.paymentRequest; 32205 sourceIdentifier = data.basketId; 32206 } else { 32207 /* session.completeSessionRequest() does not take an errors array as input so just return 32208 and use default modal error handling. 32209 */ 32210 return; 32211 } 32212 }, 32213 error: function (err) { 32214 /* session.completeSessionRequest() does not take an errors array as input so just 32215 destroy the session and return. 32216 */ 32217 setTimeout(function() { 32218 session.close(); 32219 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32220 }, 2000); 32221 return; 32222 } 32223 }); 32224 } else { 32225 sessionPaymentRequest = session.paymentRequest; 32226 } 32227 32228 let requestData = { 32229 paymentRequest: sessionPaymentRequest 32230 }; 32231 if (window.shoppayClientRefs.constants.isBuyNow) { 32232 requestData.basketId = sourceIdentifier; 32233 } 32234 32235 $.ajax({ 32236 url: getUrlWithCsrfToken(window.shoppayClientRefs.urls.BeginSession), 32237 method: 'POST', 32238 async: false, 32239 data: JSON.stringify(requestData), 32240 contentType: 'application/json', 32241 success: function (data) { 32242 if (!data.error) { 32243 token = data.token; 32244 checkoutUrl = data.checkoutUrl; 32245 sourceIdentifier = data.sourceIdentifier; 32246 session.completeSessionRequest({token, checkoutUrl, sourceIdentifier}); 32247 } else { 32248 let errorMsg = technicalErrorMsg; 32249 if (data.errorMsg) { 32250 errorMsg = data.errorMsg; 32251 } 32252 /* session.completeSessionRequest() does not take an errors array as input so just return 32253 and use default modal error handling. 32254 */ 32255 return; 32256 } 32257 }, 32258 error: function (err) { 32259 /* session.completeSessionRequest() does not take an errors array as input so just 32260 destroy the session and return. 32261 */ 32262 setTimeout(function() { 32263 session.close(); 32264 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32265 }, 2000); 32266 return; 32267 } 32268 32269 }); 32270 }); 32271 32272 session.addEventListener("discountcodechanged", function(ev) { 32273 const currentPaymentRequest = session.paymentRequest; 32274 let requestData = { 32275 discountCodes: ev.discountCodes 32276 }; 32277 if (window.shoppayClientRefs.constants.isBuyNow) { 32278 requestData.basketId = sourceIdentifier; 32279 } 32280 32281 let responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.DiscountCodeChanged); 32282 if (responseJSON.exception){ 32283 session.completeDiscountCodeChange({ 32284 errors: [ 32285 { 32286 type: "discountCodeError", 32287 message: technicalErrorMsg 32288 } 32289 ] 32290 }); 32291 setTimeout(function() { 32292 session.close(); 32293 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32294 }, 2000); 32295 return; 32296 } else if (responseJSON.error) { 32297 let errorMsg = technicalErrorMsg; 32298 if (responseJSON.errorMsg) { 32299 errorMsg = responseJSON.errorMsg; 32300 } 32301 session.completeDiscountCodeChange({ 32302 errors: [ 32303 { 32304 type: "discountCodeError", 32305 message: errorMsg 32306 } 32307 ] 32308 }); 32309 return; 32310 } 32311 const { deliveryMethods, discountCodes, lineItems, shippingLines, subtotal, discounts, totalShippingPrice, totalTax, total } = responseJSON.paymentRequest; 32312 32313 var paymentRequestObject = {}; 32314 for (var propertyKey in currentPaymentRequest) { 32315 paymentRequestObject[propertyKey] = currentPaymentRequest[propertyKey]; 32316 } 32317 32318 let updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(currentPaymentRequest, { 32319 // ...currentPaymentRequest, 32320 discountCodes: discountCodes, 32321 lineItems: lineItems, 32322 shippingLines: shippingLines, 32323 deliveryMethods: deliveryMethods, 32324 subtotal: subtotal, 32325 discounts: discounts, 32326 totalTax: totalTax, 32327 total: total 32328 })); 32329 if (totalShippingPrice) { 32330 updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(updatedPaymentRequest, { 32331 // ...updatedPaymentRequest, 32332 totalShippingPrice: totalShippingPrice 32333 })); 32334 } 32335 32336 session.completeDiscountCodeChange({ updatedPaymentRequest: updatedPaymentRequest }); 32337 }); 32338 32339 session.addEventListener("deliverymethodchanged", function(ev) { 32340 const currentPaymentRequest = session.paymentRequest; 32341 let requestData = { 32342 deliveryMethod: ev.deliveryMethod, 32343 paymentRequest: currentPaymentRequest, 32344 }; 32345 32346 if (window.shoppayClientRefs.constants.isBuyNow) { 32347 requestData.basketId = sourceIdentifier; 32348 } 32349 32350 let responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.DeliveryMethodChanged); 32351 if (responseJSON.exception) { 32352 session.completeDeliveryMethodChange({ 32353 errors: [ 32354 { 32355 type: "shippingAddressError", 32356 message: technicalErrorMsg 32357 } 32358 ] 32359 }); 32360 setTimeout(function() { 32361 session.close(); 32362 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32363 }, 2000); 32364 return; 32365 } else if (responseJSON.error) { 32366 let errorMsg = technicalErrorMsg; 32367 if (responseJSON.errorMsg) { 32368 errorMsg = responseJSON.errorMsg; 32369 } 32370 const { shippingLines, totalShippingPrice, totalTax, total } = responseJSON.paymentRequest; 32371 const updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(currentPaymentRequest, { 32372 // ...currentPaymentRequest, 32373 shippingLines: shippingLines, 32374 totalShippingPrice: totalShippingPrice, 32375 totalTax: totalTax, 32376 total: total 32377 })); 32378 32379 session.completeDeliveryMethodChange({ 32380 errors: [ 32381 { 32382 type: "shippingAddressError", 32383 message: errorMsg 32384 } 32385 ], 32386 updatedPaymentRequest: updatedPaymentRequest 32387 }); 32388 return; 32389 } 32390 const { shippingLines, totalShippingPrice, totalTax, total } = responseJSON.paymentRequest; 32391 32392 // Update the payment request based on the delivery method change and update the total accordingly 32393 const updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(currentPaymentRequest, { 32394 // ...currentPaymentRequest, 32395 shippingLines: shippingLines, 32396 totalShippingPrice: totalShippingPrice, 32397 totalTax: totalTax, 32398 total: total 32399 })); 32400 32401 session.completeDeliveryMethodChange({ updatedPaymentRequest: updatedPaymentRequest }); 32402 }); 32403 32404 session.addEventListener("shippingaddresschanged", function(ev) { 32405 const currentPaymentRequest = session.paymentRequest; 32406 if (!ev.shippingAddress) { 32407 /* This event is triggered with no shipping address when a customer clicks "change" 32408 to choose an alternate email address in the modal 32409 */ 32410 session.completeShippingAddressChange({ updatedPaymentRequest: currentPaymentRequest }); 32411 return; 32412 } 32413 let requestData = { 32414 shippingAddress: ev.shippingAddress, 32415 paymentRequest: currentPaymentRequest, 32416 }; 32417 32418 if (window.shoppayClientRefs.constants.isBuyNow) { 32419 requestData.basketId = sourceIdentifier; 32420 } 32421 32422 let responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.ShippingAddressChanged); 32423 if (responseJSON.exception) { 32424 session.completeShippingAddressChange({ 32425 errors: [ 32426 { 32427 type: "shippingAddressError", 32428 message: technicalErrorMsg 32429 } 32430 ] 32431 }); 32432 setTimeout(function() { 32433 session.close(); 32434 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32435 }, 2000); 32436 return; 32437 } else if (responseJSON.error) { 32438 let errorMsg = technicalErrorMsg; 32439 if (responseJSON.errorMsg) { 32440 errorMsg = responseJSON.errorMsg; 32441 } 32442 session.completeShippingAddressChange({ 32443 errors: [ 32444 { 32445 type: "shippingAddressError", 32446 message: errorMsg 32447 } 32448 ] 32449 }); 32450 return; 32451 } 32452 const { deliveryMethods, shippingLines, totalShippingPrice, totalTax, total } = responseJSON.paymentRequest; 32453 32454 // Update the payment request based on the shipping address change 32455 const updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(currentPaymentRequest, { 32456 // ...currentPaymentRequest, 32457 deliveryMethods: deliveryMethods, 32458 shippingLines: shippingLines, 32459 totalShippingPrice: totalShippingPrice, 32460 totalTax: totalTax, 32461 total: total 32462 })); 32463 32464 session.completeShippingAddressChange({ updatedPaymentRequest: updatedPaymentRequest }); 32465 }); 32466 32467 session.addEventListener("paymentconfirmationrequested", function(ev) { 32468 const requestData = { 32469 token: session.token, 32470 paymentRequest: session.paymentRequest, 32471 }; 32472 32473 if (window.shoppayClientRefs.constants.isBuyNow) { 32474 requestData.basketId = sourceIdentifier; 32475 } 32476 32477 let responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.SubmitPayment); 32478 if (responseJSON.exception) { 32479 session.completePaymentConfirmationRequest({ 32480 errors: [ 32481 { 32482 type: "generalError", 32483 message: technicalErrorMsg 32484 } 32485 ] 32486 }); 32487 setTimeout(function() { 32488 session.close(); 32489 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32490 }, 2000); 32491 return; 32492 } else if (responseJSON.error) { 32493 let errorMsg = technicalErrorMsg; 32494 if (responseJSON.errorMsg) { 32495 errorMsg = responseJSON.errorMsg; 32496 } 32497 session.completePaymentConfirmationRequest({ 32498 errors: [ 32499 { 32500 type: "generalError", 32501 message: errorMsg 32502 } 32503 ] 32504 }); 32505 return; 32506 } 32507 32508 orderConfirmationData = { 32509 orderID: responseJSON.orderID, 32510 orderToken: responseJSON.orderToken,
32511 continueUrl: responseJSON.continueUrl 32512 }; 32513 session.completePaymentConfirmationRequest(); 32514 }); 32515 32516 session.addEventListener("paymentcomplete", function(ev) { 32517 var requestData = { 32518 token: session.token, 32519 paymentRequest: session.paymentRequest, 32520 event: ev 32521 }; 32522 if (window.shoppayClientRefs.constants.isBuyNow) { 32523 requestData.basketId = sourceIdentifier; 32524 } 32525 var responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.PaymentComplete); 32526 if (ev.processingStatus.status === "completed") { 32527 reloadOnClose = false; 32528 session.close(); 32529 var data = orderConfirmationData; 32530 var redirect = $('<form>').appendTo(document.body).attr({ 32531 method: 'POST', 32532 action: data.continueUrl 32533 }); 32534 $('<input>').appendTo(redirect).attr({ 32535 name: 'orderID', 32536 value: data.orderID 32537 }); 32538 $('<input>').appendTo(redirect).attr({ 32539 name: 'orderToken', 32540 value: data.orderToken 32541 }); 32542 redirect.submit(); 32543 } 32544 }); 32545 32546 session.addEventListener("windowclosed", function(ev) { 32547 // Reset global value to default 32548 // if (!reloadOnClose) { 32549 // reloadOnClose = true; 32550 // } else { 32551 // window.location.reload(); 32552 // } 32553 var requestData = { 32554 token: session.token, 32555 paymentRequest: session.paymentRequest, 32556 event: ev 32557 }; 32558 if (window.shoppayClientRefs.constants.isBuyNow) { 32559 requestData.basketId = sourceIdentifier; 32560 } 32561 var responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.WindowClosed); 32562 if (reloadOnClose) { 32563 $(document).trigger('Cart.Update'); 32564 } 32565 }); 32566 32567 session.addEventListener("deliverymethodtypechanged", function(ev) { 32568 var currentPaymentRequest = session.paymentRequest; 32569 var requestData = { 32570 deliveryMethodType: ev.deliveryMethodType, 32571 paymentRequest: currentPaymentRequest, 32572 }; 32573 32574 if (window.shoppayClientRefs.constants.isBuyNow) { 32575 requestData.basketId = sourceIdentifier; 32576 } 32577 32578 var responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.DeliveryMethodTypeChanged); 32579 var updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(currentPaymentRequest, responseJSON.paymentRequest)); 32580 if (responseJSON.exception) { 32581 session.completeDeliveryMethodTypeChange({ 32582 errors: [ 32583 { 32584 type: "shippingAddressError", 32585 message: technicalErrorMsg 32586 } 32587 ] 32588 }); 32589 setTimeout(function() { 32590 session.close(); 32591 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32592 }, 2000); 32593 return; 32594 } else if (responseJSON.error) { 32595 var errorMsg = technicalErrorMsg; 32596 if (responseJSON.errorMsg) { 32597 errorMsg = responseJSON.errorMsg; 32598 } 32599 session.completeDeliveryMethodTypeChange({ 32600 errors: [ 32601 { 32602 type: "shippingAddressError", 32603 message: errorMsg 32604 } 32605 ], 32606 updatedPaymentRequest: updatedPaymentRequest 32607 }); 32608 return; 32609 } 32610 session.completeDeliveryMethodTypeChange({ updatedPaymentRequest: updatedPaymentRequest }); 32611 }); 32612 32613 session.addEventListener("pickuplocationchanged", function(ev) { 32614 var currentPaymentRequest = session.paymentRequest; 32615 var requestData = { 32616 pickupLocation: ev.pickupLocation, 32617 paymentRequest: currentPaymentRequest, 32618 }; 32619 32620 if (window.shoppayClientRefs.constants.isBuyNow) { 32621 requestData.basketId = sourceIdentifier; 32622 } 32623 32624 var responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.PickupLocationChanged); 32625 var updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(currentPaymentRequest, responseJSON.paymentRequest)); 32626 if (responseJSON.exception) { 32627 session.completePickupLocationChange({ 32628 errors: [ 32629 { 32630 type: "shippingAddressError", 32631 message: technicalErrorMsg 32632 } 32633 ] 32634 }); 32635 setTimeout(function() { 32636 session.close(); 32637 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32638 }, 2000); 32639 return; 32640 } else if (responseJSON.error) { 32641 var errorMsg = technicalErrorMsg; 32642 if (responseJSON.errorMsg) { 32643 errorMsg = responseJSON.errorMsg; 32644 } 32645 session.completePickupLocationChange({ 32646 errors: [ 32647 { 32648 type: "shippingAddressError", 32649 message: errorMsg 32650 } 32651 ], 32652 updatedPaymentRequest: updatedPaymentRequest 32653 }); 32654 return; 32655 } 32656 session.completePickupLocationChange({ updatedPaymentRequest: updatedPaymentRequest }); 32657 }); 32658 32659 session.addEventListener("pickuplocationfilterchanged", function(ev) { 32660 var currentPaymentRequest = session.paymentRequest; 32661 var requestData = { 32662 buyerLocation: ev.buyerLocation, 32663 paymentRequest: currentPaymentRequest, 32664 }; 32665 32666 if (window.shoppayClientRefs.constants.isBuyNow) { 32667 requestData.basketId = sourceIdentifier; 32668 } 32669 32670 var responseJSON = createResponse(requestData, window.shoppayClientRefs.urls.PickupLocationFilterChanged); 32671 var updatedPaymentRequest = window.ShopPay.PaymentRequest.build($.extend(currentPaymentRequest, responseJSON.paymentRequest)); 32672 if (responseJSON.exception) { 32673 session.completePickupLocationFilterChange({ 32674 errors: [ 32675 { 32676 type: "shippingAddressError", 32677 message: technicalErrorMsg 32678 } 32679 ] 32680 }); 32681 setTimeout(function() { 32682 session.close(); 32683 // Event listeners have loaded so window.location.reload() will be called in windowclosed 32684 }, 2000); 32685 return; 32686 } else if (responseJSON.error) { 32687 var errorMsg = technicalErrorMsg; 32688 if (responseJSON.errorMsg) { 32689 errorMsg = responseJSON.errorMsg; 32690 } 32691 session.completePickupLocationFilterChange({ 32692 errors: [ 32693 { 32694 type: "shippingAddressError", 32695 message: errorMsg 32696 } 32697 ], 32698 updatedPaymentRequest: updatedPaymentRequest 32699 }); 32700 return; 32701 } 32702 session.completePickupLocationFilterChange({ updatedPaymentRequest: updatedPaymentRequest }); 32703 }); 32704} 32705 32706/** 32707 * Enables & Disables Shop Pay's Buy Now button click based on whether the product is ready to order on the PDP 32708 */ 32709function shoppayBtnDisabledStyle(elem, isReadyToOrder, forceDisable) { 32710 let readyToOrderPageLoad = isReadyToOrderOnPageLoad(); 32711 let isBuyNow = window.shoppayClientRefs.constants.isBuyNow; 32712 32713 if (elem) { 32714 // An error occurred, disable the button 32715 if (!isBuyNow && forceDisable) { 32716 elem.style.pointerEvents = 'none'; 32717 if (observer) { 32718 observer.disconnect(); 32719 } 32720 return; 32721 } 32722 if (!isBuyNow || (isBuyNow && (isReadyToOrder || readyToOrderPageLoad))) { 32723 elem.style.pointerEvents = 'auto'; 32724 } else { 32725 elem.style.pointerEvents = 'none'; 32726 } 32727 } 32728} 32729 32730/** 32731 * Watches for when ShopPay button is first rendered to the page to then apply correct button styling depending on whether the basket is empty or not 32732 */ 32733function shoppayMutationObserver(elemSelector) { 32734 observer = new MutationObserver((mutationsList, observer) => { 32735 const renderedShopPayElem = document.querySelector(elemSelector); 32736 if (renderedShopPayElem) { 32737 shoppayBtnDisabledStyle(renderedShopPayElem); 32738 observer.disconnect(); 32739 } 32740 }); 32741 32742 observer.observe(document.body, { childList: true, subtree: true }); 32743} 32744 32745/**
32746 * Checks whether a Buy Now product is ready on page load or not (ex: simple products vs. variants with multiple options to choose from, etc.) 32747 */ 32748function isReadyToOrderOnPageLoad() { 32749 let readyToOrder = false; 32750 let $element = document.querySelector('[data-ready-to-order]'); 32751 if ($element && $element.attributes['data-ready-to-order'] && $element.attributes['data-ready-to-order'].value) { 32752 readyToOrder = $element.attributes['data-ready-to-order'].value === "true"; 32753 } 32754 return readyToOrder; 32755} 32756 32757/** 32758 * Handles AJAX call to create / update the payment response needed for the ShopPay.PaymentRequest.build() method. 32759 * @param {Object} requestObj - a request object that contains relevant event data & session data. 32760 * @param {string} controllerURL - String url of the targeted controller (based on the urls Obj set in shoppayGlobalRefs.js) 32761 * @returns {Object} responseJSON - an updated response object to be used in the build & on the ShopPay.PaymentRequest object. 32762 */ 32763function createResponse (requestObj, controllerURL) { 32764 let responseJSON; 32765 $.ajax({ 32766 url: getUrlWithCsrfToken(controllerURL), 32767 method: 'POST', 32768 async: false, 32769 data: JSON.stringify(requestObj), 32770 contentType: 'application/json', 32771 success: function(data) { 32772 responseJSON = data; 32773 responseJSON.exception = false; 32774 }, 32775 error: function (err) { 32776 responseJSON = err.responseJSON ? err.responseJSON : {}; 32777 responseJSON.exception = true; 32778 } 32779 }); 32780 32781 return responseJSON; 32782} 32783 32784/** 32785 * Handles AJAX call to get the payment response. 32786 * @returns {Object} paymentResponse - an response object. 32787 */ 32788function buildPaymentRequest(session) { 32789 let token = document.querySelector('[data-csrf-token]'); 32790 let response; 32791 if (token) { 32792 const paymentResponse = $.ajax({ 32793 url: getUrlWithCsrfToken(window.shoppayClientRefs.urls.GetCartSummary), 32794 type: 'GET', 32795 contentType: 'application/json', 32796 async: false, 32797 success: function(data) { 32798 if (!data.error) { 32799 response = { 32800 responseJSON: data 32801 }; 32802 } else { 32803 shoppayBtnDisabledStyle(document.getElementById("shop-pay-button-container"), null, true); 32804 } 32805 }, 32806 error: function(err) { 32807 if (session) { 32808 /* Return to exit function - don't reload the page in case there is a page rendering 32809 issue (will result in infinite reload loop). 32810 */ 32811 session.close(); 32812 } 32813 shoppayBtnDisabledStyle(document.getElementById("shop-pay-button-container"), null, true); 32814 } 32815 }); 32816 return response; 32817 } else { 32818 /* Return to exit function - don't reload the page in case there is a page rendering 32819 issue (will result in infinite reload loop). 32820 */ 32821 if (session) { 32822 session.close(); 32823 } 32824 shoppayBtnDisabledStyle(document.getElementById("shop-pay-button-container"), null, true); 32825 } 32826} 32827 32828module.exports = { 32829 buildPaymentRequest: buildPaymentRequest, 32830 createResponse: createResponse, 32831 getCsrfToken: getCsrfToken, 32832 getInitProductData: getInitProductData, 32833 getUrlWithCsrfToken: getUrlWithCsrfToken, 32834 isReadyToOrderOnPageLoad: isReadyToOrderOnPageLoad, 32835 productData: productData, 32836 setInitProductData: setInitProductData, 32837 setSessionListeners: setSessionListeners, 32838 shoppayBtnDisabledStyle: shoppayBtnDisabledStyle, 32839 shoppayMutationObserver: shoppayMutationObserver, 32840}; 32841 32842},{}],128:[function(require,module,exports){ 32843'use strict'; 32844 32845exports.ServiceSuffixes = { 32846 ServiceSuite: '/ecomm/0.1', 32847 Authenticate: '/authenticate/root', 32848 PurchaseGiftCard: '/fulfillment/0.1/purchaseegift/' 32849}; 32850 32851exports.MessagePrefixes = { 32852 NonSuccess: 'Stored Value Solutions returned a result other than OK and/or without data ', 32853 Error: 'Stored Value Solutions encountered and unexpected exception ' 32854}; 32855 32856exports.TransactionInformation = { 32857 Success: 'Successful Transaction - No Additional Information', 32858 Failure: { 32859 BalanceExceeded: 'Order Failure - Requested Amount Exceeded Gift Card Balance',
32860 HeldAmountReleased: 'Order Failure - Releasing Amount Held by Pre-Authorization' 32861 } 32862} 32863 32864exports.TransactionTypes = { 32865 BalanceInquiry: 'Balance Inquiry', 32866 PreAuthorization: 'Pre-Authorization', 32867 PreAuthorizationComplete: 'Pre-Authorization Complete' 32868} 32869 32870exports.ResponseParsers = { 32871 balanceInquiryResponse: { 32872 Path: '/int_svs/cartridge/scripts/BalanceInquiryResponseParser', 32873 BodyNode: 'balanceInquiryReturn' 32874 }, 32875 preAuthResponse: { 32876 Path: '/int_svs/cartridge/scripts/PreAuthorizationResponseParser', 32877 BodyNode: 'preAuthReturn' 32878 }, 32879 preAuthCompleteResponse: { 32880 Path: '/int_svs/cartridge/scripts/PreAuthorizationCompleteResponseParser', 32881 BodyNode: 'preAuthCompleteReturn' 32882 } 32883}; 32884 32885exports.ReturnCodes = { 32886 Approval: '01', 32887 InactiveCard: '02', 32888 InvalidCardNumber: '03', 32889 InvalidTransactionCode: '04', 32890 InsufficientFunds: '05', 32891 NoPreviousAuthorizations: '06', 32892 InvalidMessage: '07', 32893 NoCardFound: '08', 32894 InsufficentFundsDueToOutstandingPreAuthorization: '09', 32895 DenialNoPreviousAuthorization: '10', 32896 NoAuthorizationNumber: '11', 32897 InvalidAuthorizationNumber: '12', 32898 MaximumSingleRechargeExceeded: '13', 32899 MaximumWOrkingBalanceExceeded: '14', 32900 HostUnavailable: '15', 32901 InvalidCardStatus: '16', 32902 UnknownDealerStoreCodeSpecialEdit: '17', 32903 MaximumNumberOfRechargesExceeded: '18', 32904 InvalidCardVerificationValueOrSecondarySecurityCode: '19', 32905 InvalidPinNumberOrPinLocked: '20', 32906 CardAlreadyIssued: '21', 32907 CardNotIssued: '22', 32908 CardAlreadyUsed: '23', 32909 ManualTransactionNotAllowed: '24', 32910 MagStripeReadNotValid: '25', 32911 TransactionTypeUnknown: '26', 32912 InvalidTenderType: '27', 32913 InvalidCustomerType: '28', 32914 MaxNumbherOfRedemptionExceeded: '30', 32915 InvalidCurrencyCode: '31', 32916 InvalidServerId: '32', 32917 FrozenCardOrUnknown: '33', 32918 InvalidAmount: '34', 32919 TransactionRejectedInvalidTransactionPromotionWideOrInvalidForOriginatingMerchantAndStore: '36', 32920 TransactionRejectedInvalidMerchantAndStoreCombinationForPromotion: '37', 32921 TransactionRejectedExceededMaximumNumberOfPromotionCards: '38', 32922 TransactionDeclinedAmountLessThanMinimum: '42', 32923 FailureInRetrievingData: '99', 32924 RateLimitExceeded: '999' 32925}; 32926 32927exports.ReturnDescriptionMessagesForReturnCodes = { 32928 '03': 'Invalid Card or PIN Number', 32929 '08': 'Invalid Card or PIN Number', 32930 '20': 'Invalid Card or PIN Number' 32931} 32932 32933exports.GiftCardTypes = { 32934 eGift: 'eGift', 32935 Physical: 'Physical', 32936 NotApplicable: 'NotApplicable' 32937}; 32938 32939exports.OrderTypes = { 32940 Interactive: 'I', 32941 Web: 'W' 32942}; 32943},{}],129:[function(require,module,exports){ 32944"use strict"; 32945 32946// rawAsap provides everything we need except exception management. 32947var rawAsap = require("./raw"); 32948// RawTasks are recycled to reduce GC churn. 32949var freeTasks = []; 32950// We queue errors to ensure they are thrown in right order (FIFO). 32951// Array-as-queue is good enough here, since we are just dealing with exceptions. 32952var pendingErrors = []; 32953var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError); 32954 32955function throwFirstError() { 32956 if (pendingErrors.length) { 32957 throw pendingErrors.shift(); 32958 } 32959} 32960 32961/** 32962 * Calls a task as soon as possible after returning, in its own event, with priority 32963 * over other events like animation, reflow, and repaint. An error thrown from an 32964 * event will not interrupt, nor even substantially slow down the processing of 32965 * other events, but will be rather postponed to a lower priority event. 32966 * @param {{call}} task A callable object, typically a function that takes no 32967 * arguments. 32968 */ 32969module.exports = asap; 32970function asap(task) { 32971 var rawTask; 32972 if (freeTasks.length) { 32973 rawTask = freeTasks.pop(); 32974 } else { 32975 rawTask = new RawTask(); 32976 } 32977 rawTask.task = task; 32978 rawAsap(rawTask); 32979} 32980 32981// We wrap tasks with recyclable task objects. A task object implements 32982// `call`, just like a function. 32983function RawTask() { 32984 this.task = null; 32985} 32986 32987// The sole purpose of wrapping the task is to catch the exception and recycle 32988// the task object after its single use. 32989RawTask.prototype.call = function () { 32990 try { 32991 this.task.call(); 32992 } catch (error) { 32993 if (asap.onerror) { 32994 // This hook exists purely for testing purposes. 32995 // Its name will be periodically randomized to break any code that 32996 // depends on its existence.
32997 asap.onerror(error); 32998 } else { 32999 // In a web browser, exceptions are not fatal. However, to avoid 33000 // slowing down the queue of pending tasks, we rethrow the error in a 33001 // lower priority turn. 33002 pendingErrors.push(error); 33003 requestErrorThrow(); 33004 } 33005 } finally { 33006 this.task = null; 33007 freeTasks[freeTasks.length] = this; 33008 } 33009}; 33010 33011},{"./raw":130}],130:[function(require,module,exports){ 33012(function (global){(function (){ 33013"use strict"; 33014 33015// Use the fastest means possible to execute a task in its own turn, with 33016// priority over other events including IO, animation, reflow, and redraw 33017// events in browsers. 33018// 33019// An exception thrown by a task will permanently interrupt the processing of 33020// subsequent tasks. The higher level `asap` function ensures that if an 33021// exception is thrown by a task, that the task queue will continue flushing as 33022// soon as possible, but if you use `rawAsap` directly, you are responsible to 33023// either ensure that no exceptions are thrown from your task, or to manually 33024// call `rawAsap.requestFlush` if an exception is thrown. 33025module.exports = rawAsap; 33026function rawAsap(task) { 33027 if (!queue.length) { 33028 requestFlush(); 33029 flushing = true; 33030 } 33031 // Equivalent to push, but avoids a function call. 33032 queue[queue.length] = task; 33033} 33034 33035var queue = []; 33036// Once a flush has been requested, no further calls to `requestFlush` are 33037// necessary until the next `flush` completes. 33038var flushing = false; 33039// `requestFlush` is an implementation-specific method that attempts to kick 33040// off a `flush` event as quickly as possible. `flush` will attempt to exhaust 33041// the event queue before yielding to the browser's own event loop. 33042var requestFlush; 33043// The position of the next task to execute in the task queue. This is 33044// preserved between calls to `flush` so that it can be resumed if 33045// a task throws an exception. 33046var index = 0; 33047// If a task schedules additional tasks recursively, the task queue can grow 33048// unbounded. To prevent memory exhaustion, the task queue will periodically 33049// truncate already-completed tasks. 33050var capacity = 1024; 33051 33052// The flush function processes all tasks that have been scheduled with 33053// `rawAsap` unless and until one of those tasks throws an exception. 33054// If a task throws an exception, `flush` ensures that its state will remain 33055// consistent and will resume where it left off when called again. 33056// However, `flush` does not make any arrangements to be called again if an 33057// exception is thrown. 33058function flush() { 33059 while (index < queue.length) { 33060 var currentIndex = index; 33061 // Advance the index before calling the task. This ensures that we will 33062 // begin flushing on the next task the task throws an error. 33063 index = index + 1; 33064 queue[currentIndex].call(); 33065 // Prevent leaking memory for long chains of recursive calls to `asap`. 33066 // If we call `asap` within tasks scheduled by `asap`, the queue will 33067 // grow, but to avoid an O(n) walk for every task we execute, we don't 33068 // shift tasks off the queue after they have been executed. 33069 // Instead, we periodically shift 1024 tasks off the queue. 33070 if (index > capacity) { 33071 // Manually shift all values starting at the index back to the 33072 // beginning of the queue. 33073 for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { 33074 queue[scan] = queue[scan + index]; 33075 } 33076 queue.length -= index; 33077 index = 0; 33078 } 33079 } 33080 queue.length = 0; 33081 index = 0; 33082 flushing = false; 33083} 33084 33085// `requestFlush` is implemented using a strategy based on data collected from 33086// every available SauceLabs Selenium web driver worker at time of writing. 33087// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 33088 33089// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that 33090// have WebKitMutationObserver but not un-prefixed MutationObserver. 33091// Must use `global` or `self` instead of `window` to work in both frames and web 33092// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. 33093 33094/* globals self */ 33095var scope = typeof global !== "undefined" ? global : self; 33096var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver; 33097 33098// MutationObservers are desirable because they have high priority and work 33099// reliably everywhere they are implemented. 33100// They are implemented in all modern browsers. 33101// 33102// - Android 4-4.3 33103// - Chrome 26-34 33104// - Firefox 14-29 33105// - Internet Explorer 11 33106// - iPad Safari 6-7.1 33107// - iPhone Safari 7-7.1 33108// - Safari 6-7 33109if (typeof BrowserMutationObserver === "function") { 33110 requestFlush = makeRequestCallFromMutationObserver(flush); 33111 33112// MessageChannels are desirable because they give direct access to the HTML 33113// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera 33114// 11-12, and in web workers in many engines. 33115// Although message channels yield to any queued rendering and IO tasks, they 33116// would be better than imposing the 4ms delay of timers. 33117// However, they do not work reliably in Internet Explorer or Safari. 33118 33119// Internet Explorer 10 is the only browser that has setImmediate but does 33120// not have MutationObservers. 33121// Although setImmediate yields to the browser's renderer, it would be 33122// preferrable to falling back to setTimeout since it does not have 33123// the minimum 4ms penalty. 33124// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (
33124and 33125// Desktop to a lesser extent) that renders both setImmediate and 33126// MessageChannel useless for the purposes of ASAP. 33127// https://github.com/kriskowal/q/issues/396 33128 33129// Timers are implemented universally. 33130// We fall back to timers in workers in most engines, and in foreground 33131// contexts in the following browsers. 33132// However, note that even this simple case requires nuances to operate in a 33133// broad spectrum of browsers. 33134// 33135// - Firefox 3-13 33136// - Internet Explorer 6-9 33137// - iPad Safari 4.3 33138// - Lynx 2.8.7 33139} else { 33140 requestFlush = makeRequestCallFromTimer(flush); 33141} 33142 33143// `requestFlush` requests that the high priority event queue be flushed as 33144// soon as possible. 33145// This is useful to prevent an error thrown in a task from stalling the event 33146// queue if the exception handled by Node.js’s 33147// `process.on("uncaughtException")` or by a domain. 33148rawAsap.requestFlush = requestFlush; 33149 33150// To request a high priority event, we induce a mutation observer by toggling 33151// the text of a text node between "1" and "-1". 33152function makeRequestCallFromMutationObserver(callback) { 33153 var toggle = 1; 33154 var observer = new BrowserMutationObserver(callback); 33155 var node = document.createTextNode(""); 33156 observer.observe(node, {characterData: true}); 33157 return function requestCall() { 33158 toggle = -toggle; 33159 node.data = toggle; 33160 }; 33161} 33162 33163// The message channel technique was discovered by Malte Ubl and was the 33164// original foundation for this library. 33165// http://www.nonblocking.io/2011/06/windownexttick.html 33166 33167// Safari 6.0.5 (at least) intermittently fails to create message ports on a 33168// page's first load. Thankfully, this version of Safari supports 33169// MutationObservers, so we don't need to fall back in that case. 33170 33171// function makeRequestCallFromMessageChannel(callback) { 33172// var channel = new MessageChannel(); 33173// channel.port1.onmessage = callback; 33174// return function requestCall() { 33175// channel.port2.postMessage(0); 33176// }; 33177// } 33178 33179// For reasons explained above, we are also unable to use `setImmediate` 33180// under any circumstances. 33181// Even if we were, there is another bug in Internet Explorer 10. 33182// It is not sufficient to assign `setImmediate` to `requestFlush` because 33183// `setImmediate` must be called *by name* and therefore must be wrapped in a 33184// closure. 33185// Never forget. 33186 33187// function makeRequestCallFromSetImmediate(callback) { 33188// return function requestCall() { 33189// setImmediate(callback); 33190// }; 33191// } 33192 33193// Safari 6.0 has a problem where timers will get lost while the user is 33194// scrolling. This problem does not impact ASAP because Safari 6.0 supports 33195// mutation observers, so that implementation is used instead. 33196// However, if we ever elect to use timers in Safari, the prevalent work-around 33197// is to add a scroll event listener that calls for a flush. 33198 33199// `setTimeout` does not call the passed callback if the delay is less than 33200// approximately 7 in web workers in Firefox 8 through 18, and sometimes not 33201// even then. 33202 33203function makeRequestCallFromTimer(callback) { 33204 return function requestCall() { 33205 // We dispatch a timeout with a specified delay of 0 for engines that 33206 // can reliably accommodate that request. This will usually be snapped 33207 // to a 4 milisecond delay, but once we're flushing, there's no delay 33208 // between events. 33209 var timeoutHandle = setTimeout(handleTimer, 0); 33210 // However, since this timer gets frequently dropped in Firefox 33211 // workers, we enlist an interval handle that will try to fire 33212 // an event 20 times per second until it succeeds. 33213 var intervalHandle = setInterval(handleTimer, 50); 33214 33215 function handleTimer() { 33216 // Whichever timer succeeds will cancel both timers and 33217 // execute the callback. 33218 clearTimeout(timeoutHandle); 33219 clearInterval(intervalHandle); 33220 callback(); 33221 } 33222 }; 33223} 33224 33225// This is for `asap.js` only. 33226// Its name will be periodically randomized to break any code that depends on 33227// its existence. 33228rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer; 33229 33230// ASAP was originally a nextTick shim included in Q. This was factored out 33231// into this ASAP package. It was later adapted to RSVP which made further 33232// amendments. These decisions, particularly to marginalize MessageChannel and 33233// to capture the MutationObserver implementation in a closure, were integrated 33234// back into ASAP proper. 33235// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js 33236 33237}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 33238 33239},{}],131:[function(require,module,exports){ 33240/*! 33241 * eventie v1.0.6 33242 * event binding helper 33243 * eventie.bind( elem, 'click', myFn ) 33244 * eventie.unbind( elem, 'click', myFn ) 33245 * MIT license 33246 */ 33247 33248/*jshint browser: true, undef: true, unused: true */ 33249/*global define: false, module: false */ 33250 33251( function( window ) { 33252 33253'use strict'; 33254 33255var docElem = document.documentElement; 33256 33257var bind = function() {}; 33258 33259function getIEEvent( obj ) { 33260 var event = window.event; 33261 // add event.target 33262 event.target = event.target || event.srcElement || obj; 33263 return event; 33264} 33265 33266if ( docElem.addEventListener ) { 33267 bind = function( obj, type, fn ) { 33268 obj.addEventListener( type, fn, false ); 33269 }; 33270} else if ( docElem.attachEvent ) { 33271 bind = function( obj, type, fn ) { 33272 obj[ type + fn ] = fn.handleEvent ? 33273 function() { 33274 var event = getIEEvent( obj ); 33275 fn.handleEvent.call( fn, event ); 33276 } : 33277 function() { 33278 var event = getIEEvent( obj ); 33279 fn.call( obj, event ); 33280 }; 33281 obj.attachEvent( "on" + type, obj[ type + fn ] ); 33282 }; 33283} 33284 33285var unbind = function() {}; 33286 33287if ( docElem.removeEventListener ) { 33288 unbind = function( obj, type, fn ) { 33289 obj.removeEventListener( type, fn, false ); 33290 }; 33291} else if ( docElem.detachEvent ) { 33292 unbind = function( obj, type, fn ) { 33293 obj.detachEvent( "on" + type, obj[ type + fn ] ); 33294 try { 33295 delete obj[ type + fn ]; 33296 } catch ( err ) { 33297 // can't delete window object properties 33298 obj[ type + fn ] = undefined; 33299 } 33300 }; 33301} 33302 33303var eventie = { 33304 bind: bind, 33305 unbind: unbind 33306}; 33307 33308// ----- module definition ----- // 33309 33310if ( typeof define === 'function' && define.amd ) { 33311 // AMD 33312 define( eventie ); 33313} else if ( typeof exports === 'object' ) { 33314 // CommonJS 33315 module.exports = eventie; 33316} else { 33317 // browser global 33318 window.eventie = eventie; 33319} 33320 33321})( window ); 33322 33323},{}
33323],132:[function(require,module,exports){ 33324/*! 33325 * imagesLoaded v3.2.0 33326 * JavaScript is all like "You images are done yet or what?" 33327 * MIT License 33328 */ 33329 33330( function( window, factory ) { 'use strict'; 33331 // universal module definition 33332 33333 /*global define: false, module: false, require: false */ 33334 33335 if ( typeof define == 'function' && define.amd ) { 33336 // AMD 33337 define( [ 33338 'eventEmitter/EventEmitter', 33339 'eventie/eventie' 33340 ], function( EventEmitter, eventie ) { 33341 return factory( window, EventEmitter, eventie ); 33342 }); 33343 } else if ( typeof module == 'object' && module.exports ) { 33344 // CommonJS 33345 module.exports = factory( 33346 window, 33347 require('wolfy87-eventemitter'), 33348 require('eventie') 33349 ); 33350 } else { 33351 // browser global 33352 window.imagesLoaded = factory( 33353 window, 33354 window.EventEmitter, 33355 window.eventie 33356 ); 33357 } 33358 33359})( window, 33360 33361// -------------------------- factory -------------------------- // 33362 33363function factory( window, EventEmitter, eventie ) { 33364 33365'use strict'; 33366 33367var $ = window.jQuery; 33368var console = window.console; 33369 33370// -------------------------- helpers -------------------------- // 33371 33372// extend objects 33373function extend( a, b ) { 33374 for ( var prop in b ) { 33375 a[ prop ] = b[ prop ]; 33376 } 33377 return a; 33378} 33379 33380var objToString = Object.prototype.toString; 33381function isArray( obj ) { 33382 return objToString.call( obj ) == '[object Array]'; 33383} 33384 33385// turn element or nodeList into an array 33386function makeArray( obj ) { 33387 var ary = []; 33388 if ( isArray( obj ) ) { 33389 // use object if already an array 33390 ary = obj; 33391 } else if ( typeof obj.length == 'number' ) { 33392 // convert nodeList to array 33393 for ( var i=0; i < obj.length; i++ ) { 33394 ary.push( obj[i] ); 33395 } 33396 } else { 33397 // array of single index 33398 ary.push( obj ); 33399 } 33400 return ary; 33401} 33402 33403 // -------------------------- imagesLoaded -------------------------- // 33404 33405 /** 33406 * @param {Array, Element, NodeList, String} elem 33407 * @param {Object or Function} options - if function, use as callback 33408 * @param {Function} onAlways - callback function 33409 */ 33410 function ImagesLoaded( elem, options, onAlways ) { 33411 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 33412 if ( !( this instanceof ImagesLoaded ) ) { 33413 return new ImagesLoaded( elem, options, onAlways ); 33414 } 33415 // use elem as selector string 33416 if ( typeof elem == 'string' ) { 33417 elem = document.querySelectorAll( elem ); 33418 } 33419 33420 this.elements = makeArray( elem ); 33421 this.options = extend( {}, this.options ); 33422 33423 if ( typeof options == 'function' ) { 33424 onAlways = options; 33425 } else { 33426 extend( this.options, options ); 33427 } 33428 33429 if ( onAlways ) { 33430 this.on( 'always', onAlways ); 33431 } 33432 33433 this.getImages(); 33434 33435 if ( $ ) { 33436 // add jQuery Deferred object 33437 this.jqDeferred = new $.Deferred(); 33438 } 33439 33440 // HACK check async to allow time to bind listeners 33441 var _this = this; 33442 setTimeout( function() { 33443 _this.check(); 33444 }); 33445 } 33446 33447 ImagesLoaded.prototype = new EventEmitter(); 33448 33449 ImagesLoaded.prototype.options = {}; 33450 33451 ImagesLoaded.prototype.getImages = function() { 33452 this.images = []; 33453 33454 // filter & find items if we have an item selector 33455 for ( var i=0; i < this.elements.length; i++ ) { 33456 var elem = this.elements[i]; 33457 this.addElementImages( elem ); 33458 } 33459 }; 33460 33461 /** 33462 * @param {Node} element 33463 */ 33464 ImagesLoaded.prototype.addElementImages = function( elem ) { 33465 // filter siblings 33466 if ( elem.nodeName == 'IMG' ) { 33467 this.addImage( elem ); 33468 } 33469 // get background image on element 33470 if ( this.options.background === true ) { 33471 this.addElementBackgroundImages( elem ); 33472 } 33473 33474 // find children 33475 // no non-element nodes, #143 33476 var nodeType = elem.nodeType; 33477 if ( !nodeType || !elementNodeTypes[ nodeType ] ) { 33478 return; 33479 } 33480 var childImgs = elem.querySelectorAll('img'); 33481 // concat childElems to filterFound array 33482 for ( var i=0; i < childImgs.length; i++ ) { 33483 var img = childImgs[i]; 33484 this.addImage( img ); 33485 } 33486 33487 // get child background images 33488 if ( typeof this.options.background == 'string' ) { 33489 var children = elem.querySelectorAll( this.options.background ); 33490 for ( i=0; i < children.length; i++ ) { 33491 var child = children[i];
33492 this.addElementBackgroundImages( child ); 33493 } 33494 } 33495 }; 33496 33497 var elementNodeTypes = { 33498 1: true, 33499 9: true, 33500 11: true 33501 }; 33502 33503 ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 33504 var style = getStyle( elem ); 33505 // get url inside url("...") 33506 var reURL = /url\(['"]*([^'"\)]+)['"]*\)/gi; 33507 var matches = reURL.exec( style.backgroundImage ); 33508 while ( matches !== null ) { 33509 var url = matches && matches[1]; 33510 if ( url ) { 33511 this.addBackground( url, elem ); 33512 } 33513 matches = reURL.exec( style.backgroundImage ); 33514 } 33515 }; 33516 33517 // IE8 33518 var getStyle = window.getComputedStyle || function( elem ) { 33519 return elem.currentStyle; 33520 }; 33521 33522 /** 33523 * @param {Image} img 33524 */ 33525 ImagesLoaded.prototype.addImage = function( img ) { 33526 var loadingImage = new LoadingImage( img ); 33527 this.images.push( loadingImage ); 33528 }; 33529 33530 ImagesLoaded.prototype.addBackground = function( url, elem ) { 33531 var background = new Background( url, elem ); 33532 this.images.push( background ); 33533 }; 33534 33535 ImagesLoaded.prototype.check = function() { 33536 var _this = this; 33537 this.progressedCount = 0; 33538 this.hasAnyBroken = false; 33539 // complete if no images 33540 if ( !this.images.length ) { 33541 this.complete(); 33542 return; 33543 } 33544 33545 function onProgress( image, elem, message ) { 33546 // HACK - Chrome triggers event before object properties have changed. #83 33547 setTimeout( function() { 33548 _this.progress( image, elem, message ); 33549 }); 33550 } 33551 33552 for ( var i=0; i < this.images.length; i++ ) { 33553 var loadingImage = this.images[i]; 33554 loadingImage.once( 'progress', onProgress ); 33555 loadingImage.check(); 33556 } 33557 }; 33558 33559 ImagesLoaded.prototype.progress = function( image, elem, message ) { 33560 this.progressedCount++; 33561 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 33562 // progress event 33563 this.emit( 'progress', this, image, elem ); 33564 if ( this.jqDeferred && this.jqDeferred.notify ) { 33565 this.jqDeferred.notify( this, image ); 33566 } 33567 // check if completed 33568 if ( this.progressedCount == this.images.length ) { 33569 this.complete(); 33570 } 33571 33572 if ( this.options.debug && console ) { 33573 console.log( 'progress: ' + message, image, elem ); 33574 } 33575 }; 33576 33577 ImagesLoaded.prototype.complete = function() { 33578 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 33579 this.isComplete = true; 33580 this.emit( eventName, this ); 33581 this.emit( 'always', this ); 33582 if ( this.jqDeferred ) { 33583 var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 33584 this.jqDeferred[ jqMethod ]( this ); 33585 } 33586 }; 33587 33588 // -------------------------- -------------------------- // 33589 33590 function LoadingImage( img ) { 33591 this.img = img; 33592 } 33593 33594 LoadingImage.prototype = new EventEmitter(); 33595 33596 LoadingImage.prototype.check = function() { 33597 // If complete is true and browser supports natural sizes, 33598 // try to check for image status manually. 33599 var isComplete = this.getIsImageComplete(); 33600 if ( isComplete ) { 33601 // report based on naturalWidth 33602 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 33603 return; 33604 } 33605 33606 // If none of the checks above matched, simulate loading on detached element. 33607 this.proxyImage = new Image(); 33608 eventie.bind( this.proxyImage, 'load', this ); 33609 eventie.bind( this.proxyImage, 'error', this ); 33610 // bind to image as well for Firefox. #191 33611 eventie.bind( this.img, 'load', this ); 33612 eventie.bind( this.img, 'error', this ); 33613 this.proxyImage.src = this.img.src; 33614 }; 33615 33616 LoadingImage.prototype.getIsImageComplete = function() { 33617 return this.img.complete && this.img.naturalWidth !== undefined; 33618 }; 33619 33620 LoadingImage.prototype.confirm = function( isLoaded, message ) { 33621 this.isLoaded = isLoaded; 33622 this.emit( 'progress', this, this.img, message ); 33623 }; 33624 33625 // ----- events ----- // 33626 33627 // trigger specified handler for event type 33628 LoadingImage.prototype.handleEvent = function( event ) { 33629 var method = 'on' + event.type; 33630 if ( this[ method ] ) { 33631 this[ method ]( event ); 33632 } 33633 }; 33634 33635 LoadingImage.prototype.onload = function() { 33636 this.confirm( true, 'onload' ); 33637 this.unbindEvents(); 33638 }; 33639 33640 LoadingImage.prototype.onerror = function() { 33641 this.confirm( false, 'onerror' ); 33642 this.unbindEvents(); 33643 }; 33644 33645 LoadingImage.prototype.unbindEvents = function() { 33646 eventie.unbind( this.proxyImage, 'load', this ); 33647 eventie.unbind( this.proxyImage, 'error', this ); 33648 eventie.unbind( this.img, 'load', this ); 33649 eventie.unbind( this.img, 'error', this ); 33650 }; 33651
33652 // -------------------------- Background -------------------------- // 33653 33654 function Background( url, element ) { 33655 this.url = url; 33656 this.element = element; 33657 this.img = new Image(); 33658 } 33659 33660 // inherit LoadingImage prototype 33661 Background.prototype = new LoadingImage(); 33662 33663 Background.prototype.check = function() { 33664 eventie.bind( this.img, 'load', this ); 33665 eventie.bind( this.img, 'error', this ); 33666 this.img.src = this.url; 33667 // check if image is already complete 33668 var isComplete = this.getIsImageComplete(); 33669 if ( isComplete ) { 33670 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 33671 this.unbindEvents(); 33672 } 33673 }; 33674 33675 Background.prototype.unbindEvents = function() { 33676 eventie.unbind( this.img, 'load', this ); 33677 eventie.unbind( this.img, 'error', this ); 33678 }; 33679 33680 Background.prototype.confirm = function( isLoaded, message ) { 33681 this.isLoaded = isLoaded; 33682 this.emit( 'progress', this, this.element, message ); 33683 }; 33684 33685 // -------------------------- jQuery -------------------------- // 33686 33687 ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 33688 jQuery = jQuery || window.jQuery; 33689 if ( !jQuery ) { 33690 return; 33691 } 33692 // set local variable 33693 $ = jQuery; 33694 // $().imagesLoaded() 33695 $.fn.imagesLoaded = function( options, callback ) { 33696 var instance = new ImagesLoaded( this, options, callback ); 33697 return instance.jqDeferred.promise( $(this) ); 33698 }; 33699 }; 33700 // try making plugin 33701 ImagesLoaded.makeJQueryPlugin(); 33702 33703 // -------------------------- -------------------------- // 33704 33705 return ImagesLoaded; 33706 33707}); 33708 33709},{"eventie":131,"wolfy87-eventemitter":142}],133:[function(require,module,exports){ 33710(function (global){(function (){ 33711/** 33712 * @license 33713 * lodash 3.10.1 (Custom Build) <https://lodash.com/> 33714 * Build: `lodash modern -d -o ./index.js` 33715 * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/> 33716 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> 33717 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 33718 * Available under MIT license <https://lodash.com/license> 33719 */ 33720;(function() { 33721 33722 /** Used as a safe reference for `undefined` in pre-ES5 environments. */ 33723 var undefined; 33724 33725 /** Used as the semantic version number. */ 33726 var VERSION = '3.10.1'; 33727 33728 /** Used to compose bitmasks for wrapper metadata. */ 33729 var BIND_FLAG = 1, 33730 BIND_KEY_FLAG = 2, 33731 CURRY_BOUND_FLAG = 4, 33732 CURRY_FLAG = 8, 33733 CURRY_RIGHT_FLAG = 16, 33734 PARTIAL_FLAG = 32, 33735 PARTIAL_RIGHT_FLAG = 64, 33736 ARY_FLAG = 128, 33737 REARG_FLAG = 256; 33738 33739 /** Used as default options for `_.trunc`. */ 33740 var DEFAULT_TRUNC_LENGTH = 30, 33741 DEFAULT_TRUNC_OMISSION = '...'; 33742 33743 /** Used to detect when a function becomes hot. */ 33744 var HOT_COUNT = 150, 33745 HOT_SPAN = 16; 33746 33747 /** Used as the size to enable large array optimizations. */ 33748 var LARGE_ARRAY_SIZE = 200; 33749 33750 /** Used to indicate the type of lazy iteratees. */ 33751 var LAZY_FILTER_FLAG = 1, 33752 LAZY_MAP_FLAG = 2; 33753 33754 /** Used as the `TypeError` message for "Functions" methods. */ 33755 var FUNC_ERROR_TEXT = 'Expected a function'; 33756 33757 /** Used as the internal argument placeholder. */ 33758 var PLACEHOLDER = '__lodash_placeholder__'; 33759 33760 /** `Object#toString` result references. */ 33761 var argsTag = '[object Arguments]', 33762 arrayTag = '[object Array]', 33763 boolTag = '[object Boolean]', 33764 dateTag = '[object Date]', 33765 errorTag = '[object Error]', 33766 funcTag = '[object Function]', 33767 mapTag = '[object Map]', 33768 numberTag = '[object Number]', 33769 objectTag = '[object Object]', 33770 regexpTag = '[object RegExp]', 33771 setTag = '[object Set]', 33772 stringTag = '[object String]', 33773 weakMapTag = '[object WeakMap]'; 33774 33775 var arrayBufferTag = '[object ArrayBuffer]', 33776 float32Tag = '[object Float32Array]', 33777 float64Tag = '[object Float64Array]', 33778 int8Tag = '[object Int8Array]', 33779 int16Tag = '[object Int16Array]', 33780 int32Tag = '[object Int32Array]', 33781 uint8Tag = '[object Uint8Array]', 33782 uint8ClampedTag = '[object Uint8ClampedArray]', 33783 uint16Tag = '[object Uint16Array]', 33784 uint32Tag = '[object Uint32Array]'; 33785 33786 /** Used to match empty string literals in compiled template source. */ 33787 var reEmptyStringLeading = /\b__p \+= '';/g, 33788 reEmptyStringMiddle = /\b(__p \+=) '' \+/g, 33789 reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; 33790 33791 /** Used to match HTML entities and HTML characters. */ 33792 var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, 33793 reUnescapedHtml = /[&<>"'`]/g, 33794 reHasEscapedHtml = RegExp(reEscapedHtml.source), 33795 reHasUnescapedHtml = RegExp(reUnescapedHtml.source); 33796 33797 /** Used to match template delimiters. */ 33798 var reEscape = /<%-([\s\S]+?)%>/g, 33799 reEvaluate = /<%([\s\S]+?)%>/g, 33800 reInterpolate = /<%=([\s\S]+?)%>/g; 33801 33802 /** Used to match property names within property paths. */ 33803 var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, 33804 reIsPlainProp = /^\w*$/, 33805 rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; 33806 33807 /** 33808 * Used to match `RegExp` [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns) 33809 * and those outlined by [`EscapeRegExpPattern`](http://ecma-international.org/ecma-262/6.0/#sec-escaperegexppattern). 33810 */ 33811 var reRegExpChars = /^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g, 33812 reHasRegExpChars = RegExp(reRegExpChars.source); 33813 33814 /** Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). */ 33815 var reComboMark = /[\u0300-\u036f\ufe20-\ufe23]/g; 33816 33817 /** Used to match backslashes in property paths. */ 33818 var reEscapeChar = /\\(\\)?/g; 33819 33820 /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ 33821 var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; 33822 33823 /** Used to match `RegExp` flags from their coerced string values. */ 33824 var reFlags = /\w*$/; 33825 33826 /** Used to detect hexadecimal string values. */ 33827 var reHasHexPrefix = /^0[xX]/; 33828 33829 /** Used to detect host constructors (Safari > 5). */ 33830 var reIsHostCtor = /^\[object .+?Constructor\]$/; 33831 33832 /** Used to detect unsigned integer values. */ 33833 var reIsUint = /^\d+$/; 33834 33835 /** Used to match latin-1 supplementary letters (excluding mathematical operators). */ 33836 var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; 33837 33838 /** Used to ensure capturing order of template delimiters. */ 33839 var reNoMatch = /($^)/; 33840 33841 /** Used to match unescaped characters in compiled string literals. */ 33842 var reUnescapedString = /['\n\r\u2028\u2029\\]/g; 33843 33844 /** Used to match words to create compound words. */ 33845 var reWords = (function() { 33846 var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]', 33847 lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+'; 33848 33849 return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g'); 33850 }()); 33851 33852 /** Used to assign default `context` object properties. */ 33853 var contextProps = [ 33854 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array', 33855 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', 33856 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'isFinite', 33857 'parseFloat', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', 33858 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap' 33859 ]; 33860 33861 /** Used to make template sourceURLs easier to identify. */ 33862 var templateCounter = -1; 33863 33864 /** Used to identify `toStringTag` values of typed arrays. */ 33865 var typedArrayTags = {}; 33866 typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = 33867 typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = 33868 typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = 33869 typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = 33870 typedArrayTags[uint32Tag] = true; 33871 typedArrayTags[argsTag] = typedArrayTags[arrayTag] = 33872 typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = 33873 typedArrayTags[dateTag] = typedArrayTags[errorTag] = 33874 typedArrayTags[funcTag] = typedArrayTags[mapTag] = 33875 typedArrayTags[numberTag] = typedArrayTags[objectTag] = 33876 typedArrayTags[regexpTag] = typedArrayTags[setTag] = 33877 typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
33878 33879 /** Used to identify `toStringTag` values supported by `_.clone`. */ 33880 var cloneableTags = {}; 33881 cloneableTags[argsTag] = cloneableTags[arrayTag] = 33882 cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = 33883 cloneableTags[dateTag] = cloneableTags[float32Tag] = 33884 cloneableTags[float64Tag] = cloneableTags[int8Tag] = 33885 cloneableTags[int16Tag] = cloneableTags[int32Tag] = 33886 cloneableTags[numberTag] = cloneableTags[objectTag] = 33887 cloneableTags[regexpTag] = cloneableTags[stringTag] = 33888 cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = 33889 cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; 33890 cloneableTags[errorTag] = cloneableTags[funcTag] = 33891 cloneableTags[mapTag] = cloneableTags[setTag] = 33892 cloneableTags[weakMapTag] = false; 33893 33894 /** Used to map latin-1 supplementary letters to basic latin letters. */ 33895 var deburredLetters = { 33896 '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', 33897 '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', 33898 '\xc7': 'C', '\xe7': 'c', 33899 '\xd0': 'D', '\xf0': 'd', 33900 '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', 33901 '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', 33902 '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', 33903 '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', 33904 '\xd1': 'N', '\xf1': 'n', 33905 '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', 33906 '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', 33907 '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', 33908 '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', 33909 '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', 33910 '\xc6': 'Ae', '\xe6': 'ae', 33911 '\xde': 'Th', '\xfe': 'th', 33912 '\xdf': 'ss' 33913 }; 33914 33915 /** Used to map characters to HTML entities. */ 33916 var htmlEscapes = { 33917 '&': '&', 33918 '<': '<', 33919 '>': '>', 33920 '"': '"', 33921 "'": ''', 33922 '`': '`' 33923 }; 33924 33925 /** Used to map HTML entities to characters. */ 33926 var htmlUnescapes = { 33927 '&': '&', 33928 '<': '<', 33929 '>': '>', 33930 '"': '"', 33931 ''': "'", 33932 '`': '`' 33933 }; 33934 33935 /** Used to determine if values are of the language type `Object`. */ 33936 var objectTypes = { 33937 'function': true, 33938 'object': true 33939 }; 33940 33941 /** Used to escape characters for inclusion in compiled regexes. */ 33942 var regexpEscapes = { 33943 '0': 'x30', '1': 'x31', '2': 'x32', '3': 'x33', '4': 'x34', 33944 '5': 'x35', '6': 'x36', '7': 'x37', '8': 'x38', '9': 'x39', 33945 'A': 'x41', 'B': 'x42', 'C': 'x43', 'D': 'x44', 'E': 'x45', 'F': 'x46', 33946 'a': 'x61', 'b': 'x62', 'c': 'x63', 'd': 'x64', 'e': 'x65', 'f': 'x66', 33947 'n': 'x6e', 'r': 'x72', 't': 'x74', 'u': 'x75', 'v': 'x76', 'x': 'x78' 33948 }; 33949 33950 /** Used to escape characters for inclusion in compiled string literals. */ 33951 var stringEscapes = { 33952 '\\': '\\', 33953 "'": "'", 33954 '\n': 'n', 33955 '\r': 'r', 33956 '\u2028': 'u2028', 33957 '\u2029': 'u2029' 33958 }; 33959 33960 /** Detect free variable `exports`. */ 33961 var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; 33962 33963 /** Detect free variable `module`. */ 33964 var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; 33965 33966 /** Detect free variable `global` from Node.js. */ 33967 var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; 33968 33969 /** Detect free variable `self`. */ 33970 var freeSelf = objectTypes[typeof self] && self && self.Object && self; 33971 33972 /** Detect free variable `window`. */ 33973 var freeWindow = objectTypes[typeof window] && window && window.Object && window; 33974 33975 /** Detect the popular CommonJS extension `module.exports`. */ 33976 var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; 33977 33978 /** 33979 * Used as a reference to the global object. 33980 * 33981 * The `this` value is used if it's the global object to avoid Greasemonkey's 33982 * restricted `window` object, otherwise the `window` object is used. 33983 */ 33984 var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; 33985 33986 /*--------------------------------------------------------------------------*/ 33987 33988 /** 33989 * The base implementation of `compareAscending` which compares values and 33990 * sorts them in ascending order without guaranteeing a stable sort. 33991 * 33992 * @private 33993 * @param {*} value The value to compare. 33994 * @param {*} other The other value to compare. 33995 * @returns {number} Returns the sort order indicator for `value`. 33996 */ 33997 function baseCompareAscending(value, other) { 33998 if (value !== other) { 33999 var valIsNull = value === null, 34000 valIsUndef = value === undefined, 34001 valIsReflexive = value === value; 34002 34003 var othIsNull = other === null, 34004 othIsUndef = other === undefined, 34005 othIsReflexive = other === other; 34006 34007 if ((value >
34007 other && !othIsNull) || !valIsReflexive || 34008 (valIsNull && !othIsUndef && othIsReflexive) || 34009 (valIsUndef && othIsReflexive)) { 34010 return 1; 34011 } 34012 if ((value < other && !valIsNull) || !othIsReflexive || 34013 (othIsNull && !valIsUndef && valIsReflexive) || 34014 (othIsUndef && valIsReflexive)) { 34015 return -1; 34016 } 34017 } 34018 return 0; 34019 } 34020 34021 /** 34022 * The base implementation of `_.findIndex` and `_.findLastIndex` without 34023 * support for callback shorthands and `this` binding. 34024 * 34025 * @private 34026 * @param {Array} array The array to search. 34027 * @param {Function} predicate The function invoked per iteration. 34028 * @param {boolean} [fromRight] Specify iterating from right to left. 34029 * @returns {number} Returns the index of the matched value, else `-1`. 34030 */ 34031 function baseFindIndex(array, predicate, fromRight) { 34032 var length = array.length, 34033 index = fromRight ? length : -1; 34034 34035 while ((fromRight ? index-- : ++index < length)) { 34036 if (predicate(array[index], index, array)) { 34037 return index; 34038 } 34039 } 34040 return -1; 34041 } 34042 34043 /** 34044 * The base implementation of `_.indexOf` without support for binary searches. 34045 * 34046 * @private 34047 * @param {Array} array The array to search. 34048 * @param {*} value The value to search for. 34049 * @param {number} fromIndex The index to search from. 34050 * @returns {number} Returns the index of the matched value, else `-1`. 34051 */ 34052 function baseIndexOf(array, value, fromIndex) { 34053 if (value !== value) { 34054 return indexOfNaN(array, fromIndex); 34055 } 34056 var index = fromIndex - 1, 34057 length = array.length; 34058 34059 while (++index < length) { 34060 if (array[index] === value) { 34061 return index; 34062 } 34063 } 34064 return -1; 34065 } 34066 34067 /** 34068 * The base implementation of `_.isFunction` without support for environments 34069 * with incorrect `typeof` results. 34070 * 34071 * @private 34072 * @param {*} value The value to check. 34073 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 34074 */ 34075 function baseIsFunction(value) { 34076 // Avoid a Chakra JIT bug in compatibility modes of IE 11. 34077 // See https://github.com/jashkenas/underscore/issues/1621 for more details. 34078 return typeof value == 'function' || false; 34079 } 34080 34081 /** 34082 * Converts `value` to a string if it's not one. An empty string is returned 34083 * for `null` or `undefined` values. 34084 * 34085 * @private 34086 * @param {*} value The value to process. 34087 * @returns {string} Returns the string. 34088 */ 34089 function baseToString(value) { 34090 return value == null ? '' : (value + ''); 34091 } 34092 34093 /** 34094 * Used by `_.trim` and `_.trimLeft` to get the index of the first character 34095 * of `string` that is not found in `chars`. 34096 * 34097 * @private 34098 * @param {string} string The string to inspect. 34099 * @param {string} chars The characters to find. 34100 * @returns {number} Returns the index of the first character not found in `chars`. 34101 */ 34102 function charsLeftIndex(string, chars) { 34103 var index = -1, 34104 length = string.length; 34105 34106 while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} 34107 return index; 34108 } 34109 34110 /** 34111 * Used by `_.trim` and `_.trimRight` to get the index of the last character 34112 * of `string` that is not found in `chars`. 34113 * 34114 * @private 34115 * @param {string} string The string to inspect. 34116 * @param {string} chars The characters to find. 34117 * @returns {number} Returns the index of the last character not found in `chars`. 34118 */ 34119 function charsRightIndex(string, chars) { 34120 var index = string.length; 34121 34122 while (index-- && chars.indexOf(string.charAt(index)) > -1) {} 34123 return index; 34124 } 34125 34126 /** 34127 * Used by `_.sortBy` to compare transformed elements of a collection and stable 34128 * sort them in ascending order. 34129 * 34130 * @private 34131 * @param {Object} object The object to compare. 34132 * @param {Object} other The other object to compare. 34133 * @returns {number} Returns the sort order indicator for `object`. 34134 */ 34135 function compareAscending(object, other) { 34136 return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index); 34137 } 34138 34139 /** 34140 * Used by `_.sortByOrder` to compare multiple properties of a value to another 34141 * and stable sort them. 34142 * 34143 * If `orders` is unspecified, all valuess are sorted in ascending order. Otherwise, 34144 * a value is sorted in ascending order if its corresponding order is "asc", and 34145 * descending if "desc". 34146 * 34147 * @private 34148 * @param {Object} object The object to compare. 34149 * @param {Object} other The other object to compare. 34150 * @param {boolean[]} orders The order to sort by for each property. 34151 * @returns {number} Returns the sort order indicator for `object`. 34152 */ 34153 function compareMultiple(object, other, orders) { 34154 var index = -1, 34155 objCriteria = object.criteria, 34156 othCriteria = other.criteria, 34157 length = objCriteria.length, 34158 ordersLength = orders.length; 34159 34160 while (++index < length) { 34161 var result = baseCompareAscending(objCriteria[index], othCriteria[index]); 34162 if (result) { 34163 if (index >= ordersLength) { 34164 return result; 34165 } 34166 var order = orders[index]; 34167 return result * ((order === 'asc' || order === true) ? 1 : -1); 34168 } 34169 } 34170 // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications 34171 // that causes it, under certain circumstances, to provide the same value for 34172 // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 34173 // for more details. 34174 //
34175 // This also ensures a stable sort in V8 and other engines. 34176 // See https://code.google.com/p/v8/issues/detail?id=90 for more details. 34177 return object.index - other.index; 34178 } 34179 34180 /** 34181 * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. 34182 * 34183 * @private 34184 * @param {string} letter The matched letter to deburr. 34185 * @returns {string} Returns the deburred letter. 34186 */ 34187 function deburrLetter(letter) { 34188 return deburredLetters[letter]; 34189 } 34190 34191 /** 34192 * Used by `_.escape` to convert characters to HTML entities. 34193 * 34194 * @private 34195 * @param {string} chr The matched character to escape. 34196 * @returns {string} Returns the escaped character. 34197 */ 34198 function escapeHtmlChar(chr) { 34199 return htmlEscapes[chr]; 34200 } 34201 34202 /** 34203 * Used by `_.escapeRegExp` to escape characters for inclusion in compiled regexes. 34204 * 34205 * @private 34206 * @param {string} chr The matched character to escape. 34207 * @param {string} leadingChar The capture group for a leading character. 34208 * @param {string} whitespaceChar The capture group for a whitespace character. 34209 * @returns {string} Returns the escaped character. 34210 */ 34211 function escapeRegExpChar(chr, leadingChar, whitespaceChar) { 34212 if (leadingChar) { 34213 chr = regexpEscapes[chr]; 34214 } else if (whitespaceChar) { 34215 chr = stringEscapes[chr]; 34216 } 34217 return '\\' + chr; 34218 } 34219 34220 /** 34221 * Used by `_.template` to escape characters for inclusion in compiled string literals. 34222 * 34223 * @private 34224 * @param {string} chr The matched character to escape. 34225 * @returns {string} Returns the escaped character. 34226 */ 34227 function escapeStringChar(chr) { 34228 return '\\' + stringEscapes[chr]; 34229 } 34230 34231 /** 34232 * Gets the index at which the first occurrence of `NaN` is found in `array`. 34233 * 34234 * @private 34235 * @param {Array} array The array to search. 34236 * @param {number} fromIndex The index to search from. 34237 * @param {boolean} [fromRight] Specify iterating from right to left. 34238 * @returns {number} Returns the index of the matched `NaN`, else `-1`. 34239 */ 34240 function indexOfNaN(array, fromIndex, fromRight) { 34241 var length = array.length, 34242 index = fromIndex + (fromRight ? 0 : -1); 34243 34244 while ((fromRight ? index-- : ++index < length)) { 34245 var other = array[index]; 34246 if (other !== other) { 34247 return index; 34248 } 34249 } 34250 return -1; 34251 } 34252 34253 /** 34254 * Checks if `value` is object-like. 34255 * 34256 * @private 34257 * @param {*} value The value to check. 34258 * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 34259 */ 34260 function isObjectLike(value) { 34261 return !!value && typeof value == 'object'; 34262 } 34263 34264 /** 34265 * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a 34266 * character code is whitespace. 34267 * 34268 * @private 34269 * @param {number} charCode The character code to inspect. 34270 * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. 34271 */ 34272 function isSpace(charCode) { 34273 return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCo
34273de == 5760 || charCode == 6158 || 34274 (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279))); 34275 } 34276 34277 /** 34278 * Replaces all `placeholder` elements in `array` with an internal placeholder 34279 * and returns an array of their indexes. 34280 * 34281 * @private 34282 * @param {Array} array The array to modify. 34283 * @param {*} placeholder The placeholder to replace. 34284 * @returns {Array} Returns the new array of placeholder indexes. 34285 */ 34286 function replaceHolders(array, placeholder) { 34287 var index = -1, 34288 length = array.length, 34289 resIndex = -1, 34290 result = []; 34291 34292 while (++index < length) { 34293 if (array[index] === placeholder) { 34294 array[index] = PLACEHOLDER; 34295 result[++resIndex] = index; 34296 } 34297 } 34298 return result; 34299 } 34300 34301 /** 34302 * An implementation of `_.uniq` optimized for sorted arrays without support 34303 * for callback shorthands and `this` binding. 34304 * 34305 * @private 34306 * @param {Array} array The array to inspect. 34307 * @param {Function} [iteratee] The function invoked per iteration. 34308 * @returns {Array} Returns the new duplicate-value-free array. 34309 */ 34310 function sortedUniq(array, iteratee) { 34311 var seen, 34312 index = -1, 34313 length = array.length, 34314 resIndex = -1, 34315 result = []; 34316 34317 while (++index < length) { 34318 var value = array[index], 34319 computed = iteratee ? iteratee(value, index, array) : value; 34320 34321 if (!index || seen !== computed) { 34322 seen = computed; 34323 result[++resIndex] = value; 34324 } 34325 } 34326 return result; 34327 } 34328 34329 /** 34330 * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace 34331 * character of `string`. 34332 * 34333 * @private 34334 * @param {string} string The string to inspect. 34335 * @returns {number} Returns the index of the first non-whitespace character. 34336 */ 34337 function trimmedLeftIndex(string) { 34338 var index = -1, 34339 length = string.length; 34340 34341 while (++index < length && isSpace(string.charCodeAt(index))) {} 34342 return index; 34343 } 34344 34345 /** 34346 * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace 34347 * character of `string`. 34348 * 34349 * @private 34350 * @param {string} string The string to inspect. 34351 * @returns {number} Returns the index of the last non-whitespace character. 34352 */ 34353 function trimmedRightIndex(string) { 34354 var index = string.length; 34355 34356 while (index-- && isSpace(string.charCodeAt(index))) {} 34357 return index; 34358 } 34359 34360 /** 34361 * Used by `_.unescape` to convert HTML entities to characters. 34362 * 34363 * @private 34364 * @param {string} chr The matched character to unescape. 34365 * @returns {string} Returns the unescaped character. 34366 */ 34367 function unescapeHtmlChar(chr) { 34368 return htmlUnescapes[chr]; 34369 } 34370 34371 /*--------------------------------------------------------------------------*/ 34372 34373 /** 34374 * Create a new pristine `lodash` function using the given `context` object. 34375 * 34376 * @static 34377 * @memberOf _ 34378 * @category Utility 34379 * @param {Object} [context=root] The context object. 34380 * @returns {Function} Returns a new `lodash` function. 34381 * @example 34382 * 34383 * _.mixin({ 'foo': _.constant('foo') }); 34384 * 34385 * var lodash = _.runInContext(); 34386 * lodash.mixin({ 'bar': lodash.constant('bar') }); 34387 * 34388 * _.isFunction(_.foo); 34389 * // => true 34390 * _.isFunction(_.bar); 34391 * // => false 34392 * 34393 * lodash.isFunction(lodash.foo); 34394 * // => false 34395 * lodash.isFunction(lodash.bar); 34396 * // => true 34397 * 34398 * // using `context` to mock `Date#getTime` use in `_.now` 34399 * var mock = _.runInContext({ 34400 * 'Date': function() { 34401 * return { 'getTime': getTimeMock }; 34402 * } 34403 * }); 34404 * 34405 * // or creating a suped-up `defer` in Node.js 34406 * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; 34407 */ 34408 function runInContext(context) { 34409 // Avoid issues with some ES3 environments that attempt to use values, named 34410 // after built-in constructors like `Object`, for the creation of literals. 34411 // ES5 clears this up by stating that literals must use built-in constructors. 34412 // See https://es5.github.io/#x11.1.5 for more details. 34413 context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; 34414 34415 /** Native constructor references. */ 34416 var Array = context.Array, 34417 Date = context.Date, 34418 Error = context.Error, 34419 Function = context.Function, 34420 Math = context.Math, 34421 Number = context.Number, 34422 Object = context.Object, 34423 RegExp = context.RegExp, 34424 String = context.String, 34425 TypeError = context.TypeError; 34426 34427 /** Used for native method references. */ 34428 var arrayProto = Array.prototype, 34429 objectProto = Object.prototype,
34430 stringProto = String.prototype; 34431 34432 /** Used to resolve the decompiled source of functions. */ 34433 var fnToString = Function.prototype.toString; 34434 34435 /** Used to check objects for own properties. */ 34436 var hasOwnProperty = objectProto.hasOwnProperty; 34437 34438 /** Used to generate unique IDs. */ 34439 var idCounter = 0; 34440 34441 /** 34442 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 34443 * of values. 34444 */ 34445 var objToString = objectProto.toString; 34446 34447 /** Used to restore the original `_` reference in `_.noConflict`. */ 34448 var oldDash = root._; 34449 34450 /** Used to detect if a method is native. */ 34451 var reIsNative = RegExp('^' + 34452 fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') 34453 .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' 34454 ); 34455 34456 /** Native method references. */ 34457 var ArrayBuffer = context.ArrayBuffer, 34458 clearTimeout = context.clearTimeout, 34459 parseFloat = context.parseFloat, 34460 pow = Math.pow, 34461 propertyIsEnumerable = objectProto.propertyIsEnumerable, 34462 Set = getNative(context, 'Set'), 34463 setTimeout = context.setTimeout, 34464 splice = arrayProto.splice, 34465 Uint8Array = context.Uint8Array, 34466 WeakMap = getNative(context, 'WeakMap'); 34467 34468 /* Native method references for those with the same name as other `lodash` methods. */ 34469 var nativeCeil = Math.ceil, 34470 nativeCreate = getNative(Object, 'create'), 34471 nativeFloor = Math.floor, 34472 nativeIsArray = getNative(Array, 'isArray'),
34473 nativeIsFinite = context.isFinite, 34474 nativeKeys = getNative(Object, 'keys'), 34475 nativeMax = Math.max, 34476 nativeMin = Math.min, 34477 nativeNow = getNative(Date, 'now'), 34478 nativeParseInt = context.parseInt, 34479 nativeRandom = Math.random; 34480 34481 /** Used as references for `-Infinity` and `Infinity`. */ 34482 var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, 34483 POSITIVE_INFINITY = Number.POSITIVE_INFINITY; 34484 34485 /** Used as references for the maximum length and index of an array. */ 34486 var MAX_ARRAY_LENGTH = 4294967295, 34487 MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, 34488 HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; 34489 34490 /** 34491 * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) 34492 * of an array-like value. 34493 */ 34494 var MAX_SAFE_INTEGER = 9007199254740991; 34495 34496 /** Used to store function metadata. */ 34497 var metaMap = WeakMap && new WeakMap; 34498 34499 /** Used to lookup unminified function names. */ 34500 var realNames = {}; 34501 34502 /*------------------------------------------------------------------------*/ 34503 34504 /** 34505 * Creates a `lodash` object which wraps `value` to enable implicit chaining. 34506 * Methods that operate on and return arrays, collections, and functions can 34507 * be chained together. Methods that retrieve a single value or may return a 34508 * primitive value will automatically end the chain returning the unwrapped 34509 * value. Explicit chaining may be enabled using `_.chain`. The execution of 34510 * chained methods is lazy, that is, execution is deferred until `_#value` 34511 * is implicitly or explicitly called. 34512 * 34513 * Lazy evaluation allows several methods to support shortcut fusion. Shortcut 34514 * fusion is an optimization strategy which merge iteratee calls; this can help 34515 * to avoid the creation of intermediate data structures and greatly reduce the 34516 * number of iteratee executions. 34517 * 34518 * Chaining is supported in custom builds as long as the `_#value` method is 34519 * directly or indirectly included in the build. 34520 * 34521 * In addition to lodash methods, wrappers have `Array` and `String` methods. 34522 * 34523 * The wrapper `Array` methods are: 34524 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, 34525 * `splice`, and `unshift` 34526 * 34527 * The wrapper `String` methods are: 34528 * `replace` and `split` 34529 * 34530 * The wrapper methods that support shortcut fusion are: 34531 * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, 34532 * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, 34533 * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, 34534 * and `where` 34535 * 34536 * The chainable wrapper methods are: 34537 * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, 34538 * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, 34539 * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, 34540 * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`, 34541 * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, 34542 * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, 34543 * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, 34544 * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, 34545 * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`, 34546 * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, 34547 * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`, 34548 * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, 34549 * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, 34550 * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, 34551 * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, 34552 * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, 34553 * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` 34554 * 34555 * The wrapper methods that are **not** chainable by default are:
34556 * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, 34557 * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, 34558 * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, 34559 * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, 34560 * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, 34561 * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, 34562 * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, 34563 * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, 34564 * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, 34565 * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, 34566 * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`, 34567 * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, 34568 * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, 34569 * `unescape`, `uniqueId`, `value`, and `words` 34570 * 34571 * The wrapper method `sample` will return a wrapped value when `n` is provided, 34572 * otherwise an unwrapped value is returned. 34573 * 34574 * @name _ 34575 * @constructor 34576 * @category Chain 34577 * @param {*} value The value to wrap in a `lodash` instance. 34578 * @returns {Object} Returns the new `lodash` wrapper instance. 34579 * @example 34580 * 34581 * var wrapped = _([1, 2, 3]); 34582 * 34583 * // returns an unwrapped value 34584 * wrapped.reduce(function(total, n) { 34585 * return total + n; 34586 * }); 34587 * // => 6 34588 * 34589 * // returns a wrapped value 34590 * var squares = wrapped.map(function(n) { 34591 * return n * n; 34592 * }); 34593 * 34594 * _.isArray(squares); 34595 * // => false 34596 * 34597 * _.isArray(squares.value()); 34598 * // => true 34599 */ 34600 function lodash(value) { 34601 if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { 34602 if (value instanceof LodashWrapper) { 34603 return value; 34604 } 34605 if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) { 34606 return wrapperClone(value); 34607 } 34608 } 34609 return new LodashWrapper(value); 34610 } 34611 34612 /** 34613 * The function whose prototype all chaining wrappers inherit from. 34614 * 34615 * @private 34616 */ 34617 function baseLodash() { 34618 // No operation performed. 34619 } 34620 34621 /** 34622 * The base constructor for creating `lodash` wrapper objects. 34623 * 34624 * @private 34625 * @param {*} value The value to wrap. 34626 * @param {boolean} [chainAll] Enable chaining for all wrapper methods. 34627 * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. 34628 */ 34629 function LodashWrapper(value, chainAll, actions) { 34630 this.__wrapped__ = value; 34631 this.__actions__ = actions || []; 34632 this.__chain__ = !!chainAll; 34633 } 34634 34635 /** 34636 * An object environment feature flags. 34637 * 34638 * @static 34639 * @memberOf _ 34640 * @type Object 34641 */ 34642 var support = lodash.support = {}; 34643 34644 /** 34645 * By default, the template delimiters used by lodash are like those in 34646 * embedded Ruby (ERB). Change the following template settings to use 34647 * alternative delimiters. 34648 * 34649 * @static 34650 * @memberOf _ 34651 * @type Object 34652 */ 34653 lodash.templateSettings = { 34654 34655 /** 34656 * Used to detect `data` property values to be HTML-escaped. 34657 * 34658 * @memberOf _.templateSettings 34659 * @type RegExp 34660 */ 34661 'escape': reEscape, 34662 34663 /** 34664 * Used to detect code to be evaluated. 34665 * 34666 * @memberOf _.templateSettings 34667 * @type RegExp 34668 */ 34669 'evaluate': reEvaluate, 34670 34671 /** 34672 * Used to detect `data` property values to inject. 34673 * 34674 * @memberOf _.templateSettings 34675 * @type RegExp 34676 */ 34677 'interpolate': reInterpolate, 34678 34679 /** 34680 * Used to reference the data object in the template text. 34681 * 34682 * @memberOf _.templateSettings 34683 * @type string 34684 */ 34685 'variable': '', 34686 34687 /** 34688 * Used to import variables into the compiled template. 34689 * 34690 * @memberOf _.templateSettings 34691 * @type Object 34692 */ 34693 'imports': { 34694 34695 /** 34696 * A reference to the `lodash` function. 34697 * 34698 * @memberOf _.templateSettings.imports 34699 * @type Function 34700 */ 34701 '_': lodash 34702 } 34703 }; 34704 34705 /*------------------------------------------------------------------------*/ 34706 34707 /** 34708 * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. 34709 * 34710 * @private 34711 * @param {*} value The value to wrap. 34712 */ 34713 function LazyWrapper(value) { 34714 this.__wrapped__ = value; 34715 this.__actions__ = []; 34716 this.__dir__ = 1; 34717 this.__filtered__ = false;
34718 this.__iteratees__ = []; 34719 this.__takeCount__ = POSITIVE_INFINITY; 34720 this.__views__ = []; 34721 } 34722 34723 /** 34724 * Creates a clone of the lazy wrapper object. 34725 * 34726 * @private 34727 * @name clone 34728 * @memberOf LazyWrapper 34729 * @returns {Object} Returns the cloned `LazyWrapper` object. 34730 */ 34731 function lazyClone() { 34732 var result = new LazyWrapper(this.__wrapped__); 34733 result.__actions__ = arrayCopy(this.__actions__); 34734 result.__dir__ = this.__dir__; 34735 result.__filtered__ = this.__filtered__; 34736 result.__iteratees__ = arrayCopy(this.__iteratees__); 34737 result.__takeCount__ = this.__takeCount__; 34738 result.__views__ = arrayCopy(this.__views__); 34739 return result; 34740 } 34741 34742 /** 34743 * Reverses the direction of lazy iteration. 34744 * 34745 * @private 34746 * @name reverse 34747 * @memberOf LazyWrapper 34748 * @returns {Object} Returns the new reversed `LazyWrapper` object. 34749 */ 34750 function lazyReverse() { 34751 if (this.__filtered__) { 34752 var result = new LazyWrapper(this); 34753 result.__dir__ = -1; 34754 result.__filtered__ = true; 34755 } else { 34756 result = this.clone(); 34757 result.__dir__ *= -1; 34758 } 34759 return result; 34760 } 34761 34762 /** 34763 * Extracts the unwrapped value from its lazy wrapper. 34764 * 34765 * @private 34766 * @name value 34767 * @memberOf LazyWrapper 34768 * @returns {*} Returns the unwrapped value. 34769 */ 34770 function lazyValue() { 34771 var array = this.__wrapped__.value(), 34772 dir = this.__dir__, 34773 isArr = isArray(array), 34774 isRight = dir < 0, 34775 arrLength = isArr ? array.length : 0, 34776 view = getView(0, arrLength, this.__views__), 34777 start = view.start, 34778 end = view.end, 34779 length = end - start, 34780 index = isRight ? end : (start - 1), 34781 iteratees = this.__iteratees__, 34782 iterLength = iteratees.length, 34783 resIndex = 0, 34784 takeCount = nativeMin(length, this.__takeCount__); 34785 34786 if (!isArr || arrLength < LARGE_ARRAY_SIZE || (arrLength == length && takeCount == length)) { 34787 return baseWrapperValue((isRight && isArr) ? array.reverse() : array, this.__actions__); 34788 } 34789 var result = []; 34790 34791 outer: 34792 while (length-- && resIndex < takeCount) { 34793 index += dir; 34794 34795 var iterIndex = -1, 34796 value = array[index]; 34797 34798 while (++iterIndex < iterLength) { 34799 var data = iteratees[iterIndex], 34800 iteratee = data.iteratee, 34801 type = data.type, 34802 computed = iteratee(value); 34803 34804 if (type == LAZY_MAP_FLAG) { 34805 value = computed; 34806 } else if (!computed) { 34807 if (type == LAZY_FILTER_FLAG) { 34808 continue outer; 34809 } else { 34810 break outer; 34811 } 34812 } 34813 } 34814 result[resIndex++] = value; 34815 } 34816 return result; 34817 } 34818 34819 /*------------------------------------------------------------------------*/ 34820 34821 /** 34822 * Creates a cache object to store key/value pairs. 34823 * 34824 * @private 34825 * @static 34826 * @name Cache 34827 * @memberOf _.memoize 34828 */ 34829 function MapCache() { 34830 this.__data__ = {}; 34831 } 34832 34833 /** 34834 * Removes `key` and its value from the cache. 34835 * 34836 * @private 34837 * @name delete 34838 * @memberOf _.memoize.Cache 34839 * @param {string} key The key of the value to remove. 34840 * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. 34841 */ 34842 function mapDelete(key) { 34843 return this.has(key) && delete this.__data__[key]; 34844 } 34845 34846 /** 34847 * Gets the cached value for `key`. 34848 * 34849 * @private 34850 * @name get 34851 * @memberOf _.memoize.Cache 34852 * @param {string} key The key of the value to get. 34853 * @returns {*} Returns the cached value. 34854 */ 34855 function mapGet(key) { 34856 return key == '__proto__' ? undefined : this.__data__[key]; 34857 } 34858 34859 /** 34860 * Checks if a cached value for `key` exists. 34861 * 34862 * @private 34863 * @name has 34864 * @memberOf _.memoize.Cache 34865 * @param {string} key The key of the entry to check. 34866 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 34867 */ 34868 function mapHas(key) { 34869 return key != '__proto__' && hasOwnProperty.call(this.__data__, key); 34870 } 34871 34872 /** 34873 * Sets `value` to `key` of the cache. 34874 * 34875 * @private 34876 * @name set 34877 * @memberOf _.memoize.Cache 34878 * @param {string} key The key of the value to cache. 34879 * @param {*} value The value to cache. 34880 * @returns {Object} Returns the cache object. 34881 */ 34882 function mapSet(key, value) { 34883 if (key != '__proto__') { 34884 this.__data__[key] = value; 34885 } 34886 return this; 34887 } 34888 34889 /*------------------------------------------------------------------------*/ 34890 34891 /** 34892 * 34893 * Creates a cache object to store unique values. 34894 * 34895 * @private 34896 * @param {Array} [values] The values to cache. 34897 */ 34898 function SetCache(values) { 34899 var length = values ? values.length : 0; 34900 34901 this.data = { 'hash': nativeCreate(null), 'set': new Set }; 34902 while (length--) { 34903 this.push(values[length]); 34904 } 34905 } 34906 34907 /** 34908 * Checks if `value` is in `cache` mimicking the return signature of 34909 * `_.indexOf` by returning `0` if the value is found, else `-1`. 34910 * 34911 * @private 34912 * @param {Object} cache The cache to search. 34913 * @param {*} value The value to search for. 34914 * @returns {number} Returns `0` if `value` is found, else `-1`. 34915 */ 34916 function cacheIndexOf(cache, value) { 34917 var data = cache.data, 34918 result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value]; 34919 34920 return result ? 0 : -1; 34921 } 34922 34923 /** 34924 * Adds `value` to the cache. 34925 * 34926 * @private 34927 * @name push 34928 * @memberOf SetCache 34929 * @param {*} value The value to cache. 34930 */ 34931 function cachePush(value) { 34932 var data = this.data; 34933 if (typeof value == 'string' || isObject(value)) { 34934 data.set.add(value); 34935 } else { 34936 data.hash[value] = true; 34937 } 34938 } 34939 34940 /*------------------------------------------------------------------------*/ 34941 34942 /** 34943 * Creates a new array joining `array` with `other`. 34944 * 34945 * @private 34946 * @param {Array} array The array to join. 34947 * @param {Array} other The other array to join. 34948 * @returns {Array} Returns the new concatenated array.
34949 */ 34950 function arrayConcat(array, other) { 34951 var index = -1, 34952 length = array.length, 34953 othIndex = -1, 34954 othLength = other.length, 34955 result = Array(length + othLength); 34956 34957 while (++index < length) { 34958 result[index] = array[index]; 34959 } 34960 while (++othIndex < othLength) { 34961 result[index++] = other[othIndex]; 34962 } 34963 return result; 34964 } 34965 34966 /** 34967 * Copies the values of `source` to `array`. 34968 * 34969 * @private 34970 * @param {Array} source The array to copy values from. 34971 * @param {Array} [array=[]] The array to copy values to. 34972 * @returns {Array} Returns `array`. 34973 */ 34974 function arrayCopy(source, array) { 34975 var index = -1, 34976 length = source.length; 34977 34978 array || (array = Array(length)); 34979 while (++index < length) { 34980 array[index] = source[index]; 34981 } 34982 return array; 34983 } 34984 34985 /** 34986 * A specialized version of `_.forEach` for arrays without support for callback 34987 * shorthands and `this` binding. 34988 * 34989 * @private 34990 * @param {Array} array The array to iterate over. 34991 * @param {Function} iteratee The function invoked per iteration. 34992 * @returns {Array} Returns `array`. 34993 */ 34994 function arrayEach(array, iteratee) { 34995 var index = -1, 34996 length = array.length; 34997 34998 while (++index < length) { 34999 if (iteratee(array[index], index, array) === false) { 35000 break; 35001 } 35002 } 35003 return array; 35004 } 35005 35006 /** 35007 * A specialized version of `_.forEachRight` for arrays without support for 35008 * callback shorthands and `this` binding. 35009 * 35010 * @private 35011 * @param {Array} array The array to iterate over. 35012 * @param {Function} iteratee The function invoked per iteration. 35013 * @returns {Array} Returns `array`. 35014 */ 35015 function arrayEachRight(array, iteratee) { 35016 var length = array.length; 35017 35018 while (length--) { 35019 if (iteratee(array[length], length, array) === false) { 35020 break; 35021 } 35022 } 35023 return array; 35024 } 35025 35026 /** 35027 * A specialized version of `_.every` for arrays without support for callback 35028 * shorthands and `this` binding. 35029 * 35030 * @private 35031 * @param {Array} array The array to iterate over. 35032 * @param {Function} predicate The function invoked per iteration. 35033 * @returns {boolean} Returns `true` if all elements pass the predicate check, 35034 * else `false`. 35035 */ 35036 function arrayEvery(array, predicate) { 35037 var index = -1, 35038 length = array.length; 35039 35040 while (++index < length) { 35041 if (!predicate(array[index], index, array)) { 35042 return false; 35043 } 35044 } 35045 return true; 35046 } 35047 35048 /** 35049 * A specialized version of `baseExtremum` for arrays which invokes `iteratee` 35050 * with one argument: (value). 35051 * 35052 * @private 35053 * @param {Array} array The array to iterate over. 35054 * @param {Function} iteratee The function invoked per iteration. 35055 * @param {Function} comparator The function used to compare values. 35056 * @param {*} exValue The initial extremum value. 35057 * @returns {*} Returns the extremum value. 35058 */ 35059 function arrayExtremum(array, iteratee, comparator, exValue) { 35060 var index = -1, 35061 length = array.length, 35062 computed = exValue, 35063 result = computed; 35064 35065 while (++index < length) { 35066 var value = array[index], 35067 current = +iteratee(value); 35068 35069 if (comparator(current, computed)) { 35070 computed = current; 35071 result = value; 35072 } 35073 } 35074 return result; 35075 } 35076 35077 /** 35078 * A specialized version of `_.filter` for arrays without support for callback 35079 * shorthands and `this` binding. 35080 * 35081 * @private 35082 * @param {Array} array The array to iterate over. 35083 * @param {Function} predicate The function invoked per iteration. 35084 * @returns {Array} Returns the new filtered array. 35085 */ 35086 function arrayFilter(array, predicate) { 35087 var index = -1, 35088 length = array.length, 35089 resIndex = -1, 35090 result = []; 35091 35092 while (++index < length) { 35093 var value = array[index]; 35094 if (predicate(value, index, array)) { 35095 result[++resIndex] = value; 35096 } 35097 } 35098 return result; 35099 } 35100 35101 /** 35102 * A specialized version of `_.map` for arrays without support for callback 35103 * shorthands and `this` binding. 35104 * 35105 * @private 35106 * @param {Array} array The array to iterate over. 35107 * @param {Function} iteratee The function invoked per iteration. 35108 * @returns {Array} Returns the new mapped array.
35109 */ 35110 function arrayMap(array, iteratee) { 35111 var index = -1, 35112 length = array.length, 35113 result = Array(length); 35114 35115 while (++index < length) { 35116 result[index] = iteratee(array[index], index, array); 35117 } 35118 return result; 35119 } 35120 35121 /** 35122 * Appends the elements of `values` to `array`. 35123 * 35124 * @private 35125 * @param {Array} array The array to modify. 35126 * @param {Array} values The values to append. 35127 * @returns {Array} Returns `array`. 35128 */ 35129 function arrayPush(array, values) { 35130 var index = -1, 35131 length = values.length, 35132 offset = array.length; 35133 35134 while (++index < length) { 35135 array[offset + index] = values[index]; 35136 } 35137 return array; 35138 } 35139 35140 /** 35141 * A specialized version of `_.reduce` for arrays without support for callback 35142 * shorthands and `this` binding. 35143 * 35144 * @private 35145 * @param {Array} array The array to iterate over. 35146 * @param {Function} iteratee The function invoked per iteration. 35147 * @param {*} [accumulator] The initial value. 35148 * @param {boolean} [initFromArray] Specify using the first element of `array` 35149 * as the initial value. 35150 * @returns {*} Returns the accumulated value. 35151 */ 35152 function arrayReduce(array, iteratee, accumulator, initFromArray) { 35153 var index = -1, 35154 length = array.length; 35155 35156 if (initFromArray && length) { 35157 accumulator = array[++index]; 35158 } 35159 while (++index < length) { 35160 accumulator = iteratee(accumulator, array[index], index, array); 35161 } 35162 return accumulator; 35163 } 35164 35165 /** 35166 * A specialized version of `_.reduceRight` for arrays without support for 35167 * callback shorthands and `this` binding. 35168 * 35169 * @private 35170 * @param {Array} array The array to iterate over. 35171 * @param {Function} iteratee The function invoked per iteration. 35172 * @param {*} [accumulator] The initial value. 35173 * @param {boolean} [initFromArray] Specify using the last element of `array` 35174 * as the initial value. 35175 * @returns {*} Returns the accumulated value. 35176 */ 35177 function arrayReduceRight(array, iteratee, accumulator, initFromArray) { 35178 var length = array.length; 35179 if (initFromArray && length) { 35180 accumulator = array[--length]; 35181 } 35182 while (length--) { 35183 accumulator = iteratee(accumulator, array[length], length, array); 35184 } 35185 return accumulator; 35186 } 35187 35188 /** 35189 * A specialized version of `_.some` for arrays without support for callback 35190 * shorthands and `this` binding. 35191 * 35192 * @private 35193 * @param {Array} array The array to iterate over. 35194 * @param {Function} predicate The function invoked per iteration. 35195 * @returns {boolean} Returns `true` if any element passes the predicate check, 35196 * else `false`. 35197 */ 35198 function arraySome(array, predicate) { 35199 var index = -1, 35200 length = array.length; 35201 35202 while (++index < length) { 35203 if (predicate(array[index], index, array)) { 35204 return true; 35205 } 35206 } 35207 return false; 35208 } 35209 35210 /** 35211 * A specialized version of `_.sum` for arrays without support for callback 35212 * shorthands and `this` binding.. 35213 * 35214 * @private 35215 * @param {Array} array The array to iterate over. 35216 * @param {Function} iteratee The function invoked per iteration. 35217 * @returns {number} Returns the sum. 35218 */ 35219 function arraySum(array, iteratee) { 35220 var length = array.length, 35221 result = 0; 35222 35223 while (length--) { 35224 result += +iteratee(array[length]) || 0; 35225 } 35226 return result; 35227 } 35228 35229 /** 35230 * Used by `_.defaults` to customize its `_.assign` use. 35231 * 35232 * @private 35233 * @param {*} objectValue The destination object property value. 35234 * @param {*} sourceValue The source object property value. 35235 * @returns {*} Returns the value to assign to the destination object. 35236 */ 35237 function assignDefaults(objectValue, sourceValue) { 35238 return objectValue === undefined ? sourceValue : objectValue; 35239 } 35240 35241 /** 35242 * Used by `_.template` to customize its `_.assign` use. 35243 * 35244 * **Note:** This function is like `assignDefaults` except that it ignores 35245 * inherited property values when checking if a property is `undefined`. 35246 * 35247 * @private 35248 * @param {*} objectValue The destination object property value. 35249 * @param {*} sourceValue The source object property value. 35250 * @param {string} key The key associated with the object and source values. 35251 * @param {Object} object The destination object. 35252 * @returns {*} Returns the value to assign to the destination object. 35253 */ 35254 function assignOwnDefaults(objectValue, sourceValue, key, object) { 35255 return (objectValue === undefined || !hasOwnProperty.call(object, key)) 35256 ? sourceValue 35257 : objectValue; 35258 } 35259 35260 /** 35261 * A specialized version of `_.assign` for customizing assigned values without 35262 * support for argument juggling, multiple sources, and `this` binding `customizer` 35263 * functions. 35264 * 35265 * @private 35266 * @param {Object} object The destination object. 35267 * @param {Object} source The source object. 35268 * @param {Function} customizer The function to customize assigned values. 35269 * @returns {Object} Returns `object`. 35270 */ 35271 function assignWith(object, source, customizer) { 35272 var index = -1, 35273 props = keys(source), 35274 length = props.length; 35275 35276 while (++index < length) { 35277 var key = props[index], 35278 value = object[key], 35279 result = customizer(value, source[key], key, object, source); 35280 35281 if ((result === result ? (result !== value) : (value === value)) || 35282 (value === undefined && !(key in object))) { 35283 object[key] = result; 35284 } 35285 } 35286 return object; 35287 } 35288 35289 /** 35290 * The base implementation of `_.assign` without support for argument juggling, 35291 * multiple sources, and `customizer` functions. 35292 * 35293 * @private 35294 * @param {Object} object The destination object. 35295 * @param {Object} source The source object. 35296 * @returns {Object} Returns `object`. 35297 */ 35298 function baseAssign(object, source) { 35299 return source == null 35300 ? object 35301 : baseCopy(source, keys(source), object); 35302 } 35303 35304 /** 35305 * The base implementation of `_.at` without support for string collections 35306 * and individual key arguments. 35307 * 35308 * @private 35309 * @param {Array|Object} collection The collection to iterate over. 35310 * @param {number[]|string[]} props The property names or indexes of elements to pick. 35311 * @returns {Array} Returns the new array of picked elements. 35312 */ 35313 function baseAt(collection, props) { 35314 var index = -1, 35315 isNil = collection == null, 35316 isArr = !isNil && isArrayLike(collection), 35317 length = isArr ? collection.length : 0, 35318 propsLength = props.length, 35319 result = Array(propsLength); 35320 35321 while(++index < propsLength) { 35322 var key = props[index]; 35323 if (isArr) { 35324 result[index] = isIndex(key, length) ? collection[key] : undefined; 35325 } else { 35326 result[index] = isNil ? undefined : collection[key]; 35327 } 35328 } 35329 return result; 35330 } 35331 35332 /** 35333 * Copies properties of `source` to `object`. 35334 * 35335 * @private 35336 * @param {Object} source The object to copy properties from. 35337 * @param {Array} props The property names to copy. 35338 * @param {Object} [object={}] The object to copy properties to. 35339 * @returns {Object} Returns `object`. 35340 */ 35341 function baseCopy(source, props, object) { 35342 object || (object = {}); 35343 35344 var index = -1, 35345 length = props.length; 35346 35347 while (++index < length) { 35348 var key = props[index]; 35349 object[key] = source[key]; 35350 } 35351 return object; 35352 } 35353 35354 /** 35355 * The base implementation of `_.callback` which supports specifying the 35356 * number of arguments to provide to `func`. 35357 * 35358 * @private 35359 * @param {*} [func=_.identity] The value to convert to a callback. 35360 * @param {*} [thisArg] The `this` binding of `func`. 35361 * @param {number} [argCount] The number of arguments to provide to `func`. 35362 * @returns {Function} Returns the callback. 35363 */ 35364 function baseCallback(func, thisArg, argCount) { 35365 var type = typeof func; 35366 if (type == 'function') { 35367 return thisArg === undefined 35368 ? func 35369 : bindCallback(func, thisArg, argCount); 35370 } 35371 if (func == null) { 35372 return identity; 35373 } 35374 if (type == 'object') { 35375 return baseMatches(func); 35376 } 35377 return thisArg === undefined 35378 ? property(func) 35379 : baseMatchesProperty(func, thisArg); 35380 } 35381 35382 /** 35383 * The base implementation of `_.clone` without support for argument juggling 35384 * and `this` binding `customizer` functions. 35385 * 35386 * @private 35387 * @param {*} value The value to clone. 35388 * @param {boolean} [isDeep] Specify a deep clone. 35389 * @param {Function} [customizer] The function to customize cloning values. 35390 * @param {string} [key] The key of `value`. 35391 * @param {Object} [object] The object `value` belongs to. 35392 * @param {Array} [stackA=[]] Tracks traversed source objects. 35393 * @param {Array} [stackB=[]] Associates clones with source counterparts. 35394 * @returns {*} Returns the cloned value. 35395 */ 35396 function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { 35397 var result; 35398 if (customizer) { 35399 result = object ? customizer(value, key, object) : customizer(value); 35400 } 35401 if (result !== undefined) { 35402 return result; 35403 } 35404 if (!isObject(value)) { 35405 return value; 35406 } 35407 var isArr = isArray(value); 35408 if (isArr) { 35409 result = initCloneArray(value); 35410 if (!isDeep) { 35411 return arrayCopy(value, result); 35412 } 35413 } else { 35414 var tag = objToString.call(value), 35415 isFunc = tag == funcTag; 35416 35417 if (tag == objectTag || tag == argsTag || (isFunc && !object)) { 35418 result = initCloneObject(isFunc ? {} : value); 35419 if (!isDeep) { 35420 return baseAssign(result, value); 35421 } 35422 } else { 35423 return cloneableTags[tag] 35424 ? initCloneByTag(value, tag, isDeep) 35425 : (object ? value : {}); 35426 } 35427 } 35428 // Check for circular references and return its corresponding clone. 35429 stackA || (stackA = []); 35430 stackB || (stackB = []); 35431 35432 var length = stackA.length; 35433 while (length--) { 35434 if (stackA[length] == value) { 35435 return stackB[length]; 35436 } 35437 } 35438 // Add the source value to the stack of traversed objects and associate it with its clone. 35439 stackA.push(value); 35440 stackB.push(result); 35441 35442 // Recursively populate clone (susceptible to call stack limits). 35443 (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { 35444 result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); 35445 }); 35446 return result; 35447 } 35448 35449 /** 35450 * The base implementation of `_.create` without support for assigning 35451 * properties to the created object. 35452 * 35453 * @private 35454 * @param {Object} prototype The object to inherit from. 35455 * @returns {Object} Returns the new object. 35456 */ 35457 var baseCreate = (function() { 35458 function object() {} 35459 return function(prototype) { 35460 if (isObject(prototype)) { 35461 object.prototype = prototype; 35462 var result = new object; 35463 object.prototype = undefined; 35464 } 35465 return result || {}; 35466 }; 35467 }()); 35468 35469 /** 35470 * The base implementation of `_.delay` and `_.defer` which accepts an index 35471 * of where to slice the arguments to provide to `func`. 35472 * 35473 * @private 35474 * @param {Function} func The function to delay. 35475 * @param {number} wait The number of milliseconds to delay invocation. 35476 * @param {Object} args The arguments provide to `func`. 35477 * @returns {number} Returns the timer id. 35478 */
35479 function baseDelay(func, wait, args) { 35480 if (typeof func != 'function') { 35481 throw new TypeError(FUNC_ERROR_TEXT); 35482 } 35483 return setTimeout(function() { func.apply(undefined, args); }, wait); 35484 } 35485 35486 /** 35487 * The base implementation of `_.difference` which accepts a single array 35488 * of values to exclude. 35489 * 35490 * @private 35491 * @param {Array} array The array to inspect. 35492 * @param {Array} values The values to exclude. 35493 * @returns {Array} Returns the new array of filtered values. 35494 */ 35495 function baseDifference(array, values) { 35496 var length = array ? array.length : 0, 35497 result = []; 35498 35499 if (!length) { 35500 return result; 35501 } 35502 var index = -1, 35503 indexOf = getIndexOf(), 35504 isCommon = indexOf == baseIndexOf, 35505 cache = (isCommon && values.length >= LARGE_ARRAY_SIZE) ? createCache(values) : null, 35506 valuesLength = values.length; 35507 35508 if (cache) { 35509 indexOf = cacheIndexOf; 35510 isCommon = false; 35511 values = cache; 35512 } 35513 outer: 35514 while (++index < length) { 35515 var value = array[index]; 35516 35517 if (isCommon && value === value) { 35518 var valuesIndex = valuesLength; 35519 while (valuesIndex--) { 35520 if (values[valuesIndex] === value) { 35521 continue outer; 35522 } 35523 } 35524 result.push(value); 35525 } 35526 else if (indexOf(values, value, 0) < 0) { 35527 result.push(value); 35528 } 35529 } 35530 return result; 35531 } 35532 35533 /** 35534 * The base implementation of `_.forEach` without support for callback 35535 * shorthands and `this` binding. 35536 * 35537 * @private 35538 * @param {Array|Object|string} collection The collection to iterate over. 35539 * @param {Function} iteratee The function invoked per iteration. 35540 * @returns {Array|Object|string} Returns `collection`. 35541 */ 35542 var baseEach = createBaseEach(baseForOwn); 35543 35544 /** 35545 * The base implementation of `_.forEachRight` without support for callback 35546 * shorthands and `this` binding. 35547 * 35548 * @private 35549 * @param {Array|Object|string} collection The collection to iterate over. 35550 * @param {Function} iteratee The function invoked per iteration. 35551 * @returns {Array|Object|string} Returns `collection`. 35552 */ 35553 var baseEachRight = createBaseEach(baseForOwnRight, true); 35554 35555 /** 35556 * The base implementation of `_.every` without support for callback 35557 * shorthands and `this` binding. 35558 * 35559 * @private 35560 * @param {Array|Object|string} collection The collection to iterate over. 35561 * @param {Function} predicate The function invoked per iteration. 35562 * @returns {boolean} Returns `true` if all elements pass the predicate check, 35563 * else `false` 35564 */ 35565 function baseEvery(collection, predicate) { 35566 var result = true; 35567 baseEach(collection, function(value, index, collection) { 35568 result = !!predicate(value, index, collection); 35569 return result; 35570 }); 35571 return result; 35572 } 35573 35574 /** 35575 * Gets the extremum value of `collection` invoking `iteratee` for each value 35576 * in `collection` to generate the criterion by which the value is ranked. 35577 * The `iteratee` is invoked with three arguments: (value, index|key, collection). 35578 * 35579 * @private 35580 * @param {Array|Object|string} collection The collection to iterate over. 35581 * @param {Function} iteratee The function invoked per iteration. 35582 * @param {Function} comparator The function used to compare values. 35583 * @param {*} exValue The initial extremum value. 35584 * @returns {*} Returns the extremum value. 35585 */ 35586 function baseExtremum(collection, iteratee, comparator, exValue) { 35587 var computed = exValue, 35588 result = computed; 35589 35590 baseEach(collection, function(value, index, collection) { 35591 var current = +iteratee(value, index, collection); 35592 if (comparator(current, computed) || (current === exValue && current === result)) { 35593 computed = current; 35594 result = value; 35595 } 35596 }); 35597 return result; 35598 } 35599 35600 /** 35601 * The base implementation of `_.fill` without an iteratee call guard. 35602 * 35603 * @private 35604 * @param {Array} array The array to fill. 35605 * @param {*} value The value to fill `array` with. 35606 * @param {number} [start=0] The start position. 35607 * @param {number} [end=array.length] The end position. 35608 * @returns {Array} Returns `array`. 35609 */ 35610 function baseFill(array, value, start, end) { 35611 var length = array.length; 35612 35613 start = start == null ? 0 : (+start || 0); 35614 if (start < 0) { 35615 start = -start > length ? 0 : (length + start); 35616 } 35617 end = (end === undefined || end > length) ? length : (+end || 0); 35618 if (end < 0) { 35619 end += length; 35620 } 35621 length = start > end ? 0 : (end >>> 0); 35622 start >>>= 0; 35623 35624 while (start < length) { 35625 array[start++] = value; 35626 } 35627 return array; 35628 } 35629 35630 /** 35631 * The base implementation of `_.filter` without support for callback 35632 * shorthands and `this` binding. 35633 * 35634 * @private 35635 * @param {Array|Object|string} collection The collection to iterate over. 35636 * @param {Function} predicate The function invoked per iteration. 35637 * @returns {Array} Returns the new filtered array.
35638 */ 35639 function baseFilter(collection, predicate) { 35640 var result = []; 35641 baseEach(collection, function(value, index, collection) { 35642 if (predicate(value, index, collection)) { 35643 result.push(value); 35644 } 35645 }); 35646 return result; 35647 } 35648 35649 /** 35650 * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, 35651 * without support for callback shorthands and `this` binding, which iterates 35652 * over `collection` using the provided `eachFunc`. 35653 * 35654 * @private 35655 * @param {Array|Object|string} collection The collection to search. 35656 * @param {Function} predicate The function invoked per iteration. 35657 * @param {Function} eachFunc The function to iterate over `collection`. 35658 * @param {boolean} [retKey] Specify returning the key of the found element 35659 * instead of the element itself. 35660 * @returns {*} Returns the found element or its key, else `undefined`. 35661 */ 35662 function baseFind(collection, predicate, eachFunc, retKey) { 35663 var result; 35664 eachFunc(collection, function(value, key, collection) { 35665 if (predicate(value, key, collection)) { 35666 result = retKey ? key : value; 35667 return false; 35668 } 35669 }); 35670 return result; 35671 } 35672 35673 /** 35674 * The base implementation of `_.flatten` with added support for restricting 35675 * flattening and specifying the start index. 35676 * 35677 * @private 35678 * @param {Array} array The array to flatten. 35679 * @param {boolean} [isDeep] Specify a deep flatten. 35680 * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. 35681 * @param {Array} [result=[]] The initial result value. 35682 * @returns {Array} Returns the new flattened array. 35683 */ 35684 function baseFlatten(array, isDeep, isStrict, result) { 35685 result || (result = []); 35686 35687 var index = -1, 35688 length = array.length; 35689 35690 while (++index < length) { 35691 var value = array[index]; 35692 if (isObjectLike(value) && isArrayLike(value) && 35693 (isStrict || isArray(value) || isArguments(value))) { 35694 if (isDeep) { 35695 // Recursively flatten arrays (susceptible to call stack limits). 35696 baseFlatten(value, isDeep, isStrict, result); 35697 } else { 35698 arrayPush(result, value); 35699 } 35700 } else if (!isStrict) { 35701 result[result.length] = value; 35702 } 35703 } 35704 return result; 35705 } 35706 35707 /** 35708 * The base implementation of `baseForIn` and `baseForOwn` which iterates 35709 * over `object` properties returned by `keysFunc` invoking `iteratee` for 35710 * each property. Iteratee functions may exit iteration early by explicitly 35711 * returning `false`. 35712 * 35713 * @private 35714 * @param {Object} object The object to iterate over. 35715 * @param {Function} iteratee The function invoked per iteration. 35716 * @param {Function} keysFunc The function to get the keys of `object`. 35717 * @returns {Object} Returns `object`. 35718 */ 35719 var baseFor = createBaseFor(); 35720 35721 /** 35722 * This function is like `baseFor` except that it iterates over properties 35723 * in the opposite order. 35724 * 35725 * @private 35726 * @param {Object} object The object to iterate over. 35727 * @param {Function} iteratee The function invoked per iteration. 35728 * @param {Function} keysFunc The function to get the keys of `object`. 35729 * @returns {Object} Returns `object`. 35730 */ 35731 var baseForRight = createBaseFor(true); 35732 35733 /** 35734 * The base implementation of `_.forIn` without support for callback 35735 * shorthands and `this` binding. 35736 * 35737 * @private 35738 * @param {Object} object The object to iterate over. 35739 * @param {Function} iteratee The function invoked per iteration. 35740 * @returns {Object} Returns `object`. 35741 */ 35742 function baseForIn(object, iteratee) { 35743 return baseFor(object, iteratee, keysIn); 35744 } 35745 35746 /** 35747 * The base implementation of `_.forOwn` without support for callback 35748 * shorthands and `this` binding. 35749 * 35750 * @private 35751 * @param {Object} object The object to iterate over. 35752 * @param {Function} iteratee The function invoked per iteration. 35753 * @returns {Object} Returns `object`. 35754 */ 35755 function baseForOwn(object, iteratee) { 35756 return baseFor(object, iteratee, keys); 35757 } 35758 35759 /** 35760 * The base implementation of `_.forOwnRight` without support for callback 35761 * shorthands and `this` binding. 35762 * 35763 * @private 35764 * @param {Object} object The object to iterate over. 35765 * @param {Function} iteratee The function invoked per iteration. 35766 * @returns {Object} Returns `object`. 35767 */ 35768 function baseForOwnRight(object, iteratee) { 35769 return baseForRight(object, iteratee, keys); 35770 } 35771 35772 /** 35773 * The base implementation of `_.functions` which creates an array of 35774 * `object` function property names filtered from those provided. 35775 * 35776 * @private 35777 * @param {Object} object The object to inspect. 35778 * @param {Array} props The property names to filter. 35779 * @returns {Array} Returns the new array of filtered property names. 35780 */ 35781 function baseFunctions(object, props) { 35782 var index = -1, 35783 length = props.length, 35784 resIndex = -1, 35785 result = []; 35786 35787 while (++index < length) { 35788 var key = props[index]; 35789 if (isFunction(object[key])) { 35790 result[++resIndex] = key; 35791 } 35792 } 35793 return result; 35794 } 35795 35796 /** 35797 * The base implementation of `get` without support for string paths 35798 * and default values. 35799 * 35800 * @private 35801 * @param {Object} object The object to query. 35802 * @param {Array} path The path of the property to get. 35803 * @param {string} [pathKey] The key representation of path. 35804 * @returns {*} Returns the resolved value. 35805 */ 35806 function baseGet(object, path, pathKey) { 35807 if (object == null) { 35808 return; 35809 } 35810 if (pathKey !== undefined && pathKey in toObject(object)) { 35811 path = [pathKey]; 35812 } 35813 var index = 0, 35814 length = path.length; 35815 35816 while (object != null && index < length) { 35817 object = object[path[index++]]; 35818 } 35819 return (index && index == length) ? object : undefined; 35820 } 35821 35822 /** 35823 * The base implementation of `_.isEqual` without support for `this` binding 35824 * `customizer` functions. 35825 * 35826 * @private 35827 * @param {*} value The value to compare. 35828 * @param {*} other The other value to compare. 35829 * @param {Function} [customizer] The function to customize comparing values. 35830 * @param {boolean} [isLoose] Specify performing partial comparisons. 35831 * @param {Array} [stackA] Tracks traversed `value` objects. 35832 * @param {Array} [stackB] Tracks traversed `other` objects. 35833 * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 35834 */ 35835 function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { 35836 if (value === other) { 35837 return true; 35838 } 35839 if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { 35840 return value !== value && other !== other; 35841 } 35842 return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); 35843 } 35844 35845 /** 35846 * A specialized version of `baseIsEqual` for arrays and objects which performs 35847 * deep comparisons and tracks traversed objects enabling objects with circular 35848 * references to be compared. 35849 * 35850 * @private 35851 * @param {Object} object The object to compare. 35852 * @param {Object} other The other object to compare. 35853 * @param {Function} equalFunc The function to determine equivalents of values. 35854 * @param {Function} [customizer] The function to customize comparing objects. 35855 * @param {boolean} [isLoose] Specify performing partial comparisons. 35856 * @param {Array} [stackA=[]] Tracks traversed `value` objects. 35857 * @param {Array} [stackB=[]] Tracks traversed `other` objects. 35858 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 35859 */ 35860 function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { 35861 var objIsArr = isArray(object), 35862 othIsArr = isArray(other), 35863 objTag = arrayTag, 35864 othTag = arrayTag; 35865 35866 if (!objIsArr) { 35867 objTag = objToString.call(object); 35868 if (objTag == argsTag) { 35869 objTag = objectTag; 35870 } else if (objTag != objectTag) { 35871 objIsArr = isTypedArray(object); 35872 } 35873 } 35874 if (!othIsArr) { 35875 othTag = objToString.call(other); 35876 if (othTag == argsTag) { 35877 othTag = objectTag; 35878 } else if (othTag != objectTag) { 35879 othIsArr = isTypedArray(other); 35880 } 35881 } 35882 var objIsObj = objTag == objectTag, 35883 othIsObj = othTag == objectTag, 35884 isSameTag = objTag == othTag; 35885 35886 if (isSameTag && !(objIsArr || objIsObj)) { 35887 return equalByTag(object, other, objTag); 35888 } 35889 if (!isLoose) { 35890 var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), 35891 othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); 35892 35893 if (objIsWrapped || othIsWrapped) { 35894 return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); 35895 } 35896 } 35897 if (!isSameTag) { 35898 return false;
35899 } 35900 // Assume cyclic values are equal. 35901 // For more information on detecting circular references see https://es5.github.io/#JO. 35902 stackA || (stackA = []); 35903 stackB || (stackB = []); 35904 35905 var length = stackA.length; 35906 while (length--) { 35907 if (stackA[length] == object) { 35908 return stackB[length] == other; 35909 } 35910 } 35911 // Add `object` and `other` to the stack of traversed objects. 35912 stackA.push(object); 35913 stackB.push(other); 35914 35915 var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); 35916 35917 stackA.pop(); 35918 stackB.pop(); 35919 35920 return result; 35921 } 35922 35923 /** 35924 * The base implementation of `_.isMatch` without support for callback 35925 * shorthands and `this` binding. 35926 * 35927 * @private 35928 * @param {Object} object The object to inspect. 35929 * @param {Array} matchData The propery names, values, and compare flags to match. 35930 * @param {Function} [customizer] The function to customize comparing objects. 35931 * @returns {boolean} Returns `true` if `object` is a match, else `false`. 35932 */ 35933 function baseIsMatch(object, matchData, customizer) { 35934 var index = matchData.length, 35935 length = index, 35936 noCustomizer = !customizer; 35937 35938 if (object == null) { 35939 return !length; 35940 } 35941 object = toObject(object); 35942 while (index--) { 35943 var data = matchData[index]; 35944 if ((noCustomizer && data[2]) 35945 ? data[1] !== object[data[0]] 35946 : !(data[0] in object) 35947 ) { 35948 return false; 35949 } 35950 } 35951 while (++index < length) { 35952 data = matchData[index]; 35953 var key = data[0], 35954 objValue = object[key], 35955 srcValue = data[1]; 35956 35957 if (noCustomizer && data[2]) { 35958 if (objValue === undefined && !(key in object)) { 35959 return false; 35960 } 35961 } else { 35962 var result = customizer ? customizer(objValue, srcValue, key) : undefined; 35963 if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) { 35964 return false; 35965 } 35966 } 35967 } 35968 return true; 35969 } 35970 35971 /** 35972 * The base implementation of `_.map` without support for callback shorthands 35973 * and `this` binding. 35974 * 35975 * @private 35976 * @param {Array|Object|string} collection The collection to iterate over. 35977 * @param {Function} iteratee The function invoked per iteration. 35978 * @returns {Array} Returns the new mapped array. 35979 */ 35980 function baseMap(collection, iteratee) { 35981 var index = -1, 35982 result = isArrayLike(collection) ? Array(collection.length) : []; 35983 35984 baseEach(collection, function(value, key, collection) { 35985 result[++index] = iteratee(value, key, collection); 35986 }); 35987 return result; 35988 } 35989 35990 /** 35991 * The base implementation of `_.matches` which does not clone `source`. 35992 * 35993 * @private 35994 * @param {Object} source The object of property values to match. 35995 * @returns {Function} Returns the new function. 35996 */ 35997 function baseMatches(source) { 35998 var matchData = getMatchData(source); 35999 if (matchData.length == 1 && matchData[0][2]) { 36000 var key = matchData[0][0], 36001 value = matchData[0][1]; 36002 36003 return function(object) { 36004 if (object == null) { 36005 return false; 36006 } 36007 return object[key] === value && (value !== undefined || (key in toObject(object))); 36008 }; 36009 } 36010 return function(object) { 36011 return baseIsMatch(object, matchData); 36012 }; 36013 } 36014 36015 /** 36016 * The base implementation of `_.matchesProperty` which does not clone `srcValue`. 36017 * 36018 * @private 36019 * @param {string} path The path of the property to get. 36020 * @param {*} srcValue The value to compare. 36021 * @returns {Function} Returns the new function. 36022 */ 36023 function baseMatchesProperty(path, srcValue) { 36024 var isArr = isArray(path), 36025 isCommon = isKey(path) && isStrictComparable(srcValue), 36026 pathKey = (path + ''); 36027 36028 path = toPath(path); 36029 return function(object) { 36030 if (object == null) { 36031 return false;
36032 } 36033 var key = pathKey; 36034 object = toObject(object); 36035 if ((isArr || !isCommon) && !(key in object)) { 36036 object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); 36037 if (object == null) { 36038 return false; 36039 } 36040 key = last(path); 36041 object = toObject(object); 36042 } 36043 return object[key] === srcValue 36044 ? (srcValue !== undefined || (key in object)) 36045 : baseIsEqual(srcValue, object[key], undefined, true); 36046 }; 36047 } 36048 36049 /** 36050 * The base implementation of `_.merge` without support for argument juggling, 36051 * multiple sources, and `this` binding `customizer` functions. 36052 * 36053 * @private 36054 * @param {Object} object The destination object. 36055 * @param {Object} source The source object. 36056 * @param {Function} [customizer] The function to customize merged values. 36057 * @param {Array} [stackA=[]] Tracks traversed source objects. 36058 * @param {Array} [stackB=[]] Associates values with source counterparts. 36059 * @returns {Object} Returns `object`. 36060 */ 36061 function baseMerge(object, source, customizer, stackA, stackB) { 36062 if (!isObject(object)) { 36063 return object; 36064 } 36065 var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), 36066 props = isSrcArr ? undefined : keys(source); 36067 36068 arrayEach(props || source, function(srcValue, key) { 36069 if (props) { 36070 key = srcValue; 36071 srcValue = source[key]; 36072 } 36073 if (isObjectLike(srcValue)) { 36074 stackA || (stackA = []); 36075 stackB || (stackB = []); 36076 baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); 36077 } 36078 else { 36079 var value = object[key], 36080 result = customizer ? customizer(value, srcValue, key, object, source) : undefined, 36081 isCommon = result === undefined; 36082 36083 if (isCommon) { 36084 result = srcValue; 36085 } 36086 if ((result !== undefined || (isSrcArr && !(key in object))) && 36087 (isCommon || (result === result ? (result !== value) : (value === value)))) { 36088 object[key] = result; 36089 } 36090 } 36091 }); 36092 return object; 36093 } 36094 36095 /** 36096 * A specialized version of `baseMerge` for arrays and objects which performs 36097 * deep merges and tracks traversed objects enabling objects with circular 36098 * references to be merged. 36099 * 36100 * @private 36101 * @param {Object} object The destination object. 36102 * @param {Object} source The source object. 36103 * @param {string} key The key of the value to merge. 36104 * @param {Function} mergeFunc The function to merge values. 36105 * @param {Function} [customizer] The function to customize merged values. 36106 * @param {Array} [stackA=[]] Tracks traversed source objects. 36107 * @param {Array} [stackB=[]] Associates values with source counterparts. 36108 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 36109 */ 36110 function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { 36111 var length = stackA.length, 36112 srcValue = source[key]; 36113 36114 while (length--) { 36115 if (stackA[length] == srcValue) { 36116 object[key] = stackB[length]; 36117 return; 36118 } 36119 } 36120 var value = object[key], 36121 result = customizer ? customizer(value, srcValue, key, object, source) : undefined, 36122 isCommon = result === undefined; 36123 36124 if (isCommon) { 36125 result = srcValue; 36126 if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { 36127 result = isArray(value) 36128 ? value 36129 : (isArrayLike(value) ? arrayCopy(value) : []); 36130 } 36131 else if (isPlainObject(srcValue) || isArguments(srcValue)) { 36132 result = isArguments(value) 36133 ? toPlainObject(value) 36134 : (isPlainObject(value) ? value : {}); 36135 } 36136 else { 36137 isCommon = false; 36138 } 36139 } 36140 // Add the source value to the stack of traversed objects and associate 36141 // it with its merged value. 36142 stackA.push(srcValue); 36143 stackB.push(result); 36144 36145 if (isCommon) { 36146 // Recursively merge objects and arrays (susceptible to call stack limits). 36147 object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); 36148 } else if (result === result ? (result !== value) : (value === value)) { 36149 object[key] = result; 36150 } 36151 } 36152 36153 /** 36154 * The base implementation of `_.property` without support for deep paths. 36155 * 36156 * @private 36157 * @param {string} key The key of the property to get. 36158 * @returns {Function} Returns the new function. 36159 */ 36160 function baseProperty(key) { 36161 return function(object) { 36162 return object == null ? undefined : object[key]; 36163 }; 36164 } 36165 36166 /** 36167 * A specialized version of `baseProperty` which supports deep paths. 36168 * 36169 * @private 36170 * @param {Array|string} path The path of the property to get. 36171 * @returns {Function} Returns the new function. 36172 */ 36173 function basePropertyDeep(path) { 36174 var pathKey = (path + ''); 36175 path = toPath(path); 36176 return function(object) { 36177 return baseGet(object, path, pathKey); 36178 }; 36179 } 36180 36181 /** 36182 * The base implementation of `_.pullAt` without support for individual 36183 * index arguments and capturing the removed elements. 36184 * 36185 * @private 36186 * @param {Array} array The array to modify. 36187 * @param {number[]} indexes The indexes of elements to remove. 36188 * @returns {Array} Returns `array`. 36189 */ 36190 function basePullAt(array, indexes) { 36191 var length = array ? indexes.length : 0; 36192 while (length--) { 36193 var index = indexes[length]; 36194 if (index != previous && isIndex(index)) { 36195 var previous = index; 36196 splice.call(array, index, 1); 36197 } 36198 } 36199 return array; 36200 } 36201 36202 /** 36203 * The base implementation of `_.random` without support for argument juggling 36204 * and returning floating-point numbers. 36205 * 36206 * @private 36207 * @param {number} min The minimum possible value. 36208 * @param {number} max The maximum possible value. 36209 * @returns {number} Returns the random number. 36210 */ 36211 function baseRandom(min, max) { 36212 return min + nativeFloor(nativeRandom() * (max - min + 1)); 36213 } 36214 36215 /** 36216 * The base implementation of `_.reduce` and `_.reduceRight` without support 36217 * for callback shorthands and `this` binding, which iterates over `collection` 36218 * using the provided `eachFunc`. 36219 * 36220 * @private 36221 * @param {Array|Object|string} collection The collection to iterate over. 36222 * @param {Function} iteratee The function invoked per iteration. 36223 * @param {*} accumulator The initial value. 36224 * @param {boolean} initFromCollection Specify using the first or last element 36225 * of `collection` as the initial value. 36226 * @param {Function} eachFunc The function to iterate over `collection`. 36227 * @returns {*} Returns the accumulated value. 36228 */ 36229 function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { 36230 eachFunc(collection, function(value, index, collection) { 36231 accumulator = initFromCollection 36232 ? (initFromCollection = false, value) 36233 : iteratee(accumulator, value, index, collection); 36234 }); 36235 return accumulator; 36236 } 36237 36238 /** 36239 * The base implementation of `setData` without support for hot loop detection. 36240 * 36241 * @private 36242 * @param {Function} func The function to associate metadata with. 36243 * @param {*} data The metadata. 36244 * @returns {Function} Returns `func`. 36245 */ 36246 var baseSetData = !metaMap ? identity : function(func, data) { 36247 metaMap.set(func, data); 36248 return func; 36249 }; 36250 36251 /** 36252 * The base implementation of `_.slice` without an iteratee call guard. 36253 * 36254 * @private 36255 * @param {Array} array The array to slice. 36256 * @param {number} [start=0] The start position. 36257 * @param {number} [end=array.length] The end position. 36258 * @returns {Array} Returns the slice of `array`. 36259 */ 36260 function baseSlice(array, start, end) { 36261 var index = -1, 36262 length = array.length; 36263 36264 start = start == null ? 0 : (+start || 0); 36265 if (start < 0) { 36266 start = -start > length ? 0 : (length + start); 36267 } 36268 end = (end === undefined || end > length) ? length : (+end || 0); 36269 if (end < 0) { 36270 end += length; 36271 } 36272 length = start > end ? 0 : ((end - start) >>> 0); 36273 start >>>= 0; 36274 36275 var result = Array(length); 36276 while (++index < length) { 36277 result[index] = array[index + start]; 36278 } 36279 return result; 36280 } 36281 36282 /** 36283 * The base implementation of `_.some` without support for callback shorthands 36284 * and `this` binding. 36285 * 36286 * @private 36287 * @param {Array|Object|string} collection The collection to iterate over. 36288 * @param {Function} predicate The function invoked per iteration. 36289 * @returns {boolean} Returns `true` if any element passes the predicate check, 36290 * else `false`. 36291 */ 36292 function baseSome(collection, predicate) { 36293 var result; 36294 36295 baseEach(collection, function(value, index, collection) { 36296 result = predicate(value, index, collection); 36297 return !result; 36298 }); 36299 return !!result; 36300 } 36301 36302 /** 36303 * The base implementation of `_.sortBy` which uses `comparer` to define 36304 * the sort order of `array` and replaces criteria objects with their 36305 * corresponding values. 36306 * 36307 * @private 36308 * @param {Array} array The array to sort. 36309 * @param {Function} comparer The function to define sort order. 36310 * @returns {Array} Returns `array`. 36311 */ 36312 function baseSortBy(array, comparer) { 36313 var length = array.length; 36314 36315 array.sort(comparer); 36316 while (length--) { 36317 array[length] = array[length].value; 36318 } 36319 return array; 36320 } 36321 36322 /** 36323 * The base implementation of `_.sortByOrder` without param guards. 36324 * 36325 * @private 36326 * @param {Array|Object|string} collection The collection to iterate over. 36327 * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. 36328 * @param {boolean[]} orders The sort orders of `iteratees`. 36329 * @returns {Array} Returns the new sorted array.
36330 */ 36331 function baseSortByOrder(collection, iteratees, orders) { 36332 var callback = getCallback(), 36333 index = -1; 36334 36335 iteratees = arrayMap(iteratees, function(iteratee) { return callback(iteratee); }); 36336 36337 var result = baseMap(collection, function(value) { 36338 var criteria = arrayMap(iteratees, function(iteratee) { return iteratee(value); }); 36339 return { 'criteria': criteria, 'index': ++index, 'value': value }; 36340 }); 36341 36342 return baseSortBy(result, function(object, other) { 36343 return compareMultiple(object, other, orders); 36344 }); 36345 } 36346 36347 /** 36348 * The base implementation of `_.sum` without support for callback shorthands 36349 * and `this` binding. 36350 * 36351 * @private 36352 * @param {Array|Object|string} collection The collection to iterate over. 36353 * @param {Function} iteratee The function invoked per iteration. 36354 * @returns {number} Returns the sum. 36355 */ 36356 function baseSum(collection, iteratee) { 36357 var result = 0; 36358 baseEach(collection, function(value, index, collection) { 36359 result += +iteratee(value, index, collection) || 0; 36360 }); 36361 return result; 36362 } 36363 36364 /** 36365 * The base implementation of `_.uniq` without support for callback shorthands 36366 * and `this` binding. 36367 * 36368 * @private 36369 * @param {Array} array The array to inspect. 36370 * @param {Function} [iteratee] The function invoked per iteration. 36371 * @returns {Array} Returns the new duplicate-value-free array. 36372 */ 36373 function baseUniq(array, iteratee) { 36374 var index = -1, 36375 indexOf = getIndexOf(), 36376 length = array.length, 36377 isCommon = indexOf == baseIndexOf, 36378 isLarge = isCommon && length >= LARGE_ARRAY_SIZE, 36379 seen = isLarge ? createCache() : null, 36380 result = []; 36381 36382 if (seen) { 36383 indexOf = cacheIndexOf; 36384 isCommon = false; 36385 } else { 36386 isLarge = false; 36387 seen = iteratee ? [] : result; 36388 } 36389 outer: 36390 while (++index < length) { 36391 var value = array[index], 36392 computed = iteratee ? iteratee(value, index, array) : value; 36393 36394 if (isCommon && value === value) { 36395 var seenIndex = seen.length; 36396 while (seenIndex--) { 36397 if (seen[seenIndex] === computed) { 36398 continue outer; 36399 } 36400 } 36401 if (iteratee) { 36402 seen.push(computed); 36403 } 36404 result.push(value); 36405 } 36406 else if (indexOf(seen, computed, 0) < 0) { 36407 if (iteratee || isLarge) { 36408 seen.push(computed); 36409 } 36410 result.push(value); 36411 } 36412 } 36413 return result; 36414 } 36415 36416 /** 36417 * The base implementation of `_.values` and `_.valuesIn` which creates an 36418 * array of `object` property values corresponding to the property names 36419 * of `props`. 36420 * 36421 * @private 36422 * @param {Object} object The object to query. 36423 * @param {Array} props The property names to get values for. 36424 * @returns {Object} Returns the array of property values. 36425 */ 36426 function baseValues(object, props) { 36427 var index = -1, 36428 length = props.length, 36429 result = Array(length); 36430 36431 while (++index < length) { 36432 result[index] = object[props[index]]; 36433 } 36434 return result; 36435 } 36436 36437 /** 36438 * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`, 36439 * and `_.takeWhile` without support for callback shorthands and `this` binding. 36440 * 36441 * @private 36442 * @param {Array} array The array to query. 36443 * @param {Function} predicate The function invoked per iteration. 36444 * @param {boolean} [isDrop] Specify dropping elements instead of taking them. 36445 * @param {boolean} [fromRight] Specify iterating from right to left. 36446 * @returns {Array} Returns the slice of `array`. 36447 */ 36448 function baseWhile(array, predicate, isDrop, fromRight) { 36449 var length = array.length, 36450 index = fromRight ? length : -1; 36451 36452 while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {} 36453 return isDrop 36454 ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) 36455 : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); 36456 } 36457 36458 /** 36459 * The base implementation of `wrapperValue` which returns the result of 36460 * performing a sequence of actions on the unwrapped `value`, where each 36461 * successive action is supplied the return value of the previous. 36462 * 36463 * @private 36464 * @param {*} value The unwrapped value. 36465 * @param {Array} actions Actions to peform to resolve the unwrapped value. 36466 * @returns {*} Returns the resolved value. 36467 */ 36468 function baseWrapperValue(value, actions) { 36469 var result = value; 36470 if (result instanceof LazyWrapper) { 36471 result = result.value(); 36472 } 36473 var index = -1, 36474 length = actions.length; 36475 36476 while (++index < length) { 36477 var action = actions[index]; 36478 result = action.func.apply(action.thisArg, arrayPush([result], action.args
36478)); 36479 } 36480 return result; 36481 } 36482 36483 /** 36484 * Performs a binary search of `array` to determine the index at which `value` 36485 * should be inserted into `array` in order to maintain its sort order. 36486 * 36487 * @private 36488 * @param {Array} array The sorted array to inspect. 36489 * @param {*} value The value to evaluate. 36490 * @param {boolean} [retHighest] Specify returning the highest qualified index. 36491 * @returns {number} Returns the index at which `value` should be inserted 36492 * into `array`. 36493 */ 36494 function binaryIndex(array, value, retHighest) { 36495 var low = 0, 36496 high = array ? array.length : low; 36497 36498 if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { 36499 while (low < high) { 36500 var mid = (low + high) >>> 1, 36501 computed = array[mid]; 36502 36503 if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { 36504 low = mid + 1; 36505 } else { 36506 high = mid; 36507 } 36508 } 36509 return high; 36510 } 36511 return binaryIndexBy(array, value, identity, retHighest); 36512 } 36513 36514 /** 36515 * This function is like `binaryIndex` except that it invokes `iteratee` for 36516 * `value` and each element of `array` to compute their sort ranking. The 36517 * iteratee is invoked with one argument; (value). 36518 * 36519 * @private 36520 * @param {Array} array The sorted array to inspect. 36521 * @param {*} value The value to evaluate. 36522 * @param {Function} iteratee The function invoked per iteration. 36523 * @param {boolean} [retHighest] Specify returning the highest qualified index. 36524 * @returns {number} Returns the index at which `value` should be inserted 36525 * into `array`. 36526 */ 36527 function binaryIndexBy(array, value, iteratee, retHighest) { 36528 value = iteratee(value); 36529 36530 var low = 0, 36531 high = array ? array.length : 0, 36532 valIsNaN = value !== value, 36533 valIsNull = value === null, 36534 valIsUndef = value === undefined; 36535 36536 while (low < high) { 36537 var mid = nativeFloor((low + high) / 2), 36538 computed = iteratee(array[mid]), 36539 isDef = computed !== undefined, 36540 isReflexive = computed === computed; 36541 36542 if (valIsNaN) { 36543 var setLow = isReflexive || retHighest; 36544 } else if (valIsNull) { 36545 setLow = isReflexive && isDef && (retHighest || computed != null); 36546 } else if (valIsUndef) { 36547 setLow = isReflexive && (retHighest || isDef); 36548 } else if (computed == null) { 36549 setLow = false; 36550 } else { 36551 setLow = retHighest ? (computed <= value) : (computed < value); 36552 } 36553 if (setLow) { 36554 low = mid + 1; 36555 } else { 36556 high = mid; 36557 } 36558 } 36559 return nativeMin(high, MAX_ARRAY_INDEX); 36560 } 36561 36562 /** 36563 * A specialized version of `baseCallback` which only supports `this` binding 36564 * and specifying the number of arguments to provide to `func`. 36565 * 36566 * @private 36567 * @param {Function} func The function to bind. 36568 * @param {*} thisArg The `this` binding of `func`. 36569 * @param {number} [argCount] The number of arguments to provide to `func`. 36570 * @returns {Function} Returns the callback. 36571 */ 36572 function bindCallback(func, thisArg, argCount) { 36573 if (typeof func != 'function') { 36574 return identity; 36575 } 36576 if (thisArg === undefined) { 36577 return func; 36578 } 36579 switch (argCount) { 36580 case 1: return function(value) { 36581 return func.call(thisArg, value); 36582 }; 36583 case 3: return function(value, index, collection) { 36584 return func.call(thisArg, value, index, collection); 36585 }; 36586 case 4: return function(accumulator, value, index, collection) { 36587 return func.call(thisArg, accumulator, value, index, collection); 36588 }; 36589 case 5: return function(value, other, key, object, source) { 36590 return func.call(thisArg, value, other, key, object, source); 36591 }; 36592 } 36593 return function() { 36594 return func.apply(thisArg, arguments); 36595 }; 36596 } 36597 36598 /** 36599 * Creates a clone of the given array buffer. 36600 * 36601 * @private 36602 * @param {ArrayBuffer} buffer The array buffer to clone. 36603 * @returns {ArrayBuffer} Returns the cloned array buffer. 36604 */ 36605 function bufferClone(buffer) { 36606 var result = new ArrayBuffer(buffer.byteLength), 36607 view = new Uint8Array(result); 36608 36609 view.set(new Uint8Array(buffer)); 36610 return result; 36611 } 36612 36613 /** 36614 * Creates an array that is the composition of partially applied arguments, 36615 * placeholders, and provided arguments into a single array of arguments. 36616 * 36617 * @private 36618 * @param {Array|Object} args The provided arguments. 36619 * @param {Array}
36619 partials The arguments to prepend to those provided. 36620 * @param {Array} holders The `partials` placeholder indexes. 36621 * @returns {Array} Returns the new array of composed arguments. 36622 */ 36623 function composeArgs(args, partials, holders) { 36624 var holdersLength = holders.length, 36625 argsIndex = -1, 36626 argsLength = nativeMax(args.length - holdersLength, 0), 36627 leftIndex = -1, 36628 leftLength = partials.length, 36629 result = Array(leftLength + argsLength); 36630 36631 while (++leftIndex < leftLength) { 36632 result[leftIndex] = partials[leftIndex]; 36633 } 36634 while (++argsIndex < holdersLength) { 36635 result[holders[argsIndex]] = args[argsIndex]; 36636 } 36637 while (argsLength--) { 36638 result[leftIndex++] = args[argsIndex++]; 36639 } 36640 return result; 36641 } 36642 36643 /** 36644 * This function is like `composeArgs` except that the arguments composition 36645 * is tailored for `_.partialRight`. 36646 * 36647 * @private 36648 * @param {Array|Object} args The provided arguments. 36649 * @param {Array} partials The arguments to append to those provided. 36650 * @param {Array} holders The `partials` placeholder indexes. 36651 * @returns {Array} Returns the new array of composed arguments. 36652 */ 36653 function composeArgsRight(args, partials, holders) { 36654 var holdersIndex = -1, 36655 holdersLength = holders.length, 36656 argsIndex = -1, 36657 argsLength = nativeMax(args.length - holdersLength, 0), 36658 rightIndex = -1, 36659 rightLength = partials.length, 36660 result = Array(argsLength + rightLength); 36661 36662 while (++argsIndex < argsLength) { 36663 result[argsIndex] = args[argsIndex]; 36664 } 36665 var offset = argsIndex; 36666 while (++rightIndex < rightLength) { 36667 result[offset + rightIndex] = partials[rightIndex]; 36668 } 36669 while (++holdersIndex < holdersLength) { 36670 result[offset + holders[holdersIndex]] = args[argsIndex++]; 36671 } 36672 return result; 36673 } 36674 36675 /** 36676 * Creates a `_.countBy`, `_.groupBy`, `_.indexBy`, or `_.partition` function. 36677 * 36678 * @private 36679 * @param {Function} setter The function to set keys and values of the accumulator object. 36680 * @param {Function} [initializer] The function to initialize the accumulator object. 36681 * @returns {Function} Returns the new aggregator function. 36682 */ 36683 function createAggregator(setter, initializer) { 36684 return function(collection, iteratee, thisArg) { 36685 var result = initializer ? initializer() : {}; 36686 iteratee = getCallback(iteratee, thisArg, 3); 36687 36688 if (isArray(collection)) { 36689 var index = -1, 36690 length = collection.length; 36691 36692 while (++index < length) { 36693 var value = collection[index]; 36694 setter(result, value, iteratee(value, index, collection), collection); 36695 } 36696 } else { 36697 baseEach(collection, function(value, key, collection) { 36698 setter(result, value, iteratee(value, key, collection), collection); 36699 }); 36700 } 36701 return result; 36702 }; 36703 } 36704 36705 /** 36706 * Creates a `_.assign`, `_.defaults`, or `_.merge` function. 36707 * 36708 * @private 36709 * @param {Function} assigner The function to assign values. 36710 * @returns {Function} Returns the new assigner function. 36711 */ 36712 function createAssigner(assigner) { 36713 return restParam(function(object, sources) { 36714 var index = -1, 36715 length = object == null ? 0 : sources.length, 36716 customizer = length > 2 ? sources[length - 2] : undefined, 36717 guard = length > 2 ? sources[2] : undefined, 36718 thisArg = length > 1 ? sources[length - 1] : undefined; 36719 36720 if (typeof customizer == 'function') { 36721 customizer = bindCallback(customizer, thisArg, 5); 36722 length -= 2; 36723 } else { 36724 customizer = typeof thisArg == 'function' ? thisArg : undefined; 36725 length -= (customizer ? 1 : 0); 36726 } 36727 if (guard && isIterateeCall(sources[0], sources[1], guard)) { 36728 customizer = length < 3 ? undefined : customizer; 36729 length = 1; 36730 } 36731 while (++index < length) { 36732 var source = sources[index]; 36733 if (source) { 36734 assigner(object, source, customizer); 36735 } 36736 } 36737 return object; 36738 }); 36739 } 36740 36741 /** 36742 * Creates a `baseEach` or `baseEachRight` function. 36743 * 36744 * @private 36745 * @param {Function} eachFunc The function to iterate over a collection. 36746 * @param {boolean} [fromRight] Specify iterating from right to left. 36747 * @returns {Function} Returns the new base function. 36748 */ 36749 function createBaseEach(eachFunc, fromRight) { 36750 return function(collection, iteratee) { 36751 var length = collection ? getLength(collection) : 0; 36752 if (!isLength(length)) { 36753 return eachFunc(collection, iteratee); 36754 } 36755 var index = fromRight ? length : -1, 36756 iterable = toObject(collection); 36757 36758 while ((fromRight ? index-- : ++index < length)) { 36759 if (iteratee(iterable[index], index, iterable) === false) { 36760 break; 36761 } 36762 } 36763 return collection; 36764 }; 36765 } 36766 36767 /** 36768 * Creates a base function for `_.forIn` or `_.forInRight`. 36769 * 36770 * @private 36771 * @param {boolean} [fromRight] Specify iterating from right to left. 36772 * @returns {Function} Returns the new base function. 36773 */ 36774 function createBaseFor(fromRight) { 36775 return function(object, iteratee, keysFunc) { 36776 var iterable = toObject(object), 36777 props = keysFunc(object), 36778 length = props.length, 36779 index = fromRight ? length : -1; 36780 36781 while ((fromRight ? index-- : ++index < length)) { 36782 var key = props[index]; 36783 if (iteratee(iterable[key], key, iterable) === false) { 36784 break; 36785 } 36786 } 36787 return object; 36788 }; 36789 } 36790 36791 /** 36792 * Creates a function that wraps `func` and invokes it with the `this` 36793 * binding of `thisArg`. 36794 * 36795 * @private 36796 * @param {Function} func The function to bind. 36797 * @param {*} [thisArg] The `this` binding of `func`. 36798 * @returns {Function} Returns the new bound function. 36799 */ 36800 function createBindWrapper(func, thisArg) { 36801 var Ctor = createCtorWrapper(func); 36802 36803 function wrapper() { 36804 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; 36805 return fn.apply(thisArg, arguments); 36806 } 36807 return wrapper; 36808 } 36809 36810 /** 36811 * Creates a `Set` cache object to optimize linear searches of large arrays. 36812 * 36813 * @private 36814 * @param {Array} [values] The values to cache. 36815 * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. 36816 */ 36817 function createCache(values) {
36818 return (nativeCreate && Set) ? new SetCache(values) : null; 36819 } 36820 36821 /** 36822 * Creates a function that produces compound words out of the words in a 36823 * given string. 36824 * 36825 * @private 36826 * @param {Function} callback The function to combine each word. 36827 * @returns {Function} Returns the new compounder function. 36828 */ 36829 function createCompounder(callback) { 36830 return function(string) { 36831 var index = -1, 36832 array = words(deburr(string)), 36833 length = array.length, 36834 result = ''; 36835 36836 while (++index < length) { 36837 result = callback(result, array[index], index); 36838 } 36839 return result; 36840 }; 36841 } 36842 36843 /** 36844 * Creates a function that produces an instance of `Ctor` regardless of 36845 * whether it was invoked as part of a `new` expression or by `call` or `apply`. 36846 * 36847 * @private 36848 * @param {Function} Ctor The constructor to wrap. 36849 * @returns {Function} Returns the new wrapped function. 36850 */ 36851 function createCtorWrapper(Ctor) { 36852 return function() { 36853 // Use a `switch` statement to work with class constructors. 36854 // See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist 36855 // for more details. 36856 var args = arguments; 36857 switch (args.length) { 36858 case 0: return new Ctor; 36859 case 1: return new Ctor(args[0]); 36860 case 2: return new Ctor(args[0], args[1]); 36861 case 3: return new Ctor(args[0], args[1], args[2]); 36862 case 4: return new Ctor(args[0], args[1], args[2], args[3]); 36863 case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); 36864 case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); 36865 case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); 36866 } 36867 var thisBinding = baseCreate(Ctor.prototype), 36868 result = Ctor.apply(thisBinding, args); 36869 36870 // Mimic the constructor's `return` behavior. 36871 // See https://es5.github.io/#x13.2.2 for more details. 36872 return isObject(result) ? result : thisBinding; 36873 }; 36874 } 36875 36876 /** 36877 * Creates a `_.curry` or `_.curryRight` function. 36878 * 36879 * @private 36880 * @param {boolean} flag The curry bit flag. 36881 * @returns {Function} Returns the new curry function. 36882 */ 36883 function createCurry(flag) { 36884 function curryFunc(func, arity, guard) { 36885 if (guard && isIterateeCall(func, arity, guard)) { 36886 arity = undefined; 36887 } 36888 var result = createWrapper(func, flag, undefined, undefined, undefined, undefined, undefined, arity); 36889 result.placeholder = curryFunc.placeholder; 36890 return result; 36891 } 36892 return curryFunc; 36893 } 36894 36895 /** 36896 * Creates a `_.defaults` or `_.defaultsDeep` function. 36897 * 36898 * @private 36899 * @param {Function} assigner The function to assign values. 36900 * @param {Function} customizer The function to customize assigned values. 36901 * @returns {Function} Returns the new defaults function. 36902 */ 36903 function createDefaults(assigner, customizer) { 36904 return restParam(function(args) { 36905 var object = args[0]; 36906 if (object == null) { 36907 return object; 36908 } 36909 args.push(customizer); 36910 return assigner.apply(undefined, args); 36911 }); 36912 } 36913 36914 /** 36915 * Creates a `_.max` or `_.min` function. 36916 * 36917 * @private 36918 * @param {Function} comparator The function used to compare values. 36919 * @param {*} exValue The initial extremum value. 36920 * @returns {Function} Returns the new extremum function. 36921 */ 36922 function createExtremum(comparator, exValue) { 36923 return function(collection, iteratee, thisArg) { 36924 if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { 36925 iteratee = undefined; 36926 } 36927 iteratee = getCallback(iteratee, thisArg, 3); 36928 if (iteratee.length == 1) { 36929 collection = isArray(collection) ? collection : toIterable(collection); 36930 var result = arrayExtremum(collection, iteratee, comparator, exValue); 36931 if (!(collection.length && result === exValue)) { 36932 return result; 36933 } 36934 } 36935 return baseExtremum(collection, iteratee, comparator, exValue); 36936 }; 36937 } 36938 36939 /** 36940 * Creates a `_.find` or `_.findLast` function. 36941 * 36942 * @private 36943 * @param {Function} eachFunc The function to iterate over a collection. 36944 * @param {boolean} [fromRight] Specify iterating from right to left. 36945 * @returns {Function} Returns the new find function. 36946 */ 36947 function createFind(eachFunc, fromRight) { 36948 return function(collection, predicate, thisArg) { 36949 predicate = getCallback(predicate, thisArg, 3); 36950 if (isArray(collection)) { 36951 var index = baseFindIndex(collection, predicate, fromRight); 36952 return index > -1 ? collection[index] : undefined; 36953 } 36954 return baseFind(collection, predicate, eachFunc); 36955 }; 36956 } 36957 36958 /** 36959 * Creates a `_.findIndex` or `_.findLastIndex` function. 36960 * 36961 * @private 36962 * @param {boolean} [fromRight] Specify iterating from right to left. 36963 * @returns {Function} Returns the new find function. 36964 */ 36965 function createFindIndex(fromRight) { 36966 return function(array, predicate, thisArg) { 36967 if (!(array && array.length)) { 36968 return -1; 36969 } 36970 predicate = getCallback(predicate, thisArg, 3); 36971 return baseFindIndex(array, predicate, fromRight); 36972 }; 36973 } 36974 36975 /** 36976 * Creates a `_.findKey` or `_.findLastKey` function. 36977 * 36978 * @private 36979 * @param {Function} objectFunc The function to iterate over an object. 36980 * @returns {Function} Returns the new find function. 36981 */ 36982 function createFindKey(objectFunc) { 36983 return function(object, predicate, thisArg) { 36984 predicate = getCallback(predicate, thisArg, 3); 36985 return baseFind(object, predicate, objectFunc, true); 36986 }; 36987 } 36988 36989 /** 36990 * Creates a `_.flow` or `_.flowRight` function. 36991 * 36992 * @private 36993 * @param {boolean} [fromRight] Specify iterating from right to left. 36994 * @returns {Function} Returns the new flow function. 36995 */ 36996 function createFlow(fromRight) { 36997 return function() { 36998 var wrapper, 36999 length = arguments.length, 37000 index = fromRight ? length : -1, 37001 leftIndex = 0, 37002 funcs = Array(length); 37003 37004 while ((fromRight ? index-- : ++index < length)) { 37005 var func = funcs[leftIndex++] = arguments[index]; 37006 if (typeof func != 'function') { 37007 throw new TypeError(FUNC_ERROR_TEXT); 37008 } 37009 if (!wrapper && LodashWrapper.prototype.thru && getFuncName(func) == 'wrapper') { 37010 wrapper = new LodashWrapper([], true); 37011 } 37012 } 37013 index = wrapper ? -1 : length; 37014 while (++index < length) { 37015 func = funcs[index]; 37016 37017 var funcName = getFuncName(func), 37018 data = funcName == 'wrapper' ? getData(func) : undefined; 37019 37020 if (data && isLaziable(data[0]) && data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && !data[4].length && data[9] == 1) {
37021 wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); 37022 } else { 37023 wrapper = (func.length == 1 && isLaziable(func)) ? wrapper[funcName]() : wrapper.thru(func); 37024 } 37025 } 37026 return function() { 37027 var args = arguments, 37028 value = args[0]; 37029 37030 if (wrapper && args.length == 1 && isArray(value) && value.length >= LARGE_ARRAY_SIZE) { 37031 return wrapper.plant(value).value(); 37032 } 37033 var index = 0, 37034 result = length ? funcs[index].apply(this, args) : value; 37035 37036 while (++index < length) { 37037 result = funcs[index].call(this, result); 37038 } 37039 return result; 37040 }; 37041 }; 37042 } 37043 37044 /** 37045 * Creates a function for `_.forEach` or `_.forEachRight`. 37046 * 37047 * @private 37048 * @param {Function} arrayFunc The function to iterate over an array. 37049 * @param {Function} eachFunc The function to iterate over a collection. 37050 * @returns {Function} Returns the new each function. 37051 */ 37052 function createForEach(arrayFunc, eachFunc) { 37053 return function(collection, iteratee, thisArg) { 37054 return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) 37055 ? arrayFunc(collection, iteratee) 37056 : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); 37057 }; 37058 } 37059 37060 /** 37061 * Creates a function for `_.forIn` or `_.forInRight`. 37062 * 37063 * @private 37064 * @param {Function} objectFunc The function to iterate over an object. 37065 * @returns {Function} Returns the new each function. 37066 */ 37067 function createForIn(objectFunc) { 37068 return function(object, iteratee, thisArg) { 37069 if (typeof iteratee != 'function' || thisArg !== undefined) { 37070 iteratee = bindCallback(iteratee, thisArg, 3); 37071 } 37072 return objectFunc(object, iteratee, keysIn); 37073 }; 37074 } 37075 37076 /** 37077 * Creates a function for `_.forOwn` or `_.forOwnRight`. 37078 * 37079 * @private 37080 * @param {Function} objectFunc The function to iterate over an object. 37081 * @returns {Function} Returns the new each function. 37082 */ 37083 function createForOwn(objectFunc) { 37084 return function(object, iteratee, thisArg) { 37085 if (typeof iteratee != 'function' || thisArg !== undefined) { 37086 iteratee = bindCallback(iteratee, thisArg, 3); 37087 } 37088 return objectFunc(object, iteratee); 37089 }; 37090 } 37091 37092 /** 37093 * Creates a function for `_.mapKeys` or `_.mapValues`. 37094 * 37095 * @private 37096 * @param {boolean} [isMapKeys] Specify mapping keys instead of values. 37097 * @returns {Function} Returns the new map function. 37098 */ 37099 function createObjectMapper(isMapKeys) { 37100 return function(object, iteratee, thisArg) { 37101 var result = {}; 37102 iteratee = getCallback(iteratee, thisArg, 3); 37103 37104 baseForOwn(object, function(value, key, object) { 37105 var mapped = iteratee(value, key, object); 37106 key = isMapKeys ? mapped : key; 37107 value = isMapKeys ? value : mapped; 37108 result[key] = value; 37109 }); 37110 return result; 37111 }; 37112 } 37113 37114 /** 37115 * Creates a function for `_.padLeft` or `_.padRight`. 37116 * 37117 * @private 37118 * @param {boolean} [fromRight] Specify padding from the right. 37119 * @returns {Function} Returns the new pad function. 37120 */ 37121 function createPadDir(fromRight) { 37122 return function(string, length, chars) { 37123 string = baseToString(string); 37124 return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string); 37125 }; 37126 } 37127 37128 /** 37129 * Creates a `_.partial` or `_.partialRight` function. 37130 * 37131 * @private 37132 * @param {boolean} flag The partial bit flag. 37133 * @returns {Function} Returns the new partial function. 37134 */ 37135 function createPartial(flag) { 37136 var partialFunc = restParam(function(func, partials) { 37137 var holders = replaceHolders(partials, partialFunc.placeholder); 37138 return createWrapper(func, flag, undefined, partials, holders); 37139 }); 37140 return partialFunc; 37141 } 37142 37143 /** 37144 * Creates a function for `_.reduce` or `_.reduceRight`. 37145 * 37146 * @private 37147 * @param {Function} arrayFunc The function to iterate over an array.
37148 * @param {Function} eachFunc The function to iterate over a collection. 37149 * @returns {Function} Returns the new each function. 37150 */ 37151 function createReduce(arrayFunc, eachFunc) { 37152 return function(collection, iteratee, accumulator, thisArg) { 37153 var initFromArray = arguments.length < 3; 37154 return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) 37155 ? arrayFunc(collection, iteratee, accumulator, initFromArray) 37156 : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); 37157 }; 37158 } 37159 37160 /** 37161 * Creates a function that wraps `func` and invokes it with optional `this` 37162 * binding of, partial application, and currying. 37163 * 37164 * @private 37165 * @param {Function|string} func The function or method name to reference. 37166 * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. 37167 * @param {*} [thisArg] The `this` binding of `func`. 37168 * @param {Array} [partials] The arguments to prepend to those provided to the new function. 37169 * @param {Array} [holders] The `partials` placeholder indexes. 37170 * @param {Array} [partialsRight] The arguments to append to those provided to the new function. 37171 * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. 37172 * @param {Array} [argPos] The argument positions of the new function. 37173 * @param {number} [ary] The arity cap of `func`. 37174 * @param {number} [arity] The arity of `func`. 37175 * @returns {Function} Returns the new wrapped function. 37176 */ 37177 function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { 37178 var isAry = bitmask & ARY_FLAG, 37179 isBind = bitmask & BIND_FLAG, 37180 isBindKey = bitmask & BIND_KEY_FLAG, 37181 isCurry = bitmask & CURRY_FLAG, 37182 isCurryBound = bitmask & CURRY_BOUND_FLAG, 37183 isCurryRight = bitmask & CURRY_RIGHT_FLAG, 37184 Ctor = isBindKey ? undefined : createCtorWrapper(func); 37185 37186 function wrapper() { 37187 // Avoid `arguments` object use disqualifying optimizations by 37188 // converting it to an array before providing it to other functions. 37189 var length = arguments.length, 37190 index = length, 37191 args = Array(length); 37192 37193 while (index--) { 37194 args[index] = arguments[index]; 37195 } 37196 if (partials) { 37197 args = composeArgs(args, partials, holders); 37198 } 37199 if (partialsRight) { 37200 args = composeArgsRight(args, partialsRight, holdersRight); 37201 } 37202 if (isCurry || isCurryRight) { 37203 var placeholder = wrapper.placeholder, 37204 argsHolders = replaceHolders(args, placeholder); 37205 37206 length -= argsHolders.length; 37207 if (length < arity) { 37208 var newArgPos = argPos ? arrayCopy(argPos) : undefined, 37209 newArity = nativeMax(arity - length, 0), 37210 newsHolders = isCurry ? argsHolders : undefined, 37211 newHoldersRight = isCurry ? undefined : argsHolders, 37212 newPartials = isCurry ? args : undefined, 37213 newPartialsRight = isCurry ? undefined : args; 37214 37215 bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); 37216 bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); 37217 37218 if (!isCurryBound) { 37219 bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); 37220 } 37221 var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity], 37222 result = createHybridWrapper.apply(undefined, newData); 37223 37224 if (isLaziable(func)) { 37225 setData(result, newData); 37226 } 37227 result.placeholder = placeholder; 37228 return result; 37229 } 37230 } 37231 var thisBinding = isBind ? thisArg : this, 37232 fn = isBindKey ? thisBinding[func] : func; 37233 37234 if (argPos) { 37235 args = reorder(args, argPos); 37236 } 37237 if (isAry && ary < args.length) { 37238 args.length = ary; 37239 } 37240 if (this && this !== root && this instanceof wrapper) { 37241 fn = Ctor || createCtorWrapper(func); 37242 }
37243 return fn.apply(thisBinding, args); 37244 } 37245 return wrapper; 37246 } 37247 37248 /** 37249 * Creates the padding required for `string` based on the given `length`. 37250 * The `chars` string is truncated if the number of characters exceeds `length`. 37251 * 37252 * @private 37253 * @param {string} string The string to create padding for. 37254 * @param {number} [length=0] The padding length. 37255 * @param {string} [chars=' '] The string used as padding. 37256 * @returns {string} Returns the pad for `string`. 37257 */ 37258 function createPadding(string, length, chars) { 37259 var strLength = string.length; 37260 length = +length; 37261 37262 if (strLength >= length || !nativeIsFinite(length)) { 37263 return ''; 37264 } 37265 var padLength = length - strLength; 37266 chars = chars == null ? ' ' : (chars + ''); 37267 return repeat(chars, nativeCeil(padLength / chars.length)).slice(0, padLength); 37268 } 37269 37270 /** 37271 * Creates a function that wraps `func` and invokes it with the optional `this` 37272 * binding of `thisArg` and the `partials` prepended to those provided to 37273 * the wrapper. 37274 * 37275 * @private 37276 * @param {Function} func The function to partially apply arguments to. 37277 * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. 37278 * @param {*} thisArg The `this` binding of `func`. 37279 * @param {Array} partials The arguments to prepend to those provided to the new function. 37280 * @returns {Function} Returns the new bound function. 37281 */ 37282 function createPartialWrapper(func, bitmask, thisArg, partials) { 37283 var isBind = bitmask & BIND_FLAG, 37284 Ctor = createCtorWrapper(func); 37285 37286 function wrapper() { 37287 // Avoid `arguments` object use disqualifying optimizations by 37288 // converting it to an array before providing it `func`. 37289 var argsIndex = -1, 37290 argsLength = arguments.length, 37291 leftIndex = -1, 37292 leftLength = partials.length, 37293 args = Array(leftLength + argsLength); 37294 37295 while (++leftIndex < leftLength) { 37296 args[leftIndex] = partials[leftIndex]; 37297 } 37298 while (argsLength--) { 37299 args[leftIndex++] = arguments[++argsIndex]; 37300 } 37301 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; 37302 return fn.apply(isBind ? thisArg : this, args); 37303 } 37304 return wrapper; 37305 } 37306 37307 /** 37308 * Creates a `_.ceil`, `_.floor`, or `_.round` function. 37309 * 37310 * @private 37311 * @param {string} methodName The name of the `Math` method to use when rounding. 37312 * @returns {Function} Returns the new round function. 37313 */ 37314 function createRound(methodName) { 37315 var func = Math[methodName]; 37316 return function(number, precision) { 37317 precision = precision === undefined ? 0 : (+precision || 0); 37318 if (precision) { 37319 precision = pow(10, precision); 37320 return func(number * precision) / precision; 37321 } 37322 return func(number); 37323 }; 37324 } 37325 37326 /** 37327 * Creates a `_.sortedIndex` or `_.sortedLastIndex` function. 37328 * 37329 * @private 37330 * @param {boolean} [retHighest] Specify returning the highest qualified index. 37331 * @returns {Function} Returns the new index function. 37332 */ 37333 function createSortedIndex(retHighest) { 37334 return function(array, value, iteratee, thisArg) { 37335 var callback = getCallback(iteratee); 37336 return (iteratee == null && callback === baseCallback) 37337 ? binaryIndex(array, value, retHighest) 37338 : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest); 37339 }; 37340 } 37341 37342 /** 37343 * Creates a function that either curries or invokes `func` with optional 37344 * `this` binding and partially applied arguments. 37345 * 37346 * @private 37347 * @param {Function|string} func The function or method name to reference. 37348 * @param {number} bitmask The bitmask of flags. 37349 * The bitmask may be composed of the following flags: 37350 * 1 - `_.bind` 37351 * 2 - `_.bindKey` 37352 * 4 - `_.curry` or `_.curryRight` of a bound function 37353 * 8 - `_.curry` 37354 * 16 - `_.curryRight` 37355 * 32 - `_.partial` 37356 * 64 - `_.partialRight` 37357 * 128 - `_.rearg` 37358 * 256 - `_.ary` 37359 * @param {*} [thisArg] The `this` binding of `func`. 37360 * @param {Array} [partials] The arguments to be partially applied. 37361 * @param {Array} [holders] The `partials` placeholder indexes. 37362 * @param {Array} [argPos] The argument positions of the new function. 37363 * @param {number} [ary] The arity cap of `func`. 37364 * @param {number} [arity] The arity of `func`. 37365 * @returns {Function} Returns the new wrapped function. 37366 */ 37367 function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { 37368 var isBindKey = bitmask & BIND_KEY_FLAG; 37369 if (!isBindKey && typeof func != 'function') { 37370 throw new TypeError(FUNC_ERROR_TEXT); 37371 } 37372 var length = partials ? partials.length : 0; 37373 if (!length) { 37374 bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); 37375 partials = holders = undefined; 37376 } 37377 length -= (holders ? holders.length : 0); 37378 if (bitmask & PARTIAL_RIGHT_FLAG) { 37379 var partialsRight = partials, 37380 holdersRight = holders; 37381 37382 partials = holders = undefined; 37383 } 37384 var data = isBindKey ? undefined : getData(func), 37385 newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity]; 37386 37387 if (data) { 37388 mergeData(newData, data); 37389 bitmask = newData[1]; 37390 arity = newData[9]; 37391 } 37392 newData[9] = arity == null 37393 ? (isBindKey ? 0 : func.length) 37394 : (nativeMax(arity - length, 0) || 0); 37395 37396 if (bitmask == BIND_FLAG) { 37397 var result = createBindWrapper(newData[0], newData[2]); 37398 } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
37399 result = createPartialWrapper.apply(undefined, newData); 37400 } else { 37401 result = createHybridWrapper.apply(undefined, newData); 37402 } 37403 var setter = data ? baseSetData : setData; 37404 return setter(result, newData); 37405 } 37406 37407 /** 37408 * A specialized version of `baseIsEqualDeep` for arrays with support for 37409 * partial deep comparisons. 37410 * 37411 * @private 37412 * @param {Array} array The array to compare. 37413 * @param {Array} other The other array to compare. 37414 * @param {Function} equalFunc The function to determine equivalents of values. 37415 * @param {Function} [customizer] The function to customize comparing arrays. 37416 * @param {boolean} [isLoose] Specify performing partial comparisons. 37417 * @param {Array} [stackA] Tracks traversed `value` objects. 37418 * @param {Array} [stackB] Tracks traversed `other` objects. 37419 * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. 37420 */ 37421 function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { 37422 var index = -1, 37423 arrLength = array.length, 37424 othLength = other.length; 37425 37426 if (arrLength != othLength && !(isLoose && othLength > arrLength)) { 37427 return false; 37428 } 37429 // Ignore non-index properties. 37430 while (++index < arrLength) { 37431 var arrValue = array[index], 37432 othValue = other[index], 37433 result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined; 37434 37435 if (result !== undefined) { 37436 if (result) { 37437 continue; 37438 } 37439 return false; 37440 } 37441 // Recursively compare arrays (susceptible to call stack limits). 37442 if (isLoose) { 37443 if (!arraySome(other, function(othValue) { 37444 return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); 37445 })) { 37446 return false; 37447 } 37448 } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) { 37449 return false; 37450 } 37451 } 37452 return true; 37453 } 37454 37455 /** 37456 * A specialized version of `baseIsEqualDeep` for comparing objects of 37457 * the same `toStringTag`. 37458 * 37459 * **Note:** This function only supports comparing values with tags of 37460 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. 37461 * 37462 * @private 37463 * @param {Object} object The object to compare. 37464 * @param {Object} other The other object to compare. 37465 * @param {string} tag The `toStringTag` of the objects to compare. 37466 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 37467 */ 37468 function equalByTag(object, other, tag) { 37469 switch (tag) { 37470 case boolTag: 37471 case dateTag: 37472 // Coerce dates and booleans to numbers, dates to milliseconds and booleans 37473 // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. 37474 return +object == +other; 37475 37476 case errorTag: 37477 return object.name == other.name && object.message == other.message; 37478 37479 case numberTag: 37480 // Treat `NaN` vs. `NaN` as equal. 37481 return (object != +object) 37482 ? other != +other 37483 : object == +other; 37484 37485 case regexpTag: 37486 case stringTag: 37487 // Coerce regexes to strings and treat strings primitives and string 37488 // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. 37489 return object == (other + ''); 37490 } 37491 return false; 37492 } 37493 37494 /** 37495 * A specialized version of `baseIsEqualDeep` for objects with support for 37496 * partial deep comparisons. 37497 * 37498 * @private 37499 * @param {Object} object The object to compare. 37500 * @param {Object} other The other object to compare. 37501 * @param {Function} equalFunc The function to determine equivalents of values. 37502 * @param {Function} [customizer] The function to customize comparing values. 37503 * @param {boolean} [isLoose] Specify performing partial comparisons. 37504 * @param {Array} [stackA] Tracks traversed `value` objects. 37505 * @param {Array} [stackB] Tracks traversed `other` objects. 37506 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 37507 */ 37508 function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
37509 var objProps = keys(object), 37510 objLength = objProps.length, 37511 othProps = keys(other), 37512 othLength = othProps.length; 37513 37514 if (objLength != othLength && !isLoose) { 37515 return false; 37516 } 37517 var index = objLength; 37518 while (index--) { 37519 var key = objProps[index]; 37520 if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) { 37521 return false; 37522 } 37523 } 37524 var skipCtor = isLoose; 37525 while (++index < objLength) { 37526 key = objProps[index]; 37527 var objValue = object[key], 37528 othValue = other[key], 37529 result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined; 37530 37531 // Recursively compare objects (susceptible to call stack limits). 37532 if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) { 37533 return false; 37534 } 37535 skipCtor || (skipCtor = key == 'constructor'); 37536 } 37537 if (!skipCtor) { 37538 var objCtor = object.constructor, 37539 othCtor = other.constructor; 37540 37541 // Non `Object` object instances with different constructors are not equal. 37542 if (objCtor != othCtor && 37543 ('constructor' in object && 'constructor' in other) && 37544 !(typeof objCtor == 'function' && objCtor instanceof objCtor && 37545 typeof othCtor == 'function' && othCtor instanceof othCtor)) { 37546 return false; 37547 } 37548 } 37549 return true; 37550 } 37551 37552 /** 37553 * Gets the appropriate "callback" function. If the `_.callback` method is 37554 * customized this function returns the custom method, otherwise it returns 37555 * the `baseCallback` function. If arguments are provided the chosen function 37556 * is invoked with them and its result is returned. 37557 * 37558 * @private 37559 * @returns {Function} Returns the chosen function or its result. 37560 */ 37561 function getCallback(func, thisArg, argCount) { 37562 var result = lodash.callback || callback; 37563 result = result === callback ? baseCallback : result; 37564 return argCount ? result(func, thisArg, argCount) : result; 37565 } 37566 37567 /** 37568 * Gets metadata for `func`. 37569 * 37570 * @private 37571 * @param {Function} func The function to query. 37572 * @returns {*} Returns the metadata for `func`. 37573 */ 37574 var getData = !metaMap ? noop : function(func) { 37575 return metaMap.get(func); 37576 }; 37577 37578 /** 37579 * Gets the name of `func`. 37580 * 37581 * @private 37582 * @param {Function} func The function to query. 37583 * @returns {string} Returns the function name. 37584 */ 37585 function getFuncName(func) { 37586 var result = func.name, 37587 array = realNames[result], 37588 length = array ? array.length : 0; 37589 37590 while (length--) { 37591 var data = array[length], 37592 otherFunc = data.func; 37593 if (otherFunc == null || otherFunc == func) { 37594 return data.name; 37595 } 37596 } 37597 return result; 37598 } 37599 37600 /** 37601 * Gets the appropriate "indexOf" function. If the `_.indexOf` method is 37602 * customized this function returns the custom method, otherwise it returns 37603 * the `baseIndexOf` function. If arguments are provided the chosen function 37604 * is invoked with them and its result is returned. 37605 * 37606 * @private 37607 * @returns {Function|number} Returns the chosen function or its result. 37608 */ 37609 function getIndexOf(collection, target, fromIndex) { 37610 var result = lodash.indexOf || indexOf; 37611 result = result === indexOf ? baseIndexOf : result; 37612 return collection ? result(collection, target, fromIndex) : result; 37613 } 37614 37615 /** 37616 * Gets the "length" property value of `object`. 37617 * 37618 * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) 37619 * that affects Safari on at least iOS 8.1-8.3 ARM64. 37620 * 37621 * @private 37622 * @param {Object} object The object to query. 37623 * @returns {*} Returns the "length" value. 37624 */ 37625 var getLength = baseProperty('length'); 37626 37627 /** 37628 * Gets the propery names, values, and compare flags of `object`. 37629 * 37630 * @private 37631 * @param {Object} object The object to query. 37632 * @returns {Array} Returns the match data of `object`. 37633 */ 37634 function getMatchData(object) { 37635 var result = pairs(object), 37636 length = result.length; 37637 37638 while (length--) { 37639 result[length][2] = isStrictComparable(result[length][1]); 37640 } 37641 return result; 37642 } 37643 37644 /** 37645 * Gets the native function at `key` of `object`. 37646 * 37647 * @private 37648 * @param {Object} object The object to query. 37649 * @param {string} key The key of the method to get. 37650 * @returns {*} Returns the function if it's native, else `undefined`. 37651 */ 37652 function getNative(object, key) { 37653 var value = object == null ? undefined : object[key]; 37654 return isNative(value) ? value : undefined; 37655 } 37656 37657 /** 37658 * Gets the view, applying any `transforms` to the `start` and `end` positions. 37659 * 37660 * @private 37661 * @param {number} start The start of the view. 37662 * @param {number} end The end of the view. 37663 * @param {Array} transforms The transformations to apply to the view. 37664 * @returns {Object}
37664 Returns an object containing the `start` and `end` 37665 * positions of the view. 37666 */ 37667 function getView(start, end, transforms) { 37668 var index = -1, 37669 length = transforms.length; 37670 37671 while (++index < length) { 37672 var data = transforms[index], 37673 size = data.size; 37674 37675 switch (data.type) { 37676 case 'drop': start += size; break; 37677 case 'dropRight': end -= size; break; 37678 case 'take': end = nativeMin(end, start + size); break; 37679 case 'takeRight': start = nativeMax(start, end - size); break; 37680 } 37681 } 37682 return { 'start': start, 'end': end }; 37683 } 37684 37685 /** 37686 * Initializes an array clone. 37687 * 37688 * @private 37689 * @param {Array} array The array to clone. 37690 * @returns {Array} Returns the initialized clone. 37691 */ 37692 function initCloneArray(array) { 37693 var length = array.length, 37694 result = new array.constructor(length); 37695 37696 // Add array properties assigned by `RegExp#exec`. 37697 if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { 37698 result.index = array.index; 37699 result.input = array.input; 37700 } 37701 return result; 37702 } 37703 37704 /** 37705 * Initializes an object clone. 37706 * 37707 * @private 37708 * @param {Object} object The object to clone. 37709 * @returns {Object} Returns the initialized clone. 37710 */ 37711 function initCloneObject(object) { 37712 var Ctor = object.constructor; 37713 if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { 37714 Ctor = Object; 37715 } 37716 return new Ctor; 37717 } 37718 37719 /** 37720 * Initializes an object clone based on its `toStringTag`. 37721 * 37722 * **Note:** This function only supports cloning values with tags of 37723 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. 37724 * 37725 * @private 37726 * @param {Object} object The object to clone. 37727 * @param {string} tag The `toStringTag` of the object to clone. 37728 * @param {boolean} [isDeep] Specify a deep clone. 37729 * @returns {Object} Returns the initialized clone. 37730 */ 37731 function initCloneByTag(object, tag, isDeep) { 37732 var Ctor = object.constructor; 37733 switch (tag) { 37734 case arrayBufferTag: 37735 return bufferClone(object); 37736 37737 case boolTag: 37738 case dateTag: 37739 return new Ctor(+object); 37740 37741 case float32Tag: case float64Tag: 37742 case int8Tag: case int16Tag: case int32Tag: 37743 case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: 37744 var buffer = object.buffer; 37745 return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); 37746 37747 case numberTag: 37748 case stringTag: 37749 return new Ctor(object); 37750 37751 case regexpTag: 37752 var result = new Ctor(object.source, reFlags.exec(object)); 37753 result.lastIndex = object.lastIndex; 37754 } 37755 return result; 37756 } 37757 37758 /** 37759 * Invokes the method at `path` on `object`. 37760 * 37761 * @private 37762 * @param {Object} object The object to query. 37763 * @param {Array|string} path The path of the method to invoke. 37764 * @param {Array} args The arguments to invoke the method with. 37765 * @returns {*} Returns the result of the invoked method. 37766 */ 37767 function invokePath(object, path, args) { 37768 if (object != null && !isKey(path, object)) { 37769 path = toPath(path); 37770 object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); 37771 path = last(path); 37772 } 37773 var func = object == null ? object : object[path]; 37774 return func == null ? undefined : func.apply(object, args); 37775 } 37776 37777 /** 37778 * Checks if `value` is array-like. 37779 * 37780 * @private 37781 * @param {*} value The value to check. 37782 * @returns {boolean} Returns `true` if `value` is array-like, else `false`. 37783 */ 37784 function isArrayLike(value) { 37785 return value != null && isLength(getLength(value)); 37786 } 37787 37788 /** 37789 * Checks if `value` is a valid array-like index. 37790 * 37791 * @private 37792 * @param {*} value The value to check. 37793 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. 37794 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. 37795 */ 37796 function isIndex(value, length) { 37797 value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; 37798 length = length == null ? MAX_SAFE_INTEGER : length; 37799 return value > -1 && value % 1 == 0 && value < length; 37800 } 37801 37802 /** 37803 * Checks if the provided arguments are from an iteratee call. 37804 * 37805 * @private 37806 * @param {*} value The potential iteratee value argument. 37807 * @param {*} index The potential iteratee index or key argument. 37808 * @param {*} object The potential iteratee object argument. 37809 * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. 37810 */ 37811 function isIterateeCall(value, index, object) { 37812 if (!isObject(object)) { 37813 return false;
37814 } 37815 var type = typeof index; 37816 if (type == 'number' 37817 ? (isArrayLike(object) && isIndex(index, object.length)) 37818 : (type == 'string' && index in object)) { 37819 var other = object[index]; 37820 return value === value ? (value === other) : (other !== other); 37821 } 37822 return false; 37823 } 37824 37825 /** 37826 * Checks if `value` is a property name and not a property path. 37827 * 37828 * @private 37829 * @param {*} value The value to check. 37830 * @param {Object} [object] The object to query keys on. 37831 * @returns {boolean} Returns `true` if `value` is a property name, else `false`. 37832 */ 37833 function isKey(value, object) { 37834 var type = typeof value; 37835 if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { 37836 return true; 37837 } 37838 if (isArray(value)) { 37839 return false; 37840 } 37841 var result = !reIsDeepProp.test(value); 37842 return result || (object != null && value in toObject(object)); 37843 } 37844 37845 /** 37846 * Checks if `func` has a lazy counterpart. 37847 * 37848 * @private 37849 * @param {Function} func The function to check. 37850 * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`. 37851 */ 37852 function isLaziable(func) { 37853 var funcName = getFuncName(func); 37854 if (!(funcName in LazyWrapper.prototype)) { 37855 return false; 37856 } 37857 var other = lodash[funcName]; 37858 if (func === other) { 37859 return true; 37860 } 37861 var data = getData(other); 37862 return !!data && func === data[0]; 37863 } 37864 37865 /** 37866 * Checks if `value` is a valid array-like length. 37867 * 37868 * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). 37869 * 37870 * @private 37871 * @param {*} value The value to check. 37872 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. 37873 */ 37874 function isLength(value) { 37875 return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; 37876 } 37877 37878 /** 37879 * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. 37880 * 37881 * @private 37882 * @param {*} value The value to check. 37883 * @returns {boolean} Returns `true` if `value` if suitable for strict 37884 * equality comparisons, else `false`. 37885 */ 37886 function isStrictComparable(value) { 37887 return value === value && !isObject(value); 37888 } 37889 37890 /** 37891 * Merges the function metadata of `source` into `data`. 37892 * 37893 * Merging metadata reduces the number of wrappers required to invoke a function. 37894 * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` 37895 * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` 37896 * augment function arguments, making the order in which they are executed important, 37897 * preventing the merging of metadata. However, we make an exception for a safe 37898 * common case where curried functions have `_.ary` and or `_.rearg` applied. 37899 * 37900 * @private 37901 * @param {Array} data The destination metadata. 37902 * @param {Array} source The source metadata. 37903 * @returns {Array} Returns `data`. 37904 */ 37905 function mergeData(data, source) { 37906 var bitmask = data[1], 37907 srcBitmask = source[1], 37908 newBitmask = bitmask | srcBitmask, 37909 isCommon = newBitmask < ARY_FLAG; 37910 37911 var isCombo = 37912 (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) || 37913 (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) || 37914 (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG); 37915 37916 // Exit early if metadata can't be merged. 37917 if (!(isCommon || isCombo)) { 37918 return data; 37919 } 37920 // Use source `thisArg` if available. 37921 if (srcBitmask & BIND_FLAG) { 37922 data[2] = source[2]; 37923 // Set when currying a bound function. 37924 newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG; 37925 } 37926 // Compose partial arguments. 37927 var value = source[3]; 37928 if (value) { 37929 var partials = data[3]; 37930 data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); 37931 data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); 37932 } 37933 // Compose partial right arguments. 37934 value = source[5]; 37935 if (value) { 37936 partials = data[5]; 37937 data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); 37938 data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); 37939 } 37940 // Use source `argPos` if available. 37941 value = source[7]; 37942 if (value) { 37943 data[7] = arrayCopy(value); 37944 } 37945 // Use source `ary` if it's smaller. 37946 if (srcBitmask & ARY_FLAG) { 37947 data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); 37948 } 37949 // Use source `arity` if one is not provided. 37950 if (data[9] == null) { 37951 data[9] = source[9]; 37952 } 37953 // Use source `func` and merge bitmasks. 37954 data[0] = source[0]; 37955 data[1] = newBitmask; 37956 37957 return data; 37958 } 37959 37960 /** 37961 * Used by `_.defaultsDeep` to customize its `_.merge` use. 37962 * 37963 * @private 37964 * @param {*} objectValue The destination object property value. 37965 * @param {*} sourceValue The source object property value. 37966 * @returns {*} Returns the value to assign to the destination object. 37967 */ 37968 function mergeDefaults(objectValue, sourceValue) { 37969 return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults); 37970 } 37971 37972 /** 37973 * A specialized version of `_.pick` which picks `object` properties specified 37974 * by `props`. 37975 * 37976 * @private 37977 * @param {Object} object The source object. 37978 * @param {string[]} props The property names to pick. 37979 * @returns {Object} Returns the new object. 37980 */ 37981 function pickByArray(object, props) { 37982 object = toObject(object); 37983 37984 var index = -1, 37985 length = props.length, 37986 result = {}; 37987 37988 while (++index < length) { 37989 var key = props[index]; 37990 if (key in object) { 37991 result[key] = object[key]; 37992 } 37993 } 37994 return result; 37995 } 37996 37997 /** 37998 * A specialized version of `_.pick` which picks `object` properties `predicate` 37999 * returns truthy for. 38000 * 38001 * @private 38002 * @param {Object} object The source object. 38003 * @param {Function} predicate The function invoked per iteration. 38004 * @returns {Object} Returns the new object. 38005 */ 38006 function pickByCallback(object, predicate) { 38007 var result = {}; 38008 baseForIn(object, function(value, key, object) { 38009 if (predicate(value, key, object)) { 38010 result[key] = value; 38011 } 38012 }); 38013 return result; 38014 } 38015 38016 /** 38017 * Reorder `array` according to the specified indexes where the element at 38018 * the first index is assigned as the first element, the element at 38019 * the second index is assigned as the second element, and so on. 38020 * 38021 * @private 38022 * @param {Array} array The array to reorder. 38023 * @param {Array} indexes The arranged array indexes. 38024 * @returns {Array} Returns `array`. 38025 */ 38026 function reorder(array, indexes) { 38027 var arrLength = array.length,
38028 length = nativeMin(indexes.length, arrLength), 38029 oldArray = arrayCopy(array); 38030 38031 while (length--) { 38032 var index = indexes[length]; 38033 array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; 38034 } 38035 return array; 38036 } 38037 38038 /** 38039 * Sets metadata for `func`. 38040 * 38041 * **Note:** If this function becomes hot, i.e. is invoked a lot in a short 38042 * period of time, it will trip its breaker and transition to an identity function 38043 * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) 38044 * for more details. 38045 * 38046 * @private 38047 * @param {Function} func The function to associate metadata with. 38048 * @param {*} data The metadata. 38049 * @returns {Function} Returns `func`. 38050 */ 38051 var setData = (function() { 38052 var count = 0, 38053 lastCalled = 0; 38054 38055 return function(key, value) { 38056 var stamp = now(), 38057 remaining = HOT_SPAN - (stamp - lastCalled); 38058 38059 lastCalled = stamp; 38060 if (remaining > 0) { 38061 if (++count >= HOT_COUNT) { 38062 return key; 38063 } 38064 } else { 38065 count = 0; 38066 } 38067 return baseSetData(key, value); 38068 }; 38069 }()); 38070 38071 /** 38072 * A fallback implementation of `Object.keys` which creates an array of the 38073 * own enumerable property names of `object`. 38074 * 38075 * @private 38076 * @param {Object} object The object to query. 38077 * @returns {Array} Returns the array of property names. 38078 */ 38079 function shimKeys(object) { 38080 var props = keysIn(object), 38081 propsLength = props.length, 38082 length = propsLength && object.length; 38083 38084 var allowIndexes = !!length && isLength(length) && 38085 (isArray(object) || isArguments(object)); 38086 38087 var index = -1, 38088 result = []; 38089 38090 while (++index < propsLength) { 38091 var key = props[index]; 38092 if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { 38093 result.push(key); 38094 } 38095 } 38096 return result; 38097 } 38098 38099 /** 38100 * Converts `value` to an array-like object if it's not one. 38101 * 38102 * @private 38103 * @param {*} value The value to process. 38104 * @returns {Array|Object} Returns the array-like object. 38105 */ 38106 function toIterable(value) { 38107 if (value == null) { 38108 return []; 38109 } 38110 if (!isArrayLike(value)) { 38111 return values(value); 38112 } 38113 return isObject(value) ? value : Object(value); 38114 } 38115 38116 /** 38117 * Converts `value` to an object if it's not one. 38118 * 38119 * @private 38120 * @param {*} value The value to process. 38121 * @returns {Object} Returns the object. 38122 */ 38123 function toObject(value) { 38124 return isObject(value) ? value : Object(value); 38125 } 38126 38127 /** 38128 * Converts `value` to property path array if it's not one. 38129 * 38130 * @private 38131 * @param {*} value The value to process. 38132 * @returns {Array} Returns the property path array. 38133 */ 38134 function toPath(value) { 38135 if (isArray(value)) { 38136 return value; 38137 } 38138 var result = []; 38139 baseToString(value).replace(rePropName, function(match, number, quote, string) { 38140 result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); 38141 }); 38142 return result; 38143 } 38144 38145 /** 38146 * Creates a clone of `wrapper`. 38147 * 38148 * @private 38149 * @param {Object} wrapper The wrapper to clone. 38150 * @returns {Object} Returns the cloned wrapper. 38151 */ 38152 function wrapperClone(wrapper) { 38153 return wrapper instanceof LazyWrapper 38154 ? wrapper.clone() 38155 : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__)); 38156 } 38157 38158 /*------------------------------------------------------------------------*/ 38159 38160 /** 38161 * Creates an array of elements split into groups the length of `size`. 38162 * If `collection` can't be split evenly, the final chunk will be the remaining 38163 * elements. 38164 * 38165 * @static 38166 * @memberOf _ 38167 * @category Array 38168 * @param {Array} array The array to process. 38169 * @param {number} [size=1] The length of each chunk. 38170 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 38171 * @returns {Array} Returns the new array containing chunks. 38172 * @example 38173 * 38174 * _.chunk(['a', 'b', 'c', 'd'], 2); 38175 * // => [['a', 'b'], ['c', 'd']] 38176 * 38177 * _.chunk(['a', 'b', 'c', 'd'], 3); 38178 * // => [['a', 'b', 'c'], ['d']] 38179 */ 38180 function chunk(array, size, guard) { 38181 if (guard ? isIterateeCall(array, size, guard) : size == null) { 38182 size = 1; 38183 } else { 38184 size = nativeMax(nativeFloor(size) || 1, 1); 38185 } 38186 var index = 0, 38187 length = array ? array.length : 0, 38188 resIndex = -1,
38189 result = Array(nativeCeil(length / size)); 38190 38191 while (index < length) { 38192 result[++resIndex] = baseSlice(array, index, (index += size)); 38193 } 38194 return result; 38195 } 38196 38197 /** 38198 * Creates an array with all falsey values removed. The values `false`, `null`, 38199 * `0`, `""`, `undefined`, and `NaN` are falsey. 38200 * 38201 * @static 38202 * @memberOf _ 38203 * @category Array 38204 * @param {Array} array The array to compact. 38205 * @returns {Array} Returns the new array of filtered values. 38206 * @example 38207 * 38208 * _.compact([0, 1, false, 2, '', 3]); 38209 * // => [1, 2, 3] 38210 */ 38211 function compact(array) { 38212 var index = -1, 38213 length = array ? array.length : 0, 38214 resIndex = -1, 38215 result = []; 38216 38217 while (++index < length) { 38218 var value = array[index]; 38219 if (value) { 38220 result[++resIndex] = value; 38221 } 38222 } 38223 return result; 38224 } 38225 38226 /** 38227 * Creates an array of unique `array` values not included in the other 38228 * provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 38229 * for equality comparisons. 38230 * 38231 * @static 38232 * @memberOf _ 38233 * @category Array 38234 * @param {Array} array The array to inspect. 38235 * @param {...Array} [values] The arrays of values to exclude. 38236 * @returns {Array} Returns the new array of filtered values. 38237 * @example 38238 * 38239 * _.difference([1, 2, 3], [4, 2]); 38240 * // => [1, 3] 38241 */ 38242 var difference = restParam(function(array, values) { 38243 return (isObjectLike(array) && isArrayLike(array)) 38244 ? baseDifference(array, baseFlatten(values, false, true)) 38245 : []; 38246 }); 38247 38248 /** 38249 * Creates a slice of `array` with `n` elements dropped from the beginning. 38250 * 38251 * @static 38252 * @memberOf _ 38253 * @category Array 38254 * @param {Array} array The array to query. 38255 * @param {number} [n=1] The number of elements to drop. 38256 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 38257 * @returns {Array} Returns the slice of `array`. 38258 * @example 38259 * 38260 * _.drop([1, 2, 3]); 38261 * // => [2, 3] 38262 * 38263 * _.drop([1, 2, 3], 2); 38264 * // => [3] 38265 * 38266 * _.drop([1, 2, 3], 5); 38267 * // => [] 38268 * 38269 * _.drop([1, 2, 3], 0); 38270 * // => [1, 2, 3] 38271 */ 38272 function drop(array, n, guard) { 38273 var length = array ? array.length : 0; 38274 if (!length) { 38275 return []; 38276 } 38277 if (guard ? isIterateeCall(array, n, guard) : n == null) { 38278 n = 1; 38279 } 38280 return baseSlice(array, n < 0 ? 0 : n); 38281 } 38282 38283 /** 38284 * Creates a slice of `array` with `n` elements dropped from the end. 38285 * 38286 * @static 38287 * @memberOf _ 38288 * @category Array 38289 * @param {Array} array The array to query. 38290 * @param {number} [n=1] The number of elements to drop. 38291 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 38292 * @returns {Array} Returns the slice of `array`. 38293 * @example 38294 * 38295 * _.dropRight([1, 2, 3]); 38296 * // => [1, 2] 38297 * 38298 * _.dropRight([1, 2, 3], 2); 38299 * // => [1] 38300 * 38301 * _.dropRight([1, 2, 3], 5); 38302 * // => [] 38303 * 38304 * _.dropRight([1, 2, 3], 0); 38305 * // => [1, 2, 3] 38306 */ 38307 function dropRight(array, n, guard) { 38308 var length = array ? array.length : 0; 38309 if (!length) { 38310 return []; 38311 } 38312 if (guard ? isIterateeCall(array, n, guard) : n == null) { 38313 n = 1; 38314 } 38315 n = length - (+n || 0); 38316 return baseSlice(array, 0, n < 0 ? 0 : n); 38317 } 38318 38319 /** 38320 * Creates a slice of `array` excluding elements dropped from the end. 38321 * Elements are dropped until `predicate` returns falsey. The predicate is 38322 * bound to `thisArg` and invoked with three arguments: (value, index, array). 38323 * 38324 * If a property name is provided for `predicate` the created `_.property` 38325 * style callback returns the property value of the given element. 38326 * 38327 * If a value is also provided for `thisArg` the created `_.matchesProperty` 38328 * style callback returns `true` for elements that have a matching property 38329 * value, else `false`. 38330 * 38331 * If an object is provided for `predicate` the created `_.matches` style 38332 * callback returns `true` for elements that match the properties of the given 38333 * object, else `false`. 38334 * 38335 * @static 38336 * @memberOf _ 38337 * @category Array 38338 * @param {Array} array The array to query. 38339 * @param {Function|Object|string} [predicate=_.identity] The function invoked 38340 * per iteration. 38341 * @param {*} [thisArg] The `this` binding of `predicate`. 38342 * @returns {Array} Returns the slice of `array`. 38343 * @example 38344 * 38345 * _.dropRightWhile([1, 2, 3], function(n) { 38346 * return n > 1; 38347 * }); 38348 * // => [1] 38349 * 38350 * var users = [ 38351 * { 'user': 'barney', 'active': true }, 38352 * { 'user': 'fred', 'active': false }, 38353 * { 'user': 'pebbles', 'active': false } 38354 * ]; 38355 * 38356 * // using the `_.matches` callback shorthand 38357 * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); 38358 * // => ['barney', 'fred'] 38359 *
38360 * // using the `_.matchesProperty` callback shorthand 38361 * _.pluck(_.dropRightWhile(users, 'active', false), 'user'); 38362 * // => ['barney'] 38363 * 38364 * // using the `_.property` callback shorthand 38365 * _.pluck(_.dropRightWhile(users, 'active'), 'user'); 38366 * // => ['barney', 'fred', 'pebbles'] 38367 */ 38368 function dropRightWhile(array, predicate, thisArg) { 38369 return (array && array.length) 38370 ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true) 38371 : []; 38372 } 38373 38374 /** 38375 * Creates a slice of `array` excluding elements dropped from the beginning. 38376 * Elements are dropped until `predicate` returns falsey. The predicate is 38377 * bound to `thisArg` and invoked with three arguments: (value, index, array). 38378 * 38379 * If a property name is provided for `predicate` the created `_.property` 38380 * style callback returns the property value of the given element. 38381 * 38382 * If a value is also provided for `thisArg` the created `_.matchesProperty` 38383 * style callback returns `true` for elements that have a matching property 38384 * value, else `false`. 38385 * 38386 * If an object is provided for `predicate` the created `_.matches` style 38387 * callback returns `true` for elements that have the properties of the given 38388 * object, else `false`. 38389 * 38390 * @static 38391 * @memberOf _ 38392 * @category Array 38393 * @param {Array} array The array to query. 38394 * @param {Function|Object|string} [predicate=_.identity] The function invoked 38395 * per iteration. 38396 * @param {*} [thisArg] The `this` binding of `predicate`. 38397 * @returns {Array} Returns the slice of `array`. 38398 * @example 38399 * 38400 * _.dropWhile([1, 2, 3], function(n) { 38401 * return n < 3; 38402 * }); 38403 * // => [3] 38404 * 38405 * var users = [ 38406 * { 'user': 'barney', 'active': false }, 38407 * { 'user': 'fred', 'active': false }, 38408 * { 'user': 'pebbles', 'active': true } 38409 * ]; 38410 * 38411 * // using the `_.matches` callback shorthand 38412 * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); 38413 * // => ['fred', 'pebbles'] 38414 * 38415 * // using the `_.matchesProperty` callback shorthand 38416 * _.pluck(_.dropWhile(users, 'active', false), 'user'); 38417 * // => ['pebbles'] 38418 * 38419 * // using the `_.property` callback shorthand 38420 * _.pluck(_.dropWhile(users, 'active'), 'user'); 38421 * // => ['barney', 'fred', 'pebbles'] 38422 */ 38423 function dropWhile(array, predicate, thisArg) { 38424 return (array && array.length) 38425 ? baseWhile(array, getCallback(predicate, thisArg, 3), true) 38426 : []; 38427 } 38428 38429 /** 38430 * Fills elements of `array` with `value` from `start` up to, but not 38431 * including, `end`. 38432 * 38433 * **Note:** This method mutates `array`. 38434 * 38435 * @static 38436 * @memberOf _ 38437 * @category Array 38438 * @param {Array} array The array to fill. 38439 * @param {*} value The value to fill `array` with. 38440 * @param {number} [start=0] The start position. 38441 * @param {number} [end=array.length] The end position. 38442 * @returns {Array} Returns `array`. 38443 * @example 38444 * 38445 * var array = [1, 2, 3]; 38446 * 38447 * _.fill(array, 'a'); 38448 * console.log(array); 38449 * // => ['a', 'a', 'a'] 38450 * 38451 * _.fill(Array(3), 2); 38452 * // => [2, 2, 2] 38453 * 38454 * _.fill([4, 6, 8], '*', 1, 2); 38455 * // => [4, '*', 8] 38456 */ 38457 function fill(array, value, start, end) { 38458 var length = array ? array.length : 0; 38459 if (!length) { 38460 return []; 38461 } 38462 if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { 38463 start = 0; 38464 end = length; 38465 } 38466 return baseFill(array, value, start, end); 38467 } 38468 38469 /** 38470 * This method is like `_.find` except that it returns the index of the first 38471 * element `predicate` returns truthy for instead of the element itself. 38472 * 38473 * If a property name is provided for `predicate` the created `_.property` 38474 * style callback returns the property value of the given element. 38475 * 38476 * If a value is also provided for `thisArg` the created `_.matchesProperty` 38477 * style callback returns `true` for elements that have a matching property 38478 * value, else `false`. 38479 * 38480 * If an object is provided for `predicate` the created `_.matches` style 38481 * callback returns `true` for elements that have the properties of the given 38482 * object, else `false`. 38483 * 38484 * @static 38485 * @memberOf _ 38486 * @category Array 38487 * @param {Array} array The array to search. 38488 * @param {Function|Object|string} [predicate=_.identity] The function invoked 38489 * per iteration. 38490 * @param {*} [thisArg] The `this` binding of `predicate`. 38491 * @returns {number} Returns the index of the found element, else `-1`. 38492 * @example 38493 * 38494 * var users = [ 38495 * { 'user': 'barney', 'active': false }, 38496 * { 'user': 'fred', 'active': false }, 38497 * { 'user': 'pebbles', 'active': true } 38498 * ]; 38499 * 38500 * _.findIndex(users, function(chr) { 38501 * return chr.user == 'barney'; 38502 * }); 38503 * // => 0 38504 * 38505 * // using the `_.matches` callback shorthand 38506 * _.findIndex(users, { 'user': 'fred', 'active': false }); 38507 * // => 1 38508 *
38509 * // using the `_.matchesProperty` callback shorthand 38510 * _.findIndex(users, 'active', false); 38511 * // => 0 38512 * 38513 * // using the `_.property` callback shorthand 38514 * _.findIndex(users, 'active'); 38515 * // => 2 38516 */ 38517 var findIndex = createFindIndex(); 38518 38519 /** 38520 * This method is like `_.findIndex` except that it iterates over elements 38521 * of `collection` from right to left. 38522 * 38523 * If a property name is provided for `predicate` the created `_.property` 38524 * style callback returns the property value of the given element. 38525 * 38526 * If a value is also provided for `thisArg` the created `_.matchesProperty` 38527 * style callback returns `true` for elements that have a matching property 38528 * value, else `false`. 38529 * 38530 * If an object is provided for `predicate` the created `_.matches` style 38531 * callback returns `true` for elements that have the properties of the given 38532 * object, else `false`. 38533 * 38534 * @static 38535 * @memberOf _ 38536 * @category Array 38537 * @param {Array} array The array to search. 38538 * @param {Function|Object|string} [predicate=_.identity] The function invoked 38539 * per iteration. 38540 * @param {*} [thisArg] The `this` binding of `predicate`. 38541 * @returns {number} Returns the index of the found element, else `-1`. 38542 * @example 38543 * 38544 * var users = [ 38545 * { 'user': 'barney', 'active': true }, 38546 * { 'user': 'fred', 'active': false }, 38547 * { 'user': 'pebbles', 'active': false } 38548 * ]; 38549 * 38550 * _.findLastIndex(users, function(chr) { 38551 * return chr.user == 'pebbles'; 38552 * }); 38553 * // => 2 38554 * 38555 * // using the `_.matches` callback shorthand 38556 * _.findLastIndex(users, { 'user': 'barney', 'active': true }); 38557 * // => 0 38558 * 38559 * // using the `_.matchesProperty` callback shorthand 38560 * _.findLastIndex(users, 'active', false); 38561 * // => 2 38562 * 38563 * // using the `_.property` callback shorthand 38564 * _.findLastIndex(users, 'active'); 38565 * // => 0 38566 */ 38567 var findLastIndex = createFindIndex(true); 38568 38569 /** 38570 * Gets the first element of `array`. 38571 * 38572 * @static 38573 * @memberOf _ 38574 * @alias head 38575 * @category Array 38576 * @param {Array} array The array to query. 38577 * @returns {*} Returns the first element of `array`. 38578 * @example 38579 * 38580 * _.first([1, 2, 3]); 38581 * // => 1 38582 * 38583 * _.first([]); 38584 * // => undefined 38585 */ 38586 function first(array) { 38587 return array ? array[0] : undefined; 38588 } 38589 38590 /** 38591 * Flattens a nested array. If `isDeep` is `true` the array is recursively 38592 * flattened, otherwise it is only flattened a single level. 38593 * 38594 * @static 38595 * @memberOf _ 38596 * @category Array 38597 * @param {Array} array The array to flatten. 38598 * @param {boolean} [isDeep] Specify a deep flatten. 38599 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 38600 * @returns {Array} Returns the new flattened array. 38601 * @example 38602 * 38603 * _.flatten([1, [2, 3, [4]]]); 38604 * // => [1, 2, 3, [4]] 38605 * 38606 * // using `isDeep` 38607 * _.flatten([1, [2, 3, [4]]], true); 38608 * // => [1, 2, 3, 4] 38609 */ 38610 function flatten(array, isDeep, guard) { 38611 var length = array ? array.length : 0; 38612 if (guard && isIterateeCall(array, isDeep, guard)) { 38613 isDeep = false; 38614 } 38615 return length ? baseFlatten(array, isDeep) : []; 38616 } 38617 38618 /** 38619 * Recursively flattens a nested array. 38620 * 38621 * @static 38622 * @memberOf _ 38623 * @category Array 38624 * @param {Array} array The array to recursively flatten. 38625 * @returns {Array} Returns the new flattened array. 38626 * @example 38627 * 38628 * _.flattenDeep([1, [2, 3, [4]]]); 38629 * // => [1, 2, 3, 4] 38630 */ 38631 function flattenDeep(array) { 38632 var length = array ? array.length : 0; 38633 return length ? baseFlatten(array, true) : []; 38634 } 38635 38636 /** 38637 * Gets the index at which the first occurrence of `value` is found in `array` 38638 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 38639 * for equality comparisons. If `fromIndex` is negative, it is used as the offset 38640 * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` 38641 * performs a faster binary search. 38642 * 38643 * @static 38644 * @memberOf _ 38645 * @category Array 38646 * @param {Array} array The array to search. 38647 * @param {*} value The value to search for. 38648 * @param {boolean|number} [fromIndex=0] The index to search from or `true` 38649 * to perform a binary search on a sorted array.
38650 * @returns {number} Returns the index of the matched value, else `-1`. 38651 * @example 38652 * 38653 * _.indexOf([1, 2, 1, 2], 2); 38654 * // => 1 38655 * 38656 * // using `fromIndex` 38657 * _.indexOf([1, 2, 1, 2], 2, 2); 38658 * // => 3 38659 * 38660 * // performing a binary search 38661 * _.indexOf([1, 1, 2, 2], 2, true); 38662 * // => 2 38663 */ 38664 function indexOf(array, value, fromIndex) { 38665 var length = array ? array.length : 0; 38666 if (!length) { 38667 return -1; 38668 } 38669 if (typeof fromIndex == 'number') { 38670 fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; 38671 } else if (fromIndex) { 38672 var index = binaryIndex(array, value); 38673 if (index < length && 38674 (value === value ? (value === array[index]) : (array[index] !== array[index]))) { 38675 return index; 38676 } 38677 return -1; 38678 } 38679 return baseIndexOf(array, value, fromIndex || 0); 38680 } 38681 38682 /** 38683 * Gets all but the last element of `array`. 38684 * 38685 * @static 38686 * @memberOf _ 38687 * @category Array 38688 * @param {Array} array The array to query. 38689 * @returns {Array} Returns the slice of `array`. 38690 * @example 38691 * 38692 * _.initial([1, 2, 3]); 38693 * // => [1, 2] 38694 */ 38695 function initial(array) { 38696 return dropRight(array, 1); 38697 } 38698 38699 /** 38700 * Creates an array of unique values that are included in all of the provided 38701 * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 38702 * for equality comparisons. 38703 * 38704 * @static 38705 * @memberOf _ 38706 * @category Array 38707 * @param {...Array} [arrays] The arrays to inspect. 38708 * @returns {Array} Returns the new array of shared values. 38709 * @example 38710 * _.intersection([1, 2], [4, 2], [2, 1]); 38711 * // => [2] 38712 */ 38713 var intersection = restParam(function(arrays) { 38714 var othLength = arrays.length, 38715 othIndex = othLength, 38716 caches = Array(length), 38717 indexOf = getIndexOf(), 38718 isCommon = indexOf == baseIndexOf, 38719 result = []; 38720 38721 while (othIndex--) { 38722 var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : []; 38723 caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null; 38724 } 38725 var array = arrays[0], 38726 index = -1, 38727 length = array ? array.length : 0, 38728 seen = caches[0]; 38729 38730 outer: 38731 while (++index < length) { 38732 value = array[index]; 38733 if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) { 38734 var othIndex = othLength; 38735 while (--othIndex) { 38736 var cache = caches[othIndex]; 38737 if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) { 38738 continue outer; 38739 } 38740 } 38741 if (seen) { 38742 seen.push(value); 38743 } 38744 result.push(value); 38745 } 38746 } 38747 return result; 38748 }); 38749 38750 /** 38751 * Gets the last element of `array`. 38752 * 38753 * @static 38754 * @memberOf _ 38755 * @category Array 38756 * @param {Array} array The array to query. 38757 * @returns {*} Returns the last element of `array`. 38758 * @example 38759 * 38760 * _.last([1, 2, 3]); 38761 * // => 3 38762 */ 38763 function last(array) { 38764 var length = array ? array.length : 0; 38765 return length ? array[length - 1] : undefined; 38766 } 38767 38768 /** 38769 * This method is like `_.indexOf` except that it iterates over elements of 38770 * `array` from right to left. 38771 * 38772 * @static 38773 * @memberOf _ 38774 * @category Array 38775 * @param {Array} array The array to search. 38776 * @param {*} value The value to search for. 38777 * @param {boolean|number} [fromIndex=array.length-1] The index to search from 38778 * or `true` to perform a binary search on a sorted array. 38779 * @returns {number} Returns the index of the matched value, else `-1`. 38780 * @example 38781 * 38782 * _.lastIndexOf([1, 2, 1, 2], 2); 38783 * // => 3 38784 * 38785 * // using `fromIndex` 38786 * _.lastIndexOf([1, 2, 1, 2], 2, 2); 38787 * // => 1 38788 * 38789 * // performing a binary search 38790 * _.lastIndexOf([1, 1, 2, 2], 2, true); 38791 * // => 3 38792 */ 38793 function lastIndexOf(array, value, fromIndex) { 38794 var length = array ? array.length : 0; 38795 if (!length) { 38796 return -1; 38797 } 38798 var index = length; 38799 if (typeof fromIndex == 'number') { 38800 index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; 38801 } else if (fromIndex) { 38802 index = binaryIndex(array, value, true) - 1; 38803 var other = array[index]; 38804 if (value === value ? (value === other) : (other !== other)) { 38805 return index; 38806 } 38807 return -1; 38808 } 38809 if (value !== value) { 38810 return indexOfNaN(array, index, true); 38811 } 38812 while (index--) { 38813 if (array[index] === value) { 38814 return index; 38815 } 38816 } 38817 return -1; 38818 } 38819 38820 /** 38821 * Removes all provided values from `array` using 38822 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 38823 * for equality comparisons. 38824 * 38825 * **Note:** Unlike `_.without`, this method mutates `array`. 38826 * 38827 * @static 38828 * @memberOf _ 38829 * @category Array 38830 * @param {Array} array The array to modify. 38831 * @param {...*} [values] The values to remove. 38832 * @returns {Array} Returns `array`. 38833 * @example 38834 * 38835 * var array = [1, 2, 3, 1, 2, 3]; 38836 * 38837 * _.pull(array, 2, 3); 38838 * console.log(array); 38839 * // => [1, 1] 38840 */ 38841 function pull() { 38842 var args = arguments, 38843 array = args[0]; 38844 38845 if (!(array && array.length)) { 38846 return array; 38847 } 38848 var index = 0, 38849 indexOf = getIndexOf(), 38850 length = args.length; 38851 38852 while (++index < length) { 38853 var fromIndex = 0, 38854 value = args[index]; 38855 38856 while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { 38857 splice.call(array, fromIndex, 1); 38858 } 38859 } 38860 return array; 38861 } 38862 38863 /** 38864 * Removes elements from `array` corresponding to the given indexes and returns 38865 * an array of the removed elements. Indexes may be specified as an array of 38866 * indexes or as individual arguments. 38867 * 38868 * **Note:** Unlike `_.at`, this method mutates `array`. 38869 * 38870 * @static 38871 * @memberOf _ 38872 * @category Array 38873 * @param {Array} array The array to modify. 38874 * @param {...(number|number[])} [indexes] The indexes of elements to remove, 38875 * specified as individual indexes or arrays of indexes. 38876 * @returns {Array} Returns the new array of removed elements. 38877 * @example 38878 * 38879 * var array = [5, 10, 15, 20]; 38880 * var evens = _.pullAt(array, 1, 3); 38881 * 38882 * console.log(array); 38883 * // => [5, 15] 38884 * 38885 * console.log(evens); 38886 * // => [10, 20] 38887 */ 38888 var pullAt = restParam(function(array, indexes) { 38889 indexes = baseFlatten(indexes); 38890 38891 var result = baseAt(array, indexes); 38892 basePullAt(array, indexes.sort(baseCompareAscending)); 38893 return result; 38894 }); 38895 38896 /** 38897 * Removes all elements from `array` that `predicate` returns truthy for 38898 * and returns an array of the removed elements. The predicate is bound to 38899 * `thisArg` and invoked with three arguments: (value, index, array). 38900 * 38901 * If a property name is provided for `predicate` the created `_.property` 38902 * style callback returns the property value of the given element. 38903 * 38904 * If a value is also provided for `thisArg` the created `_.matchesProperty` 38905 * style callback returns `true` for elements that have a matching property 38906 * value, else `false`. 38907 * 38908 * If an object is provided for `predicate` the created `_.matches` style 38909 * callback returns `true` for elements that have the properties of the given 38910 * object, else `false`. 38911 * 38912 * **Note:** Unlike `_.filter`, this method mutates `array`. 38913 * 38914 * @static 38915 * @memberOf _ 38916 * @category Array 38917 * @param {Array} array The array to modify. 38918 * @param {Function|Object|string} [predicate=_.identity] The function invoked 38919 * per iteration. 38920 * @param {*} [thisArg] The `this` binding of `predicate`. 38921 * @returns {Array} Returns the new array of removed elements. 38922 * @example 38923 * 38924 * var array = [1, 2, 3, 4]; 38925 * var evens = _.remove(array, function(n) { 38926 * return n % 2 == 0; 38927 * }); 38928 * 38929 * console.log(array); 38930 * // => [1, 3] 38931 * 38932 * console.log(evens); 38933 * // => [2, 4] 38934 */ 38935 function remove(array, predicate, thisArg) { 38936 var result = []; 38937 if (!(array && array.length)) { 38938 return result; 38939 } 38940 var index = -1, 38941 indexes = [], 38942 length = array.length; 38943 38944 predicate = getCallback(predicate, thisArg, 3); 38945 while (++index < length) { 38946 var value = array[index]; 38947 if (predicate(value, index, array)) { 38948 result.push(value); 38949 indexes.push(index); 38950 } 38951 } 38952 basePullAt(array, indexes); 38953 return result; 38954 } 38955 38956 /** 38957 * Gets all but the first element of `array`. 38958 * 38959 * @static 38960 * @memberOf _ 38961 * @alias tail 38962 * @category Array 38963 * @param {Array} array The array to query. 38964 * @returns {Array} Returns the slice of `array`. 38965 * @example 38966 * 38967 * _.rest([1, 2, 3]); 38968 * // => [2, 3] 38969 */ 38970 function rest(array) { 38971 return drop(array, 1); 38972 } 38973 38974 /** 38975 * Creates a slice of `array` from `start` up to, but not including, `end`. 38976 * 38977 * **Note:** This method is used instead of `Array#slice` to supp
38977ort node 38978 * lists in IE < 9 and to ensure dense arrays are returned. 38979 * 38980 * @static 38981 * @memberOf _ 38982 * @category Array 38983 * @param {Array} array The array to slice. 38984 * @param {number} [start=0] The start position. 38985 * @param {number} [end=array.length] The end position. 38986 * @returns {Array} Returns the slice of `array`. 38987 */ 38988 function slice(array, start, end) { 38989 var length = array ? array.length : 0; 38990 if (!length) { 38991 return []; 38992 } 38993 if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { 38994 start = 0; 38995 end = length; 38996 } 38997 return baseSlice(array, start, end); 38998 } 38999 39000 /** 39001 * Uses a binary search to determine the lowest index at which `value` should 39002 * be inserted into `array` in order to maintain its sort order. If an iteratee 39003 * function is provided it is invoked for `value` and each element of `array` 39004 * to compute their sort ranking. The iteratee is bound to `thisArg` and 39005 * invoked with one argument; (value). 39006 * 39007 * If a property name is provided for `iteratee` the created `_.property` 39008 * style callback returns the property value of the given element. 39009 * 39010 * If a value is also provided for `thisArg` the created `_.matchesProperty` 39011 * style callback returns `true` for elements that have a matching property 39012 * value, else `false`. 39013 * 39014 * If an object is provided for `iteratee` the created `_.matches` style 39015 * callback returns `true` for elements that have the properties of the given 39016 * object, else `false`. 39017 * 39018 * @static 39019 * @memberOf _ 39020 * @category Array 39021 * @param {Array} array The sorted array to inspect. 39022 * @param {*} value The value to evaluate. 39023 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 39024 * per iteration. 39025 * @param {*} [thisArg] The `this` binding of `iteratee`. 39026 * @returns {number} Returns the index at which `value` should be inserted 39027 * into `array`. 39028 * @example 39029 * 39030 * _.sortedIndex([30, 50], 40); 39031 * // => 1 39032 * 39033 * _.sortedIndex([4, 4, 5, 5], 5); 39034 * // => 2 39035 * 39036 * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; 39037 * 39038 * // using an iteratee function 39039 * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { 39040 * return this.data[word]; 39041 * }, dict); 39042 * // => 1 39043 * 39044 * // using the `_.property` callback shorthand 39045 * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); 39046 * // => 1 39047 */ 39048 var sortedIndex = createSortedIndex(); 39049 39050 /** 39051 * This method is like `_.sortedIndex` except that it returns the highest 39052 * index at which `value` should be inserted into `array` in order to 39053 * maintain its sort order. 39054 * 39055 * @static 39056 * @memberOf _ 39057 * @category Array 39058 * @param {Array} array The sorted array to inspect. 39059 * @param {*} value The value to evaluate. 39060 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 39061 * per iteration. 39062 * @param {*} [thisArg] The `this` binding of `iteratee`. 39063 * @returns {number} Returns the index at which `value` should be inserted 39064 * into `array`. 39065 * @example 39066 * 39067 * _.sortedLastIndex([4, 4, 5, 5], 5); 39068 * // => 4 39069 */ 39070 var sortedLastIndex = createSortedIndex(true); 39071 39072 /** 39073 * Creates a slice of `array` with `n` elements taken from the beginning. 39074 * 39075 * @static 39076 * @memberOf _ 39077 * @category Array 39078 * @param {Array} array The array to query. 39079 * @param {number} [n=1] The number of elements to take. 39080 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 39081 * @returns {Array} Returns the slice of `array`. 39082 * @example 39083 * 39084 * _.take([1, 2, 3]); 39085 * // => [1] 39086 * 39087 * _.take([1, 2, 3], 2); 39088 * // => [1, 2] 39089 * 39090 * _.take([1, 2, 3], 5); 39091 * // => [1, 2, 3] 39092 * 39093 * _.take([1, 2, 3], 0); 39094 * // => [] 39095 */ 39096 function take(array, n, guard) { 39097 var length = array ? array.length : 0; 39098 if (!length) { 39099 return []; 39100 } 39101 if (guard ? isIterateeCall(array, n, guard) : n == null) { 39102 n = 1; 39103 } 39104 return baseSlice(array, 0, n < 0 ? 0 : n); 39105 } 39106 39107 /** 39108 * Creates a slice of `array` with `n` elements taken from the end. 39109 * 39110 * @static 39111 * @memberOf _ 39112 * @category Array 39113 * @param {Array} array The array to query. 39114 * @param {number} [n=1] The number of elements to take. 39115 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 39116 * @returns {Array} Returns the slice of `array`. 39117 * @example 39118 * 39119 * _.takeRight([1, 2, 3]); 39120 * // => [3] 39121 * 39122 * _.takeRight([1, 2, 3], 2); 39123 * // => [2, 3] 39124 * 39125 * _.takeRight([1, 2, 3], 5); 39126 * // => [1, 2, 3] 39127 * 39128 * _.takeRight([1, 2, 3], 0); 39129 * // => [] 39130 */ 39131 function takeRight(array, n, guard) { 39132 var length = array ? array.length : 0; 39133 if (!length) { 39134 return []; 39135 } 39136 if (guard ? isIterateeCall(array, n, guard) : n == null) { 39137 n = 1; 39138 } 39139 n = length - (+n || 0); 39140 return baseSlice(array, n < 0 ? 0 : n); 39141 } 39142 39143 /** 39144 * Creates a slice of `array` with elements taken from the end. Elements are 39145 * taken until `predicate` returns falsey. The predicate is bound to `thisArg` 39146 * and invoked with three arguments: (value, index, array). 39147 * 39148 * If a property name is provided for `predicate` the created `_.property` 39149 * style callback returns the property value of the given element. 39150 * 39151 * If a value is also provided for `thisArg` the created `_.matchesProperty` 39152 * style callback returns `true` for elements that have a matching property 39153 * value, else `false`. 39154 * 39155 * If an object is provided for `predicate` the created `_.matches` style 39156 * callback returns `true` for elements that have the properties of the given 39157 * object, else `false`. 39158 * 39159 * @static 39160 * @memberOf _ 39161 * @category Array 39162 * @param {Array} array The array to query. 39163 * @param {Function|Object|string} [predicate=_.identity] The function invoked 39164 * per iteration. 39165 * @param {*} [thisArg] The `this` binding of `predicate`. 39166 * @returns {Array} Returns the slice of `array`. 39167 * @example 39168 * 39169 * _.takeRightWhile([1, 2, 3], function(n) { 39170 * return n > 1; 39171 * }); 39172 * // => [2, 3] 39173 * 39174 * var users = [ 39175 * { 'user': 'barney', 'active': true }, 39176 * { 'user': 'fred', 'active': false }, 39177 * { 'user': 'pebbles', 'active': false } 39178 * ]; 39179 * 39180 * // using the `_.matches` callback shorthand 39181 * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); 39182 * // => ['pebbles'] 39183 *
39184 * // using the `_.matchesProperty` callback shorthand 39185 * _.pluck(_.takeRightWhile(users, 'active', false), 'user'); 39186 * // => ['fred', 'pebbles'] 39187 * 39188 * // using the `_.property` callback shorthand 39189 * _.pluck(_.takeRightWhile(users, 'active'), 'user'); 39190 * // => [] 39191 */ 39192 function takeRightWhile(array, predicate, thisArg) { 39193 return (array && array.length) 39194 ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true) 39195 : []; 39196 } 39197 39198 /** 39199 * Creates a slice of `array` with elements taken from the beginning. Elements 39200 * are taken until `predicate` returns falsey. The predicate is bound to 39201 * `thisArg` and invoked with three arguments: (value, index, array). 39202 * 39203 * If a property name is provided for `predicate` the created `_.property` 39204 * style callback returns the property value of the given element. 39205 * 39206 * If a value is also provided for `thisArg` the created `_.matchesProperty` 39207 * style callback returns `true` for elements that have a matching property 39208 * value, else `false`. 39209 * 39210 * If an object is provided for `predicate` the created `_.matches` style 39211 * callback returns `true` for elements that have the properties of the given 39212 * object, else `false`. 39213 * 39214 * @static 39215 * @memberOf _ 39216 * @category Array 39217 * @param {Array} array The array to query. 39218 * @param {Function|Object|string} [predicate=_.identity] The function invoked 39219 * per iteration. 39220 * @param {*} [thisArg] The `this` binding of `predicate`. 39221 * @returns {Array} Returns the slice of `array`. 39222 * @example 39223 * 39224 * _.takeWhile([1, 2, 3], function(n) { 39225 * return n < 3; 39226 * }); 39227 * // => [1, 2] 39228 * 39229 * var users = [ 39230 * { 'user': 'barney', 'active': false }, 39231 * { 'user': 'fred', 'active': false}, 39232 * { 'user': 'pebbles', 'active': true } 39233 * ]; 39234 * 39235 * // using the `_.matches` callback shorthand 39236 * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); 39237 * // => ['barney'] 39238 * 39239 * // using the `_.matchesProperty` callback shorthand 39240 * _.pluck(_.takeWhile(users, 'active', false), 'user'); 39241 * // => ['barney', 'fred'] 39242 * 39243 * // using the `_.property` callback shorthand 39244 * _.pluck(_.takeWhile(users, 'active'), 'user'); 39245 * // => [] 39246 */ 39247 function takeWhile(array, predicate, thisArg) { 39248 return (array && array.length) 39249 ? baseWhile(array, getCallback(predicate, thisArg, 3)) 39250 : []; 39251 } 39252 39253 /** 39254 * Creates an array of unique values, in order, from all of the provided arrays 39255 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 39256 * for equality comparisons. 39257 * 39258 * @static 39259 * @memberOf _ 39260 * @category Array 39261 * @param {...Array} [arrays] The arrays to inspect. 39262 * @returns {Array} Returns the new array of combined values. 39263 * @example 39264 * 39265 * _.union([1, 2], [4, 2], [2, 1]); 39266 * // => [1, 2, 4] 39267 */ 39268 var union = restParam(function(arrays) { 39269 return baseUniq(baseFlatten(arrays, false, true)); 39270 }); 39271 39272 /** 39273 * Creates a duplicate-free version of an array, using 39274 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 39275 * for equality comparisons, in which only the first occurence of each element 39276 * is kept. Providing `true` for `isSorted` performs a faster search algorithm 39277 * for sorted arrays. If an iteratee function is provided it is invoked for 39278 * each element in the array to generate the criterion by which uniqueness 39279 * is computed. The `iteratee` is bound to `thisArg` and invoked with three 39280 * arguments: (value, index, array). 39281 * 39282 * If a property name is provided for `iteratee` the created `_.property` 39283 * style callback returns the property value of the given element. 39284 * 39285 * If a value is also provided for `thisArg` the created `_.matchesProperty` 39286 * style callback returns `true` for elements that have a matching property 39287 * value, else `false`. 39288 * 39289 * If an object is provided for `iteratee` the created `_.matches` style 39290 * callback returns `true` for elements that have the properties of the given 39291 * object, else `false`. 39292 * 39293 * @static 39294 * @memberOf _ 39295 * @alias unique 39296 * @category Array 39297 * @param {Array} array The array to inspect. 39298 * @param {boolean} [isSorted] Specify the array is sorted. 39299 * @param {Function|Object|string} [iteratee] The function invoked per iteration. 39300 * @param {*} [thisArg] The `this` binding of `iteratee`. 39301 * @returns {Array} Returns the new duplicate-value-free array. 39302 * @example 39303 * 39304 * _.uniq([2, 1, 2]); 39305 * // => [2, 1] 39306 * 39307 * // using `isSorted` 39308 * _.uniq([1, 1, 2], true); 39309 * // => [1, 2] 39310 * 39311 * // using an iteratee function 39312 * _.uniq([1, 2.5, 1.5, 2], function(n) { 39313 * return this.floor(n); 39314 * }, Math); 39315 * // => [1, 2.5] 39316 *
39317 * // using the `_.property` callback shorthand 39318 * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); 39319 * // => [{ 'x': 1 }, { 'x': 2 }] 39320 */ 39321 function uniq(array, isSorted, iteratee, thisArg) { 39322 var length = array ? array.length : 0; 39323 if (!length) { 39324 return []; 39325 } 39326 if (isSorted != null && typeof isSorted != 'boolean') { 39327 thisArg = iteratee; 39328 iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted; 39329 isSorted = false; 39330 } 39331 var callback = getCallback(); 39332 if (!(iteratee == null && callback === baseCallback)) { 39333 iteratee = callback(iteratee, thisArg, 3); 39334 } 39335 return (isSorted && getIndexOf() == baseIndexOf) 39336 ? sortedUniq(array, iteratee) 39337 : baseUniq(array, iteratee); 39338 } 39339 39340 /** 39341 * This method is like `_.zip` except that it accepts an array of grouped 39342 * elements and creates an array regrouping the elements to their pre-zip 39343 * configuration. 39344 * 39345 * @static 39346 * @memberOf _ 39347 * @category Array 39348 * @param {Array} array The array of grouped elements to process. 39349 * @returns {Array} Returns the new array of regrouped elements. 39350 * @example 39351 * 39352 * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); 39353 * // => [['fred', 30, true], ['barney', 40, false]] 39354 * 39355 * _.unzip(zipped); 39356 * // => [['fred', 'barney'], [30, 40], [true, false]] 39357 */ 39358 function unzip(array) { 39359 if (!(array && array.length)) { 39360 return []; 39361 } 39362 var index = -1, 39363 length = 0; 39364 39365 array = arrayFilter(array, function(group) { 39366 if (isArrayLike(group)) { 39367 length = nativeMax(group.length, length); 39368 return true; 39369 } 39370 }); 39371 var result = Array(length); 39372 while (++index < length) { 39373 result[index] = arrayMap(array, baseProperty(index)); 39374 } 39375 return result; 39376 } 39377 39378 /** 39379 * This method is like `_.unzip` except that it accepts an iteratee to specify 39380 * how regrouped values should be combined. The `iteratee` is bound to `thisArg` 39381 * and invoked with four arguments: (accumulator, value, index, group). 39382 * 39383 * @static 39384 * @memberOf _ 39385 * @category Array 39386 * @param {Array} array The array of grouped elements to process. 39387 * @param {Function} [iteratee] The function to combine regrouped values. 39388 * @param {*} [thisArg] The `this` binding of `iteratee`. 39389 * @returns {Array} Returns the new array of regrouped elements. 39390 * @example 39391 * 39392 * var zipped = _.zip([1, 2], [10, 20], [100, 200]); 39393 * // => [[1, 10, 100], [2, 20, 200]] 39394 * 39395 * _.unzipWith(zipped, _.add); 39396 * // => [3, 30, 300] 39397 */ 39398 function unzipWith(array, iteratee, thisArg) { 39399 var length = array ? array.length : 0; 39400 if (!length) { 39401 return []; 39402 } 39403 var result = unzip(array); 39404 if (iteratee == null) { 39405 return result; 39406 } 39407 iteratee = bindCallback(iteratee, thisArg, 4); 39408 return arrayMap(result, function(group) { 39409 return arrayReduce(group, iteratee, undefined, true); 39410 }); 39411 } 39412 39413 /** 39414 * Creates an array excluding all provided values using 39415 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 39416 * for equality comparisons. 39417 * 39418 * @static 39419 * @memberOf _ 39420 * @category Array 39421 * @param {Array} array The array to filter. 39422 * @param {...*} [values] The values to exclude. 39423 * @returns {Array} Returns the new array of filtered values. 39424 * @example 39425 * 39426 * _.without([1, 2, 1, 3], 1, 2); 39427 * // => [3] 39428 */ 39429 var without = restParam(function(array, values) { 39430 return isArrayLike(array) 39431 ? baseDifference(array, values) 39432 : []; 39433 }); 39434 39435 /** 39436 * Creates an array of unique values that is the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) 39437 * of the provided arrays. 39438 * 39439 * @static 39440 * @memberOf _ 39441 * @category Array 39442 * @param {...Array} [arrays] The arrays to inspect. 39443 * @returns {Array} Returns the new array of values. 39444 * @example 39445 * 39446 * _.xor([1, 2], [4, 2]); 39447 * // => [1, 4] 39448 */ 39449 function xor() { 39450 var index = -1, 39451 length = arguments.length; 39452 39453 while (++index < length) { 39454 var array = arguments[index]; 39455 if (isArrayLike(array)) { 39456 var result = result 39457 ? arrayPush(baseDifference(result, array), baseDifference(array, result)) 39458 : array; 39459 } 39460 } 39461 return result ? baseUniq(result) : []; 39462 } 39463 39464 /** 39465 * Creates an array of grouped elements, the first of which contains the first 39466 * elements of the given arrays, the second of which contains the second elements 39467 * of the given arrays, and so on. 39468 * 39469 * @static 39470 * @memberOf _ 39471 * @category Array 39472 * @param {...Array} [arrays] The arrays to process. 39473 * @returns {Array} Returns the new array of grouped elements. 39474 * @example 39475 * 39476 * _.zip(['fred', 'barney'], [30, 40], [true, false]); 39477 * // => [['fred', 30, true], ['barney', 40, false]] 39478 */ 39479 var zip = restParam(unzip); 39480 39481 /** 39482 * The inverse of `_.pairs`;
39482 this method returns an object composed from arrays 39483 * of property names and values. Provide either a single two dimensional array, 39484 * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names 39485 * and one of corresponding values. 39486 * 39487 * @static 39488 * @memberOf _ 39489 * @alias object 39490 * @category Array 39491 * @param {Array} props The property names. 39492 * @param {Array} [values=[]] The property values. 39493 * @returns {Object} Returns the new object. 39494 * @example 39495 * 39496 * _.zipObject([['fred', 30], ['barney', 40]]); 39497 * // => { 'fred': 30, 'barney': 40 } 39498 * 39499 * _.zipObject(['fred', 'barney'], [30, 40]); 39500 * // => { 'fred': 30, 'barney': 40 } 39501 */ 39502 function zipObject(props, values) { 39503 var index = -1, 39504 length = props ? props.length : 0, 39505 result = {}; 39506 39507 if (length && !values && !isArray(props[0])) { 39508 values = []; 39509 } 39510 while (++index < length) { 39511 var key = props[index]; 39512 if (values) { 39513 result[key] = values[index]; 39514 } else if (key) { 39515 result[key[0]] = key[1]; 39516 } 39517 } 39518 return result; 39519 } 39520 39521 /** 39522 * This method is like `_.zip` except that it accepts an iteratee to specify 39523 * how grouped values should be combined. The `iteratee` is bound to `thisArg` 39524 * and invoked with four arguments: (accumulator, value, index, group). 39525 * 39526 * @static 39527 * @memberOf _ 39528 * @category Array 39529 * @param {...Array} [arrays] The arrays to process. 39530 * @param {Function} [iteratee] The function to combine grouped values. 39531 * @param {*} [thisArg] The `this` binding of `iteratee`. 39532 * @returns {Array} Returns the new array of grouped elements. 39533 * @example 39534 * 39535 * _.zipWith([1, 2], [10, 20], [100, 200], _.add); 39536 * // => [111, 222] 39537 */ 39538 var zipWith = restParam(function(arrays) { 39539 var length = arrays.length, 39540 iteratee = length > 2 ? arrays[length - 2] : undefined, 39541 thisArg = length > 1 ? arrays[length - 1] : undefined; 39542 39543 if (length > 2 && typeof iteratee == 'function') { 39544 length -= 2; 39545 } else { 39546 iteratee = (length > 1 && typeof thisArg == 'function') ? (--length, thisArg) : undefined; 39547 thisArg = undefined; 39548 } 39549 arrays.length = length; 39550 return unzipWith(arrays, iteratee, thisArg); 39551 }); 39552 39553 /*------------------------------------------------------------------------*/ 39554 39555 /** 39556 * Creates a `lodash` object that wraps `value` with explicit method 39557 * chaining enabled. 39558 * 39559 * @static 39560 * @memberOf _ 39561 * @category Chain 39562 * @param {*} value The value to wrap. 39563 * @returns {Object} Returns the new `lodash` wrapper instance. 39564 * @example 39565 * 39566 * var users = [ 39567 * { 'user': 'barney', 'age': 36 }, 39568 * { 'user': 'fred', 'age': 40 }, 39569 * { 'user': 'pebbles', 'age': 1 } 39570 * ]; 39571 * 39572 * var youngest = _.chain(users) 39573 * .sortBy('age') 39574 * .map(function(chr) { 39575 * return chr.user + ' is ' + chr.age; 39576 * }) 39577 * .first() 39578 * .value(); 39579 * // => 'pebbles is 1' 39580 */ 39581 function chain(value) { 39582 var result = lodash(value); 39583 result.__chain__ = true; 39584 return result; 39585 } 39586 39587 /** 39588 * This method invokes `interceptor` and returns `value`. The interceptor is 39589 * bound to `thisArg` and invoked with one argument; (value). The purpose of 39590 * this method is to "tap into" a method chain in order to perform operations 39591 * on intermediate results within the chain. 39592 * 39593 * @static 39594 * @memberOf _ 39595 * @category Chain 39596 * @param {*} value The value to provide to `interceptor`. 39597 * @param {Function} interceptor The function to invoke. 39598 * @param {*} [thisArg] The `this` binding of `interceptor`. 39599 * @returns {*} Returns `value`. 39600 * @example 39601 * 39602 * _([1, 2, 3]) 39603 * .tap(function(array) { 39604 * array.pop(); 39605 * }) 39606 * .reverse() 39607 * .value(); 39608 * // => [2, 1] 39609 */ 39610 function tap(value, interceptor, thisArg) { 39611 interceptor.call(thisArg, value); 39612 return value; 39613 } 39614 39615 /** 39616 * This method is like `_.tap` except that it returns the result of `interceptor`. 39617 * 39618 * @static 39619 * @memberOf _ 39620 * @category Chain 39621 * @param {*} value The value to provide to `interceptor`. 39622 * @param {Function} interceptor The function to invoke. 39623 * @param {*} [thisArg] The `this` binding of `interceptor`. 39624 * @returns {*} Returns the result of `interceptor`. 39625 * @example 39626 * 39627 * _(' abc ') 39628 * .chain() 39629 * .trim() 39630 * .thru(function(value) { 39631 * return [value]; 39632 * }) 39633 * .value(); 39634 * // => ['abc'] 39635 */ 39636 function thru(value, interceptor, thisArg) { 39637 return interceptor.call(thisArg, value); 39638 } 39639 39640 /** 39641 * Enables explicit method chaining on the wrapper object. 39642 * 39643 * @name chain 39644 * @memberOf _ 39645 * @category Chain 39646 * @returns {Object} Returns the new `lodash` wrapper instance. 39647 * @example 39648 * 39649 * var users = [ 39650 * { 'user': 'barney', 'age': 36 }, 39651 * { 'user': 'fred', 'age': 40 } 39652 * ]; 39653 * 39654 * // without explicit chaining 39655 * _(users).first(); 39656 * // => { 'user': 'barney', 'age': 36 } 39657 * 39658 * // with explicit chaining 39659 * _(users).chain() 39660 * .first() 39661 * .pick('user') 39662 * .value(); 39663 * // => { 'user': 'barney' } 39664 */ 39665 function wrapperChain() { 39666 return chain(this); 39667 } 39668 39669 /** 39670 * Executes the chained sequence and returns the wrapped result. 39671 * 39672 * @name commit 39673 * @memberOf _ 39674 * @category Chain 39675 * @returns {Object} Returns the new `lodash` wrapper instance. 39676 * @example 39677 * 39678 * var array = [1, 2]; 39679 * var wrapped = _(array).push(3); 39680 * 39681 * console.log(array); 39682 * // => [1, 2] 39683 * 39684 * wrapped = wrapped.commit(); 39685 * console.log(array); 39686 * // => [1, 2, 3] 39687 * 39688 * wrapped.last(); 39689 * // => 3 39690 * 39691 * console.log(array); 39692 * // => [1, 2, 3] 39693 */ 39694 function wrapperCommit() { 39695 return new LodashWrapper(this.value(), this.__chain__); 39696 } 39697 39698 /** 39699 * Creates a new array joining a wrapped array with any additional arrays 39700 * and/or values. 39701 * 39702 * @name concat 39703 * @memberOf _ 39704 * @category Chain 39705 * @param {...*} [values] The values to concatenate. 39706 * @returns {Array} Returns the new concatenated array.
39707 * @example 39708 * 39709 * var array = [1]; 39710 * var wrapped = _(array).concat(2, [3], [[4]]); 39711 * 39712 * console.log(wrapped.value()); 39713 * // => [1, 2, 3, [4]] 39714 * 39715 * console.log(array); 39716 * // => [1] 39717 */ 39718 var wrapperConcat = restParam(function(values) { 39719 values = baseFlatten(values); 39720 return this.thru(function(array) { 39721 return arrayConcat(isArray(array) ? array : [toObject(array)], values); 39722 }); 39723 }); 39724 39725 /** 39726 * Creates a clone of the chained sequence planting `value` as the wrapped value. 39727 * 39728 * @name plant 39729 * @memberOf _ 39730 * @category Chain 39731 * @returns {Object} Returns the new `lodash` wrapper instance. 39732 * @example 39733 * 39734 * var array = [1, 2]; 39735 * var wrapped = _(array).map(function(value) { 39736 * return Math.pow(value, 2); 39737 * }); 39738 * 39739 * var other = [3, 4]; 39740 * var otherWrapped = wrapped.plant(other); 39741 * 39742 * otherWrapped.value(); 39743 * // => [9, 16] 39744 * 39745 * wrapped.value(); 39746 * // => [1, 4] 39747 */ 39748 function wrapperPlant(value) { 39749 var result, 39750 parent = this; 39751 39752 while (parent instanceof baseLodash) { 39753 var clone = wrapperClone(parent); 39754 if (result) { 39755 previous.__wrapped__ = clone; 39756 } else { 39757 result = clone; 39758 } 39759 var previous = clone; 39760 parent = parent.__wrapped__; 39761 } 39762 previous.__wrapped__ = value; 39763 return result; 39764 } 39765 39766 /** 39767 * Reverses the wrapped array so the first element becomes the last, the 39768 * second element becomes the second to last, and so on. 39769 * 39770 * **Note:** This method mutates the wrapped array. 39771 * 39772 * @name reverse 39773 * @memberOf _ 39774 * @category Chain 39775 * @returns {Object} Returns the new reversed `lodash` wrapper instance. 39776 * @example 39777 * 39778 * var array = [1, 2, 3]; 39779 * 39780 * _(array).reverse().value() 39781 * // => [3, 2, 1] 39782 * 39783 * console.log(array); 39784 * // => [3, 2, 1] 39785 */ 39786 function wrapperReverse() { 39787 var value = this.__wrapped__; 39788 39789 var interceptor = function(value) { 39790 return (wrapped && wrapped.__dir__ < 0) ? value : value.reverse(); 39791 }; 39792 if (value instanceof LazyWrapper) { 39793 var wrapped = value; 39794 if (this.__actions__.length) {
39795 wrapped = new LazyWrapper(this); 39796 } 39797 wrapped = wrapped.reverse(); 39798 wrapped.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined }); 39799 return new LodashWrapper(wrapped, this.__chain__); 39800 } 39801 return this.thru(interceptor); 39802 } 39803 39804 /** 39805 * Produces the result of coercing the unwrapped value to a string. 39806 * 39807 * @name toString 39808 * @memberOf _ 39809 * @category Chain 39810 * @returns {string} Returns the coerced string value. 39811 * @example 39812 * 39813 * _([1, 2, 3]).toString(); 39814 * // => '1,2,3' 39815 */ 39816 function wrapperToString() { 39817 return (this.value() + ''); 39818 } 39819 39820 /** 39821 * Executes the chained sequence to extract the unwrapped value. 39822 * 39823 * @name value 39824 * @memberOf _ 39825 * @alias run, toJSON, valueOf 39826 * @category Chain 39827 * @returns {*} Returns the resolved unwrapped value. 39828 * @example 39829 * 39830 * _([1, 2, 3]).value(); 39831 * // => [1, 2, 3] 39832 */ 39833 function wrapperValue() { 39834 return baseWrapperValue(this.__wrapped__, this.__actions__); 39835 } 39836 39837 /*------------------------------------------------------------------------*/ 39838 39839 /** 39840 * Creates an array of elements corresponding to the given keys, or indexes, 39841 * of `collection`. Keys may be specified as individual arguments or as arrays 39842 * of keys. 39843 * 39844 * @static 39845 * @memberOf _ 39846 * @category Collection 39847 * @param {Array|Object|string} collection The collection to iterate over. 39848 * @param {...(number|number[]|string|string[])} [props] The property names 39849 * or indexes of elements to pick, specified individually or in arrays. 39850 * @returns {Array} Returns the new array of picked elements. 39851 * @example 39852 * 39853 * _.at(['a', 'b', 'c'], [0, 2]); 39854 * // => ['a', 'c'] 39855 * 39856 * _.at(['barney', 'fred', 'pebbles'], 0, 2); 39857 * // => ['barney', 'pebbles'] 39858 */ 39859 var at = restParam(function(collection, props) { 39860 return baseAt(collection, baseFlatten(props)); 39861 }); 39862 39863 /**
39864 * Creates an object composed of keys generated from the results of running 39865 * each element of `collection` through `iteratee`. The corresponding value 39866 * of each key is the number of times the key was returned by `iteratee`. 39867 * The `iteratee` is bound to `thisArg` and invoked with three arguments: 39868 * (value, index|key, collection). 39869 * 39870 * If a property name is provided for `iteratee` the created `_.property` 39871 * style callback returns the property value of the given element. 39872 * 39873 * If a value is also provided for `thisArg` the created `_.matchesProperty` 39874 * style callback returns `true` for elements that have a matching property 39875 * value, else `false`. 39876 * 39877 * If an object is provided for `iteratee` the created `_.matches` style 39878 * callback returns `true` for elements that have the properties of the given 39879 * object, else `false`. 39880 * 39881 * @static 39882 * @memberOf _ 39883 * @category Collection 39884 * @param {Array|Object|string} collection The collection to iterate over. 39885 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 39886 * per iteration. 39887 * @param {*} [thisArg] The `this` binding of `iteratee`. 39888 * @returns {Object} Returns the composed aggregate object. 39889 * @example 39890 * 39891 * _.countBy([4.3, 6.1, 6.4], function(n) { 39892 * return Math.floor(n); 39893 * }); 39894 * // => { '4': 1, '6': 2 } 39895 * 39896 * _.countBy([4.3, 6.1, 6.4], function(n) { 39897 * return this.floor(n); 39898 * }, Math); 39899 * // => { '4': 1, '6': 2 } 39900 * 39901 * _.countBy(['one', 'two', 'three'], 'length'); 39902 * // => { '3': 2, '5': 1 } 39903 */ 39904 var countBy = createAggregator(function(result, value, key) { 39905 hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1); 39906 }); 39907 39908 /** 39909 * Checks if `predicate` returns truthy for **all** elements of `collection`. 39910 * The predicate is bound to `thisArg` and invoked with three arguments: 39911 * (value, index|key, collection). 39912 * 39913 * If a property name is provided for `predicate` the created `_.property` 39914 * style callback returns the property value of the given element. 39915 * 39916 * If a value is also provided for `thisArg` the created `_.matchesProperty` 39917 * style callback returns `true` for elements that have a matching property 39918 * value, else `false`. 39919 * 39920 * If an object is provided for `predicate` the created `_.matches` style 39921 * callback returns `true` for elements that have the properties of the given 39922 * object, else `false`. 39923 * 39924 * @static 39925 * @memberOf _ 39926 * @alias all 39927 * @category Collection 39928 * @param {Array|Object|string} collection The collection to iterate over. 39929 * @param {Function|Object|string} [predicate=_.identity] The function invoked 39930 * per iteration. 39931 * @param {*} [thisArg] The `this` binding of `predicate`. 39932 * @returns {boolean} Returns `true` if all elements pass the predicate check, 39933 * else `false`. 39934 * @example 39935 * 39936 * _.every([true, 1, null, 'yes'], Boolean); 39937 * // => false 39938 * 39939 * var users = [ 39940 * { 'user': 'barney', 'active': false }, 39941 * { 'user': 'fred', 'active': false } 39942 * ]; 39943 * 39944 * // using the `_.matches` callback shorthand 39945 * _.every(users, { 'user': 'barney', 'active': false }); 39946 * // => false 39947 * 39948 * // using the `_.matchesProperty` callback shorthand 39949 * _.every(users, 'active', false); 39950 * // => true 39951 * 39952 * // using the `_.property` callback shorthand 39953 * _.every(users, 'active'); 39954 * // => false 39955 */ 39956 function every(collection, predicate, thisArg) { 39957 var func = isArray(collection) ? arrayEvery : baseEvery; 39958 if (thisArg && isIterateeCall(collection, predicate, thisArg)) { 39959 predicate = undefined; 39960 } 39961 if (typeof predicate != 'function' || thisArg !== undefined) { 39962 predicate = getCallback(predicate, thisArg, 3); 39963 } 39964 return func(collection, predicate); 39965 } 39966 39967 /** 39968 * Iterates over elements of `collection`, returning an array of all elements 39969 * `predicate` returns truthy for. The predicate is bound to `thisArg` and 39970 * invoked with three arguments: (value, index|key, collection). 39971 * 39972 * If a property name is provided for `predicate` the created `_.property` 39973 * style callback returns the property value of the given element. 39974 * 39975 * If a value is also provided for `thisArg` the created `_.matchesProperty` 39976 * style callback returns `true` for elements that have a matching property 39977 * value, else `false`. 39978 * 39979 * If an object is provided for `predicate` the created `_.matches` style 39980 * callback returns `true` for elements that have the properties of the given 39981 * object, else `false`. 39982 * 39983 * @static 39984 * @memberOf _ 39985 * @alias select 39986 * @category Collection 39987 * @param {Array|Object|string} collection The collection to iterate over. 39988 * @param {Function|Object|string} [predicate=_.identity] The function invoked 39989 * per iteration. 39990 * @param {*} [thisArg] The `this` binding of `predicate`. 39991 * @returns {Array} Returns the new filtered array.
39992 * @example 39993 * 39994 * _.filter([4, 5, 6], function(n) { 39995 * return n % 2 == 0; 39996 * }); 39997 * // => [4, 6] 39998 * 39999 * var users = [ 40000 * { 'user': 'barney', 'age': 36, 'active': true }, 40001 * { 'user': 'fred', 'age': 40, 'active': false } 40002 * ]; 40003 * 40004 * // using the `_.matches` callback shorthand 40005 * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user'); 40006 * // => ['barney'] 40007 * 40008 * // using the `_.matchesProperty` callback shorthand 40009 * _.pluck(_.filter(users, 'active', false), 'user'); 40010 * // => ['fred'] 40011 * 40012 * // using the `_.property` callback shorthand 40013 * _.pluck(_.filter(users, 'active'), 'user'); 40014 * // => ['barney'] 40015 */ 40016 function filter(collection, predicate, thisArg) { 40017 var func = isArray(collection) ? arrayFilter : baseFilter; 40018 predicate = getCallback(predicate, thisArg, 3); 40019 return func(collection, predicate); 40020 } 40021 40022 /** 40023 * Iterates over elements of `collection`, returning the first element 40024 * `predicate` returns truthy for. The predicate is bound to `thisArg` and 40025 * invoked with three arguments: (value, index|key, collection). 40026 * 40027 * If a property name is provided for `predicate` the created `_.property` 40028 * style callback returns the property value of the given element. 40029 * 40030 * If a value is also provided for `thisArg` the created `_.matchesProperty` 40031 * style callback returns `true` for elements that have a matching property 40032 * value, else `false`. 40033 * 40034 * If an object is provided for `predicate` the created `_.matches` style 40035 * callback returns `true` for elements that have the properties of the given 40036 * object, else `false`. 40037 * 40038 * @static 40039 * @memberOf _ 40040 * @alias detect 40041 * @category Collection 40042 * @param {Array|Object|string} collection The collection to search. 40043 * @param {Function|Object|string} [predicate=_.identity] The function invoked 40044 * per iteration. 40045 * @param {*} [thisArg] The `this` binding of `predicate`. 40046 * @returns {*} Returns the matched element, else `undefined`. 40047 * @example 40048 * 40049 * var users = [ 40050 * { 'user': 'barney', 'age': 36, 'active': true }, 40051 * { 'user': 'fred', 'age': 40, 'active': false }, 40052 * { 'user': 'pebbles', 'age': 1, 'active': true } 40053 * ]; 40054 * 40055 * _.result(_.find(users, function(chr) { 40056 * return chr.age < 40; 40057 * }), 'user'); 40058 * // => 'barney' 40059 * 40060 * // using the `_.matches` callback shorthand 40061 * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); 40062 * // => 'pebbles' 40063 * 40064 * // using the `_.matchesProperty` callback shorthand 40065 * _.result(_.find(users, 'active', false), 'user'); 40066 * // => 'fred' 40067 * 40068 * // using the `_.property` callback shorthand 40069 * _.result(_.find(users, 'active'), 'user'); 40070 * // => 'barney' 40071 */ 40072 var find = createFind(baseEach); 40073 40074 /** 40075 * This method is like `_.find` except that it iterates over elements of 40076 * `collection` from right to left. 40077 * 40078 * @static 40079 * @memberOf _ 40080 * @category Collection 40081 * @param {Array|Object|string} collection The collection to search. 40082 * @param {Function|Object|string} [predicate=_.identity] The function invoked 40083 * per iteration. 40084 * @param {*} [thisArg] The `this` binding of `predicate`. 40085 * @returns {*} Returns the matched element, else `undefined`. 40086 * @example 40087 * 40088 * _.findLast([1, 2, 3, 4], function(n) { 40089 * return n % 2 == 1; 40090 * }); 40091 * // => 3 40092 */ 40093 var findLast = createFind(baseEachRight, true); 40094 40095 /** 40096 * Performs a deep comparison between each element in `collection` and the 40097 * source object, returning the first element that has equivalent property 40098 * values. 40099 * 40100 * **Note:** This method supports comparing arrays, booleans, `Date` objects, 40101 * numbers, `Object` objects, regexes, and strings. Objects are compared by 40102 * their own, not inherited, enumerable properties. For comparing a single 40103 * own or inherited property value see `_.matchesProperty`. 40104 * 40105 * @static 40106 * @memberOf _ 40107 * @category Collection 40108 * @param {Array|Object|string} collection The collection to search. 40109 * @param {Object} source The object of property values to match. 40110 * @returns {*} Returns the matched element, else `undefined`. 40111 * @example 40112 * 40113 * var users = [ 40114 * { 'user': 'barney', 'age': 36, 'active': true }, 40115 * { 'user': 'fred', 'age': 40, 'active': false } 40116 * ]; 40117 * 40118 * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user'); 40119 * // => 'barney' 40120 * 40121 * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user'); 40122 * // => 'fred' 40123 */ 40124 function findWhere(collection, source) { 40125 return find(collection, baseMatches(source)); 40126 } 40127 40128 /** 40129 * Iterates over elements of `collection` invoking `iteratee` for each element. 40130 * The `iteratee` is bound to `thisArg` and invoked with three arguments: 40131 * (value, index|key, collection). Iteratee functions may exit iteration early 40132 * by explicitly returning `false`. 40133 * 40134 * **Note:** As with other "Collections" methods, objects with a "length" property 40135 * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` 40136 * may be used for object iteration. 40137 * 40138 * @static 40139 * @memberOf _ 40140 * @alias each 40141 * @category Collection 40142 * @param {Array|Object|string} collection The collection to iterate over. 40143 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 40144 * @param {*} [thisArg] The `this` binding of `iteratee`. 40145 * @returns {Array|Object|string} Returns `collection`. 40146 * @example 40147 *
40148 * _([1, 2]).forEach(function(n) { 40149 * console.log(n); 40150 * }).value(); 40151 * // => logs each value from left to right and returns the array 40152 * 40153 * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { 40154 * console.log(n, key); 40155 * }); 40156 * // => logs each value-key pair and returns the object (iteration order is not guaranteed) 40157 */ 40158 var forEach = createForEach(arrayEach, baseEach); 40159 40160 /** 40161 * This method is like `_.forEach` except that it iterates over elements of 40162 * `collection` from right to left. 40163 * 40164 * @static 40165 * @memberOf _ 40166 * @alias eachRight 40167 * @category Collection 40168 * @param {Array|Object|string} collection The collection to iterate over. 40169 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 40170 * @param {*} [thisArg] The `this` binding of `iteratee`. 40171 * @returns {Array|Object|string} Returns `collection`. 40172 * @example 40173 * 40174 * _([1, 2]).forEachRight(function(n) { 40175 * console.log(n); 40176 * }).value(); 40177 * // => logs each value from right to left and returns the array 40178 */ 40179 var forEachRight = createForEach(arrayEachRight, baseEachRight); 40180 40181 /**
40182 * Creates an object composed of keys generated from the results of running 40183 * each element of `collection` through `iteratee`. The corresponding value 40184 * of each key is an array of the elements responsible for generating the key. 40185 * The `iteratee` is bound to `thisArg` and invoked with three arguments: 40186 * (value, index|key, collection). 40187 * 40188 * If a property name is provided for `iteratee` the created `_.property` 40189 * style callback returns the property value of the given element. 40190 * 40191 * If a value is also provided for `thisArg` the created `_.matchesProperty` 40192 * style callback returns `true` for elements that have a matching property 40193 * value, else `false`. 40194 * 40195 * If an object is provided for `iteratee` the created `_.matches` style 40196 * callback returns `true` for elements that have the properties of the given 40197 * object, else `false`. 40198 * 40199 * @static 40200 * @memberOf _ 40201 * @category Collection 40202 * @param {Array|Object|string} collection The collection to iterate over. 40203 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 40204 * per iteration. 40205 * @param {*} [thisArg] The `this` binding of `iteratee`. 40206 * @returns {Object} Returns the composed aggregate object. 40207 * @example 40208 * 40209 * _.groupBy([4.2, 6.1, 6.4], function(n) { 40210 * return Math.floor(n); 40211 * }); 40212 * // => { '4': [4.2], '6': [6.1, 6.4] } 40213 * 40214 * _.groupBy([4.2, 6.1, 6.4], function(n) { 40215 * return this.floor(n); 40216 * }, Math); 40217 * // => { '4': [4.2], '6': [6.1, 6.4] } 40218 * 40219 * // using the `_.property` callback shorthand 40220 * _.groupBy(['one', 'two', 'three'], 'length'); 40221 * // => { '3': ['one', 'two'], '5': ['three'] } 40222 */ 40223 var groupBy = createAggregator(function(result, value, key) { 40224 if (hasOwnProperty.call(result, key)) { 40225 result[key].push(value); 40226 } else { 40227 result[key] = [value]; 40228 } 40229 }); 40230 40231 /** 40232 * Checks if `value` is in `collection` using 40233 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) 40234 * for equality comparisons. If `fromIndex` is negative, it is used as the offset 40235 * from the end of `collection`. 40236 * 40237 * @static 40238 * @memberOf _ 40239 * @alias contains, include 40240 * @category Collection 40241 * @param {Array|Object|string} collection The collection to search. 40242 * @param {*} target The value to search for. 40243 * @param {number} [fromIndex=0] The index to search from. 40244 * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. 40245 * @returns {boolean} Returns `true` if a matching element is found, else `false`. 40246 * @example 40247 * 40248 * _.includes([1, 2, 3], 1); 40249 * // => true 40250 * 40251 * _.includes([1, 2, 3], 1, 2); 40252 * // => false 40253 * 40254 * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); 40255 * // => true 40256 * 40257 * _.includes('pebbles', 'eb'); 40258 * // => true 40259 */ 40260 function includes(collection, target, fromIndex, guard) { 40261 var length = collection ? getLength(collection) : 0; 40262 if (!isLength(length)) { 40263 collection = values(collection); 40264 length = collection.length; 40265 } 40266 if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) { 40267 fromIndex = 0; 40268 } else { 40269 fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); 40270 } 40271 return (typeof collection == 'string' || !isArray(collection) && isString(collection)) 40272 ? (fromIndex <= length && collection.indexOf(target, fromIndex) > -1) 40273 : (!!length && getIndexOf(collection, target, fromIndex) > -1); 40274 } 40275 40276 /**
40277 * Creates an object composed of keys generated from the results of running 40278 * each element of `collection` through `iteratee`. The corresponding value 40279 * of each key is the last element responsible for generating the key. The 40280 * iteratee function is bound to `thisArg` and invoked with three arguments: 40281 * (value, index|key, collection). 40282 * 40283 * If a property name is provided for `iteratee` the created `_.property` 40284 * style callback returns the property value of the given element. 40285 * 40286 * If a value is also provided for `thisArg` the created `_.matchesProperty` 40287 * style callback returns `true` for elements that have a matching property 40288 * value, else `false`. 40289 * 40290 * If an object is provided for `iteratee` the created `_.matches` style 40291 * callback returns `true` for elements that have the properties of the given 40292 * object, else `false`. 40293 * 40294 * @static 40295 * @memberOf _ 40296 * @category Collection 40297 * @param {Array|Object|string} collection The collection to iterate over. 40298 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 40299 * per iteration. 40300 * @param {*} [thisArg] The `this` binding of `iteratee`. 40301 * @returns {Object} Returns the composed aggregate object. 40302 * @example 40303 * 40304 * var keyData = [ 40305 * { 'dir': 'left', 'code': 97 }, 40306 * { 'dir': 'right', 'code': 100 } 40307 * ]; 40308 * 40309 * _.indexBy(keyData, 'dir'); 40310 * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } 40311 * 40312 * _.indexBy(keyData, function(object) { 40313 * return String.fromCharCode(object.code); 40314 * }); 40315 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } 40316 * 40317 * _.indexBy(keyData, function(object) { 40318 * return this.fromCharCode(object.code); 40319 * }, String); 40320 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } 40321 */ 40322 var indexBy = createAggregator(function(result, value, key) { 40323 result[key] = value; 40324 }); 40325 40326 /** 40327 * Invokes the method at `path` of each element in `collection`, returning 40328 * an array of the results of each invoked method. Any additional arguments 40329 * are provided to each invoked method. If `methodName` is a function it is 40330 * invoked for, and `this` bound to, each element in `collection`. 40331 * 40332 * @static 40333 * @memberOf _ 40334 * @category Collection 40335 * @param {Array|Object|string} collection The collection to iterate over. 40336 * @param {Array|Function|string} path The path of the method to invoke or 40337 * the function invoked per iteration. 40338 * @param {...*} [args] The arguments to invoke the method with. 40339 * @returns {Array} Returns the array of results. 40340 * @example 40341 * 40342 * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); 40343 * // => [[1, 5, 7], [1, 2, 3]] 40344 * 40345 * _.invoke([123, 456], String.prototype.split, ''); 40346 * // => [['1', '2', '3'], ['4', '5', '6']] 40347 */ 40348 var invoke = restParam(function(collection, path, args) { 40349 var index = -1, 40350 isFunc = typeof path == 'function', 40351 isProp = isKey(path), 40352 result = isArrayLike(collection) ? Array(collection.length) : []; 40353 40354 baseEach(collection, function(value) { 40355 var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined); 40356 result[++index] = func ? func.apply(value, args) : invokePath(value, path, args); 40357 }); 40358 return result; 40359 }); 40360 40361 /** 40362 * Creates an array of values by running each element in `collection` through 40363 * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three 40364 * arguments: (value, index|key, collection). 40365 * 40366 * If a property name is provided for `iteratee` the created `_.property` 40367 * style callback returns the property value of the given element. 40368 * 40369 * If a value is also provided for `thisArg` the created `_.matchesProperty` 40370 * style callback returns `true` for elements that have a matching property 40371 * value, else `false`. 40372 * 40373 * If an object is provided for `iteratee` the created `_.matches` style 40374 * callback returns `true` for elements that have the properties of the given 40375 * object, else `false`. 40376 * 40377 * Many lodash methods are guarded to work as iteratees for methods like 40378 * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. 40379 * 40380 * The guarded methods are: 40381 * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, 40382 * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, 40383 * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, 40384 * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, 40385 * `sum`, `uniq`, and `words` 40386 * 40387 * @static 40388 * @memberOf _ 40389 * @alias collect 40390 * @category Collection 40391 * @param {Array|Object|string} collection The collection to iterate over. 40392 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 40393 * per iteration. 40394 * @param {*} [thisArg] The `this` binding of `iteratee`. 40395 * @returns {Array} Returns the new mapped array.
40396 * @example 40397 * 40398 * function timesThree(n) { 40399 * return n * 3; 40400 * } 40401 * 40402 * _.map([1, 2], timesThree); 40403 * // => [3, 6] 40404 * 40405 * _.map({ 'a': 1, 'b': 2 }, timesThree); 40406 * // => [3, 6] (iteration order is not guaranteed) 40407 * 40408 * var users = [ 40409 * { 'user': 'barney' }, 40410 * { 'user': 'fred' } 40411 * ]; 40412 * 40413 * // using the `_.property` callback shorthand 40414 * _.map(users, 'user'); 40415 * // => ['barney', 'fred'] 40416 */ 40417 function map(collection, iteratee, thisArg) { 40418 var func = isArray(collection) ? arrayMap : baseMap; 40419 iteratee = getCallback(iteratee, thisArg, 3); 40420 return func(collection, iteratee); 40421 } 40422 40423 /** 40424 * Creates an array of elements split into two groups, the first of which 40425 * contains elements `predicate` returns truthy for, while the second of which 40426 * contains elements `predicate` returns falsey for. The predicate is bound 40427 * to `thisArg` and invoked with three arguments: (value, index|key, collection). 40428 * 40429 * If a property name is provided for `predicate` the created `_.property` 40430 * style callback returns the property value of the given element. 40431 * 40432 * If a value is also provided for `thisArg` the created `_.matchesProperty` 40433 * style callback returns `true` for elements that have a matching property 40434 * value, else `false`. 40435 * 40436 * If an object is provided for `predicate` the created `_.matches` style 40437 * callback returns `true` for elements that have the properties of the given 40438 * object, else `false`. 40439 * 40440 * @static 40441 * @memberOf _ 40442 * @category Collection 40443 * @param {Array|Object|string} collection The collection to iterate over. 40444 * @param {Function|Object|string} [predicate=_.identity] The function invoked 40445 * per iteration. 40446 * @param {*} [thisArg] The `this` binding of `predicate`. 40447 * @returns {Array} Returns the array of grouped elements. 40448 * @example 40449 * 40450 * _.partition([1, 2, 3], function(n) { 40451 * return n % 2; 40452 * }); 40453 * // => [[1, 3], [2]] 40454 * 40455 * _.partition([1.2, 2.3, 3.4], function(n) { 40456 * return this.floor(n) % 2; 40457 * }, Math); 40458 * // => [[1.2, 3.4], [2.3]] 40459 * 40460 * var users = [ 40461 * { 'user': 'barney', 'age': 36, 'active': false }, 40462 * { 'user': 'fred', 'age': 40, 'active': true }, 40463 * { 'user': 'pebbles', 'age': 1, 'active': false } 40464 * ]; 40465 * 40466 * var mapper = function(array) { 40467 * return _.pluck(array, 'user'); 40468 * }; 40469 * 40470 * // using the `_.matches` callback shorthand 40471 * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); 40472 * // => [['pebbles'], ['barney', 'fred']] 40473 * 40474 * // using the `_.matchesProperty` callback shorthand 40475 * _.map(_.partition(users, 'active', false), mapper); 40476 * // => [['barney', 'pebbles'], ['fred']] 40477 * 40478 * // using the `_.property` callback shorthand 40479 * _.map(_.partition(users, 'active'), mapper); 40480 * // => [['fred'], ['barney', 'pebbles']] 40481 */ 40482 var partition = createAggregator(function(result, value, key) { 40483 result[key ? 0 : 1].push(value); 40484 }, function() { return [[], []]; }); 40485 40486 /** 40487 * Gets the property value of `path` from all elements in `collection`. 40488 * 40489 * @static 40490 * @memberOf _ 40491 * @category Collection 40492 * @param {Array|Object|string} collection The collection to iterate over. 40493 * @param {Array|string} path The path of the property to pluck. 40494 * @returns {Array} Returns the property values. 40495 * @example 40496 * 40497 * var users = [ 40498 * { 'user': 'barney', 'age': 36 }, 40499 * { 'user': 'fred', 'age': 40 } 40500 * ]; 40501 * 40502 * _.pluck(users, 'user'); 40503 * // => ['barney', 'fred'] 40504 * 40505 * var userIndex = _.indexBy(users, 'user'); 40506 * _.pluck(userIndex, 'age'); 40507 * // => [36, 40] (iteration order is not guaranteed) 40508 */ 40509 function pluck(collection, path) { 40510 return map(collection, property(path)); 40511 } 40512 40513 /** 40514 * Reduces `collection` to a value which is the accumulated result of running 40515 * each element in `collection` through `iteratee`, where each successive 40516 * invocation is supplied the return value of the previous. If `accumulator` 40517 * is not provided the first element of `collection` is used as the initial 40518 * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: 40519 * (accumulator, value, index|key, collection). 40520 * 40521 * Many lodash methods are guarded to work as iteratees for methods like 40522 * `_.reduce`, `_.reduceRight`, and `_.transform`. 40523 * 40524 * The guarded methods are: 40525 * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortByAll`, 40526 * and `sortByOrder` 40527 * 40528 * @static 40529 * @memberOf _ 40530 * @alias foldl, inject 40531 * @category Collection 40532 * @param {Array|Object|string} collection The collection to iterate over. 40533 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 40534 * @param {*} [accumulator] The initial value. 40535 * @param {*} [thisArg] The `this` binding of `iteratee`. 40536 * @returns {*} Returns the accumulated value. 40537 * @example 40538 * 40539 * _.reduce([1, 2], function(total, n) { 40540 * return total + n; 40541 * }); 40542 * // => 3 40543 * 40544 * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) { 40545 * result[key] = n * 3; 40546 * return result; 40547 * }, {}); 40548 * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) 40549 */ 40550 var reduce = createReduce(arrayReduce, baseEach); 40551 40552 /** 40553 * This method is like `_.reduce` except that it iterates over elements of 40554 * `collection` from right to left. 40555 * 40556 * @static 40557 * @memberOf _ 40558 * @alias foldr 40559 * @category Collection 40560 * @param {Array|Object|string} collection The collection to iterate over. 40561 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 40562 * @param {*} [accumulator] The initial value. 40563 * @param {*} [thisArg] The `this` binding of `iteratee`. 40564 * @returns {*} Returns the accumulated value. 40565 * @example 40566 * 40567 * var array = [[0, 1], [2, 3], [4, 5]]; 40568 * 40569 * _.reduceRight(array, function(flattened, other) { 40570 * return flattened.concat(other); 40571 * }, []); 40572 * // => [4, 5, 2, 3, 0, 1] 40573 */ 40574 var reduceRight = createReduce(arrayReduceRight, baseEachRight); 40575 40576 /** 40577 * The opposite of `_.filter`; this method returns the elements of `collection` 40578 * that `predicate` does **not** return truthy for. 40579 * 40580 * @static 40581 * @memberOf _ 40582 * @category Collection 40583 * @param {Array|Object|string} collection The collection to iterate over. 40584 * @param {Function|Object|string} [predicate=_.identity] The function invoked 40585 * per iteration. 40586 * @param {*} [thisArg] The `this` binding of `predicate`. 40587 * @returns {Array} Returns the new filtered array.
40588 * @example 40589 * 40590 * _.reject([1, 2, 3, 4], function(n) { 40591 * return n % 2 == 0; 40592 * }); 40593 * // => [1, 3] 40594 * 40595 * var users = [ 40596 * { 'user': 'barney', 'age': 36, 'active': false }, 40597 * { 'user': 'fred', 'age': 40, 'active': true } 40598 * ]; 40599 * 40600 * // using the `_.matches` callback shorthand 40601 * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user'); 40602 * // => ['barney'] 40603 * 40604 * // using the `_.matchesProperty` callback shorthand 40605 * _.pluck(_.reject(users, 'active', false), 'user'); 40606 * // => ['fred'] 40607 * 40608 * // using the `_.property` callback shorthand 40609 * _.pluck(_.reject(users, 'active'), 'user'); 40610 * // => ['barney'] 40611 */ 40612 function reject(collection, predicate, thisArg) { 40613 var func = isArray(collection) ? arrayFilter : baseFilter; 40614 predicate = getCallback(predicate, thisArg, 3); 40615 return func(collection, function(value, index, collection) { 40616 return !predicate(value, index, collection); 40617 }); 40618 } 40619 40620 /** 40621 * Gets a random element or `n` random elements from a collection. 40622 * 40623 * @static 40624 * @memberOf _ 40625 * @category Collection 40626 * @param {Array|Object|string} collection The collection to sample. 40627 * @param {number} [n] The number of elements to sample. 40628 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 40629 * @returns {*} Returns the random sample(s). 40630 * @example 40631 * 40632 * _.sample([1, 2, 3, 4]); 40633 * // => 2 40634 * 40635 * _.sample([1, 2, 3, 4], 2); 40636 * // => [3, 1] 40637 */ 40638 function sample(collection, n, guard) { 40639 if (guard ? isIterateeCall(collection, n, guard) : n == null) { 40640 collection = toIterable(collection); 40641 var length = collection.length; 40642 return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; 40643 } 40644 var index = -1, 40645 result = toArray(collection), 40646 length = result.length, 40647 lastIndex = length - 1; 40648 40649 n = nativeMin(n < 0 ? 0 : (+n || 0), length); 40650 while (++index < n) { 40651 var rand = baseRandom(index, lastIndex), 40652 value = result[rand]; 40653 40654 result[rand] = result[index]; 40655 result[index] = value; 40656 } 40657 result.length = n; 40658 return result; 40659 } 40660 40661 /** 40662 * Creates an array of shuffled values, using a version of the 40663 * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). 40664 * 40665 * @static 40666 * @memberOf _ 40667 * @category Collection 40668 * @param {Array|Object|string} collection The collection to shuffle. 40669 * @returns {Array} Returns the new shuffled array. 40670 * @example 40671 * 40672 * _.shuffle([1, 2, 3, 4]); 40673 * // => [4, 1, 3, 2] 40674 */ 40675 function shuffle(collection) { 40676 return sample(collection, POSITIVE_INFINITY); 40677 } 40678 40679 /** 40680 * Gets the size of `collection` by returning its length for array-like 40681 * values or the number of own enumerable properties for objects. 40682 * 40683 * @static 40684 * @memberOf _ 40685 * @category Collection 40686 * @param {Array|Object|string} collection The collection to inspect. 40687 * @returns {number} Returns the size of `collection`. 40688 * @example 40689 * 40690 * _.size([1, 2, 3]); 40691 * // => 3 40692 * 40693 * _.size({ 'a': 1, 'b': 2 }); 40694 * // => 2 40695 * 40696 * _.size('pebbles'); 40697 * // => 7 40698 */ 40699 function size(collection) { 40700 var length = collection ? getLength(collection) : 0; 40701 return isLength(length) ? length : keys(collection).length; 40702 } 40703 40704 /** 40705 * Checks if `predicate` returns truthy for **any** element of `collection`. 40706 * The function returns as soon as it finds a passing value and does not iterate 40707 * over the entire collection. The predicate is bound to `thisArg` and invoked 40708 * with three arguments: (value, index|key, collection). 40709 * 40710 * If a property name is provided for `predicate` the created `_.property` 40711 * style callback returns the property value of the given element. 40712 * 40713 * If a value is also provided for `thisArg` the created `_.matchesProperty` 40714 * style callback returns `true` for elements that have a matching property 40715 * value, else `false`. 40716 * 40717 * If an object is provided for `predicate` the created `_.matches` style 40718 * callback returns `true` for elements that have the properties of the given 40719 * object, else `false`. 40720 * 40721 * @static 40722 * @memberOf _ 40723 * @alias any 40724 * @category Collection 40725 * @param {Array|Object|string} collection The collection to iterate over. 40726 * @param {Function|Object|string} [predicate=_.identity] The function invoked 40727 * per iteration. 40728 * @param {*} [thisArg] The `this` binding of `predicate`. 40729 * @returns {boolean} Returns `true` if any element passes the predicate check, 40730 * else `false`. 40731 * @example 40732 * 40733 * _.some([null, 0, 'yes', false], Boolean); 40734 * // => true 40735 * 40736 * var users = [ 40737 * { 'user': 'barney', 'active': true }, 40738 * { 'user': 'fred', 'active': false } 40739 * ]; 40740 * 40741 * // using the `_.matches` callback shorthand 40742 * _.some(users, { 'user': 'barney', 'active': false }); 40743 * // => false 40744 *
40745 * // using the `_.matchesProperty` callback shorthand 40746 * _.some(users, 'active', false); 40747 * // => true 40748 * 40749 * // using the `_.property` callback shorthand 40750 * _.some(users, 'active'); 40751 * // => true 40752 */ 40753 function some(collection, predicate, thisArg) { 40754 var func = isArray(collection) ? arraySome : baseSome; 40755 if (thisArg && isIterateeCall(collection, predicate, thisArg)) { 40756 predicate = undefined; 40757 } 40758 if (typeof predicate != 'function' || thisArg !== undefined) { 40759 predicate = getCallback(predicate, thisArg, 3); 40760 } 40761 return func(collection, predicate); 40762 } 40763 40764 /** 40765 * Creates an array of elements, sorted in ascending order by the results of 40766 * running each element in a collection through `iteratee`. This method performs 40767 * a stable sort, that is, it preserves the original sort order of equal elements. 40768 * The `iteratee` is bound to `thisArg` and invoked with three arguments: 40769 * (value, index|key, collection). 40770 * 40771 * If a property name is provided for `iteratee` the created `_.property` 40772 * style callback returns the property value of the given element. 40773 * 40774 * If a value is also provided for `thisArg` the created `_.matchesProperty` 40775 * style callback returns `true` for elements that have a matching property 40776 * value, else `false`. 40777 * 40778 * If an object is provided for `iteratee` the created `_.matches` style 40779 * callback returns `true` for elements that have the properties of the given 40780 * object, else `false`. 40781 * 40782 * @static 40783 * @memberOf _ 40784 * @category Collection 40785 * @param {Array|Object|string} collection The collection to iterate over. 40786 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 40787 * per iteration. 40788 * @param {*} [thisArg] The `this` binding of `iteratee`. 40789 * @returns {Array} Returns the new sorted array. 40790 * @example 40791 * 40792 * _.sortBy([1, 2, 3], function(n) { 40793 * return Math.sin(n); 40794 * }); 40795 * // => [3, 1, 2] 40796 * 40797 * _.sortBy([1, 2, 3], function(n) { 40798 * return this.sin(n); 40799 * }, Math); 40800 * // => [3, 1, 2] 40801 * 40802 * var users = [ 40803 * { 'user': 'fred' }, 40804 * { 'user': 'pebbles' }, 40805 * { 'user': 'barney' } 40806 * ]; 40807 * 40808 * // using the `_.property` callback shorthand 40809 * _.pluck(_.sortBy(users, 'user'), 'user'); 40810 * // => ['barney', 'fred', 'pebbles'] 40811 */ 40812 function sortBy(collection, iteratee, thisArg) { 40813 if (collection == null) { 40814 return []; 40815 } 40816 if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { 40817 iteratee = undefined; 40818 } 40819 var index = -1; 40820 iteratee = getCallback(iteratee, thisArg, 3); 40821 40822 var result = baseMap(collection, function(value, key, collection) { 40823 return { 'criteria': iteratee(value, key, collection), 'index': ++index, 'value': value }; 40824 }); 40825 return baseSortBy(result, compareAscending); 40826 } 40827 40828 /** 40829 * This method is like `_.sortBy` except that it can sort by multiple iteratees 40830 * or property names. 40831 * 40832 * If a property name is provided for an iteratee the created `_.property` 40833 * style callback returns the property value of the given element. 40834 * 40835 * If an object is provided for an iteratee the created `_.matches` style 40836 * callback returns `true` for elements that have the properties of the given 40837 * object, else `false`. 40838 * 40839 * @static 40840 * @memberOf _ 40841 * @category Collection 40842 * @param {Array|Object|string} collection The collection to iterate over. 40843 * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees 40844 * The iteratees to sort by, specified as individual values or arrays of values. 40845 * @returns {Array} Returns the new sorted array. 40846 * @example 40847 * 40848 * var users = [ 40849 * { 'user': 'fred', 'age': 48 }, 40850 * { 'user': 'barney', 'age': 36 }, 40851 * { 'user': 'fred', 'age': 42 }, 40852 * { 'user': 'barney', 'age': 34 } 40853 * ]; 40854 * 40855 * _.map(_.sortByAll(users, ['user', 'age']), _.values); 40856 * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] 40857 * 40858 * _.map(_.sortByAll(users, 'user', function(chr) { 40859 * return Math.floor(chr.age / 10); 40860 * }), _.values); 40861 * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] 40862 */ 40863 var sortByAll = restParam(function(collection, iteratees) { 40864 if (collection == null) { 40865 return []; 40866 } 40867 var guard = iteratees[2]; 40868 if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) { 40869 iteratees.length = 1; 40870 } 40871 return baseSortByOrder(collection, baseFlatten(iteratees), []); 40872 }); 40873 40874 /** 40875 * This method is like `_.sortByAll` except that it allows specifying the 40876 * sort orders of the iteratees to sort by. If `orders` is unspecified, all 40877 * values are sorted in ascending order. Otherwise, a value is sorted in 40878 * ascending order if its corresponding order is "asc", and desce
40878nding if "desc". 40879 * 40880 * If a property name is provided for an iteratee the created `_.property` 40881 * style callback returns the property value of the given element. 40882 * 40883 * If an object is provided for an iteratee the created `_.matches` style 40884 * callback returns `true` for elements that have the properties of the given 40885 * object, else `false`. 40886 * 40887 * @static 40888 * @memberOf _ 40889 * @category Collection 40890 * @param {Array|Object|string} collection The collection to iterate over. 40891 * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. 40892 * @param {boolean[]} [orders] The sort orders of `iteratees`. 40893 * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. 40894 * @returns {Array} Returns the new sorted array. 40895 * @example 40896 * 40897 * var users = [ 40898 * { 'user': 'fred', 'age': 48 }, 40899 * { 'user': 'barney', 'age': 34 }, 40900 * { 'user': 'fred', 'age': 42 }, 40901 * { 'user': 'barney', 'age': 36 } 40902 * ]; 40903 * 40904 * // sort by `user` in ascending order and by `age` in descending order 40905 * _.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values); 40906 * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] 40907 */ 40908 function sortByOrder(collection, iteratees, orders, guard) { 40909 if (collection == null) { 40910 return []; 40911 } 40912 if (guard && isIterateeCall(iteratees, orders, guard)) { 40913 orders = undefined; 40914 } 40915 if (!isArray(iteratees)) { 40916 iteratees = iteratees == null ? [] : [iteratees]; 40917 } 40918 if (!isArray(orders)) { 40919 orders = orders == null ? [] : [orders]; 40920 } 40921 return baseSortByOrder(collection, iteratees, orders); 40922 } 40923 40924 /** 40925 * Performs a deep comparison between each element in `collection` and the 40926 * source object, returning an array of all elements that have equivalent 40927 * property values. 40928 * 40929 * **Note:** This method supports comparing arrays, booleans, `Date` objects, 40930 * numbers, `Object` objects, regexes, and strings. Objects are compared by 40931 * their own, not inherited, enumerable properties. For comparing a single 40932 * own or inherited property value see `_.matchesProperty`. 40933 * 40934 * @static 40935 * @memberOf _ 40936 * @category Collection 40937 * @param {Array|Object|string} collection The collection to search. 40938 * @param {Object} source The object of property values to match. 40939 * @returns {Array} Returns the new filtered array. 40940 * @example 40941 * 40942 * var users = [ 40943 * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] }, 40944 * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] } 40945 * ]; 40946 * 40947 * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user'); 40948 * // => ['barney'] 40949 * 40950 * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); 40951 * // => ['fred'] 40952 */ 40953 function where(collection, source) { 40954 return filter(collection, baseMatches(source)); 40955 } 40956 40957 /*------------------------------------------------------------------------*/ 40958 40959 /** 40960 * Gets the number of milliseconds that have elapsed since the Unix epoch 40961 * (1 January 1970 00:00:00 UTC). 40962 * 40963 * @static 40964 * @memberOf _ 40965 * @category Date 40966 * @example 40967 * 40968 * _.defer(function(stamp) { 40969 * console.log(_.now() - stamp); 40970 * }, _.now()); 40971 * // => logs the number of milliseconds it took for the deferred function to be invoked 40972 */ 40973 var now = nativeNow || function() { 40974 return new Date().getTime(); 40975 }; 40976 40977 /*------------------------------------------------------------------------*/ 40978 40979 /** 40980 * The opposite of `_.before`; this method creates a function that invokes 40981 * `func` once it is called `n` or more times. 40982 * 40983 * @static 40984 * @memberOf _ 40985 * @category Function 40986 * @param {number} n The number of calls before `func` is invoked. 40987 * @param {Function} func The function to restrict. 40988 * @returns {Function} Returns the new restricted function. 40989 * @example 40990 * 40991 * var saves = ['profile', 'settings']; 40992 * 40993 * var done = _.after(saves.length, function() { 40994 * console.log('done saving!'); 40995 * }); 40996 * 40997 * _.forEach(saves, function(type) { 40998 * asyncSave({ 'type': type, 'complete': done }); 40999 * }); 41000 * // => logs 'done saving!' after the two async saves have completed 41001 */ 41002 function after(n, func) { 41003 if (typeof func != 'function') { 41004 if (typeof n == 'function') { 41005 var temp = n; 41006 n = func; 41007 func = temp; 41008 } else { 41009 throw new TypeError(FUNC_ERROR_TEXT); 41010 } 41011 } 41012 n = nativeIsFinite(n = +n) ? n : 0; 41013 return function() { 41014 if (--n < 1) { 41015 return func.apply(this, arguments); 41016 } 41017 }; 41018 } 41019 41020 /** 41021 * Creates a function that accepts up to `n` arguments ignoring any 41022 * additional arguments. 41023 * 41024 * @static 41025 * @memberOf _ 41026 * @category Function 41027 * @param {Function} func The function to cap arguments for. 41028 * @param {number} [n=func.length] The arity cap. 41029 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 41030 * @returns {Function} Returns the new function. 41031 * @example 41032 * 41033 * _.map(['6', '8', '10'], _.ary(parseInt, 1)); 41034 * // => [6, 8, 10] 41035 */ 41036 function ary(func, n, guard) { 41037 if (guard && isIterateeCall(func, n, guard)) { 41038 n = undefined; 41039 } 41040 n = (func && n == null) ? func.length : nativeMax(+n || 0, 0); 41041 return createWrapper(func, ARY_FLAG, undefined, undefined, undefined, undefined, n); 41042 } 41043 41044 /** 41045 * Creates a function that invokes `func`, with the `this` binding and arguments 41046 * of the created function, while it is called less than `n` times. Subsequent 41047 * calls to the created function return the result of the last `func` invocation. 41048 * 41049 * @static 41050 * @memberOf _ 41051 * @category Function 41052 * @param {number} n The number of calls at which `func` is no longer invoked. 41053 * @param {Function} func The function to restrict. 41054 * @returns {Function} Returns the new restricted function. 41055 * @example 41056 * 41057 * jQuery('#add').on('click', _.before(5, addContactToList)); 41058 * // => allows adding up to 4 contacts to the list 41059 */ 41060 function before(n, func) { 41061 var result; 41062 if (typeof func != 'function') { 41063 if (typeof n == 'function') { 41064 var temp = n; 41065 n = func; 41066 func = temp; 41067 } else { 41068 throw new TypeError(FUNC_ERROR_TEXT); 41069 } 41070 } 41071 return function() { 41072 if (--n > 0) { 41073 result = func.apply(this, arguments); 41074 } 41075 if (n <= 1) { 41076 func = undefined; 41077 } 41078 return result; 41079 }; 41080 } 41081 41082 /** 41083 * Creates a function that invokes `func` with the `this` binding of `thisArg` 41084 * and prepends any additional `_.bind` arguments to those provided to the 41085 * bound function. 41086 * 41087 * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, 41088 * may be used as a placeholder for partially applied arguments. 41089 * 41090 * **Note:** Unlike native `Function#bind` this method does not set the "length" 41091 * property of bound functions. 41092 * 41093 * @static 41094 * @memberOf _ 41095 * @category Function 41096 * @param {Function} func The function to bind. 41097 * @param {*} thisArg The `this` binding of `func`. 41098 * @param {...*} [partials] The arguments to be partially applied. 41099 * @returns {Function} Returns the new bound function. 41100 * @example 41101 * 41102 * var greet = function(greeting, punctuation) { 41103 * return greeting + ' ' + this.user + punctuation; 41104 * }; 41105 * 41106 * var object = { 'user': 'fred' }; 41107 * 41108 * var bound = _.bind(greet, object, 'hi'); 41109 * bound('!'); 41110 * // => 'hi fred!' 41111 * 41112 * // using placeholders 41113 * var bound = _.bind(greet, object, _, '!'); 41114 * bound('hi'); 41115 * // => 'hi fred!' 41116 */ 41117 var bind = restParam(function(func, thisArg, partials) { 41118 var bitmask = BIND_FLAG; 41119 if (partials.length) { 41120 var holders = replaceHolders(partials, bind.placeholder); 41121 bitmask |= PARTIAL_FLAG; 41122 } 41123 return createWrapper(func, bitmask, thisArg, partials, holders); 41124 }); 41125 41126 /** 41127 * Binds methods of an object to the object itself, overwriting the existing 41128 * method. Method names may be specified as individual arguments or as arrays
41129 * of method names. If no method names are provided all enumerable function 41130 * properties, own and inherited, of `object` are bound. 41131 * 41132 * **Note:** This method does not set the "length" property of bound functions. 41133 * 41134 * @static 41135 * @memberOf _ 41136 * @category Function 41137 * @param {Object} object The object to bind and assign the bound methods to. 41138 * @param {...(string|string[])} [methodNames] The object method names to bind, 41139 * specified as individual method names or arrays of method names. 41140 * @returns {Object} Returns `object`. 41141 * @example 41142 * 41143 * var view = { 41144 * 'label': 'docs', 41145 * 'onClick': function() { 41146 * console.log('clicked ' + this.label); 41147 * } 41148 * }; 41149 * 41150 * _.bindAll(view); 41151 * jQuery('#docs').on('click', view.onClick); 41152 * // => logs 'clicked docs' when the element is clicked 41153 */ 41154 var bindAll = restParam(function(object, methodNames) { 41155 methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object); 41156 41157 var index = -1, 41158 length = methodNames.length; 41159 41160 while (++index < length) { 41161 var key = methodNames[index]; 41162 object[key] = createWrapper(object[key], BIND_FLAG, object); 41163 } 41164 return object; 41165 }); 41166 41167 /** 41168 * Creates a function that invokes the method at `object[key]` and prepends 41169 * any additional `_.bindKey` arguments to those provided to the bound function. 41170 * 41171 * This method differs from `_.bind` by allowing bound functions to reference 41172 * methods that may be redefined or don't yet exist. 41173 * See [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) 41174 * for more details. 41175 * 41176 * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic 41177 * builds, may be used as a placeholder for partially applied arguments. 41178 * 41179 * @static 41180 * @memberOf _ 41181 * @category Function 41182 * @param {Object} object The object the method belongs to. 41183 * @param {string} key The key of the method. 41184 * @param {...*} [partials] The arguments to be partially applied. 41185 * @returns {Function} Returns the new bound function. 41186 * @example 41187 * 41188 * var object = { 41189 * 'user': 'fred', 41190 * 'greet': function(greeting, punctuation) { 41191 * return greeting + ' ' + this.user + punctuation; 41192 * } 41193 * }; 41194 * 41195 * var bound = _.bindKey(object, 'greet', 'hi'); 41196 * bound('!'); 41197 * // => 'hi fred!' 41198 * 41199 * object.greet = function(greeting, punctuation) { 41200 * return greeting + 'ya ' + this.user + punctuation; 41201 * }; 41202 * 41203 * bound('!'); 41204 * // => 'hiya fred!' 41205 * 41206 * // using placeholders 41207 * var bound = _.bindKey(object, 'greet', _, '!'); 41208 * bound('hi'); 41209 * // => 'hiya fred!' 41210 */ 41211 var bindKey = restParam(function(object, key, partials) { 41212 var bitmask = BIND_FLAG | BIND_KEY_FLAG; 41213 if (partials.length) { 41214 var holders = replaceHolders(partials, bindKey.placeholder); 41215 bitmask |= PARTIAL_FLAG; 41216 } 41217 return createWrapper(key, bitmask, object, partials, holders); 41218 }); 41219 41220 /** 41221 * Creates a function that accepts one or more arguments of `func` that when 41222 * called either invokes `func` returning its result, if all `func` arguments 41223 * have been provided, or returns a function that accepts one or more of the 41224 * remaining `func` arguments, and so on. The arity of `func` may be specified 41225 * if `func.length` is not sufficient. 41226 * 41227 * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, 41228 * may be used as a placeholder for provided arguments. 41229 * 41230 * **Note:** This method does not set the "length" property of curried functions. 41231 * 41232 * @static 41233 * @memberOf _ 41234 * @category Function 41235 * @param {Function} func The function to curry. 41236 * @param {number} [arity=func.length] The arity of `func`. 41237 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 41238 * @returns {Function} Returns the new curried function. 41239 * @example 41240 * 41241 * var abc = function(a, b, c) { 41242 * return [a, b, c]; 41243 * }; 41244 * 41245 * var curried = _.curry(abc); 41246 * 41247 * curried(1)(2)(3); 41248 * // => [1, 2, 3] 41249 * 41250 * curried(1, 2)(3); 41251 * // => [1, 2, 3] 41252 * 41253 * curried(1, 2, 3); 41254 * // => [1, 2, 3] 41255 * 41256 * // using placeholders 41257 * curried(1)(_, 3)(2); 41258 * // => [1, 2, 3] 41259 */ 41260 var curry = createCurry(CURRY_FLAG); 41261 41262 /** 41263 * This method is like `_.curry` except that arguments are applied to `func` 41264 * in the manner of `_.partialRight` instead of `_.partial`. 41265 * 41266 * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic 41267 * builds, may be used as a placeholder for provided arguments. 41268 * 41269 * **Note:** This method does not set the "length" property of curried functions. 41270 * 41271 * @static 41272 * @memberOf _ 41273 * @category Function 41274 * @param {Function} func The function to curry. 41275 * @param {number} [arity=func.length] The arity of `func`. 41276 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 41277 * @returns {Function} Returns the new curried function. 41278 * @example 41279 * 41280 * var abc = function(a, b, c) { 41281 * return [a, b, c]; 41282 * }; 41283 * 41284 * var curried = _.curryRight(abc); 41285 * 41286 * curried(3)(2)(1); 41287 * // => [1, 2, 3] 41288 * 41289 * curried(2, 3)(1); 41290 * // => [1, 2, 3] 41291 * 41292 * curried(1, 2, 3); 41293 * // => [1, 2, 3] 41294 * 41295 * // using placeholders 41296 * curried(3)(1, _)(2); 41297 * // => [1, 2, 3] 41298 */ 41299 var curryRight = createCurry(CURRY_RIGHT_FLAG); 41300 41301 /** 41302 * Creates a debounced function that delays invoking `func` until after `wait` 41303 * milliseconds have elapsed since the last time the debounced function was 41304 * invoked. The debounced function comes with a `cancel` method to cancel 41305 * delayed invocations. Provide an options object to indicate that `func` 41306 * should be invoked on the leading and/or trailing edge of the `wait` timeout. 41307 * Subsequent calls to the debounced function return the result of the last 41308 * `func` invocation. 41309 * 41310 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked 41311 * on the trailing edge of the timeout only if the the debounced function is 41312 * invoked more than once during the `wait` timeout. 41313 * 41314 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) 41315 * for details over the differences between `_.debounce` and `_.throttle`. 41316 * 41317 * @static 41318 * @memberOf _ 41319 * @category Function 41320 * @param {Function} func The function to debounce. 41321 * @param {number} [wait=0] The number of milliseconds to delay. 41322 * @param {Object} [options] The options object. 41323 * @param {boolean} [options.leading=false] Specify invoking on the leading 41324 * edge of the timeout. 41325 * @param {number} [options.maxWait] The maximum time `func` is allowed to be 41326 * delayed before it is invoked. 41327 * @param {boolean} [options.trailing=true] Specify invoking on the trailing 41328 * edge of the timeout. 41329 * @returns {Function} Returns the new debounced function. 41330 * @example 41331 * 41332 * // avoid costly calculations while the window size is in flux 41333 * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); 41334 * 41335 * // invoke `sendMail` when the click event is fired, debouncing subsequent calls 41336 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { 41337 * 'leading': true, 41338 * 'trailing': false 41339 * })); 41340 * 41341 * // ensure `batchLog` is invoked once after 1 second of debounced calls 41342 * var source = new EventSource('/stream'); 41343 * jQuery(source).on('message', _.debounce(batchLog, 250, { 41344 * 'maxWait': 1000 41345 * })); 41346 * 41347 * // cancel a debounced call 41348 * var todoChanges = _.debounce(batchLog, 1000); 41349 * Object.observe(models.todo, todoChanges); 41350 *
41351 * Object.observe(models, function(changes) { 41352 * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { 41353 * todoChanges.cancel(); 41354 * } 41355 * }, ['delete']); 41356 * 41357 * // ...at some point `models.todo` is changed 41358 * models.todo.completed = true; 41359 * 41360 * // ...before 1 second has passed `models.todo` is deleted 41361 * // which cancels the debounced `todoChanges` call 41362 * delete models.todo; 41363 */ 41364 function debounce(func, wait, options) { 41365 var args, 41366 maxTimeoutId, 41367 result, 41368 stamp, 41369 thisArg, 41370 timeoutId, 41371 trailingCall, 41372 lastCalled = 0, 41373 maxWait = false, 41374 trailing = true; 41375 41376 if (typeof func != 'function') { 41377 throw new TypeError(FUNC_ERROR_TEXT); 41378 } 41379 wait = wait < 0 ? 0 : (+wait || 0); 41380 if (options === true) { 41381 var leading = true; 41382 trailing = false; 41383 } else if (isObject(options)) { 41384 leading = !!options.leading; 41385 maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); 41386 trailing = 'trailing' in options ? !!options.trailing : trailing; 41387 } 41388 41389 function cancel() { 41390 if (timeoutId) { 41391 clearTimeout(timeoutId); 41392 } 41393 if (maxTimeoutId) { 41394 clearTimeout(maxTimeoutId); 41395 } 41396 lastCalled = 0; 41397 maxTimeoutId = timeoutId = trailingCall = undefined; 41398 } 41399 41400 function complete(isCalled, id) { 41401 if (id) { 41402 clearTimeout(id); 41403 } 41404 maxTimeoutId = timeoutId = trailingCall = undefined; 41405 if (isCalled) { 41406 lastCalled = now(); 41407 result = func.apply(thisArg, args); 41408 if (!timeoutId && !maxTimeoutId) { 41409 args = thisArg = undefined; 41410 } 41411 } 41412 } 41413 41414 function delayed() { 41415 var remaining = wait - (now() - stamp); 41416 if (remaining <= 0 || remaining > wait) { 41417 complete(trailingCall, maxTimeoutId); 41418 } else { 41419 timeoutId = setTimeout(delayed, remaining); 41420 } 41421 } 41422 41423 function maxDelayed() { 41424 complete(trailing, timeoutId); 41425 } 41426 41427 function debounced() { 41428 args = arguments; 41429 stamp = now(); 41430 thisArg = this; 41431 trailingCall = trailing && (timeoutId || !leading); 41432 41433 if (maxWait === false) { 41434 var leadingCall = leading && !timeoutId; 41435 } else { 41436 if (!maxTimeoutId && !leading) { 41437 lastCalled = stamp; 41438 } 41439 var remaining = maxWait - (stamp - lastCalled), 41440 isCalled = remaining <= 0 || remaining > maxWait; 41441 41442 if (isCalled) { 41443 if (maxTimeoutId) { 41444 maxTimeoutId = clearTimeout(maxTimeoutId); 41445 } 41446 lastCalled = stamp; 41447 result = func.apply(thisArg, args); 41448 } 41449 else if (!maxTimeoutId) { 41450 maxTimeoutId = setTimeout(maxDelayed, remaining); 41451 } 41452 } 41453 if (isCalled && timeoutId) { 41454 timeoutId = clearTimeout(timeoutId); 41455 } 41456 else if (!timeoutId && wait !== maxWait) { 41457 timeoutId = setTimeout(delayed, wait); 41458 } 41459 if (leadingCall) { 41460 isCalled = true; 41461 result = func.apply(thisArg, args); 41462 } 41463 if (isCalled && !timeoutId && !maxTimeoutId) { 41464 args = thisArg = undefined; 41465 } 41466 return result; 41467 } 41468 debounced.cancel = cancel; 41469 return debounced; 41470 } 41471 41472 /** 41473 * Defers invoking the `func` until the current call stack has cleared. Any 41474 * additional arguments are provided to `func` when it is invoked. 41475 * 41476 * @static 41477 * @memberOf _ 41478 * @category Function 41479 * @param {Function} func The function to defer. 41480 * @param {...*} [args] The arguments to invoke the function with. 41481 * @returns {number} Returns the timer id. 41482 * @example 41483 * 41484 * _.defer(function(text) { 41485 * console.log(text); 41486 * }, 'deferred'); 41487 * // logs 'deferred' after one or more milliseconds 41488 */ 41489 var defer = restParam(function(func, args) { 41490 return baseDelay(func, 1, args); 41491 }); 41492 41493 /** 41494 * Invokes `func` after `wait` milliseconds. Any additional arguments are 41495 * provided to `func` when it is invoked. 41496 * 41497 * @static 41498 * @memberOf _ 41499 * @category Function 41500 * @param {Function} func The function to delay. 41501 * @param {number} wait The number of milliseconds to delay invocation. 41502 * @param {...*} [args] The arguments to invoke the function with. 41503 * @returns {number} Returns the timer id. 41504 * @example 41505 * 41506 * _.delay(function(text) { 41507 * console.log(text); 41508 * }, 1000, 'later'); 41509 * // => logs 'later' after one second 41510 */
41511 var delay = restParam(function(func, wait, args) { 41512 return baseDelay(func, wait, args); 41513 }); 41514 41515 /** 41516 * Creates a function that returns the result of invoking the provided 41517 * functions with the `this` binding of the created function, where each 41518 * successive invocation is supplied the return value of the previous. 41519 * 41520 * @static 41521 * @memberOf _ 41522 * @category Function 41523 * @param {...Function} [funcs] Functions to invoke. 41524 * @returns {Function} Returns the new function. 41525 * @example 41526 * 41527 * function square(n) { 41528 * return n * n; 41529 * } 41530 * 41531 * var addSquare = _.flow(_.add, square); 41532 * addSquare(1, 2); 41533 * // => 9 41534 */ 41535 var flow = createFlow(); 41536 41537 /** 41538 * This method is like `_.flow` except that it creates a function that 41539 * invokes the provided functions from right to left. 41540 * 41541 * @static 41542 * @memberOf _ 41543 * @alias backflow, compose 41544 * @category Function 41545 * @param {...Function} [funcs] Functions to invoke. 41546 * @returns {Function} Returns the new function. 41547 * @example 41548 * 41549 * function square(n) { 41550 * return n * n; 41551 * } 41552 * 41553 * var addSquare = _.flowRight(square, _.add); 41554 * addSquare(1, 2); 41555 * // => 9 41556 */ 41557 var flowRight = createFlow(true); 41558 41559 /** 41560 * Creates a function that memoizes the result of `func`. If `resolver` is 41561 * provided it determines the cache key for storing the result based on the 41562 * arguments provided to the memoized function. By default, the first argument 41563 * provided to the memoized function is coerced to a string and used as the 41564 * cache key. The `func` is invoked with the `this` binding of the memoized 41565 * function. 41566 * 41567 * **Note:** The cache is exposed as the `cache` property on the memoized 41568 * function. Its creation may be customized by replacing the `_.memoize.Cache` 41569 * constructor with one whose instances implement the [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object) 41570 * method interface of `get`, `has`, and `set`. 41571 * 41572 * @static 41573 * @memberOf _ 41574 * @category Function 41575 * @param {Function} func The function to have its output memoized. 41576 * @param {Function} [resolver] The function to resolve the cache key. 41577 * @returns {Function} Returns the new memoizing function. 41578 * @example 41579 * 41580 * var upperCase = _.memoize(function(string) { 41581 * return string.toUpperCase(); 41582 * }); 41583 * 41584 * upperCase('fred'); 41585 * // => 'FRED' 41586 * 41587 * // modifying the result cache 41588 * upperCase.cache.set('fred', 'BARNEY'); 41589 * upperCase('fred'); 41590 * // => 'BARNEY' 41591 * 41592 * // replacing `_.memoize.Cache` 41593 * var object = { 'user': 'fred' }; 41594 * var other = { 'user': 'barney' }; 41595 * var identity = _.memoize(_.identity); 41596 * 41597 * identity(object); 41598 * // => { 'user': 'fred' } 41599 * identity(other); 41600 * // => { 'user': 'fred' } 41601 * 41602 * _.memoize.Cache = WeakMap; 41603 * var identity = _.memoize(_.identity); 41604 * 41605 * identity(object); 41606 * // => { 'user': 'fred' } 41607 * identity(other); 41608 * // => { 'user': 'barney' } 41609 */ 41610 function memoize(func, resolver) { 41611 if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { 41612 throw new TypeError(FUNC_ERROR_TEXT); 41613 } 41614 var memoized = function() { 41615 var args = arguments, 41616 key = resolver ? resolver.apply(this, args) : args[0], 41617 cache = memoized.cache; 41618 41619 if (cache.has(key)) { 41620 return cache.get(key); 41621 } 41622 var result = func.apply(this, args); 41623 memoized.cache = cache.set(key, result); 41624 return result; 41625 }; 41626 memoized.cache = new memoize.Cache; 41627 return memoized; 41628 } 41629 41630 /** 41631 * Creates a function that runs each argument through a corresponding 41632 * transform function. 41633 * 41634 * @static 41635 * @memberOf _ 41636 * @category Function 41637 * @param {Function} func The function to wrap. 41638 * @param {...(Function|Function[])} [transforms] The functions to transform 41639 * arguments, specified as individual functions or arrays of functions. 41640 * @returns {Function} Returns the new function. 41641 * @example 41642 * 41643 * function doubled(n) { 41644 * return n * 2; 41645 * } 41646 * 41647 * function square(n) { 41648 * return n * n; 41649 * } 41650 * 41651 * var modded = _.modArgs(function(x, y) { 41652 * return [x, y]; 41653 * }, square, doubled); 41654 * 41655 * modded(1, 2); 41656 * // => [1, 4] 41657 * 41658 * modded(5, 10); 41659 * // => [25, 20] 41660 */ 41661 var modArgs = restParam(function(func, transforms) { 41662 transforms = baseFlatten(transforms); 41663 if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { 41664 throw new TypeError(FUNC_ERROR_TEXT); 41665 } 41666 var length = transforms.length; 41667 return restParam(function(args) { 41668 var index = nativeMin(args.length, length); 41669 while (index--) { 41670 args[index] = transforms[index](args[index]); 41671 } 41672 return func.apply(this, args); 41673 }); 41674 }); 41675 41676 /** 41677 * Creates a function that negates the result of the predicate `func`. The 41678 * `func` predicate is invoked with the `this` binding and arguments of the 41679 * created function. 41680 * 41681 * @static 41682 * @memberOf _ 41683 * @category Function 41684 * @param {Function} predicate The predicate to negate. 41685 * @returns {Function} Returns the new function. 41686 * @example 41687 * 41688 * function isEven(n) { 41689 * return n % 2 == 0; 41690 * } 41691 * 41692 * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); 41693 * // => [1, 3, 5] 41694 */ 41695 function negate(predicate) { 41696 if (typeof predicate != 'function') { 41697 throw new TypeError(FUNC_ERROR_TEXT); 41698 } 41699 return function() { 41700 return !predicate.apply(this, arguments); 41701 }; 41702 } 41703 41704 /** 41705 * Creates a function that is restricted to invoking `func` once. Repeat calls 41706 * to the function return the value of the first call. The `func` is invoked 41707 * with the `this` binding and arguments of the created function. 41708 * 41709 * @static 41710 * @memberOf _ 41711 * @category Function 41712 * @param {Function} func The function to restrict. 41713 * @returns {Function} Returns the new restricted function. 41714 * @example 41715 * 41716 * var initialize = _.once(createApplication); 41717 * initialize(); 41718 * initialize(); 41719 * // `initialize` invokes `createApplication` once 41720 */ 41721 function once(func) { 41722 return before(2, func); 41723 } 41724 41725 /** 41726 * Creates a function that invokes `func` with `partial` arguments prepended 41727 * to those provided to the new function. This method is like `_.bind` except 41728 * it does **not** alter the `this` binding. 41729 * 41730 * The `_.partial.placeholder` value, which defaults to `_` in monolithic 41731 * builds, may be used as a placeholder for partially applied arguments. 41732 * 41733 * **Note:** This method does not set the "length" property of partially 41734 * applied functions. 41735 * 41736 * @static 41737 * @memberOf _ 41738 * @category Function 41739 * @param {Function} func The function to partially apply arguments to. 41740 * @param {...*} [partials] The arguments to be partially applied. 41741 * @returns {Function} Returns the new partially applied function. 41742 * @example 41743 * 41744 * var greet = function(greeting, name) { 41745 * return greeting + ' ' + name; 41746 * }; 41747 * 41748 * var sayHelloTo = _.partial(greet, 'hello'); 41749 * sayHelloTo('fred'); 41750 * // => 'hello fred' 41751 * 41752 * // using placeholders 41753 * var greetFred = _.partial(greet, _, 'fred'); 41754 * greetFred('hi'); 41755 * // => 'hi fred' 41756 */
41757 var partial = createPartial(PARTIAL_FLAG); 41758 41759 /** 41760 * This method is like `_.partial` except that partially applied arguments 41761 * are appended to those provided to the new function. 41762 * 41763 * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic 41764 * builds, may be used as a placeholder for partially applied arguments. 41765 * 41766 * **Note:** This method does not set the "length" property of partially 41767 * applied functions. 41768 * 41769 * @static 41770 * @memberOf _ 41771 * @category Function 41772 * @param {Function} func The function to partially apply arguments to. 41773 * @param {...*} [partials] The arguments to be partially applied. 41774 * @returns {Function} Returns the new partially applied function. 41775 * @example 41776 * 41777 * var greet = function(greeting, name) { 41778 * return greeting + ' ' + name; 41779 * }; 41780 * 41781 * var greetFred = _.partialRight(greet, 'fred'); 41782 * greetFred('hi'); 41783 * // => 'hi fred' 41784 * 41785 * // using placeholders 41786 * var sayHelloTo = _.partialRight(greet, 'hello', _); 41787 * sayHelloTo('fred'); 41788 * // => 'hello fred' 41789 */ 41790 var partialRight = createPartial(PARTIAL_RIGHT_FLAG); 41791 41792 /** 41793 * Creates a function that invokes `func` with arguments arranged according 41794 * to the specified indexes where the argument value at the first index is 41795 * provided as the first argument, the argument value at the second index is 41796 * provided as the second argument, and so on. 41797 * 41798 * @static 41799 * @memberOf _ 41800 * @category Function 41801 * @param {Function} func The function to rearrange arguments for. 41802 * @param {...(number|number[])} indexes The arranged argument indexes, 41803 * specified as individual indexes or arrays of indexes. 41804 * @returns {Function} Returns the new function. 41805 * @example 41806 * 41807 * var rearged = _.rearg(function(a, b, c) { 41808 * return [a, b, c]; 41809 * }, 2, 0, 1); 41810 * 41811 * rearged('b', 'c', 'a') 41812 * // => ['a', 'b', 'c'] 41813 * 41814 * var map = _.rearg(_.map, [1, 0]); 41815 * map(function(n) { 41816 * return n * 3; 41817 * }, [1, 2, 3]); 41818 * // => [3, 6, 9] 41819 */ 41820 var rearg = restParam(function(func, indexes) { 41821 return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes)); 41822 }); 41823 41824 /** 41825 * Creates a function that invokes `func` with the `this` binding of the 41826 * created function and arguments from `start` and beyond provided as an array. 41827 * 41828 * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). 41829 * 41830 * @static 41831 * @memberOf _ 41832 * @category Function 41833 * @param {Function} func The function to apply a rest parameter to. 41834 * @param {number} [start=func.length-1] The start position of the rest parameter. 41835 * @returns {Function} Returns the new function. 41836 * @example 41837 * 41838 * var say = _.restParam(function(what, names) { 41839 * return what + ' ' + _.initial(names).join(', ') + 41840 * (_.size(names) > 1 ? ', & ' : '') + _.last(names); 41841 * }); 41842 * 41843 * say('hello', 'fred', 'barney', 'pebbles'); 41844 * // => 'hello fred, barney, & pebbles' 41845 */ 41846 function restParam(func, start) { 41847 if (typeof func != 'function') { 41848 throw new TypeError(FUNC_ERROR_TEXT); 41849 } 41850 start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); 41851 return function() { 41852 var args = arguments, 41853 index = -1, 41854 length = nativeMax(args.length - start, 0), 41855 rest = Array(length); 41856 41857 while (++index < length) { 41858 rest[index] = args[start + index]; 41859 } 41860 switch (start) { 41861 case 0: return func.call(this, rest); 41862 case 1: return func.call(this, args[0], rest); 41863 case 2: return func.call(this, args[0], args[1], rest); 41864 } 41865 var otherArgs = Array(start + 1); 41866 index = -1; 41867 while (++index < start) { 41868 otherArgs[index] = args[index]; 41869 } 41870 otherArgs[start] = rest; 41871 return func.apply(this, otherArgs); 41872 }; 41873 } 41874 41875 /** 41876 * Creates a function that invokes `func` with the `this` binding of the created 41877 * function and an array of arguments much like [`Function#apply`](https://es5.github.io/#x15.3.4.3). 41878 * 41879 * **Note:** This method is based on the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). 41880 * 41881 * @static 41882 * @memberOf _ 41883 * @category Function 41884 * @param {Function} func The function to spread arguments over. 41885 * @returns {Function} Returns the new function. 41886 * @example 41887 * 41888 * var say = _.spread(function(who, what) { 41889 * return who + ' says ' + what; 41890 * }); 41891 * 41892 * say(['fred', 'hello']); 41893 * // => 'fred says hello' 41894 * 41895 * // with a Promise 41896 * var numbers = Promise.all([ 41897 * Promise.resolve(40), 41898 * Promise.resolve(36) 41899 * ]); 41900 * 41901 * numbers.then(_.spread(function(x, y) { 41902 * return x + y; 41903 * })); 41904 * // => a Promise of 76 41905 */ 41906 function spread(func) { 41907 if (typeof func != 'function') { 41908 throw new TypeError(FUNC_ERROR_TEXT); 41909 } 41910 return function(array) { 41911 return func.apply(this, array); 41912 }; 41913 } 41914 41915 /** 41916 * Creates a throttled function that only invokes `func` at most once per 41917 * every `wait` milliseconds. The throttled function comes with a `cancel` 41918 * method to cancel delayed invocations. Provide an options object to indicate 41919 * that `func` should be invoked on the leading and/or trailing edge of the 41920 * `wait` timeout. Subsequent calls to the throttled function return the 41921 * result of the last `func` call. 41922 * 41923 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked 41924 * on the trailing edge of the timeout only if the the throttled function is 41925 * invoked more than once during the `wait` timeout. 41926 * 41927 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) 41928 * for details over the differences between `_.throttle` and `_.debounce`. 41929 * 41930 * @static 41931 * @memberOf _ 41932 * @category Function 41933 * @param {Function} func The function to throttle. 41934 * @param {number} [wait=0] The number of milliseconds to throttle invocations to. 41935 * @param {Object} [options] The options object. 41936 * @param {boolean} [options.leading=true] Specify invoking on the leading 41937 * edge of the timeout. 41938 * @param {boolean} [options.trailing=true] Specify invoking on the trailing 41939 * edge of the timeout. 41940 * @returns {Function} Returns the new throttled function. 41941 * @example 41942 * 41943 * // avoid excessively updating the position while scrolling 41944 * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); 41945 * 41946 * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes 41947 * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { 41948 * 'trailing': false 41949 * })); 41950 * 41951 * // cancel a trailing throttled call 41952 * jQuery(window).on('popstate', throttled.cancel); 41953 */ 41954 function throttle(func, wait, options) { 41955 var leading = true, 41956 trailing = true; 41957 41958 if (typeof func != 'function') { 41959 throw new TypeError(FUNC_ERROR_TEXT); 41960 } 41961 if (options === false) { 41962 leading = false;
41963 } else if (isObject(options)) { 41964 leading = 'leading' in options ? !!options.leading : leading; 41965 trailing = 'trailing' in options ? !!options.trailing : trailing; 41966 } 41967 return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing }); 41968 } 41969 41970 /** 41971 * Creates a function that provides `value` to the wrapper function as its 41972 * first argument. Any additional arguments provided to the function are 41973 * appended to those provided to the wrapper function. The wrapper is invoked 41974 * with the `this` binding of the created function. 41975 * 41976 * @static 41977 * @memberOf _ 41978 * @category Function 41979 * @param {*} value The value to wrap. 41980 * @param {Function} wrapper The wrapper function. 41981 * @returns {Function} Returns the new function. 41982 * @example 41983 * 41984 * var p = _.wrap(_.escape, function(func, text) { 41985 * return '<p>' + func(text) + '</p>'; 41986 * }); 41987 * 41988 * p('fred, barney, & pebbles'); 41989 * // => '<p>fred, barney, & pebbles</p>' 41990 */ 41991 function wrap(value, wrapper) { 41992 wrapper = wrapper == null ? identity : wrapper; 41993 return createWrapper(wrapper, PARTIAL_FLAG, undefined, [value], []); 41994 } 41995 41996 /*------------------------------------------------------------------------*/ 41997 41998 /** 41999 * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, 42000 * otherwise they are assigned by reference. If `customizer` is provided it is 42001 * invoked to produce the cloned values. If `customizer` returns `undefined` 42002 * cloning is handled by the method instead. The `customizer` is bound to 42003 * `thisArg` and invoked with two argument; (value [, index|key, object]). 42004 * 42005 * **Note:** This method is loosely based on the 42006 * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). 42007 * The enumerable properties of `arguments` objects and objects created by 42008 * constructors other than `Object` are cloned to plain `Object` objects. An 42009 * empty object is returned for uncloneable values such as functions, DOM nodes, 42010 * Maps, Sets, and WeakMaps. 42011 * 42012 * @static 42013 * @memberOf _ 42014 * @category Lang 42015 * @param {*} value The value to clone. 42016 * @param {boolean} [isDeep] Specify a deep clone. 42017 * @param {Function} [customizer] The function to customize cloning values. 42018 * @param {*} [thisArg] The `this` binding of `customizer`. 42019 * @returns {*} Returns the cloned value. 42020 * @example 42021 * 42022 * var users = [ 42023 * { 'user': 'barney' }, 42024 * { 'user': 'fred' } 42025 * ]; 42026 * 42027 * var shallow = _.clone(users); 42028 * shallow[0] === users[0]; 42029 * // => true 42030 * 42031 * var deep = _.clone(users, true); 42032 * deep[0] === users[0]; 42033 * // => false 42034 * 42035 * // using a customizer callback 42036 * var el = _.clone(document.body, function(value) { 42037 * if (_.isElement(value)) { 42038 * return value.cloneNode(false); 42039 * } 42040 * }); 42041 * 42042 * el === document.body 42043 * // => false 42044 * el.nodeName 42045 * // => BODY 42046 * el.childNodes.length; 42047 * // => 0 42048 */ 42049 function clone(value, isDeep, customizer, thisArg) { 42050 if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { 42051 isDeep = false; 42052 } 42053 else if (typeof isDeep == 'function') { 42054 thisArg = customizer; 42055 customizer = isDeep; 42056 isDeep = false; 42057 } 42058 return typeof customizer == 'function' 42059 ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 1)) 42060 : baseClone(value, isDeep); 42061 } 42062 42063 /** 42064 * Creates a deep clone of `value`. If `customizer` is provided it is invoked 42065 * to produce the cloned values. If `customizer` returns `undefined` cloning 42066 * is handled by the method instead. The `customizer` is bound to `thisArg` 42067 * and invoked with two argument; (value [, index|key, object]). 42068 * 42069 * **Note:** This method is loosely based on the 42070 * [structured clone algorithm](http://www.w3.org/TR/html5/infrastru
42070cture.html#internal-structured-cloning-algorithm). 42071 * The enumerable properties of `arguments` objects and objects created by 42072 * constructors other than `Object` are cloned to plain `Object` objects. An 42073 * empty object is returned for uncloneable values such as functions, DOM nodes, 42074 * Maps, Sets, and WeakMaps. 42075 * 42076 * @static 42077 * @memberOf _ 42078 * @category Lang 42079 * @param {*} value The value to deep clone. 42080 * @param {Function} [customizer] The function to customize cloning values. 42081 * @param {*} [thisArg] The `this` binding of `customizer`. 42082 * @returns {*} Returns the deep cloned value. 42083 * @example 42084 * 42085 * var users = [ 42086 * { 'user': 'barney' }, 42087 * { 'user': 'fred' } 42088 * ]; 42089 * 42090 * var deep = _.cloneDeep(users); 42091 * deep[0] === users[0]; 42092 * // => false 42093 * 42094 * // using a customizer callback 42095 * var el = _.cloneDeep(document.body, function(value) { 42096 * if (_.isElement(value)) { 42097 * return value.cloneNode(true); 42098 * } 42099 * }); 42100 * 42101 * el === document.body 42102 * // => false 42103 * el.nodeName 42104 * // => BODY 42105 * el.childNodes.length; 42106 * // => 20 42107 */ 42108 function cloneDeep(value, customizer, thisArg) { 42109 return typeof customizer == 'function' 42110 ? baseClone(value, true, bindCallback(customizer, thisArg, 1)) 42111 : baseClone(value, true); 42112 } 42113 42114 /** 42115 * Checks if `value` is greater than `other`. 42116 * 42117 * @static 42118 * @memberOf _ 42119 * @category Lang 42120 * @param {*} value The value to compare. 42121 * @param {*} other The other value to compare. 42122 * @returns {boolean} Returns `true` if `value` is greater than `other`, else `false`. 42123 * @example 42124 * 42125 * _.gt(3, 1); 42126 * // => true 42127 * 42128 * _.gt(3, 3); 42129 * // => false 42130 * 42131 * _.gt(1, 3); 42132 * // => false 42133 */ 42134 function gt(value, other) { 42135 return value > other; 42136 } 42137 42138 /** 42139 * Checks if `value` is greater than or equal to `other`. 42140 * 42141 * @static 42142 * @memberOf _ 42143 * @category Lang 42144 * @param {*} value The value to compare. 42145 * @param {*} other The other value to compare. 42146 * @returns {boolean} Returns `true` if `value` is greater than or equal to `other`, else `false`. 42147 * @example 42148 * 42149 * _.gte(3, 1); 42150 * // => true 42151 * 42152 * _.gte(3, 3); 42153 * // => true 42154 * 42155 * _.gte(1, 3); 42156 * // => false 42157 */ 42158 function gte(value, other) { 42159 return value >= other; 42160 } 42161 42162 /** 42163 * Checks if `value` is classified as an `arguments` object. 42164 * 42165 * @static 42166 * @memberOf _ 42167 * @category Lang 42168 * @param {*} value The value to check. 42169 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42170 * @example 42171 * 42172 * _.isArguments(function() { return arguments; }()); 42173 * // => true 42174 * 42175 * _.isArguments([1, 2, 3]); 42176 * // => false 42177 */ 42178 function isArguments(value) { 42179 return isObjectLike(value) && isArrayLike(value) && 42180 hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); 42181 } 42182 42183 /** 42184 * Checks if `value` is classified as an `Array` object. 42185 * 42186 * @static 42187 * @memberOf _ 42188 * @category Lang 42189 * @param {*} value The value to check. 42190 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42191 * @example 42192 * 42193 * _.isArray([1, 2, 3]); 42194 * // => true 42195 * 42196 * _.isArray(function() { return arguments; }()); 42197 * // => false 42198 */ 42199 var isArray = nativeIsArray || function(value) { 42200 return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; 42201 }; 42202 42203 /** 42204 * Checks if `value` is classified as a boolean primitive or object. 42205 * 42206 * @static 42207 * @memberOf _ 42208 * @category Lang 42209 * @param {*} value The value to check. 42210 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42211 * @example 42212 * 42213 * _.isBoolean(false); 42214 * // => true 42215 * 42216 * _.isBoolean(null); 42217 * // => false 42218 */ 42219 function isBoolean(value) { 42220 return value === true || value === false || (isObjectLike(value) && objToString.call(value) == boolTag); 42221 } 42222 42223 /** 42224 * Checks if `value` is classified as a `Date` object. 42225 * 42226 * @static 42227 * @memberOf _ 42228 * @category Lang 42229 * @param {*} value The value to check. 42230 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42231 * @example 42232 * 42233 * _.isDate(new Date); 42234 * // => true 42235 * 42236 * _.isDate('Mon April 23 2012'); 42237 * // => false 42238 */ 42239 function isDate(value) { 42240 return isObjectLike(value) && objToString.call(value) == dateTag; 42241 } 42242 42243 /** 42244 * Checks if `value` is a DOM element. 42245 * 42246 * @static 42247 * @memberOf _ 42248 * @category Lang 42249 * @param {*} value The value to check. 42250 * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. 42251 * @example 42252 * 42253 * _.isElement(document.body); 42254 * // => true 42255 * 42256 * _.isElement('<body>'); 42257 * // => false 42258 */ 42259 function isElement(value) { 42260 return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value); 42261 } 42262 42263 /** 42264 * Checks if `value` is empty. A value is considered empty unless it is an 42265 * `arguments` object, array, string, or jQuery-like collection with a length 42266 * greater than `0` or an object with own enumerable properties. 42267 * 42268 * @static 42269 * @memberOf _ 42270 * @category Lang 42271 * @param {Array|Object|string} value The value to inspect. 42272 * @returns {boolean} Returns `true` if `value` is empty, else `false`. 42273 * @example 42274 * 42275 * _.isEmpty(null); 42276 * // => true 42277 * 42278 * _.isEmpty(true); 42279 * // => true 42280 * 42281 * _.isEmpty(1); 42282 * // => true 42283 * 42284 * _.isEmpty([1, 2, 3]); 42285 * // => false 42286 * 42287 * _.isEmpty({ 'a': 1 }); 42288 * // => false 42289 */ 42290 function isEmpty(value) { 42291 if (value == null) { 42292 return true; 42293 } 42294 if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) || 42295 (isObjectLike(value) && isFunction(value.splice)))) { 42296 return !value.length; 42297 } 42298 return !keys(value).length; 42299 } 42300 42301 /** 42302 * Performs a deep comparison between two values to determine if they are 42303 * equivalent. If `customizer` is provided it is invoked to compare values. 42304 * If `customizer` returns `undefined` comparisons are handled by the method 42305 * instead. The `customizer` is bound to `thisArg` and invoked with three 42306 * arguments: (value, other [, index|key]). 42307 * 42308 * **Note:** This method supports comparing arrays, booleans, `Date` objects, 42309 * numbers, `Object` objects, regexes, and strings. Objects are compared by 42310 * their own, not inherited, enumerable properties. Functions and DOM nodes 42311 * are **not** supported. Provide a customizer function to extend support 42312 * for comparing other values. 42313 * 42314 * @static 42315 * @memberOf _ 42316 * @alias eq 42317 * @category Lang 42318 * @param {*} value The value to compare. 42319 * @param {*} other The other value to compare. 42320 * @param {Function} [customizer] The function to customize value comparisons. 42321 * @param {*} [thisArg] The `this` binding of `customizer`. 42322 * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 42323 * @example 42324 * 42325 * var object = { 'user': 'fred' }; 42326 * var other = { 'user': 'fred' }; 42327 * 42328 * object == other; 42329 * // => false 42330 * 42331 * _.isEqual(object, other); 42332 * // => true 42333 * 42334 * // using a customizer callback 42335 * var array = ['hello', 'goodbye']; 42336 * var other = ['hi', 'goodbye']; 42337 * 42338 * _.isEqual(array, other, function(value, other) { 42339 * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { 42340 * return true; 42341 * } 42342 * }); 42343 * // => true 42344 */ 42345 function isEqual(value, other, customizer, thisArg) { 42346 customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; 42347 var result = customizer ? customizer(value, other) : undefined; 42348 return result === undefined ? baseIsEqual(value, other, customizer) : !!result; 42349 } 42350 42351 /** 42352 * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, 42353 * `SyntaxError`, `TypeError`, or `URIError` object. 42354 * 42355 * @static 42356 * @memberOf _ 42357 * @category Lang 42358 * @param {*} value The value to check. 42359 * @returns {boolean} Returns `true` if `value` is an error object, else `false`. 42360 * @example 42361 * 42362 * _.isError(new Error); 42363 * // => true 42364 * 42365 * _.isError(Error); 42366 * // => false 42367 */ 42368 function isError(value) { 42369 return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag; 42370 } 42371 42372 /** 42373 * Checks if `value` is a finite primitive number. 42374 * 42375 * **Note:** This method is based on [`Number.isFinite`](http://ecma-international.org/ecma-262/6.0/#sec-number.isfinite). 42376 * 42377 * @static 42378 * @memberOf _ 42379 * @category Lang 42380 * @param {*} value The value to check. 42381 * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. 42382 * @example 42383 * 42384 * _.isFinite(10); 42385 * // => true 42386 * 42387 * _.isFinite('10'); 42388 * // => false 42389 * 42390 * _.isFinite(true); 42391 * // => false 42392 * 42393 * _.isFinite(Object(10)); 42394 * // => false 42395 * 42396 * _.isFinite(Infinity); 42397 * // => false 42398 */ 42399 function isFinite(value) { 42400 return typeof value == 'number' && nativeIsFinite(value); 42401 } 42402 42403 /** 42404 * Checks if `value` is classified as a `Function` object. 42405 * 42406 * @static 42407 * @memberOf _ 42408 * @category Lang 42409 * @param {*} value The value to check. 42410 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42411 * @example 42412 * 42413 * _.isFunction(_); 42414 * // => true 42415 * 42416 * _.isFunction(/abc/); 42417 * // => false 42418 */ 42419 function isFunction(value) {
42420 // The use of `Object#toString` avoids issues with the `typeof` operator 42421 // in older versions of Chrome and Safari which return 'function' for regexes 42422 // and Safari 8 equivalents which return 'object' for typed array constructors. 42423 return isObject(value) && objToString.call(value) == funcTag; 42424 } 42425 42426 /** 42427 * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. 42428 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 42429 * 42430 * @static 42431 * @memberOf _ 42432 * @category Lang 42433 * @param {*} value The value to check. 42434 * @returns {boolean} Returns `true` if `value` is an object, else `false`. 42435 * @example 42436 * 42437 * _.isObject({}); 42438 * // => true 42439 * 42440 * _.isObject([1, 2, 3]); 42441 * // => true 42442 * 42443 * _.isObject(1); 42444 * // => false 42445 */ 42446 function isObject(value) { 42447 // Avoid a V8 JIT bug in Chrome 19-20. 42448 // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. 42449 var type = typeof value; 42450 return !!value && (type == 'object' || type == 'function'); 42451 } 42452 42453 /** 42454 * Performs a deep comparison between `object` and `source` to determine if 42455 * `object` contains equivalent property values. If `customizer` is provided 42456 * it is invoked to compare values. If `customizer` returns `undefined` 42457 * comparisons are handled by the method instead. The `customizer` is bound 42458 * to `thisArg` and invoked with three arguments: (value, other, index|key). 42459 * 42460 * **Note:** This method supports comparing properties of arrays, booleans, 42461 * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions 42462 * and DOM nodes are **not** supported. Provide a customizer function to extend 42463 * support for comparing other values. 42464 * 42465 * @static 42466 * @memberOf _ 42467 * @category Lang 42468 * @param {Object} object The object to inspect. 42469 * @param {Object} source The object of property values to match. 42470 * @param {Function} [customizer] The function to customize value comparisons. 42471 * @param {*} [thisArg] The `this` binding of `customizer`. 42472 * @returns {boolean} Returns `true` if `object` is a match, else `false`. 42473 * @example 42474 * 42475 * var object = { 'user': 'fred', 'age': 40 }; 42476 * 42477 * _.isMatch(object, { 'age': 40 }); 42478 * // => true 42479 * 42480 * _.isMatch(object, { 'age': 36 }); 42481 * // => false 42482 * 42483 * // using a customizer callback 42484 * var object = { 'greeting': 'hello' }; 42485 * var source = { 'greeting': 'hi' }; 42486 * 42487 * _.isMatch(object, source, function(value, other) { 42488 * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; 42489 * }); 42490 * // => true 42491 */ 42492 function isMatch(object, source, customizer, thisArg) { 42493 customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; 42494 return baseIsMatch(object, getMatchData(source), customizer); 42495 } 42496 42497 /** 42498 * Checks if `value` is `NaN`. 42499 * 42500 * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4) 42501 * which returns `true` for `undefined` and other non-numeric values. 42502 * 42503 * @static 42504 * @memberOf _ 42505 * @category Lang 42506 * @param {*} value The value to check. 42507 * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. 42508 * @example 42509 * 42510 * _.isNaN(NaN); 42511 * // => true 42512 * 42513 * _.isNaN(new Number(NaN)); 42514 * // => true 42515 * 42516 * isNaN(undefined); 42517 * // => true 42518 * 42519 * _.isNaN(undefined); 42520 * // => false 42521 */ 42522 function isNaN(value) { 42523 // An `NaN` primitive is the only value that is not equal to itself. 42524 // Perform the `toStringTag` check first to avoid errors with some host objects in IE. 42525 return isNumber(value) && value != +value; 42526 } 42527 42528 /** 42529 * Checks if `value` is a native function. 42530 * 42531 * @static 42532 * @memberOf _ 42533 * @category Lang 42534 * @param {*} value The value to check. 42535 * @returns {boolean} Returns `true` if `value` is a native function, else `false`. 42536 * @example 42537 * 42538 * _.isNative(Array.prototype.push); 42539 * // => true 42540 * 42541 * _.isNative(_); 42542 * // => false 42543 */ 42544 function isNative(value) { 42545 if (value == null) { 42546 return false;
vendor: 4,241 bytes, lines 42547-42692
42547 } 42548 if (isFunction(value)) { 42549 return reIsNative.test(fnToString.call(value)); 42550 } 42551 return isObjectLike(value) && reIsHostCtor.test(value); 42552 } 42553 42554 /** 42555 * Checks if `value` is `null`. 42556 * 42557 * @static 42558 * @memberOf _ 42559 * @category Lang 42560 * @param {*} value The value to check. 42561 * @returns {boolean} Returns `true` if `value` is `null`, else `false`. 42562 * @example 42563 * 42564 * _.isNull(null); 42565 * // => true 42566 * 42567 * _.isNull(void 0); 42568 * // => false 42569 */ 42570 function isNull(value) { 42571 return value === null; 42572 } 42573 42574 /** 42575 * Checks if `value` is classified as a `Number` primitive or object. 42576 * 42577 * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified 42578 * as numbers, use the `_.isFinite` method. 42579 * 42580 * @static 42581 * @memberOf _ 42582 * @category Lang 42583 * @param {*} value The value to check. 42584 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42585 * @example 42586 * 42587 * _.isNumber(8.4); 42588 * // => true 42589 * 42590 * _.isNumber(NaN); 42591 * // => true 42592 * 42593 * _.isNumber('8.4'); 42594 * // => false 42595 */ 42596 function isNumber(value) { 42597 return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag); 42598 } 42599 42600 /** 42601 * Checks if `value` is a plain object, that is, an object created by the 42602 * `Object` constructor or one with a `[[Prototype]]` of `null`. 42603 * 42604 * **Note:** This method assumes objects created by the `Object` constructor 42605 * have no inherited enumerable properties. 42606 * 42607 * @static 42608 * @memberOf _ 42609 * @category Lang 42610 * @param {*} value The value to check. 42611 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. 42612 * @example 42613 * 42614 * function Foo() { 42615 * this.a = 1; 42616 * } 42617 * 42618 * _.isPlainObject(new Foo); 42619 * // => false 42620 * 42621 * _.isPlainObject([1, 2, 3]); 42622 * // => false 42623 * 42624 * _.isPlainObject({ 'x': 0, 'y': 0 }); 42625 * // => true 42626 * 42627 * _.isPlainObject(Object.create(null)); 42628 * // => true 42629 */ 42630 function isPlainObject(value) { 42631 var Ctor; 42632 42633 // Exit early for non `Object` objects. 42634 if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) || 42635 (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { 42636 return false; 42637 } 42638 // IE < 9 iterates inherited properties before own properties. If the first 42639 // iterated property is an object's own property then there are no inherited 42640 // enumerable properties. 42641 var result; 42642 // In most environments an object's own properties are iterated before 42643 // its inherited properties. If the last iterated property is an object's 42644 // own property then there are no inherited enumerable properties. 42645 baseForIn(value, function(subValue, key) { 42646 result = key; 42647 }); 42648 return result === undefined || hasOwnProperty.call(value, result); 42649 } 42650 42651 /** 42652 * Checks if `value` is classified as a `RegExp` object. 42653 * 42654 * @static 42655 * @memberOf _ 42656 * @category Lang 42657 * @param {*} value The value to check. 42658 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42659 * @example 42660 * 42661 * _.isRegExp(/abc/); 42662 * // => true 42663 * 42664 * _.isRegExp('/abc/'); 42665 * // => false 42666 */ 42667 function isRegExp(value) { 42668 return isObject(value) && objToString.call(value) == regexpTag; 42669 } 42670 42671 /** 42672 * Checks if `value` is classified as a `String` primitive or object. 42673 * 42674 * @static 42675 * @memberOf _ 42676 * @category Lang 42677 * @param {*} value The value to check. 42678 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42679 * @example 42680 * 42681 * _.isString('abc'); 42682 * // => true 42683 * 42684 * _.isString(1); 42685 * // => false 42686 */ 42687 function isString(value) { 42688 return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); 42689 } 42690 42691 /** 42692 * Checks if `value` is classified as a typed array.
42693 * 42694 * @static 42695 * @memberOf _ 42696 * @category Lang 42697 * @param {*} value The value to check. 42698 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 42699 * @example 42700 * 42701 * _.isTypedArray(new Uint8Array); 42702 * // => true 42703 * 42704 * _.isTypedArray([]); 42705 * // => false 42706 */ 42707 function isTypedArray(value) { 42708 return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; 42709 } 42710 42711 /** 42712 * Checks if `value` is `undefined`. 42713 * 42714 * @static 42715 * @memberOf _ 42716 * @category Lang 42717 * @param {*} value The value to check. 42718 * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. 42719 * @example 42720 * 42721 * _.isUndefined(void 0); 42722 * // => true 42723 * 42724 * _.isUndefined(null); 42725 * // => false 42726 */ 42727 function isUndefined(value) { 42728 return value === undefined; 42729 } 42730 42731 /** 42732 * Checks if `value` is less than `other`. 42733 * 42734 * @static 42735 * @memberOf _ 42736 * @category Lang 42737 * @param {*} value The value to compare. 42738 * @param {*} other The other value to compare. 42739 * @returns {boolean} Returns `true` if `value` is less than `other`, else `false`. 42740 * @example 42741 * 42742 * _.lt(1, 3); 42743 * // => true 42744 * 42745 * _.lt(3, 3); 42746 * // => false 42747 * 42748 * _.lt(3, 1); 42749 * // => false 42750 */ 42751 function lt(value, other) { 42752 return value < other; 42753 } 42754 42755 /** 42756 * Checks if `value` is less than or equal to `other`. 42757 * 42758 * @static 42759 * @memberOf _ 42760 * @category Lang 42761 * @param {*} value The value to compare. 42762 * @param {*} other The other value to compare. 42763 * @returns {boolean} Returns `true` if `value` is less than or equal to `other`, else `false`. 42764 * @example 42765 * 42766 * _.lte(1, 3); 42767 * // => true 42768 * 42769 * _.lte(3, 3); 42770 * // => true 42771 * 42772 * _.lte(3, 1); 42773 * // => false 42774 */ 42775 function lte(value, other) { 42776 return value <= other; 42777 } 42778 42779 /** 42780 * Converts `value` to an array. 42781 * 42782 * @static 42783 * @memberOf _ 42784 * @category Lang 42785 * @param {*} value The value to convert. 42786 * @returns {Array} Returns the converted array. 42787 * @example 42788 * 42789 * (function() { 42790 * return _.toArray(arguments).slice(1); 42791 * }(1, 2, 3)); 42792 * // => [2, 3] 42793 */ 42794 function toArray(value) { 42795 var length = value ? getLength(value) : 0; 42796 if (!isLength(length)) { 42797 return values(value); 42798 } 42799 if (!length) { 42800 return []; 42801 } 42802 return arrayCopy(value); 42803 } 42804 42805 /** 42806 * Converts `value` to a plain object flattening inherited enumerable 42807 * properties of `value` to own properties of the plain object. 42808 * 42809 * @static 42810 * @memberOf _ 42811 * @category Lang 42812 * @param {*} value The value to convert. 42813 * @returns {Object} Returns the converted plain object. 42814 * @example 42815 * 42816 * function Foo() { 42817 * this.b = 2; 42818 * } 42819 * 42820 * Foo.prototype.c = 3; 42821 * 42822 * _.assign({ 'a': 1 }, new Foo); 42823 * // => { 'a': 1, 'b': 2 } 42824 * 42825 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); 42826 * // => { 'a': 1, 'b': 2, 'c': 3 } 42827 */ 42828 function toPlainObject(value) { 42829 return baseCopy(value, keysIn(value)); 42830 } 42831 42832 /*------------------------------------------------------------------------*/ 42833 42834 /** 42835 * Recursively merges own enumerable properties of the source object(s), that 42836 * don't resolve to `undefined` into the destination object. Subsequent sources 42837 * overwrite property assignments of previous sources. If `customizer` is 42838 * provided it is invoked to produce the merged values of the destination and 42839 * source properties. If `customizer` returns `undefined` merging is handled 42840 * by the method instead. The `customizer` is bound to `thisArg` and invoked 42841 * with five arguments: (objectValue, sourceValue, key, object, source). 42842 * 42843 * @static 42844 * @memberOf _ 42845 * @category Object 42846 * @param {Object} object The destination object. 42847 * @param {...Object} [sources] The source objects. 42848 * @param {Function} [customizer] The function to customize assigned values. 42849 * @param {*} [thisArg] The `this` binding of `customizer`. 42850 * @returns {Object} Returns `object`. 42851 * @example 42852 * 42853 * var users = { 42854 * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] 42855 * }; 42856 * 42857 * var ages = { 42858 * 'data': [{ 'age': 36 }, { 'age': 40 }] 42859 * }; 42860 * 42861 * _.merge(users, ages); 42862 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } 42863 * 42864 * // using a customizer callback 42865 * var object = { 42866 * 'fruits': ['apple'], 42867 * 'vegetables': ['beet'] 42868 * }; 42869 * 42870 * var other = { 42871 * 'fruits': ['banana'], 42872 * 'vegetables': ['carrot'] 42873 * }; 42874 * 42875 * _.merge(object, other, function(a, b) { 42876 * if (_.isArray(a)) { 42877 * return a.concat(b); 42878 * } 42879 * }); 42880 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } 42881 */ 42882 var merge = createAssigner(baseMerge); 42883 42884 /** 42885 * Assigns own enumerable properties of source object(s) to the destination 42886 * object. Subsequent sources overwrite property assignments of previous sources. 42887 * If `customizer` is provided it is invoked to produce the assigned values. 42888 * The `customizer` is bound to `thisArg` and invoked with five arguments: 42889 * (objectValue, sourceValue, key, object, source).
42890 * 42891 * **Note:** This method mutates `object` and is based on 42892 * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). 42893 * 42894 * @static 42895 * @memberOf _ 42896 * @alias extend 42897 * @category Object 42898 * @param {Object} object The destination object. 42899 * @param {...Object} [sources] The source objects. 42900 * @param {Function} [customizer] The function to customize assigned values. 42901 * @param {*} [thisArg] The `this` binding of `customizer`. 42902 * @returns {Object} Returns `object`. 42903 * @example 42904 * 42905 * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); 42906 * // => { 'user': 'fred', 'age': 40 } 42907 * 42908 * // using a customizer callback 42909 * var defaults = _.partialRight(_.assign, function(value, other) { 42910 * return _.isUndefined(value) ? other : value; 42911 * }); 42912 * 42913 * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); 42914 * // => { 'user': 'barney', 'age': 36 } 42915 */ 42916 var assign = createAssigner(function(object, source, customizer) { 42917 return customizer 42918 ? assignWith(object, source, customizer) 42919 : baseAssign(object, source); 42920 }); 42921 42922 /** 42923 * Creates an object that inherits from the given `prototype` object. If a 42924 * `properties` object is provided its own enumerable properties are assigned 42925 * to the created object. 42926 * 42927 * @static 42928 * @memberOf _ 42929 * @category Object 42930 * @param {Object} prototype The object to inherit from. 42931 * @param {Object} [properties] The properties to assign to the object. 42932 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 42933 * @returns {Object} Returns the new object. 42934 * @example 42935 * 42936 * function Shape() { 42937 * this.x = 0; 42938 * this.y = 0; 42939 * } 42940 * 42941 * function Circle() { 42942 * Shape.call(this); 42943 * } 42944 * 42945 * Circle.prototype = _.create(Shape.prototype, { 42946 * 'constructor': Circle 42947 * }); 42948 * 42949 * var circle = new Circle; 42950 * circle instanceof Circle; 42951 * // => true 42952 * 42953 * circle instanceof Shape; 42954 * // => true 42955 */ 42956 function create(prototype, properties, guard) { 42957 var result = baseCreate(prototype); 42958 if (guard && isIterateeCall(prototype, properties, guard)) { 42959 properties = undefined; 42960 } 42961 return properties ? baseAssign(result, properties) : result; 42962 } 42963 42964 /** 42965 * Assigns own enumerable properties of source object(s) to the destination 42966 * object for all destination properties that resolve to `undefined`. Once a 42967 * property is set, additional values of the same property are ignored. 42968 * 42969 * **Note:** This method mutates `object`. 42970 * 42971 * @static 42972 * @memberOf _ 42973 * @category Object 42974 * @param {Object} object The destination object. 42975 * @param {...Object} [sources] The source objects. 42976 * @returns {Object} Returns `object`. 42977 * @example 42978 * 42979 * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); 42980 * // => { 'user': 'barney', 'age': 36 } 42981 */ 42982 var defaults = createDefaults(assign, assignDefaults); 42983 42984 /** 42985 * This method is like `_.defaults` except that it recursively assigns 42986 * default properties. 42987 * 42988 * **Note:** This method mutates `object`. 42989 * 42990 * @static 42991 * @memberOf _ 42992 * @category Object 42993 * @param {Object} object The destination object. 42994 * @param {...Object} [sources] The source objects. 42995 * @returns {Object} Returns `object`. 42996 * @example 42997 * 42998 * _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } }); 42999 * // => { 'user': { 'name': 'barney', 'age': 36 } } 43000 * 43001 */ 43002 var defaultsDeep = createDefaults(merge, mergeDefaults); 43003 43004 /** 43005 * This method is like `_.find` except that it returns the key of the first 43006 * element `predicate` returns truthy for instead of the element itself. 43007 * 43008 * If a property name is provided for `predicate` the created `_.property` 43009 * style callback returns the property value of the given element. 43010 * 43011 * If a value is also provided for `thisArg` the created `_.matchesProperty` 43012 * style callback returns `true` for elements that have a matching property 43013 * value, else `false`. 43014 * 43015 * If an object is provided for `predicate` the created `_.matches` style 43016 * callback returns `true` for elements that have the properties of the given 43017 * object, else `false`. 43018 * 43019 * @static 43020 * @memberOf _ 43021 * @category Object 43022 * @param {Object} object The object to search. 43023 * @param {Function|Object|string} [predicate=_.identity] The function invoked 43024 * per iteration. 43025 * @param {*} [thisArg] The `this` binding of `predicate`. 43026 * @returns {string|undefined} Returns the key of the matched element, else `undefined`. 43027 * @example 43028 * 43029 * var users = { 43030 * 'barney': { 'age': 36, 'active': true }, 43031 * 'fred': { 'age': 40, 'active': false }, 43032 * 'pebbles': { 'age': 1, 'active': true } 43033 * }; 43034 * 43035 * _.findKey(users, function(chr) { 43036 * return chr.age < 40; 43037 * }); 43038 * // => 'barney' (iteration order is not guaranteed) 43039 * 43040 * // using the `_.matches` callback shorthand 43041 * _.findKey(users, { 'age': 1, 'active': true }); 43042 * // => 'pebbles' 43043 *
43044 * // using the `_.matchesProperty` callback shorthand 43045 * _.findKey(users, 'active', false); 43046 * // => 'fred' 43047 * 43048 * // using the `_.property` callback shorthand 43049 * _.findKey(users, 'active'); 43050 * // => 'barney' 43051 */ 43052 var findKey = createFindKey(baseForOwn); 43053 43054 /** 43055 * This method is like `_.findKey` except that it iterates over elements of 43056 * a collection in the opposite order. 43057 * 43058 * If a property name is provided for `predicate` the created `_.property` 43059 * style callback returns the property value of the given element. 43060 * 43061 * If a value is also provided for `thisArg` the created `_.matchesProperty` 43062 * style callback returns `true` for elements that have a matching property 43063 * value, else `false`. 43064 * 43065 * If an object is provided for `predicate` the created `_.matches` style 43066 * callback returns `true` for elements that have the properties of the given 43067 * object, else `false`. 43068 * 43069 * @static 43070 * @memberOf _ 43071 * @category Object 43072 * @param {Object} object The object to search. 43073 * @param {Function|Object|string} [predicate=_.identity] The function invoked 43074 * per iteration. 43075 * @param {*} [thisArg] The `this` binding of `predicate`. 43076 * @returns {string|undefined} Returns the key of the matched element, else `undefined`. 43077 * @example 43078 * 43079 * var users = { 43080 * 'barney': { 'age': 36, 'active': true }, 43081 * 'fred': { 'age': 40, 'active': false }, 43082 * 'pebbles': { 'age': 1, 'active': true } 43083 * }; 43084 * 43085 * _.findLastKey(users, function(chr) { 43086 * return chr.age < 40; 43087 * }); 43088 * // => returns `pebbles` assuming `_.findKey` returns `barney` 43089 * 43090 * // using the `_.matches` callback shorthand 43091 * _.findLastKey(users, { 'age': 36, 'active': true }); 43092 * // => 'barney' 43093 * 43094 * // using the `_.matchesProperty` callback shorthand 43095 * _.findLastKey(users, 'active', false); 43096 * // => 'fred' 43097 * 43098 * // using the `_.property` callback shorthand 43099 * _.findLastKey(users, 'active'); 43100 * // => 'pebbles' 43101 */ 43102 var findLastKey = createFindKey(baseForOwnRight); 43103 43104 /** 43105 * Iterates over own and inherited enumerable properties of an object invoking 43106 * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked 43107 * with three arguments: (value, key, object). Iteratee functions may exit 43108 * iteration early by explicitly returning `false`. 43109 * 43110 * @static 43111 * @memberOf _ 43112 * @category Object 43113 * @param {Object} object The object to iterate over. 43114 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 43115 * @param {*} [thisArg] The `this` binding of `iteratee`. 43116 * @returns {Object} Returns `object`. 43117 * @example 43118 * 43119 * function Foo() { 43120 * this.a = 1; 43121 * this.b = 2; 43122 * } 43123 * 43124 * Foo.prototype.c = 3; 43125 * 43126 * _.forIn(new Foo, function(value, key) { 43127 * console.log(key); 43128 * }); 43129 * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) 43130 */ 43131 var forIn = createForIn(baseFor); 43132 43133 /** 43134 * This method is like `_.forIn` except that it iterates over properties of 43135 * `object` in the opposite order. 43136 * 43137 * @static 43138 * @memberOf _ 43139 * @category Object 43140 * @param {Object} object The object to iterate over. 43141 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 43142 * @param {*} [thisArg] The `this` binding of `iteratee`. 43143 * @returns {Object} Returns `object`. 43144 * @example 43145 * 43146 * function Foo() { 43147 * this.a = 1; 43148 * this.b = 2; 43149 * } 43150 * 43151 * Foo.prototype.c = 3; 43152 * 43153 * _.forInRight(new Foo, function(value, key) { 43154 * console.log(key); 43155 * }); 43156 * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' 43157 */ 43158 var forInRight = createForIn(baseForRight); 43159 43160 /** 43161 * Iterates over own enumerable properties of an object invoking `iteratee` 43162 * for each property. The `iteratee` is bound to `thisArg` and invoked with 43163 * three arguments: (value, key, object). Iteratee functions may exit iteration 43164 * early by explicitly returning `false`. 43165 * 43166 * @static 43167 * @memberOf _ 43168 * @category Object 43169 * @param {Object} object The object to iterate over. 43170 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 43171 * @param {*} [thisArg] The `this` binding of `iteratee`. 43172 * @returns {Object} Returns `object`. 43173 * @example 43174 * 43175 * function Foo() { 43176 * this.a = 1; 43177 * this.b = 2; 43178 * } 43179 * 43180 * Foo.prototype.c = 3; 43181 * 43182 * _.forOwn(new Foo, function(value, key) { 43183 * console.log(key); 43184 * }); 43185 * // => logs 'a' and 'b' (iteration order is not guaranteed) 43186 */ 43187 var forOwn = createForOwn(baseForOwn); 43188 43189 /** 43190 * This method is like `_.forOwn` except that it iterates over properties of 43191 * `object` in the opposite order. 43192 * 43193 * @static 43194 * @memberOf _ 43195 * @category Object 43196 * @param {Object} object The object to iterate over. 43197 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 43198 * @param {*} [thisArg] The `this` binding of `iteratee`. 43199 * @returns {Object} Returns `object`. 43200 * @example 43201 * 43202 * function Foo() { 43203 * this.a = 1; 43204 * this.b = 2; 43205 * } 43206 * 43207 * Foo.prototype.c = 3; 43208 * 43209 * _.forOwnRight(new Foo, function(value, key) { 43210 * console.log(key); 43211 * }); 43212 * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' 43213 */ 43214 var forOwnRight = createForOwn(baseForOwnRight); 43215 43216 /** 43217 * Creates an array of function property names from all enumerable properties, 43218 * own and inherited, of `object`. 43219 * 43220 * @static 43221 * @memberOf _ 43222 * @alias methods 43223 * @category Object 43224 * @param {Object} object The object to inspect. 43225 * @returns {Array} Returns the new array of property names. 43226 * @example 43227 * 43228 * _.functions(_); 43229 * // => ['after', 'ary', 'assign', ...] 43230 */ 43231 function functions(object) { 43232 return baseFunctions(object, keysIn(object)); 43233 } 43234 43235 /** 43236 * Gets the property value at `path` of `object`. If the resolved value is 43237 * `undefined` the `defaultValue` is used in its place. 43238 * 43239 * @static 43240 * @memberOf _ 43241 * @category Object 43242 * @param {Object} object The object to query. 43243 * @param {Array|string} path The path of the property to get. 43244 * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. 43245 * @returns {*} Returns the resolved value. 43246 * @example 43247 * 43248 * var object = { 'a': [{ 'b': { 'c': 3 } }] }; 43249 * 43250 * _.get(object, 'a[0].b.c'); 43251 * // => 3 43252 * 43253 * _.get(object, ['a', '0', 'b', 'c']); 43254 * // => 3 43255 * 43256 * _.get(object, 'a.b.c', 'default'); 43257 * // => 'default' 43258 */ 43259 function get(object, path, defaultValue) { 43260 var result = object == null ? undefined : baseGet(object, toPath(path), path + ''); 43261 return result === undefined ? defaultValue : result; 43262 } 43263 43264 /** 43265 * Checks if `path` is a direct property. 43266 * 43267 * @static 43268 * @memberOf _ 43269 * @category Object 43270 * @param {Object} object The object to query. 43271 * @param {Array|string} path The path to check. 43272 * @returns {boolean} Returns `true` if `path` is a direct property, else `false`. 43273 * @example 43274 * 43275 * var object = { 'a': { 'b': { 'c': 3 } } }; 43276 * 43277 * _.has(object, 'a'); 43278 * // => true 43279 * 43280 * _.has(object, 'a.b.c'); 43281 * // => true 43282 * 43283 * _.has(object, ['a', 'b', 'c']); 43284 * // => true 43285 */ 43286 function has(object, path) { 43287 if (object == null) { 43288 return false;
43289 } 43290 var result = hasOwnProperty.call(object, path); 43291 if (!result && !isKey(path)) { 43292 path = toPath(path); 43293 object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); 43294 if (object == null) { 43295 return false; 43296 } 43297 path = last(path); 43298 result = hasOwnProperty.call(object, path); 43299 } 43300 return result || (isLength(object.length) && isIndex(path, object.length) && 43301 (isArray(object) || isArguments(object))); 43302 } 43303 43304 /** 43305 * Creates an object composed of the inverted keys and values of `object`. 43306 * If `object` contains duplicate values, subsequent values overwrite property 43307 * assignments of previous values unless `multiValue` is `true`. 43308 * 43309 * @static 43310 * @memberOf _ 43311 * @category Object 43312 * @param {Object} object The object to invert. 43313 * @param {boolean} [multiValue] Allow multiple values per key. 43314 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 43315 * @returns {Object} Returns the new inverted object. 43316 * @example 43317 * 43318 * var object = { 'a': 1, 'b': 2, 'c': 1 }; 43319 * 43320 * _.invert(object); 43321 * // => { '1': 'c', '2': 'b' } 43322 * 43323 * // with `multiValue` 43324 * _.invert(object, true); 43325 * // => { '1': ['a', 'c'], '2': ['b'] } 43326 */ 43327 function invert(object, multiValue, guard) { 43328 if (guard && isIterateeCall(object, multiValue, guard)) { 43329 multiValue = undefined; 43330 } 43331 var index = -1, 43332 props = keys(object), 43333 length = props.length, 43334 result = {}; 43335 43336 while (++index < length) { 43337 var key = props[index], 43338 value = object[key]; 43339 43340 if (multiValue) { 43341 if (hasOwnProperty.call(result, value)) { 43342 result[value].push(key); 43343 } else { 43344 result[value] = [key]; 43345 } 43346 } 43347 else { 43348 result[value] = key; 43349 } 43350 } 43351 return result; 43352 } 43353 43354 /** 43355 * Creates an array of the own enumerable property names of `object`. 43356 * 43357 * **Note:** Non-object values are coerced to objects. See the 43358 * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) 43359 * for more details. 43360 * 43361 * @static 43362 * @memberOf _ 43363 * @category Object 43364 * @param {Object} object The object to query. 43365 * @returns {Array} Returns the array of property names. 43366 * @example 43367 * 43368 * function Foo() { 43369 * this.a = 1; 43370 * this.b = 2; 43371 * } 43372 * 43373 * Foo.prototype.c = 3; 43374 * 43375 * _.keys(new Foo); 43376 * // => ['a', 'b'] (iteration order is not guaranteed) 43377 * 43378 * _.keys('hi'); 43379 * // => ['0', '1'] 43380 */ 43381 var keys = !nativeKeys ? shimKeys : function(object) { 43382 var Ctor = object == null ? undefined : object.constructor; 43383 if ((typeof Ctor == 'function' && Ctor.prototype === object) || 43384 (typeof object != 'function' && isArrayLike(object))) { 43385 return shimKeys(object); 43386 } 43387 return isObject(object) ? nativeKeys(object) : []; 43388 }; 43389 43390 /** 43391 * Creates an array of the own and inherited enumerable property names of `object`. 43392 * 43393 * **Note:** Non-object values are coerced to objects. 43394 * 43395 * @static 43396 * @memberOf _ 43397 * @category Object 43398 * @param {Object} object The object to query. 43399 * @returns {Array} Returns the array of property names. 43400 * @example 43401 * 43402 * function Foo() { 43403 * this.a = 1; 43404 * this.b = 2; 43405 * } 43406 * 43407 * Foo.prototype.c = 3; 43408 * 43409 * _.keysIn(new Foo); 43410 * // => ['a', 'b', 'c'] (iteration order is not guaranteed) 43411 */ 43412 function keysIn(object) { 43413 if (object == null) { 43414 return []; 43415 } 43416 if (!isObject(object)) { 43417 object = Object(object); 43418 } 43419 var length = object.length; 43420 length = (length && isLength(length) && 43421 (isArray(object) || isArguments(object)) && length) || 0; 43422 43423 var Ctor = object.constructor, 43424 index = -1, 43425 isProto = typeof Ctor == 'function' && Ctor.prototype === object, 43426 result = Array(length), 43427 skipIndexes = length > 0; 43428 43429 while (++index < length) { 43430 result[index] = (index + ''); 43431 } 43432 for (var key in object) { 43433 if (!(skipIndexes && isIndex(key, length)) && 43434 !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { 43435 result.push(key); 43436 } 43437 } 43438 return result; 43439 } 43440 43441 /** 43442 * The opposite of `_.mapValues`; this method creates an object with the 43443 * same values as `object` and keys generated by running each own enumerable 43444 * property of `object` through `iteratee`. 43445 * 43446 * @static 43447 * @memberOf _ 43448 * @category Object 43449 * @param {Object} object The object to iterate over. 43450 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 43451 * per iteration. 43452 * @param {*} [thisArg] The `this` binding of `iteratee`. 43453 * @returns {Object} Returns the new mapped object. 43454 * @example 43455 * 43456 * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { 43457 * return key + value; 43458 * }); 43459 * // => { 'a1': 1, 'b2': 2 } 43460 */ 43461 var mapKeys = createObjectMapper(true); 43462 43463 /** 43464 * Creates an object with the same keys as `object` and values generated by 43465 * running each own enumerable property of `object` through `iteratee`. The 43466 * iteratee function is bound to `thisArg` and invoked with three arguments: 43467 * (value, key, object). 43468 * 43469 * If a property name is provided for `iteratee` the created `_.property` 43470 * style callback returns the property value of the given element. 43471 * 43472 * If a value is also provided for `thisArg` the created `_.matchesProperty` 43473 * style callback returns `true` for elements that have a matching property 43474 * value, else `false`. 43475 * 43476 * If an object is provided for `iteratee` the created `_.matches` style 43477 * callback returns `true` for elements that have the properties of the given 43478 * object, else `false`. 43479 * 43480 * @static 43481 * @memberOf _ 43482 * @category Object 43483 * @param {Object} object The object to iterate over. 43484 * @param {Function|Object|string} [iteratee=_.identity] The function invoked 43485 * per iteration. 43486 * @param {*} [thisArg] The `this` binding of `iteratee`. 43487 * @returns {Object} Returns the new mapped object. 43488 * @example 43489 * 43490 * _.mapValues({ 'a': 1, 'b': 2 }, function(n) { 43491 * return n * 3; 43492 * }); 43493 * // => { 'a': 3, 'b': 6 } 43494 * 43495 * var users = { 43496 * 'fred': { 'user': 'fred', 'age': 40 }, 43497 * 'pebbles': { 'user': 'pebbles', 'age': 1 } 43498 * }; 43499 *
43500 * // using the `_.property` callback shorthand 43501 * _.mapValues(users, 'age'); 43502 * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) 43503 */ 43504 var mapValues = createObjectMapper(); 43505 43506 /** 43507 * The opposite of `_.pick`; this method creates an object composed of the 43508 * own and inherited enumerable properties of `object` that are not omitted. 43509 * 43510 * @static 43511 * @memberOf _ 43512 * @category Object 43513 * @param {Object} object The source object. 43514 * @param {Function|...(string|string[])} [predicate] The function invoked per 43515 * iteration or property names to omit, specified as individual property 43516 * names or arrays of property names. 43517 * @param {*} [thisArg] The `this` binding of `predicate`. 43518 * @returns {Object} Returns the new object. 43519 * @example 43520 * 43521 * var object = { 'user': 'fred', 'age': 40 }; 43522 * 43523 * _.omit(object, 'age'); 43524 * // => { 'user': 'fred' } 43525 * 43526 * _.omit(object, _.isNumber); 43527 * // => { 'user': 'fred' } 43528 */ 43529 var omit = restParam(function(object, props) { 43530 if (object == null) { 43531 return {}; 43532 } 43533 if (typeof props[0] != 'function') { 43534 var props = arrayMap(baseFlatten(props), String); 43535 return pickByArray(object, baseDifference(keysIn(object), props)); 43536 } 43537 var predicate = bindCallback(props[0], props[1], 3); 43538 return pickByCallback(object, function(value, key, object) { 43539 return !predicate(value, key, object); 43540 }); 43541 }); 43542 43543 /** 43544 * Creates a two dimensional array of the key-value pairs for `object`, 43545 * e.g. `[[key1, value1], [key2, value2]]`. 43546 * 43547 * @static 43548 * @memberOf _ 43549 * @category Object 43550 * @param {Object} object The object to query. 43551 * @returns {Array} Returns the new array of key-value pairs. 43552 * @example 43553 * 43554 * _.pairs({ 'barney': 36, 'fred': 40 }); 43555 * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) 43556 */ 43557 function pairs(object) { 43558 object = toObject(object); 43559 43560 var index = -1, 43561 props = keys(object), 43562 length = props.length, 43563 result = Array(length); 43564 43565 while (++index < length) { 43566 var key = props[index]; 43567 result[index] = [key, object[key]]; 43568 } 43569 return result; 43570 } 43571 43572 /**
43573 * Creates an object composed of the picked `object` properties. Property 43574 * names may be specified as individual arguments or as arrays of property 43575 * names. If `predicate` is provided it is invoked for each property of `object` 43576 * picking the properties `predicate` returns truthy for. The predicate is 43577 * bound to `thisArg` and invoked with three arguments: (value, key, object). 43578 * 43579 * @static 43580 * @memberOf _ 43581 * @category Object 43582 * @param {Object} object The source object. 43583 * @param {Function|...(string|string[])} [predicate] The function invoked per 43584 * iteration or property names to pick, specified as individual property 43585 * names or arrays of property names. 43586 * @param {*} [thisArg] The `this` binding of `predicate`. 43587 * @returns {Object} Returns the new object. 43588 * @example 43589 * 43590 * var object = { 'user': 'fred', 'age': 40 }; 43591 * 43592 * _.pick(object, 'user'); 43593 * // => { 'user': 'fred' } 43594 * 43595 * _.pick(object, _.isString); 43596 * // => { 'user': 'fred' } 43597 */ 43598 var pick = restParam(function(object, props) { 43599 if (object == null) { 43600 return {}; 43601 } 43602 return typeof props[0] == 'function' 43603 ? pickByCallback(object, bindCallback(props[0], props[1], 3)) 43604 : pickByArray(object, baseFlatten(props)); 43605 }); 43606 43607 /** 43608 * This method is like `_.get` except that if the resolved value is a function 43609 * it is invoked with the `this` binding of its parent object and its result 43610 * is returned. 43611 * 43612 * @static 43613 * @memberOf _ 43614 * @category Object 43615 * @param {Object} object The object to query. 43616 * @param {Array|string} path The path of the property to resolve. 43617 * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. 43618 * @returns {*} Returns the resolved value. 43619 * @example 43620 * 43621 * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; 43622 * 43623 * _.result(object, 'a[0].b.c1'); 43624 * // => 3 43625 * 43626 * _.result(object, 'a[0].b.c2'); 43627 * // => 4 43628 * 43629 * _.result(object, 'a.b.c', 'default'); 43630 * // => 'default' 43631 * 43632 * _.result(object, 'a.b.c', _.constant('default')); 43633 * // => 'default' 43634 */ 43635 function result(object, path, defaultValue) { 43636 var result = object == null ? undefined : object[path]; 43637 if (result === undefined) { 43638 if (object != null && !isKey(path, object)) { 43639 path = toPath(path); 43640 object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); 43641 result = object == null ? undefined : object[last(path)]; 43642 } 43643 result = result === undefined ? defaultValue : result; 43644 } 43645 return isFunction(result) ? result.call(object) : result; 43646 } 43647 43648 /** 43649 * Sets the property value of `path` on `object`. If a portion of `path` 43650 * does not exist it is created. 43651 * 43652 * @static 43653 * @memberOf _ 43654 * @category Object 43655 * @param {Object} object The object to augment. 43656 * @param {Array|string} path The path of the property to set. 43657 * @param {*} value The value to set. 43658 * @returns {Object} Returns `object`. 43659 * @example 43660 * 43661 * var object = { 'a': [{ 'b': { 'c': 3 } }] }; 43662 * 43663 * _.set(object, 'a[0].b.c', 4); 43664 * console.log(object.a[0].b.c); 43665 * // => 4 43666 * 43667 * _.set(object, 'x[0].y.z', 5); 43668 * console.log(object.x[0].y.z); 43669 * // => 5 43670 */ 43671 function set(object, path, value) { 43672 if (object == null) { 43673 return object; 43674 } 43675 var pathKey = (path + ''); 43676 path = (object[pathKey] != null || isKey(path, object)) ? [pathKey] : toPath(path); 43677 43678 var index = -1, 43679 length = path.length, 43680 lastIndex = length - 1, 43681 nested = object; 43682 43683 while (nested != null && ++index < length) { 43684 var key = path[index]; 43685 if (isObject(nested)) { 43686 if (index == lastIndex) { 43687 nested[key] = value; 43688 } else if (nested[key] == null) { 43689 nested[key] = isIndex(path[index + 1]) ? [] : {}; 43690 } 43691 } 43692 nested = nested[key]; 43693 } 43694 return object; 43695 } 43696 43697 /** 43698 * An alternative to `_.reduce`; this method transforms `object` to a new 43699 * `accumulator` object which is the result of running each of its own enumerable 43700 * properties through `iteratee`, with each invocation potentially mutating 43701 * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked 43702 * with four arguments: (accumulator, value, key, object). Iteratee functions 43703 * may exit iteration early by explicitly returning `false`. 43704 * 43705 * @static 43706 * @memberOf _ 43707 * @category Object 43708 * @param {Array|Object} object The object to iterate over. 43709 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 43710 * @param {*} [accumulator] The custom accumulator value. 43711 * @param {*} [thisArg] The `this` binding of `iteratee`. 43712 * @returns {*} Returns the accumulated value. 43713 * @example 43714 * 43715 * _.transform([2, 3, 4], function(result, n) { 43716 * result.push(n *= n); 43717 * return n % 2 == 0; 43718 * }); 43719 * // => [4, 9] 43720 * 43721 * _.transform({ 'a': 1, 'b': 2 }, function(result, n, key) { 43722 * result[key] = n * 3; 43723 * }); 43724 * // => { 'a': 3, 'b': 6 } 43725 */ 43726 function transform(object, iteratee, accumulator, thisArg) { 43727 var isArr = isArray(object) || isTypedArray(object); 43728 iteratee = getCallback(iteratee, thisArg, 4); 43729 43730 if (accumulator == null) { 43731 if (isArr || isObject(object)) { 43732 var Ctor = object.constructor; 43733 if (isArr) { 43734 accumulator = isArray(object) ? new Ctor : []; 43735 } else { 43736 accumulator = baseCreate(isFunction(Ctor) ? Ctor.prototype : undefined); 43737 } 43738 } else { 43739 accumulator = {}; 43740 } 43741 } 43742 (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { 43743 return iteratee(accumulator, value, index, object); 43744 }); 43745 return accumulator; 43746 } 43747 43748 /** 43749 * Creates an array of the own enumerable property values of `object`. 43750 * 43751 * **Note:** Non-object values are coerced to objects. 43752 * 43753 * @static 43754 * @memberOf _ 43755 * @category Object 43756 * @param {Object} object The object to query. 43757 * @returns {Array} Returns the array of property values. 43758 * @example 43759 * 43760 * function Foo() { 43761 * this.a = 1; 43762 * this.b = 2; 43763 * } 43764 * 43765 * Foo.prototype.c = 3; 43766 * 43767 * _.values(new Foo); 43768 * // => [1, 2] (iteration order is not guaranteed) 43769 * 43770 * _.values('hi'); 43771 * // => ['h', 'i'] 43772 */ 43773 function values(object) { 43774 return baseValues(object, keys(object)); 43775 } 43776 43777 /** 43778 * Creates an array of the own and inherited enumerable property values 43779 * of `object`. 43780 * 43781 * **Note:** Non-object values are coerced to objects. 43782 * 43783 * @static 43784 * @memberOf _ 43785 * @category Object 43786 * @param {Object} object The object to query. 43787 * @returns {Array} Returns the array of property values. 43788 * @example 43789 * 43790 * function Foo() { 43791 * this.a = 1; 43792 * this.b = 2; 43793 * } 43794 * 43795 * Foo.prototype.c = 3; 43796 *
43797 * _.valuesIn(new Foo); 43798 * // => [1, 2, 3] (iteration order is not guaranteed) 43799 */ 43800 function valuesIn(object) { 43801 return baseValues(object, keysIn(object)); 43802 } 43803 43804 /*------------------------------------------------------------------------*/ 43805 43806 /** 43807 * Checks if `n` is between `start` and up to but not including, `end`. If 43808 * `end` is not specified it is set to `start` with `start` then set to `0`. 43809 * 43810 * @static 43811 * @memberOf _ 43812 * @category Number 43813 * @param {number} n The number to check. 43814 * @param {number} [start=0] The start of the range. 43815 * @param {number} end The end of the range. 43816 * @returns {boolean} Returns `true` if `n` is in the range, else `false`. 43817 * @example 43818 * 43819 * _.inRange(3, 2, 4); 43820 * // => true 43821 * 43822 * _.inRange(4, 8); 43823 * // => true 43824 * 43825 * _.inRange(4, 2); 43826 * // => false 43827 * 43828 * _.inRange(2, 2); 43829 * // => false 43830 * 43831 * _.inRange(1.2, 2); 43832 * // => true 43833 * 43834 * _.inRange(5.2, 4); 43835 * // => false 43836 */ 43837 function inRange(value, start, end) { 43838 start = +start || 0; 43839 if (end === undefined) { 43840 end = start; 43841 start = 0; 43842 } else { 43843 end = +end || 0; 43844 } 43845 return value >= nativeMin(start, end) && value < nativeMax(start, end); 43846 } 43847 43848 /** 43849 * Produces a random number between `min` and `max` (inclusive). If only one 43850 * argument is provided a number between `0` and the given number is returned. 43851 * If `floating` is `true`, or either `min` or `max` are floats, a floating-point 43852 * number is returned instead of an integer. 43853 * 43854 * @static 43855 * @memberOf _ 43856 * @category Number 43857 * @param {number} [min=0] The minimum possible value. 43858 * @param {number} [max=1] The maximum possible value. 43859 * @param {boolean} [floating] Specify returning a floating-point number. 43860 * @returns {number} Returns the random number. 43861 * @example 43862 * 43863 * _.random(0, 5); 43864 * // => an integer between 0 and 5 43865 * 43866 * _.random(5); 43867 * // => also an integer between 0 and 5 43868 * 43869 * _.random(5, true); 43870 * // => a floating-point number between 0 and 5 43871 * 43872 * _.random(1.2, 5.2); 43873 * // => a floating-point number between 1.2 and 5.2 43874 */ 43875 function random(min, max, floating) { 43876 if (floating && isIterateeCall(min, max, floating)) { 43877 max = floating = undefined; 43878 } 43879 var noMin = min == null, 43880 noMax = max == null; 43881 43882 if (floating == null) { 43883 if (noMax && typeof min == 'boolean') { 43884 floating = min; 43885 min = 1; 43886 } 43887 else if (typeof max == 'boolean') { 43888 floating = max; 43889 noMax = true; 43890 } 43891 } 43892 if (noMin && noMax) { 43893 max = 1; 43894 noMax = false; 43895 } 43896 min = +min || 0; 43897 if (noMax) { 43898 max = min; 43899 min = 0; 43900 } else { 43901 max = +max || 0; 43902 } 43903 if (floating || min % 1 || max % 1) { 43904 var rand = nativeRandom(); 43905 return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max); 43906 } 43907 return baseRandom(min, max); 43908 } 43909 43910 /*------------------------------------------------------------------------*/ 43911 43912 /** 43913 * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). 43914 * 43915 * @static 43916 * @memberOf _ 43917 * @category String 43918 * @param {string} [string=''] The string to convert. 43919 * @returns {string} Returns the camel cased string. 43920 * @example 43921 * 43922 * _.camelCase('Foo Bar'); 43923 * // => 'fooBar' 43924 * 43925 * _.camelCase('--foo-bar'); 43926 * // => 'fooBar' 43927 * 43928 * _.camelCase('__foo_bar__'); 43929 * // => 'fooBar' 43930 */ 43931 var camelCase = createCompounder(function(result, word, index) { 43932 word = word.toLowerCase(); 43933 return result + (index ? (word.charAt(0).toUpperCase() + word.slice(1)) : word); 43934 }); 43935 43936 /** 43937 * Capitalizes the first character of `string`. 43938 * 43939 * @static 43940 * @memberOf _ 43941 * @category String 43942 * @param {string} [string=''] The string to capitalize. 43943 * @returns {string} Returns the capitalized string. 43944 * @example 43945 * 43946 * _.capitalize('fred'); 43947 * // => 'Fred' 43948 */ 43949 function capitalize(string) {
43950 string = baseToString(string); 43951 return string && (string.charAt(0).toUpperCase() + string.slice(1)); 43952 } 43953 43954 /** 43955 * Deburrs `string` by converting [latin-1 supplementary letters](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) 43956 * to basic latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). 43957 * 43958 * @static 43959 * @memberOf _ 43960 * @category String 43961 * @param {string} [string=''] The string to deburr. 43962 * @returns {string} Returns the deburred string. 43963 * @example 43964 * 43965 * _.deburr('déjàvu'); 43966 * // => 'deja vu' 43967 */ 43968 function deburr(string) { 43969 string = baseToString(string); 43970 return string && string.replace(reLatin1, deburrLetter).replace(reComboMark, ''); 43971 } 43972 43973 /** 43974 * Checks if `string` ends with the given target string. 43975 * 43976 * @static 43977 * @memberOf _ 43978 * @category String 43979 * @param {string} [string=''] The string to search. 43980 * @param {string} [target] The string to search for. 43981 * @param {number} [position=string.length] The position to search from. 43982 * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`. 43983 * @example 43984 * 43985 * _.endsWith('abc', 'c'); 43986 * // => true 43987 * 43988 * _.endsWith('abc', 'b'); 43989 * // => false 43990 * 43991 * _.endsWith('abc', 'b', 2); 43992 * // => true 43993 */ 43994 function endsWith(string, target, position) { 43995 string = baseToString(string); 43996 target = (target + ''); 43997 43998 var length = string.length; 43999 position = position === undefined 44000 ? length 44001 : nativeMin(position < 0 ? 0 : (+position || 0), length); 44002 44003 position -= target.length; 44004 return position >= 0 && string.indexOf(target, position) == position; 44005 } 44006 44007 /** 44008 * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to 44009 * their corresponding HTML entities. 44010 * 44011 * **Note:** No other characters are escaped. To escape additional characters 44012 * use a third-party library like [_he_](https://mths.be/he). 44013 * 44014 * Though the ">" character is escaped for symmetry, characters like 44015 * ">" and "/" don't need escaping in HTML and have no special meaning 44016 * unless they're part of a tag or unquoted attribute value. 44017 * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) 44018 * (under "semi-related fun fact") for more details. 44019 * 44020 * Backticks are escaped because in Internet Explorer < 9, they can break out 44021 * of attribute values or HTML comments. See [#59](https://html5sec.org/#59), 44022 * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and 44023 * [#133](https://html5sec.org/#133) of the [HTML5 Security Cheatsheet](https://html5sec.org/) 44024 * for more details. 44025 * 44026 * When working with HTML you should always [quote attribute values](http://wonko.com/post/html-escaping) 44027 * to reduce XSS vectors. 44028 * 44029 * @static 44030 * @memberOf _ 44031 * @category String 44032 * @param {string} [string=''] The string to escape. 44033 * @returns {string} Returns the escaped string. 44034 * @example 44035 * 44036 * _.escape('fred, barney, & pebbles'); 44037 * // => 'fred, barney, & pebbles' 44038 */ 44039 function escape(string) { 44040 // Reset `lastIndex` because in IE < 9 `String#replace` does not. 44041 string = baseToString(string); 44042 return (string && reHasUnescapedHtml.test(string)) 44043 ? string.replace(reUnescapedHtml, escapeHtmlChar) 44044 : string; 44045 } 44046 44047 /** 44048 * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", 44049 * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. 44050 * 44051 * @static 44052 * @memberOf _ 44053 * @category String 44054 * @param {string} [string=''] The string to escape. 44055 * @returns {string} Returns the escaped string. 44056 * @example 44057 * 44058 * _.escapeRegExp('[lodash](https://lodash.com/)'); 44059 * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' 44060 */ 44061 function escapeRegExp(string) {
44062 string = baseToString(string); 44063 return (string && reHasRegExpChars.test(string)) 44064 ? string.replace(reRegExpChars, escapeRegExpChar) 44065 : (string || '(?:)'); 44066 } 44067 44068 /** 44069 * Converts `string` to [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). 44070 * 44071 * @static 44072 * @memberOf _ 44073 * @category String 44074 * @param {string} [string=''] The string to convert. 44075 * @returns {string} Returns the kebab cased string. 44076 * @example 44077 * 44078 * _.kebabCase('Foo Bar'); 44079 * // => 'foo-bar' 44080 * 44081 * _.kebabCase('fooBar'); 44082 * // => 'foo-bar' 44083 * 44084 * _.kebabCase('__foo_bar__'); 44085 * // => 'foo-bar' 44086 */ 44087 var kebabCase = createCompounder(function(result, word, index) { 44088 return result + (index ? '-' : '') + word.toLowerCase(); 44089 }); 44090 44091 /** 44092 * Pads `string` on the left and right sides if it's shorter than `length`. 44093 * Padding characters are truncated if they can't be evenly divided by `length`. 44094 * 44095 * @static 44096 * @memberOf _ 44097 * @category String 44098 * @param {string} [string=''] The string to pad. 44099 * @param {number} [length=0] The padding length. 44100 * @param {string} [chars=' '] The string used as padding. 44101 * @returns {string} Returns the padded string. 44102 * @example 44103 * 44104 * _.pad('abc', 8); 44105 * // => ' abc ' 44106 * 44107 * _.pad('abc', 8, '_-'); 44108 * // => '_-abc_-_' 44109 * 44110 * _.pad('abc', 3); 44111 * // => 'abc' 44112 */ 44113 function pad(string, length, chars) { 44114 string = baseToString(string); 44115 length = +length; 44116 44117 var strLength = string.length; 44118 if (strLength >= length || !nativeIsFinite(length)) { 44119 return string; 44120 } 44121 var mid = (length - strLength) / 2, 44122 leftLength = nativeFloor(mid), 44123 rightLength = nativeCeil(mid); 44124 44125 chars = createPadding('', rightLength, chars); 44126 return chars.slice(0, leftLength) + string + chars; 44127 } 44128 44129 /** 44130 * Pads `string` on the left side if it's shorter than `length`. Padding 44131 * characters are truncated if they exceed `length`. 44132 * 44133 * @static 44134 * @memberOf _ 44135 * @category String 44136 * @param {string} [string=''] The string to pad. 44137 * @param {number} [length=0] The padding length. 44138 * @param {string} [chars=' '] The string used as padding. 44139 * @returns {string} Returns the padded string. 44140 * @example 44141 * 44142 * _.padLeft('abc', 6); 44143 * // => ' abc' 44144 * 44145 * _.padLeft('abc', 6, '_-'); 44146 * // => '_-_abc' 44147 * 44148 * _.padLeft('abc', 3); 44149 * // => 'abc' 44150 */ 44151 var padLeft = createPadDir(); 44152 44153 /** 44154 * Pads `string` on the right side if it's shorter than `length`. Padding 44155 * characters are truncated if they exceed `length`. 44156 * 44157 * @static 44158 * @memberOf _ 44159 * @category String 44160 * @param {string} [string=''] The string to pad. 44161 * @param {number} [length=0] The padding length. 44162 * @param {string} [chars=' '] The string used as padding. 44163 * @returns {string} Returns the padded string. 44164 * @example 44165 * 44166 * _.padRight('abc', 6); 44167 * // => 'abc ' 44168 * 44169 * _.padRight('abc', 6, '_-'); 44170 * // => 'abc_-_' 44171 * 44172 * _.padRight('abc', 3); 44173 * // => 'abc' 44174 */ 44175 var padRight = createPadDir(true); 44176 44177 /** 44178 * Converts `string` to an integer of the specified radix. If `radix` is 44179 * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal, 44180 * in which case a `radix` of `16` is used. 44181 * 44182 * **Note:** This method aligns with the [ES5 implementation](https://es5.github.io/#E) 44183 * of `parseInt`. 44184 * 44185 * @static 44186 * @memberOf _ 44187 * @category String 44188 * @param {string} string The string to convert. 44189 * @param {number} [radix] The radix to interpret `value` by. 44190 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 44191 * @returns {number} Returns the converted integer. 44192 * @example 44193 * 44194 * _.parseInt('08'); 44195 * // => 8 44196 * 44197 * _.map(['6', '08', '10'], _.parseInt); 44198 * // => [6, 8, 10] 44199 */ 44200 function parseInt(string, radix, guard) { 44201 // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. 44202 // Chrome fails to trim leading <BOM> whitespace characters. 44203 // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. 44204 if (guard ? isIterateeCall(string, radix, guard) : radix == null) { 44205 radix = 0; 44206 } else if (radix) { 44207 radix = +radix; 44208 }
44209 string = trim(string); 44210 return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10)); 44211 } 44212 44213 /** 44214 * Repeats the given string `n` times. 44215 * 44216 * @static 44217 * @memberOf _ 44218 * @category String 44219 * @param {string} [string=''] The string to repeat. 44220 * @param {number} [n=0] The number of times to repeat the string. 44221 * @returns {string} Returns the repeated string. 44222 * @example 44223 * 44224 * _.repeat('*', 3); 44225 * // => '***' 44226 * 44227 * _.repeat('abc', 2); 44228 * // => 'abcabc' 44229 * 44230 * _.repeat('abc', 0); 44231 * // => '' 44232 */ 44233 function repeat(string, n) { 44234 var result = ''; 44235 string = baseToString(string); 44236 n = +n; 44237 if (n < 1 || !string || !nativeIsFinite(n)) { 44238 return result; 44239 } 44240 // Leverage the exponentiation by squaring algorithm for a faster repeat. 44241 // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. 44242 do { 44243 if (n % 2) { 44244 result += string; 44245 } 44246 n = nativeFloor(n / 2); 44247 string += string; 44248 } while (n); 44249 44250 return result; 44251 } 44252 44253 /** 44254 * Converts `string` to [snake case](https://en.wikipedia.org/wiki/Snake_case). 44255 * 44256 * @static 44257 * @memberOf _ 44258 * @category String 44259 * @param {string} [string=''] The string to convert. 44260 * @returns {string} Returns the snake cased string. 44261 * @example 44262 * 44263 * _.snakeCase('Foo Bar'); 44264 * // => 'foo_bar' 44265 * 44266 * _.snakeCase('fooBar'); 44267 * // => 'foo_bar' 44268 * 44269 * _.snakeCase('--foo-bar'); 44270 * // => 'foo_bar' 44271 */ 44272 var snakeCase = createCompounder(function(result, word, index) { 44273 return result + (index ? '_' : '') + word.toLowerCase(); 44274 }); 44275 44276 /** 44277 * Converts `string` to [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). 44278 * 44279 * @static 44280 * @memberOf _ 44281 * @category String 44282 * @param {string} [string=''] The string to convert. 44283 * @returns {string} Returns the start cased string. 44284 * @example 44285 * 44286 * _.startCase('--foo-bar'); 44287 * // => 'Foo Bar' 44288 * 44289 * _.startCase('fooBar'); 44290 * // => 'Foo Bar' 44291 * 44292 * _.startCase('__foo_bar__'); 44293 * // => 'Foo Bar' 44294 */ 44295 var startCase = createCompounder(function(result, word, index) { 44296 return result + (index ? ' ' : '') + (word.charAt(0).toUpperCase() + word.slice(1)); 44297 }); 44298 44299 /** 44300 * Checks if `string` starts with the given target string. 44301 * 44302 * @static 44303 * @memberOf _ 44304 * @category String 44305 * @param {string} [string=''] The string to search. 44306 * @param {string} [target] The string to search for. 44307 * @param {number} [position=0] The position to search from. 44308 * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`. 44309 * @example 44310 * 44311 * _.startsWith('abc', 'a'); 44312 * // => true 44313 * 44314 * _.startsWith('abc', 'b'); 44315 * // => false 44316 * 44317 * _.startsWith('abc', 'b', 1); 44318 * // => true 44319 */ 44320 function startsWith(string, target, position) { 44321 string = baseToString(string); 44322 position = position == null 44323 ? 0 44324 : nativeMin(position < 0 ? 0 : (+position || 0), string.length); 44325 44326 return string.lastIndexOf(target, position) == position; 44327 } 44328 44329 /** 44330 * Creates a compiled template function that can interpolate data properties 44331 * in "interpolate" delimiters, HTML-escape interpolated data properties in 44332 * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data 44333 * properties may be accessed as free variables in the template. If a setting 44334 * object is provided it takes precedence over `_.templateSettings` values. 44335 * 44336 * **Note:** In the development build `_.template` utilizes 44337 * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) 44338 * for easier debugging. 44339 * 44340 * For more information on precompiling templates see 44341 * [lodash's custom builds documentation](https://lodash.com/custom-builds). 44342 * 44343 * For more information on Chrome extension sandboxes see 44344 * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). 44345 * 44346 * @static 44347 * @memberOf _ 44348 * @category String 44349 * @param {string} [string=''] The template string. 44350 * @param {Object} [options] The options object. 44351 * @param {RegExp} [options.escape] The HTML "escape" delimiter. 44352 * @param {RegExp} [options.evaluate] The "evaluate" delimiter. 44353 * @param {Object} [options.imports] An object to import into the template as free variables. 44354 * @param {RegExp} [options.interpolate] The "interpolate" delimiter. 44355 * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. 44356 * @param {string} [options.variable] The data object variable name. 44357 * @param- {Object} [otherOptions] Enables the legacy `options` param signature. 44358 * @returns {Function} Returns the compiled template function. 44359 * @example 44360 * 44361 * // using the "interpolate" delimiter to create a compiled template 44362 * var compiled = _.template('hello <%= user %>!'); 44363 * compiled({ 'user': 'fred' }); 44364 * // => 'hello fred!' 44365 * 44366 * // using the HTML "escape" delimiter to escape data property values 44367 * var compiled = _.template('<b><%- value %></b>'); 44368 * compiled({ 'value': '<script>' }); 44369 * // => '<b><script></b>' 44370 * 44371 * // using the "evaluate" delimiter to execute JavaScript and generate HTML 44372 * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>'); 44373 * compiled({ 'users': ['fred', 'barney'] }); 44374 * // => '<li>fred</li><li>barney</li>' 44375 * 44376 * // using the internal `print` function in "evaluate" delimiters 44377 * var compiled = _.template('<% print("hello " + user); %>!'); 44378 * compiled({ 'user': 'barney' }); 44379 * // => 'hello barney!' 44380 * 44381 * // using the ES delimiter as an alternative to the default "interpolate" delimiter 44382 * var compiled = _.template('hello ${ user }!'); 44383 * compiled({ 'user': 'pebbles' }); 44384 * // => 'hello pebbles!' 44385 * 44386 * // using custom template delimiters 44387 * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g; 44388 * var compiled = _.template('hello {{ user }}!'); 44389 * compiled({ 'user': 'mustache' }); 44390 * // => 'hello mustache!' 44391 * 44392 * // using backslashes to treat delimiters as plain text 44393 * var compiled = _.template('<%= "\\<%- value %\\>" %>'); 44394 * compiled({ 'value': 'ignored' }); 44395 * // => '<%- value %>' 44396 * 44397 * // using the `imports` option to import `jQuery` as `jq`
44398 * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>'; 44399 * var compiled = _.template(text, { 'imports': { 'jq': jQuery } }); 44400 * compiled({ 'users': ['fred', 'barney'] }); 44401 * // => '<li>fred</li><li>barney</li>' 44402 * 44403 * // using the `sourceURL` option to specify a custom sourceURL for the template 44404 * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' }); 44405 * compiled(data); 44406 * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector 44407 * 44408 * // using the `variable` option to ensure a with-statement isn't used in the compiled template 44409 * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' }); 44410 * compiled.source; 44411 * // => function(data) { 44412 * // var __t, __p = ''; 44413 * // __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!'; 44414 * // return __p; 44415 * // } 44416 * 44417 * // using the `source` property to inline compiled templates for meaningful 44418 * // line numbers in error messages and a stack trace 44419 * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ 44420 * var JST = {\ 44421 * "main": ' + _.template(mainText).source + '\ 44422 * };\ 44423 * '); 44424 */ 44425 function template(string, options, otherOptions) { 44426 // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/) 44427 // and Laura Doktorova's doT.js (https://github.com/olado/doT). 44428 var settings = lodash.templateSettings; 44429 44430 if (otherOptions && isIterateeCall(string, options, otherOptions)) { 44431 options = otherOptions = undefined; 44432 } 44433 string = baseToString(string); 44434 options = assignWith(baseAssign({}, otherOptions || options), settings, assignOwnDefaults); 44435 44436 var imports = assignWith(baseAssign({}, options.imports), settings.imports, assignOwnDefaults), 44437 importsKeys = keys(imports), 44438 importsValues = baseValues(imports, importsKeys); 44439 44440 var isEscaping, 44441 isEvaluating, 44442 index = 0, 44443 interpolate = options.interpolate || reNoMatch, 44444 source = "__p += '"; 44445 44446 // Compile the regexp to match each delimiter. 44447 var reDelimiters = RegExp( 44448 (options.escape || reNoMatch).source + '|' + 44449 interpolate.source + '|' + 44450 (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' + 44451 (options.evaluate || reNoMatch).source + '|$' 44452 , 'g'); 44453 44454 // Use a sourceURL for easier debugging. 44455 var sourceURL = '//# sourceURL=' + 44456 ('sourceURL' in options 44457 ? options.sourceURL 44458 : ('lodash.templateSources[' + (++templateCounter) + ']') 44459 ) + '\n'; 44460 44461 string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) { 44462 interpolateValue || (interpolateValue = esTemplateValue); 44463 44464 // Escape characters that can't be included in string literals. 44465 source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar); 44466 44467 // Replace delimiters with snippets. 44468 if (escapeValue) { 44469 isEscaping = true; 44470 source += "' +\n__e(" + escapeValue + ") +\n'"; 44471 } 44472 if (evaluateValue) { 44473 isEvaluating = true; 44474 source += "';\n" + evaluateValue + ";\n__p += '"; 44475 } 44476 if (interpolateValue) { 44477 source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'"; 44478 } 44479 index = offset + match.length; 44480 44481 // The JS engine embedded in Adobe products requires returning the `match` 44482 // string in order to produce the correct `offset` value. 44483 return match; 44484 }); 44485 44486 source += "';\n"; 44487 44488 // If `variable` is not specified wrap a with-statement around the generated 44489 // code to add the data object to the top of the scope chain. 44490 var variable = options.variable; 44491 if (!variable) { 44492 source = 'with (obj) {\n' + source + '\n}\n'; 44493 } 44494 // Cleanup code by stripping empty strings. 44495 source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) 44496 .replace(reEmptyStringMiddle, '$1') 44497 .replace(reEmptyStringTrailing, '$1;'); 44498 44499 // Frame code as the function body.
44500 source = 'function(' + (variable || 'obj') + ') {\n' + 44501 (variable 44502 ? '' 44503 : 'obj || (obj = {});\n' 44504 ) + 44505 "var __t, __p = ''" + 44506 (isEscaping 44507 ? ', __e = _.escape' 44508 : '' 44509 ) + 44510 (isEvaluating 44511 ? ', __j = Array.prototype.join;\n' + 44512 "function print() { __p += __j.call(arguments, '') }\n" 44513 : ';\n' 44514 ) + 44515 source + 44516 'return __p\n}'; 44517 44518 var result = attempt(function() { 44519 return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues); 44520 }); 44521 44522 // Provide the compiled function's source by its `toString` method or 44523 // the `source` property as a convenience for inlining compiled templates. 44524 result.source = source; 44525 if (isError(result)) { 44526 throw result; 44527 } 44528 return result; 44529 } 44530 44531 /** 44532 * Removes leading and trailing whitespace or specified characters from `string`. 44533 * 44534 * @static 44535 * @memberOf _ 44536 * @category String 44537 * @param {string} [string=''] The string to trim. 44538 * @param {string} [chars=whitespace] The characters to trim. 44539 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 44540 * @returns {string} Returns the trimmed string. 44541 * @example 44542 * 44543 * _.trim(' abc '); 44544 * // => 'abc' 44545 * 44546 * _.trim('-_-abc-_-', '_-'); 44547 * // => 'abc' 44548 * 44549 * _.map([' foo ', ' bar '], _.trim); 44550 * // => ['foo', 'bar'] 44551 */ 44552 function trim(string, chars, guard) { 44553 var value = string; 44554 string = baseToString(string); 44555 if (!string) { 44556 return string; 44557 } 44558 if (guard ? isIterateeCall(value, chars, guard) : chars == null) { 44559 return string.slice(trimmedLeftIndex(string), trimmedRightIndex(string) + 1); 44560 } 44561 chars = (chars + ''); 44562 return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1); 44563 } 44564 44565 /** 44566 * Removes leading whitespace or specified characters from `string`. 44567 * 44568 * @static 44569 * @memberOf _ 44570 * @category String 44571 * @param {string} [string=''] The string to trim. 44572 * @param {string} [chars=whitespace] The characters to trim. 44573 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 44574 * @returns {string} Returns the trimmed string. 44575 * @example 44576 * 44577 * _.trimLeft(' abc '); 44578 * // => 'abc ' 44579 * 44580 * _.trimLeft('-_-abc-_-', '_-'); 44581 * // => 'abc-_-' 44582 */ 44583 function trimLeft(string, chars, guard) { 44584 var value = string; 44585 string = baseToString(string); 44586 if (!string) { 44587 return string; 44588 } 44589 if (guard ? isIterateeCall(value, chars, guard) : chars == null) { 44590 return string.slice(trimmedLeftIndex(string)); 44591 } 44592 return string.slice(charsLeftIndex(string, (chars + ''))); 44593 } 44594 44595 /** 44596 * Removes trailing whitespace or specified characters from `string`. 44597 * 44598 * @static 44599 * @memberOf _ 44600 * @category String 44601 * @param {string} [string=''] The string to trim. 44602 * @param {string} [chars=whitespace] The characters to trim. 44603 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 44604 * @returns {string} Returns the trimmed string. 44605 * @example 44606 * 44607 * _.trimRight(' abc '); 44608 * // => ' abc' 44609 * 44610 * _.trimRight('-_-abc-_-', '_-'); 44611 * // => '-_-abc' 44612 */ 44613 function trimRight(string, chars, guard) { 44614 var value = string; 44615 string = baseToString(string); 44616 if (!string) { 44617 return string; 44618 } 44619 if (guard ? isIterateeCall(value, chars, guard) : chars == null) { 44620 return string.slice(0, trimmedRightIndex(string) + 1); 44621 } 44622 return string.slice(0, charsRightIndex(string, (chars + '')) + 1); 44623 } 44624 44625 /** 44626 * Truncates `string` if it's longer than the given maximum string length. 44627 * The last characters of the truncated string are replaced with the omission 44628 * string which defaults to "...". 44629 * 44630 * @static 44631 * @memberOf _ 44632 * @category String 44633 * @param {string} [string=''] The string to truncate. 44634 * @param {Object|number} [options] The options object or maximum string length. 44635 * @param {number} [options.length=30] The maximum string length. 44636 * @param {string} [options.omission='...'] The string to indicate text is omitted. 44637 * @param {RegExp|string} [options.separator] The separator pattern to truncate to. 44638 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 44639 * @returns {string} Returns the truncated string. 44640 * @example 44641 * 44642 * _.trunc('hi-diddly-ho there, neighborino'); 44643 * // => 'hi-diddly-ho there, neighbo...' 44644 * 44645 * _.trunc('hi-diddly-ho there, neighborino', 24); 44646 * // => 'hi-diddly-ho there, n...' 44647 * 44648 * _.trunc('hi-diddly-ho there, neighborino', { 44649 * 'length': 24, 44650 * 'separator': ' ' 44651 * }); 44652 * // => 'hi-diddly-ho there,...' 44653 * 44654 * _.trunc('hi-diddly-ho there, neighborino', { 44655 * 'length': 24, 44656 * 'separator': /,? +/ 44657 * }); 44658 * // => 'hi-diddly-ho there...' 44659 * 44660 * _.trunc('hi-diddly-ho there, neighborino', { 44661 * 'omission': ' [...]' 44662 * }); 44663 * // => 'hi-diddly-ho there, neig [...]' 44664 */ 44665 function trunc(string, options, guard) { 44666 if (guard && isIterateeCall(string, options, guard)) { 44667 options = undefined; 44668 } 44669 var length = DEFAULT_TRUNC_LENGTH, 44670 omission = DEFAULT_TRUNC_OMISSION; 44671 44672 if (options != null) { 44673 if (isObject(options)) { 44674 var separator = 'separator' in options ? options.separator : separator; 44675 length = 'length' in options ? (+options.length || 0) : length; 44676 omission = 'omission' in options ? baseToString(options.omission) : omission; 44677 } else { 44678 length = +options || 0; 44679 } 44680 }
44681 string = baseToString(string); 44682 if (length >= string.length) { 44683 return string; 44684 } 44685 var end = length - omission.length; 44686 if (end < 1) { 44687 return omission; 44688 } 44689 var result = string.slice(0, end); 44690 if (separator == null) { 44691 return result + omission; 44692 } 44693 if (isRegExp(separator)) { 44694 if (string.slice(end).search(separator)) { 44695 var match, 44696 newEnd, 44697 substring = string.slice(0, end); 44698 44699 if (!separator.global) { 44700 separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g'); 44701 } 44702 separator.lastIndex = 0; 44703 while ((match = separator.exec(substring))) { 44704 newEnd = match.index; 44705 } 44706 result = result.slice(0, newEnd == null ? end : newEnd); 44707 } 44708 } else if (string.indexOf(separator, end) != end) { 44709 var index = result.lastIndexOf(separator); 44710 if (index > -1) { 44711 result = result.slice(0, index); 44712 } 44713 } 44714 return result + omission; 44715 } 44716 44717 /** 44718 * The inverse of `_.escape`; this method converts the HTML entities 44719 * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to their 44720 * corresponding characters. 44721 * 44722 * **Note:** No other HTML entities are unescaped. To unescape additional HTML 44723 * entities use a third-party library like [_he_](https://mths.be/he). 44724 * 44725 * @static 44726 * @memberOf _ 44727 * @category String 44728 * @param {string} [string=''] The string to unescape. 44729 * @returns {string} Returns the unescaped string. 44730 * @example 44731 * 44732 * _.unescape('fred, barney, & pebbles'); 44733 * // => 'fred, barney, & pebbles' 44734 */ 44735 function unescape(string) { 44736 string = baseToString(string); 44737 return (string && reHasEscapedHtml.test(string)) 44738 ? string.replace(reEscapedHtml, unescapeHtmlChar) 44739 : string; 44740 } 44741 44742 /** 44743 * Splits `string` into an array of its words. 44744 * 44745 * @static 44746 * @memberOf _ 44747 * @category String 44748 * @param {string} [string=''] The string to inspect. 44749 * @param {RegExp|string} [pattern] The pattern to match words. 44750 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 44751 * @returns {Array} Returns the words of `string`. 44752 * @example 44753 * 44754 * _.words('fred, barney, & pebbles'); 44755 * // => ['fred', 'barney', 'pebbles'] 44756 * 44757 * _.words('fred, barney, & pebbles', /[^, ]+/g); 44758 * // => ['fred', 'barney', '&', 'pebbles'] 44759 */ 44760 function words(string, pattern, guard) { 44761 if (guard && isIterateeCall(string, pattern, guard)) { 44762 pattern = undefined; 44763 } 44764 string = baseToString(string); 44765 return string.match(pattern || reWords) || []; 44766 } 44767 44768 /*------------------------------------------------------------------------*/ 44769 44770 /** 44771 * Attempts to invoke `func`, returning either the result or the caught error 44772 * object. Any additional arguments are provided to `func` when it is invoked. 44773 * 44774 * @static 44775 * @memberOf _ 44776 * @category Utility 44777 * @param {Function} func The function to attempt. 44778 * @returns {*} Returns the `func` result or error object. 44779 * @example 44780 * 44781 * // avoid throwing errors for invalid selectors 44782 * var elements = _.attempt(function(selector) { 44783 * return document.querySelectorAll(selector); 44784 * }, '>_>'); 44785 * 44786 * if (_.isError(elements)) { 44787 * elements = []; 44788 * } 44789 */ 44790 var attempt = restParam(function(func, args) { 44791 try { 44792 return func.apply(undefined, args); 44793 } catch(e) { 44794 return isError(e) ? e : new Error(e); 44795 } 44796 }); 44797 44798 /** 44799 * Creates a function that invokes `func` with the `this` binding of `thisArg` 44800 * and arguments of the created function. If `func` is a property name the 44801 * created callback returns the property value for a given element. If `func` 44802 * is an object the created callback returns `true` for elements that contain 44803 * the equivalent object properties, otherwise it returns `false`. 44804 * 44805 * @static 44806 * @memberOf _ 44807 * @alias iteratee 44808 * @category Utility 44809 * @param {*} [func=_.identity] The value to convert to a callback. 44810 * @param {*} [thisArg] The `this` binding of `func`. 44811 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. 44812 * @returns {Function} Returns the callback. 44813 * @example 44814 * 44815 * var users = [ 44816 * { 'user': 'barney', 'age': 36 }, 44817 * { 'user': 'fred', 'age': 40 } 44818 * ]; 44819 * 44820 * // wrap to create custom callback shorthands 44821 * _.callback = _.wrap(_.callback, function(callback, func, thisArg) { 44822 * var match = /^(.+?)__([gl]t)(.+)$/.exec(func); 44823 * if (!match) { 44824 * return callback(func, thisArg); 44825 * } 44826 * return function(object) { 44827 * return match[2] == 'gt' 44828 * ? object[match[1]] > match[3] 44829 * : object[match[1]] < match[3]; 44830 * }; 44831 * }); 44832 * 44833 * _.filter(users, 'age__gt36'); 44834 * // => [{ 'user': 'fred', 'age': 40 }] 44835 */ 44836 function callback(func, thisArg, guard) { 44837 if (guard && isIterateeCall(func, thisArg, guard)) { 44838 thisArg = undefined; 44839 } 44840 return isObjectLike(func) 44841 ? matches(func) 44842 : baseCallback(func, thisArg); 44843 } 44844 44845 /** 44846 * Creates a function that returns `value`. 44847 * 44848 * @static 44849 * @memberOf _ 44850 * @category Utility 44851 * @param {*} value The value to return from the new function. 44852 * @returns {Function} Returns the new function. 44853 * @example 44854 * 44855 * var object = { 'user': 'fred' }; 44856 * var getter = _.constant(object); 44857 * 44858 * getter() === object; 44859 * // => true 44860 */ 44861 function constant(value) { 44862 return function() { 44863 return value; 44864 }; 44865 } 44866 44867 /** 44868 * This method returns the first argument provided to it. 44869 * 44870 * @static 44871 * @memberOf _ 44872 * @category Utility 44873 * @param {*} value Any value. 44874 * @returns {*} Returns `value`. 44875 * @example 44876 * 44877 * var object = { 'user': 'fred' }; 44878 * 44879 * _.identity(object) === object; 44880 * // => true 44881 */ 44882 function identity(value) { 44883 return value; 44884 } 44885 44886 /** 44887 * Creates a function that performs a deep comparison between a given object 44888 * and `source`, returning `true` if the given object has equivalent property 44889 * values, else `false`. 44890 * 44891 * **Note:** This method supports comparing arrays, booleans, `Date` objects, 44892 * numbers, `Object` objects, regexes, and strings. Objects are compared by 44893 * their own, not inherited, enumerable properties. For comparing a single 44894 * own or inherited property value see `_.matchesProperty`. 44895 * 44896 * @static 44897 * @memberOf _ 44898 * @category Utility 44899 * @param {Object} source The object of property values to match. 44900 * @returns {Function} Returns the new function. 44901 * @example 44902 * 44903 * var users = [ 44904 * { 'user': 'barney', 'age': 36, 'active': true }, 44905 * { 'user': 'fred', 'age': 40, 'active': false } 44906 * ]; 44907 * 44908 * _.filter(users, _.matches({ 'age': 40, 'active': false })); 44909 * // => [{ 'user': 'fred', 'age': 40, 'active': false }] 44910 */ 44911 function matches(source) { 44912 return baseMatches(baseClone(source, true)); 44913 } 44914 44915 /** 44916 * Creates a function that compares the property value of `path` on a given 44917 * object to `value`. 44918 * 44919 * **Note:** This method supports comparing arrays, booleans, `Date` objects, 44920 * numbers, `Object` objects, regexes, and strings. Objects are compared by 44921 * their own, not inherited, enumerable properties. 44922 * 44923 * @static 44924 * @memberOf _ 44925 * @category Utility 44926 * @param {Array|string} path The path of the property to get. 44927 * @param {*} srcValue The value to match. 44928 * @returns {Function} Returns the new function. 44929 * @example 44930 * 44931 * var users = [ 44932 * { 'user': 'barney' }, 44933 * { 'user': 'fred' } 44934 * ]; 44935 * 44936 * _.find(users, _.matchesProperty('user', 'fred')); 44937 * // => { 'user': 'fred' } 44938 */ 44939 function matchesProperty(path, srcValue) { 44940 return baseMatchesProperty(path, baseClone(srcValue, true)); 44941 } 44942 44943 /** 44944 * Creates a function that invokes the method at `path` on a given object. 44945 * Any additional arguments are provided to the invoked method. 44946 * 44947 * @static 44948 * @memberOf _ 44949 * @category Utility 44950 * @param {Array|string} path The path of the method to invoke. 44951 * @param {...*} [args] The arguments to invoke the method with. 44952 * @returns {Function} Returns the new function. 44953 * @example 44954 * 44955 * var objects = [ 44956 * { 'a': { 'b': { 'c': _.constant(2) } } }, 44957 * { 'a': { 'b': { 'c': _.constant(1) } } } 44958 * ]; 44959 * 44960 * _.map(objects, _.method('a.b.c')); 44961 * // => [2, 1] 44962 * 44963 * _.invoke(_.sortBy(objects, _.method(['a', 'b', 'c'])), 'a.b.c'); 44964 * // => [1, 2] 44965 */ 44966 var method = restParam(function(path, args) { 44967 return function(object) { 44968 return invokePath(object, path, args); 44969 }; 44970 }); 44971 44972 /** 44973 * The opposite of `_.method`; this method creates a function that invokes 44974 * the method at a given path on `object`. Any additional arguments are 44975 * provided to the invoked method. 44976 * 44977 * @static 44978 * @memberOf _ 44979 * @category Utility 44980 * @param {Object} object The object to query. 44981 * @param {...*} [args] The arguments to invoke the method with. 44982 * @returns {Function} Returns the new function. 44983 * @example 44984 * 44985 * var array = _.times(3, _.constant), 44986 * object = { 'a': array, 'b': array, 'c': array }; 44987 * 44988 * _.map(['a[2]', 'c[0]'], _.methodOf(object)); 44989 * // => [2, 0] 44990 * 44991 * _.map([['a', '2'], ['c', '0']], _.methodOf(object)); 44992 * // => [2, 0] 44993 */ 44994 var methodOf = restParam(function(object, args) { 44995 return function(path) { 44996 return invokePath(object, path, args); 44997 }; 44998 }); 44999 45000 /** 45001 * Adds all own enumerable function properties of a source object to the 45002 * destination object. If `object` is a function then methods are added to 45003 * its prototype as well. 45004 * 45005 * **Note:** Use `_.runInContext` to create a pristine `lodash` function to 45006 * avoid conflicts caused by modifying the original. 45007 * 45008 * @static 45009 * @memberOf _ 45010 * @category Utility 45011 * @param {Function|Object} [object=lodash] The destination object. 45012 * @param {Object} source The object of functions to add. 45013 * @param {Object} [options] The options object. 45014 * @param {boolean} [options.chain=true] Specify whether the functions added 45015 * are chainable. 45016 * @returns {Function|Object} Returns `object`. 45017 * @example 45018 * 45019 * function vowels(string) { 45020 * return _.filter(string, function(v) { 45021 * return /[aeiou]/i.test(v); 45022 * }); 45023 * } 45024 * 45025 * _.mixin({ 'vowels': vowels }); 45026 * _.vowels('fred'); 45027 * // => ['e'] 45028 *
45029 * _('fred').vowels().value(); 45030 * // => ['e'] 45031 * 45032 * _.mixin({ 'vowels': vowels }, { 'chain': false }); 45033 * _('fred').vowels(); 45034 * // => ['e'] 45035 */ 45036 function mixin(object, source, options) { 45037 if (options == null) { 45038 var isObj = isObject(source), 45039 props = isObj ? keys(source) : undefined, 45040 methodNames = (props && props.length) ? baseFunctions(source, props) : undefined; 45041 45042 if (!(methodNames ? methodNames.length : isObj)) { 45043 methodNames = false; 45044 options = source; 45045 source = object; 45046 object = this; 45047 } 45048 } 45049 if (!methodNames) { 45050 methodNames = baseFunctions(source, keys(source)); 45051 } 45052 var chain = true, 45053 index = -1, 45054 isFunc = isFunction(object), 45055 length = methodNames.length; 45056 45057 if (options === false) { 45058 chain = false; 45059 } else if (isObject(options) && 'chain' in options) { 45060 chain = options.chain; 45061 } 45062 while (++index < length) { 45063 var methodName = methodNames[index], 45064 func = source[methodName]; 45065 45066 object[methodName] = func; 45067 if (isFunc) { 45068 object.prototype[methodName] = (function(func) { 45069 return function() { 45070 var chainAll = this.__chain__; 45071 if (chain || chainAll) { 45072 var result = object(this.__wrapped__), 45073 actions = result.__actions__ = arrayCopy(this.__actions__); 45074 45075 actions.push({ 'func': func, 'args': arguments, 'thisArg': object }); 45076 result.__chain__ = chainAll; 45077 return result; 45078 } 45079 return func.apply(object, arrayPush([this.value()], arguments)); 45080 }; 45081 }(func)); 45082 } 45083 } 45084 return object; 45085 } 45086 45087 /** 45088 * Reverts the `_` variable to its previous value and returns a reference to 45089 * the `lodash` function. 45090 * 45091 * @static 45092 * @memberOf _ 45093 * @category Utility 45094 * @returns {Function} Returns the `lodash` function. 45095 * @example 45096 * 45097 * var lodash = _.noConflict(); 45098 */ 45099 function noConflict() { 45100 root._ = oldDash; 45101 return this; 45102 } 45103 45104 /** 45105 * A no-operation function that returns `undefined` regardless of the 45106 * arguments it receives. 45107 * 45108 * @static 45109 * @memberOf _ 45110 * @category Utility 45111 * @example 45112 * 45113 * var object = { 'user': 'fred' }; 45114 * 45115 * _.noop(object) === undefined; 45116 * // => true 45117 */ 45118 function noop() { 45119 // No operation performed. 45120 } 45121 45122 /** 45123 * Creates a function that returns the property value at `path` on a 45124 * given object. 45125 * 45126 * @static 45127 * @memberOf _ 45128 * @category Utility 45129 * @param {Array|string} path The path of the property to get. 45130 * @returns {Function} Returns the new function. 45131 * @example 45132 * 45133 * var objects = [ 45134 * { 'a': { 'b': { 'c': 2 } } }, 45135 * { 'a': { 'b': { 'c': 1 } } } 45136 * ]; 45137 * 45138 * _.map(objects, _.property('a.b.c')); 45139 * // => [2, 1] 45140 * 45141 * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c'); 45142 * // => [1, 2] 45143 */ 45144 function property(path) { 45145 return isKey(path) ? baseProperty(path) : basePropertyDeep(path); 45146 } 45147 45148 /** 45149 * The opposite of `_.property`; this method creates a function that returns 45150 * the property value at a given path on `object`. 45151 * 45152 * @static 45153 * @memberOf _ 45154 * @category Utility 45155 * @param {Object} object The object to query. 45156 * @returns {Function} Returns the new function. 45157 * @example 45158 * 45159 * var array = [0, 1, 2], 45160 * object = { 'a': array, 'b': array, 'c': array }; 45161 * 45162 * _.map(['a[2]', 'c[0]'], _.propertyOf(object)); 45163 * // => [2, 0] 45164 * 45165 * _.map([['a', '2'], ['c', '0']], _.propertyOf(object)); 45166 * // => [2, 0] 45167 */ 45168 function propertyOf(object) { 45169 return function(path) { 45170 return baseGet(object, toPath(path), path + ''); 45171 }; 45172 } 45173 45174 /** 45175 * Creates an array of numbers (positive and/or negative) progressing from 45176 * `start` up to, but not including, `end`. If `end` is not specified it is 45177 * set to `start` with `start` then set to `0`. If `end` is less than `start` 45178 * a zero-length range is created unless a negative `step` is specified. 45179 * 45180 * @static 45181 * @memberOf _ 45182 * @category Utility 45183 * @param {number} [start=0] The start of the range. 45184 * @param {number} end The end of the range. 45185 * @param {number} [step=1] The value to increment or decrement by. 45186 * @returns {Array} Returns the new array of numbers. 45187 * @example 45188 * 45189 * _.range(4); 45190 * // => [0, 1, 2, 3] 45191 * 45192 * _.range(1, 5); 45193 * // => [1, 2, 3, 4] 45194 * 45195 * _.range(0, 20, 5); 45196 * // => [0, 5, 10, 15] 45197 * 45198 * _.range(0, -4, -1); 45199 * // => [0, -1, -2, -3] 45200 * 45201 * _.range(1, 4, 0); 45202 * // => [1, 1, 1] 45203 * 45204 * _.range(0); 45205 * // => [] 45206 */ 45207 function range(start, end, step) { 45208 if (step && isIterateeCall(start, end, step)) { 45209 end = step = undefined; 45210 } 45211 start = +start || 0; 45212 step = step == null ? 1 : (+step || 0); 45213 45214 if (end == null) { 45215 end = start; 45216 start = 0; 45217 } else { 45218 end = +end || 0; 45219 } 45220 // Use `Array(length)` so engines like Chakra and V8 avoid slower modes. 45221 // See https://youtu.be/XAqIpGU8ZZk#t=17m25s for more details. 45222 var index = -1, 45223 length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), 45224 result = Array(length); 45225 45226 while (++index < length) { 45227 result[index] = start; 45228 start += step; 45229 } 45230 return result; 45231 } 45232 45233 /** 45234 * Invokes the iteratee function `n` times, returning an array of the results 45235 * of each invocation. The `iteratee` is bound to `thisArg` and invoked with 45236 * one argument; (index). 45237 * 45238 * @static 45239 * @memberOf _ 45240 * @category Utility 45241 * @param {number} n The number of times to invoke `iteratee`. 45242 * @param {Function} [iteratee=_.identity] The function invoked per iteration. 45243 * @param {*} [thisArg] The `this` binding of `iteratee`. 45244 * @returns {Array} Returns the array of results. 45245 * @example 45246 * 45247 * var diceRolls = _.times(3, _.partial(_.random, 1, 6, false)); 45248 * // => [3, 6, 4] 45249 * 45250 * _.times(3, function(n) { 45251 * mage.castSpell(n); 45252 * }); 45253 * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` 45254 * 45255 * _.times(3, function(n) { 45256 * this.cast(n); 45257 * }, mage); 45258 * // => also invokes `mage.castSpell(n)` three times 45259 */ 45260 function times(n, iteratee, thisArg) { 45261 n = nativeFloor(n); 45262 45263 // Exit early to avoid a JSC JIT bug in Safari 8 45264 // where `Array(0)` is treated as `Array(1)`. 45265 if (n < 1 || !nativeIsFinite(n)) { 45266 return []; 45267 } 45268 var index = -1, 45269 result = Array(nativeMin(n, MAX_ARRAY_LENGTH)); 45270 45271 iteratee = bindCallback(iteratee, thisArg, 1); 45272 while (++index < n) { 45273 if (index < MAX_ARRAY_LENGTH) { 45274 result[index] = iteratee(index); 45275 } else { 45276 iteratee(index); 45277 } 45278 } 45279 return result; 45280 } 45281 45282 /** 45283 * Generates a unique ID. If `prefix` is provided the ID is appended to it. 45284 * 45285 * @static 45286 * @memberOf _ 45287 * @category Utility 45288 * @param {string} [prefix] The value to prefix the ID with. 45289 * @returns {string} Returns the unique ID. 45290 * @example 45291 * 45292 * _.uniqueId('contact_'); 45293 * // => 'contact_104' 45294 * 45295 * _.uniqueId(); 45296 * // => '105' 45297 */ 45298 function uniqueId(prefix) { 45299 var id = ++idCounter; 45300 return baseToString(prefix) + id; 45301 } 45302 45303 /*------------------------------------------------------------------------*/ 45304 45305 /** 45306 * Adds two numbers. 45307 * 45308 * @static 45309 * @memberOf _ 45310 * @category Math 45311 * @param {number} augend The first number to add. 45312 * @param {number} addend The second number to add. 45313 * @returns {number} Returns the sum. 45314 * @example 45315 * 45316 * _.add(6, 4); 45317 * // => 10 45318 */ 45319 function add(augend, addend) { 45320 return (+augend || 0) + (+addend || 0); 45321 } 45322 45323 /** 45324 * Calculates `n` rounded up to `precision`. 45325 * 45326 * @static 45327 * @memberOf _ 45328 * @category Math 45329 * @param {number} n The number to round up. 45330 * @param {number} [precision=0] The precision to round up to. 45331 * @returns {number} Returns the rounded up number. 45332 * @example 45333 * 45334 * _.ceil(4.006); 45335 * // => 5 45336 * 45337 * _.ceil(6.004, 2); 45338 * // => 6.01 45339 * 45340 * _.ceil(6040, -2); 45341 * // => 6100 45342 */ 45343 var ceil = createRound('ceil'); 45344 45345 /** 45346 * Calculates `n` rounded down to `precision`. 45347 * 45348 * @static 45349 * @memberOf _ 45350 * @category Math 45351 * @param {number} n The number to round down. 45352 * @param {number} [precision=0] The precision to round down to. 45353 * @returns {number} Returns the rounded down number. 45354 * @example 45355 * 45356 * _.floor(4.006); 45357 * // => 4 45358 * 45359 * _.floor(0.046, 2); 45360 * // => 0.04 45361 * 45362 * _.floor(4060, -2); 45363 * // => 4000 45364 */ 45365 var floor = createRound('floor'); 45366 45367 /** 45368 * Gets the maximum value of `collection`. If `collection` is empty or falsey 45369 * `-Infinity` is returned. If an iteratee function is provided it is invoked 45370 * for each value in `collection` to generate the criterion by which the value 45371 * is ranked. The `iteratee` is bound to `thisArg` and invoked with three 45372 * arguments: (value, index, collection). 45373 * 45374 * If a property name is provided for `iteratee` the created `_.property` 45375 * style callback returns the property value of the given element. 45376 * 45377 * If a value is also provided for `thisArg` the created `_.matchesProperty` 45378 * style callback returns `true` for elements that have a matching property 45379 * value, else `false`. 45380 * 45381 * If an object is provided for `iteratee` the created `_.matches` style 45382 * callback returns `true` for elements that have the properties of the given 45383 * object, else `false`. 45384 * 45385 * @static 45386 * @memberOf _ 45387 * @category Math 45388 * @param {Array|Object|string} collection The collection to iterate over. 45389 * @param {Function|Object|string} [iteratee] The function invoked per iteration. 45390 * @param {*} [thisArg] The `this` binding of `iteratee`. 45391 * @returns {*} Returns the maximum value. 45392 * @example 45393 * 45394 * _.max([4, 2, 8, 6]); 45395 * // => 8 45396 * 45397 * _.max([]); 45398 * // => -Infinity 45399 * 45400 * var users = [ 45401 * { 'user': 'barney', 'age': 36 }, 45402 * { 'user': 'fred', 'age': 40 } 45403 * ]; 45404 * 45405 * _.max(users, function(chr) { 45406 * return chr.age; 45407 * }); 45408 * // => { 'user': 'fred', 'age': 40 } 45409 *
45410 * // using the `_.property` callback shorthand 45411 * _.max(users, 'age'); 45412 * // => { 'user': 'fred', 'age': 40 } 45413 */ 45414 var max = createExtremum(gt, NEGATIVE_INFINITY); 45415 45416 /** 45417 * Gets the minimum value of `collection`. If `collection` is empty or falsey 45418 * `Infinity` is returned. If an iteratee function is provided it is invoked 45419 * for each value in `collection` to generate the criterion by which the value 45420 * is ranked. The `iteratee` is bound to `thisArg` and invoked with three 45421 * arguments: (value, index, collection). 45422 * 45423 * If a property name is provided for `iteratee` the created `_.property` 45424 * style callback returns the property value of the given element. 45425 * 45426 * If a value is also provided for `thisArg` the created `_.matchesProperty` 45427 * style callback returns `true` for elements that have a matching property 45428 * value, else `false`. 45429 * 45430 * If an object is provided for `iteratee` the created `_.matches` style 45431 * callback returns `true` for elements that have the properties of the given 45432 * object, else `false`. 45433 * 45434 * @static 45435 * @memberOf _ 45436 * @category Math 45437 * @param {Array|Object|string} collection The collection to iterate over. 45438 * @param {Function|Object|string} [iteratee] The function invoked per iteration. 45439 * @param {*} [thisArg] The `this` binding of `iteratee`. 45440 * @returns {*} Returns the minimum value. 45441 * @example 45442 * 45443 * _.min([4, 2, 8, 6]); 45444 * // => 2 45445 * 45446 * _.min([]); 45447 * // => Infinity 45448 * 45449 * var users = [ 45450 * { 'user': 'barney', 'age': 36 }, 45451 * { 'user': 'fred', 'age': 40 } 45452 * ]; 45453 * 45454 * _.min(users, function(chr) { 45455 * return chr.age; 45456 * }); 45457 * // => { 'user': 'barney', 'age': 36 } 45458 * 45459 * // using the `_.property` callback shorthand 45460 * _.min(users, 'age'); 45461 * // => { 'user': 'barney', 'age': 36 } 45462 */ 45463 var min = createExtremum(lt, POSITIVE_INFINITY); 45464 45465 /** 45466 * Calculates `n` rounded to `precision`. 45467 * 45468 * @static 45469 * @memberOf _ 45470 * @category Math 45471 * @param {number} n The number to round. 45472 * @param {number} [precision=0] The precision to round to. 45473 * @returns {number} Returns the rounded number. 45474 * @example 45475 * 45476 * _.round(4.006); 45477 * // => 4 45478 * 45479 * _.round(4.006, 2); 45480 * // => 4.01 45481 * 45482 * _.round(4060, -2); 45483 * // => 4100 45484 */ 45485 var round = createRound('round'); 45486 45487 /** 45488 * Gets the sum of the values in `collection`. 45489 * 45490 * @static 45491 * @memberOf _ 45492 * @category Math 45493 * @param {Array|Object|string} collection The collection to iterate over. 45494 * @param {Function|Object|string} [iteratee] The function invoked per iteration. 45495 * @param {*} [thisArg] The `this` binding of `iteratee`. 45496 * @returns {number} Returns the sum. 45497 * @example 45498 * 45499 * _.sum([4, 6]); 45500 * // => 10 45501 * 45502 * _.sum({ 'a': 4, 'b': 6 }); 45503 * // => 10 45504 * 45505 * var objects = [ 45506 * { 'n': 4 }, 45507 * { 'n': 6 } 45508 * ]; 45509 * 45510 * _.sum(objects, function(object) { 45511 * return object.n; 45512 * }); 45513 * // => 10 45514 * 45515 * // using the `_.property` callback shorthand 45516 * _.sum(objects, 'n'); 45517 * // => 10 45518 */ 45519 function sum(collection, iteratee, thisArg) { 45520 if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { 45521 iteratee = undefined; 45522 } 45523 iteratee = getCallback(iteratee, thisArg, 3); 45524 return iteratee.length == 1 45525 ? arraySum(isArray(collection) ? collection : toIterable(collection), iteratee) 45526 : baseSum(collection, iteratee); 45527 } 45528 45529 /*------------------------------------------------------------------------*/ 45530 45531 // Ensure wrappers are instances of `baseLodash`. 45532 lodash.prototype = baseLodash.prototype; 45533 45534 LodashWrapper.prototype = baseCreate(baseLodash.prototype); 45535 LodashWrapper.prototype.constructor = LodashWrapper; 45536 45537 LazyWrapper.prototype = baseCreate(baseLodash.prototype); 45538 LazyWrapper.prototype.constructor = LazyWrapper; 45539 45540 // Add functions to the `Map` cache. 45541 MapCache.prototype['delete'] = mapDelete; 45542 MapCache.prototype.get = mapGet; 45543 MapCache.prototype.has = mapHas; 45544 MapCache.prototype.set = mapSet; 45545 45546 // Add functions to the `Set` cache. 45547 SetCache.prototype.push = cachePush; 45548 45549 // Assign cache to `_.memoize`. 45550 memoize.Cache = MapCache; 45551 45552 // Add functions that return wrapped values when chaining. 45553 lodash.after = after; 45554 lodash.ary = ary; 45555 lodash.assign = assign; 45556 lodash.at = at; 45557 lodash.before = before; 45558 lodash.bind = bind; 45559 lodash.bindAll = bindAll; 45560 lodash.bindKey = bindKey; 45561 lodash.callback = callback; 45562 lodash.chain = chain; 45563 lodash.chunk = chunk; 45564 lodash.compact = compact; 45565 lodash.constant = constant; 45566 lodash.countBy = countBy; 45567 lodash.create = create; 45568 lodash.curry = curry; 45569 lodash.curryRight = curryRight; 45570 lodash.debounce = debounce; 45571 lodash.defaults = defaults; 45572 lodash.defaultsDeep = defaultsDeep; 45573 lodash.defer = defer;
45574 lodash.delay = delay; 45575 lodash.difference = difference; 45576 lodash.drop = drop; 45577 lodash.dropRight = dropRight; 45578 lodash.dropRightWhile = dropRightWhile; 45579 lodash.dropWhile = dropWhile; 45580 lodash.fill = fill; 45581 lodash.filter = filter; 45582 lodash.flatten = flatten; 45583 lodash.flattenDeep = flattenDeep; 45584 lodash.flow = flow; 45585 lodash.flowRight = flowRight; 45586 lodash.forEach = forEach; 45587 lodash.forEachRight = forEachRight; 45588 lodash.forIn = forIn; 45589 lodash.forInRight = forInRight; 45590 lodash.forOwn = forOwn; 45591 lodash.forOwnRight = forOwnRight; 45592 lodash.functions = functions; 45593 lodash.groupBy = groupBy; 45594 lodash.indexBy = indexBy; 45595 lodash.initial = initial; 45596 lodash.intersection = intersection; 45597 lodash.invert = invert; 45598 lodash.invoke = invoke; 45599 lodash.keys = keys; 45600 lodash.keysIn = keysIn; 45601 lodash.map = map; 45602 lodash.mapKeys = mapKeys; 45603 lodash.mapValues = mapValues; 45604 lodash.matches = matches; 45605 lodash.matchesProperty = matchesProperty; 45606 lodash.memoize = memoize; 45607 lodash.merge = merge; 45608 lodash.method = method; 45609 lodash.methodOf = methodOf; 45610 lodash.mixin = mixin; 45611 lodash.modArgs = modArgs; 45612 lodash.negate = negate; 45613 lodash.omit = omit; 45614 lodash.once = once; 45615 lodash.pairs = pairs; 45616 lodash.partial = partial; 45617 lodash.partialRight = partialRight; 45618 lodash.partition = partition; 45619 lodash.pick = pick; 45620 lodash.pluck = pluck; 45621 lodash.property = property; 45622 lodash.propertyOf = propertyOf; 45623 lodash.pull = pull; 45624 lodash.pullAt = pullAt; 45625 lodash.range = range; 45626 lodash.rearg = rearg; 45627 lodash.reject = reject; 45628 lodash.remove = remove; 45629 lodash.rest = rest; 45630 lodash.restParam = restParam; 45631 lodash.set = set; 45632 lodash.shuffle = shuffle; 45633 lodash.slice = slice; 45634 lodash.sortBy = sortBy; 45635 lodash.sortByAll = sortByAll; 45636 lodash.sortByOrder = sortByOrder; 45637 lodash.spread = spread; 45638 lodash.take = take; 45639 lodash.takeRight = takeRight; 45640 lodash.takeRightWhile = takeRightWhile; 45641 lodash.takeWhile = takeWhile; 45642 lodash.tap = tap; 45643 lodash.throttle = throttle; 45644 lodash.thru = thru; 45645 lodash.times = times; 45646 lodash.toArray = toArray; 45647 lodash.toPlainObject = toPlainObject; 45648 lodash.transform = transform; 45649 lodash.union = union; 45650 lodash.uniq = uniq; 45651 lodash.unzip = unzip; 45652 lodash.unzipWith = unzipWith; 45653 lodash.values = values; 45654 lodash.valuesIn = valuesIn; 45655 lodash.where = where; 45656 lodash.without = without; 45657 lodash.wrap = wrap; 45658 lodash.xor = xor; 45659 lodash.zip = zip; 45660 lodash.zipObject = zipObject; 45661 lodash.zipWith = zipWith; 45662 45663 // Add aliases. 45664 lodash.backflow = flowRight; 45665 lodash.collect = map; 45666 lodash.compose = flowRight; 45667 lodash.each = forEach; 45668 lodash.eachRight = forEachRight; 45669 lodash.extend = assign; 45670 lodash.iteratee = callback; 45671 lodash.methods = functions; 45672 lodash.object = zipObject; 45673 lodash.select = filter; 45674 lodash.tail = rest; 45675 lodash.unique = uniq; 45676 45677 // Add functions to `lodash.prototype`. 45678 mixin(lodash, lodash); 45679 45680 /*------------------------------------------------------------------------*/ 45681 45682 // Add functions that return unwrapped values when chaining. 45683 lodash.add = add; 45684 lodash.attempt = attempt; 45685 lodash.camelCase = camelCase; 45686 lodash.capitalize = capitalize; 45687 lodash.ceil = ceil; 45688 lodash.clone = clone; 45689 lodash.cloneDeep = cloneDeep; 45690 lodash.deburr = deburr; 45691 lodash.endsWith = endsWith; 45692 lodash.escape = escape; 45693 lodash.escapeRegExp = escapeRegExp; 45694 lodash.every = every; 45695 lodash.find = find; 45696 lodash.findIndex = findIndex; 45697 lodash.findKey = findKey; 45698 lodash.findLast = findLast; 45699 lodash.findLastIndex = findLastIndex; 45700 lodash.findLastKey = findLastKey; 45701 lodash.findWhere = findWhere; 45702 lodash.first = first; 45703 lodash.floor = floor; 45704 lodash.get = get; 45705 lodash.gt = gt; 45706 lodash.gte = gte; 45707 lodash.has = has; 45708 lodash.identity = identity; 45709 lodash.includes = includes; 45710 lodash.indexOf = indexOf; 45711 lodash.inRange = inRange; 45712 lodash.isArguments = isArguments; 45713 lodash.isArray = isArray; 45714 lodash.isBoolean = isBoolean; 45715 lodash.isDate = isDate; 45716 lodash.isElement = isElement; 45717 lodash.isEmpty = isEmpty; 45718 lodash.isEqual = isEqual; 45719 lodash.isError = isError; 45720 lodash.isFinite = isFinite; 45721 lodash.isFunction = isFunction; 45722 lodash.isMatch = isMatch; 45723 lodash.isNaN = isNaN; 45724 lodash.isNative = isNative; 45725 lodash.isNull = isNull; 45726 lodash.isNumber = isNumber; 45727 lodash.isObject = isObject; 45728 lodash.isPlainObject = isPlainObject; 45729 lodash.isRegExp = isRegExp; 45730 lodash.isString = isString; 45731 lodash.isTypedArray = isTypedArray; 45732 lodash.isUndefined = isUndefined; 45733 lodash.kebabCase = kebabCase; 45734 lodash.last = last; 45735 lodash.lastIndexOf = lastIndexOf; 45736 lodash.lt = lt; 45737 lodash.lte = lte; 45738 lodash.max = max; 45739 lodash.min = min; 45740 lodash.noConflict = noConflict; 45741 lodash.noop = noop; 45742 lodash.now = now; 45743 lodash.pad = pad; 45744 lodash.padLeft = padLeft; 45745 lodash.padRight = padRight; 45746 lodash.parseInt = parseInt; 45747 lodash.random = random; 45748 lodash.reduce = reduce; 45749 lodash.reduceRight = reduceRight; 45750 lodash.repeat = repeat; 45751 lodash.result = result; 45752 lodash.round = round; 45753 lodash.runInContext = runInContext; 45754 lodash.size = size; 45755 lodash.snakeCase = snakeCase; 45756 lodash.some = some; 45757 lodash.sortedIndex = sortedIndex; 45758 lodash.sortedLastIndex = sortedLastIndex; 45759 lodash.startCase = startCase; 45760 lodash.startsWith = startsWith; 45761 lodash.sum = sum; 45762 lodash.template = template; 45763 lodash.trim = trim; 45764 lodash.trimLeft = trimLeft; 45765 lodash.trimRight = trimRight; 45766 lodash.trunc = trunc; 45767 lodash.unescape = unescape; 45768 lodash.uniqueId = uniqueId; 45769 lodash.words = words; 45770 45771 // Add aliases. 45772 lodash.all = every; 45773 lodash.any = some; 45774 lodash.contains = includes; 45775 lodash.eq = isEqual; 45776 lodash.detect = find; 45777 lodash.foldl = reduce; 45778 lodash.foldr = reduceRight; 45779 lodash.head = first; 45780 lodash.include = includes; 45781 lodash.inject = reduce; 45782 45783 mixin(lodash, (function() { 45784 var source = {}; 45785 baseForOwn(lodash, function(func, methodName) { 45786 if (!lodash.prototype[methodName]) { 45787 source[methodName] = func; 45788 } 45789 }); 45790 return source; 45791 }()), false); 45792 45793 /*------------------------------------------------------------------------*/ 45794 45795 // Add functions capable of returning wrapped and unwrapped values when chaining. 45796 lodash.sample = sample; 45797 45798 lodash.prototype.sample = function(n) { 45799 if (!this.__chain__ && n == null) { 45800 return sample(this.value()); 45801 } 45802 return this.thru(function(value) { 45803 return sample(value, n); 45804 }); 45805 }; 45806 45807 /*------------------------------------------------------------------------*/ 45808 45809 /** 45810 * The semantic version number. 45811 * 45812 * @static 45813 * @memberOf _ 45814 * @type string 45815 */ 45816 lodash.VERSION = VERSION; 45817 45818 // Assign default placeholders. 45819 arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) { 45820 lodash[methodName].placeholder = lodash; 45821 }); 45822 45823 // Add `LazyWrapper` methods for `_.drop` and `_.take` variants. 45824 arrayEach(['drop', 'take'], function(methodName, index) { 45825 LazyWrapper.prototype[methodName] = function(n) { 45826 var filtered = this.__filtered__; 45827 if (filtered && !index) {
45828 return new LazyWrapper(this); 45829 } 45830 n = n == null ? 1 : nativeMax(nativeFloor(n) || 0, 0); 45831 45832 var result = this.clone(); 45833 if (filtered) { 45834 result.__takeCount__ = nativeMin(result.__takeCount__, n); 45835 } else { 45836 result.__views__.push({ 'size': n, 'type': methodName + (result.__dir__ < 0 ? 'Right' : '') }); 45837 } 45838 return result; 45839 }; 45840 45841 LazyWrapper.prototype[methodName + 'Right'] = function(n) { 45842 return this.reverse()[methodName](n).reverse(); 45843 }; 45844 }); 45845 45846 // Add `LazyWrapper` methods that accept an `iteratee` value. 45847 arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) { 45848 var type = index + 1, 45849 isFilter = type != LAZY_MAP_FLAG; 45850 45851 LazyWrapper.prototype[methodName] = function(iteratee, thisArg) { 45852 var result = this.clone(); 45853 result.__iteratees__.push({ 'iteratee': getCallback(iteratee, thisArg, 1), 'type': type }); 45854 result.__filtered__ = result.__filtered__ || isFilter; 45855 return result; 45856 }; 45857 }); 45858 45859 // Add `LazyWrapper` methods for `_.first` and `_.last`. 45860 arrayEach(['first', 'last'], function(methodName, index) { 45861 var takeName = 'take' + (index ? 'Right' : ''); 45862 45863 LazyWrapper.prototype[methodName] = function() { 45864 return this[takeName](1).value()[0]; 45865 }; 45866 }); 45867 45868 // Add `LazyWrapper` methods for `_.initial` and `_.rest`. 45869 arrayEach(['initial', 'rest'], function(methodName, index) { 45870 var dropName = 'drop' + (index ? '' : 'Right'); 45871 45872 LazyWrapper.prototype[methodName] = function() { 45873 return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1); 45874 }; 45875 }); 45876 45877 // Add `LazyWrapper` methods for `_.pluck` and `_.where`. 45878 arrayEach(['pluck', 'where'], function(methodName, index) { 45879 var operationName = index ? 'filter' : 'map', 45880 createCallback = index ? baseMatches : property; 45881 45882 LazyWrapper.prototype[methodName] = function(value) { 45883 return this[operationName](createCallback(value)); 45884 }; 45885 }); 45886 45887 LazyWrapper.prototype.compact = function() { 45888 return this.filter(identity); 45889 }; 45890 45891 LazyWrapper.prototype.reject = function(predicate, thisArg) { 45892 predicate = getCallback(predicate, thisArg, 1); 45893 return this.filter(function(value) { 45894 return !predicate(value); 45895 }); 45896 }; 45897 45898 LazyWrapper.prototype.slice = function(start, end) { 45899 start = start == null ? 0 : (+start || 0); 45900 45901 var result = this; 45902 if (result.__filtered__ && (start > 0 || end < 0)) { 45903 return new LazyWrapper(result); 45904 } 45905 if (start < 0) { 45906 result = result.takeRight(-start); 45907 } else if (start) { 45908 result = result.drop(start); 45909 } 45910 if (end !== undefined) { 45911 end = (+end || 0); 45912 result = end < 0 ? result.dropRight(-end) : result.take(end - start); 45913 } 45914 return result; 45915 }; 45916 45917 LazyWrapper.prototype.takeRightWhile = function(predicate, thisArg) { 45918 return this.reverse().takeWhile(predicate, thisArg).reverse(); 45919 }; 45920 45921 LazyWrapper.prototype.toArray = function() { 45922 return this.take(POSITIVE_INFINITY); 45923 }; 45924 45925 // Add `LazyWrapper` methods to `lodash.prototype`. 45926 baseForOwn(LazyWrapper.prototype, function(func, methodName) { 45927 var checkIteratee = /^(?:filter|map|reject)|While$/.test(methodName), 45928 retUnwrapped = /^(?:first|last)$/.test(methodName), 45929 lodashFunc = lodash[retUnwrapped ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName]; 45930 45931 if (!lodashFunc) { 45932 return; 45933 } 45934 lodash.prototype[methodName] = function() { 45935 var args = retUnwrapped ? [1] : arguments, 45936 chainAll = this.__chain__, 45937 value = this.__wrapped__, 45938 isHybrid = !!this.__actions__.length, 45939 isLazy = value instanceof LazyWrapper, 45940 iteratee = args[0], 45941 useLazy = isLazy || isArray(value); 45942 45943 if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) { 45944 // Avoid lazy use if the iteratee has a "length" value other than `1`. 45945 isLazy = useLazy = false;
45946 } 45947 var interceptor = function(value) { 45948 return (retUnwrapped && chainAll) 45949 ? lodashFunc(value, 1)[0] 45950 : lodashFunc.apply(undefined, arrayPush([value], args)); 45951 }; 45952 45953 var action = { 'func': thru, 'args': [interceptor], 'thisArg': undefined }, 45954 onlyLazy = isLazy && !isHybrid; 45955 45956 if (retUnwrapped && !chainAll) { 45957 if (onlyLazy) { 45958 value = value.clone(); 45959 value.__actions__.push(action); 45960 return func.call(value); 45961 } 45962 return lodashFunc.call(undefined, this.value())[0]; 45963 } 45964 if (!retUnwrapped && useLazy) { 45965 value = onlyLazy ? value : new LazyWrapper(this); 45966 var result = func.apply(value, args); 45967 result.__actions__.push(action); 45968 return new LodashWrapper(result, chainAll); 45969 } 45970 return this.thru(interceptor); 45971 }; 45972 }); 45973 45974 // Add `Array` and `String` methods to `lodash.prototype`. 45975 arrayEach(['join', 'pop', 'push', 'replace', 'shift', 'sort', 'splice', 'split', 'unshift'], function(methodName) { 45976 var func = (/^(?:replace|split)$/.test(methodName) ? stringProto : arrayProto)[methodName], 45977 chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru', 45978 retUnwrapped = /^(?:join|pop|replace|shift)$/.test(methodName); 45979 45980 lodash.prototype[methodName] = function() { 45981 var args = arguments; 45982 if (retUnwrapped && !this.__chain__) { 45983 return func.apply(this.value(), args); 45984 } 45985 return this[chainName](function(value) { 45986 return func.apply(value, args); 45987 }); 45988 }; 45989 }); 45990 45991 // Map minified function names to their real names. 45992 baseForOwn(LazyWrapper.prototype, function(func, methodName) { 45993 var lodashFunc = lodash[methodName]; 45994 if (lodashFunc) { 45995 var key = lodashFunc.name, 45996 names = realNames[key] || (realNames[key] = []); 45997 45998 names.push({ 'name': methodName, 'func': lodashFunc }); 45999 } 46000 }); 46001 46002 realNames[createHybridWrapper(undefined, BIND_KEY_FLAG).name] = [{ 'name': 'wrapper', 'func': undefined }]; 46003 46004 // Add functions to the lazy wrapper. 46005 LazyWrapper.prototype.clone = lazyClone; 46006 LazyWrapper.prototype.reverse = lazyReverse; 46007 LazyWrapper.prototype.value = lazyValue; 46008 46009 // Add chaining functions to the `lodash` wrapper. 46010 lodash.prototype.chain = wrapperChain; 46011 lodash.prototype.commit = wrapperCommit; 46012 lodash.prototype.concat = wrapperConcat; 46013 lodash.prototype.plant = wrapperPlant; 46014 lodash.prototype.reverse = wrapperReverse; 46015 lodash.prototype.toString = wrapperToString; 46016 lodash.prototype.run = lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue; 46017 46018 // Add function aliases to the `lodash` wrapper. 46019 lodash.prototype.collect = lodash.prototype.map; 46020 lodash.prototype.head = lodash.prototype.first; 46021 lodash.prototype.select = lodash.prototype.filter; 46022 lodash.prototype.tail = lodash.prototype.rest; 46023 46024 return lodash; 46025 } 46026 46027 /*--------------------------------------------------------------------------*/ 46028 46029 // Export lodash. 46030 var _ = runInContext(); 46031
46032 // Some AMD build optimizers like r.js check for condition patterns like the following: 46033 if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { 46034 // Expose lodash to the global object when an AMD loader is present to avoid 46035 // errors in cases where lodash is loaded by a script tag and not intended 46036 // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch for 46037 // more details. 46038 root._ = _; 46039 46040 // Define as an anonymous module so, through path mapping, it can be 46041 // referenced as the "underscore" module. 46042 define(function() { 46043 return _; 46044 }); 46045 } 46046 // Check for `exports` after `define` in case a build optimizer adds an `exports` object. 46047 else if (freeExports && freeModule) { 46048 // Export for Node.js or RingoJS. 46049 if (moduleExports) { 46050 (freeModule.exports = _)._ = _; 46051 } 46052 // Export for Rhino with CommonJS support. 46053 else { 46054 freeExports._ = _; 46055 } 46056 } 46057 else { 46058 // Export for a browser or Rhino. 46059 root._ = _; 46060 } 46061}.call(this)); 46062 46063}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 46064 46065},{}],134:[function(require,module,exports){ 46066'use strict'; 46067 46068module.exports = require('./lib') 46069 46070},{"./lib":139}],135:[function(require,module,exports){ 46071'use strict'; 46072 46073var asap = require('asap/raw'); 46074 46075function noop() {} 46076 46077// States: 46078// 46079// 0 - pending 46080// 1 - fulfilled with _value 46081// 2 - rejected with _value 46082// 3 - adopted the state of another promise, _value 46083// 46084// once the state is no longer pending (0) it is immutable 46085 46086// All `_` prefixed properties will be reduced to `_{random number}` 46087// at build time to obfuscate them and discourage their use. 46088// We don't use symbols or Object.defineProperty to fully hide them 46089// because the performance isn't good enough. 46090 46091 46092// to avoid using try/catch inside critical functions, we 46093// extract them to here. 46094var LAST_ERROR = null; 46095var IS_ERROR = {}; 46096function getThen(obj) { 46097 try { 46098 return obj.then; 46099 } catch (ex) { 46100 LAST_ERROR = ex; 46101 return IS_ERROR; 46102 } 46103} 46104 46105function tryCallOne(fn, a) { 46106 try { 46107 return fn(a); 46108 } catch (ex) { 46109 LAST_ERROR = ex; 46110 return IS_ERROR; 46111 } 46112} 46113function tryCallTwo(fn, a, b) { 46114 try { 46115 fn(a, b); 46116 } catch (ex) { 46117 LAST_ERROR = ex; 46118 return IS_ERROR; 46119 } 46120} 46121 46122module.exports = Promise; 46123 46124function Promise(fn) { 46125 if (typeof this !== 'object') { 46126 throw new TypeError('Promises must be constructed via new'); 46127 } 46128 if (typeof fn !== 'function') { 46129 throw new TypeError('Promise constructor\'s argument is not a function'); 46130 } 46131 this._40 = 0; 46132 this._65 = 0; 46133 this._55 = null; 46134 this._72 = null; 46135 if (fn === noop) return; 46136 doResolve(fn, this); 46137} 46138Promise._37 = null; 46139Promise._87 = null; 46140Promise._61 = noop; 46141 46142Promise.prototype.then = function(onFulfilled, onRejected) { 46143 if (this.constructor !== Promise) { 46144 return safeThen(this, onFulfilled, onRejected); 46145 } 46146 var res = new Promise(noop); 46147 handle(this, new Handler(onFulfilled, onRejected, res)); 46148 return res; 46149}; 46150 46151function safeThen(self, onFulfilled, onRejected) { 46152 return new self.constructor(function (resolve, reject) { 46153 var res = new Promise(noop); 46154 res.then(resolve, reject); 46155 handle(self, new Handler(onFulfilled, onRejected, res)); 46156 }); 46157} 46158function handle(self, deferred) { 46159 while (self._65 === 3) { 46160 self = self._55; 46161 } 46162 if (Promise._37) { 46163 Promise._37(self); 46164 } 46165 if (self._65 === 0) { 46166 if (self._40 === 0) { 46167 self._40 = 1; 46168 self._72 = deferred; 46169 return; 46170 } 46171 if (self._40 === 1) { 46172 self._40 = 2; 46173 self._72 = [self._72, deferred]; 46174 return; 46175 } 46176 self._72.push(deferred); 46177 return; 46178 } 46179 handleResolved(self, deferred); 46180} 46181 46182function handleResolved(self, deferred) { 46183 asap(function() { 46184 var cb = self._65 === 1 ? deferred.onFulfilled : deferred.onRejected; 46185 if (cb === null) { 46186 if (self._65 === 1) { 46187 resolve(deferred.promise, self._55); 46188 } else { 46189 reject(deferred.promise, self._55); 46190 } 46191 return; 46192 } 46193 var ret = tryCallOne(cb, self._55); 46194 if (ret === IS_ERROR) { 46195 reject(deferred.promise, LAST_ERROR); 46196 } else { 46197 resolve(deferred.promise, ret); 46198 } 46199 }); 46200} 46201function resolve(self, newValue) { 46202 // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 46203 if (newValue === self) { 46204 return reject( 46205 self, 46206 new TypeError('A promise cannot be resolved with itself.') 46207 ); 46208 } 46209 if ( 46210 newValue && 46211 (typeof newValue === 'object' || typeof newValue === 'function') 46212 ) { 46213 var then = getThen(newValue); 46214 if (then === IS_ERROR) { 46215 return reject(self, LAST_ERROR); 46216 } 46217 if ( 46218 then === self.then && 46219 newValue instanceof Promise 46220 ) { 46221 self._65 = 3; 46222 self._55 = newValue; 46223 finale(self); 46224 return; 46225 } else if (typeof then === 'function') { 46226 doResolve(then.bind(newValue), self); 46227 return; 46228 } 46229 } 46230 self._65 = 1; 46231 self._55 = newValue; 46232 finale(self); 46233} 46234 46235function reject(self, newValue) { 46236 self._65 = 2; 46237 self._55 = newValue; 46238 if (Promise._87) { 46239 Promise._87(self, newValue); 46240 } 46241 finale(self); 46242} 46243function finale(self) { 46244 if (self._40 === 1) { 46245 handle(self, self._72); 46246 self._72 = null; 46247 } 46248 if (self._40 === 2) { 46249 for (var i = 0; i < self._72.length; i++) { 46250 handle(self, self._72[i]); 46251 } 46252 self._72 = null; 46253 } 46254} 46255 46256function Handler(onFulfilled, onRejected, promise){ 46257 this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; 46258 this.onRejected = typeof onRejected === 'function' ? onRejected : null; 46259 this.promise = promise; 46260} 46261 46262/** 46263 * Take a potentially misbehaving resolver function and make sure 46264 * onFulfilled and onRejected are only called once. 46265 * 46266 * Makes no guarantees about asynchrony. 46267 */ 46268function doResolve(fn, promise) { 46269 var done = false;
46270 var res = tryCallTwo(fn, function (value) { 46271 if (done) return; 46272 done = true; 46273 resolve(promise, value); 46274 }, function (reason) { 46275 if (done) return; 46276 done = true; 46277 reject(promise, reason); 46278 }); 46279 if (!done && res === IS_ERROR) { 46280 done = true; 46281 reject(promise, LAST_ERROR); 46282 } 46283} 46284 46285},{"asap/raw":130}],136:[function(require,module,exports){ 46286'use strict'; 46287 46288var Promise = require('./core.js'); 46289 46290module.exports = Promise; 46291Promise.prototype.done = function (onFulfilled, onRejected) { 46292 var self = arguments.length ? this.then.apply(this, arguments) : this; 46293 self.then(null, function (err) { 46294 setTimeout(function () { 46295 throw err; 46296 }, 0); 46297 }); 46298}; 46299 46300},{"./core.js":135}],137:[function(require,module,exports){ 46301'use strict'; 46302 46303//This file contains the ES6 extensions to the core Promises/A+ API 46304 46305var Promise = require('./core.js'); 46306 46307module.exports = Promise; 46308 46309/* Static Functions */ 46310 46311var TRUE = valuePromise(true); 46312var FALSE = valuePromise(false); 46313var NULL = valuePromise(null); 46314var UNDEFINED = valuePromise(undefined); 46315var ZERO = valuePromise(0); 46316var EMPTYSTRING = valuePromise(''); 46317 46318function valuePromise(value) { 46319 var p = new Promise(Promise._61); 46320 p._65 = 1; 46321 p._55 = value; 46322 return p; 46323} 46324Promise.resolve = function (value) { 46325 if (value instanceof Promise) return value; 46326 46327 if (value === null) return NULL; 46328 if (value === undefined) return UNDEFINED; 46329 if (value === true) return TRUE; 46330 if (value === false) return FALSE; 46331 if (value === 0) return ZERO; 46332 if (value === '') return EMPTYSTRING; 46333 46334 if (typeof value === 'object' || typeof value === 'function') { 46335 try { 46336 var then = value.then; 46337 if (typeof then === 'function') { 46338 return new Promise(then.bind(value)); 46339 } 46340 } catch (ex) { 46341 return new Promise(function (resolve, reject) { 46342 reject(ex); 46343 }); 46344 } 46345 } 46346 return valuePromise(value); 46347}; 46348 46349Promise.all = function (arr) { 46350 var args = Array.prototype.slice.call(arr); 46351 46352 return new Promise(function (resolve, reject) { 46353 if (args.length === 0) return resolve([]); 46354 var remaining = args.length; 46355 function res(i, val) { 46356 if (val && (typeof val === 'object' || typeof val === 'function')) { 46357 if (val instanceof Promise && val.then === Promise.prototype.then) { 46358 while (val._65 === 3) { 46359 val = val._55; 46360 } 46361 if (val._65 === 1) return res(i, val._55); 46362 if (val._65 === 2) reject(val._55); 46363 val.then(function (val) { 46364 res(i, val); 46365 }, reject); 46366 return; 46367 } else { 46368 var then = val.then; 46369 if (typeof then === 'function') { 46370 var p = new Promise(then.bind(val)); 46371 p.then(function (val) { 46372 res(i, val); 46373 }, reject); 46374 return; 46375 } 46376 } 46377 } 46378 args[i] = val; 46379 if (--remaining === 0) { 46380 resolve(args); 46381 } 46382 } 46383 for (var i = 0; i < args.length; i++) { 46384 res(i, args[i]); 46385 } 46386 }); 46387}; 46388 46389Promise.reject = function (value) { 46390 return new Promise(function (resolve, reject) { 46391 reject(value); 46392 }); 46393}; 46394 46395Promise.race = function (values) { 46396 return new Promise(function (resolve, reject) { 46397 values.forEach(function(value){ 46398 Promise.resolve(value).then(resolve, reject); 46399 }); 46400 }); 46401}; 46402 46403/* Prototype Methods */ 46404 46405Promise.prototype['catch'] = function (onRejected) { 46406 return this.then(null, onRejected); 46407}; 46408 46409},{"./core.js":135}],138:[function(require,module,exports){ 46410'use strict'; 46411 46412var Promise = require('./core.js'); 46413 46414module.exports = Promise; 46415Promise.prototype['finally'] = function (f) { 46416 return this.then(function (value) { 46417 return Promise.resolve(f()).then(function () { 46418 return value; 46419 }); 46420 }, function (err) { 46421 return Promise.resolve(f()).then(function () { 46422 throw err; 46423 }); 46424 }); 46425}; 46426 46427},{"./core.js":135}],139:[function(require,module,exports){ 46428'use strict'; 46429 46430module.exports = require('./core.js'); 46431require('./done.js'); 46432require('./finally.js'); 46433require('./es6-extensions.js'); 46434require('./node-extensions.js'); 46435require('./synchronous.js'); 46436 46437},{"./core.js":135,"./done.js":136,"./es6-extensions.js":137,"./finally.js":138,"./node-extensions.js":140,"./synchronous.js":141}],140:[function(require,module,exports){ 46438'use strict'; 46439 46440// This file contains then/promise specific extensions that are only useful 46441// for node.js interop 46442 46443var Promise = require('./core.js'); 46444var asap = require('asap'); 46445 46446module.exports = Promise; 46447 46448/* Static Functions */ 46449 46450Promise.denodeify = function (fn, argumentCount) { 46451 if ( 46452 typeof argumentCount === 'number' && argumentCount !== Infinity 46453 ) { 46454 return denodeifyWithCount(fn, argumentCount); 46455 } else { 46456 return denodeifyWithoutCount(fn); 46457 } 46458}; 46459 46460var callbackFn = ( 46461 'function (err, res) {' + 46462 'if (err) { rj(err); } else { rs(res); }' + 46463 '}' 46464); 46465function denodeifyWithCount(fn, argumentCount) { 46466 var args = []; 46467 for (var i = 0; i < argumentCount; i++) { 46468 args.push('a' + i); 46469 } 46470 var body = [ 46471 'return function (' + args.join(',') + ') {', 46472 'var self = this;', 46473 'return new Promise(function (rs, rj) {', 46474 'var res = fn.call(',
46475 ['self'].concat(args).concat([callbackFn]).join(','), 46476 ');', 46477 'if (res &&', 46478 '(typeof res === "object" || typeof res === "function") &&', 46479 'typeof res.then === "function"', 46480 ') {rs(res);}', 46481 '});', 46482 '};' 46483 ].join(''); 46484 return Function(['Promise', 'fn'], body)(Promise, fn); 46485} 46486function denodeifyWithoutCount(fn) { 46487 var fnLength = Math.max(fn.length - 1, 3); 46488 var args = []; 46489 for (var i = 0; i < fnLength; i++) { 46490 args.push('a' + i); 46491 } 46492 var body = [ 46493 'return function (' + args.join(',') + ') {', 46494 'var self = this;', 46495 'var args;', 46496 'var argLength = arguments.length;', 46497 'if (arguments.length > ' + fnLength + ') {', 46498 'args = new Array(arguments.length + 1);', 46499 'for (var i = 0; i < arguments.length; i++) {', 46500 'args[i] = arguments[i];', 46501 '}', 46502 '}', 46503 'return new Promise(function (rs, rj) {', 46504 'var cb = ' + callbackFn + ';', 46505 'var res;', 46506 'switch (argLength) {', 46507 args.concat(['extra']).map(function (_, index) { 46508 return ( 46509 'case ' + (index) + ':' + 46510 'res = fn.call(' + ['self'].concat(args.slice(0, index)).concat('cb').join(',') + ');' + 46511 'break;' 46512 ); 46513 }).join(''), 46514 'default:', 46515 'args[argLength] = cb;', 46516 'res = fn.apply(self, args);', 46517 '}', 46518 46519 'if (res &&', 46520 '(typeof res === "object" || typeof res === "function") &&', 46521 'typeof res.then === "function"', 46522 ') {rs(res);}', 46523 '});', 46524 '};' 46525 ].join(''); 46526 46527 return Function( 46528 ['Promise', 'fn'], 46529 body 46530 )(Promise, fn); 46531} 46532 46533Promise.nodeify = function (fn) { 46534 return function () { 46535 var args = Array.prototype.slice.call(arguments); 46536 var callback = 46537 typeof args[args.length - 1] === 'function' ? args.pop() : null; 46538 var ctx = this; 46539 try { 46540 return fn.apply(this, arguments).nodeify(callback, ctx); 46541 } catch (ex) { 46542 if (callback === null || typeof callback == 'undefined') { 46543 return new Promise(function (resolve, reject) { 46544 reject(ex); 46545 }); 46546 } else { 46547 asap(function () { 46548 callback.call(ctx, ex); 46549 }) 46550 } 46551 } 46552 } 46553}; 46554 46555Promise.prototype.nodeify = function (callback, ctx) { 46556 if (typeof callback != 'function') return this; 46557 46558 this.then(function (value) { 46559 asap(function () { 46560 callback.call(ctx, null, value); 46561 }); 46562 }, function (err) { 46563 asap(function () { 46564 callback.call(ctx, err); 46565 }); 46566 }); 46567}; 46568 46569},{"./core.js":135,"asap":129}],141:[function(require,module,exports){ 46570'use strict'; 46571 46572var Promise = require('./core.js'); 46573 46574module.exports = Promise; 46575Promise.enableSynchronous = function () { 46576 Promise.prototype.isPending = function() { 46577 return this.getState() == 0; 46578 }; 46579 46580 Promise.prototype.isFulfilled = function() { 46581 return this.getState() == 1; 46582 }; 46583 46584 Promise.prototype.isRejected = function() { 46585 return this.getState() == 2; 46586 }; 46587 46588 Promise.prototype.getValue = function () { 46589 if (this._65 === 3) { 46590 return this._55.getValue(); 46591 } 46592 46593 if (!this.isFulfilled()) { 46594 throw new Error('Cannot get a value of an unfulfilled promise.'); 46595 } 46596 46597 return this._55; 46598 }; 46599 46600 Promise.prototype.getReason = function () { 46601 if (this._65 === 3) { 46602 return this._55.getReason(); 46603 } 46604 46605 if (!this.isRejected()) { 46606 throw new Error('Cannot get a rejection reason of a non-rejected promise.'); 46607 } 46608 46609 return this._55; 46610 }; 46611 46612 Promise.prototype.getState = function () { 46613 if (this._65 === 3) { 46614 return this._55.getState(); 46615 } 46616 if (this._65 === -1 || this._65 === -2) { 46617 return 0; 46618 } 46619 46620 return this._65; 46621 }; 46622}; 46623 46624Promise.disableSynchronous = function() { 46625 Promise.prototype.isPending = undefined; 46626 Promise.prototype.isFulfilled = undefined; 46627 Promise.prototype.isRejected = undefined; 46628 Promise.prototype.getValue = undefined; 46629 Promise.prototype.getReason = undefined; 46630 Promise.prototype.getState = undefined; 46631}; 46632 46633},{"./core.js":135}],142:[function(require,module,exports){ 46634/*! 46635 * EventEmitter v4.2.11 - git.io/ee 46636 * Unlicense - http://unlicense.org/ 46637 * Oliver Caldwell - http://oli.me.uk/ 46638 * @preserve 46639 */ 46640 46641;(function () { 46642 'use strict'; 46643 46644 /** 46645 * Class for managing events. 46646 * Can be extended to provide event functionality in other classes. 46647 * 46648 * @class EventEmitter Manages event registering and emitting. 46649 */ 46650 function EventEmitter() {} 46651 46652 // Shortcuts to improve speed and size 46653 var proto = EventEmitter.prototype; 46654 var exports = this; 46655 var originalGlobalValue = exports.EventEmitter; 46656 46657 /** 46658 * Finds the index of the listener for the event in its storage array. 46659 * 46660 * @param {Function[]} listeners Array of listeners to search through. 46661 * @param {Function} listener Method to look for. 46662 * @return {Number} Index of the specified listener, -1 if not found 46663 * @api private 46664 */ 46665 function indexOfListener(listeners, listener) { 46666 var i = listeners.length; 46667 while (i--) { 46668 if (listeners[i].listener === listener) { 46669 return i; 46670 } 46671 } 46672 46673 return -1; 46674 } 46675 46676 /** 46677 * Alias a method while keeping the context correct, to allow for over
46677writing of target method. 46678 * 46679 * @param {String} name The name of the target method. 46680 * @return {Function} The aliased method 46681 * @api private 46682 */ 46683 function alias(name) { 46684 return function aliasClosure() { 46685 return this[name].apply(this, arguments); 46686 }; 46687 } 46688 46689 /** 46690 * Returns the listener array for the specified event. 46691 * Will initialise the event object and listener arrays if required. 46692 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 46693 * Each property in the object response is an array of listener functions. 46694 * 46695 * @param {String|RegExp} evt Name of the event to return the listeners from. 46696 * @return {Function[]|Object} All listener functions for the event. 46697 */ 46698 proto.getListeners = function getListeners(evt) { 46699 var events = this._getEvents(); 46700 var response; 46701 var key; 46702 46703 // Return a concatenated array of all matching events if 46704 // the selector is a regular expression. 46705 if (evt instanceof RegExp) { 46706 response = {}; 46707 for (key in events) { 46708 if (events.hasOwnProperty(key) && evt.test(key)) { 46709 response[key] = events[key]; 46710 } 46711 } 46712 } 46713 else { 46714 response = events[evt] || (events[evt] = []); 46715 } 46716 46717 return response; 46718 }; 46719 46720 /** 46721 * Takes a list of listener objects and flattens it into a list of listener functions. 46722 * 46723 * @param {Object[]} listeners Raw listener objects. 46724 * @return {Function[]} Just the listener functions. 46725 */ 46726 proto.flattenListeners = function flattenListeners(listeners) { 46727 var flatListeners = []; 46728 var i; 46729 46730 for (i = 0; i < listeners.length; i += 1) { 46731 flatListeners.push(listeners[i].listener); 46732 } 46733 46734 return flatListeners; 46735 }; 46736 46737 /** 46738 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. 46739 * 46740 * @param {String|RegExp} evt Name of the event to return the listeners from. 46741 * @return {Object} All listener functions for an event in an object. 46742 */ 46743 proto.getListenersAsObject = function getListenersAsObject(evt) { 46744 var listeners = this.getListeners(evt); 46745 var response; 46746 46747 if (listeners instanceof Array) { 46748 response = {}; 46749 response[evt] = listeners; 46750 } 46751 46752 return response || listeners; 46753 }; 46754 46755 /** 46756 * Adds a listener function to the specified event. 46757 * The listener will not be added if it is a duplicate. 46758 * If the listener returns true then it will be removed after it is called. 46759 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 46760 * 46761 * @param {String|RegExp} evt Name of the event to attach the listener to. 46762 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 46763 * @return {Object} Current instance of EventEmitter for chaining. 46764 */ 46765 proto.addListener = function addListener(evt, listener) { 46766 var listeners = this.getListenersAsObject(evt); 46767 var listenerIsWrapped = typeof listener === 'object'; 46768 var key; 46769 46770 for (key in listeners) { 46771 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 46772 listeners[key].push(listenerIsWrapped ? listener : { 46773 listener: listener, 46774 once: false 46775 }); 46776 } 46777 } 46778 46779 return this; 46780 }; 46781 46782 /** 46783 * Alias of addListener 46784 */ 46785 proto.on = alias('addListener'); 46786 46787 /** 46788 * Semi-alias of addListener. It will add a listener that will be 46789 * automatically removed after its first execution. 46790 * 46791 * @param {String|RegExp} evt Name of the event to attach the listener to. 46792 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 46793 * @return {Object} Current instance of EventEmitter for chaining. 46794 */ 46795 proto.addOnceListener = function addOnceListener(evt, listener) { 46796 return this.addListener(evt, { 46797 listener: listener, 46798 once: true 46799 }); 46800 }; 46801 46802 /** 46803 * Alias of addOnceListener. 46804 */ 46805 proto.once = alias('addOnceListener'); 46806 46807 /** 46808 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. 46809 * You need to tell it what event names should be matched by a regex. 46810 * 46811 * @param {String} evt Name of the event to create. 46812 * @return {Object} Current instance of EventEmitter for chaining. 46813 */ 46814 proto.defineEvent = function defineEvent(evt) { 46815 this.getListeners(evt); 46816 return this; 46817 }; 46818 46819 /** 46820 * Uses defineEvent to define multiple events. 46821 * 46822 * @param {String[]} evts An array of event names to define. 46823 * @return {Object} Current instance of EventEmitter for chaining. 46824 */ 46825 proto.defineEvents = function defineEvents(evts) { 46826 for (var i = 0; i < evts.length; i += 1) { 46827 this.defineEvent(evts[i]); 46828 } 46829 return this; 46830 }; 46831 46832 /** 46833 * Removes a listener function from the specified event. 46834 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 46835 * 46836 * @param {String|RegExp} evt Name of the event to remove the listener from. 46837 * @param {Function} listener Method to remove from the event. 46838 * @return {Object} Current instance of EventEmitter for chaining. 46839 */ 46840 proto.removeListener = function removeListener(evt, listener) { 46841 var listeners = this.getListenersAsObject(evt); 46842 var index; 46843 var key; 46844 46845 for (key in listeners) { 46846 if (listeners.hasOwnProperty(key)) { 46847 index = indexOfListener(listeners[key], listener); 46848 46849 if (index !== -1) { 46850 listeners[key].splice(index, 1); 46851 } 46852 } 46853 } 46854 46855 return this; 46856 }; 46857 46858 /** 46859 * Alias of removeListener 46860 */ 46861 proto.off = alias('removeListener'); 46862 46863 /** 46864 * Adds listeners in bulk using the manipulateListeners method. 46865 * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. 46866 * You can also pass it a regular expression to add the array of listeners to all events that match it. 46867 * Yeah, this function does quite a bit. That's probably a bad thing. 46868 * 46869 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. 46870 * @param {Function[]} [listeners] An optional array of listener functions to add. 46871 * @return {Object} Current instance of EventEmitter for chaining. 46872 */ 46873 proto.addListeners = function addListeners(evt, listeners) { 46874 // Pass through to manipulateListeners 46875 return this.manipulateListeners(false, evt, listeners); 46876 }; 46877 46878 /** 46879 * Removes listeners in bulk using the manipulateListeners method. 46880 * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 46881 * You can also pass it an event name and an array of listeners to be removed. 46882 * You can also pass it a regular expression to remove the listeners from all events that match it. 46883 * 46884 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. 46885 * @param {Function[]} [listeners] An optional array of listener functions to remove. 46886 * @return {Object} Current instance of EventEmitter for chaining. 46887 */ 46888 proto.removeListeners = function removeListeners(evt, listeners) { 46889 // Pass through to manipulateListeners 46890 return this.manipulateListeners(true, evt, listeners); 46891 }; 46892 46893 /** 46894 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. 46895 * The first argument will determine if the listeners are removed (true) or added (false). 46896 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 46897 * You can also pass it an event name and an array of listeners to be added/removed. 46898 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 46899 * 46900 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 46901 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. 46902 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 46903 * @return {Object} Current instance of EventEmitter for chaining. 46904 */ 46905 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 46906 var i; 46907 var value; 46908 var single = remove ? this.removeListener : this.addListener; 46909 var multiple = remove ? this.removeListeners : this.addListeners; 46910 46911 // If evt is an object then pass each of its properties to this method 46912 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 46913 for (i in evt) { 46914 if (evt.hasOwnProperty(i) && (value = evt[i])) { 46915 // Pass the single listener straight through to the singular method 46916 if (typeof value === 'function') { 46917 single.call(this, i, value); 46918 } 46919 else { 46920 // Otherwise pass back to the multiple function 46921 multiple.call(this, i, value); 46922 } 46923 } 46924 } 46925 } 46926 else { 46927 // So evt must be a string 46928 // And listeners must be an array of listeners 46929 // Loop over it and pass each one to the multiple method 46930 i = listeners.length; 46931 while (i--) { 46932 single.call(this, evt, listeners[i]); 46933 } 46934 } 46935 46936 return this; 46937 }; 46938 46939 /** 46940 * Removes all listeners from a specified event. 46941 * If you do not specify an event then all listeners will be removed. 46942 * That means every event will be emptied. 46943 * You can also pass a regex to remove all events that match it. 46944 * 46945 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 46946 * @return {Object} Current instance of EventEmitter for chaining. 46947 */ 46948 proto.removeEvent = function removeEvent(evt) { 46949 var type = typeof evt; 46950 var events = this._getEvents(); 46951 var key; 46952 46953 // Remove different things depending on the state of evt 46954 if (type === 'string') { 46955 // Remove all listeners for the specified event 46956 delete events[evt]; 46957 } 46958 else if (evt instanceof RegExp) { 46959 // Remove all events matching the regex. 46960 for (key in events) { 46961 if (events.hasOwnProperty(key) && evt.test(key)) { 46962 delete events[key]; 46963 } 46964 } 46965 } 46966 else { 46967 // Remove all listeners in all events 46968 delete this._events; 46969 } 46970 46971 return this; 46972 }; 46973 46974 /** 46975 * Alias of removeEvent. 46976 * 46977 * Added to mirror the node API. 46978 */ 46979 proto.removeAllListeners = alias('removeEvent'); 46980 46981 /** 46982 * Emits an event of your choice. 46983 * When emitted, every listener attached to that event will be executed. 46984 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 46985 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. 46986 * So they will not arrive within the array on the other side, they will be separate. 46987 * You can also pass a regular expression to emit to all events that match it. 46988 * 46989 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 46990 * @param {Array} [args] Optional array of arguments to be passed to each listener. 46991 * @return {Object} Current instance of EventEmitter for chaining. 46992 */ 46993 proto.emitEvent = function emitEvent(evt, args) { 46994 var listenersMap = this.getListenersAsObject(evt); 46995 var listeners; 46996 var listener; 46997 var i; 46998 var key; 46999 var response; 47000 47001 for (key in listenersMap) { 47002 if (listenersMap.hasOwnProperty(key)) { 47003 listeners = listenersMap[key].slice(0); 47004 i = listeners.length; 47005 47006 while (i--) { 47007 // If the listener returns true then it shall be removed from the event 47008 // The function is executed either with a basic call or an apply if there is an args array 47009 listener = listeners[i]; 47010 47011 if (listener.once === true) { 47012 this.removeListener(evt, listener.listener); 47013 } 47014 47015 response = listener.listener.apply(this, args || []); 47016 47017 if (response === this._getOnceReturnValue()) { 47018 this.removeListener(evt, listener.listener); 47019 } 47020 } 47021 } 47022 } 47023 47024 return this; 47025 }; 47026 47027 /** 47028 * Alias of emitEvent 47029 */ 47030 proto.trigger = alias('emitEvent'); 47031 47032 /** 47033 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. 47034 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 47035 * 47036 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 47037 * @param {...*} Optional additional arguments to be passed to each listener. 47038 * @return {Object} Current instance of EventEmitter for chaining. 47039 */ 47040 proto.emit = function emit(evt) { 47041 var args = Array.prototype.slice.call(arguments, 1); 47042 return this.emitEvent(evt, args); 47043 }; 47044 47045 /** 47046 * Sets the current value to check against when executing listeners. If a 47047 * listeners return value matches the one set here then it will be removed 47048 * after execution. This value defaults to true. 47049 * 47050 * @param {*} value The new value to check for when executing listeners. 47051 * @return {Object} Current instance of EventEmitter for chaining. 47052 */ 47053 proto.setOnceReturnValue = function setOnceReturnValue(value) { 47054 this._onceReturnValue = value; 47055 return this; 47056 }; 47057 47058 /** 47059 * Fetches the current value to check against when executing listeners. If 47060 * the listeners return value matches this one then it should be removed 47061 * automatically. It will return true by default. 47062 * 47063 * @return {*|Boolean} The current value to check for or the default, true. 47064 * @api private 47065 */ 47066 proto._getOnceReturnValue = function _getOnceReturnValue() { 47067 if (this.hasOwnProperty('_onceReturnValue')) { 47068 return this._onceReturnValue; 47069 } 47070 else { 47071 return true; 47072 } 47073 }; 47074 47075 /** 47076 * Fetches the events object and creates one if required. 47077 * 47078 * @return {Object} The events storage object. 47079 * @api private 47080 */ 47081 p
47081roto._getEvents = function _getEvents() { 47082 return this._events || (this._events = {}); 47083 }; 47084 47085 /** 47086 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 47087 * 47088 * @return {Function} Non conflicting EventEmitter class. 47089 */ 47090 EventEmitter.noConflict = function noConflict() { 47091 exports.EventEmitter = originalGlobalValue; 47092 return EventEmitter; 47093 }; 47094 47095 // Expose the class either via AMD, CommonJS or the global object 47096 if (typeof define === 'function' && define.amd) { 47097 define(function () { 47098 return EventEmitter; 47099 }); 47100 } 47101 else if (typeof module === 'object' && module.exports){ 47102 module.exports = EventEmitter; 47103 } 47104 else { 47105 exports.EventEmitter = EventEmitter; 47106 } 47107}.call(this)); 47108 47109},{}]},{},[5]) 47110 47111//# sourceMappingURL=app.js.map
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.