From 90d16e38403ebfd9a42f853f3131cd5eadfddea4 Mon Sep 17 00:00:00 2001 From: support Date: Sun, 1 Nov 2026 07:33:09 +0100 Subject: [PATCH 1/3] Offer the server time zone as a choice in store settings The installer leaves the store's time zone empty, so dates follow the server, but the select had no empty option. It showed its first zone, and saving General settings stored that zone, moving every date shown. An empty option keeps the value empty. A configured zone that resolves but is not listed, such as a Windows id on Linux, gets its own option so that saving does not change it. The option's text has a default: a database already on 2.4 does not import the 2.4 resources again. --- .../DateTimeServiceExtensionsTests.cs | 79 ++++++++++++++++++ .../Controllers/SettingController.cs | 25 +++--- .../Extensions/DateTimeServiceExtensions.cs | 56 +++++++++++++ .../Controllers/SettingController.cs | 20 ++--- .../App_Data/Resources/DefaultLanguage.xml | Bin 1565656 -> 1565934 bytes .../App_Data/Resources/Upgrade/en_240.xml | 3 + 6 files changed, 157 insertions(+), 26 deletions(-) create mode 100644 src/Tests/Grand.Web.Admin.Tests/Extensions/DateTimeServiceExtensionsTests.cs create mode 100644 src/Web/Grand.Web.AdminShared/Extensions/DateTimeServiceExtensions.cs diff --git a/src/Tests/Grand.Web.Admin.Tests/Extensions/DateTimeServiceExtensionsTests.cs b/src/Tests/Grand.Web.Admin.Tests/Extensions/DateTimeServiceExtensionsTests.cs new file mode 100644 index 0000000000..473203caea --- /dev/null +++ b/src/Tests/Grand.Web.Admin.Tests/Extensions/DateTimeServiceExtensionsTests.cs @@ -0,0 +1,79 @@ +using Grand.Business.Core.Interfaces.Common.Directory; +using Grand.Web.AdminShared.Extensions; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System.Collections.ObjectModel; + +namespace Grand.Web.Admin.Tests.Extensions; + +[TestClass] +public class DateTimeServiceExtensionsTests +{ + private const string ServerLabel = "Server time zone"; + + private readonly TimeZoneInfo _dateline = TimeZoneInfo.CreateCustomTimeZone("Dateline", TimeSpan.FromHours(-12), "Dateline", "Dateline"); + private readonly TimeZoneInfo _warsaw = TimeZoneInfo.CreateCustomTimeZone("Warsaw", TimeSpan.FromHours(1), "Warsaw", "Warsaw"); + private readonly TimeZoneInfo _unlisted = TimeZoneInfo.CreateCustomTimeZone("Other/Name", TimeSpan.FromHours(2), "Other", "Other"); + private IDateTimeService _dateTimeService; + + [TestInitialize] + public void Init() + { + var service = new Mock(); + service.Setup(x => x.GetSystemTimeZones()) + .Returns(new ReadOnlyCollection([_dateline, _warsaw])); + service.Setup(x => x.FindTimeZoneById(It.IsAny())).Throws(); + service.Setup(x => x.FindTimeZoneById("Other/Name")).Returns(_unlisted); + _dateTimeService = service.Object; + } + + private IList Options(string configured) => + _dateTimeService.GetStoreTimeZoneOptions(configured, ServerLabel); + + private static string Selected(IList options) => options.Single(x => x.Selected).Value; + + [TestMethod] + public void GetStoreTimeZoneOptions_StartWithTheServerZone_WithAnEmptyValue() + { + var first = Options("Warsaw")[0]; + + Assert.AreEqual("", first.Value); + StringAssert.StartsWith(first.Text, ServerLabel); + } + + [TestMethod] + [DataRow(null)] + [DataRow("")] + public void GetStoreTimeZoneOptions_NothingConfigured_SelectsTheServerZone(string configured) + { + //so saving the form leaves the store following the server + Assert.AreEqual("", Selected(Options(configured))); + } + + [TestMethod] + public void GetStoreTimeZoneOptions_ConfiguredZoneListed_SelectsIt() + { + Assert.AreEqual("Warsaw", Selected(Options("Warsaw"))); + } + + [TestMethod] + public void GetStoreTimeZoneOptions_ConfiguredZoneDiffersInCase_SelectsTheListedId() + { + Assert.AreEqual("Warsaw", Selected(Options("warsaw"))); + } + + [TestMethod] + public void GetStoreTimeZoneOptions_ConfiguredZoneResolvesButIsNotListed_KeepsIt() + { + //a Windows id on Linux, or the reverse: dates are shown in it, so saving must not change it + Assert.AreEqual("Other/Name", Selected(Options("Other/Name"))); + } + + [TestMethod] + public void GetStoreTimeZoneOptions_ConfiguredZoneUnknownOnThisMachine_SelectsTheServerZone() + { + //DateTimeService.CurrentTimeZone falls back to the server here as well + Assert.AreEqual("", Selected(Options("Gone/Zone"))); + } +} diff --git a/src/Web/Grand.Web.Admin/Controllers/SettingController.cs b/src/Web/Grand.Web.Admin/Controllers/SettingController.cs index 775218bef6..08d6310d35 100644 --- a/src/Web/Grand.Web.Admin/Controllers/SettingController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/SettingController.cs @@ -23,8 +23,10 @@ using Grand.Domain.Seo; using Grand.Domain.Stores; using Grand.Domain.Vendors; +using Grand.Infrastructure; using Grand.Infrastructure.Caching; using Grand.SharedKernel.Extensions; +using Grand.Web.AdminShared.Extensions; using Grand.Web.AdminShared.Extensions.Mapping; using Grand.Web.AdminShared.Extensions.Mapping.Settings; using Grand.Web.AdminShared.Models.Settings; @@ -37,7 +39,6 @@ using Grand.Mediator; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; -using OperatingSystem = Grand.Infrastructure.OperatingSystem; namespace Grand.Web.Admin.Controllers; @@ -596,25 +597,21 @@ public async Task Customer(CustomerSettingsModel model) return RedirectToAction("Customer"); } - public async Task GeneralCommon([FromServices] IEnumerable themes, [FromServices] IDateTimeService dateTimeService) + public async Task GeneralCommon([FromServices] IEnumerable themes, [FromServices] IDateTimeService dateTimeService, + [FromServices] IContextAccessor contextAccessor) { var model = new GeneralCommonSettingsModel(); var storeScope = await GetActiveStore(); model.ActiveStore = storeScope; //datettime settings var dateTimeSettings = await settingService.LoadSetting(storeScope); - model.DateTimeSettings.DefaultStoreTimeZoneId = dateTimeSettings.DefaultStoreTimeZoneId; - var iswindows = OperatingSystem.IsWindows(); - foreach (var timeZone in dateTimeService.GetSystemTimeZones()) - { - var name = iswindows ? timeZone.DisplayName : $"{timeZone.StandardName} ({timeZone.Id})"; - model.DateTimeSettings.AvailableTimeZones.Add(new SelectListItem { - Text = name, - Value = timeZone.Id, - Selected = timeZone.Id.Equals(dateTimeSettings.DefaultStoreTimeZoneId, - StringComparison.OrdinalIgnoreCase) - }); - } + //the default text is for a database already on 2.4, where the resources of 2.4 are not imported again + model.DateTimeSettings.AvailableTimeZones = dateTimeService.GetStoreTimeZoneOptions( + dateTimeSettings.DefaultStoreTimeZoneId, + translationService.GetResource("Admin.Settings.GeneralCommon.DefaultStoreTimeZone.Server", + contextAccessor.WorkContext.WorkingLanguage.Id, "Server time zone")); + model.DateTimeSettings.DefaultStoreTimeZoneId = + model.DateTimeSettings.AvailableTimeZones.First(x => x.Selected).Value; //store information var storeInformationSettings = await settingService.LoadSetting(storeScope); diff --git a/src/Web/Grand.Web.AdminShared/Extensions/DateTimeServiceExtensions.cs b/src/Web/Grand.Web.AdminShared/Extensions/DateTimeServiceExtensions.cs new file mode 100644 index 0000000000..42cfb0dcbc --- /dev/null +++ b/src/Web/Grand.Web.AdminShared/Extensions/DateTimeServiceExtensions.cs @@ -0,0 +1,56 @@ +using Grand.Business.Core.Interfaces.Common.Directory; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace Grand.Web.AdminShared.Extensions; + +public static class DateTimeServiceExtensions +{ + /// + /// The choices for a store's time zone, with the one dates are really shown in selected + /// (see DateTimeService.CurrentTimeZone). The empty value means the store follows the server, as it does + /// after installation, so saving the form never turns that into a fixed zone. A configured zone that + /// resolves but is not listed - a Windows id on Linux, or the reverse - keeps an option of its own. + /// + public static IList GetStoreTimeZoneOptions(this IDateTimeService dateTimeService, + string configuredTimeZoneId, string serverTimeZoneLabel) + { + var options = new List { + new() { Text = $"{serverTimeZoneLabel}: {DisplayName(TimeZoneInfo.Local)}", Value = "" } + }; + options.AddRange(dateTimeService.GetSystemTimeZones() + .Select(zone => new SelectListItem { Text = DisplayName(zone), Value = zone.Id })); + + var selected = options.FirstOrDefault(x => x.Value.Equals(configuredTimeZoneId, StringComparison.OrdinalIgnoreCase)) + ?? AddUnlistedZone(dateTimeService, configuredTimeZoneId, options) + ?? options[0]; + selected.Selected = true; + + return options; + } + + private static SelectListItem AddUnlistedZone(IDateTimeService dateTimeService, string timeZoneId, + List options) + { + if (string.IsNullOrEmpty(timeZoneId)) return null; + try + { + var option = new SelectListItem { + Text = DisplayName(dateTimeService.FindTimeZoneById(timeZoneId)), Value = timeZoneId + }; + options.Add(option); + return option; + } + catch (Exception exc) when (exc is TimeZoneNotFoundException or InvalidTimeZoneException) + { + //unknown on this machine - DateTimeService.CurrentTimeZone shows dates in the server's zone then + return null; + } + } + + private static string DisplayName(TimeZoneInfo zone) + { + return Grand.Infrastructure.OperatingSystem.IsWindows() + ? zone.DisplayName + : $"{zone.StandardName} ({zone.Id})"; + } +} diff --git a/src/Web/Grand.Web.Store/Controllers/SettingController.cs b/src/Web/Grand.Web.Store/Controllers/SettingController.cs index 59cf921fcd..d1e5b79db7 100644 --- a/src/Web/Grand.Web.Store/Controllers/SettingController.cs +++ b/src/Web/Grand.Web.Store/Controllers/SettingController.cs @@ -20,6 +20,7 @@ using Grand.Domain.Stores; using Grand.Infrastructure; using Grand.Infrastructure.Caching; +using Grand.Web.AdminShared.Extensions; using Grand.Web.AdminShared.Extensions.Mapping; using Grand.Web.AdminShared.Extensions.Mapping.Settings; using Grand.Web.AdminShared.Models.Settings; @@ -78,18 +79,13 @@ public async Task GeneralCommon([FromServices] IEnumerable(storeScope); - model.DateTimeSettings.DefaultStoreTimeZoneId = dateTimeSettings.DefaultStoreTimeZoneId; - var isWindows = Grand.Infrastructure.OperatingSystem.IsWindows(); - foreach (var timeZone in dateTimeService.GetSystemTimeZones()) - { - var name = isWindows ? timeZone.DisplayName : $"{timeZone.StandardName} ({timeZone.Id})"; - model.DateTimeSettings.AvailableTimeZones.Add(new SelectListItem { - Text = name, - Value = timeZone.Id, - Selected = timeZone.Id.Equals(dateTimeSettings.DefaultStoreTimeZoneId, - StringComparison.OrdinalIgnoreCase) - }); - } + //the default text is for a database already on 2.4, where the resources of 2.4 are not imported again + model.DateTimeSettings.AvailableTimeZones = dateTimeService.GetStoreTimeZoneOptions( + dateTimeSettings.DefaultStoreTimeZoneId, + translationService.GetResource("Admin.Settings.GeneralCommon.DefaultStoreTimeZone.Server", + contextAccessor.WorkContext.WorkingLanguage.Id, "Server time zone")); + model.DateTimeSettings.DefaultStoreTimeZoneId = + model.DateTimeSettings.AvailableTimeZones.First(x => x.Selected).Value; var storeInformationSettings = await settingService.LoadSetting(storeScope); model.StoreInformationSettings = storeInformationSettings.ToModel(); diff --git a/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml b/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml index 1deef84754ceac110c8f6e369516888bcf752b34..ee6e753e3f0188256542dc49d34a1c4eab2f1d93 100644 GIT binary patch delta 119 zcmca{JpSFu_=Xn77N!>F7M2#)7Pc1l7LFFq7OocV7M>Q~Eqq>f)A?-pc&0np^6_!% zF%&bTG88eCO>dN9x1ApFi=S(H+E4zX=?g6QtlGWo_<)!nhy{RH5Qv3F7M2#)7Pc1l7LFFq7OocV7M>Q~Eqq>f?FsgLK+F%s0zfPX X#6mzU48$TpEDFS8+Y{`?`<4O#S(X}x diff --git a/src/Web/Grand.Web/App_Data/Resources/Upgrade/en_240.xml b/src/Web/Grand.Web/App_Data/Resources/Upgrade/en_240.xml index cef280fe42..ae4b8289b2 100644 --- a/src/Web/Grand.Web/App_Data/Resources/Upgrade/en_240.xml +++ b/src/Web/Grand.Web/App_Data/Resources/Upgrade/en_240.xml @@ -555,4 +555,7 @@ This order can no longer be cancelled - only a pending order can. + + Server time zone + \ No newline at end of file From 61f9e5cd38f48ae24e51e3faa30bcdb1961e722c Mon Sep 17 00:00:00 2001 From: support Date: Sun, 1 Nov 2026 07:33:09 +0100 Subject: [PATCH 2/3] Let a guest without an email be saved in the admin The edit validator lowercased the posted email and the update trimmed it without checking it, so saving a guest, who has none, returned a 500. The email is now required unless the customer has none stored and is not being moved to the Registered group. The required message is also localized now: WithMessage covered only EmailAddress, so an empty field showed the FluentValidation default. --- .../Services/CustomerViewModelServiceTests.cs | 11 +++ .../Validators/CustomerValidatorTests.cs | 78 ++++++++++++++++++- .../Services/CustomerViewModelService.cs | 4 +- .../Validators/Customers/CustomerValidator.cs | 22 +++++- 4 files changed, 108 insertions(+), 7 deletions(-) diff --git a/src/Tests/Grand.Web.Admin.Tests/Services/CustomerViewModelServiceTests.cs b/src/Tests/Grand.Web.Admin.Tests/Services/CustomerViewModelServiceTests.cs index 7fbd5b0a99..c5aca627ed 100644 --- a/src/Tests/Grand.Web.Admin.Tests/Services/CustomerViewModelServiceTests.cs +++ b/src/Tests/Grand.Web.Admin.Tests/Services/CustomerViewModelServiceTests.cs @@ -172,6 +172,17 @@ public async Task InsertCustomerModel_MapsStoreIdFromModel() _customerServiceMock.Verify(c => c.InsertCustomer(It.Is(x => x.StoreId == "store-1")), Times.Once); } + [TestMethod] + public async Task UpdateCustomerModel_GuestWithoutEmail_StaysWithoutOne() + { + var customer = await _customerViewModelService.UpdateCustomerModel( + new Customer { Id = "c1" }, new CustomerModel { Id = "c1", AdminComment = "called in" }); + + Assert.AreEqual("called in", customer.AdminComment); + Assert.IsTrue(string.IsNullOrEmpty(customer.Email)); + Assert.IsTrue(string.IsNullOrEmpty(customer.Username)); + } + [TestMethod] public async Task PrepareCustomerModel_StoreManager_PresetsCurrentStoreId() { diff --git a/src/Tests/Grand.Web.Admin.Tests/Validators/CustomerValidatorTests.cs b/src/Tests/Grand.Web.Admin.Tests/Validators/CustomerValidatorTests.cs index 9cf0644de1..8de8117536 100644 --- a/src/Tests/Grand.Web.Admin.Tests/Validators/CustomerValidatorTests.cs +++ b/src/Tests/Grand.Web.Admin.Tests/Validators/CustomerValidatorTests.cs @@ -20,7 +20,9 @@ public class CustomerValidatorTests private const string CurrentStoreId = "store-current"; private const string RequiredMessage = "Admin.Customers.Customers.Fields.Store.Required"; private const string MustBeCurrentStoreMessage = "Admin.Customers.Customers.Fields.Store.MustBeCurrentStore"; + private const string EmailRequiredMessage = "Admin.Customers.Customers.Fields.Email.Required"; + private Mock _customerServiceMock; private Mock _groupServiceMock; private CustomerValidator _validator; @@ -30,6 +32,7 @@ public void Setup() var translationServiceMock = new Mock(); translationServiceMock.Setup(t => t.GetResource(It.IsAny())).Returns(k => k); + _customerServiceMock = new Mock(); _groupServiceMock = new Mock(); _groupServiceMock .Setup(g => g.GetAllCustomerGroups(It.IsAny(), It.IsAny(), It.IsAny(), @@ -49,7 +52,7 @@ public void Setup() translationServiceMock.Object, new Mock().Object, contextAccessorMock.Object, - new Mock().Object, + _customerServiceMock.Object, _groupServiceMock.Object, new CustomerSettings(), new CustomerConfig()); @@ -58,6 +61,79 @@ public void Setup() private static CustomerModel BuildModel(string storeId) => new() { Id = "customer-1", Email = "customer@example.com", StoreId = storeId }; + [TestMethod] + [DataRow(null)] + [DataRow("")] + public async Task Email_Empty_GuestWithoutEmail_IsAccepted(string email) + { + _customerServiceMock.Setup(c => c.GetCustomerById("customer-1")) + .ReturnsAsync(new Customer { Id = "customer-1", Email = null }); + + var result = await _validator.ValidateAsync(new CustomerModel { Id = "customer-1", Email = email, StoreId = CurrentStoreId }); + + Assert.IsFalse(result.Errors.Any(e => e.PropertyName == nameof(CustomerModel.Email))); + } + + [TestMethod] + public async Task Email_Empty_GuestBecomingRegistered_ReportsRequired() + { + _customerServiceMock.Setup(c => c.GetCustomerById("customer-1")) + .ReturnsAsync(new Customer { Id = "customer-1", Email = null }); + _groupServiceMock.Setup(g => g.GetCustomerGroupBySystemName(SystemCustomerGroupNames.Registered)) + .ReturnsAsync(new CustomerGroup { Id = "group-registered" }); + + var result = await _validator.ValidateAsync(new CustomerModel { + Id = "customer-1", StoreId = CurrentStoreId, CustomerGroups = ["group-registered"] + }); + + Assert.IsTrue(result.Errors.Any(e => e.ErrorMessage == EmailRequiredMessage)); + } + + [TestMethod] + public async Task Email_Invalid_GuestWithoutEmail_IsStillChecked() + { + _customerServiceMock.Setup(c => c.GetCustomerById("customer-1")) + .ReturnsAsync(new Customer { Id = "customer-1", Email = null }); + + var result = await _validator.ValidateAsync(new CustomerModel { Id = "customer-1", Email = "not-an-email", StoreId = CurrentStoreId }); + + Assert.IsTrue(result.Errors.Any(e => e.PropertyName == nameof(CustomerModel.Email))); + } + + [TestMethod] + [DataRow(null)] + [DataRow("")] + public async Task Email_Cleared_RegisteredCustomer_ReportsRequired(string email) + { + _customerServiceMock.Setup(c => c.GetCustomerById("customer-1")) + .ReturnsAsync(new Customer { Id = "customer-1", Email = "customer@example.com" }); + + var result = await _validator.ValidateAsync(new CustomerModel { Id = "customer-1", Email = email, StoreId = CurrentStoreId }); + + Assert.IsTrue(result.Errors.Any(e => e.ErrorMessage == EmailRequiredMessage)); + } + + [TestMethod] + public async Task Email_Changed_IsStillCheckedForDuplicates() + { + _customerServiceMock.Setup(c => c.GetCustomerById("customer-1")) + .ReturnsAsync(new Customer { Id = "customer-1", Email = "customer@example.com" }); + _customerServiceMock.Setup(c => c.GetCustomerByEmail("taken@example.com", It.IsAny())) + .ReturnsAsync(new Customer { Id = "customer-2", Email = "taken@example.com" }); + + var result = await _validator.ValidateAsync(new CustomerModel { Id = "customer-1", Email = "taken@example.com", StoreId = CurrentStoreId }); + + Assert.IsTrue(result.Errors.Any(e => e.ErrorMessage == "Account.EmailUsernameErrors.EmailAlreadyExists")); + } + + [TestMethod] + public async Task Email_Empty_NewCustomer_ReportsRequired() + { + var result = await _validator.ValidateAsync(new CustomerModel { StoreId = CurrentStoreId }); + + Assert.IsTrue(result.Errors.Any(e => e.ErrorMessage == EmailRequiredMessage)); + } + [TestMethod] public async Task StoreId_Empty_FailsRequired() { diff --git a/src/Web/Grand.Web.AdminShared/Services/CustomerViewModelService.cs b/src/Web/Grand.Web.AdminShared/Services/CustomerViewModelService.cs index ae9f0f111d..5aa490448b 100644 --- a/src/Web/Grand.Web.AdminShared/Services/CustomerViewModelService.cs +++ b/src/Web/Grand.Web.AdminShared/Services/CustomerViewModelService.cs @@ -506,8 +506,8 @@ await _customerService.UpdateUserField(customer, SystemCustomerFieldNames.TwoFac customer.Email = model.Email; customer.Username = _customerSettings.UsernamesEnabled switch { - true when _customerSettings.AllowUsersToChangeUsernames => model.Username.Trim(), - false => model.Email.Trim(), + true when _customerSettings.AllowUsersToChangeUsernames => model.Username?.Trim(), + false => model.Email?.Trim(), _ => customer.Username }; diff --git a/src/Web/Grand.Web.AdminShared/Validators/Customers/CustomerValidator.cs b/src/Web/Grand.Web.AdminShared/Validators/Customers/CustomerValidator.cs index 041059c58b..a99eef952f 100644 --- a/src/Web/Grand.Web.AdminShared/Validators/Customers/CustomerValidator.cs +++ b/src/Web/Grand.Web.AdminShared/Validators/Customers/CustomerValidator.cs @@ -31,9 +31,11 @@ public CustomerValidator( CustomerCreateValidator(); CustomerEditValidator(); - //customer email - RuleFor(x => x.Email).NotEmpty().EmailAddress() - .WithMessage(translationService.GetResource("Admin.Customers.Customers.Fields.Email.Required")); + //customer email - a guest has none, and staying a guest must not take inventing one + RuleFor(x => x.Email) + .NotEmpty().WithMessage(translationService.GetResource("Admin.Customers.Customers.Fields.Email.Required")) + .EmailAddress().WithMessage(translationService.GetResource("Admin.Customers.Customers.Fields.Email.Required")) + .WhenAsync(async (x, _) => !string.IsNullOrEmpty(x.Email) || !await StaysGuestWithoutEmail(x)); //store - required only when the editor is not an administrator (admins may manage store-independent //back-office/system accounts that have no store) @@ -107,6 +109,17 @@ public CustomerValidator( context.AddFailure("The username cannot be empty"); }); + async Task StaysGuestWithoutEmail(CustomerModel model) + { + if (string.IsNullOrEmpty(model.Id)) return false; + + var customer = await customerService.GetCustomerById(model.Id); + if (customer == null || !string.IsNullOrEmpty(customer.Email)) return false; + + var registered = await groupService.GetCustomerGroupBySystemName(SystemCustomerGroupNames.Registered); + return registered == null || model.CustomerGroups == null || !model.CustomerGroups.Contains(registered.Id); + } + async Task ValidateCustomerGroups(IList customerGroups, CustomerModel customerModel) { ArgumentNullException.ThrowIfNull(customerGroups); @@ -250,7 +263,8 @@ void CustomerEditValidator() customer?.Id == contextAccessor.WorkContext.CurrentCustomer.Id) context.AddFailure("You can't edit own data from admin panel"); - if (customer != null && customer.Email != x.Email.ToLower()) + //an empty email is for the required rule above to judge: guests have none + if (customer != null && !string.IsNullOrWhiteSpace(x.Email) && customer.Email != x.Email.ToLower()) { if (!CommonHelper.IsValidEmail(x.Email)) context.AddFailure( From d8515f10b5efad7b74118975a4433763604df3f8 Mon Sep 17 00:00:00 2001 From: support Date: Sun, 1 Nov 2026 07:33:09 +0100 Subject: [PATCH 3/3] Stop reporting untouched fields when they lose focus The message appeared on mousedown, when an autofocused field lost focus, and moved the layout. The button under the pointer slid away before mouseup and the click was lost, on the login page among others. An untouched empty field, unticked checkbox or empty group now reports nothing until the form is submitted. --- .../Grand.Web/vueapp/src/compat/validate.js | 19 +++++++++++++++++-- .../wwwroot/bundles/app.runtime.bundle.js | 4 ++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Web/Grand.Web/vueapp/src/compat/validate.js b/src/Web/Grand.Web/vueapp/src/compat/validate.js index 810fffbb30..7f13d3ce7f 100644 --- a/src/Web/Grand.Web/vueapp/src/compat/validate.js +++ b/src/Web/Grand.Web/vueapp/src/compat/validate.js @@ -66,6 +66,9 @@ const messages = { const isEmpty = v => v === '' || v === null || v === undefined +//What getValue() reports for a field left as it was: an unticked checkbox is false, a group is []. +const isUnanswered = v => isEmpty(v) || v === false || (Array.isArray(v) && v.length === 0) + const validators = { required(value, params) { const allowFalse = params && typeof params === 'object' && 'allowFalse' in params @@ -168,6 +171,18 @@ export const ValidationProvider = { mounted() { this._onEvent = () => this.validate() + /* + * Leaving a field nobody has touched is not an attempt to fill it in, so it + * reports nothing; submitting still does. The message used to appear on + * mousedown, when an autofocused field lost focus, and move the layout - the + * button under the pointer slid away before mouseup and the click was lost. + * A field being typed in validates on `input`, so its layout is already settled. + */ + this._onFocusOut = () => { + if (this.state === null && isUnanswered(this.getValue())) return + this.validate() + } + /* * Controls that commit on `change` must not be validated on `input`. * A real click on a checkbox dispatches click, input and change as @@ -188,13 +203,13 @@ export const ValidationProvider = { if (!commitsOnChange) this.$el.addEventListener('input', this._onEvent) this.$el.addEventListener('change', this._onEvent) - this.$el.addEventListener('focusout', this._onEvent) + this.$el.addEventListener('focusout', this._onFocusOut) }, unmounted() { if (this.$el && this._onEvent) { this.$el.removeEventListener('input', this._onEvent) this.$el.removeEventListener('change', this._onEvent) - this.$el.removeEventListener('focusout', this._onEvent) + this.$el.removeEventListener('focusout', this._onFocusOut) } }, methods: { diff --git a/src/Web/Grand.Web/wwwroot/bundles/app.runtime.bundle.js b/src/Web/Grand.Web/wwwroot/bundles/app.runtime.bundle.js index 1d58022418..b472856af2 100644 --- a/src/Web/Grand.Web/wwwroot/bundles/app.runtime.bundle.js +++ b/src/Web/Grand.Web/wwwroot/bundles/app.runtime.bundle.js @@ -103,7 +103,7 @@ var BO=Object.create(null);function VO(e,t){if(!W(e)){if(e.nodeType)e=e.innerHTM :style="{ height: '3.5rem', cursor: 'pointer', opacity: i === index ? 1 : 0.5 }" @click="goTo(i)"> - `};function xk(e){e.component(`b-form-rating`,vk),e.component(`countdown`,yk),e.component(`vue-gallery-slideshow`,bk)}function Sk(e,t,n){if(!e)return null;let r=n||document,i=typeof CSS<`u`&&CSS.escape?CSS.escape(e):e;return r.querySelector(`[name="${i}"]`)?.getAttribute(`data-val-`+t)||null}function Ck(e,t,n){let r=(window.grandValidationMessages||{})[e],i=r&&r!==`validation.`+e?r:t;return n===void 0?i:String(i).replace(`{0}`,n)}var wk={required:(e,t,n,r)=>Sk(e,`required`,r)||n||Ck(`required`,`This field is required.`),email:(e,t,n,r)=>Sk(e,`email`,r)||Ck(`email`,`This field must be a valid email.`),confirmed:(e,t,n,r)=>Sk(e,`equalto`,r)||Ck(`confirmed`,`The confirmation does not match.`),min:(e,t,n,r)=>Sk(e,`min`,r)||Ck(`minlength`,`This field should be at least {0} characters.`,t),max:(e,t,n,r)=>Sk(e,`max`,r)||Ck(`maxlength`,`This field should be at most {0} characters.`,t),exact_length:(e,t,n)=>n||Ck(`exactlength`,`Select at least {0} option.`,t)},Tk=e=>e===``||e==null,Ek={required(e,t){let n=t&&typeof t==`object`&&`allowFalse`in t?t.allowFalse:void 0;return n===!1||n===`false`?e===!0:!Tk(e)},email(e){return Tk(e)?!0:/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e)},min(e,t){if(Tk(e))return!0;let n=Array.isArray(t)?t[0]:t;return String(e).length>=parseInt(n)},max(e,t){if(Tk(e))return!0;let n=Array.isArray(t)?t[0]:t;return String(e).length<=parseInt(n)},confirmed(e,t,n){let r=Array.isArray(t)?t[0]:t;typeof r==`string`&&r.startsWith(`@`)&&(r=r.substring(1));let i=n.observer?n.observer.findProvider(r):null;return!i||e===i.getValue()},exact_length(e,t){if(Tk(e))return!1;let n=Array.isArray(t)?t[0]:t,r=parseInt(n,10),i=Number.isNaN(r)?1:r;return(e.length===void 0?String(e).length:e.length)>=i}};function Dk(e){return e?typeof e==`string`?e.split(`|`).filter(Boolean).map(e=>{let t=e.indexOf(`:`);return t===-1?{name:e,params:null}:{name:e.substring(0,t),params:e.substring(t+1).split(`,`)}}):Object.entries(e).filter(e=>e[1]!==!1).map(([e,t])=>({name:e,params:t===!0?null:t})):[]}var Ok={name:`ValidationProvider`,inject:{observer:{from:`veeObserver`,default:null}},props:{tag:{type:String,default:`div`},rules:{type:[String,Object],default:null},name:{type:String,default:null},vid:{type:String,default:null},mode:{type:String,default:null}},data(){return{errors:[],state:null}},computed:{classes(){return this.state===null?``:this.state?`is-valid`:`is-invalid`},fieldId(){return this.vid||this.name}},created(){this.observer&&this.observer.register(this)},beforeUnmount(){this.observer&&this.observer.unregister(this)},mounted(){this._onEvent=()=>this.validate();let e=this.control();e?.tagName!==`SELECT`&&e?.type!==`checkbox`&&e?.type!==`radio`&&this.$el.addEventListener(`input`,this._onEvent),this.$el.addEventListener(`change`,this._onEvent),this.$el.addEventListener(`focusout`,this._onEvent)},unmounted(){this.$el&&this._onEvent&&(this.$el.removeEventListener(`input`,this._onEvent),this.$el.removeEventListener(`change`,this._onEvent),this.$el.removeEventListener(`focusout`,this._onEvent))},methods:{control(){return this.$el?this.$el.querySelector(`input, select, textarea`):null},getValue(){let e=this.control();if(e){if(e.type===`checkbox`){if(!e.hasAttribute(`value`))return e.checked;let t=this.$el.querySelectorAll(`input[type=checkbox]`);return Array.from(t).filter(e=>e.checked).map(e=>e.value)}if(e.type===`radio`){let e=this.$el.querySelectorAll(`input[type=radio]`);for(let t of e)if(t.checked)return t.value}else return e.value}},fieldName(){let e=this.control();return this.name||(e?e.getAttribute(`name`):null)||this.vid},validate(){let e=this.getValue(),t=[],n=Dk(this.rules),r=n.map(e=>Array.isArray(e.params)?e.params[1]:null).find(Boolean)||null;for(let i of n){let n=Ek[i.name];if(n&&!n(e,i.params,this)){let e=wk[i.name],n=Array.isArray(i.params)?i.params[0]:i.params,a=i.params&&i.params[1]||r;t.push(e?e(this.fieldName(),n,a,this.$el):Ck(`invalid`,`Invalid value.`))}}this.errors=t,this.state=t.length===0;let i=this.control();return i&&(i.classList.toggle(`is-invalid`,t.length>0),i.classList.toggle(`is-valid`,t.length===0&&this.state!==null)),Promise.resolve(t.length===0)},reset(){this.errors=[],this.state=null;let e=this.control();e&&e.classList.remove(`is-invalid`,`is-valid`)}},render(){let e=this.$slots.default?this.$slots.default({errors:this.errors,classes:this.classes,valid:this.state}):[];return Nx(this.tag,null,e)}},kk={name:`ValidationObserver`,props:{tag:{type:String,default:`div`}},provide(){return{veeObserver:this}},data(){return{providers:[]}},computed:{errors(){let e={};return this.providers.forEach(t=>{e[t.fieldId||t.fieldName()]=t.errors}),e},invalid(){return this.providers.some(e=>e.state===!1)}},methods:{register(e){this.providers.push(e)},unregister(e){let t=this.providers.indexOf(e);t>-1&&this.providers.splice(t,1)},findProvider(e){return this.providers.find(t=>t.vid===e||t.name===e)||null},validate(){return Promise.all(this.providers.map(e=>e.validate())).then(e=>e.every(Boolean))},handleSubmit(e){return this.validate().then(t=>{t&&typeof e==`function`&&e()})},reset(){this.providers.forEach(e=>e.reset())}},render(){let e=this.$slots.default?this.$slots.default({handleSubmit:this.handleSubmit,validate:this.validate,reset:this.reset,errors:this.errors,invalid:this.invalid}):[];return Nx(this.tag,null,e)}};function Ak(e){e.component(`validation-provider`,Ok),e.component(`validation-observer`,kk)}var jk=null;function Mk(){return jk||(jk=document.createElement(`div`),jk.className=`toast-container position-fixed top-0 end-0 p-3`,jk.style.zIndex=`1090`,document.body.appendChild(jk)),jk}var Nk={toast(e,t={}){let n=t.variant||`info`,r=document.createElement(`div`);r.className=`toast show align-items-center border-`+n,r.setAttribute(`role`,`alert`);let i=document.createElement(`div`);i.className=`toast-header text-bg-`+n;let a=document.createElement(`strong`);a.className=`me-auto`,a.innerText=t.title||``;let o=document.createElement(`button`);o.type=`button`,o.className=`btn-close btn-close-white ms-2`,o.addEventListener(`click`,()=>r.remove()),i.appendChild(a),i.appendChild(o),r.appendChild(i);let s=document.createElement(`div`);if(s.className=`toast-body`,t.href){let n=document.createElement(`a`);n.href=t.href,n.innerText=e,s.appendChild(n)}else s.innerText=e;r.appendChild(s),Mk().appendChild(r);let c=t.autoHideDelay||5e3;t.noAutoHide||setTimeout(()=>r.remove(),c)}},Pk={};function Z(e,t){Pk[e]=t}function Fk(e){let t=e.textContent.trim();if(!t)return{};try{return JSON.parse(t)}catch(t){return console.error(`[grand] view "${e.dataset.grandVm}" has an unparseable payload`,t),null}}var Ik=`script[type="application/json"][data-grand-vm]`;function Lk(e,t=[]){return e.querySelectorAll(Ik).forEach(e=>t.push(e)),e.querySelectorAll(`template`).forEach(e=>Lk(e.content,t)),t}function Rk(e=document){Lk(e).forEach(e=>{if(e.dataset.grandVmReady)return;let t=e.dataset.grandVm,n=Pk[t];if(!n){console.error(`[grand] no view-model registered for "${t}"`);return}let r=Fk(e);r!==null&&(e.dataset.grandVmReady=`1`,n(r,e))})}function zk(e){let t=document.querySelector(`#ModalQuickView.show`);return t?t.querySelector(`#product-details-form`):e?document.querySelector(e):null}function Bk(e){document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,e):e()}Bk(function(){let e=document.querySelector(`input[name=__RequestVerificationToken]`);if(!e)return;let t=e.value;R.defaults.headers.common[`X-CSRF-TOKEN`]=t});function Vk(e,t,n){n===void 0&&(n=0),e.length>0&&e[n](function(){n++,n===e.length?t():Vk(e,t,n)})}function Hk(){var e=document.createEvent(`Event`);e.initEvent(`DOMContentLoaded`,!0,!0),document.dispatchEvent(e)}function Uk(e,t){var n=document.createElement(`script`);n.type=`text/javascript`,e.src?(n.onload=t,n.onerror=t,n.src=e.src):n.textContent=e.innerText,document.body.appendChild(n),e.parentNode.removeChild(e),e.src||t()}var Wk=[`application/javascript`,`application/ecmascript`,`application/x-ecmascript`,`application/x-javascript`,`text/ecmascript`,`text/javascript`,`text/javascript1.0`,`text/javascript1.1`,`text/javascript1.2`,`text/javascript1.3`,`text/javascript1.4`,`text/javascript1.5`,`text/jscript`,`text/livescript`,`text/x-ecmascript`,`text/x-javascript`];function Gk(e){var t=e.querySelectorAll(`script`),n=[],r;[].forEach.call(t,function(e){r=e.getAttribute(`type`),r&&Wk.indexOf(r)===-1||n.push(function(t){Uk(e,t)})}),Vk(n,Hk)}function Kk(e){e.stopPropagation()}(function(){function e(e,t){return t||=document,t.querySelectorAll(e)}function t(e,t){for(var n in Object.keys(e))t(e[n])}function n(){var t=e(`ul`,this)[0];t&&!t.classList.contains(`-visible`)&&t.classList.add(`-visible`)}function r(){var e=this.parentElement;e&&e.classList.contains(`-visible`)&&setTimeout(function(){e.classList.remove(`-visible`)},300)}window.addEventListener(`load`,function(){t(e(`.Menu li.-hasSubmenu`),function(e){e.showMenu=n,e.hideMenu=r}),t(e(`.Menu > li.-hasSubmenu`),function(e){e.addEventListener(`click`,n)}),t(e(`.Menu li .back`),function(e){e.addEventListener(`click`,r)}),t(e(`.Menu > li.-hasSubmenu li.-hasSubmenu`),function(e){e.addEventListener(`click`,n)})})})();var Q={availableDates:[],availableDatesFrom:[],availableDatesTo:[],currentMonth:-1,currentYear:-1,currentMonthFrom:-1,currentYearFrom:-1,currentMonthTo:-1,currentYearTo:-1,_parameter:``,noReservationsMessage:``,productId:``,ajaxUrl:``,ajaxUrl2:``,startDate:``,startDateMonth:``,startDateYear:``,init:function(e,t,n,r,i,a,o){this.noReservationsMessage=r,this.ajaxUrl=i,this.ajaxUrl2=o,this.productId=a,this.startDate=e,this.startDateMonth=n,this.startDateYear=t,document.getElementById(`reservationDatepicker`)!=null&&this.fillAvailableDates(t,n,Q._parameter,!1),document.getElementById(`reservationDatepickerFrom`)!=null&&this.fillAvailableDatesFrom(t,n),document.getElementById(`reservationDatepickerTo`)!=null&&this.fillAvailableDatesTo(t,n);var s=new Date(this.startDate),c=new af.default({field:document.getElementById(`reservationDatepicker`),onSelect:this.onDatePickerDateChange,disableDayFn:this.daysToMark,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${(`0`+(e.getMonth()+1)).slice(-2)}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=t[0],r=parseInt(t[1],10),i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();document.getElementById(`hoursDiv`)!=null&&(document.getElementById(`hoursDiv`).innerHTML=``),Q.fillAvailableDates(t,n,Q._parameter,!1),Q.onDatePickerDateChange()},firstDay:1,defaultDate:s});new af.default({field:document.getElementById(`reservationDatepickerFrom`),onSelect:this.onDatePickerSelect,disableDayFn:this.daysToMarkFrom,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${(`0`+(e.getMonth()+1)).slice(-2)}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=parseInt(t[0],10),r=parseInt(t[1],10),i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();Q.fillAvailableDatesFrom(t,n)},firstDay:1,defaultDate:s}),new af.default({field:document.getElementById(`reservationDatepickerTo`),onSelect:this.onDatePickerSelect,disableDayFn:this.daysToMarkTo,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${(`0`+(e.getMonth()+1)).slice(-2)}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=parseInt(t[0],10),r=parseInt(t[1],10),i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();Q.fillAvailableDatesTo(t,n)},firstDay:1,defaultDate:s}),this.onDatePickerDateChange(),document.getElementById(`parameterDropdown`)!=null&&document.querySelector(`#parameterDropdown`).addEventListener(`change`,function(){Q.fillAvailableDates(Q.currentYear,Q.currentMonth,this.value),c.clear(),document.getElementById(`hoursDiv`)!=null&&(document.getElementById(`hoursDiv`).innerHTML=Q.noReservationsMessage)})},reload:function(e,t,n){this.startDate=e,this.startDateMonth=n,this.startDateYear=t,this.fillAvailableDates(t,n,Q._parameter,!1),new af.default({field:document.getElementById(`reservationDatepicker`),onSelect:this.onDatePickerDateChange,disableDayFn:this.daysToMark,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${e.getMonth()+1}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=parseInt(t[0],10),r=parseInt(t[1],10)-1,i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();document.getElementById(`hoursDiv`)!=null&&(document.getElementById(`hoursDiv`).innerHTML=``),Q.fillAvailableDates(t,n,Q._parameter,!1)},firstDay:1,defaultDate:this.startDate}),this.onDatePickerDateChange()},daysToMark:function(e){for(let a=0;a`}}if(Q.availableDates.length==0){var f=document.createElement(`label`);f.innerHTML=Q.noReservationsMessage,document.querySelector(`#hoursDiv`).appendChild(f)}}},fillAvailableDates:function(e,t,n){var r={productId:Q.productId,month:t,year:e,parameter:n};R({url:Q.ajaxUrl,method:`post`,params:r,headers:{Accept:`application/json`,"Content-Type":`application/json`}}).then(r=>{Q.currentMonth=t,Q.currentYear=e,Q.availableDates=r.data,Q._parameter=n}).catch(function(e){alert(e)})},fillAvailableDatesFrom:function(e,t){var n={productId:Q.productId,month:t,year:e,parameter:null};R({url:Q.ajaxUrl,method:`post`,params:n,headers:{Accept:`application/json`,"Content-Type":`application/json`}}).then(n=>(Q.currentMonthFrom=t,Q.currentYearFrom=e,Q.availableDatesFrom=Q.availableDatesFrom.concat(n.data),!0)).catch(function(e){alert(e)})},fillAvailableDatesTo:function(e,t){var n={productId:Q.productId,month:t,year:e,parameter:null};R({url:Q.ajaxUrl,method:`post`,params:n,headers:{Accept:`application/json`,"Content-Type":`application/json`}}).then(n=>{Q.currentMonthTo=t,Q.currentYearTo=e,Q.availableDatesTo=Q.availableDatesTo.concat(n.data)}).catch(function(e){alert(e)})},onDatePickerSelect:function(){var e=zk(`#product-details-form-`+Q.productId);if(e){var t=new FormData(e);R({url:Q.ajaxUrl2,method:`post`,data:t}).then(e=>{var t=function(e,t){var n=document.querySelector(e);n&&(n.innerText=t)};e.data.sku&&t(`#sku-`+Q.productId,e.data.sku),e.data.mpn&&t(`#mpn-`+Q.productId,e.data.mpn),e.data.gtin&&t(`#gtin-`+Q.productId,e.data.gtin),e.data.price&&(document.querySelector(`.price-value-`+Q.productId+` .actual-price`)?t(`.price-value-`+Q.productId+` .actual-price`,e.data.price):t(`.price-value-`+Q.productId,e.data.price))})}}};window.runScripts=Gk,window.StopPropagation=Kk,window.Reservation=Q;var qk={loadWaiting:!1,sidebarcartselector:`.sidebar-cart`,quickview_product:function(e){R({url:e,method:`get`}).then(function(e){qk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){qk.resetLoadWaiting()})},addproducttocart_catalog:function(e,t,n){if(t.toLowerCase()==`true`){var r=document.querySelector(`#addtocart_`+n+`_EnteredQuantity`).value;e.indexOf(`forceredirection`)==-1?e+=`?quantity=`+r:e+=`&quantity=`+r}this.loadWaiting==0&&(this.setLoadWaiting(!0),R({url:e,method:`post`}).then(function(e){qk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){window.vmwishlist!==void 0&&window.vmwishlist.getModel(),window.vmorder!==void 0&&window.vmorder.getModel(),qk.resetLoadWaiting()}))},addproducttocart_details:function(e,t){if(this.loadWaiting==0){this.setLoadWaiting(!0);var n=zk(t);n?R({url:e,data:new FormData(n),method:`post`}).then(function(e){qk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){window.vmwishlist!==void 0&&window.vmwishlist.getModel(),window.vmorder!==void 0&&window.vmorder.getModel(),qk.resetLoadWaiting()}):this.setLoadWaiting(!1)}},updateitem:function(e,t){var n,r=zk(t);if(r){var i=new FormData(r);n=window.vmwishlist===void 0?window.vmorder:window.vmwishlist,R({url:e,data:i,method:`post`}).then(function(e){e.data.success?window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalQuickView`)).hide():n.displayWarning(e.data.message,`danger`)}).catch(function(e){e.axiosFailure}).then(function(){n.getModel(),qk.resetLoadWaiting()})}},addbid:function(e,t){if(this.loadWaiting==0){this.setLoadWaiting(!0);var n=document.querySelector(t);R({url:e,data:new FormData(n),method:`post`}).then(function(e){qk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){qk.resetLoadWaiting()})}},addproducttocomparelist:function(e,t,n){if(this.loadWaiting==0){this.setLoadWaiting(!0);var r=this.getCookie(`Grand.CompareProduct`);return r===``?r=e:r.includes(e)||(r=r+`|`+e),this.setCookie(`Grand.CompareProduct`,r),window.vm.updateCompareProductsQty(),window.vm.displayBarNotification(t,n,`success`,3500),this.resetLoadWaiting(),!1}},setLoadWaiting:function(e){this.loadWaiting=e},success_process:function(e){if(e.data.updatetopwishlistsectionhtml&&document.querySelector(`.wishlist-qty`)&&(document.querySelector(`.wishlist-qty`).innerHTML=e.data.updatetopwishlistsectionhtml),e.data.sidebarshoppingcartmodel){var t=e.data.sidebarshoppingcartmodel;window.vm.flycart=t,window.vm.flycartitems=t.Items,window.vm.flycartindicator=t.TotalProducts}if(e.data.updatetopcartsectionhtml&&(window.vm.flycartindicator=e.data.updatetopcartsectionhtml),e.data.product&&e.data.success==1&&(window.vm.PopupQuickViewVueModal=e.data.model,Object.assign(window.vm.PopupQuickViewVueModal,{RelatedProducts:[]}),window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalQuickView`)).show(),e.data.model.ProductType==20)){var n=new Date(e.data.model.StartDate).toLocaleDateString(`en-US`),r=new Date(e.data.model.StartDate).getFullYear(),i=new Date(e.data.model.StartDate).getUTCMonth()+1;Object.assign(window.vm.PopupQuickViewVueModal,{ReservationFullDate:n}),Object.assign(window.vm.PopupQuickViewVueModal,{ReservationYear:r}),Object.assign(window.vm.PopupQuickViewVueModal,{ReservationMonth:i})}if(e.data.message){if(e.data.success==1){if(window.vm.PopupAddToCartVueModal=e.data.model,window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalQuickView`)).hide(),window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalAddToCart`)).show(),e.data.refreshreservation==1){var a=document.querySelector(`#parameterDropdown`),o=a?a.value:``;window.Reservation.fillAvailableDates(window.Reservation.currentYear,window.Reservation.currentMonth,o,!0)}}else window.vm.displayBarNotification(e.data.message,``,`error`,3500);return!1}return e.data.redirect?(location.href=e.data.redirect,!0):!1},resetLoadWaiting:function(){qk.setLoadWaiting(!1)},axiosFailure:function(){alert(`Failed to add the product. Please refresh the page and try one more time.`)},setCookie:function(e,t,n){let r=new Date;r.setTime(r.getTime()+n*24*60*60*1e3);let i=`expires=`+r.toUTCString();document.cookie=e+`=`+t+`;`+i+`;path=/`},getCookie:function(e){let t=e+`=`,n=document.cookie.split(`;`);for(let e=0;et.$nextTick(e))}function Yk(e,t,n){document.addEventListener(e,e=>{let r=e.target.closest?.(t);r&&n(r,e)})}Z(`advancedSearch`,({elements:e})=>{let t=()=>{let t=document.getElementById(e.checkboxId),n=document.getElementById(e.blockId);t&&n&&(n.style.display=t.checked?`flex`:`none`)};Yk(`click`,`#`+e.checkboxId,t),Jk(t)});function Xk(){return document.querySelector(`input[name=__RequestVerificationToken]`)?.value??``}function Zk(e={}){let t=new FormData;return Object.entries(e).forEach(([e,n])=>t.append(e,n)),t.append(`__RequestVerificationToken`,Xk()),t}function Qk(e,t,n=`danger`){e&&Nk.toast(e,{title:t,variant:n,autoHideDelay:5e3,appendToast:!0})}function $(e,t,n){Qk(e?.response?.data?.message||n||e?.message||String(e),t)}function $k(e){navigator.permissions&&navigator.permissions.query({name:`microphone`}).then(t=>{e(t.state!==`denied`),t.onchange=()=>e(t.state!==`denied`)}).catch(()=>{})}function eA(e,t){let n=(e,n)=>(e||[]).forEach(e=>{let r=document.querySelector(`#${t}_attribute_label_${e}`),i=document.querySelector(`#${t}_attribute_input_${e}`);r&&(r.style.display=n),i&&(i.style.display=n)});n(e.enabledattributeids,`block`),n(e.disabledattributeids,`none`)}function tA(e,t,n=document){let r=n.querySelector(`#download-message, .download-message`);r&&(r.style.display=`block`,r.classList.toggle(`alert-info`,t),r.classList.toggle(`alert-danger`,!t),r.innerText=e)}function nA(e,t=document){let n=t.querySelector(`.download-file`);n&&(n.style.display=`inline-block`,n.setAttribute(`href`,e))}Z(`checkoutAttributes`,({routes:e})=>{let t=()=>{let t=document.querySelector(`#shopping-cart-form`);if(t)return R.post(e.change,new FormData(t)).then(({data:e})=>{let t=window.vmorder;t&&(t.totals=e.model,t.cart.CheckoutAttributeInfo=e.checkoutattributeinfo||``),eA(e,`checkout`)}).catch(e=>console.error(`[grand] checkout attribute change failed`,e))};window.checkoutAttributeChange=t,window.uploadFile=e=>{let n=new FormData;n.append(`file`,e.files[0]);let r=e.getAttribute(`attribute`);R.post(e.getAttribute(`data-url`),n).then(({data:n})=>{if(n.success){let t=window.vmorder?.cart.CheckoutAttributes.find(e=>e.Id===r);t&&(t.DefaultValue=n.downloadGuid),e.setAttribute(`qq-button-id`,n.downloadGuid);let i=document.querySelector(`.hidden-upload-input`);i&&(i.value=n.downloadGuid),nA(n.downloadUrl)}return tA(n.message,n.success),t()}).catch(e=>console.error(`[grand] checkout attribute upload failed`,e))},Jk(t)}),Z(`contactAttributes`,({routes:e})=>{let t=()=>{let t=document.querySelector(`#contactus-form`);if(t)return R.post(e.change,new FormData(t)).then(({data:e})=>eA(e,`contact`)).catch(e=>console.error(`[grand] contact attribute change failed`,e))};window.contactAttributeChange=t,window.uploadFile=e=>{let n=new FormData;n.append(`file`,e.files[0]);let r=e.closest(`.contact-attribute-upload`)||document;R.post(e.getAttribute(`data-url`),n).then(({data:e})=>{if(e.success){let t=r.querySelector(`.hidden-upload-input`);t&&(t.value=e.downloadGuid),nA(e.downloadUrl,r)}return tA(e.message,e.success,r),t()}).catch(e=>console.error(`[grand] contact attribute upload failed`,e))},Yk(`change`,`.contact-attributes [id^="contact_attribute_"]`,t),Yk(`click`,`.contact-attributes [id^="contact_attribute_"]`,t),Yk(`click`,`.contact-attributes [id^="color-squares-"] li`,e=>{document.querySelector(`.contact-attributes .selected-value`)?.classList.remove(`selected-value`),e.classList.add(`selected-value`)}),Jk(t)}),Z(`barNotifications`,({messages:e})=>{ik(t=>{e.forEach(({text:e,variant:n})=>t.displayBarNotification(e,``,n,3500))})}),Z(`checkoutSteps`,({routes:e})=>{Jk(()=>{let t=window.vmorder;t?.vCartUrl?(t.vCartUrl.init(e.cartSummary,e.cartTotal),t.vShipping.init(`#co-shipping-form`,e.saveShipping),t.vBilling.init(`#co-billing-form`,e.saveBilling),t.vShippingMethod.init(`#co-shipping-method-form`,e.saveShippingMethod),t.vPaymentMethod.init(`#co-payment-method-form`,e.savePaymentMethod),t.vPaymentInfo.init(`#co-payment-info-form`,e.savePaymentInfo),t.vConfirmOrder.init(e.confirmOrder,e.completed)):console.error(`[grand] checkout controllers missing - public.checkout.js did not load`)})}),Z(`jsResources`,({res:e,routes:t,validation:n})=>{window.grandRes=Object.assign(window.grandRes||{},e),window.grandRoutes=Object.assign(window.grandRoutes||{},t),window.grandValidationMessages=Object.assign(window.grandValidationMessages||{},n)}),Z(`confirmDelete`,({route:e,field:t,selector:n,res:r})=>{document.addEventListener(`click`,i=>{let a=i.target.closest(n);a&&window.confirm(r.areYouSure)&&R.post(e,Zk({[t]:a.dataset.deleteId})).then(e=>{e.data.success===!1?Qk(e.data.error||e.data.message,r.warning):window.location=e.data.redirect}).catch(e=>$(e,r.warning))})}),Z(`confirmPost`,({route:e,elements:t,res:n})=>{Yk(`click`,`#`+t.buttonId,r=>{window.confirm(n.areYouSure)&&R.post(e).then(()=>{r.style.display=`none`;let e=document.getElementById(t.checkId);e&&(e.checked=!0)}).catch(e=>$(e,n.warning))})}),Z(`estimateShipping`,({routes:e,elements:t,res:n})=>{Yk(`click`,`#`+t.buttonId,()=>{let t=document.getElementById(`shopping-cart-form`);t&&R.post(e.estimate,new FormData(t)).then(e=>{let t=document.querySelector(`.estimate-shipping-result`);t&&(t.innerHTML=e.data),window.checkoutAttributeChange?.()}).catch(()=>Qk(n.estimateFailed,n.warning))}),Yk(`change`,`#`+t.countrySelectId,r=>{let i=document.getElementById(t.stateSelectId),a=document.getElementById(t.progressId);a&&(a.style.display=`block`),R.get(e.getStates,{params:{countryId:r.value,addSelectStateItem:!1}}).then(e=>{i&&(i.innerHTML=``,e.data.forEach(e=>{let t=document.createElement(`option`);t.value=e.id,t.innerHTML=e.name,i.appendChild(t)})),a&&(a.style.display=`none`),window.checkoutAttributeChange?.()}).catch(e=>{a&&(a.style.display=`none`),$(e,n.warning)})})}),Z(`cookieBar`,({route:e,elements:t,res:n})=>{Yk(`click`,`#`+t.barId+` [data-accept]`,r=>{R.post(e,null,{params:{accept:r.dataset.accept}}).then(()=>{let e=document.getElementById(t.barId);e&&(e.style.display=`none`)}).catch(e=>$(e,n.warning))})}),Z(`geolocation`,({route:e,known:t})=>{navigator.geolocation&&navigator.geolocation.getCurrentPosition(n=>{let{latitude:r,longitude:i}=n.coords;if(r===t.latitude&&i===t.longitude)return;let a=new FormData;a.append(`latitude`,r),a.append(`longitude`,i),R.post(e,a).catch(e=>console.error(`[grand] position update failed`,e))})}),Z(`inDomComponents`,({components:e})=>{e.forEach(({name:e,template:t,props:n})=>{ek(e,{template:t,props:(n||[]).reduce((e,t)=>(e[t]=null,e),{})})})}),Z(`passwordPage`,({route:e,elements:t,submitOnEnter:n,res:r})=>{let i=e=>e?document.getElementById(e):null,a=()=>{let n=i(t.pageIdFieldId),a=i(t.passwordId);n&&a&&R.post(e,Zk({id:n.value,password:a.value})).then(e=>{let n=i(t.errorId);if(!e.data.Authenticated){n&&(n.innerText=e.data.Error);return}let r=i(t.pageId),a=r?.querySelector(t.titleSelector);if(a&&(a.innerHTML=e.data.Title,!a.innerText.trim())){let e=i(t.titleId);e&&(e.style.display=`none`)}let o=r?.querySelector(`.page-body`);o&&(o.innerHTML=e.data.Body);let s=i(t.promptId);s&&(s.style.display=`none`),r&&(r.style.display=`block`)}).catch(e=>$(e,r.warning))};Jk(()=>{let e=i(t.pageId);e&&(e.style.display=`none`)}),t.buttonId&&Yk(`click`,`#`+t.buttonId,a),n&&Yk(`keydown`,`#`+t.passwordId,(e,t)=>{t.key===`Enter`&&a()})});function rA(e){let t=e.dataset.bundleProduct,n=document.getElementById(`product-details-form`);if(n)return R.post(e.dataset.attributeRoute,new FormData(n),{params:{product:t}}).then(e=>{let n=document.querySelector(`.price-value-`+t);n&&e.data.price&&(n.innerText=e.data.price)}).catch(e=>console.error(`[grand] bundle attribute change failed`,e))}Yk(`change`,`[data-bundle-product] [id^="product_attribute_"]`,e=>rA(e.closest(`[data-bundle-product]`))),Yk(`click`,`[data-bundle-product] [id^="product_attribute_"]`,e=>rA(e.closest(`[data-bundle-product]`))),Z(`productAttributesBundle`,({componentName:e,templateId:t,containerId:n,attributes:r})=>{ek(e,{template:t,data:()=>({productAttributes:r}),mounted(){let e=document.getElementById(n);e&&rA(e)}})});var iA={main:e=>`
+
`};function xk(e){e.component(`b-form-rating`,vk),e.component(`countdown`,yk),e.component(`vue-gallery-slideshow`,bk)}function Sk(e,t,n){if(!e)return null;let r=n||document,i=typeof CSS<`u`&&CSS.escape?CSS.escape(e):e;return r.querySelector(`[name="${i}"]`)?.getAttribute(`data-val-`+t)||null}function Ck(e,t,n){let r=(window.grandValidationMessages||{})[e],i=r&&r!==`validation.`+e?r:t;return n===void 0?i:String(i).replace(`{0}`,n)}var wk={required:(e,t,n,r)=>Sk(e,`required`,r)||n||Ck(`required`,`This field is required.`),email:(e,t,n,r)=>Sk(e,`email`,r)||Ck(`email`,`This field must be a valid email.`),confirmed:(e,t,n,r)=>Sk(e,`equalto`,r)||Ck(`confirmed`,`The confirmation does not match.`),min:(e,t,n,r)=>Sk(e,`min`,r)||Ck(`minlength`,`This field should be at least {0} characters.`,t),max:(e,t,n,r)=>Sk(e,`max`,r)||Ck(`maxlength`,`This field should be at most {0} characters.`,t),exact_length:(e,t,n)=>n||Ck(`exactlength`,`Select at least {0} option.`,t)},Tk=e=>e===``||e==null,Ek=e=>Tk(e)||e===!1||Array.isArray(e)&&e.length===0,Dk={required(e,t){let n=t&&typeof t==`object`&&`allowFalse`in t?t.allowFalse:void 0;return n===!1||n===`false`?e===!0:!Tk(e)},email(e){return Tk(e)?!0:/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e)},min(e,t){if(Tk(e))return!0;let n=Array.isArray(t)?t[0]:t;return String(e).length>=parseInt(n)},max(e,t){if(Tk(e))return!0;let n=Array.isArray(t)?t[0]:t;return String(e).length<=parseInt(n)},confirmed(e,t,n){let r=Array.isArray(t)?t[0]:t;typeof r==`string`&&r.startsWith(`@`)&&(r=r.substring(1));let i=n.observer?n.observer.findProvider(r):null;return!i||e===i.getValue()},exact_length(e,t){if(Tk(e))return!1;let n=Array.isArray(t)?t[0]:t,r=parseInt(n,10),i=Number.isNaN(r)?1:r;return(e.length===void 0?String(e).length:e.length)>=i}};function Ok(e){return e?typeof e==`string`?e.split(`|`).filter(Boolean).map(e=>{let t=e.indexOf(`:`);return t===-1?{name:e,params:null}:{name:e.substring(0,t),params:e.substring(t+1).split(`,`)}}):Object.entries(e).filter(e=>e[1]!==!1).map(([e,t])=>({name:e,params:t===!0?null:t})):[]}var kk={name:`ValidationProvider`,inject:{observer:{from:`veeObserver`,default:null}},props:{tag:{type:String,default:`div`},rules:{type:[String,Object],default:null},name:{type:String,default:null},vid:{type:String,default:null},mode:{type:String,default:null}},data(){return{errors:[],state:null}},computed:{classes(){return this.state===null?``:this.state?`is-valid`:`is-invalid`},fieldId(){return this.vid||this.name}},created(){this.observer&&this.observer.register(this)},beforeUnmount(){this.observer&&this.observer.unregister(this)},mounted(){this._onEvent=()=>this.validate(),this._onFocusOut=()=>{this.state===null&&Ek(this.getValue())||this.validate()};let e=this.control();e?.tagName!==`SELECT`&&e?.type!==`checkbox`&&e?.type!==`radio`&&this.$el.addEventListener(`input`,this._onEvent),this.$el.addEventListener(`change`,this._onEvent),this.$el.addEventListener(`focusout`,this._onFocusOut)},unmounted(){this.$el&&this._onEvent&&(this.$el.removeEventListener(`input`,this._onEvent),this.$el.removeEventListener(`change`,this._onEvent),this.$el.removeEventListener(`focusout`,this._onFocusOut))},methods:{control(){return this.$el?this.$el.querySelector(`input, select, textarea`):null},getValue(){let e=this.control();if(e){if(e.type===`checkbox`){if(!e.hasAttribute(`value`))return e.checked;let t=this.$el.querySelectorAll(`input[type=checkbox]`);return Array.from(t).filter(e=>e.checked).map(e=>e.value)}if(e.type===`radio`){let e=this.$el.querySelectorAll(`input[type=radio]`);for(let t of e)if(t.checked)return t.value}else return e.value}},fieldName(){let e=this.control();return this.name||(e?e.getAttribute(`name`):null)||this.vid},validate(){let e=this.getValue(),t=[],n=Ok(this.rules),r=n.map(e=>Array.isArray(e.params)?e.params[1]:null).find(Boolean)||null;for(let i of n){let n=Dk[i.name];if(n&&!n(e,i.params,this)){let e=wk[i.name],n=Array.isArray(i.params)?i.params[0]:i.params,a=i.params&&i.params[1]||r;t.push(e?e(this.fieldName(),n,a,this.$el):Ck(`invalid`,`Invalid value.`))}}this.errors=t,this.state=t.length===0;let i=this.control();return i&&(i.classList.toggle(`is-invalid`,t.length>0),i.classList.toggle(`is-valid`,t.length===0&&this.state!==null)),Promise.resolve(t.length===0)},reset(){this.errors=[],this.state=null;let e=this.control();e&&e.classList.remove(`is-invalid`,`is-valid`)}},render(){let e=this.$slots.default?this.$slots.default({errors:this.errors,classes:this.classes,valid:this.state}):[];return Nx(this.tag,null,e)}},Ak={name:`ValidationObserver`,props:{tag:{type:String,default:`div`}},provide(){return{veeObserver:this}},data(){return{providers:[]}},computed:{errors(){let e={};return this.providers.forEach(t=>{e[t.fieldId||t.fieldName()]=t.errors}),e},invalid(){return this.providers.some(e=>e.state===!1)}},methods:{register(e){this.providers.push(e)},unregister(e){let t=this.providers.indexOf(e);t>-1&&this.providers.splice(t,1)},findProvider(e){return this.providers.find(t=>t.vid===e||t.name===e)||null},validate(){return Promise.all(this.providers.map(e=>e.validate())).then(e=>e.every(Boolean))},handleSubmit(e){return this.validate().then(t=>{t&&typeof e==`function`&&e()})},reset(){this.providers.forEach(e=>e.reset())}},render(){let e=this.$slots.default?this.$slots.default({handleSubmit:this.handleSubmit,validate:this.validate,reset:this.reset,errors:this.errors,invalid:this.invalid}):[];return Nx(this.tag,null,e)}};function jk(e){e.component(`validation-provider`,kk),e.component(`validation-observer`,Ak)}var Mk=null;function Nk(){return Mk||(Mk=document.createElement(`div`),Mk.className=`toast-container position-fixed top-0 end-0 p-3`,Mk.style.zIndex=`1090`,document.body.appendChild(Mk)),Mk}var Pk={toast(e,t={}){let n=t.variant||`info`,r=document.createElement(`div`);r.className=`toast show align-items-center border-`+n,r.setAttribute(`role`,`alert`);let i=document.createElement(`div`);i.className=`toast-header text-bg-`+n;let a=document.createElement(`strong`);a.className=`me-auto`,a.innerText=t.title||``;let o=document.createElement(`button`);o.type=`button`,o.className=`btn-close btn-close-white ms-2`,o.addEventListener(`click`,()=>r.remove()),i.appendChild(a),i.appendChild(o),r.appendChild(i);let s=document.createElement(`div`);if(s.className=`toast-body`,t.href){let n=document.createElement(`a`);n.href=t.href,n.innerText=e,s.appendChild(n)}else s.innerText=e;r.appendChild(s),Nk().appendChild(r);let c=t.autoHideDelay||5e3;t.noAutoHide||setTimeout(()=>r.remove(),c)}},Fk={};function Z(e,t){Fk[e]=t}function Ik(e){let t=e.textContent.trim();if(!t)return{};try{return JSON.parse(t)}catch(t){return console.error(`[grand] view "${e.dataset.grandVm}" has an unparseable payload`,t),null}}var Lk=`script[type="application/json"][data-grand-vm]`;function Rk(e,t=[]){return e.querySelectorAll(Lk).forEach(e=>t.push(e)),e.querySelectorAll(`template`).forEach(e=>Rk(e.content,t)),t}function zk(e=document){Rk(e).forEach(e=>{if(e.dataset.grandVmReady)return;let t=e.dataset.grandVm,n=Fk[t];if(!n){console.error(`[grand] no view-model registered for "${t}"`);return}let r=Ik(e);r!==null&&(e.dataset.grandVmReady=`1`,n(r,e))})}function Bk(e){let t=document.querySelector(`#ModalQuickView.show`);return t?t.querySelector(`#product-details-form`):e?document.querySelector(e):null}function Vk(e){document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,e):e()}Vk(function(){let e=document.querySelector(`input[name=__RequestVerificationToken]`);if(!e)return;let t=e.value;R.defaults.headers.common[`X-CSRF-TOKEN`]=t});function Hk(e,t,n){n===void 0&&(n=0),e.length>0&&e[n](function(){n++,n===e.length?t():Hk(e,t,n)})}function Uk(){var e=document.createEvent(`Event`);e.initEvent(`DOMContentLoaded`,!0,!0),document.dispatchEvent(e)}function Wk(e,t){var n=document.createElement(`script`);n.type=`text/javascript`,e.src?(n.onload=t,n.onerror=t,n.src=e.src):n.textContent=e.innerText,document.body.appendChild(n),e.parentNode.removeChild(e),e.src||t()}var Gk=[`application/javascript`,`application/ecmascript`,`application/x-ecmascript`,`application/x-javascript`,`text/ecmascript`,`text/javascript`,`text/javascript1.0`,`text/javascript1.1`,`text/javascript1.2`,`text/javascript1.3`,`text/javascript1.4`,`text/javascript1.5`,`text/jscript`,`text/livescript`,`text/x-ecmascript`,`text/x-javascript`];function Kk(e){var t=e.querySelectorAll(`script`),n=[],r;[].forEach.call(t,function(e){r=e.getAttribute(`type`),r&&Gk.indexOf(r)===-1||n.push(function(t){Wk(e,t)})}),Hk(n,Uk)}function qk(e){e.stopPropagation()}(function(){function e(e,t){return t||=document,t.querySelectorAll(e)}function t(e,t){for(var n in Object.keys(e))t(e[n])}function n(){var t=e(`ul`,this)[0];t&&!t.classList.contains(`-visible`)&&t.classList.add(`-visible`)}function r(){var e=this.parentElement;e&&e.classList.contains(`-visible`)&&setTimeout(function(){e.classList.remove(`-visible`)},300)}window.addEventListener(`load`,function(){t(e(`.Menu li.-hasSubmenu`),function(e){e.showMenu=n,e.hideMenu=r}),t(e(`.Menu > li.-hasSubmenu`),function(e){e.addEventListener(`click`,n)}),t(e(`.Menu li .back`),function(e){e.addEventListener(`click`,r)}),t(e(`.Menu > li.-hasSubmenu li.-hasSubmenu`),function(e){e.addEventListener(`click`,n)})})})();var Q={availableDates:[],availableDatesFrom:[],availableDatesTo:[],currentMonth:-1,currentYear:-1,currentMonthFrom:-1,currentYearFrom:-1,currentMonthTo:-1,currentYearTo:-1,_parameter:``,noReservationsMessage:``,productId:``,ajaxUrl:``,ajaxUrl2:``,startDate:``,startDateMonth:``,startDateYear:``,init:function(e,t,n,r,i,a,o){this.noReservationsMessage=r,this.ajaxUrl=i,this.ajaxUrl2=o,this.productId=a,this.startDate=e,this.startDateMonth=n,this.startDateYear=t,document.getElementById(`reservationDatepicker`)!=null&&this.fillAvailableDates(t,n,Q._parameter,!1),document.getElementById(`reservationDatepickerFrom`)!=null&&this.fillAvailableDatesFrom(t,n),document.getElementById(`reservationDatepickerTo`)!=null&&this.fillAvailableDatesTo(t,n);var s=new Date(this.startDate),c=new af.default({field:document.getElementById(`reservationDatepicker`),onSelect:this.onDatePickerDateChange,disableDayFn:this.daysToMark,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${(`0`+(e.getMonth()+1)).slice(-2)}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=t[0],r=parseInt(t[1],10),i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();document.getElementById(`hoursDiv`)!=null&&(document.getElementById(`hoursDiv`).innerHTML=``),Q.fillAvailableDates(t,n,Q._parameter,!1),Q.onDatePickerDateChange()},firstDay:1,defaultDate:s});new af.default({field:document.getElementById(`reservationDatepickerFrom`),onSelect:this.onDatePickerSelect,disableDayFn:this.daysToMarkFrom,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${(`0`+(e.getMonth()+1)).slice(-2)}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=parseInt(t[0],10),r=parseInt(t[1],10),i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();Q.fillAvailableDatesFrom(t,n)},firstDay:1,defaultDate:s}),new af.default({field:document.getElementById(`reservationDatepickerTo`),onSelect:this.onDatePickerSelect,disableDayFn:this.daysToMarkTo,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${(`0`+(e.getMonth()+1)).slice(-2)}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=parseInt(t[0],10),r=parseInt(t[1],10),i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();Q.fillAvailableDatesTo(t,n)},firstDay:1,defaultDate:s}),this.onDatePickerDateChange(),document.getElementById(`parameterDropdown`)!=null&&document.querySelector(`#parameterDropdown`).addEventListener(`change`,function(){Q.fillAvailableDates(Q.currentYear,Q.currentMonth,this.value),c.clear(),document.getElementById(`hoursDiv`)!=null&&(document.getElementById(`hoursDiv`).innerHTML=Q.noReservationsMessage)})},reload:function(e,t,n){this.startDate=e,this.startDateMonth=n,this.startDateYear=t,this.fillAvailableDates(t,n,Q._parameter,!1),new af.default({field:document.getElementById(`reservationDatepicker`),onSelect:this.onDatePickerDateChange,disableDayFn:this.daysToMark,format:`MM/DD/YYYY`,toString:function(e){let t=(`0`+e.getDate()).slice(-2);return`${e.getMonth()+1}/${t}/${e.getFullYear()}`},parse:function(e){let t=e.split(`/`),n=parseInt(t[0],10),r=parseInt(t[1],10)-1,i=parseInt(t[2],10);return new Date(i,r,n)},onDraw:function(e){var t=e.calendars[0].year.toString(),n=(e.calendars[0].month+1).toString();document.getElementById(`hoursDiv`)!=null&&(document.getElementById(`hoursDiv`).innerHTML=``),Q.fillAvailableDates(t,n,Q._parameter,!1)},firstDay:1,defaultDate:this.startDate}),this.onDatePickerDateChange()},daysToMark:function(e){for(let a=0;a`}}if(Q.availableDates.length==0){var f=document.createElement(`label`);f.innerHTML=Q.noReservationsMessage,document.querySelector(`#hoursDiv`).appendChild(f)}}},fillAvailableDates:function(e,t,n){var r={productId:Q.productId,month:t,year:e,parameter:n};R({url:Q.ajaxUrl,method:`post`,params:r,headers:{Accept:`application/json`,"Content-Type":`application/json`}}).then(r=>{Q.currentMonth=t,Q.currentYear=e,Q.availableDates=r.data,Q._parameter=n}).catch(function(e){alert(e)})},fillAvailableDatesFrom:function(e,t){var n={productId:Q.productId,month:t,year:e,parameter:null};R({url:Q.ajaxUrl,method:`post`,params:n,headers:{Accept:`application/json`,"Content-Type":`application/json`}}).then(n=>(Q.currentMonthFrom=t,Q.currentYearFrom=e,Q.availableDatesFrom=Q.availableDatesFrom.concat(n.data),!0)).catch(function(e){alert(e)})},fillAvailableDatesTo:function(e,t){var n={productId:Q.productId,month:t,year:e,parameter:null};R({url:Q.ajaxUrl,method:`post`,params:n,headers:{Accept:`application/json`,"Content-Type":`application/json`}}).then(n=>{Q.currentMonthTo=t,Q.currentYearTo=e,Q.availableDatesTo=Q.availableDatesTo.concat(n.data)}).catch(function(e){alert(e)})},onDatePickerSelect:function(){var e=Bk(`#product-details-form-`+Q.productId);if(e){var t=new FormData(e);R({url:Q.ajaxUrl2,method:`post`,data:t}).then(e=>{var t=function(e,t){var n=document.querySelector(e);n&&(n.innerText=t)};e.data.sku&&t(`#sku-`+Q.productId,e.data.sku),e.data.mpn&&t(`#mpn-`+Q.productId,e.data.mpn),e.data.gtin&&t(`#gtin-`+Q.productId,e.data.gtin),e.data.price&&(document.querySelector(`.price-value-`+Q.productId+` .actual-price`)?t(`.price-value-`+Q.productId+` .actual-price`,e.data.price):t(`.price-value-`+Q.productId,e.data.price))})}}};window.runScripts=Kk,window.StopPropagation=qk,window.Reservation=Q;var Jk={loadWaiting:!1,sidebarcartselector:`.sidebar-cart`,quickview_product:function(e){R({url:e,method:`get`}).then(function(e){Jk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){Jk.resetLoadWaiting()})},addproducttocart_catalog:function(e,t,n){if(t.toLowerCase()==`true`){var r=document.querySelector(`#addtocart_`+n+`_EnteredQuantity`).value;e.indexOf(`forceredirection`)==-1?e+=`?quantity=`+r:e+=`&quantity=`+r}this.loadWaiting==0&&(this.setLoadWaiting(!0),R({url:e,method:`post`}).then(function(e){Jk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){window.vmwishlist!==void 0&&window.vmwishlist.getModel(),window.vmorder!==void 0&&window.vmorder.getModel(),Jk.resetLoadWaiting()}))},addproducttocart_details:function(e,t){if(this.loadWaiting==0){this.setLoadWaiting(!0);var n=Bk(t);n?R({url:e,data:new FormData(n),method:`post`}).then(function(e){Jk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){window.vmwishlist!==void 0&&window.vmwishlist.getModel(),window.vmorder!==void 0&&window.vmorder.getModel(),Jk.resetLoadWaiting()}):this.setLoadWaiting(!1)}},updateitem:function(e,t){var n,r=Bk(t);if(r){var i=new FormData(r);n=window.vmwishlist===void 0?window.vmorder:window.vmwishlist,R({url:e,data:i,method:`post`}).then(function(e){e.data.success?window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalQuickView`)).hide():n.displayWarning(e.data.message,`danger`)}).catch(function(e){e.axiosFailure}).then(function(){n.getModel(),Jk.resetLoadWaiting()})}},addbid:function(e,t){if(this.loadWaiting==0){this.setLoadWaiting(!0);var n=document.querySelector(t);R({url:e,data:new FormData(n),method:`post`}).then(function(e){Jk.success_process(e)}).catch(function(e){e.axiosFailure}).then(function(){Jk.resetLoadWaiting()})}},addproducttocomparelist:function(e,t,n){if(this.loadWaiting==0){this.setLoadWaiting(!0);var r=this.getCookie(`Grand.CompareProduct`);return r===``?r=e:r.includes(e)||(r=r+`|`+e),this.setCookie(`Grand.CompareProduct`,r),window.vm.updateCompareProductsQty(),window.vm.displayBarNotification(t,n,`success`,3500),this.resetLoadWaiting(),!1}},setLoadWaiting:function(e){this.loadWaiting=e},success_process:function(e){if(e.data.updatetopwishlistsectionhtml&&document.querySelector(`.wishlist-qty`)&&(document.querySelector(`.wishlist-qty`).innerHTML=e.data.updatetopwishlistsectionhtml),e.data.sidebarshoppingcartmodel){var t=e.data.sidebarshoppingcartmodel;window.vm.flycart=t,window.vm.flycartitems=t.Items,window.vm.flycartindicator=t.TotalProducts}if(e.data.updatetopcartsectionhtml&&(window.vm.flycartindicator=e.data.updatetopcartsectionhtml),e.data.product&&e.data.success==1&&(window.vm.PopupQuickViewVueModal=e.data.model,Object.assign(window.vm.PopupQuickViewVueModal,{RelatedProducts:[]}),window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalQuickView`)).show(),e.data.model.ProductType==20)){var n=new Date(e.data.model.StartDate).toLocaleDateString(`en-US`),r=new Date(e.data.model.StartDate).getFullYear(),i=new Date(e.data.model.StartDate).getUTCMonth()+1;Object.assign(window.vm.PopupQuickViewVueModal,{ReservationFullDate:n}),Object.assign(window.vm.PopupQuickViewVueModal,{ReservationYear:r}),Object.assign(window.vm.PopupQuickViewVueModal,{ReservationMonth:i})}if(e.data.message){if(e.data.success==1){if(window.vm.PopupAddToCartVueModal=e.data.model,window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalQuickView`)).hide(),window.bootstrap.Modal.getOrCreateInstance(document.getElementById(`ModalAddToCart`)).show(),e.data.refreshreservation==1){var a=document.querySelector(`#parameterDropdown`),o=a?a.value:``;window.Reservation.fillAvailableDates(window.Reservation.currentYear,window.Reservation.currentMonth,o,!0)}}else window.vm.displayBarNotification(e.data.message,``,`error`,3500);return!1}return e.data.redirect?(location.href=e.data.redirect,!0):!1},resetLoadWaiting:function(){Jk.setLoadWaiting(!1)},axiosFailure:function(){alert(`Failed to add the product. Please refresh the page and try one more time.`)},setCookie:function(e,t,n){let r=new Date;r.setTime(r.getTime()+n*24*60*60*1e3);let i=`expires=`+r.toUTCString();document.cookie=e+`=`+t+`;`+i+`;path=/`},getCookie:function(e){let t=e+`=`,n=document.cookie.split(`;`);for(let e=0;et.$nextTick(e))}function Xk(e,t,n){document.addEventListener(e,e=>{let r=e.target.closest?.(t);r&&n(r,e)})}Z(`advancedSearch`,({elements:e})=>{let t=()=>{let t=document.getElementById(e.checkboxId),n=document.getElementById(e.blockId);t&&n&&(n.style.display=t.checked?`flex`:`none`)};Xk(`click`,`#`+e.checkboxId,t),Yk(t)});function Zk(){return document.querySelector(`input[name=__RequestVerificationToken]`)?.value??``}function Qk(e={}){let t=new FormData;return Object.entries(e).forEach(([e,n])=>t.append(e,n)),t.append(`__RequestVerificationToken`,Zk()),t}function $k(e,t,n=`danger`){e&&Pk.toast(e,{title:t,variant:n,autoHideDelay:5e3,appendToast:!0})}function $(e,t,n){$k(e?.response?.data?.message||n||e?.message||String(e),t)}function eA(e){navigator.permissions&&navigator.permissions.query({name:`microphone`}).then(t=>{e(t.state!==`denied`),t.onchange=()=>e(t.state!==`denied`)}).catch(()=>{})}function tA(e,t){let n=(e,n)=>(e||[]).forEach(e=>{let r=document.querySelector(`#${t}_attribute_label_${e}`),i=document.querySelector(`#${t}_attribute_input_${e}`);r&&(r.style.display=n),i&&(i.style.display=n)});n(e.enabledattributeids,`block`),n(e.disabledattributeids,`none`)}function nA(e,t,n=document){let r=n.querySelector(`#download-message, .download-message`);r&&(r.style.display=`block`,r.classList.toggle(`alert-info`,t),r.classList.toggle(`alert-danger`,!t),r.innerText=e)}function rA(e,t=document){let n=t.querySelector(`.download-file`);n&&(n.style.display=`inline-block`,n.setAttribute(`href`,e))}Z(`checkoutAttributes`,({routes:e})=>{let t=()=>{let t=document.querySelector(`#shopping-cart-form`);if(t)return R.post(e.change,new FormData(t)).then(({data:e})=>{let t=window.vmorder;t&&(t.totals=e.model,t.cart.CheckoutAttributeInfo=e.checkoutattributeinfo||``),tA(e,`checkout`)}).catch(e=>console.error(`[grand] checkout attribute change failed`,e))};window.checkoutAttributeChange=t,window.uploadFile=e=>{let n=new FormData;n.append(`file`,e.files[0]);let r=e.getAttribute(`attribute`);R.post(e.getAttribute(`data-url`),n).then(({data:n})=>{if(n.success){let t=window.vmorder?.cart.CheckoutAttributes.find(e=>e.Id===r);t&&(t.DefaultValue=n.downloadGuid),e.setAttribute(`qq-button-id`,n.downloadGuid);let i=document.querySelector(`.hidden-upload-input`);i&&(i.value=n.downloadGuid),rA(n.downloadUrl)}return nA(n.message,n.success),t()}).catch(e=>console.error(`[grand] checkout attribute upload failed`,e))},Yk(t)}),Z(`contactAttributes`,({routes:e})=>{let t=()=>{let t=document.querySelector(`#contactus-form`);if(t)return R.post(e.change,new FormData(t)).then(({data:e})=>tA(e,`contact`)).catch(e=>console.error(`[grand] contact attribute change failed`,e))};window.contactAttributeChange=t,window.uploadFile=e=>{let n=new FormData;n.append(`file`,e.files[0]);let r=e.closest(`.contact-attribute-upload`)||document;R.post(e.getAttribute(`data-url`),n).then(({data:e})=>{if(e.success){let t=r.querySelector(`.hidden-upload-input`);t&&(t.value=e.downloadGuid),rA(e.downloadUrl,r)}return nA(e.message,e.success,r),t()}).catch(e=>console.error(`[grand] contact attribute upload failed`,e))},Xk(`change`,`.contact-attributes [id^="contact_attribute_"]`,t),Xk(`click`,`.contact-attributes [id^="contact_attribute_"]`,t),Xk(`click`,`.contact-attributes [id^="color-squares-"] li`,e=>{document.querySelector(`.contact-attributes .selected-value`)?.classList.remove(`selected-value`),e.classList.add(`selected-value`)}),Yk(t)}),Z(`barNotifications`,({messages:e})=>{ik(t=>{e.forEach(({text:e,variant:n})=>t.displayBarNotification(e,``,n,3500))})}),Z(`checkoutSteps`,({routes:e})=>{Yk(()=>{let t=window.vmorder;t?.vCartUrl?(t.vCartUrl.init(e.cartSummary,e.cartTotal),t.vShipping.init(`#co-shipping-form`,e.saveShipping),t.vBilling.init(`#co-billing-form`,e.saveBilling),t.vShippingMethod.init(`#co-shipping-method-form`,e.saveShippingMethod),t.vPaymentMethod.init(`#co-payment-method-form`,e.savePaymentMethod),t.vPaymentInfo.init(`#co-payment-info-form`,e.savePaymentInfo),t.vConfirmOrder.init(e.confirmOrder,e.completed)):console.error(`[grand] checkout controllers missing - public.checkout.js did not load`)})}),Z(`jsResources`,({res:e,routes:t,validation:n})=>{window.grandRes=Object.assign(window.grandRes||{},e),window.grandRoutes=Object.assign(window.grandRoutes||{},t),window.grandValidationMessages=Object.assign(window.grandValidationMessages||{},n)}),Z(`confirmDelete`,({route:e,field:t,selector:n,res:r})=>{document.addEventListener(`click`,i=>{let a=i.target.closest(n);a&&window.confirm(r.areYouSure)&&R.post(e,Qk({[t]:a.dataset.deleteId})).then(e=>{e.data.success===!1?$k(e.data.error||e.data.message,r.warning):window.location=e.data.redirect}).catch(e=>$(e,r.warning))})}),Z(`confirmPost`,({route:e,elements:t,res:n})=>{Xk(`click`,`#`+t.buttonId,r=>{window.confirm(n.areYouSure)&&R.post(e).then(()=>{r.style.display=`none`;let e=document.getElementById(t.checkId);e&&(e.checked=!0)}).catch(e=>$(e,n.warning))})}),Z(`estimateShipping`,({routes:e,elements:t,res:n})=>{Xk(`click`,`#`+t.buttonId,()=>{let t=document.getElementById(`shopping-cart-form`);t&&R.post(e.estimate,new FormData(t)).then(e=>{let t=document.querySelector(`.estimate-shipping-result`);t&&(t.innerHTML=e.data),window.checkoutAttributeChange?.()}).catch(()=>$k(n.estimateFailed,n.warning))}),Xk(`change`,`#`+t.countrySelectId,r=>{let i=document.getElementById(t.stateSelectId),a=document.getElementById(t.progressId);a&&(a.style.display=`block`),R.get(e.getStates,{params:{countryId:r.value,addSelectStateItem:!1}}).then(e=>{i&&(i.innerHTML=``,e.data.forEach(e=>{let t=document.createElement(`option`);t.value=e.id,t.innerHTML=e.name,i.appendChild(t)})),a&&(a.style.display=`none`),window.checkoutAttributeChange?.()}).catch(e=>{a&&(a.style.display=`none`),$(e,n.warning)})})}),Z(`cookieBar`,({route:e,elements:t,res:n})=>{Xk(`click`,`#`+t.barId+` [data-accept]`,r=>{R.post(e,null,{params:{accept:r.dataset.accept}}).then(()=>{let e=document.getElementById(t.barId);e&&(e.style.display=`none`)}).catch(e=>$(e,n.warning))})}),Z(`geolocation`,({route:e,known:t})=>{navigator.geolocation&&navigator.geolocation.getCurrentPosition(n=>{let{latitude:r,longitude:i}=n.coords;if(r===t.latitude&&i===t.longitude)return;let a=new FormData;a.append(`latitude`,r),a.append(`longitude`,i),R.post(e,a).catch(e=>console.error(`[grand] position update failed`,e))})}),Z(`inDomComponents`,({components:e})=>{e.forEach(({name:e,template:t,props:n})=>{ek(e,{template:t,props:(n||[]).reduce((e,t)=>(e[t]=null,e),{})})})}),Z(`passwordPage`,({route:e,elements:t,submitOnEnter:n,res:r})=>{let i=e=>e?document.getElementById(e):null,a=()=>{let n=i(t.pageIdFieldId),a=i(t.passwordId);n&&a&&R.post(e,Qk({id:n.value,password:a.value})).then(e=>{let n=i(t.errorId);if(!e.data.Authenticated){n&&(n.innerText=e.data.Error);return}let r=i(t.pageId),a=r?.querySelector(t.titleSelector);if(a&&(a.innerHTML=e.data.Title,!a.innerText.trim())){let e=i(t.titleId);e&&(e.style.display=`none`)}let o=r?.querySelector(`.page-body`);o&&(o.innerHTML=e.data.Body);let s=i(t.promptId);s&&(s.style.display=`none`),r&&(r.style.display=`block`)}).catch(e=>$(e,r.warning))};Yk(()=>{let e=i(t.pageId);e&&(e.style.display=`none`)}),t.buttonId&&Xk(`click`,`#`+t.buttonId,a),n&&Xk(`keydown`,`#`+t.passwordId,(e,t)=>{t.key===`Enter`&&a()})});function iA(e){let t=e.dataset.bundleProduct,n=document.getElementById(`product-details-form`);if(n)return R.post(e.dataset.attributeRoute,new FormData(n),{params:{product:t}}).then(e=>{let n=document.querySelector(`.price-value-`+t);n&&e.data.price&&(n.innerText=e.data.price)}).catch(e=>console.error(`[grand] bundle attribute change failed`,e))}Xk(`change`,`[data-bundle-product] [id^="product_attribute_"]`,e=>iA(e.closest(`[data-bundle-product]`))),Xk(`click`,`[data-bundle-product] [id^="product_attribute_"]`,e=>iA(e.closest(`[data-bundle-product]`))),Z(`productAttributesBundle`,({componentName:e,templateId:t,containerId:n,attributes:r})=>{ek(e,{template:t,data:()=>({productAttributes:r}),mounted(){let e=document.getElementById(n);e&&iA(e)}})});var aA={main:e=>`
@@ -113,4 +113,4 @@ var BO=Object.create(null);function VO(e,t){if(!W(e)){if(e.nodeType)e=e.innerHTM
-
`};Z(`productGallery`,({componentName:e,variant:t,mainImageId:n,images:r})=>{ek(e,{template:iA[t](n),data:()=>({images:r,index:null}),components:{VueGallerySlideshow:bk}})}),Z(`galleryThumbnails`,({mainImageId:e})=>{Yk(`click`,`[data-gallery-thumb]`,t=>{let n=document.getElementById(e);n&&n.setAttribute(`src`,t.getAttribute(`data-src`))})}),Z(`imageZoom`,()=>{Yk(`click`,`[data-zoom-image]`,e=>{let t=e.parentElement?.querySelector(`img`);t&&window.mediumZoom&&window.mediumZoom(t,{background:`#232323`,margin:30}).open()})}),Z(`pushNotifications`,({firebase:e,route:t})=>{Jk(()=>{window.PushNotifications&&(window.PushNotifications.init(e.publicApiKey,e.senderId,e.projectId,e.authDomain,e.storageBucket,e.databaseUrl,t,e.appId),window.PushNotifications.process())})});function aA(e,t){let n=parseInt(e.value,10);e.value=Math.max(1,(isNaN(n)?0:n)+t)}Z(`quantityStepper`,()=>{Yk(`click`,`[data-quantity-step]`,e=>{let t=document.getElementById(e.dataset.quantityTarget);t&&aA(t,Number(e.dataset.quantityStep))})}),Z(`quickViewModal`,({elements:e})=>{Yk(`shown.bs.modal`,`#`+e.modalId,()=>{let e=window.vm;e&&(e.initReservationQV?.(),e.QuickViewShown?.())})}),Z(`reservationInfo`,({productId:e,start:t,routes:n,res:r})=>{Jk(()=>{window.Reservation?.init(t.date,t.year,t.month,r.noAvailableReservations,n.datesForMonth,e,n.attributeChange)})}),Z(`searchModal`,({elements:e})=>{Yk(`shown.bs.modal`,`#`+e.modalId,()=>{let e=tk()?.$refs?.searchBoxInput;e&&e.focus()})});var oA=991;Z(`twoColumnsSidebar`,({elements:e})=>{Jk(()=>{let t=document.querySelector(e.sidebarSelector),n=document.getElementById(e.desktopHostId);if(!t||!n)return;let r=document.getElementById(e.toggleId),i=Array.prototype.some.call(t.children,t=>t.id!==e.categoryNavigationId);r&&!i&&(r.classList.remove(`d-block`),r.classList.add(`d-none`));let a=()=>{let r=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)<=oA?document.querySelector(e.mobileHostSelector):n;r&&t.parentElement!==r&&r.appendChild(t)};a(),window.addEventListener(`resize`,a)})}),Z(`enableWhenChecked`,({elements:e})=>{Yk(`change`,`#`+e.checkboxId,t=>{let n=document.getElementById(e.targetId);n&&n.classList.toggle(`disabled`,!t.checked)})}),Z(`checkAll`,({elements:e})=>{Yk(`click`,`#`+e.checkboxId,t=>{document.querySelectorAll(e.rowSelector).forEach(e=>{e.checked=t.checked})})});var sA=`username-available-status alert alert-success d-flex justify-content-center mt-3 mb-0`,cA=`username-not-available-status alert alert-danger d-flex justify-content-center mt-3 mb-0`,lA=`username-not-available-status text-danger d-flex order-2 mt-3`;Z(`usernameAvailability`,({route:e,elements:t,res:n})=>{Yk(`click`,`#`+t.buttonId,r=>{let i=document.getElementById(t.usernameId),a=document.getElementById(t.resultId),o=document.getElementById(t.progressId);if(!i||!a)return;if(a.innerText=``,!i.value){a.setAttribute(`class`,lA),a.innerText=n.enterUsername;return}o&&(o.style.display=`block`),r.setAttribute(`disabled`,`disabled`);let s=()=>{r.removeAttribute(`disabled`),o&&(o.style.display=`none`)};R.post(e,Zk({Username:i.value})).then(e=>{s(),a.setAttribute(`class`,e.data.Available?sA:cA),a.innerText=e.data.Text}).catch(e=>{s(),$(e,n.warning)})})});function uA(e,t){if(!t)return;let n=document.querySelector(e);n&&(n.innerText=t)}function dA(e,t){e&&e.forEach(e=>{let n=document.querySelector(`#product_attribute_label_`+e),r=document.querySelector(`#product_attribute_input_`+e);n&&(n.style.display=t),r&&(r.style.display=t)})}function fA(e,t){let n=document.getElementById(`stock-availability-schema-`+e);if(!t)n?.remove();else if(n)n.setAttribute(`href`,t);else{let n=document.querySelector(`[data-offer-for="${e}"]`);if(n){let r=document.createElement(`link`);r.id=`stock-availability-schema-`+e,r.setAttribute(`itemprop`,`availability`),r.setAttribute(`href`,t),n.prepend(r)}}let r=document.getElementById(`product-structured-data-`+e);if(r)try{let e=JSON.parse(r.textContent);if(!e.offers)return;t?e.offers.availability=t:delete e.offers.availability,r.textContent=JSON.stringify(e)}catch(e){console.error(`[grand] product structured data could not be updated`,e)}}function pA(e,t,n){if(!t)return;let r=()=>{let n=document.getElementById(`main-product-img-`+e);n&&n.setAttribute(`src`,t)};if(n!==`swiper`||document.querySelector(`.product-grouped`)){r();return}let i=window.vm?.$refs?.swiperTop?.$swiper;i?i.slides[i.activeIndex]?.querySelector(`img`)?.dataset.srcs!==t&&i.slides.forEach((e,n)=>{e.querySelector(`img`)?.dataset.srcs===t&&i.slideTo(n,1e3,!1)}):r()}Z(`productAttributes`,({productId:e,attributes:t,route:n,picture:r,res:i})=>{let a=hk({data:()=>({ProductAttributes:t}),methods:{attrchange(){let t=document.getElementById(`product-details-form-`+e);if(t)return R.post(n,new FormData(t),{params:{product:e}}).then(({data:t})=>{let n=document.querySelector(`.price-value-${e} .actual-price`)||document.querySelector(`.price-value-${e}`);t.price&&n&&(n.innerText=t.price),uA(`#sku-`+e,t.sku),uA(`#mpn-`+e,t.mpn),uA(`#gtin-`+e,t.gtin),uA(`#stock-availability-value-`+e,t.stockAvailability),`availability`in t&&fA(e,t.availability);let i=document.querySelector(`#out-of-stock-subscribe-`+e);i&&typeof t.outOfStockSubscription==`boolean`&&(i.style.display=t.outOfStockSubscription?`block`:`none`),i&&t.buttonTextOutOfStockSubscription&&(i.value=t.buttonTextOutOfStockSubscription),dA(t.enabledattributemappingids,`table-cell`),dA(t.disabledattributemappingids,`none`),setTimeout(()=>pA(e,t.pictureDefaultSizeUrl,r),100)}).catch(e=>$(e,i.warning))}}}),o=`standardProductAttributes_`+e;window[o]=QO(o,a),ik(e=>e.$nextTick(()=>a.attrchange()))}),Z(`warehouseSelector`,({productId:e,route:t,elements:n})=>{Yk(`change`,`#`+n.selectId,()=>{let r=document.getElementById(n.selectId);if(!r)return;let i=new FormData;i.append(`warehouseId`,r.value),i.append(`productId`,e),R.post(t,i).then(t=>{let n=document.getElementById(`stock-availability-value-`+e);n&&t.data.stockAvailability&&(n.innerText=t.data.stockAvailability),`availability`in t.data&&fA(e,t.data.availability),window[`standardProductAttributes_`+e]?.attrchange()}).catch(e=>console.error(`[grand] warehouse change failed`,e))})}),Z(`state`,({name:e,data:t})=>{window[e]=QO(e,hk({data:()=>({...t})}))}),Z(`applyVendor`,({model:e,res:t})=>{window.applyvendor=QO(`applyvendor`,hk({data:()=>({Name:e.Name,Email:e.Email,AcceptPrivacyPolicy:!1})}));let n=document.getElementById(`apply-vendor`),r=document.getElementById(`accept-terms-of-service`);n&&r&&n.addEventListener(`click`,e=>{r.checked||(e.preventDefault(),Qk(t.acceptTermsRequired,t.warning))})});var mA=[`AskQuestionEmail`,`AskQuestionFullName`,`AskQuestionPhone`,`AskQuestionMessage`];Z(`askQuestion`,({data:e,captchaTarget:t,res:n})=>{window.askquestion=QO(`askquestion`,hk({data:()=>({...e}),methods:{async sendContactUsForm(e){let t=tk().$refs;if(!await t.contact.validate())return;let r={};mA.forEach(e=>{r[e]=t[e].value}),r.Id=t.AskQuestionProductId.value;let i=document.querySelector(`[id^='g-recaptcha-response']`);return i&&(r[`g-recaptcha-response-value`]=i.value),R.post(e,Zk(r)).then(e=>{let t=document.querySelector(`.product-standard`);if(!t)return;let n=t.querySelector(`.product-contact-error`),r=t.querySelector(`.product-contact-send`);e.data.success?(t.querySelector(`#contact-us-product`).style.display=`none`,n.style.display=`none`,r.innerHTML=e.data.message,r.style.display=`block`):(n.innerHTML=e.data.message,n.style.display=`block`)}).catch(e=>$(e,n.warning))},getCaptcha(){if(!t)return;let e=document.getElementById(`captcha-box`),n=document.getElementById(t);e&&n&&n.prepend(e)}}}))});var hA=4;function gA(e){let t=Math.max(1,e.PageNumber-hA),n=e.PageNumber+hA((e[n[t]]=e[n[t]]||[]).push(n),e),{}):e||{}}function yA(e,t){if(!t)return;let n=t.PagingFilteringContext;if(!n)return;e.pager=gA(n);let r=n.SpecificationFilter;r&&(r.NotFilteredItems=vA(r.NotFilteredItems,_A),r.AlreadyFilteredItems=vA(r.AlreadyFilteredItems,_A))}Z(`catalog`,({model:e,res:t})=>{window.catalog=QO(`catalog`,hk({data:()=>({Model:[],pager:[],clientRendered:!1}),created(){this.Model=e,yA(this,e)},watch:{Model(e){yA(this,e)}},methods:{loadProducts(e){this.getResponse(e);let t=new URL(e,window.location.origin);t.searchParams.delete(`timestamp`),window.history.replaceState({path:t.href},``,t.href)},setRating(e){let t=new URL(window.location.href);e===``?t.searchParams.delete(`rating`):t.searchParams.set(`rating`,e),t.searchParams.delete(`pagenumber`),this.loadProducts(t.href)},getResponse(e){let n=new URL(e,window.location.origin);return n.searchParams.set(`timestamp`,new Date().getTime()),R.get(n.href,{headers:{Accept:`application/json`}}).then(e=>{this.Model=e.data,yA(this,e.data),this.clientRendered=!0}).catch(e=>{console.error(`[grand] catalog request failed`,e),Qk(t.loadFailed,t.warning)})},goToPage(e){let t=new URL(window.location.href);t.searchParams.set(`pagenumber`,e),this.loadProducts(t.href),this.scrollToSection()},scrollToSection(){let e=document.getElementById(`catalog-products`);e&&window.scrollTo({top:e.offsetTop,left:0,behavior:`smooth`})}}}))}),Z(`catalogModern`,({model:e,res:t})=>{window.catalog=QO(`catalog`,hk({data:()=>({Model:[],pager:[],Count:[]}),created(){this.Model=e,this.refresh(e)},watch:{Model(e){this.refresh(e)}},methods:{refresh(e){e&&(yA(this,e),this.setCount(0))},loadProducts(e){let t=new URL(e,window.location.origin);t.searchParams.delete(`timestamp`),t.searchParams.delete(`pagenumber`),typeof AjaxFilter<`u`?t.searchParams.forEach((e,t)=>{let n=document.querySelector(`#ajaxfilter-form .`+t);n&&(n.value=e),AjaxFilter.setFilter(t)}):this.getResponse(e),window.history.replaceState({path:t.href},``,t.href)},getResponse(e){let n=new URL(e,window.location.origin);return n.searchParams.set(`timestamp`,new Date().getTime()),R.get(n.href,{headers:{Accept:`application/json`,"X-Response-View":`Json`}}).then(e=>{let t=e.data,n=t.PagingFilteringContext.PageNumber;if(n>1&&n!==this.Model.PagingFilteringContext.PageNumber){let e=this.Model.Products;this.Model=t,this.Model.Products=e.concat(t.Products)}else this.Model=t;this.refresh(this.Model),window.scrollpagination&&(window.scrollpagination.stop=!1)}).catch(e=>{console.error(`[grand] catalog request failed`,e),Qk(t.loadFailed,t.warning)})},goToPage(e){let t=new URL(window.location.href);t.searchParams.set(`pagenumber`,e),this.loadProducts(t.href)},setCount(e){let t=e>0?e:1,n=Math.ceil(this.Model.Products.length/t);this.Count={...this.Count,p_numbers:Array.from(Array(n).keys())}}}}))}),Z(`comments`,({name:e,formId:t,comments:n,fields:r})=>{let i={};r.forEach(e=>{i[e]=``}),window[e]=QO(e,hk({data:()=>({Model:n,...i}),methods:{submitComment(){let e=document.getElementById(t);return R.post(e.getAttribute(`action`),new FormData(e),{headers:{Accept:`application/json`}}).then(e=>{let{success:t,message:n,model:i}=e.data;window.vm.displayBarNotification(n,``,t?`success`:`error`,t?3e3:3500),t&&(r.forEach(e=>{this[e]=``}),i&&this.addComment(i))}).catch(e=>console.error(`[grand] comment submit failed`,e))},addComment(e){this.Model.push(e)}}}))}),Z(`compareProducts`,({model:e,specificationAttributes:t,loadRoute:n})=>{window.specificationAttributes=QO(`specificationAttributes`,hk({data:()=>({Model:t})})),ik(t=>{n?t.getCompareList(n):t.compareproducts=e})});function bA(e){let t=document.getElementById(`captcha-box`),n=document.getElementById(e);t&&n&&n.prepend(t)}Z(`contactForm`,({name:e,data:t,formId:n,submitMethod:r,modalId:i,captcha:a,res:o})=>{let s=hk({data:()=>({...t,Message:{Result:null,SuccessfullySent:!1}}),methods:{[r](e){let t=document.getElementById(n);return R.post(e,new FormData(t),{headers:{Accept:`application/json`}}).then(e=>{let{Result:n,SuccessfullySent:r}=e.data;this.Message.Result=n,this.Message.SuccessfullySent=r,r&&(t.style.display=`none`,i&&Ha.getOrCreateInstance(document.getElementById(i)).hide()),Qk(n,``,r?`info`:`danger`)}).catch(e=>$(e,o.warning))},getCaptcha(){a?.tabTarget&&bA(a.tabTarget)}}});if(window[e]=QO(e,s),i&&a?.popupTarget){let e=document.getElementById(i);e&&(e.addEventListener(`shown.bs.modal`,()=>{e.querySelector(`.captcha-box`)||bA(a.popupTarget)}),e.addEventListener(`hide.bs.modal`,()=>{e.querySelector(`.captcha-box`)&&bA(a.restoreTarget)}))}});var xA=new Map,SA=!1;function CA(e,t){e.classList.remove(t?`is-invalid`:`is-valid`),e.classList.add(t?`is-valid`:`is-invalid`)}function wA(e,t){if(!t.value)return;let n=document.getElementById(e.elements.stateSelectId);return R.get(e.routes.getStates,{params:{countryId:t.value,addSelectStateItem:`true`}}).then(t=>{let r=window[e.name];r.AvailableStates=t.data,r.StateProvinceId=t.data[0].id,n&&CA(n,!1)}).catch(t=>$(t,e.res.warning))}function TA(e){let t=document.getElementById(e.checkboxId),n=document.querySelector(e.targetSelector);t&&n&&(n.style.display=t.checked?`block`:`none`)}function EA(){SA||(SA=!0,document.addEventListener(`change`,e=>{let t=e.target.id;if(t)for(let n of xA.values()){if(t===n.elements.countrySelectId)return void wA(n,e.target);if(t===n.elements.stateSelectId)return void CA(e.target,e.target.selectedIndex>0);if(n.newsletterToggle&&t===n.newsletterToggle.checkboxId){TA(n.newsletterToggle);return}}}))}Z(`countryStateForm`,e=>{window[e.name]=QO(e.name,hk({data:()=>({...e.data})})),xA.set(e.name,e),EA(),ik(t=>t.$nextTick(()=>{document.querySelectorAll(`[data-checked='true']`).forEach(e=>{e.checked=!0}),e.newsletterToggle&&TA(e.newsletterToggle)}))}),Z(`globals`,({name:e,data:t})=>{window[e]=t}),Z(`merchandiseReturn`,({pickupDate:e,showPickupDate:t,itemIds:n})=>{let r={};n.forEach(e=>{r[`quantity_`+e]=`0`}),window.merchandisereturns=QO(`merchandisereturns`,hk({data:()=>({...t?{PickupDate:e??``}:{},newAddress:!1,...r,checkboxes:[]}),created(){this.isNewAddress()},methods:{allowed(e,t){let n=window.vm.$refs[t];n&&(e.checked?n.removeAttribute(`disabled`):n.setAttribute(`disabled`,`disabled`))},isNewAddress(){let e=document.getElementById(`pickup-address-select`);this.newAddress=!e||e.value===``}}}))}),Z(`outOfStockSubscription`,({productId:e,routes:t,elements:n,res:r})=>{ik(i=>i.$nextTick(()=>{let i=document.getElementById(n.buttonId);i&&(R.get(t.buttonText).then(e=>{i.value=e.data,i.style.display=`inline-block`}).catch(e=>$(e,r.warning)),i.addEventListener(`click`,()=>{let a=document.getElementById(`product-details-form-`+e);R.post(t.popup,a?new FormData(a):null).then(e=>{document.getElementById(n.contentId).innerHTML=e.data.resource,i.value=e.data.buttontext,Ha.getOrCreateInstance(document.getElementById(n.modalId)).show()}).catch(e=>$(e,r.warning))}))}))}),Z(`reviews`,e=>{let{name:t,modalId:n,methods:r,addReviewKey:i,overviewKey:a,overviewVm:o,helpfulness:s,res:c}=e,l=hk({data:()=>({Model:e.model,rating:null,captcha:null}),methods:{[r.setHelpfulness](e,t,n,r,i){return R.post(e,null,{params:{[s.reviewIdParam]:n,[s.ownerIdParam]:r,washelpful:t}}).then(e=>{document.getElementById(`helpfulness-vote-yes-`+n).innerHTML=e.data.TotalYes,document.getElementById(`helpfulness-vote-no-`+n).innerHTML=e.data.TotalNo,Qk(e.data.Result,i,`info`)}).catch(e=>$(e,c.warning))},[r.addReview](){let e=document.getElementById(n),t=e?.closest(`.tab-pane`);if(t&&!t.classList.contains(`active`)){let e=document.querySelector(`[data-bs-target="#${t.id}"], #${t.id}-tab`);e&&Ks.getOrCreateInstance(e).show()}Ha.getOrCreateInstance(e).show()},modalReviewShown(){let e=document.getElementById(n),t=this.Model[i];t.DisplayCaptcha&&!e.querySelector(`.captcha-box`)&&!t.SuccessfullyAdded&&document.getElementById(`captcha-popup`).prepend(document.getElementById(`captcha-box`)),this.Model={...this.Model,ReviewTitle:``,ReviewText:``}},modalReviewClose(){let e=document.getElementById(n);this.Model[i].DisplayCaptcha&&e.querySelector(`.captcha-box`)&&document.getElementById(`captcha-container`).prepend(document.getElementById(`captcha-box`))},[r.submitReview](){let e=document.getElementById(`addReviewForm`),t=e.getAttribute(`data-title`);return R.post(e.getAttribute(`action`),new FormData(e)).then(e=>{this.Model=e.data;let r=e.data[i].SuccessfullyAdded;r&&Ha.getOrCreateInstance(document.getElementById(n)).hide(),Qk(e.data[i].Result,t,r?`info`:`danger`);let s=e.data[a];s&&window[o]&&(window[o].Model=s)}).catch(e=>$(e,c.warning))}}});window[t]=QO(t,l),document.addEventListener(`shown.bs.modal`,e=>{e.target.id===n&&l.modalReviewShown()}),document.addEventListener(`hide.bs.modal`,e=>{e.target.id===n&&l.modalReviewClose()})}),Z(`scrollPagination`,()=>{let e=hk({data:()=>({stop:!1}),methods:{next(){let e=window.catalog,t=e.Model.PagingFilteringContext.PageNumber,n=e.Count?.p_numbers;if(n&&n.length&&!(n[n.length-1]<=t)){if(typeof AjaxFilter>`u`){let n=new URL(window.location.href);n.searchParams.set(`pagenumber`,t+1),e.loadProducts(n.href)}else document.getElementById(`PageNumber`).value=t,AjaxFilter.setFilter(`pagenumber`)}},pageScroll(){let e=document.getElementById(`catalog-products`);if(!e)return;let t=e.scrollHeight*.3,{PageNumber:n,TotalPages:r}=window.catalog.Model.PagingFilteringContext;window.scrollY>=t&&ne.pageScroll())});var DA=600;function OA(e,t){return e.filter(e=>e.SearchType===t)}Z(`searchBox`,({lang:e,routes:t,res:n})=>{let r=null;window.searchbox=QO(`searchbox`,hk({data:()=>({recording:!1,recognition:null,searchitems:null,focus:!1,text:``,lang:e,placeholder:n.placeholder,micMessage:n.micHold,searchcategories:null,searchbrands:null,searchblog:null,searchproducts:null,allowed:!0}),created(){this.allowCheck()},methods:{formSubmit(){tk().$refs.searchForm.submit()},startRecording(){this.recognition.start()},stopRecording(){this.recognition.stop()},allowCheck(){$k(e=>{this.allowed=e})},autocompleteVue(){let e=tk().$refs.searchBoxInput,n=e.getAttribute(`minlength`);clearTimeout(r),!(e.value.length{let e=document.getElementById(`SearchCategoryId`);R.get(t.autocomplete,{params:{term:this.text,categoryId:e?e.value:``}}).then(e=>{let t=e.data;t&&(this.searchitems=t,this.searchcategories=OA(t,`Category`),this.searchbrands=OA(t,`Brand`),this.searchblog=OA(t,`Blog`),this.searchproducts=OA(t,`Product`))}).catch(e=>console.error(`[grand] autocomplete failed`,e))},DA))},handleSpeech(e,t,r){let i=e.results[e.resultIndex][0].transcript,a=i.toLowerCase().trim();a===n.voiceStop?this.stopRecording():!r.value&&this.recording?this.text=i:a===n.voiceGo?(this.stopRecording(),t.submit()):a===n.voiceReset?this.text=``:this.recording&&(this.text=i)}},watch:{text(){this.autocompleteVue(),this.text===``&&(this.searchitems=null)},recording(){let e=window.SpeechRecognition||window.webkitSpeechRecognition;if(!e){this.allowed=!1;return}if(!this.recording){this.stopRecording(),this.placeholder=n.placeholder,this.micMessage=n.micHold;return}let t=tk().$refs;this.recognition=new e,this.recognition.continuous=!0,this.recognition.lang=this.lang,t.searchBoxInput.focus(),this.startRecording(),this.placeholder=n.micPlaceholder,this.micMessage=n.micPlaceholder,this.recognition.addEventListener(`result`,e=>this.handleSpeech(e,t.searchForm,t.searchBoxInput))}}}))}),Z(`shoppingCart`,({model:e,routes:t,res:n})=>{let r=e=>Qk(e,n.warning);window.vmorder=QO(`vmorder`,hk({data:()=>({cart:e,totals:null,checkoutAsGuest:!1,MinOrderTotalWarning:null,TermsOfServiceOnOrderConfirmPage:null,ConfirmWarnings:null,terms:!1,acceptTerms:!1}),created(){this.updateTotals(),document.body.classList.add(`cart-view`)},watch:{terms(){this.terms===!0&&(this.acceptTerms=!1)}},methods:{updateCart(){return R.get(t.summary).then(e=>{this.cart=e.data}).catch(e=>$(e,n.warning))},updateTotals(){return R.get(t.total).then(e=>{this.totals=e.data}).catch(e=>$(e,n.warning))},termsCheck(e){this.cart.MinOrderSubtotalWarning??(this.terms?(this.checkout(e),this.acceptTerms=!1):this.acceptTerms=!0)},checkout(e){if(e){window.location=t.checkout;return}if(!this.cart.ShowCheckoutAsGuestButton&&this.cart.IsGuest){window.location=t.loginReturningToCart;return}let n=document.getElementById(`shopping-cart-form`);n.setAttribute(`action`,t.startCheckout),n.submit()},ApplyGiftVoucher(e){return R.post(e,Zk({giftvouchercouponcode:document.getElementById(`giftvouchercouponcode`).value})).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},removeGiftVoucher(e){return R.get(e).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},getModel(){return R.get(t.shoppingCart,{params:{timestamp:new Date().getTime()}}).then(e=>(this.cart=e.data,window.vm.flycartindicator=this.cart.Items.reduce((e,t)=>e+t.Quantity,0),this.updateTotals())).catch(e=>$(e,n.warning))},updateQuantity(e,i){return R.post(t.updateQuantity,Zk({shoppingcartId:i,ShoppingCartType:1,quantity:document.getElementById(e+i).value})).then(e=>(e.data.success?(this.cart=e.data.model,window.vm.flycartindicator=e.data.totalproducts):r(e.data.warnings),this.updateTotals())).catch(e=>$(e,n.warning))},updateCartType(e,r){return R.post(t.changeTypeCartItem,Zk({id:e,status:r})).then(e=>(this.cart=e.data.model,window.vm.updateSidebarShoppingCart(t.sidebarShoppingCart),this.updateTotals())).catch(e=>$(e,n.warning))},updateOnCart(e){return R.get(`${t.getItemCart}/${e}`).then(t=>{t.data.success?(window.vm.PopupQuickViewVueModal=t.data.model,window.vm.UpdatedShoppingCartItemId=e,Ha.getOrCreateInstance(document.getElementById(`ModalQuickView`)).show()):r(t.data.message)}).catch(e=>$(e,n.warning))},cartClick(e){let t=e.target.closest(`.deleteshoppingcartitem`);t&&t.dataset.deleteUrl&&this.deleteitem(t.dataset.deleteUrl)},deleteitem(e){return R.post(e).then(e=>{let t=window.vm;if(t.flycartindicator=e.data.totalproducts,document.querySelector(`.sidebar-cart`)){let n=e.data.sidebarshoppingcartmodel;t.flycart=n,t.flycartitems=n.Items,t.flycartindicator=n.TotalProducts}return this.cart=e.data.model,this.updateTotals()}).catch(e=>$(e,n.warning))},ApplyDiscountCode(e){return R.post(e,Zk({discountcouponcode:document.getElementById(`discountcouponcode`).value})).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},RemoveDiscountId(e){return R.get(e).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},displayWarning(e){r(e)}}}))}),Z(`vendorReviewOverview`,({model:e})=>{window.vendorreviewsoverview=QO(`vendorreviewsoverview`,hk({data:()=>({Model:e}),computed:{rating(){return this.Model&&this.Model.TotalReviews?this.Model.RatingSum/this.Model.TotalReviews:0}}}))});var kA=/[`~!#$%^&*()_|+\-=?;:'",.<>{}[\]\\/]/gi;function AA(e){let t=new SpeechSynthesisUtterance;t.text=e,window.speechSynthesis.speak(t)}Z(`voiceNavigation`,({lang:e,commands:t,res:n})=>{window.voicenavigator=QO(`voicenavigator`,hk({data:()=>({recording:!1,recognition:null,lang:e,commands:t,transcript:``,variant:`info`,micMessage:n.micHold,voiceMessage:n.tryAgain,allowed:!0}),created(){this.allowCheck()},methods:{startRecording(){this.recognition.start()},stopRecording(){this.recognition.stop()},allowCheck(){$k(e=>{this.allowed=e})},handleSpeech(e){if(!this.recording||!e.results[0].isFinal)return;let t=e.results[e.resultIndex][0].transcript;this.transcript=t;let n=t.replace(kA,``).toLowerCase(),r=this.commands.find(e=>e.triggers.some(e=>n.includes(e)));r?(this.stopRecording(),this.variant=`success`,setTimeout(()=>{window.location.href=r.url},300)):setTimeout(()=>AA(this.voiceMessage),300)}},watch:{recording(){let e=window.SpeechRecognition||window.webkitSpeechRecognition;e?this.recording?(this.recognition=new e,this.recognition.continuous=!0,this.recognition.lang=this.lang,this.recognition.interimResults=!1,this.recognition.maxAlternatives=1,this.startRecording(),this.micMessage=n.micPlaceholder,this.recognition.addEventListener(`result`,e=>this.handleSpeech(e))):(this.stopRecording(),this.transcript=``,this.variant=`info`,this.micMessage=n.micHold):this.allowed=!1}}}))}),Z(`wishlist`,({model:e,routes:t,res:n})=>{window.vmwishlist=QO(`vmwishlist`,hk({data:()=>({Model:e,PopupUpdateVueModal:null}),methods:{deleteFromWishlist(e){return R.get(`${t.deleteItem}/${e}`).then(e=>{if(e.data.success)return this.getModel();this.displayWarning(e.data.message,`danger`)}).catch(e=>$(e,n.warning))},addToCartFromWishlist(e){return R.post(t.addToCart+e).then(e=>{if(!e.data.success)this.displayWarning(e.data.message,`danger`);else return window.vm.updateSidebarShoppingCart(t.sidebarShoppingCart),this.displayWarning(n.addedToCart,`info`,n.success),this.getModel()}).catch(e=>$(e,n.warning))},getItemCart(e){return R.get(`${t.getItemCart}/${e}`).then(t=>{t.data.success?(window.vm.PopupQuickViewVueModal=t.data.model,window.vm.UpdatedShoppingCartItemId=e,Ha.getOrCreateInstance(document.getElementById(`ModalQuickView`)).show()):this.displayWarning(t.data.message,`danger`)}).catch(e=>$(e,n.warning))},updateQuantity(e,r){return R.post(t.updateQuantity,Zk({shoppingcartId:r,ShoppingCartType:2,quantity:document.getElementById(e+r).value})).then(e=>{if(e.data.success)return this.getModel();this.displayWarning(e.data.warnings,`danger`)}).catch(e=>$(e,n.warning))},getModel(){return R.get(t.wishlist,{params:{timestamp:new Date().getTime()},headers:{Accept:`application/json`,"X-Response-View":`Json`}}).then(e=>{this.Model=e.data;let t=document.querySelector(`.wishlist-qty`);t&&(t.innerHTML=this.Model.Items.reduce((e,t)=>e+t.Quantity,0))}).catch(e=>$(e,n.warning))},displayWarning(e,t,r){Qk(e,r??n.warning,t)}}}))});function jA(e){Object.defineProperty(e.config.globalProperties,"vm",{get:()=>tk(),configurable:!0}),Object.assign(e.config.globalProperties,{window,document,location,localStorage,bootstrap:It,hideTooltip:NA})}$O(e=>{xk(e),Ak(e),jA(e),e.config.globalProperties.$bvToast=Nk,e.config.errorHandler=(e,t,n)=>console.error(e,n)});function MA(){document.body.__tooltipDelegate||(document.body.__tooltipDelegate=new qo(document.body,{selector:`[data-bs-toggle="tooltip"]`}))}document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,MA):MA();function NA(e){e&&qo.getInstance(e)?.hide()}window.hideTooltip=NA,rk(()=>Rk()),document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>Rk()):Rk(),window.grandInitViews=Rk,window.grandMountIslands=dk,window.bootstrap=It,window.Vue=_k,window.axios=R,window.Pikaday=af.default,window.VueGallerySlideshow=bk,window.$bvToast=Nk,window.vee_getMessage=Sk})(); \ No newline at end of file + `};Z(`productGallery`,({componentName:e,variant:t,mainImageId:n,images:r})=>{ek(e,{template:aA[t](n),data:()=>({images:r,index:null}),components:{VueGallerySlideshow:bk}})}),Z(`galleryThumbnails`,({mainImageId:e})=>{Xk(`click`,`[data-gallery-thumb]`,t=>{let n=document.getElementById(e);n&&n.setAttribute(`src`,t.getAttribute(`data-src`))})}),Z(`imageZoom`,()=>{Xk(`click`,`[data-zoom-image]`,e=>{let t=e.parentElement?.querySelector(`img`);t&&window.mediumZoom&&window.mediumZoom(t,{background:`#232323`,margin:30}).open()})}),Z(`pushNotifications`,({firebase:e,route:t})=>{Yk(()=>{window.PushNotifications&&(window.PushNotifications.init(e.publicApiKey,e.senderId,e.projectId,e.authDomain,e.storageBucket,e.databaseUrl,t,e.appId),window.PushNotifications.process())})});function oA(e,t){let n=parseInt(e.value,10);e.value=Math.max(1,(isNaN(n)?0:n)+t)}Z(`quantityStepper`,()=>{Xk(`click`,`[data-quantity-step]`,e=>{let t=document.getElementById(e.dataset.quantityTarget);t&&oA(t,Number(e.dataset.quantityStep))})}),Z(`quickViewModal`,({elements:e})=>{Xk(`shown.bs.modal`,`#`+e.modalId,()=>{let e=window.vm;e&&(e.initReservationQV?.(),e.QuickViewShown?.())})}),Z(`reservationInfo`,({productId:e,start:t,routes:n,res:r})=>{Yk(()=>{window.Reservation?.init(t.date,t.year,t.month,r.noAvailableReservations,n.datesForMonth,e,n.attributeChange)})}),Z(`searchModal`,({elements:e})=>{Xk(`shown.bs.modal`,`#`+e.modalId,()=>{let e=tk()?.$refs?.searchBoxInput;e&&e.focus()})});var sA=991;Z(`twoColumnsSidebar`,({elements:e})=>{Yk(()=>{let t=document.querySelector(e.sidebarSelector),n=document.getElementById(e.desktopHostId);if(!t||!n)return;let r=document.getElementById(e.toggleId),i=Array.prototype.some.call(t.children,t=>t.id!==e.categoryNavigationId);r&&!i&&(r.classList.remove(`d-block`),r.classList.add(`d-none`));let a=()=>{let r=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)<=sA?document.querySelector(e.mobileHostSelector):n;r&&t.parentElement!==r&&r.appendChild(t)};a(),window.addEventListener(`resize`,a)})}),Z(`enableWhenChecked`,({elements:e})=>{Xk(`change`,`#`+e.checkboxId,t=>{let n=document.getElementById(e.targetId);n&&n.classList.toggle(`disabled`,!t.checked)})}),Z(`checkAll`,({elements:e})=>{Xk(`click`,`#`+e.checkboxId,t=>{document.querySelectorAll(e.rowSelector).forEach(e=>{e.checked=t.checked})})});var cA=`username-available-status alert alert-success d-flex justify-content-center mt-3 mb-0`,lA=`username-not-available-status alert alert-danger d-flex justify-content-center mt-3 mb-0`,uA=`username-not-available-status text-danger d-flex order-2 mt-3`;Z(`usernameAvailability`,({route:e,elements:t,res:n})=>{Xk(`click`,`#`+t.buttonId,r=>{let i=document.getElementById(t.usernameId),a=document.getElementById(t.resultId),o=document.getElementById(t.progressId);if(!i||!a)return;if(a.innerText=``,!i.value){a.setAttribute(`class`,uA),a.innerText=n.enterUsername;return}o&&(o.style.display=`block`),r.setAttribute(`disabled`,`disabled`);let s=()=>{r.removeAttribute(`disabled`),o&&(o.style.display=`none`)};R.post(e,Qk({Username:i.value})).then(e=>{s(),a.setAttribute(`class`,e.data.Available?cA:lA),a.innerText=e.data.Text}).catch(e=>{s(),$(e,n.warning)})})});function dA(e,t){if(!t)return;let n=document.querySelector(e);n&&(n.innerText=t)}function fA(e,t){e&&e.forEach(e=>{let n=document.querySelector(`#product_attribute_label_`+e),r=document.querySelector(`#product_attribute_input_`+e);n&&(n.style.display=t),r&&(r.style.display=t)})}function pA(e,t){let n=document.getElementById(`stock-availability-schema-`+e);if(!t)n?.remove();else if(n)n.setAttribute(`href`,t);else{let n=document.querySelector(`[data-offer-for="${e}"]`);if(n){let r=document.createElement(`link`);r.id=`stock-availability-schema-`+e,r.setAttribute(`itemprop`,`availability`),r.setAttribute(`href`,t),n.prepend(r)}}let r=document.getElementById(`product-structured-data-`+e);if(r)try{let e=JSON.parse(r.textContent);if(!e.offers)return;t?e.offers.availability=t:delete e.offers.availability,r.textContent=JSON.stringify(e)}catch(e){console.error(`[grand] product structured data could not be updated`,e)}}function mA(e,t,n){if(!t)return;let r=()=>{let n=document.getElementById(`main-product-img-`+e);n&&n.setAttribute(`src`,t)};if(n!==`swiper`||document.querySelector(`.product-grouped`)){r();return}let i=window.vm?.$refs?.swiperTop?.$swiper;i?i.slides[i.activeIndex]?.querySelector(`img`)?.dataset.srcs!==t&&i.slides.forEach((e,n)=>{e.querySelector(`img`)?.dataset.srcs===t&&i.slideTo(n,1e3,!1)}):r()}Z(`productAttributes`,({productId:e,attributes:t,route:n,picture:r,res:i})=>{let a=hk({data:()=>({ProductAttributes:t}),methods:{attrchange(){let t=document.getElementById(`product-details-form-`+e);if(t)return R.post(n,new FormData(t),{params:{product:e}}).then(({data:t})=>{let n=document.querySelector(`.price-value-${e} .actual-price`)||document.querySelector(`.price-value-${e}`);t.price&&n&&(n.innerText=t.price),dA(`#sku-`+e,t.sku),dA(`#mpn-`+e,t.mpn),dA(`#gtin-`+e,t.gtin),dA(`#stock-availability-value-`+e,t.stockAvailability),`availability`in t&&pA(e,t.availability);let i=document.querySelector(`#out-of-stock-subscribe-`+e);i&&typeof t.outOfStockSubscription==`boolean`&&(i.style.display=t.outOfStockSubscription?`block`:`none`),i&&t.buttonTextOutOfStockSubscription&&(i.value=t.buttonTextOutOfStockSubscription),fA(t.enabledattributemappingids,`table-cell`),fA(t.disabledattributemappingids,`none`),setTimeout(()=>mA(e,t.pictureDefaultSizeUrl,r),100)}).catch(e=>$(e,i.warning))}}}),o=`standardProductAttributes_`+e;window[o]=QO(o,a),ik(e=>e.$nextTick(()=>a.attrchange()))}),Z(`warehouseSelector`,({productId:e,route:t,elements:n})=>{Xk(`change`,`#`+n.selectId,()=>{let r=document.getElementById(n.selectId);if(!r)return;let i=new FormData;i.append(`warehouseId`,r.value),i.append(`productId`,e),R.post(t,i).then(t=>{let n=document.getElementById(`stock-availability-value-`+e);n&&t.data.stockAvailability&&(n.innerText=t.data.stockAvailability),`availability`in t.data&&pA(e,t.data.availability),window[`standardProductAttributes_`+e]?.attrchange()}).catch(e=>console.error(`[grand] warehouse change failed`,e))})}),Z(`state`,({name:e,data:t})=>{window[e]=QO(e,hk({data:()=>({...t})}))}),Z(`applyVendor`,({model:e,res:t})=>{window.applyvendor=QO(`applyvendor`,hk({data:()=>({Name:e.Name,Email:e.Email,AcceptPrivacyPolicy:!1})}));let n=document.getElementById(`apply-vendor`),r=document.getElementById(`accept-terms-of-service`);n&&r&&n.addEventListener(`click`,e=>{r.checked||(e.preventDefault(),$k(t.acceptTermsRequired,t.warning))})});var hA=[`AskQuestionEmail`,`AskQuestionFullName`,`AskQuestionPhone`,`AskQuestionMessage`];Z(`askQuestion`,({data:e,captchaTarget:t,res:n})=>{window.askquestion=QO(`askquestion`,hk({data:()=>({...e}),methods:{async sendContactUsForm(e){let t=tk().$refs;if(!await t.contact.validate())return;let r={};hA.forEach(e=>{r[e]=t[e].value}),r.Id=t.AskQuestionProductId.value;let i=document.querySelector(`[id^='g-recaptcha-response']`);return i&&(r[`g-recaptcha-response-value`]=i.value),R.post(e,Qk(r)).then(e=>{let t=document.querySelector(`.product-standard`);if(!t)return;let n=t.querySelector(`.product-contact-error`),r=t.querySelector(`.product-contact-send`);e.data.success?(t.querySelector(`#contact-us-product`).style.display=`none`,n.style.display=`none`,r.innerHTML=e.data.message,r.style.display=`block`):(n.innerHTML=e.data.message,n.style.display=`block`)}).catch(e=>$(e,n.warning))},getCaptcha(){if(!t)return;let e=document.getElementById(`captcha-box`),n=document.getElementById(t);e&&n&&n.prepend(e)}}}))});var gA=4;function _A(e){let t=Math.max(1,e.PageNumber-gA),n=e.PageNumber+gA((e[n[t]]=e[n[t]]||[]).push(n),e),{}):e||{}}function bA(e,t){if(!t)return;let n=t.PagingFilteringContext;if(!n)return;e.pager=_A(n);let r=n.SpecificationFilter;r&&(r.NotFilteredItems=yA(r.NotFilteredItems,vA),r.AlreadyFilteredItems=yA(r.AlreadyFilteredItems,vA))}Z(`catalog`,({model:e,res:t})=>{window.catalog=QO(`catalog`,hk({data:()=>({Model:[],pager:[],clientRendered:!1}),created(){this.Model=e,bA(this,e)},watch:{Model(e){bA(this,e)}},methods:{loadProducts(e){this.getResponse(e);let t=new URL(e,window.location.origin);t.searchParams.delete(`timestamp`),window.history.replaceState({path:t.href},``,t.href)},setRating(e){let t=new URL(window.location.href);e===``?t.searchParams.delete(`rating`):t.searchParams.set(`rating`,e),t.searchParams.delete(`pagenumber`),this.loadProducts(t.href)},getResponse(e){let n=new URL(e,window.location.origin);return n.searchParams.set(`timestamp`,new Date().getTime()),R.get(n.href,{headers:{Accept:`application/json`}}).then(e=>{this.Model=e.data,bA(this,e.data),this.clientRendered=!0}).catch(e=>{console.error(`[grand] catalog request failed`,e),$k(t.loadFailed,t.warning)})},goToPage(e){let t=new URL(window.location.href);t.searchParams.set(`pagenumber`,e),this.loadProducts(t.href),this.scrollToSection()},scrollToSection(){let e=document.getElementById(`catalog-products`);e&&window.scrollTo({top:e.offsetTop,left:0,behavior:`smooth`})}}}))}),Z(`catalogModern`,({model:e,res:t})=>{window.catalog=QO(`catalog`,hk({data:()=>({Model:[],pager:[],Count:[]}),created(){this.Model=e,this.refresh(e)},watch:{Model(e){this.refresh(e)}},methods:{refresh(e){e&&(bA(this,e),this.setCount(0))},loadProducts(e){let t=new URL(e,window.location.origin);t.searchParams.delete(`timestamp`),t.searchParams.delete(`pagenumber`),typeof AjaxFilter<`u`?t.searchParams.forEach((e,t)=>{let n=document.querySelector(`#ajaxfilter-form .`+t);n&&(n.value=e),AjaxFilter.setFilter(t)}):this.getResponse(e),window.history.replaceState({path:t.href},``,t.href)},getResponse(e){let n=new URL(e,window.location.origin);return n.searchParams.set(`timestamp`,new Date().getTime()),R.get(n.href,{headers:{Accept:`application/json`,"X-Response-View":`Json`}}).then(e=>{let t=e.data,n=t.PagingFilteringContext.PageNumber;if(n>1&&n!==this.Model.PagingFilteringContext.PageNumber){let e=this.Model.Products;this.Model=t,this.Model.Products=e.concat(t.Products)}else this.Model=t;this.refresh(this.Model),window.scrollpagination&&(window.scrollpagination.stop=!1)}).catch(e=>{console.error(`[grand] catalog request failed`,e),$k(t.loadFailed,t.warning)})},goToPage(e){let t=new URL(window.location.href);t.searchParams.set(`pagenumber`,e),this.loadProducts(t.href)},setCount(e){let t=e>0?e:1,n=Math.ceil(this.Model.Products.length/t);this.Count={...this.Count,p_numbers:Array.from(Array(n).keys())}}}}))}),Z(`comments`,({name:e,formId:t,comments:n,fields:r})=>{let i={};r.forEach(e=>{i[e]=``}),window[e]=QO(e,hk({data:()=>({Model:n,...i}),methods:{submitComment(){let e=document.getElementById(t);return R.post(e.getAttribute(`action`),new FormData(e),{headers:{Accept:`application/json`}}).then(e=>{let{success:t,message:n,model:i}=e.data;window.vm.displayBarNotification(n,``,t?`success`:`error`,t?3e3:3500),t&&(r.forEach(e=>{this[e]=``}),i&&this.addComment(i))}).catch(e=>console.error(`[grand] comment submit failed`,e))},addComment(e){this.Model.push(e)}}}))}),Z(`compareProducts`,({model:e,specificationAttributes:t,loadRoute:n})=>{window.specificationAttributes=QO(`specificationAttributes`,hk({data:()=>({Model:t})})),ik(t=>{n?t.getCompareList(n):t.compareproducts=e})});function xA(e){let t=document.getElementById(`captcha-box`),n=document.getElementById(e);t&&n&&n.prepend(t)}Z(`contactForm`,({name:e,data:t,formId:n,submitMethod:r,modalId:i,captcha:a,res:o})=>{let s=hk({data:()=>({...t,Message:{Result:null,SuccessfullySent:!1}}),methods:{[r](e){let t=document.getElementById(n);return R.post(e,new FormData(t),{headers:{Accept:`application/json`}}).then(e=>{let{Result:n,SuccessfullySent:r}=e.data;this.Message.Result=n,this.Message.SuccessfullySent=r,r&&(t.style.display=`none`,i&&Ha.getOrCreateInstance(document.getElementById(i)).hide()),$k(n,``,r?`info`:`danger`)}).catch(e=>$(e,o.warning))},getCaptcha(){a?.tabTarget&&xA(a.tabTarget)}}});if(window[e]=QO(e,s),i&&a?.popupTarget){let e=document.getElementById(i);e&&(e.addEventListener(`shown.bs.modal`,()=>{e.querySelector(`.captcha-box`)||xA(a.popupTarget)}),e.addEventListener(`hide.bs.modal`,()=>{e.querySelector(`.captcha-box`)&&xA(a.restoreTarget)}))}});var SA=new Map,CA=!1;function wA(e,t){e.classList.remove(t?`is-invalid`:`is-valid`),e.classList.add(t?`is-valid`:`is-invalid`)}function TA(e,t){if(!t.value)return;let n=document.getElementById(e.elements.stateSelectId);return R.get(e.routes.getStates,{params:{countryId:t.value,addSelectStateItem:`true`}}).then(t=>{let r=window[e.name];r.AvailableStates=t.data,r.StateProvinceId=t.data[0].id,n&&wA(n,!1)}).catch(t=>$(t,e.res.warning))}function EA(e){let t=document.getElementById(e.checkboxId),n=document.querySelector(e.targetSelector);t&&n&&(n.style.display=t.checked?`block`:`none`)}function DA(){CA||(CA=!0,document.addEventListener(`change`,e=>{let t=e.target.id;if(t)for(let n of SA.values()){if(t===n.elements.countrySelectId)return void TA(n,e.target);if(t===n.elements.stateSelectId)return void wA(e.target,e.target.selectedIndex>0);if(n.newsletterToggle&&t===n.newsletterToggle.checkboxId){EA(n.newsletterToggle);return}}}))}Z(`countryStateForm`,e=>{window[e.name]=QO(e.name,hk({data:()=>({...e.data})})),SA.set(e.name,e),DA(),ik(t=>t.$nextTick(()=>{document.querySelectorAll(`[data-checked='true']`).forEach(e=>{e.checked=!0}),e.newsletterToggle&&EA(e.newsletterToggle)}))}),Z(`globals`,({name:e,data:t})=>{window[e]=t}),Z(`merchandiseReturn`,({pickupDate:e,showPickupDate:t,itemIds:n})=>{let r={};n.forEach(e=>{r[`quantity_`+e]=`0`}),window.merchandisereturns=QO(`merchandisereturns`,hk({data:()=>({...t?{PickupDate:e??``}:{},newAddress:!1,...r,checkboxes:[]}),created(){this.isNewAddress()},methods:{allowed(e,t){let n=window.vm.$refs[t];n&&(e.checked?n.removeAttribute(`disabled`):n.setAttribute(`disabled`,`disabled`))},isNewAddress(){let e=document.getElementById(`pickup-address-select`);this.newAddress=!e||e.value===``}}}))}),Z(`outOfStockSubscription`,({productId:e,routes:t,elements:n,res:r})=>{ik(i=>i.$nextTick(()=>{let i=document.getElementById(n.buttonId);i&&(R.get(t.buttonText).then(e=>{i.value=e.data,i.style.display=`inline-block`}).catch(e=>$(e,r.warning)),i.addEventListener(`click`,()=>{let a=document.getElementById(`product-details-form-`+e);R.post(t.popup,a?new FormData(a):null).then(e=>{document.getElementById(n.contentId).innerHTML=e.data.resource,i.value=e.data.buttontext,Ha.getOrCreateInstance(document.getElementById(n.modalId)).show()}).catch(e=>$(e,r.warning))}))}))}),Z(`reviews`,e=>{let{name:t,modalId:n,methods:r,addReviewKey:i,overviewKey:a,overviewVm:o,helpfulness:s,res:c}=e,l=hk({data:()=>({Model:e.model,rating:null,captcha:null}),methods:{[r.setHelpfulness](e,t,n,r,i){return R.post(e,null,{params:{[s.reviewIdParam]:n,[s.ownerIdParam]:r,washelpful:t}}).then(e=>{document.getElementById(`helpfulness-vote-yes-`+n).innerHTML=e.data.TotalYes,document.getElementById(`helpfulness-vote-no-`+n).innerHTML=e.data.TotalNo,$k(e.data.Result,i,`info`)}).catch(e=>$(e,c.warning))},[r.addReview](){let e=document.getElementById(n),t=e?.closest(`.tab-pane`);if(t&&!t.classList.contains(`active`)){let e=document.querySelector(`[data-bs-target="#${t.id}"], #${t.id}-tab`);e&&Ks.getOrCreateInstance(e).show()}Ha.getOrCreateInstance(e).show()},modalReviewShown(){let e=document.getElementById(n),t=this.Model[i];t.DisplayCaptcha&&!e.querySelector(`.captcha-box`)&&!t.SuccessfullyAdded&&document.getElementById(`captcha-popup`).prepend(document.getElementById(`captcha-box`)),this.Model={...this.Model,ReviewTitle:``,ReviewText:``}},modalReviewClose(){let e=document.getElementById(n);this.Model[i].DisplayCaptcha&&e.querySelector(`.captcha-box`)&&document.getElementById(`captcha-container`).prepend(document.getElementById(`captcha-box`))},[r.submitReview](){let e=document.getElementById(`addReviewForm`),t=e.getAttribute(`data-title`);return R.post(e.getAttribute(`action`),new FormData(e)).then(e=>{this.Model=e.data;let r=e.data[i].SuccessfullyAdded;r&&Ha.getOrCreateInstance(document.getElementById(n)).hide(),$k(e.data[i].Result,t,r?`info`:`danger`);let s=e.data[a];s&&window[o]&&(window[o].Model=s)}).catch(e=>$(e,c.warning))}}});window[t]=QO(t,l),document.addEventListener(`shown.bs.modal`,e=>{e.target.id===n&&l.modalReviewShown()}),document.addEventListener(`hide.bs.modal`,e=>{e.target.id===n&&l.modalReviewClose()})}),Z(`scrollPagination`,()=>{let e=hk({data:()=>({stop:!1}),methods:{next(){let e=window.catalog,t=e.Model.PagingFilteringContext.PageNumber,n=e.Count?.p_numbers;if(n&&n.length&&!(n[n.length-1]<=t)){if(typeof AjaxFilter>`u`){let n=new URL(window.location.href);n.searchParams.set(`pagenumber`,t+1),e.loadProducts(n.href)}else document.getElementById(`PageNumber`).value=t,AjaxFilter.setFilter(`pagenumber`)}},pageScroll(){let e=document.getElementById(`catalog-products`);if(!e)return;let t=e.scrollHeight*.3,{PageNumber:n,TotalPages:r}=window.catalog.Model.PagingFilteringContext;window.scrollY>=t&&ne.pageScroll())});var OA=600;function kA(e,t){return e.filter(e=>e.SearchType===t)}Z(`searchBox`,({lang:e,routes:t,res:n})=>{let r=null;window.searchbox=QO(`searchbox`,hk({data:()=>({recording:!1,recognition:null,searchitems:null,focus:!1,text:``,lang:e,placeholder:n.placeholder,micMessage:n.micHold,searchcategories:null,searchbrands:null,searchblog:null,searchproducts:null,allowed:!0}),created(){this.allowCheck()},methods:{formSubmit(){tk().$refs.searchForm.submit()},startRecording(){this.recognition.start()},stopRecording(){this.recognition.stop()},allowCheck(){eA(e=>{this.allowed=e})},autocompleteVue(){let e=tk().$refs.searchBoxInput,n=e.getAttribute(`minlength`);clearTimeout(r),!(e.value.length{let e=document.getElementById(`SearchCategoryId`);R.get(t.autocomplete,{params:{term:this.text,categoryId:e?e.value:``}}).then(e=>{let t=e.data;t&&(this.searchitems=t,this.searchcategories=kA(t,`Category`),this.searchbrands=kA(t,`Brand`),this.searchblog=kA(t,`Blog`),this.searchproducts=kA(t,`Product`))}).catch(e=>console.error(`[grand] autocomplete failed`,e))},OA))},handleSpeech(e,t,r){let i=e.results[e.resultIndex][0].transcript,a=i.toLowerCase().trim();a===n.voiceStop?this.stopRecording():!r.value&&this.recording?this.text=i:a===n.voiceGo?(this.stopRecording(),t.submit()):a===n.voiceReset?this.text=``:this.recording&&(this.text=i)}},watch:{text(){this.autocompleteVue(),this.text===``&&(this.searchitems=null)},recording(){let e=window.SpeechRecognition||window.webkitSpeechRecognition;if(!e){this.allowed=!1;return}if(!this.recording){this.stopRecording(),this.placeholder=n.placeholder,this.micMessage=n.micHold;return}let t=tk().$refs;this.recognition=new e,this.recognition.continuous=!0,this.recognition.lang=this.lang,t.searchBoxInput.focus(),this.startRecording(),this.placeholder=n.micPlaceholder,this.micMessage=n.micPlaceholder,this.recognition.addEventListener(`result`,e=>this.handleSpeech(e,t.searchForm,t.searchBoxInput))}}}))}),Z(`shoppingCart`,({model:e,routes:t,res:n})=>{let r=e=>$k(e,n.warning);window.vmorder=QO(`vmorder`,hk({data:()=>({cart:e,totals:null,checkoutAsGuest:!1,MinOrderTotalWarning:null,TermsOfServiceOnOrderConfirmPage:null,ConfirmWarnings:null,terms:!1,acceptTerms:!1}),created(){this.updateTotals(),document.body.classList.add(`cart-view`)},watch:{terms(){this.terms===!0&&(this.acceptTerms=!1)}},methods:{updateCart(){return R.get(t.summary).then(e=>{this.cart=e.data}).catch(e=>$(e,n.warning))},updateTotals(){return R.get(t.total).then(e=>{this.totals=e.data}).catch(e=>$(e,n.warning))},termsCheck(e){this.cart.MinOrderSubtotalWarning??(this.terms?(this.checkout(e),this.acceptTerms=!1):this.acceptTerms=!0)},checkout(e){if(e){window.location=t.checkout;return}if(!this.cart.ShowCheckoutAsGuestButton&&this.cart.IsGuest){window.location=t.loginReturningToCart;return}let n=document.getElementById(`shopping-cart-form`);n.setAttribute(`action`,t.startCheckout),n.submit()},ApplyGiftVoucher(e){return R.post(e,Qk({giftvouchercouponcode:document.getElementById(`giftvouchercouponcode`).value})).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},removeGiftVoucher(e){return R.get(e).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},getModel(){return R.get(t.shoppingCart,{params:{timestamp:new Date().getTime()}}).then(e=>(this.cart=e.data,window.vm.flycartindicator=this.cart.Items.reduce((e,t)=>e+t.Quantity,0),this.updateTotals())).catch(e=>$(e,n.warning))},updateQuantity(e,i){return R.post(t.updateQuantity,Qk({shoppingcartId:i,ShoppingCartType:1,quantity:document.getElementById(e+i).value})).then(e=>(e.data.success?(this.cart=e.data.model,window.vm.flycartindicator=e.data.totalproducts):r(e.data.warnings),this.updateTotals())).catch(e=>$(e,n.warning))},updateCartType(e,r){return R.post(t.changeTypeCartItem,Qk({id:e,status:r})).then(e=>(this.cart=e.data.model,window.vm.updateSidebarShoppingCart(t.sidebarShoppingCart),this.updateTotals())).catch(e=>$(e,n.warning))},updateOnCart(e){return R.get(`${t.getItemCart}/${e}`).then(t=>{t.data.success?(window.vm.PopupQuickViewVueModal=t.data.model,window.vm.UpdatedShoppingCartItemId=e,Ha.getOrCreateInstance(document.getElementById(`ModalQuickView`)).show()):r(t.data.message)}).catch(e=>$(e,n.warning))},cartClick(e){let t=e.target.closest(`.deleteshoppingcartitem`);t&&t.dataset.deleteUrl&&this.deleteitem(t.dataset.deleteUrl)},deleteitem(e){return R.post(e).then(e=>{let t=window.vm;if(t.flycartindicator=e.data.totalproducts,document.querySelector(`.sidebar-cart`)){let n=e.data.sidebarshoppingcartmodel;t.flycart=n,t.flycartitems=n.Items,t.flycartindicator=n.TotalProducts}return this.cart=e.data.model,this.updateTotals()}).catch(e=>$(e,n.warning))},ApplyDiscountCode(e){return R.post(e,Qk({discountcouponcode:document.getElementById(`discountcouponcode`).value})).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},RemoveDiscountId(e){return R.get(e).then(e=>(this.cart=e.data.model,this.updateTotals())).catch(e=>$(e,n.warning))},displayWarning(e){r(e)}}}))}),Z(`vendorReviewOverview`,({model:e})=>{window.vendorreviewsoverview=QO(`vendorreviewsoverview`,hk({data:()=>({Model:e}),computed:{rating(){return this.Model&&this.Model.TotalReviews?this.Model.RatingSum/this.Model.TotalReviews:0}}}))});var AA=/[`~!#$%^&*()_|+\-=?;:'",.<>{}[\]\\/]/gi;function jA(e){let t=new SpeechSynthesisUtterance;t.text=e,window.speechSynthesis.speak(t)}Z(`voiceNavigation`,({lang:e,commands:t,res:n})=>{window.voicenavigator=QO(`voicenavigator`,hk({data:()=>({recording:!1,recognition:null,lang:e,commands:t,transcript:``,variant:`info`,micMessage:n.micHold,voiceMessage:n.tryAgain,allowed:!0}),created(){this.allowCheck()},methods:{startRecording(){this.recognition.start()},stopRecording(){this.recognition.stop()},allowCheck(){eA(e=>{this.allowed=e})},handleSpeech(e){if(!this.recording||!e.results[0].isFinal)return;let t=e.results[e.resultIndex][0].transcript;this.transcript=t;let n=t.replace(AA,``).toLowerCase(),r=this.commands.find(e=>e.triggers.some(e=>n.includes(e)));r?(this.stopRecording(),this.variant=`success`,setTimeout(()=>{window.location.href=r.url},300)):setTimeout(()=>jA(this.voiceMessage),300)}},watch:{recording(){let e=window.SpeechRecognition||window.webkitSpeechRecognition;e?this.recording?(this.recognition=new e,this.recognition.continuous=!0,this.recognition.lang=this.lang,this.recognition.interimResults=!1,this.recognition.maxAlternatives=1,this.startRecording(),this.micMessage=n.micPlaceholder,this.recognition.addEventListener(`result`,e=>this.handleSpeech(e))):(this.stopRecording(),this.transcript=``,this.variant=`info`,this.micMessage=n.micHold):this.allowed=!1}}}))}),Z(`wishlist`,({model:e,routes:t,res:n})=>{window.vmwishlist=QO(`vmwishlist`,hk({data:()=>({Model:e,PopupUpdateVueModal:null}),methods:{deleteFromWishlist(e){return R.get(`${t.deleteItem}/${e}`).then(e=>{if(e.data.success)return this.getModel();this.displayWarning(e.data.message,`danger`)}).catch(e=>$(e,n.warning))},addToCartFromWishlist(e){return R.post(t.addToCart+e).then(e=>{if(!e.data.success)this.displayWarning(e.data.message,`danger`);else return window.vm.updateSidebarShoppingCart(t.sidebarShoppingCart),this.displayWarning(n.addedToCart,`info`,n.success),this.getModel()}).catch(e=>$(e,n.warning))},getItemCart(e){return R.get(`${t.getItemCart}/${e}`).then(t=>{t.data.success?(window.vm.PopupQuickViewVueModal=t.data.model,window.vm.UpdatedShoppingCartItemId=e,Ha.getOrCreateInstance(document.getElementById(`ModalQuickView`)).show()):this.displayWarning(t.data.message,`danger`)}).catch(e=>$(e,n.warning))},updateQuantity(e,r){return R.post(t.updateQuantity,Qk({shoppingcartId:r,ShoppingCartType:2,quantity:document.getElementById(e+r).value})).then(e=>{if(e.data.success)return this.getModel();this.displayWarning(e.data.warnings,`danger`)}).catch(e=>$(e,n.warning))},getModel(){return R.get(t.wishlist,{params:{timestamp:new Date().getTime()},headers:{Accept:`application/json`,"X-Response-View":`Json`}}).then(e=>{this.Model=e.data;let t=document.querySelector(`.wishlist-qty`);t&&(t.innerHTML=this.Model.Items.reduce((e,t)=>e+t.Quantity,0))}).catch(e=>$(e,n.warning))},displayWarning(e,t,r){$k(e,r??n.warning,t)}}}))});function MA(e){Object.defineProperty(e.config.globalProperties,"vm",{get:()=>tk(),configurable:!0}),Object.assign(e.config.globalProperties,{window,document,location,localStorage,bootstrap:It,hideTooltip:PA})}$O(e=>{xk(e),jk(e),MA(e),e.config.globalProperties.$bvToast=Pk,e.config.errorHandler=(e,t,n)=>console.error(e,n)});function NA(){document.body.__tooltipDelegate||(document.body.__tooltipDelegate=new qo(document.body,{selector:`[data-bs-toggle="tooltip"]`}))}document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,NA):NA();function PA(e){e&&qo.getInstance(e)?.hide()}window.hideTooltip=PA,rk(()=>zk()),document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>zk()):zk(),window.grandInitViews=zk,window.grandMountIslands=dk,window.bootstrap=It,window.Vue=_k,window.axios=R,window.Pikaday=af.default,window.VueGallerySlideshow=bk,window.$bvToast=Pk,window.vee_getMessage=Sk})(); \ No newline at end of file