Översvämningsskydd HydroSnake 145x25cm
HydroSnake™ är en modern och effektiv lösning för översvämningsskydd av bostäder och kommersiella fastigheter. Produkten är en sandlös barriär som snabbt aktiveras vid kontakt med vatten och kan absorbera upp till cirka 20 liter.
Före användning väger HydroSnake™ mindre än 0,5 kg och är enkel att hantera och placera. När den aktiveras expanderar den till upp till 1,45 meters längd och bildar en stabil barriär som kan stoppa eller leda bort vatten samt icke-korrosiva kemikalier och föroreningar.
HydroSnake™ är idealisk för användning vid lagerdörrar, trädgårdsgrindar, gångvägar, idrottsytor samt inom räddnings- och beredskapsarbete. Produkten är miljövänlig och säker att kassera efter användning, antingen via deponi, förbränning eller genom spridning på mark.
Kommer i 2-pack.
Error executing template "Designs/Swift-v2/Components/VariantSelector.cshtml" System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct. at System.Collections.Generic.Dictionary`2.FindValue(TKey key) at Dynamicweb.Host.Core.Context.Session.get_Item(String key) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.GetConnectorResponses[T](ResponseCacheLevel cacheModel, String cacheKey) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.GetProductInfos(ResponseCacheLevel cacheModel, User user) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.IsProductInCache(ResponseCacheLevel productCacheLevel, String productIdentifier, User user, Currency currency) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductManager.GetProductsForRequest(Settings settings, ResponseCacheLevel productCacheLevel, List`1 products, Logger logger, LiveContext context, Boolean doCurrencyCheck) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductManager.FetchProductInfos(List`1 products, LiveContext context, Settings settings, Logger logger, Boolean doCurrencyCheck, SubmitType submitType, Boolean updateCache) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductPriceProvider.PreparePrices(PriceContext context, IEnumerable`1 selections) at Dynamicweb.Ecommerce.Prices.PriceManager.PreparePrices(PriceContext context, IEnumerable`1 selections) at Dynamicweb.Ecommerce.Prices.PriceManager.PreparePrices(PriceContext context, IEnumerable`1 products, Int64 stockLocationId) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.PreparePrices(PriceContext context, Boolean& pricesHasBeenPrepared, Object lock, IList`1 products, Int64 stockLocationId) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(VariantInfoViewModelSettings settings, Product product, Dictionary`2 variants, Lazy`1 details, IList`1 products, Boolean& pricesHasBeenPrepared, Boolean& variantPricesHasBeenPrepared, Object lock) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass15_1.<BulkCreateView>b__6() at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy`1.CreateValue() at Dynamicweb.Ecommerce.ProductCatalog.ProductViewModelExtensions.VariantGroups(ProductViewModel productViewModel) at CompiledRazorTemplates.Dynamic.RazorEngine_c5890cccb2a742878152d809dc040398.ExecuteAsync() at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System.Collections.Generic 3 @using System.Linq 4 @using Dynamicweb.Ecommerce.ProductCatalog 5 @using Dynamicweb.Ecommerce.Products 6 @using Dynamicweb.Ecommerce.Variants 7 @using Dynamicweb.Frontend 8 9 @functions { 10 //Find contrast color (white, black) 11 public static string GetContrastColor(string hexString) 12 { 13 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 14 15 int nThreshold = 105; 16 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 17 (bg.B * 0.114)); 18 19 string foreColor = (255 - bgDelta < nThreshold) ? "#333" : "#fff"; 20 return foreColor; 21 } 22 23 public string GetLayoutForVariantGroup(string variantGroupId) 24 { 25 string showVariantGroups = Model.Item?.GetRawValueString("ShowVariantGroupOptions"); 26 var selectedVariantGroupsList = Model.Item?.GetItems("VariantGroups") ?? new List<ItemViewModel>(); 27 bool showAllVariantGroupsDefault = string.IsNullOrEmpty(showVariantGroups) || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any(); 28 string defaultVariantGroupLayout = Model.Item?.GetRawValueString("DefaultVariantGroupLayout"); 29 defaultVariantGroupLayout = !string.IsNullOrEmpty(defaultVariantGroupLayout) ? defaultVariantGroupLayout : "button"; 30 31 if (showAllVariantGroupsDefault) return defaultVariantGroupLayout; 32 33 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 34 { 35 var variantGroups = selectedVariantGroupListItem.GetList("VariantGroups").GetRawValue().OfType<string>().ToList(); 36 if (variantGroups.Any(s => s.Equals(variantGroupId))) return selectedVariantGroupListItem.GetRawValueString("VariantGroupLayout"); 37 } 38 39 return defaultVariantGroupLayout; 40 } 41 42 //Collect all variant images 43 public static Dictionary<string, string> GetVariantImages(List<VariantInfoViewModel> variantInfo, Dictionary<string, string> list) 44 { 45 foreach (var variantGroup in variantInfo) 46 { 47 if (variantGroup.Image?.Value != null && !list.ContainsKey(variantGroup.OptionID)) 48 { 49 list.Add(variantGroup.OptionID, variantGroup.Image.Value); 50 } 51 52 if (variantGroup.VariantInfo != null) 53 { 54 GetVariantImages(variantGroup.VariantInfo, list); 55 } 56 } 57 58 return list; 59 } 60 61 private string GetDefaultOrVariantGroupValue(string variantGroupId, string itemField, string itemFieldDefaultValue, Dictionary<string, string> fieldValueMapping) 62 { 63 if (!string.IsNullOrEmpty(variantGroupId)) 64 { 65 string itemFieldValue = Model.Item?.GetRawValueString(itemField, itemFieldDefaultValue); 66 string itemFieldParameter = GetViewParameterString(itemField); 67 itemFieldValue = string.IsNullOrEmpty(itemFieldValue) && !string.IsNullOrEmpty(itemFieldParameter) ? itemFieldParameter : itemFieldValue; 68 69 if (fieldValueMapping != null && !string.IsNullOrEmpty(itemFieldValue) && fieldValueMapping.Any()) 70 { 71 itemFieldValue = fieldValueMapping.ContainsKey(itemFieldValue) ? fieldValueMapping[itemFieldValue] : itemFieldValue; 72 } 73 74 // If no variantGroup (i.e. Visual Editor), return default value 75 if (string.IsNullOrEmpty(variantGroupId)) return itemFieldValue; 76 77 string showVariantGroups = Model.Item?.GetString("ShowVariantGroupOptions", "all"); 78 var selectedVariantGroupsList = Model.Item?.GetItems("VariantGroups") ?? new List<ItemViewModel>(); 79 // If no exceptions or settings are all the same, return default value 80 if (showVariantGroups == "all" || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any()) return itemFieldValue; 81 82 // Get specific value for variant group 83 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 84 { 85 var variantGroups = selectedVariantGroupListItem.GetList("VariantGroups").GetRawValue().OfType<string>().ToList(); 86 if (!variantGroups.Any(s => s.Equals(variantGroupId))) continue; 87 88 itemFieldValue = selectedVariantGroupListItem.GetRawValueString(itemField, itemFieldDefaultValue); 89 itemFieldValue = fieldValueMapping.ContainsKey(itemFieldValue) ? fieldValueMapping[itemFieldValue] : itemFieldValue; 90 } 91 92 return itemFieldValue; 93 } 94 else 95 { 96 return string.Empty; 97 } 98 } 99 100 private bool GetDefaultOrVariantGroupValue(string variantGroupId, string itemField) 101 { 102 if (!string.IsNullOrEmpty(variantGroupId)) 103 { 104 bool itemFieldValue = Model.Item?.GetBoolean(itemField) ?? false; 105 106 // If no variantGroup (i.e. Visual Editor), return default value 107 if (string.IsNullOrEmpty(variantGroupId)) return itemFieldValue; 108 109 string showVariantGroups = Model.Item?.GetString("ShowVariantGroupOptions", "all"); 110 var selectedVariantGroupsList = Model.Item?.GetItems("VariantGroups") ?? new List<ItemViewModel>(); 111 // If no exceptions or settings are all the same, return default value 112 if (showVariantGroups == "all" || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any()) return itemFieldValue; 113 114 // Get specific value for variant group 115 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 116 { 117 var variantGroups = selectedVariantGroupListItem.GetList("VariantGroups").GetRawValue().OfType<string>().ToList(); 118 if (!variantGroups.Any(s => s.Equals(variantGroupId))) continue; 119 120 itemFieldValue = selectedVariantGroupListItem.GetBoolean(itemField); 121 } 122 123 return itemFieldValue; 124 } 125 else 126 { 127 return false; 128 } 129 } 130 } 131 132 @{ 133 ProductViewModel product = null; 134 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 135 { 136 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 137 } 138 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 139 { 140 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 141 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 142 143 if (productList?.Products is object) 144 { 145 product = productList.Products[0]; 146 } 147 } 148 } 149 150 @if ((product is object)) 151 { 152 bool hideGroupHeaders = !string.IsNullOrEmpty(Model?.Item?.GetString("HideGroupHeaders")) ? Model.Item.GetBoolean("HideGroupHeaders") : false; 153 var productVariantGroups = product.VariantGroups(); 154 155 string itemId = Model?.Item?.SystemName != null ? $"item_{Model.Item.SystemName.ToLower()}" : string.Empty; 156 157 bool isModalSelector = Model?.Item == null; 158 string target = isModalSelector ? "data-response-target-element=\"DynamicModalContent\"" : string.Empty; 159 160 string variantSelectorServicePageId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("VariantSelectorServicePage")) ? Dynamicweb.Context.Current.Request.Form.Get("VariantSelectorServicePage") : string.Empty; 161 string formAction = isModalSelector ? $"action=\"/Default.aspx?ID={variantSelectorServicePageId}\"" : string.Empty; 162 163 string getProductInfo = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["getproductinfo"]) ? Dynamicweb.Context.Current.Request.Form["getproductinfo"] : string.Empty; 164 165 if (productVariantGroups.Any() && product?.VariantInfo?.VariantInfo != null) 166 { 167 string[] variantId = product.VariantId.Split('.'); 168 int groupNumber = 1; 169 170 string baseUrl = $"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}"; 171 string variantUrl = string.Empty; 172 if (!string.IsNullOrEmpty(product.VariantId) && !isModalSelector) 173 { 174 variantUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl($"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}&VariantID={product.VariantId}"); 175 } 176 177 Dictionary<string, string> variantImages = new Dictionary<string, string>(); 178 variantImages = GetVariantImages(product.VariantInfo.VariantInfo, variantImages); 179 180 <form @formAction class="d-flex flex-column gap-2 js-variant-selector @itemId" @target data-combinations="@string.Join(",", product.VariantCombinations())" data-base-url="@baseUrl" data-friendly-url="@variantUrl"> 181 @if (isModalSelector) 182 { 183 <input type="hidden" name="productId" value="@product.Id"> 184 <input type="hidden" name="variantid" value="@product.VariantId"> 185 <input type="hidden" name="QuantitySelector" value="true"> 186 <input type="hidden" name="VariantSelectorServicePage" value="@variantSelectorServicePageId"> 187 <input type="hidden" name="ViewType" value="ModalContent"> 188 189 if (GetViewParameter("ButtonLayout") != null) 190 { 191 <input type="hidden" name="ButtonLayout" value="@GetViewParameter("ButtonLayout")"> 192 } 193 194 if (GetViewParameter("ButtonAspectRatio") != null) 195 { 196 <input type="hidden" name="ButtonAspectRatio" value="@GetViewParameter("ButtonAspectRatio")"> 197 } 198 199 if (!string.IsNullOrEmpty(getProductInfo)) 200 { 201 <input type="hidden" name="getproductinfo" value="@getProductInfo"> 202 } 203 } 204 205 @foreach (var variantGroup in productVariantGroups) 206 { 207 VariantGroupViewModel group = variantGroup; 208 string variantGroupLayout = GetLayoutForVariantGroup(variantGroup.Id) ?? "button"; 209 string horizontalAlign = GetDefaultOrVariantGroupValue(variantGroup.Id, "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "justify-content-center" }, { "end", "justify-content-end" } }); 210 string horizontalTextAlign = GetDefaultOrVariantGroupValue(variantGroup.Id, "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "text-center" }, { "end", "text-end" } }); 211 bool showSelectedOptionName = GetDefaultOrVariantGroupValue(variantGroup.Id, "ShowSelectedOptionName"); 212 213 214 <div> 215 @if (!hideGroupHeaders) 216 { 217 <h3 class="h6 @horizontalTextAlign"> 218 @group.Name 219 220 @if (showSelectedOptionName) 221 { 222 string selectedOptionName = group.Options.FirstOrDefault(opt => variantId.Contains(opt.Id))?.Name ?? string.Empty; 223 <span class="fw-light px-1 swift-selected-option-name">@selectedOptionName</span> 224 } 225 </h3> 226 } 227 <div class="d-flex gap-2 @horizontalAlign flex-wrap js-variant-group" data-group-id="@groupNumber"> 228 @if (variantGroupLayout == "button") 229 { 230 foreach (var option in group.Options) 231 { 232 string active = variantId != null && variantId.Contains(option.Id) ? "active" : string.Empty; 233 string buttonId = $"{product.Id}_{option.Id}_{Pageview.CurrentParagraph.ID}"; 234 string contrastColor = string.Empty; 235 string buttonAspectRatio = GetDefaultOrVariantGroupValue(variantGroup.Id, "ButtonAspectRatio", "100%", new Dictionary<string, string> { { "100%", "--bs-aspect-ratio:100%" }, { "56%", "--bs-aspect-ratio:56%" }, { "177%", "--bs-aspect-ratio:177%" }, { "75%", "--bs-aspect-ratio:75%" }, { "133%", "--bs-aspect-ratio:133%" } }); 236 buttonAspectRatio = buttonAspectRatio == string.Empty ? "--bs-aspect-ratio:100%" : buttonAspectRatio; 237 238 string buttonLayout = GetDefaultOrVariantGroupValue(variantGroup.Id, "ButtonLayout", "rounded-circle", new Dictionary<string, string> { { "round", "rounded-circle" }, { "square", "rounded-0" }, { "square-rounded", "rounded-3" } }); 239 240 var displayType = group.DisplayType; 241 displayType = displayType == VariantGroupDisplayType.NothingSelected && !string.IsNullOrEmpty(option.Color) ? VariantGroupDisplayType.VariantColor : displayType; 242 displayType = displayType == VariantGroupDisplayType.NothingSelected && string.IsNullOrEmpty(option.OptionImage.Value) && string.IsNullOrEmpty(option.Color) ? VariantGroupDisplayType.VariantName : displayType; 243 displayType = displayType == VariantGroupDisplayType.NothingSelected && !string.IsNullOrEmpty(option.OptionImage.Value) ? VariantGroupDisplayType.VariantOptionImage : displayType; 244 245 var btnWidth = displayType == VariantGroupDisplayType.VariantColor || displayType == VariantGroupDisplayType.VariantImage || displayType == VariantGroupDisplayType.VariantOptionImage ? $"style=\"width:64px\"" : string.Empty; 246 var btnClasses = string.Empty; 247 248 btnClasses = displayType == VariantGroupDisplayType.VariantColor ? $"overflow-hidden colorbox colorbox-auto p-0 border {buttonLayout}" : btnClasses; 249 btnClasses = displayType == VariantGroupDisplayType.VariantImage ? $"overflow-hidden p-0 {buttonLayout}" : btnClasses; 250 btnClasses = displayType == VariantGroupDisplayType.VariantOptionImage ? $"overflow-hidden colorbox colorbox-auto {buttonLayout} p-0" : btnClasses; 251 252 <button type="button" style="border-radius: 25px; border: 2px solid #138f34" class="px-4 btn @btnClasses d-inline-block variant-option js-variant-option @active" @btnWidth onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@(product.Id)_@(option.Id)_@Pageview.CurrentParagraph.ID"> 253 <div class="@(displayType == VariantGroupDisplayType.VariantName ? string.Empty : "ratio")" style="@(buttonAspectRatio)"> 254 255 @switch (displayType) 256 { 257 case VariantGroupDisplayType.VariantOptionImage: 258 if (!string.IsNullOrEmpty(option.OptionImage.Value)) 259 { 260 <img style="object-fit:cover;--variantoption-check-color:@(contrastColor)" src="/Admin/Public/GetImage.ashx?image=@(option.OptionImage.Value)&width=64&format=webp"> 261 } 262 else if (!string.IsNullOrEmpty(option.Color)) 263 { 264 <span class="" style="background-color:@(option.Color);--variantoption-check-color:@(contrastColor)"><span class="visually-hidden">@option.Color</span></span> 265 } 266 else 267 { 268 <span class="d-flex align-items-center justify-content-center">@(option.Name)</span> 269 } 270 break; 271 272 case VariantGroupDisplayType.VariantImage: 273 string variantImage = string.Empty; 274 variantImages.TryGetValue(option.Id, out variantImage); 275 <img style="object-fit:contain" src="/Admin/Public/GetImage.ashx?image=@(variantImage)&width=64&format=webp"> 276 break; 277 278 case VariantGroupDisplayType.VariantColor: 279 contrastColor = GetContrastColor(option.Color); 280 <span style="background-color:@(option.Color);--variantoption-check-color:@(contrastColor)"><span class="visually-hidden">@option.Color</span></span> 281 break; 282 283 case VariantGroupDisplayType.VariantName: 284 <span class="d-flex align-items-center justify-content-center">@(option.Name)</span> 285 break; 286 287 } 288 </div> 289 </button> 290 } 291 } 292 else 293 { 294 // Add logic to swap name with dimentions 295 <select class="form-select" id="VariantDropdown_@variantGroup.Id" aria-label="@variantGroup.Name" onchange="swift.VariantSelector.OptionClick(event)"> 296 @if (string.IsNullOrEmpty(product.VariantId)) 297 { 298 <option value="" class="variant-option js-variant-option" data-variant-id="">@Translate("Nothing selected")</option> 299 } 300 301 @foreach (var option in variantGroup.Options ) 302 { 303 string replaceTextWithSize = ""; // Declare fresh per option 304 305 // Lookup size match for this option 306 if (variantGroup.Name.Contains("Storlek skylt")) 307 { 308 309 foreach (var category in product.ProductCategories) 310 { 311 312 foreach (var field in category.Value.Fields) 313 { 314 var sizeOptions = field.Value.Value as List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>; 315 var nameToMatch = option.Name; 316 317 if (sizeOptions != null && sizeOptions.Any()) 318 { 319 foreach (var size in sizeOptions) 320 { 321 switch (option.Name?.Trim().ToLowerInvariant()) 322 { 323 case "Mycket liten": 324 nameToMatch = "Extra-small"; 325 break; 326 case "liten": 327 nameToMatch = "Small"; 328 break; 329 case "normal": 330 nameToMatch = "Normal"; 331 break; 332 case "stor": 333 nameToMatch = "Large"; 334 break; 335 case "Mycket stor": 336 nameToMatch = "Extra-Large"; 337 break; 338 default: 339 break; 340 } 341 342 if (size.Name == nameToMatch) // Match by name 343 { replaceTextWithSize = size.Value; // Set the correct angle (e.g., "600 grader") 344 } 345 } 346 } 347 } 348 } 349 } 350 351 string active = variantId != null && variantId.Contains(option.Id) ? "active" : ""; 352 var selected = variantId != null && variantId.Contains(option.Id) ? "selected" : ""; 353 var value = $"{product.Id}_{option.Id}"; 354 355 <option value="@(value)" 356 class="variant-option js-variant-option @active" 357 data-variant-id="@option.Id" 358 id="@(value)_@(Pageview.CurrentParagraph.ID)" 359 @selected> 360 @(string.IsNullOrEmpty(replaceTextWithSize) ? option.Name : option.Name + ": " + replaceTextWithSize) 361 </option> 362 } 363 </select> } 364 </div> 365 </div> 366 367 groupNumber++; 368 } 369 </form> 370 371 <script type="module"> 372 swift.VariantSelector.init(); 373 </script> 374 } 375 else if (Pageview.IsVisualEditorMode) 376 { 377 string horizontalAlign = GetDefaultOrVariantGroupValue("", "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "justify-content-center" }, { "end", "justify-content-end" } }); 378 string horizontalTextAlign = GetDefaultOrVariantGroupValue("", "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "text-center" }, { "end", "text-end" } }); 379 380 <form class="d-flex flex-column js-variant-selector @itemId" data-combinations="VO1,VO2,VO3,VO4"> 381 <div> 382 @if (!hideGroupHeaders) 383 { 384 <h3 class="h6 @horizontalTextAlign">@Translate("Sizes")</h3> 385 } 386 <div class="mb-3 @horizontalAlign js-variant-group" data-group-id="0"> 387 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" data-dw-button="secondary" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO1" id="@(product.Id)_VO1_@Pageview.CurrentParagraph.ID">S</button> 388 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" data-dw-button="secondary" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO2" id="@(product.Id)_VO2_@Pageview.CurrentParagraph.ID">M</button> 389 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" data-dw-button="secondary" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO3" id="@(product.Id)_VO3_@Pageview.CurrentParagraph.ID">L</button> 390 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" data-dw-button="secondary" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO4" id="@(product.Id)_VO4_@Pageview.CurrentParagraph.ID">XL</button> 391 </div> 392 </div> 393 </form> 394 395 <script type="module"> 396 swift.VariantSelector.init(); 397 </script> 398 } 399 } 400 else if (Pageview.IsVisualEditorMode) 401 { 402 <div class="alert alert-dark m-0" role="alert"> 403 <span>@Translate("The variant selector will be shown here, if any variants are available")</span> 404 </div> 405 } 406
Error executing template "Designs/Swift-v2/Paragraph/Swift-v2_ProductPrice.cshtml" System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct. at System.Collections.Generic.Dictionary`2.FindValue(TKey key) at Dynamicweb.Host.Core.Context.Session.get_Item(String key) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.GetConnectorResponses[T](ResponseCacheLevel cacheModel, String cacheKey) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.GetProductInfos(ResponseCacheLevel cacheModel, User user) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.IsProductInCache(ResponseCacheLevel productCacheLevel, String productIdentifier, User user, Currency currency) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductManager.GetProductsForRequest(Settings settings, ResponseCacheLevel productCacheLevel, List`1 products, Logger logger, LiveContext context, Boolean doCurrencyCheck) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductManager.FetchProductInfos(List`1 products, LiveContext context, Settings settings, Logger logger, Boolean doCurrencyCheck, SubmitType submitType, Boolean updateCache) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductPriceProvider.PreparePrices(PriceContext context, IEnumerable`1 selections) at Dynamicweb.Ecommerce.Prices.PriceManager.PreparePrices(PriceContext context, IEnumerable`1 selections) at Dynamicweb.Ecommerce.Prices.PriceManager.PreparePrices(PriceContext context, IEnumerable`1 products, Int64 stockLocationId) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.PreparePrices(PriceContext context, Boolean& pricesHasBeenPrepared, Object lock, IList`1 products, Int64 stockLocationId) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(VariantInfoViewModelSettings settings, Product product, Dictionary`2 variants, Lazy`1 details, IList`1 products, Boolean& pricesHasBeenPrepared, Boolean& variantPricesHasBeenPrepared, Object lock) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass15_1.<BulkCreateView>b__6() at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) --- End of stack trace from previous location --- at System.Lazy`1.CreateValue() at CompiledRazorTemplates.Dynamic.RazorEngine_7dea2f317f9a4e5684af4984f6751ae8.ExecuteAsync() at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Ecommerce.Products 4 5 @{ 6 ProductViewModel product = null; 7 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 8 { 9 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 10 } else if (!string.IsNullOrEmpty(Pageview.Page.Item["DummyProduct"]?.ToString()) && Pageview.IsVisualEditorMode) 11 { 12 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 13 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 14 15 if (productList?.Products is object) 16 { 17 product = productList.Products[0]; 18 } 19 } else if (Pageview.IsVisualEditorMode) { 20 product = new ProductViewModel(); 21 product.Price = new PriceViewModel() { 22 Price = 99, 23 PriceFormatted = "99 " + Pageview.Area.EcomCurrencyId, 24 PriceWithoutVat = 99, 25 PriceWithoutVatFormatted = "99 " + Pageview.Area.EcomCurrencyId, 26 PriceWithVat = 99, 27 PriceWithVatFormatted = "99 " + Pageview.Area.EcomCurrencyId 28 }; 29 product.PriceInformative = new PriceViewModel() { 30 Price = 49, 31 PriceFormatted = "49 " + Pageview.Area.EcomCurrencyId, 32 PriceWithoutVat = 49, 33 PriceWithoutVatFormatted = "49 " + Pageview.Area.EcomCurrencyId, 34 PriceWithVat = 49, 35 PriceWithVatFormatted = "49 " + Pageview.Area.EcomCurrencyId 36 }; 37 product.PriceBeforeDiscount = new PriceViewModel() { 38 Price = 199, 39 PriceFormatted = "199 " + Pageview.Area.EcomCurrencyId, 40 PriceWithoutVat = 199, 41 PriceWithoutVatFormatted = "199 " + Pageview.Area.EcomCurrencyId, 42 PriceWithVat = 199, 43 PriceWithVatFormatted = "99 " + Pageview.Area.EcomCurrencyId 44 }; 45 } 46 47 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 48 bool anonymousUser = Pageview.User == null; 49 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser; 50 51 bool productIsDiscontinued = product is object && product.Discontinued; 52 bool doNotShowPriceIfProductIsDiscontinued = Model.Item.GetBoolean("DoNotShowPriceIfProductIsDiscontinued"); 53 var isDiscontinued = productIsDiscontinued && doNotShowPriceIfProductIsDiscontinued; 54 55 string priceType = string.Empty; 56 if (Dynamicweb.Context.Current.Items.Contains("PriceType")) 57 { 58 priceType = Dynamicweb.Context.Current.Items["PriceType"].ToString().ToLower(); 59 } 60 61 string isPriceRequestfieldValue = product.ProductFields["Prisfrfrgan_och_kontakt"].Value.ToString(); 62 bool isPriceRequest = isPriceRequestfieldValue.Equals("True", StringComparison.OrdinalIgnoreCase); 63 if (isPriceRequest) { 64 return; 65 } 66 } 67 68 @if (product is object && !hidePrice && !isDiscontinued && priceType != "fixedprice") { 69 bool showInformativePrice = Model.Item.GetBoolean("ShowInformativePrice"); 70 string unitId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("UnitId")) ? Dynamicweb.Context.Current.Request.Form.Get("UnitId") : string.Empty; 71 72 string priceFontSize = Model.Item.GetRawValueString("PriceSize", "fs-2"); 73 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 74 string layout = Model.Item.GetRawValueString("Layout", "horizontal"); 75 string textAlign = horizontalAlign == "center" ? "text-center" : string.Empty; 76 textAlign = horizontalAlign == "end" ? "text-end" : textAlign; 77 78 horizontalAlign = horizontalAlign == "center" && layout == "horizontal" ? "justify-content-center" : horizontalAlign; 79 horizontalAlign = horizontalAlign == "end" && layout == "horizontal" ? "justify-content-end" : horizontalAlign; 80 horizontalAlign = horizontalAlign == "center" && layout == "vertical" ? "align-items-center" : horizontalAlign; 81 horizontalAlign = horizontalAlign == "end" && layout == "vertical" ? "align-items-end" : horizontalAlign; 82 83 string flexDirection = layout == "horizontal" ? string.Empty : "flex-column"; 84 string flexGap = layout == "horizontal" ? "gap-3" : string.Empty; 85 string order = layout == "horizontal" ? string.Empty : "order-2"; 86 87 string showPricesWithVat = Dynamicweb.Ecommerce.Common.Context.DisplayPricesWithVat.ToString(); 88 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 89 90 string priceMin = ""; 91 string priceMax = ""; 92 93 @* Hide price is product has variants and is not a variant *@ 94 bool isVariant = !string.IsNullOrEmpty(product.VariantId); 95 bool hasVariants = product.VariantInfo.VariantInfo != null; 96 if (!isVariant && hasVariants) { 97 return; 98 } 99 100 <div class="@textAlign item_@Model.Item.SystemName.ToLower()" data-product-id="@product.Id" data-variant-id="@product.VariantId"> 101 @if (showInformativePrice && product.PriceInformative.Price != 0) 102 { 103 <div class="opacity-50"> 104 <span>@Translate("RRP") </span> 105 <span class="text-decoration-line-through text-price">@product.PriceInformative.PriceFormatted</span> 106 </div> 107 } 108 <div class="@priceFontSize m-0 d-flex flex-wrap @flexDirection @flexGap @horizontalAlign" style="row-gap: 0 !important" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 109 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 110 111 112 @if (showPricesWithVat == "false" && !neverShowVat) 113 { 114 string beforePrice = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).PriceBeforeDiscount.PriceWithoutVatFormatted : product.PriceBeforeDiscount.PriceWithoutVatFormatted; 115 116 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 117 if (product.Price.Price != product.PriceBeforeDiscount.Price) 118 { 119 <span class="text-decoration-line-through opacity-75 @order">@beforePrice</span> 120 } 121 } 122 else 123 { 124 string beforePrice = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).PriceBeforeDiscount.PriceFormatted : product.PriceBeforeDiscount.PriceFormatted; 125 126 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 127 128 if (product.Price.Price != product.PriceBeforeDiscount.Price) 129 { 130 <span class="text-decoration-line-through opacity-75 @order"> 131 <span class="text-price">@beforePrice</span> 132 </span> 133 } 134 } 135 @if (showPricesWithVat == "false" && !neverShowVat) 136 { 137 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceWithoutVatFormatted : product.Price.PriceWithoutVatFormatted; 138 139 if (product?.VariantInfo?.VariantInfo != null) 140 { 141 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 142 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 143 } 144 if (priceMin != priceMax) 145 { 146 price = priceMin + " - " + priceMax; 147 } 148 149 <span class="text-price">@price</span> 150 } 151 else 152 { 153 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceFormatted : product.Price.PriceFormatted; 154 155 if (product?.VariantInfo?.VariantInfo != null) 156 { 157 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 158 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 159 } 160 if (priceMin != priceMax) 161 { 162 price = priceMin + " - " + priceMax; 163 } 164 165 <span class="text-price">@price</span> 166 } 167 168 @* Stock state for Schema.org, start *@ 169 @{ 170 Uri url = Dynamicweb.Context.Current.Request.Url; 171 } 172 173 <link itemprop="url" href="@url"> 174 175 @{ 176 bool IsNeverOutOfStock = product.NeverOutOfstock; 177 } 178 179 @if (IsNeverOutOfStock) 180 { 181 <span itemprop="availability" class="d-none">@Translate("Available in stock")</span> 182 } 183 else 184 { 185 if (product.StockLevel > 0) 186 { 187 <span itemprop="availability" class="d-none">InStock</span> 188 } 189 else 190 { 191 <span itemprop="availability" class="d-none">OutOfStock</span> 192 } 193 } 194 @* Stock state for Schema.org, stop *@ 195 196 </div> 197 198 @if (showPricesWithVat == "false" && !neverShowVat) 199 { 200 if (!Pageview.IsVisualEditorMode) 201 { 202 <small class="opacity-85 fst-normal js-text-price-with-vat d-none" data-suffix="@Translate("Incl. VAT")"></small> 203 } 204 else 205 { 206 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceWithVatFormatted : product.Price.PriceWithVatFormatted; 207 208 if (product?.VariantInfo?.VariantInfo != null) 209 { 210 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 211 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 212 } 213 if (priceMin != priceMax) 214 { 215 price = priceMin + " - " + priceMax; 216 } 217 <small class="opacity-85 fst-normal">@price @Translate("Incl. VAT")</small> 218 } 219 } 220 </div> 221 } 222 else if (Pageview.IsVisualEditorMode) 223 { 224 <div class="alert alert-dark m-0" role="alert"> 225 <span>@Translate("No products available")</span> 226 </div> 227 } 228
Error executing template "Designs/Swift-v2/Paragraph/Swift-v2_ProductAddToCart.cshtml" System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct. at System.Collections.Generic.Dictionary`2.FindValue(TKey key) at Dynamicweb.Host.Core.Context.Session.get_Item(String key) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.GetConnectorResponses[T](ResponseCacheLevel cacheModel, String cacheKey) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.GetProductInfos(ResponseCacheLevel cacheModel, User user) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Cache.ResponseCache.IsProductInCache(ResponseCacheLevel productCacheLevel, String productIdentifier, User user, Currency currency) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductManager.GetProductsForRequest(Settings settings, ResponseCacheLevel productCacheLevel, List`1 products, Logger logger, LiveContext context, Boolean doCurrencyCheck) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductManager.FetchProductInfos(List`1 products, LiveContext context, Settings settings, Logger logger, Boolean doCurrencyCheck, SubmitType submitType, Boolean updateCache) at Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Products.ProductPriceProvider.PreparePrices(PriceContext context, IEnumerable`1 selections) at Dynamicweb.Ecommerce.Prices.PriceManager.PreparePrices(PriceContext context, IEnumerable`1 selections) at Dynamicweb.Ecommerce.Prices.PriceManager.PreparePrices(PriceContext context, IEnumerable`1 products, Int64 stockLocationId) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.PreparePrices(PriceContext context, Boolean& pricesHasBeenPrepared, Object lock, IList`1 products, Int64 stockLocationId) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(VariantInfoViewModelSettings settings, Product product, Dictionary`2 variants, Lazy`1 details, IList`1 products, Boolean& pricesHasBeenPrepared, Boolean& variantPricesHasBeenPrepared, Object lock) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass15_1.<BulkCreateView>b__6() at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) --- End of stack trace from previous location --- at System.Lazy`1.CreateValue() at CompiledRazorTemplates.Dynamic.RazorEngine_a89821225b2a45e497f521dd0a271e9b.ExecuteAsync() at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Rendering 4 @using Dynamicweb.Core.Encoders 5 @using System.Globalization 6 7 @functions { 8 string? DoubleToString(double? value) 9 { 10 if (value.HasValue) 11 { 12 return value.Value.ToString(CultureInfo.InvariantCulture); 13 } 14 return null; 15 } 16 } 17 18 @{ 19 ProductViewModel product = null; 20 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 21 { 22 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 23 } 24 else if (!string.IsNullOrEmpty(Pageview.Page.Item["DummyProduct"]?.ToString()) && Pageview.IsVisualEditorMode) 25 { 26 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 27 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 28 29 if (productList?.Products is object) 30 { 31 product = productList.Products[0]; 32 } 33 } else if (Pageview.IsVisualEditorMode) { 34 product = new ProductViewModel(); 35 product.Id = "1"; 36 product.VariantId = "394041"; 37 product.PurchaseMinimumQuantity = 1; 38 product.PurchaseQuantityStep = 1; 39 product.StockLevel = 10; 40 product.DefaultUnitId = "1"; 41 product.ProductType = Dynamicweb.Ecommerce.Products.ProductType.Stock; 42 product.NeverOutOfstock = false; 43 product.Discontinued = false; 44 product.Price = new PriceViewModel() { 45 Price = 99, 46 PriceFormatted = "99 " + Pageview.Area.EcomCurrencyId, 47 PriceWithoutVat = 99, 48 PriceWithoutVatFormatted = "99 " + Pageview.Area.EcomCurrencyId, 49 PriceWithVat = 99, 50 PriceWithVatFormatted = "99 " + Pageview.Area.EcomCurrencyId 51 }; 52 } 53 54 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 55 bool anonymousUser = Pageview.User == null; 56 57 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser; 58 hideAddToCart = Pageview.IsVisualEditorMode ? false : hideAddToCart; 59 60 bool isVariant = !string.IsNullOrEmpty(product.VariantId); 61 bool hasVariants = product.VariantInfo.VariantInfo != null; 62 } 63 64 @if (product is object && !hideAddToCart) 65 { 66 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 67 horizontalAlign = horizontalAlign == "center" ? "justify-content-center" : horizontalAlign; 68 horizontalAlign = horizontalAlign == "end" ? "justify-content-end" : horizontalAlign; 69 horizontalAlign = horizontalAlign == "full" ? "" : horizontalAlign; 70 71 bool favoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowAddToFavorites")) ? Model.Item.GetBoolean("ShowAddToFavorites") : false; 72 bool quantitySelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowQuantitySelector")) ? Model.Item.GetBoolean("ShowQuantitySelector") : false; 73 bool unitsSelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowUnitsSelector")) ? Model.Item.GetBoolean("ShowUnitsSelector") : false; 74 bool hideInventory = !string.IsNullOrEmpty(Model.Item.GetString("HideInventory")) ? Model.Item.GetBoolean("HideInventory") : false; 75 bool hideStockState = !string.IsNullOrEmpty(Model.Item.GetString("HideStockState")) ? Model.Item.GetBoolean("HideStockState") : false; 76 77 string iconPath = "/Files/Images/Icons/"; 78 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 79 if (!url.Contains("LayoutTemplate")) 80 { 81 url += url.Contains("?") ? "&LayoutTemplate=Swift-v2_MiniCart.cshtml" : "?LayoutTemplate=Swift-v2_MiniCart.cshtml"; 82 } 83 84 string whenVariantsExist = Model.Item.GetRawValueString("WhenVariantsExist", "hide"); 85 string flexFill = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "flex-fill" : ""; 86 string fullWidth = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "w-100" : ""; 87 string addToCartIcon = Model.Item.GetRawValueString("Icon", iconPath + "cart-shopping.svg"); 88 string addToCartLabel = !addToCartIcon.Contains("_none") ? $"<span class=\"icon-2\">{ReadFile(addToCartIcon)}</span>" : ""; 89 addToCartLabel += !addToCartIcon.Contains("_none") && !Model.Item.GetBoolean("HideButtonText") ? " " : ""; 90 addToCartLabel += !Model.Item.GetBoolean("HideButtonText") ? $"<span class=\"d-none d-md-inline\">{Translate("Add to cart")}</span><span class=\"d-inline d-md-none\">{Translate("Add")}</span>" : ""; 91 bool userHasPendingQuote = Dynamicweb.Ecommerce.Common.Context.Cart != null && Dynamicweb.Ecommerce.Common.Context.Cart.IsQuote; 92 93 94 if (product.VariantInfo?.VariantInfo == null || whenVariantsExist == "disable") 95 { 96 string unitId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("UnitId")) ? Dynamicweb.Context.Current.Request.Form.Get("UnitId") : product.DefaultUnitId; 97 if (string.IsNullOrEmpty(unitId) && product?.UnitOptions != null) 98 { 99 if (product.UnitOptions?.FirstOrDefault<UnitOptionViewModel>() != null) 100 { 101 unitId = product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Id; 102 } 103 } 104 105 double? stepQty = product.PurchaseQuantityStep > 0 ? product.PurchaseQuantityStep : 1; 106 double? minQty = product.PurchaseMinimumQuantity > 0 ? product.PurchaseMinimumQuantity : 1; 107 double? valueQty = minQty > stepQty ? minQty : stepQty; 108 string? disableAddToCart = null; 109 double? maxQty = null; 110 111 if (Dynamicweb.Context.Current.Items.Contains("ProductQuantity")) 112 { 113 valueQty = Convert.ToDouble(Dynamicweb.Context.Current.Items["ProductQuantity"].ToString()); 114 } 115 116 if (product.ProductType == Dynamicweb.Ecommerce.Products.ProductType.Stock && !product.NeverOutOfstock) 117 { 118 disableAddToCart = product.StockLevel <= 0 ? "disabled" : disableAddToCart; 119 maxQty = product.StockLevel; 120 } 121 122 disableAddToCart = whenVariantsExist == "disable" && product.VariantInfo?.VariantInfo != null && string.IsNullOrEmpty(product.VariantId) ? "disabled" : disableAddToCart; 123 disableAddToCart = product.Discontinued ? "disabled" : disableAddToCart; 124 125 126 127 if (unitsSelector && product.UnitOptions?.Count > 0) 128 { 129 <form method="post" action="/Default.aspx?ID=@(Pageview.Page.ID)&ProductId=@product.Id" id="UnitSelectorForm_@(product.Id)_@(product.VariantId?.Replace(".", "_"))_@Model.ID"> 130 <input type="hidden" name="redirect" value="false"> 131 <input type="hidden" name="VariantID" value="@product.VariantId"> 132 <input type="hidden" name="UnitID" class="js-unit-id" value="@unitId"> 133 </form> 134 } 135 136 @* Price request - custom code *@ 137 string isPriceRequestfieldValue = product.ProductFields["Prisfrfrgan_och_kontakt"].Value.ToString(); 138 bool isPriceRequest = isPriceRequestfieldValue.Equals("True", StringComparison.OrdinalIgnoreCase); 139 if (isPriceRequest) 140 { 141 string priceRequestText = Pageview.AreaSettings.GetRawValueString("PriceRequest", ""); 142 143 <div>@priceRequestText</div> 144 145 <div> 146 <button type="button" class="btn btn-secondary" data-dw-button="secondary" data-bs-toggle="modal" data-bs-target="#quoteRequest">@Translate("Show price request form")</button> 147 148 <div class="modal fade" tabindex="-1" role="dialog" id="quoteRequest"> 149 <div class="modal-dialog" role="document"> 150 <div class="modal-content"> 151 <div class="modal-header"> 152 <h5 class="modal-title" id="exampleModalLiveLabel">@Translate("Price request")</h5> 153 <button type="button" class="close" data-bs-dismiss="modal" aria-label="Close" style="background: transparent; border: 0; padding: 0;"> 154 <span class="icon-4">@ReadFile(iconPath + "x.svg")</span> 155 </button> 156 </div> 157 <div class="modal-body"> 158 @{ 159 string moduleOutput = Model.GetModuleOutput(); 160 161 if (!string.IsNullOrWhiteSpace(moduleOutput)) { 162 <div>@moduleOutput</div> 163 } 164 } 165 </div> 166 <div class="modal-footer"> 167 <button type="button" class="btn btn-secondary" data-dw-button="secondary" data-bs-dismiss="modal">@Translate("Close")</button> 168 </div> 169 </div> 170 </div> 171 </div> 172 </div> 173 174 return; 175 } 176 177 @* Show text field - custom code *@ 178 bool hasSkyltTextSkaAnges = false; 179 string skylttext_hjlptext = string.Empty; 180 string skylttext_antal_tecken_begrnsning = string.Empty; 181 182 foreach (var category in product.ProductCategories) 183 { 184 foreach (var field in category.Value.Fields) 185 { 186 if (field.Value.SystemName.ToString() == "Skylttext_ska_anges" && field.Value.ToString() == "True") { 187 hasSkyltTextSkaAnges = true; 188 } 189 if (field.Value.SystemName.ToString() == "Skylttext_hjlptext") { 190 skylttext_hjlptext = field.Value.ToString(); 191 } 192 if (field.Value.SystemName.ToString() == "Skylttext_antal_tecken_begrnsning") { 193 skylttext_antal_tecken_begrnsning = field.Value.ToString(); 194 } 195 } 196 } 197 <div class="d-flex @fullWidth js-input-group item_@Model.Item.SystemName.ToLower()"> 198 <div class="d-flex @fullWidth @horizontalAlign flex-wrap flex-lg-nowrap gap-2"> 199 <form method="post" action="@url" class="@fullWidth" style="z-index: 1"> 200 <input type="hidden" name="redirect" value="false"> 201 <input type="hidden" name="ProductId" value="@product.Id"> 202 <input type="hidden" name="ProductName" value="@HtmlEncoder.HtmlEncode(product.Name)"> 203 <input type="hidden" name="ProductVariantName" value="@product.VariantName"> 204 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code"> 205 <input type="hidden" name="ProductPrice" value="@product.Price.ToStringInvariant()"> 206 <input type="hidden" name="ProductDiscount" value="@product.Discount.ToStringInvariant()"> 207 <input type="hidden" name="ProductReferer" value="component_ProductAddToCart"> 208 <input type="hidden" name="cartcmd" value="add"> 209 <input type="submit" class="d-none" onclick="event.preventDefault(); swift.Cart.Update(event)"> @* Fix for enterKey should not redirect to minicart page *@ 210 211 @if (hasSkyltTextSkaAnges) { 212 <div class="mb-4 mt-2"> 213 <h3 class="h5 mb-1">@Translate("Ange skylttext")</h3> 214 <div>@skylttext_hjlptext</div> 215 <div class="mt-2 form-floating"> 216 <input id="EcomOrderLineFieldInput_SignCustomText" class="form-control" name="EcomOrderLineFieldInput_SignCustomText" type="text" size="20" maxlength="@skylttext_antal_tecken_begrnsning"> 217 <label for="EcomOrderLineFieldInput_SignCustomText">@Translate("Skylttext") (@Translate("max") @skylttext_antal_tecken_begrnsning @Translate("tecken"))</label> 218 </div> 219 </div> 220 } 221 222 @if (!string.IsNullOrEmpty(product.VariantId)) 223 { 224 <input type="hidden" name="VariantId" value="@product.VariantId"> 225 } 226 227 <template class="js-step-quantity-warning"> 228 <div class="modal-header"> 229 <h1 class="modal-title fs-5">@Translate("The quantity is not valid")</h1> 230 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 231 </div> 232 <div class="modal-body"> 233 @Translate("Please select a quantity that is dividable by") @stepQty 234 </div> 235 </template> 236 237 <template class="js-min-quantity-warning"> 238 <div class="modal-header"> 239 <h1 class="modal-title fs-5">@Translate("The product could not be added to the cart")</h1> 240 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 241 </div> 242 <div class="modal-body"> 243 @Translate("The quantity is not valid. You must buy at least") @product.PurchaseMinimumQuantity 244 </div> 245 </template> 246 247 <template class="js-value-missing-warning"> 248 <div class="modal-header"> 249 <h1 class="modal-title fs-5">@Translate("No amount specified")</h1> 250 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 251 </div> 252 <div class="modal-body"> 253 @Translate("Specify an amount to add to the cart") 254 </div> 255 </template> 256 257 @if (userHasPendingQuote) 258 { 259 <input type="hidden" name="PendingQuote" value="true"> 260 261 <template class="js-pending-quote-notice"> 262 <div class="modal-header"> 263 <h1 class="modal-title fs-5">@Translate("Pending Quote")</h1> 264 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="@Translate("Close")"></button> 265 </div> 266 <div class="modal-body"> 267 @Translate("You need to complete your current quote or empty the cart before adding this product to cart.") 268 </div> 269 </template> 270 } 271 272 @if (quantitySelector || (!anonymousUser && product.VariantInfo?.VariantInfo != null) || (!anonymousUser && favoritesSelector)) 273 { 274 <input type="hidden" id="Unit_@(product.Id)_@product.VariantId?.Replace(".", "_")" name="UnitID" value="@unitId" /> 275 } 276 277 <div class="d-flex flex-wrap gap-2"> 278 @if (!quantitySelector) 279 { 280 <input id="Quantity_@(product.Id)_@product.VariantId?.Replace(".", "_")" class="swift_quantity_field" name="Quantity" value="@valueQty" type="hidden" @disableAddToCart> 281 } 282 283 @if (unitsSelector && product.UnitOptions?.Count > 0) 284 { 285 string selectedUnitName = !string.IsNullOrEmpty(unitId) && product?.UnitOptions != null ? unitId : product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Name; 286 287 foreach (var unitOption in product.UnitOptions) 288 { 289 if (unitOption.Id == unitId) 290 { 291 selectedUnitName = unitOption.Name; 292 } 293 } 294 295 <button class="btn btn-secondary @flexFill dropdown-toggle" data-dw-button="secondary" type="button" data-bs-toggle="dropdown" aria-expanded="false"> 296 @selectedUnitName 297 </button> 298 299 <ul class="dropdown-menu swift_unit-field"> 300 @foreach (var unitOption in product.UnitOptions) 301 { 302 var selectedUnit = unitOption.Id == unitId ? "selected" : ""; 303 304 <li> 305 <button type="button" class="btn dropdown-item" data-value="@unitOption.Id" onclick="document.querySelector('#UnitSelectorForm_@(product.Id)_@(product.VariantId.Replace(".", "_"))_@Model.ID').querySelector('.js-unit-id').value = this.getAttribute('data-value'); 306 document.querySelector('#Unit_@(product.Id)_@product.VariantId?.Replace(".", "_")').value = this.getAttribute('data-value'); 307 swift.PageUpdater.Update(document.querySelector('#UnitSelectorForm_@(product.Id)_@(product.VariantId?.Replace(".", "_"))_@Model.ID'))"> 308 <span>@unitOption.Name</span> 309 <span> 310 @if (unitOption.StockLevel > 0 || unitOption.NeverOutOfStock) 311 { 312 if (!Model.Item.GetBoolean("HideInventory") && !unitOption.NeverOutOfStock) 313 { 314 <span class="small text-success">@unitOption.StockLevel @Translate("In stock")</span> 315 } 316 else 317 { 318 <span class="small text-success">@Translate("In stock")</span> 319 } 320 } 321 else 322 { 323 <span class="small text-danger">@Translate("Out of Stock")</span> 324 } 325 </span> 326 </button> 327 </li> 328 } 329 </ul> 330 } 331 @if (quantitySelector) 332 { 333 @RenderPartial("Components/QuantitySelector.cshtml", product) 334 } 335 336 @{ 337 if (!isVariant && !hasVariants) { 338 disableAddToCart = ""; 339 } 340 if (isVariant) { 341 disableAddToCart = ""; 342 } 343 } 344 345 <button @disableAddToCart type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary @flexFill js-add-to-cart-button" data-dw-button="primary" style="white-space: nowrap" title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)_@Pageview.CurrentParagraph.ID"> 346 @if (!Model.Item.GetBoolean("HideButtonText")) 347 { 348 <span class="text-nowrap d-flex align-items-center justify-content-center gap-2"> 349 @addToCartLabel 350 </span> 351 } 352 else 353 { 354 @addToCartLabel 355 } 356 </button> 357 </div> 358 </form> 359 @if (!anonymousUser && favoritesSelector) 360 { 361 @RenderPartial("Components/ToggleFavorite.cshtml", product) 362 } 363 </div> 364 </div> 365 } 366 else if (whenVariantsExist == "modal") 367 { 368 string ButtonShape = Model.Item.GetRawValueString("VariantButtonShape", "square"); 369 string buttonAspectRatio = Model.Item.GetRawValueString("VariantImageAspectRatio", "56%"); 370 371 string buttonText = Translate("Select"); 372 string variantId = !string.IsNullOrWhiteSpace(product.VariantId) ? product.VariantId : product.DefaultVariantId; 373 374 string variantSelectorServicePageId = !string.IsNullOrEmpty(Model.Item.GetString("VariantSelectorServicePageId")) ? Model.Item.GetLink("VariantSelectorServicePageId").PageId.ToString() : ""; 375 variantSelectorServicePageId = variantSelectorServicePageId != "" ? variantSelectorServicePageId : GetPageIdByNavigationTag("VariantSelectorService").ToString(); 376 377 <div class="d-flex @horizontalAlign w-100 item_@Model.Item.SystemName.ToLower()"> 378 @if (!anonymousUser && favoritesSelector) 379 { 380 @RenderPartial("Components/ToggleFavorite.cshtml", product) 381 } 382 <form action="/Default.aspx?ID=@variantSelectorServicePageId" data-response-target-element="DynamicModalContent" data-preloader="inline" style="z-index: 1" class="@fullWidth"> 383 <input type="hidden" name="ProductID" value="@product.Id"> 384 <input type="hidden" name="VariantID" value="@variantId"> 385 <input type="hidden" name="QuantitySelector" value="@quantitySelector.ToString()"> 386 <input type="hidden" name="HideInventory" value="@hideInventory.ToString()"> 387 <input type="hidden" name="HideStockState" value="@hideStockState.ToString()"> 388 <input type="hidden" name="ButtonLayout" value="@ButtonShape"> 389 <input type="hidden" name="ButtonAspectRatio" value="@buttonAspectRatio"> 390 <input type="hidden" name="VariantSelectorServicePage" value="@variantSelectorServicePageId"> 391 <input type="hidden" name="ViewType" value="ModalContent"> 392 393 <button type="button" onclick="swift.PageUpdater.Update(event)" class="btn btn-primary @fullWidth" data-dw-button="primary" title="@Translate("Select")" data-bs-toggle="modal" data-bs-target="#DynamicModal" id="OpenVariantSelectorModal@(product.Id)_@Pageview.CurrentParagraph.ID">@buttonText</button> 394 </form> 395 </div> 396 } 397 } 398
Tillbehör
Produktdokumentation
| Namn | Ladda ned | Filtyp | |
|---|---|---|---|
|
|
Datablad HydroSnake.pdf | 3096 KB |