Gates V-belt Hi-power Dubl-V AA75
Error executing template "Designs/Swift/Paragraph/Swift_ProductSpecification.cshtml" System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at Dynamicweb.Ecommerce.Products.GroupRelation.GetGroupRelationsByChildId(String childId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetOrderedInheritableParentIds(Group group, String defaultLanguageId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupFieldValuesByLanguage(Group group, List`1 categoryFields, String languageId, Boolean isInheritedValue, Boolean searchRecursively) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.SearchForGroupFieldValue(Group group, List`1 categoryFields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupCategoryFieldValues(IEnumerable`1 groups, List`1 fields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValuesFromGroups(IEnumerable`1 groupInfos, List`1 catFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValueFromGroups(IEnumerable`1 groupInfos, Field catField) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String defaultLanguageId, IEnumerable`1 orderedGroups, Field catField, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String categoryId, String fieldId, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetProductCategoryFieldValue(Product product, String categoryId, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, Product product, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetFieldDisplayGroupValues(ProductViewModelSettings settings, Product product, String languageID, Lazy`1 productIds) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.<BulkCreateView>b__60() at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at CompiledRazorTemplates.Dynamic.RazorEngine_83c3e920ca6c46f49d5bc5546126d159.Execute() at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) 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 System.Globalization; 4 @functions 5 { 6 public static class NumberHelper 7 { 8 /// <summary> 9 /// Converts a scientific notation string with a comma (e.g. "5,8E-05") to a decimal. 10 /// Returns 0 if the string is invalid or empty. 11 /// </summary> 12 public static decimal ToDecimal(string input) 13 { 14 if (string.IsNullOrWhiteSpace(input)) 15 { 16 return 0m; 17 } 18 19 // Tell the parser to look for a comma 20 var format = new NumberFormatInfo { NumberDecimalSeparator = "," }; 21 22 // TryParse safely attempts to convert without throwing exceptions on bad data 23 if (decimal.TryParse(input, NumberStyles.Float, format, out decimal result)) 24 { 25 return result; 26 } 27 28 return 0m; // Return a default value if parsing fails 29 } 30 } 31 } 32 @{ 33 ProductViewModel product = null; 34 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 35 { 36 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 37 } 38 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 39 { 40 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 41 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 42 43 if (productList?.Products is object) 44 { 45 product = productList.Products[0]; 46 } 47 } 48 } 49 50 @if (product is object && Model?.Item != null) { 51 var displayGroupsRaw = Model.Item.GetRawValueString("DisplayGroups") ?? ""; 52 IEnumerable<string> selectedDisplayGroupIds = 53 displayGroupsRaw.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 54 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 55 56 foreach (var selection in selectedDisplayGroupIds) 57 { 58 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups?.Values ?? Enumerable.Empty<CategoryFieldViewModel>()) 59 { 60 if (selection == group.Id) 61 { 62 int fieldsWithNoValueOrZero = 0; 63 64 foreach (var field in group.Fields) 65 { 66 var value = field.Value?.Value?.ToString(); 67 68 if (string.IsNullOrWhiteSpace(value)) 69 { 70 fieldsWithNoValueOrZero++; 71 } 72 } 73 74 if (fieldsWithNoValueOrZero != group.Fields.Count) 75 { 76 displayGroups.Add(group); 77 } 78 } 79 } 80 } 81 82 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 83 84 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 85 86 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 87 88 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 89 90 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 91 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 92 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 93 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 94 95 string layout = Model.Item.GetRawValueString("Layout", "list"); 96 string size = Model.Item.GetRawValueString("Size", "full"); 97 string gaps = size == "full" ? " gap-4" : " gap-2"; 98 99 100 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 101 { 102 product.ProductFields.Clear(); 103 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 104 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 105 showProductFields = true; 106 } 107 108 if (layout == "commas") 109 { 110 gaps = size == "full" ? " gap-4" : " gap-2"; 111 112 } 113 114 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 115 <div class="grid"> 116 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) { 117 if (!hideTitle) 118 { 119 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 120 } 121 } 122 123 @if (displayGroups.Count != 0) 124 { 125 if (layout != "accordion") 126 { 127 foreach (var group in displayGroups) 128 { 129 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 130 131 if (!hideHeader) { 132 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 133 } 134 135 { @RenderFieldsFromList(group.Fields, layout) } 136 137 } 138 } 139 else 140 { 141 <div class="g-col-12"> 142 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 143 @foreach (var group in displayGroups) 144 { 145 <div class="accordion-item"> 146 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 147 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Id"> 148 @group.Name 149 </button> 150 </h2> 151 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 152 <div class="accordion-body"> 153 @{ @RenderFieldsFromList(group.Fields, "list") } 154 </div> 155 </div> 156 </div> 157 } 158 </div> 159 </div> 160 } 161 } 162 163 @if (product.ProductFields != null && showProductFields) 164 { 165 if (product.ProductFields.Count > 0) 166 { 167 if (layout != "accordion") 168 { 169 {@RenderFieldsFromList(product.ProductFields, layout) } 170 } 171 else 172 { 173 <div class="g-col-12"> 174 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 175 <div class="accordion-item"> 176 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 177 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@Model.ID" aria-expanded="false" aria-controls="SpecificationItem_@Model.ID"> 178 @Translate("Specifications") 179 </button> 180 </h2> 181 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 182 <div class="accordion-body"> 183 @{ @RenderFieldsFromList(product.ProductFields, "List") } 184 </div> 185 </div> 186 </div> 187 </div> 188 </div> 189 } 190 } 191 } 192 193 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 194 { 195 if (product.ProductCategories.Count > 0) 196 { 197 if (layout != "accordion") 198 { 199 foreach (var group in product.ProductCategories) 200 { 201 CategoryFieldViewModel category = group.Value; 202 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 203 204 if (!hideHeader) { 205 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 206 } 207 208 { @RenderFieldsFromList(category.Fields, layout) } 209 } 210 } 211 else 212 { 213 <div class="g-col-12"> 214 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 215 @foreach (var group in product.ProductCategories) 216 { 217 CategoryFieldViewModel category = group.Value; 218 219 <div class="accordion-item"> 220 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 221 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Value.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Value.Id"> 222 @group.Value.Name 223 </button> 224 </h2> 225 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 226 <div class="accordion-body"> 227 @{ @RenderFieldsFromList(category.Fields, "list") } 228 </div> 229 </div> 230 </div> 231 } 232 </div> 233 </div> 234 } 235 } 236 } 237 </div> 238 </div> 239 } 240 else if (Pageview.IsVisualEditorMode) 241 { 242 <div class="alert alert-warning m-0">@Translate("No products available")</div> 243 } 244 245 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 246 { 247 string size = Model.Item.GetRawValueString("Size", "full"); 248 string gaps = size != "full" ? " gap-1" : string.Empty; 249 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 250 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 251 252 if (layout == "columns") { 253 <div class="g-col-12"> 254 <div class="grid@(gaps)"> 255 @foreach (var field in fields) 256 { 257 {@RenderField(field.Value, layout)} 258 } 259 </div> 260 </div> 261 } 262 if (layout == "list") { 263 <div class="g-col-12"> 264 <dl class="grid@(gaps)"> 265 @foreach (var field in fields) 266 { 267 {@RenderField(field.Value, layout)} 268 } 269 </dl> 270 </div> 271 } 272 if (layout == "table") 273 { 274 string tableSize = size == "full" ? "" : " table-sm"; 275 <div class="g-col-12"> 276 <table class="table table-striped@(tableSize)"> 277 @foreach (var field in fields) 278 { 279 {@RenderField(field.Value, layout)} 280 } 281 </table> 282 </div> 283 } 284 if (layout == "bullets") 285 { 286 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 287 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 288 <div class="g-col-12"> 289 <ul class="@listSize" @listStyle> 290 @foreach (var field in fields) 291 { 292 {@RenderField(field.Value, layout)} 293 } 294 </ul> 295 </div> 296 } 297 if (layout == "commas") 298 { 299 List<string> featuresList = new List<string>(); 300 301 foreach (var field in fields) 302 { 303 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 304 305 if (field.Value?.Value != null) 306 { 307 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 308 { 309 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 310 311 //Hack to support field type providers with a single value 312 if (values.FirstOrDefault() != null) 313 { 314 firstListItemValue = values.FirstOrDefault().Value; 315 } 316 } 317 } 318 319 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 320 { 321 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 322 { 323 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 324 { 325 List<string> options = new List<string>(); 326 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 327 { 328 if (!string.IsNullOrWhiteSpace(option.Value)) 329 { 330 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 331 { 332 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 333 options.Add(colorSpan); 334 } 335 else if (!string.IsNullOrEmpty(option.Value)) 336 { 337 options.Add(option.Name); 338 } 339 } 340 } 341 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 342 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 343 { 344 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 345 } 346 347 if (!string.IsNullOrEmpty(optionsString)) 348 { 349 if (!hideFieldLabels) 350 { 351 featuresList.Add(field.Value.Name + ": " + optionsString); 352 } 353 else 354 { 355 featuresList.Add(optionsString); 356 } 357 } 358 } 359 else 360 { 361 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 362 { 363 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 364 { 365 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 366 367 if (!hideFieldLabels) 368 { 369 featuresList.Add(field.Value.Name + ": " + colorSpan); 370 } 371 else 372 { 373 featuresList.Add(colorSpan); 374 } 375 } 376 else 377 { 378 if (!hideFieldLabels) 379 { 380 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 381 } 382 else 383 { 384 featuresList.Add(field.Value.Value.ToString()); 385 } 386 } 387 } 388 } 389 } 390 } 391 } 392 393 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 394 395 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 396 } 397 } 398 399 @helper RenderField(FieldValueViewModel field, string layout) 400 { 401 string size = Model.Item.GetRawValueString("Size", "full"); 402 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 403 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 404 bool noValues = false; 405 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 406 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 407 408 if (!string.IsNullOrEmpty(fieldValue)) 409 { 410 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 411 { 412 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 413 noValues = values.Count > 0 ? false : true; 414 415 //Hack to support field type providers with a single value 416 if (values.FirstOrDefault() != null) 417 { 418 firstListItemValue = values.FirstOrDefault().Value; 419 } 420 } 421 } 422 423 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 424 { 425 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 426 { 427 if (layout == "columns") 428 { 429 430 <div class="grid g-col-6 g-col-lg-4 gap-1"> 431 @if (!hideFieldLabels) 432 { 433 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 434 } 435 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 436 437 @{ @RenderFieldValue(field)} 438 </dd> 439 </div> 440 } 441 if (layout == "list") 442 { 443 if (!hideFieldLabels) 444 { 445 <dt class="g-col-4">@field.Name</dt> 446 } 447 <dd class="g-col-8 mb-0 text-break"> 448 @{ @RenderFieldValue(field)} 449 </dd> 450 } 451 if (layout == "table") 452 { 453 <tr> 454 @if (!hideFieldLabels) 455 { 456 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 457 } 458 <td class="text-break"> 459 @{ @RenderFieldValue(field) } 460 </td> 461 </tr> 462 } 463 if (layout == "bullets") 464 { 465 <li> 466 @if (!hideFieldLabels) 467 { 468 <strong>@field.Name</strong> 469 } 470 <span> 471 @{ @RenderFieldValue(field) } 472 </span> 473 </li> 474 } 475 } 476 } 477 } 478 479 @helper RenderFieldValue(FieldValueViewModel field) 480 { 481 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 482 if (field.SystemName == "ProductWeight") 483 { 484 485 decimal calculatedValue = NumberHelper.ToDecimal(fieldValue); 486 decimal baseValue = NumberHelper.ToDecimal("0,00001"); 487 488 489 fieldValue = calculatedValue.ToString("0.######", System.Globalization.CultureInfo.InvariantCulture).Replace(".", ","); 490 491 } 492 bool isLink = field?.Type == "Link"; 493 bool isColor = false; 494 bool isBrandName = field?.SystemName == "Brand_name"; 495 496 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 497 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 498 499 500 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 501 { 502 int valueCount = 0; 503 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 504 int totalValues = values.Count; 505 506 foreach (FieldOptionValueViewModel option in values) 507 { 508 if (!string.IsNullOrEmpty(option.Value)) 509 { 510 if (option.Value.Substring(0, 1) == "#") 511 { 512 isColor = true; 513 } 514 } 515 516 if (!isColor) 517 { 518 @option.Name 519 } 520 else 521 { 522 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 523 } 524 525 if (valueCount != totalValues && valueCount < (totalValues - 1)) 526 { 527 if (isColor) 528 { 529 <text> </text> 530 } 531 else 532 { 533 <text>, </text> 534 } 535 } 536 valueCount++; 537 } 538 } 539 else 540 { 541 if (fieldValue.Substring(0, 1) == "#") 542 { 543 isColor = true; 544 } 545 546 if (!isColor) 547 { 548 if (isLink) 549 { 550 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 551 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 552 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 553 554 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 555 } 556 else if (isBrandName) 557 { 558 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 559 <span itemprop="name">@fieldValue</span> 560 </span> 561 } 562 else 563 { 564 @fieldValue 565 } 566 567 } 568 else 569 { 570 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 571 } 572 } 573 } 574
Error executing template "Designs/Swift/Paragraph/Swift_ProductSpecification.cshtml" System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at Dynamicweb.Ecommerce.Products.GroupRelation.GetGroupRelationsByChildId(String childId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetOrderedInheritableParentIds(Group group, String defaultLanguageId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupFieldValuesByLanguage(Group group, List`1 categoryFields, String languageId, Boolean isInheritedValue, Boolean searchRecursively) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.SearchForGroupFieldValue(Group group, List`1 categoryFields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupCategoryFieldValues(IEnumerable`1 groups, List`1 fields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValuesFromGroups(IEnumerable`1 groupInfos, List`1 catFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValueFromGroups(IEnumerable`1 groupInfos, Field catField) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String defaultLanguageId, IEnumerable`1 orderedGroups, Field catField, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String categoryId, String fieldId, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetProductCategoryFieldValue(Product product, String categoryId, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, Product product, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetFieldDisplayGroupValues(ProductViewModelSettings settings, Product product, String languageID, Lazy`1 productIds) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.<BulkCreateView>b__60() at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_83c3e920ca6c46f49d5bc5546126d159.Execute() at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) 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 System.Globalization; 4 @functions 5 { 6 public static class NumberHelper 7 { 8 /// <summary> 9 /// Converts a scientific notation string with a comma (e.g. "5,8E-05") to a decimal. 10 /// Returns 0 if the string is invalid or empty. 11 /// </summary> 12 public static decimal ToDecimal(string input) 13 { 14 if (string.IsNullOrWhiteSpace(input)) 15 { 16 return 0m; 17 } 18 19 // Tell the parser to look for a comma 20 var format = new NumberFormatInfo { NumberDecimalSeparator = "," }; 21 22 // TryParse safely attempts to convert without throwing exceptions on bad data 23 if (decimal.TryParse(input, NumberStyles.Float, format, out decimal result)) 24 { 25 return result; 26 } 27 28 return 0m; // Return a default value if parsing fails 29 } 30 } 31 } 32 @{ 33 ProductViewModel product = null; 34 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 35 { 36 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 37 } 38 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 39 { 40 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 41 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 42 43 if (productList?.Products is object) 44 { 45 product = productList.Products[0]; 46 } 47 } 48 } 49 50 @if (product is object && Model?.Item != null) { 51 var displayGroupsRaw = Model.Item.GetRawValueString("DisplayGroups") ?? ""; 52 IEnumerable<string> selectedDisplayGroupIds = 53 displayGroupsRaw.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 54 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 55 56 foreach (var selection in selectedDisplayGroupIds) 57 { 58 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups?.Values ?? Enumerable.Empty<CategoryFieldViewModel>()) 59 { 60 if (selection == group.Id) 61 { 62 int fieldsWithNoValueOrZero = 0; 63 64 foreach (var field in group.Fields) 65 { 66 var value = field.Value?.Value?.ToString(); 67 68 if (string.IsNullOrWhiteSpace(value)) 69 { 70 fieldsWithNoValueOrZero++; 71 } 72 } 73 74 if (fieldsWithNoValueOrZero != group.Fields.Count) 75 { 76 displayGroups.Add(group); 77 } 78 } 79 } 80 } 81 82 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 83 84 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 85 86 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 87 88 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 89 90 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 91 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 92 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 93 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 94 95 string layout = Model.Item.GetRawValueString("Layout", "list"); 96 string size = Model.Item.GetRawValueString("Size", "full"); 97 string gaps = size == "full" ? " gap-4" : " gap-2"; 98 99 100 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 101 { 102 product.ProductFields.Clear(); 103 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 104 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 105 showProductFields = true; 106 } 107 108 if (layout == "commas") 109 { 110 gaps = size == "full" ? " gap-4" : " gap-2"; 111 112 } 113 114 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 115 <div class="grid"> 116 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) { 117 if (!hideTitle) 118 { 119 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 120 } 121 } 122 123 @if (displayGroups.Count != 0) 124 { 125 if (layout != "accordion") 126 { 127 foreach (var group in displayGroups) 128 { 129 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 130 131 if (!hideHeader) { 132 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 133 } 134 135 { @RenderFieldsFromList(group.Fields, layout) } 136 137 } 138 } 139 else 140 { 141 <div class="g-col-12"> 142 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 143 @foreach (var group in displayGroups) 144 { 145 <div class="accordion-item"> 146 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 147 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Id"> 148 @group.Name 149 </button> 150 </h2> 151 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 152 <div class="accordion-body"> 153 @{ @RenderFieldsFromList(group.Fields, "list") } 154 </div> 155 </div> 156 </div> 157 } 158 </div> 159 </div> 160 } 161 } 162 163 @if (product.ProductFields != null && showProductFields) 164 { 165 if (product.ProductFields.Count > 0) 166 { 167 if (layout != "accordion") 168 { 169 {@RenderFieldsFromList(product.ProductFields, layout) } 170 } 171 else 172 { 173 <div class="g-col-12"> 174 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 175 <div class="accordion-item"> 176 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 177 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@Model.ID" aria-expanded="false" aria-controls="SpecificationItem_@Model.ID"> 178 @Translate("Specifications") 179 </button> 180 </h2> 181 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 182 <div class="accordion-body"> 183 @{ @RenderFieldsFromList(product.ProductFields, "List") } 184 </div> 185 </div> 186 </div> 187 </div> 188 </div> 189 } 190 } 191 } 192 193 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 194 { 195 if (product.ProductCategories.Count > 0) 196 { 197 if (layout != "accordion") 198 { 199 foreach (var group in product.ProductCategories) 200 { 201 CategoryFieldViewModel category = group.Value; 202 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 203 204 if (!hideHeader) { 205 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 206 } 207 208 { @RenderFieldsFromList(category.Fields, layout) } 209 } 210 } 211 else 212 { 213 <div class="g-col-12"> 214 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 215 @foreach (var group in product.ProductCategories) 216 { 217 CategoryFieldViewModel category = group.Value; 218 219 <div class="accordion-item"> 220 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 221 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Value.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Value.Id"> 222 @group.Value.Name 223 </button> 224 </h2> 225 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 226 <div class="accordion-body"> 227 @{ @RenderFieldsFromList(category.Fields, "list") } 228 </div> 229 </div> 230 </div> 231 } 232 </div> 233 </div> 234 } 235 } 236 } 237 </div> 238 </div> 239 } 240 else if (Pageview.IsVisualEditorMode) 241 { 242 <div class="alert alert-warning m-0">@Translate("No products available")</div> 243 } 244 245 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 246 { 247 string size = Model.Item.GetRawValueString("Size", "full"); 248 string gaps = size != "full" ? " gap-1" : string.Empty; 249 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 250 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 251 252 if (layout == "columns") { 253 <div class="g-col-12"> 254 <div class="grid@(gaps)"> 255 @foreach (var field in fields) 256 { 257 {@RenderField(field.Value, layout)} 258 } 259 </div> 260 </div> 261 } 262 if (layout == "list") { 263 <div class="g-col-12"> 264 <dl class="grid@(gaps)"> 265 @foreach (var field in fields) 266 { 267 {@RenderField(field.Value, layout)} 268 } 269 </dl> 270 </div> 271 } 272 if (layout == "table") 273 { 274 string tableSize = size == "full" ? "" : " table-sm"; 275 <div class="g-col-12"> 276 <table class="table table-striped@(tableSize)"> 277 @foreach (var field in fields) 278 { 279 {@RenderField(field.Value, layout)} 280 } 281 </table> 282 </div> 283 } 284 if (layout == "bullets") 285 { 286 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 287 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 288 <div class="g-col-12"> 289 <ul class="@listSize" @listStyle> 290 @foreach (var field in fields) 291 { 292 {@RenderField(field.Value, layout)} 293 } 294 </ul> 295 </div> 296 } 297 if (layout == "commas") 298 { 299 List<string> featuresList = new List<string>(); 300 301 foreach (var field in fields) 302 { 303 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 304 305 if (field.Value?.Value != null) 306 { 307 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 308 { 309 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 310 311 //Hack to support field type providers with a single value 312 if (values.FirstOrDefault() != null) 313 { 314 firstListItemValue = values.FirstOrDefault().Value; 315 } 316 } 317 } 318 319 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 320 { 321 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 322 { 323 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 324 { 325 List<string> options = new List<string>(); 326 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 327 { 328 if (!string.IsNullOrWhiteSpace(option.Value)) 329 { 330 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 331 { 332 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 333 options.Add(colorSpan); 334 } 335 else if (!string.IsNullOrEmpty(option.Value)) 336 { 337 options.Add(option.Name); 338 } 339 } 340 } 341 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 342 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 343 { 344 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 345 } 346 347 if (!string.IsNullOrEmpty(optionsString)) 348 { 349 if (!hideFieldLabels) 350 { 351 featuresList.Add(field.Value.Name + ": " + optionsString); 352 } 353 else 354 { 355 featuresList.Add(optionsString); 356 } 357 } 358 } 359 else 360 { 361 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 362 { 363 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 364 { 365 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 366 367 if (!hideFieldLabels) 368 { 369 featuresList.Add(field.Value.Name + ": " + colorSpan); 370 } 371 else 372 { 373 featuresList.Add(colorSpan); 374 } 375 } 376 else 377 { 378 if (!hideFieldLabels) 379 { 380 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 381 } 382 else 383 { 384 featuresList.Add(field.Value.Value.ToString()); 385 } 386 } 387 } 388 } 389 } 390 } 391 } 392 393 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 394 395 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 396 } 397 } 398 399 @helper RenderField(FieldValueViewModel field, string layout) 400 { 401 string size = Model.Item.GetRawValueString("Size", "full"); 402 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 403 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 404 bool noValues = false; 405 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 406 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 407 408 if (!string.IsNullOrEmpty(fieldValue)) 409 { 410 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 411 { 412 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 413 noValues = values.Count > 0 ? false : true; 414 415 //Hack to support field type providers with a single value 416 if (values.FirstOrDefault() != null) 417 { 418 firstListItemValue = values.FirstOrDefault().Value; 419 } 420 } 421 } 422 423 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 424 { 425 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 426 { 427 if (layout == "columns") 428 { 429 430 <div class="grid g-col-6 g-col-lg-4 gap-1"> 431 @if (!hideFieldLabels) 432 { 433 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 434 } 435 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 436 437 @{ @RenderFieldValue(field)} 438 </dd> 439 </div> 440 } 441 if (layout == "list") 442 { 443 if (!hideFieldLabels) 444 { 445 <dt class="g-col-4">@field.Name</dt> 446 } 447 <dd class="g-col-8 mb-0 text-break"> 448 @{ @RenderFieldValue(field)} 449 </dd> 450 } 451 if (layout == "table") 452 { 453 <tr> 454 @if (!hideFieldLabels) 455 { 456 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 457 } 458 <td class="text-break"> 459 @{ @RenderFieldValue(field) } 460 </td> 461 </tr> 462 } 463 if (layout == "bullets") 464 { 465 <li> 466 @if (!hideFieldLabels) 467 { 468 <strong>@field.Name</strong> 469 } 470 <span> 471 @{ @RenderFieldValue(field) } 472 </span> 473 </li> 474 } 475 } 476 } 477 } 478 479 @helper RenderFieldValue(FieldValueViewModel field) 480 { 481 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 482 if (field.SystemName == "ProductWeight") 483 { 484 485 decimal calculatedValue = NumberHelper.ToDecimal(fieldValue); 486 decimal baseValue = NumberHelper.ToDecimal("0,00001"); 487 488 489 fieldValue = calculatedValue.ToString("0.######", System.Globalization.CultureInfo.InvariantCulture).Replace(".", ","); 490 491 } 492 bool isLink = field?.Type == "Link"; 493 bool isColor = false; 494 bool isBrandName = field?.SystemName == "Brand_name"; 495 496 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 497 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 498 499 500 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 501 { 502 int valueCount = 0; 503 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 504 int totalValues = values.Count; 505 506 foreach (FieldOptionValueViewModel option in values) 507 { 508 if (!string.IsNullOrEmpty(option.Value)) 509 { 510 if (option.Value.Substring(0, 1) == "#") 511 { 512 isColor = true; 513 } 514 } 515 516 if (!isColor) 517 { 518 @option.Name 519 } 520 else 521 { 522 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 523 } 524 525 if (valueCount != totalValues && valueCount < (totalValues - 1)) 526 { 527 if (isColor) 528 { 529 <text> </text> 530 } 531 else 532 { 533 <text>, </text> 534 } 535 } 536 valueCount++; 537 } 538 } 539 else 540 { 541 if (fieldValue.Substring(0, 1) == "#") 542 { 543 isColor = true; 544 } 545 546 if (!isColor) 547 { 548 if (isLink) 549 { 550 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 551 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 552 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 553 554 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 555 } 556 else if (isBrandName) 557 { 558 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 559 <span itemprop="name">@fieldValue</span> 560 </span> 561 } 562 else 563 { 564 @fieldValue 565 } 566 567 } 568 else 569 { 570 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 571 } 572 } 573 } 574
Error executing template "Designs/Swift/Paragraph/Swift_ProductSpecification.cshtml" System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at Dynamicweb.Ecommerce.Products.GroupRelation.GetGroupRelationsByChildId(String childId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetOrderedInheritableParentIds(Group group, String defaultLanguageId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupFieldValuesByLanguage(Group group, List`1 categoryFields, String languageId, Boolean isInheritedValue, Boolean searchRecursively) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.SearchForGroupFieldValue(Group group, List`1 categoryFields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupCategoryFieldValues(IEnumerable`1 groups, List`1 fields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValuesFromGroups(IEnumerable`1 groupInfos, List`1 catFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValueFromGroups(IEnumerable`1 groupInfos, Field catField) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String defaultLanguageId, IEnumerable`1 orderedGroups, Field catField, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String categoryId, String fieldId, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetProductCategoryFieldValue(Product product, String categoryId, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, Product product, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetFieldDisplayGroupValues(ProductViewModelSettings settings, Product product, String languageID, Lazy`1 productIds) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.<BulkCreateView>b__60() at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_83c3e920ca6c46f49d5bc5546126d159.Execute() at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) 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 System.Globalization; 4 @functions 5 { 6 public static class NumberHelper 7 { 8 /// <summary> 9 /// Converts a scientific notation string with a comma (e.g. "5,8E-05") to a decimal. 10 /// Returns 0 if the string is invalid or empty. 11 /// </summary> 12 public static decimal ToDecimal(string input) 13 { 14 if (string.IsNullOrWhiteSpace(input)) 15 { 16 return 0m; 17 } 18 19 // Tell the parser to look for a comma 20 var format = new NumberFormatInfo { NumberDecimalSeparator = "," }; 21 22 // TryParse safely attempts to convert without throwing exceptions on bad data 23 if (decimal.TryParse(input, NumberStyles.Float, format, out decimal result)) 24 { 25 return result; 26 } 27 28 return 0m; // Return a default value if parsing fails 29 } 30 } 31 } 32 @{ 33 ProductViewModel product = null; 34 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 35 { 36 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 37 } 38 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 39 { 40 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 41 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 42 43 if (productList?.Products is object) 44 { 45 product = productList.Products[0]; 46 } 47 } 48 } 49 50 @if (product is object && Model?.Item != null) { 51 var displayGroupsRaw = Model.Item.GetRawValueString("DisplayGroups") ?? ""; 52 IEnumerable<string> selectedDisplayGroupIds = 53 displayGroupsRaw.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 54 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 55 56 foreach (var selection in selectedDisplayGroupIds) 57 { 58 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups?.Values ?? Enumerable.Empty<CategoryFieldViewModel>()) 59 { 60 if (selection == group.Id) 61 { 62 int fieldsWithNoValueOrZero = 0; 63 64 foreach (var field in group.Fields) 65 { 66 var value = field.Value?.Value?.ToString(); 67 68 if (string.IsNullOrWhiteSpace(value)) 69 { 70 fieldsWithNoValueOrZero++; 71 } 72 } 73 74 if (fieldsWithNoValueOrZero != group.Fields.Count) 75 { 76 displayGroups.Add(group); 77 } 78 } 79 } 80 } 81 82 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 83 84 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 85 86 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 87 88 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 89 90 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 91 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 92 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 93 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 94 95 string layout = Model.Item.GetRawValueString("Layout", "list"); 96 string size = Model.Item.GetRawValueString("Size", "full"); 97 string gaps = size == "full" ? " gap-4" : " gap-2"; 98 99 100 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 101 { 102 product.ProductFields.Clear(); 103 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 104 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 105 showProductFields = true; 106 } 107 108 if (layout == "commas") 109 { 110 gaps = size == "full" ? " gap-4" : " gap-2"; 111 112 } 113 114 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 115 <div class="grid"> 116 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) { 117 if (!hideTitle) 118 { 119 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 120 } 121 } 122 123 @if (displayGroups.Count != 0) 124 { 125 if (layout != "accordion") 126 { 127 foreach (var group in displayGroups) 128 { 129 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 130 131 if (!hideHeader) { 132 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 133 } 134 135 { @RenderFieldsFromList(group.Fields, layout) } 136 137 } 138 } 139 else 140 { 141 <div class="g-col-12"> 142 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 143 @foreach (var group in displayGroups) 144 { 145 <div class="accordion-item"> 146 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 147 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Id"> 148 @group.Name 149 </button> 150 </h2> 151 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 152 <div class="accordion-body"> 153 @{ @RenderFieldsFromList(group.Fields, "list") } 154 </div> 155 </div> 156 </div> 157 } 158 </div> 159 </div> 160 } 161 } 162 163 @if (product.ProductFields != null && showProductFields) 164 { 165 if (product.ProductFields.Count > 0) 166 { 167 if (layout != "accordion") 168 { 169 {@RenderFieldsFromList(product.ProductFields, layout) } 170 } 171 else 172 { 173 <div class="g-col-12"> 174 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 175 <div class="accordion-item"> 176 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 177 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@Model.ID" aria-expanded="false" aria-controls="SpecificationItem_@Model.ID"> 178 @Translate("Specifications") 179 </button> 180 </h2> 181 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 182 <div class="accordion-body"> 183 @{ @RenderFieldsFromList(product.ProductFields, "List") } 184 </div> 185 </div> 186 </div> 187 </div> 188 </div> 189 } 190 } 191 } 192 193 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 194 { 195 if (product.ProductCategories.Count > 0) 196 { 197 if (layout != "accordion") 198 { 199 foreach (var group in product.ProductCategories) 200 { 201 CategoryFieldViewModel category = group.Value; 202 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 203 204 if (!hideHeader) { 205 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 206 } 207 208 { @RenderFieldsFromList(category.Fields, layout) } 209 } 210 } 211 else 212 { 213 <div class="g-col-12"> 214 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 215 @foreach (var group in product.ProductCategories) 216 { 217 CategoryFieldViewModel category = group.Value; 218 219 <div class="accordion-item"> 220 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 221 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Value.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Value.Id"> 222 @group.Value.Name 223 </button> 224 </h2> 225 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 226 <div class="accordion-body"> 227 @{ @RenderFieldsFromList(category.Fields, "list") } 228 </div> 229 </div> 230 </div> 231 } 232 </div> 233 </div> 234 } 235 } 236 } 237 </div> 238 </div> 239 } 240 else if (Pageview.IsVisualEditorMode) 241 { 242 <div class="alert alert-warning m-0">@Translate("No products available")</div> 243 } 244 245 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 246 { 247 string size = Model.Item.GetRawValueString("Size", "full"); 248 string gaps = size != "full" ? " gap-1" : string.Empty; 249 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 250 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 251 252 if (layout == "columns") { 253 <div class="g-col-12"> 254 <div class="grid@(gaps)"> 255 @foreach (var field in fields) 256 { 257 {@RenderField(field.Value, layout)} 258 } 259 </div> 260 </div> 261 } 262 if (layout == "list") { 263 <div class="g-col-12"> 264 <dl class="grid@(gaps)"> 265 @foreach (var field in fields) 266 { 267 {@RenderField(field.Value, layout)} 268 } 269 </dl> 270 </div> 271 } 272 if (layout == "table") 273 { 274 string tableSize = size == "full" ? "" : " table-sm"; 275 <div class="g-col-12"> 276 <table class="table table-striped@(tableSize)"> 277 @foreach (var field in fields) 278 { 279 {@RenderField(field.Value, layout)} 280 } 281 </table> 282 </div> 283 } 284 if (layout == "bullets") 285 { 286 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 287 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 288 <div class="g-col-12"> 289 <ul class="@listSize" @listStyle> 290 @foreach (var field in fields) 291 { 292 {@RenderField(field.Value, layout)} 293 } 294 </ul> 295 </div> 296 } 297 if (layout == "commas") 298 { 299 List<string> featuresList = new List<string>(); 300 301 foreach (var field in fields) 302 { 303 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 304 305 if (field.Value?.Value != null) 306 { 307 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 308 { 309 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 310 311 //Hack to support field type providers with a single value 312 if (values.FirstOrDefault() != null) 313 { 314 firstListItemValue = values.FirstOrDefault().Value; 315 } 316 } 317 } 318 319 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 320 { 321 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 322 { 323 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 324 { 325 List<string> options = new List<string>(); 326 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 327 { 328 if (!string.IsNullOrWhiteSpace(option.Value)) 329 { 330 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 331 { 332 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 333 options.Add(colorSpan); 334 } 335 else if (!string.IsNullOrEmpty(option.Value)) 336 { 337 options.Add(option.Name); 338 } 339 } 340 } 341 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 342 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 343 { 344 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 345 } 346 347 if (!string.IsNullOrEmpty(optionsString)) 348 { 349 if (!hideFieldLabels) 350 { 351 featuresList.Add(field.Value.Name + ": " + optionsString); 352 } 353 else 354 { 355 featuresList.Add(optionsString); 356 } 357 } 358 } 359 else 360 { 361 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 362 { 363 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 364 { 365 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 366 367 if (!hideFieldLabels) 368 { 369 featuresList.Add(field.Value.Name + ": " + colorSpan); 370 } 371 else 372 { 373 featuresList.Add(colorSpan); 374 } 375 } 376 else 377 { 378 if (!hideFieldLabels) 379 { 380 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 381 } 382 else 383 { 384 featuresList.Add(field.Value.Value.ToString()); 385 } 386 } 387 } 388 } 389 } 390 } 391 } 392 393 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 394 395 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 396 } 397 } 398 399 @helper RenderField(FieldValueViewModel field, string layout) 400 { 401 string size = Model.Item.GetRawValueString("Size", "full"); 402 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 403 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 404 bool noValues = false; 405 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 406 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 407 408 if (!string.IsNullOrEmpty(fieldValue)) 409 { 410 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 411 { 412 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 413 noValues = values.Count > 0 ? false : true; 414 415 //Hack to support field type providers with a single value 416 if (values.FirstOrDefault() != null) 417 { 418 firstListItemValue = values.FirstOrDefault().Value; 419 } 420 } 421 } 422 423 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 424 { 425 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 426 { 427 if (layout == "columns") 428 { 429 430 <div class="grid g-col-6 g-col-lg-4 gap-1"> 431 @if (!hideFieldLabels) 432 { 433 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 434 } 435 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 436 437 @{ @RenderFieldValue(field)} 438 </dd> 439 </div> 440 } 441 if (layout == "list") 442 { 443 if (!hideFieldLabels) 444 { 445 <dt class="g-col-4">@field.Name</dt> 446 } 447 <dd class="g-col-8 mb-0 text-break"> 448 @{ @RenderFieldValue(field)} 449 </dd> 450 } 451 if (layout == "table") 452 { 453 <tr> 454 @if (!hideFieldLabels) 455 { 456 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 457 } 458 <td class="text-break"> 459 @{ @RenderFieldValue(field) } 460 </td> 461 </tr> 462 } 463 if (layout == "bullets") 464 { 465 <li> 466 @if (!hideFieldLabels) 467 { 468 <strong>@field.Name</strong> 469 } 470 <span> 471 @{ @RenderFieldValue(field) } 472 </span> 473 </li> 474 } 475 } 476 } 477 } 478 479 @helper RenderFieldValue(FieldValueViewModel field) 480 { 481 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 482 if (field.SystemName == "ProductWeight") 483 { 484 485 decimal calculatedValue = NumberHelper.ToDecimal(fieldValue); 486 decimal baseValue = NumberHelper.ToDecimal("0,00001"); 487 488 489 fieldValue = calculatedValue.ToString("0.######", System.Globalization.CultureInfo.InvariantCulture).Replace(".", ","); 490 491 } 492 bool isLink = field?.Type == "Link"; 493 bool isColor = false; 494 bool isBrandName = field?.SystemName == "Brand_name"; 495 496 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 497 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 498 499 500 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 501 { 502 int valueCount = 0; 503 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 504 int totalValues = values.Count; 505 506 foreach (FieldOptionValueViewModel option in values) 507 { 508 if (!string.IsNullOrEmpty(option.Value)) 509 { 510 if (option.Value.Substring(0, 1) == "#") 511 { 512 isColor = true; 513 } 514 } 515 516 if (!isColor) 517 { 518 @option.Name 519 } 520 else 521 { 522 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 523 } 524 525 if (valueCount != totalValues && valueCount < (totalValues - 1)) 526 { 527 if (isColor) 528 { 529 <text> </text> 530 } 531 else 532 { 533 <text>, </text> 534 } 535 } 536 valueCount++; 537 } 538 } 539 else 540 { 541 if (fieldValue.Substring(0, 1) == "#") 542 { 543 isColor = true; 544 } 545 546 if (!isColor) 547 { 548 if (isLink) 549 { 550 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 551 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 552 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 553 554 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 555 } 556 else if (isBrandName) 557 { 558 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 559 <span itemprop="name">@fieldValue</span> 560 </span> 561 } 562 else 563 { 564 @fieldValue 565 } 566 567 } 568 else 569 { 570 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 571 } 572 } 573 } 574
Datasheets & Documents
| Name | Download | File type | |
|---|---|---|---|
|
|
gates-design-power-app-sellsheet-en.pdf | 1662 KB |
New column
| Name | Download | File type | |
|---|---|---|---|
|
hi-power-kileremme.png | 1024 KB | .png |
Request additional documents and drawings
Product drawings, documents and brochures of any kind may contain errors for which Brd. Klee is not liable for.
Error executing template "Designs/Swift/Paragraph/Swift_ProductSpecification.cshtml" System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at Dynamicweb.Ecommerce.Products.GroupRelation.GetGroupRelationsByChildId(String childId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetOrderedInheritableParentIds(Group group, String defaultLanguageId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupFieldValuesByLanguage(Group group, List`1 categoryFields, String languageId, Boolean isInheritedValue, Boolean searchRecursively) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.SearchForGroupFieldValue(Group group, List`1 categoryFields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupCategoryFieldValues(IEnumerable`1 groups, List`1 fields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValuesFromGroups(IEnumerable`1 groupInfos, List`1 catFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValueFromGroups(IEnumerable`1 groupInfos, Field catField) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String defaultLanguageId, IEnumerable`1 orderedGroups, Field catField, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String categoryId, String fieldId, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetProductCategoryFieldValue(Product product, String categoryId, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, Product product, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetFieldDisplayGroupValues(ProductViewModelSettings settings, Product product, String languageID, Lazy`1 productIds) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.<BulkCreateView>b__60() at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_83c3e920ca6c46f49d5bc5546126d159.Execute() at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) 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 System.Globalization; 4 @functions 5 { 6 public static class NumberHelper 7 { 8 /// <summary> 9 /// Converts a scientific notation string with a comma (e.g. "5,8E-05") to a decimal. 10 /// Returns 0 if the string is invalid or empty. 11 /// </summary> 12 public static decimal ToDecimal(string input) 13 { 14 if (string.IsNullOrWhiteSpace(input)) 15 { 16 return 0m; 17 } 18 19 // Tell the parser to look for a comma 20 var format = new NumberFormatInfo { NumberDecimalSeparator = "," }; 21 22 // TryParse safely attempts to convert without throwing exceptions on bad data 23 if (decimal.TryParse(input, NumberStyles.Float, format, out decimal result)) 24 { 25 return result; 26 } 27 28 return 0m; // Return a default value if parsing fails 29 } 30 } 31 } 32 @{ 33 ProductViewModel product = null; 34 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 35 { 36 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 37 } 38 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 39 { 40 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 41 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 42 43 if (productList?.Products is object) 44 { 45 product = productList.Products[0]; 46 } 47 } 48 } 49 50 @if (product is object && Model?.Item != null) { 51 var displayGroupsRaw = Model.Item.GetRawValueString("DisplayGroups") ?? ""; 52 IEnumerable<string> selectedDisplayGroupIds = 53 displayGroupsRaw.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 54 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 55 56 foreach (var selection in selectedDisplayGroupIds) 57 { 58 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups?.Values ?? Enumerable.Empty<CategoryFieldViewModel>()) 59 { 60 if (selection == group.Id) 61 { 62 int fieldsWithNoValueOrZero = 0; 63 64 foreach (var field in group.Fields) 65 { 66 var value = field.Value?.Value?.ToString(); 67 68 if (string.IsNullOrWhiteSpace(value)) 69 { 70 fieldsWithNoValueOrZero++; 71 } 72 } 73 74 if (fieldsWithNoValueOrZero != group.Fields.Count) 75 { 76 displayGroups.Add(group); 77 } 78 } 79 } 80 } 81 82 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 83 84 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 85 86 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 87 88 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 89 90 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 91 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 92 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 93 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 94 95 string layout = Model.Item.GetRawValueString("Layout", "list"); 96 string size = Model.Item.GetRawValueString("Size", "full"); 97 string gaps = size == "full" ? " gap-4" : " gap-2"; 98 99 100 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 101 { 102 product.ProductFields.Clear(); 103 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 104 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 105 showProductFields = true; 106 } 107 108 if (layout == "commas") 109 { 110 gaps = size == "full" ? " gap-4" : " gap-2"; 111 112 } 113 114 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 115 <div class="grid"> 116 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) { 117 if (!hideTitle) 118 { 119 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 120 } 121 } 122 123 @if (displayGroups.Count != 0) 124 { 125 if (layout != "accordion") 126 { 127 foreach (var group in displayGroups) 128 { 129 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 130 131 if (!hideHeader) { 132 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 133 } 134 135 { @RenderFieldsFromList(group.Fields, layout) } 136 137 } 138 } 139 else 140 { 141 <div class="g-col-12"> 142 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 143 @foreach (var group in displayGroups) 144 { 145 <div class="accordion-item"> 146 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 147 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Id"> 148 @group.Name 149 </button> 150 </h2> 151 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 152 <div class="accordion-body"> 153 @{ @RenderFieldsFromList(group.Fields, "list") } 154 </div> 155 </div> 156 </div> 157 } 158 </div> 159 </div> 160 } 161 } 162 163 @if (product.ProductFields != null && showProductFields) 164 { 165 if (product.ProductFields.Count > 0) 166 { 167 if (layout != "accordion") 168 { 169 {@RenderFieldsFromList(product.ProductFields, layout) } 170 } 171 else 172 { 173 <div class="g-col-12"> 174 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 175 <div class="accordion-item"> 176 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 177 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@Model.ID" aria-expanded="false" aria-controls="SpecificationItem_@Model.ID"> 178 @Translate("Specifications") 179 </button> 180 </h2> 181 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 182 <div class="accordion-body"> 183 @{ @RenderFieldsFromList(product.ProductFields, "List") } 184 </div> 185 </div> 186 </div> 187 </div> 188 </div> 189 } 190 } 191 } 192 193 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 194 { 195 if (product.ProductCategories.Count > 0) 196 { 197 if (layout != "accordion") 198 { 199 foreach (var group in product.ProductCategories) 200 { 201 CategoryFieldViewModel category = group.Value; 202 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 203 204 if (!hideHeader) { 205 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 206 } 207 208 { @RenderFieldsFromList(category.Fields, layout) } 209 } 210 } 211 else 212 { 213 <div class="g-col-12"> 214 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 215 @foreach (var group in product.ProductCategories) 216 { 217 CategoryFieldViewModel category = group.Value; 218 219 <div class="accordion-item"> 220 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 221 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Value.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Value.Id"> 222 @group.Value.Name 223 </button> 224 </h2> 225 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 226 <div class="accordion-body"> 227 @{ @RenderFieldsFromList(category.Fields, "list") } 228 </div> 229 </div> 230 </div> 231 } 232 </div> 233 </div> 234 } 235 } 236 } 237 </div> 238 </div> 239 } 240 else if (Pageview.IsVisualEditorMode) 241 { 242 <div class="alert alert-warning m-0">@Translate("No products available")</div> 243 } 244 245 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 246 { 247 string size = Model.Item.GetRawValueString("Size", "full"); 248 string gaps = size != "full" ? " gap-1" : string.Empty; 249 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 250 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 251 252 if (layout == "columns") { 253 <div class="g-col-12"> 254 <div class="grid@(gaps)"> 255 @foreach (var field in fields) 256 { 257 {@RenderField(field.Value, layout)} 258 } 259 </div> 260 </div> 261 } 262 if (layout == "list") { 263 <div class="g-col-12"> 264 <dl class="grid@(gaps)"> 265 @foreach (var field in fields) 266 { 267 {@RenderField(field.Value, layout)} 268 } 269 </dl> 270 </div> 271 } 272 if (layout == "table") 273 { 274 string tableSize = size == "full" ? "" : " table-sm"; 275 <div class="g-col-12"> 276 <table class="table table-striped@(tableSize)"> 277 @foreach (var field in fields) 278 { 279 {@RenderField(field.Value, layout)} 280 } 281 </table> 282 </div> 283 } 284 if (layout == "bullets") 285 { 286 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 287 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 288 <div class="g-col-12"> 289 <ul class="@listSize" @listStyle> 290 @foreach (var field in fields) 291 { 292 {@RenderField(field.Value, layout)} 293 } 294 </ul> 295 </div> 296 } 297 if (layout == "commas") 298 { 299 List<string> featuresList = new List<string>(); 300 301 foreach (var field in fields) 302 { 303 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 304 305 if (field.Value?.Value != null) 306 { 307 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 308 { 309 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 310 311 //Hack to support field type providers with a single value 312 if (values.FirstOrDefault() != null) 313 { 314 firstListItemValue = values.FirstOrDefault().Value; 315 } 316 } 317 } 318 319 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 320 { 321 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 322 { 323 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 324 { 325 List<string> options = new List<string>(); 326 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 327 { 328 if (!string.IsNullOrWhiteSpace(option.Value)) 329 { 330 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 331 { 332 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 333 options.Add(colorSpan); 334 } 335 else if (!string.IsNullOrEmpty(option.Value)) 336 { 337 options.Add(option.Name); 338 } 339 } 340 } 341 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 342 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 343 { 344 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 345 } 346 347 if (!string.IsNullOrEmpty(optionsString)) 348 { 349 if (!hideFieldLabels) 350 { 351 featuresList.Add(field.Value.Name + ": " + optionsString); 352 } 353 else 354 { 355 featuresList.Add(optionsString); 356 } 357 } 358 } 359 else 360 { 361 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 362 { 363 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 364 { 365 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 366 367 if (!hideFieldLabels) 368 { 369 featuresList.Add(field.Value.Name + ": " + colorSpan); 370 } 371 else 372 { 373 featuresList.Add(colorSpan); 374 } 375 } 376 else 377 { 378 if (!hideFieldLabels) 379 { 380 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 381 } 382 else 383 { 384 featuresList.Add(field.Value.Value.ToString()); 385 } 386 } 387 } 388 } 389 } 390 } 391 } 392 393 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 394 395 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 396 } 397 } 398 399 @helper RenderField(FieldValueViewModel field, string layout) 400 { 401 string size = Model.Item.GetRawValueString("Size", "full"); 402 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 403 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 404 bool noValues = false; 405 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 406 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 407 408 if (!string.IsNullOrEmpty(fieldValue)) 409 { 410 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 411 { 412 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 413 noValues = values.Count > 0 ? false : true; 414 415 //Hack to support field type providers with a single value 416 if (values.FirstOrDefault() != null) 417 { 418 firstListItemValue = values.FirstOrDefault().Value; 419 } 420 } 421 } 422 423 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 424 { 425 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 426 { 427 if (layout == "columns") 428 { 429 430 <div class="grid g-col-6 g-col-lg-4 gap-1"> 431 @if (!hideFieldLabels) 432 { 433 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 434 } 435 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 436 437 @{ @RenderFieldValue(field)} 438 </dd> 439 </div> 440 } 441 if (layout == "list") 442 { 443 if (!hideFieldLabels) 444 { 445 <dt class="g-col-4">@field.Name</dt> 446 } 447 <dd class="g-col-8 mb-0 text-break"> 448 @{ @RenderFieldValue(field)} 449 </dd> 450 } 451 if (layout == "table") 452 { 453 <tr> 454 @if (!hideFieldLabels) 455 { 456 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 457 } 458 <td class="text-break"> 459 @{ @RenderFieldValue(field) } 460 </td> 461 </tr> 462 } 463 if (layout == "bullets") 464 { 465 <li> 466 @if (!hideFieldLabels) 467 { 468 <strong>@field.Name</strong> 469 } 470 <span> 471 @{ @RenderFieldValue(field) } 472 </span> 473 </li> 474 } 475 } 476 } 477 } 478 479 @helper RenderFieldValue(FieldValueViewModel field) 480 { 481 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 482 if (field.SystemName == "ProductWeight") 483 { 484 485 decimal calculatedValue = NumberHelper.ToDecimal(fieldValue); 486 decimal baseValue = NumberHelper.ToDecimal("0,00001"); 487 488 489 fieldValue = calculatedValue.ToString("0.######", System.Globalization.CultureInfo.InvariantCulture).Replace(".", ","); 490 491 } 492 bool isLink = field?.Type == "Link"; 493 bool isColor = false; 494 bool isBrandName = field?.SystemName == "Brand_name"; 495 496 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 497 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 498 499 500 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 501 { 502 int valueCount = 0; 503 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 504 int totalValues = values.Count; 505 506 foreach (FieldOptionValueViewModel option in values) 507 { 508 if (!string.IsNullOrEmpty(option.Value)) 509 { 510 if (option.Value.Substring(0, 1) == "#") 511 { 512 isColor = true; 513 } 514 } 515 516 if (!isColor) 517 { 518 @option.Name 519 } 520 else 521 { 522 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 523 } 524 525 if (valueCount != totalValues && valueCount < (totalValues - 1)) 526 { 527 if (isColor) 528 { 529 <text> </text> 530 } 531 else 532 { 533 <text>, </text> 534 } 535 } 536 valueCount++; 537 } 538 } 539 else 540 { 541 if (fieldValue.Substring(0, 1) == "#") 542 { 543 isColor = true; 544 } 545 546 if (!isColor) 547 { 548 if (isLink) 549 { 550 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 551 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 552 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 553 554 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 555 } 556 else if (isBrandName) 557 { 558 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 559 <span itemprop="name">@fieldValue</span> 560 </span> 561 } 562 else 563 { 564 @fieldValue 565 } 566 567 } 568 else 569 { 570 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 571 } 572 } 573 } 574
At Brd. Klee A/S we are ISO 9001:2015 certified
Since 1994, Brd. Klee has been ISO certified after 9001:2015 standard by Norske Veritas.
Reasons to choose us
- Over 500.000 products
- Data sheets, manuals og 3D drawings
- Our employees are specialists
- More than 75 years in the industry
We can help you 24/7
You can order and have goods delivered 24 hours a day - all year.
Outside normal opening hours, service costs a fee.
Call us on telephone (+45) 43 86 83 33