Vårt rekommenderade val för staketlösningar, pergolor, tork-, tränings- och gungställningar m.m. Tryckimpregnerad och grundmålad, omlimmad stolpe som tål nedgrävning. Stolpen har fasade kanter och är rakkapad i båda ändarna.
För extra skydd av stolpen rekommenderar vi att köpa till stolphatt för staketlösningar samt Cubic beslag för uppbyggnad av pergolor, tork-, tränings- och gungställningar m.m.
Error executing template "Designs/Swift/Paragraph/Swift_ProductSpecification_EA.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at CompiledRazorTemplates.Dynamic.RazorEngine_0fe51ee60ee54728a5068cd94d202e2d.<>c__DisplayClass30_0.<RenderArticle>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\ContextAnd\Plus_Prod\Files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification_EA.cshtml:line 1250 at CompiledRazorTemplates.Dynamic.RazorEngine_0fe51ee60ee54728a5068cd94d202e2d.<>c__DisplayClass27_0.<RenderField>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\ContextAnd\Plus_Prod\Files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification_EA.cshtml:line 983 at CompiledRazorTemplates.Dynamic.RazorEngine_0fe51ee60ee54728a5068cd94d202e2d.<>c__DisplayClass26_0.<RenderFieldsFromList>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\ContextAnd\Plus_Prod\Files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification_EA.cshtml:line 823 at CompiledRazorTemplates.Dynamic.RazorEngine_0fe51ee60ee54728a5068cd94d202e2d.Execute() in D:\dynamicweb.net\Solutions\ContextAnd\Plus_Prod\Files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification_EA.cshtml:line 409 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 3 @using Dynamicweb.Frontend 4 @using System.IO 5 @using Dynamicweb.Ecommerce.ProductCatalog 6 7 @functions { 8 public ProductViewModel product { get; set; } = new ProductViewModel(); 9 public string galleryLayout { get; set; } 10 public string[] supportedImageFormats { get; set; } 11 public string[] supportedVideoFormats { get; set; } 12 public string[] supportedDocumentFormats { get; set; } 13 public string[] allSupportedFormats { get; set; } 14 15 public class RatioSettings 16 { 17 public string Ratio { get; set; } 18 public string CssClass { get; set; } 19 public string CssVariable { get; set; } 20 public string Fill { get; set; } 21 } 22 23 public RatioSettings GetRatioSettings(string size = "desktop") 24 { 25 var ratioSettings = new RatioSettings(); 26 27 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 28 ratio = ratio != "0" ? ratio : ""; 29 string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 30 string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 31 cssClass = ratio == "fill" && size == "mobile" ? " ratio" : cssClass; 32 cssVariable = ratio == "fill" && size == "mobile" ? "--bs-aspect-ratio: 66%" : cssVariable; 33 34 ratioSettings.Ratio = ratio; 35 ratioSettings.CssClass = cssClass; 36 ratioSettings.CssVariable = cssVariable; 37 ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; 38 39 return ratioSettings; 40 } 41 } 42 @{ 43 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 44 45 ProductViewModel product = new ProductViewModel(); 46 47 ProductViewModelSettings productSetting = new ProductViewModelSettings 48 { 49 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 50 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 51 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 52 ShopId = Pageview.Area.EcomShopId 53 }; 54 55 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 56 { 57 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 58 } 59 else if (Pageview.Item["DummyProduct"] != null) 60 { 61 62 string dummyProductId = ""; 63 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 64 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 65 if (productList.Products != null) 66 { 67 foreach (var p in productList.Products) { dummyProductId = p.Id; } 68 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel(); 69 product = dummyProduct; 70 } 71 else 72 { 73 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 74 } 75 } 76 else if (Pageview.Item["DummyProduct"] == null) 77 { 78 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 79 } 80 } 81 82 @if (product?.Id != null) 83 { 84 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetRawValueString("DisplayGroups").Split(',').ToList(); 85 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 86 87 foreach (var selection in selectedDisplayGroupIds) 88 { 89 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 90 { 91 if (selection == group.Id) 92 { 93 displayGroups.Add(group); 94 } 95 } 96 } 97 98 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 99 100 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 101 102 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 103 104 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 105 106 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 107 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 108 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 109 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 110 111 string layout = Model.Item.GetRawValueString("Layout", "list"); 112 string size = Model.Item.GetRawValueString("Size", "full"); 113 string gaps = size == "full" ? " gap-4" : " gap-2"; 114 115 //IDictionary<string, string> customFscFields = new Dictionary<string, string>(); 116 //var anyFscDisplayGrps = false; 117 IDictionary<string, string> customDisplayFields = new Dictionary<string, string>(); 118 var anyCustomDisplayGrps = false; 119 var montagevejledningField = product.ProductFields.TryGetValue("InstallationPdf", out FieldValueViewModel installationPdf); 120 var overensstemmelseserklæringField = product.ProductFields.TryGetValue("CompliancePdf", out FieldValueViewModel compliancePdf); 121 var styrkeberegningerField = product.ProductFields.TryGetValue("StacticCalculationsPDF", out FieldValueViewModel stacticCalculationsPDF); 122 product.ProductFields.TryGetValue("DokumentsPDF", out FieldValueViewModel dokumentsPDF); 123 var fscField = product.ProductFields.TryGetValue("FSC", out FieldValueViewModel fscTag); 124 var fscLinkField = product.ProductFields.TryGetValue("FSC_link", out FieldValueViewModel fscLinkTag); 125 var pefcLinkField = product.ProductFields.TryGetValue("PEFC_link", out FieldValueViewModel pefcLinkTag); 126 var videoLinkField = product.ProductFields.TryGetValue("VideoLink", out FieldValueViewModel videoLinkTag); 127 var iconPath = "/Files/Templates/Designs/Swift/Assets/Icons/"; 128 var imageIcon = "file-image.svg"; 129 var pdfIcon = "file-pdf.svg"; 130 var fileIcon = "file-regular.svg"; 131 var fscIcon = "file-fsc.svg"; 132 var pefcIcon = "file-pefc.svg"; 133 string colCount = ""; 134 135 136 if (!String.IsNullOrEmpty(fscTag.Value.ToString())) 137 { 138 if (fscTag.Value.ToString().ToLower().Contains("fsc")) 139 { 140 customDisplayFields.Add(fscTag.Value.ToString(), fscLinkTag.Value.ToString()); 141 } 142 if (fscTag.Value.ToString().ToLower().Contains("pefc")) 143 { 144 customDisplayFields.Add(fscTag.Value.ToString(), pefcLinkTag.Value.ToString()); 145 } 146 anyCustomDisplayGrps = true; 147 } 148 149 if (!String.IsNullOrEmpty(installationPdf.Value.ToString())) 150 { 151 customDisplayFields.Add(installationPdf.Name.ToString(), installationPdf.Value.ToString()); 152 anyCustomDisplayGrps = true; 153 } 154 if (!String.IsNullOrEmpty(compliancePdf.Value.ToString())) 155 { 156 customDisplayFields.Add(compliancePdf.Name.ToString(), compliancePdf.Value.ToString()); 157 anyCustomDisplayGrps = true; 158 } 159 if (!String.IsNullOrEmpty(stacticCalculationsPDF.Value.ToString())) 160 { 161 customDisplayFields.Add(stacticCalculationsPDF.Name.ToString(), stacticCalculationsPDF.Value.ToString()); 162 anyCustomDisplayGrps = true; 163 } 164 if (!String.IsNullOrEmpty(dokumentsPDF.Value.ToString())) 165 { 166 customDisplayFields.Add(dokumentsPDF.Name.ToString(), dokumentsPDF.Value.ToString()); 167 anyCustomDisplayGrps = true; 168 } 169 if (!String.IsNullOrEmpty(videoLinkTag.Value.ToString())) 170 { 171 customDisplayFields.Add(videoLinkTag.Name.ToString(), videoLinkTag.Value.ToString()); 172 anyCustomDisplayGrps = true; 173 } 174 175 176 177 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 178 { 179 product.ProductFields.Clear(); 180 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 181 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 182 showProductFields = true; 183 } 184 185 if (layout == "commas") 186 { 187 gaps = size == "full" ? " gap-4" : " gap-2"; 188 189 } 190 191 <div class="grid h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 192 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) 193 { 194 if (!hideTitle) 195 { 196 <h2 class="g-col-12 @titleFontSize mb-0">@Model.Item.GetString("Title")</h2> 197 } 198 } 199 200 @if (displayGroups.Count != 0) 201 { 202 if (layout != "accordion") 203 { 204 foreach (var group in displayGroups) 205 { 206 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 207 208 if (!hideHeader) 209 { 210 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 211 } 212 213 { @RenderFieldsFromList(group.Fields, layout, colCount) } 214 } 215 } 216 else 217 { 218 <div class="g-col-12"> 219 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 220 @foreach (var group in displayGroups) 221 { 222 <div class="accordion-item"> 223 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 224 <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"> 225 @group.Name 226 </button> 227 </h2> 228 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 229 <div class="accordion-body"> 230 @{ @RenderFieldsFromList(group.Fields, "list", colCount) } 231 </div> 232 </div> 233 </div> 234 } 235 </div> 236 </div> 237 } 238 } 239 240 @if (product.ProductFields != null && showProductFields) 241 { 242 if (product.ProductFields.Count > 0) 243 { 244 if (layout != "accordion") 245 { 246 {@RenderFieldsFromList(product.ProductFields, layout, colCount) } 247 } 248 else 249 { 250 <div class="g-col-12"> 251 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 252 <div class="accordion-item"> 253 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 254 <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"> 255 @Translate("Specifications") 256 </button> 257 </h2> 258 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 259 <div class="accordion-body"> 260 @{ @RenderFieldsFromList(product.ProductFields, "List", colCount) } 261 </div> 262 </div> 263 </div> 264 </div> 265 </div> 266 } 267 } 268 } 269 270 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 271 { 272 if (product.ProductCategories.Count > 0) 273 { 274 if (layout != "accordion") 275 { 276 foreach (var group in product.ProductCategories) 277 { 278 CategoryFieldViewModel category = group.Value; 279 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 280 281 if (!hideHeader) 282 { 283 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 284 } 285 286 { @RenderFieldsFromList(category.Fields, layout, "") } 287 } 288 } 289 else 290 { 291 <div class="g-col-12"> 292 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 293 @foreach (var group in product.ProductCategories) 294 { 295 CategoryFieldViewModel category = group.Value; 296 297 <div class="accordion-item"> 298 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 299 <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"> 300 @group.Key 301 </button> 302 </h2> 303 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 304 <div class="accordion-body"> 305 @{ @RenderFieldsFromList(category.Fields, "list", colCount) } 306 </div> 307 </div> 308 </div> 309 } 310 </div> 311 </div> 312 } 313 } 314 } 315 316 @{ string displayGroupsList = ""; 317 string divider = ""; 318 foreach (var group in displayGroups) 319 { 320 displayGroupsList = "tab_" + group.Id + "," + "SpecificationItem_" + group.Id + divider + displayGroupsList; 321 divider = ","; 322 } } 323 324 @if (displayGroups.Count != 0) 325 { 326 if (layout != "navtabs") 327 { 328 foreach (var group in displayGroups) 329 { 330 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 331 332 if (!hideHeader) 333 { 334 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 335 } 336 337 { @RenderFieldsFromList(group.Fields, layout, colCount) } 338 } 339 } 340 else 341 { 342 bool first = true; 343 var displayNumber = 0; 344 var customDisplayGrpouPos = 3; 345 346 <div class="g-col-12 diplay-fields efa-mod d-none d-sm-block"> 347 <ul class="nav nav-pills px-3 px-md-5 px-lg-7" id="pills-tab" role="tablist"> 348 @{ foreach (var tab in displayGroups) 349 { 350 displayNumber++; 351 if (first) 352 { 353 <li class="nav-item pe-5 py-2 py-md-2" role="presentation"> 354 <button class="nav-link active text-uppercase fc-dark bg-transparent p-0 efa-mod" id="@tab.Id-tab" onclick="toggleReset('tab_@tab.Id')" data-bs-toggle="tab" data-bs-target="#tab_@tab.Id" type="button" role="tab" aria-controls="@tab.Id" aria-selected="true">@tab.Name</button> 355 </li> 356 first = false; 357 } 358 else 359 { 360 <li class="nav-item @displayGroups.Count || @displayNumber pe-5 py-2 py-md-2" role="presentation"> 361 <button class="nav-link text-uppercase fc-dark bg-transparent p-0 efa-mod" id="@tab.Id-tab" onclick="toggleReset('tab_@tab.Id')" data-bs-toggle="tab" data-bs-target="#tab_@tab.Id" type="button" role="tab" aria-controls="@tab.Id" aria-selected="false">@tab.Name</button> 362 </li> 363 } 364 if (displayNumber == customDisplayGrpouPos || (displayNumber == displayGroups.Count && displayNumber <= customDisplayGrpouPos)) 365 { 366 if (anyCustomDisplayGrps) 367 { 368 <li class="nav-item pe-5 py-2 py-md-2" role="presentation"> 369 <button class="nav-link text-uppercase fc-dark bg-transparent p-0 efa-mod" id="@Translate("Documents_downloads")-tab" onclick="toggleReset('tab_@Translate("Documents_downloads")')" data-bs-toggle="tab" data-bs-target="#tab_@Translate("Documents_downloads")" type="button" role="tab" aria-controls="@Translate("Documents_downloads")" aria-selected="false">@Translate("Documents/downloads")</button> 370 </li> 371 } 372 } 373 } 374 displayNumber = 0; } 375 </ul> 376 @{ first = true; } 377 <div class="tab-content bg-super-light efa-mod px-3 px-md-5 px-lg-7 py-4 py-md-5" id="pills-tabContent"> 378 @{ 379 foreach (var item in displayGroups) 380 { 381 displayNumber++; 382 383 if (item.Fields.Count >= 4) 384 { 385 colCount = "g-col-md-6 g-col-lg-4 g-col-xl-3"; 386 } 387 else if (item.Fields.Count == 3) 388 { 389 colCount = "g-col-md-6 g-col-lg-4"; 390 } 391 else if (item.Fields.Count == 2) 392 { 393 colCount = "g-col-md-6 g-col-lg-6"; 394 } 395 else 396 { 397 colCount = ""; 398 } 399 400 @*foreach(var field in item.Fields) { 401 <p><strong>@item.Id</strong></p> 402 <p>@field.Key</p> 403 }*@ 404 405 if (first) 406 { 407 <div class="tab-pane fade show active collapsed efa-mod" id="tab_@item.Id" role="tabpanel" aria-labelledby=""> 408 <div> 409 @{ @RenderFieldsFromList(item.Fields, "display-fields", colCount) } 410 </div> 411 <div class="readmore-overlay efa-mod"> 412 <div class="readmore-overlay_button fs-7 fc-grey efa-mod" onclick="readMore('tab_@item.Id')"> 413 @Translate("Read more") 414 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16"> 415 <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" /> 416 </svg> 417 </div> 418 </div> 419 </div> 420 first = false; 421 } 422 else 423 { 424 425 <div class="tab-pane fade collapsed efa-mod" id="tab_@item.Id" role="tabpanel" aria-labelledby=""> 426 <div> 427 @{ @RenderFieldsFromList(item.Fields, "display-fields", colCount) } 428 </div> 429 <div class="readmore-overlay efa-mod"> 430 <div class="readmore-overlay_button fs-7 fc-grey efa-mod" onclick="readMore('tab_@item.Id')"> 431 @Translate("Read more") 432 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16"> 433 <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" /> 434 </svg> 435 </div> 436 </div> 437 </div> 438 } 439 440 if (displayNumber == customDisplayGrpouPos || (displayNumber == displayGroups.Count && displayNumber <= customDisplayGrpouPos)) 441 { 442 if (anyCustomDisplayGrps) 443 { 444 string icon = ""; 445 446 <div class="tab-pane fade collapsed efa-mod" id="tab_@Translate("Documents_downloads")" role="tabpanel" aria-labelledby=""> 447 <div> 448 <div class="g-col-12 grid gap-0"> 449 450 @{ 451 if (customDisplayFields.Count >= 4) 452 { 453 colCount = "g-col-md-6 g-col-lg-4 g-col-xl-3"; 454 } 455 else if (customDisplayFields.Count == 3) 456 { 457 colCount = "g-col-md-6 g-col-lg-4"; 458 } 459 else if (customDisplayFields.Count == 2) 460 { 461 colCount = "g-col-md-6 g-col-lg-6"; 462 } 463 else 464 { 465 colCount = ""; 466 } 467 } 468 469 @foreach (var field in customDisplayFields) 470 { 471 if(field.Key.Contains("Video")) { 472 <div class="g-col-12 @colCount mb-3 pe-0 pe-md-4 align-items-center"> 473 @RenderVideoPreview(field.Value, field.Key) 474 </div> 475 } 476 else 477 { 478 <div class="g-col-12 @colCount mb-3 pe-0 pe-md-4 d-flex align-items-center"> 479 @if (field.Key.Contains("FSC")) 480 { 481 icon = iconPath + fscIcon; 482 } 483 else if (field.Key.Contains("PEFC")) 484 { 485 icon = iconPath + pefcIcon; 486 } 487 else if (field.Value.Contains(".pdf")) 488 { 489 icon = iconPath + pdfIcon; 490 } 491 else if (field.Value.Contains(".png") || field.Value.Contains(".jpg") || field.Value.Contains(".jpeg")) 492 { 493 icon = iconPath + imageIcon; 494 } 495 else 496 { 497 icon = iconPath + fileIcon; 498 } 499 <span class="me-2 icon-3 efa-mod"> 500 @ReadFile(icon) 501 </span> 502 <a name="@icon" class="fw-bold m-0" href="@field.Value" title="@field.Key" target="_blank" rel="noopener"> 503 <p class="m-0">@field.Key</p> 504 </a> 505 </div> 506 507 } 508 } 509 </div> 510 </div> 511 <div class="readmore-overlay efa-mod"> 512 <div class="readmore-overlay_button fs-7 fc-grey efa-mod" onclick="readMore('tab_@Translate("Documents_downloads")')"> 513 @Translate("Read more") 514 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16"> 515 <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" /> 516 </svg> 517 </div> 518 </div> 519 </div> 520 } 521 } 522 523 } 524 525 displayNumber = 0; } 526 </div> 527 </div> 528 529 <div class="g-col-12 d-block d-sm-none"> 530 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 531 @{ 532 foreach (var group in displayGroups) 533 { 534 displayNumber++; 535 536 if (group.Fields.Count >= 4) 537 { 538 colCount = "g-col-md-6 g-col-lg-4 g-col-xl-3"; 539 } 540 else if (group.Fields.Count == 3) 541 { 542 colCount = "g-col-md-6 g-col-lg-4"; 543 } 544 else if (group.Fields.Count == 2) 545 { 546 colCount = "g-col-md-6 g-col-lg-6"; 547 } 548 else 549 { 550 colCount = ""; 551 } 552 553 <div class="accordion-item"> 554 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 555 <button class="accordion-button collapsed text-uppercase fc-dark efa-mod" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Id"> 556 @group.Name 557 </button> 558 </h2> 559 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse collapsed efa-mod" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 560 <div class="accordion-body bg-super-light efa-mod"> 561 @{ @RenderFieldsFromList(group.Fields, "display-fields", colCount) } 562 </div> 563 <div class="readmore-overlay pb-3 efa-mod"> 564 <div class="readmore-overlay_button fs-7 fc-grey efa-mod" onclick="readMore('SpecificationItem_@group.Id')"> 565 @Translate("Read more") 566 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16"> 567 <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" /> 568 </svg> 569 </div> 570 </div> 571 </div> 572 </div> 573 if (displayNumber == customDisplayGrpouPos || (displayNumber == displayGroups.Count && displayNumber <= customDisplayGrpouPos)) 574 { 575 if (anyCustomDisplayGrps) 576 { 577 string icon = ""; 578 579 <div class="accordion-item"> 580 <h2 class="accordion-header" id="SpecificationHeading_@Translate("Documents_downloads")"> 581 <button class="accordion-button collapsed text-uppercase fc-dark efa-mod" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@Translate("Documents_downloads")" aria-expanded="false" aria-controls="SpecificationItem_@Translate("Documents_downloads")"> 582 @Translate("Documents/downloads") 583 </button> 584 </h2> 585 <div id="SpecificationItem_@Translate("Documents_downloads")" class="accordion-collapse collapse collapsed efa-mod" aria-labelledby="SpecificationHeading_@Translate("Documents_downloads")" data-bs-parent="#Specifications_@Model.ID"> 586 <div class="accordion-body bg-super-light efa-mod"> 587 <div class="g-col-12 grid gap-0"> 588 589 @{ 590 if (customDisplayFields.Count >= 4) 591 { 592 colCount = "g-col-md-6 g-col-lg-4 g-col-xl-3"; 593 } 594 else if (customDisplayFields.Count == 3) 595 { 596 colCount = "g-col-md-6 g-col-lg-4"; 597 } 598 else if (customDisplayFields.Count == 2) 599 { 600 colCount = "g-col-md-6 g-col-lg-6"; 601 } 602 else 603 { 604 colCount = ""; 605 } 606 } 607 608 @foreach (var field in customDisplayFields) 609 { 610 if(field.Key.Contains("Video")) { 611 <div class="g-col-12 @colCount mb-3 pe-0 pe-md-4 d-flex align-items-start"> 612 @RenderVideoPreview(field.Value, field.Key) 613 </div> 614 615 } else { 616 <div class="g-col-12 @colCount mb-3 pe-0 pe-md-4 d-flex align-items-start"> 617 618 @if (field.Key.Contains("FSC")) 619 { 620 icon = iconPath + fscIcon; 621 } 622 else if (field.Key.Contains("PEFC")) 623 { 624 icon = iconPath + pefcIcon; 625 } 626 else if (field.Value.Contains(".pdf")) 627 { 628 icon = iconPath + pdfIcon; 629 } 630 else if (field.Value.Contains(".png") || field.Value.Contains(".jpg") || field.Value.Contains(".jpeg")) 631 { 632 icon = iconPath + imageIcon; 633 } 634 else 635 { 636 icon = iconPath + fileIcon; 637 } 638 <span class="me-2 icon-3 efa-mod"> 639 @ReadFile(icon) 640 </span> 641 <a class="fw-bold m-0" href="@field.Value" title="@field.Key" target="_blank" rel="noopener"> 642 <p class="m-0">@field.Key</p> 643 </a> 644 645 </div> 646 } 647 } 648 </div> 649 </div> 650 <div class="readmore-overlay pb-3 efa-mod"> 651 <div class="readmore-overlay_button fs-7 fc-grey efa-mod" onclick="readMore('SpecificationItem_@Translate("Documents_downloads")')"> 652 @Translate("Read more") 653 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16"> 654 <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" /> 655 </svg> 656 </div> 657 </div> 658 </div> 659 </div> 660 } 661 } 662 } 663 664 displayNumber = 0; 665 } 666 </div> 667 </div> 668 <script type="text/javascript"> 669 670 var displayGroups = '@displayGroupsList'; 671 var displayGroupList = displayGroups.split(','); 672 673 for (var i = 0; i < displayGroupList.length; i++) { 674 675 let elem = document.getElementById(displayGroupList[i]); 676 677 const observer = new ResizeObserver(change => { 678 const tapElem = change[0]; 679 if (tapElem.contentRect.height > 600) { 680 elem.classList.add('readmore-container'); 681 } 682 }); 683 observer.observe(elem); 684 } 685 686 function toggleReset(id) { 687 // Reset read-more state when switching desktop tabs. 688 // This prevents the old inline onclick from throwing: "toogleReset is not defined". 689 let tabPanes = document.querySelectorAll(".tab-pane.efa-mod"); 690 tabPanes.forEach(function (pane) { 691 pane.classList.add("collapsed"); 692 }); 693 694 let element = document.getElementById(id); 695 if (element) { 696 element.classList.add("collapsed"); 697 } 698 699 let toggleButtons = document.querySelectorAll(".readmore-overlay_button"); 700 toggleButtons.forEach(function (toggleElement) { 701 let chevronIcon = toggleElement.querySelector("svg"); 702 toggleElement.innerHTML = '@Translate("Read more")'; 703 704 if (chevronIcon) { 705 toggleElement.appendChild(chevronIcon); 706 } 707 }); 708 }; 709 710 function readMore(id) { 711 let element = document.getElementById(id); 712 element.classList.toggle('collapsed'); 713 714 let toggleElement = document.querySelector(`.readmore-overlay_button[onclick="readMore('${id}')"]`); 715 if (toggleElement) { 716 let chevronIcon = toggleElement.querySelector("svg"); // Keep the chevron icon 717 toggleElement.innerHTML = element.classList.contains('collapsed') 718 ? '@Translate("Read more")' 719 : '@Translate("Read less")'; 720 721 if (chevronIcon) { 722 toggleElement.appendChild(chevronIcon); // Reattach the chevron icon 723 } 724 } 725 }; 726 </script> 727 } 728 } 729 730 @if (product.ProductFields != null && showProductFields) 731 { 732 if (product.ProductFields.Count > 0) 733 { 734 if (layout != "navtabs") 735 { 736 {@RenderFieldsFromList(product.ProductFields, layout, "") } 737 } 738 else 739 { 740 <div class="g-col-12"> 741 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 742 <div class="accordion-item"> 743 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 744 <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"> 745 @Translate("Specifications") 746 </button> 747 </h2> 748 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 749 <div class="accordion-body"> 750 @{ @RenderFieldsFromList(product.ProductFields, "List", colCount) } 751 </div> 752 </div> 753 </div> 754 </div> 755 </div> 756 } 757 } 758 } 759 760 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 761 { 762 if (product.ProductCategories.Count > 0) 763 { 764 if (layout != "navtabs") 765 { 766 foreach (var group in product.ProductCategories) 767 { 768 CategoryFieldViewModel category = group.Value; 769 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 770 771 if (!hideHeader) 772 { 773 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 774 } 775 776 { @RenderFieldsFromList(category.Fields, layout, colCount) } 777 } 778 } 779 else 780 { 781 <div class="g-col-12"> 782 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 783 @foreach (var group in product.ProductCategories) 784 { 785 CategoryFieldViewModel category = group.Value; 786 787 <div class="accordion-item"> 788 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 789 <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"> 790 @group.Key 791 </button> 792 </h2> 793 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 794 <div class="accordion-body"> 795 @{ @RenderFieldsFromList(category.Fields, "list", colCount) } 796 </div> 797 </div> 798 </div> 799 } 800 </div> 801 </div> 802 } 803 } 804 } 805 </div> 806 } 807 else if (Pageview.IsVisualEditorMode) 808 { 809 <div class="alert alert-warning m-0">@Translate("No products available")</div> 810 } 811 812 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout, string colCount) 813 { 814 string size = Model.Item.GetRawValueString("Size", "full"); 815 string gaps = size != "full" ? " gap-1" : string.Empty; 816 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 817 818 if (layout == "display-fields") 819 { 820 <div class="g-col-12 grid gap-0"> 821 @foreach (var field in fields) 822 { 823 {@RenderField(field.Value, layout, colCount)} 824 } 825 </div> 826 } 827 if (layout == "columns") 828 { 829 <div class="g-col-12 grid@(gaps)"> 830 @foreach (var field in fields) 831 { 832 {@RenderField(field.Value, layout, "")} 833 } 834 </div> 835 } 836 if (layout == "list") 837 { 838 <dl class="g-col-12 grid@(gaps)"> 839 @foreach (var field in fields) 840 { 841 {@RenderField(field.Value, layout, "")} 842 } 843 </dl> 844 } 845 if (layout == "table") 846 { 847 string tableSize = size == "full" ? "" : " table-sm"; 848 <div class="g-col-12"> 849 <table class="table table-striped@(tableSize)"> 850 @foreach (var field in fields) 851 { 852 {@RenderField(field.Value, layout, "")} 853 } 854 </table> 855 </div> 856 } 857 if (layout == "bullets") 858 { 859 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 860 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 861 <div class="g-col-12"> 862 <ul class="@listSize" @listStyle> 863 @foreach (var field in fields) 864 { 865 {@RenderField(field.Value, layout, "")} 866 } 867 </ul> 868 </div> 869 } 870 if (layout == "commas") 871 { 872 List<string> featuresList = new List<string>(); 873 874 foreach (var field in fields) 875 { 876 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 877 { 878 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 879 { 880 List<string> options = new List<string>(); 881 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 882 { 883 if (!string.IsNullOrWhiteSpace(option.Value)) 884 { 885 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 886 { 887 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 888 options.Add(colorSpan); 889 } 890 else if (!string.IsNullOrEmpty(option.Value)) 891 { 892 options.Add(option.Name); 893 } 894 } 895 } 896 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 897 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 898 { 899 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 900 } 901 902 if (!hideFieldLabels) 903 { 904 featuresList.Add(field.Value.Name + ": " + optionsString); 905 } 906 else 907 { 908 featuresList.Add(optionsString); 909 } 910 } 911 else 912 { 913 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 914 { 915 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 916 { 917 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 918 919 if (!hideFieldLabels) 920 { 921 featuresList.Add(field.Value.Name + ": " + colorSpan); 922 } 923 else 924 { 925 featuresList.Add(colorSpan); 926 } 927 } 928 else 929 { 930 if (!hideFieldLabels) 931 { 932 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 933 } 934 else 935 { 936 featuresList.Add(field.Value.Value.ToString()); 937 } 938 } 939 } 940 } 941 } 942 } 943 944 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 945 946 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 947 } 948 } 949 950 @helper RenderField(FieldValueViewModel field, string layout, string colCount) 951 { 952 string size = Model.Item.GetRawValueString("Size", "full"); 953 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 954 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 955 bool noValues = false; 956 string orderLast = ""; 957 958 if (!string.IsNullOrEmpty(fieldValue)) 959 { 960 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 961 { 962 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 963 noValues = values.Count > 0 ? false : true; 964 } 965 } 966 967 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 968 { 969 if (layout == "display-fields") 970 { 971 if (fieldValue == "1") { 972 orderLast = "order-last"; 973 } 974 975 <div class="g-col-12 @colCount @orderLast mb-3 pe-0 pe-md-4"> 976 977 @if (field.SystemName.Contains("InspirationArticleTabId")) 978 { 979 var dummy = false; 980 if (fieldValue == "1") { 981 dummy = true; 982 } else { 983 @RenderArticle(fieldValue, dummy) 984 } 985 } 986 else 987 { 988 if (!hideFieldLabels) 989 { 990 if (field?.SystemName != "ProductLongDescription") 991 { 992 if (Dynamicweb.Ecommerce.Common.Context.LanguageID == "LANG2") 993 { 994 <p class="fw-bold m-0">@Translate(field?.Name):</p> 995 } 996 else 997 { 998 <p class="fw-bold m-0">@field.Name:</p> 999 } 1000 } 1001 } 1002 <p class="text-break m-0"> 1003 @{ @RenderFieldValue(field) } 1004 </p> 1005 } 1006 </div> 1007 } 1008 if (layout == "columns") 1009 { 1010 1011 <div class="grid g-col-6 g-col-lg-4 gap-1"> 1012 @if (!hideFieldLabels) 1013 { 1014 if (field?.SystemName != "ProductLongDescription") 1015 { 1016 if (Dynamicweb.Ecommerce.Common.Context.LanguageID == "LANG2") 1017 { 1018 <dt class="g-col-12 g-col-lg-4">@Translate(field?.Name)</dt> 1019 } 1020 else 1021 { 1022 <dt class="g-col-12 g-col-lg-4">@field?.Name</dt> 1023 } 1024 } 1025 } 1026 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 1027 @{ @RenderFieldValue(field) } 1028 </dd> 1029 </div> 1030 } 1031 if (layout == "list") 1032 { 1033 if (!hideFieldLabels) 1034 { 1035 if (field?.SystemName != "ProductLongDescription") 1036 { 1037 if (Dynamicweb.Ecommerce.Common.Context.LanguageID == "LANG2") 1038 { 1039 <dt class="g-col-4">@Translate(field?.Name)</dt> 1040 } 1041 else 1042 { 1043 <dt class="g-col-4">@field?.Name</dt> 1044 } 1045 } 1046 } 1047 <dd class="g-col-8 mb-0 text-break"> 1048 @{ @RenderFieldValue(field) } 1049 </dd> 1050 } 1051 if (layout == "table") 1052 { 1053 <tr> 1054 @if (!hideFieldLabels) 1055 { 1056 if (field?.SystemName != "ProductLongDescription") 1057 { 1058 if (Dynamicweb.Ecommerce.Common.Context.LanguageID == "LANG2") 1059 { 1060 <th class="w-25 w-lg-50" scope="row">@Translate(field?.Name)</th> 1061 } 1062 else 1063 { 1064 <th class="w-25 w-lg-50" scope="row">@field?.Name</th> 1065 } 1066 } 1067 } 1068 <td class="text-break"> 1069 @{ @RenderFieldValue(field) } 1070 </td> 1071 </tr> 1072 } 1073 if (layout == "bullets") 1074 { 1075 <li> 1076 @if (!hideFieldLabels) 1077 { 1078 if (field?.SystemName != "ProductLongDescription") 1079 { 1080 if (Dynamicweb.Ecommerce.Common.Context.LanguageID == "LANG2") 1081 { 1082 <strong>@Translate(field?.Name)</strong> 1083 } 1084 else 1085 { 1086 <strong>@field?.Name</strong> 1087 } 1088 } 1089 } 1090 <span> 1091 @{ @RenderFieldValue(field) } 1092 </span> 1093 </li> 1094 } 1095 } 1096 } 1097 1098 @helper RenderFieldValue(FieldValueViewModel field) 1099 { 1100 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 1101 1102 bool isLink = field?.Type == "Link"; 1103 bool isColor = false; 1104 bool isBrandName = field?.SystemName == "Brand_name"; 1105 bool isYoutubeVideo = field?.SystemName == "VideoLink"; 1106 1107 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 1108 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 1109 1110 1111 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 1112 { 1113 int valueCount = 0; 1114 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 1115 int totalValues = values.Count; 1116 1117 foreach (FieldOptionValueViewModel option in values) 1118 { 1119 if (!string.IsNullOrEmpty(option.Value)) 1120 { 1121 if (option.Value.Substring(0, 1) == "#") 1122 { 1123 isColor = true; 1124 } 1125 } 1126 1127 if (!isColor) 1128 { 1129 @option.Name 1130 } 1131 else 1132 { 1133 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 1134 } 1135 1136 if (valueCount != totalValues && valueCount < (totalValues - 1)) 1137 { 1138 if (isColor) 1139 { 1140 <text> </text> 1141 } 1142 else 1143 { 1144 <text>, </text> 1145 } 1146 } 1147 valueCount++; 1148 } 1149 } 1150 else 1151 { 1152 if (fieldValue.Substring(0, 1) == "#") 1153 { 1154 isColor = true; 1155 } 1156 1157 if (!isColor) 1158 { 1159 if (isLink) 1160 { 1161 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 1162 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 1163 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 1164 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 1165 if (isYoutubeVideo) 1166 { 1167 var videoId = linktTitle; 1168 1169 videoId = videoId.StartsWith("http://") ? videoId.Replace("http://", "") : ""; 1170 1171 linktTitle = "https://img.youtube.com/vi/" + linktTitle.Substring(linktTitle.LastIndexOf('=') + 1) + "/maxresdefault.jpg"; 1172 1173 RatioSettings ratioSettings = GetRatioSettings("desktop"); 1174 1175 <div id="SmallScreenImagesThumbnails_@Model.ID" class="grid grid-2 gap-2 overflow-x-auto my-3"> 1176 <div class="border outline-none @(ratioSettings.CssClass)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to=""> 1177 <a class="d-flex align-items-center justify-content-center" href="@field.Value" @target @rel> 1178 <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 1179 <img src="@linktTitle" alt="" class="p-0 p-lg-1 w-100 h-100" style="object-fit: contain" data-video-id="@field.Value"> 1180 </a> 1181 </div> 1182 </div> 1183 } 1184 else 1185 { 1186 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 1187 } 1188 1189 } 1190 else if (isBrandName) 1191 { 1192 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 1193 <span itemprop="name">@fieldValue</span> 1194 </span> 1195 } 1196 1197 else 1198 { 1199 @fieldValue 1200 } 1201 } 1202 else 1203 { 1204 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 1205 } 1206 } 1207 } 1208 1209 @helper RenderVideoPreview(string fieldValue, string fieldName) { 1210 1211 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 1212 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 1213 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 1214 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 1215 1216 var videoId = linktTitle; 1217 1218 videoId = videoId.StartsWith("http://") ? videoId.Replace("http://", "") : ""; 1219 1220 linktTitle = "https://img.youtube.com/vi/" + linktTitle.Substring(linktTitle.LastIndexOf('=') + 1) + "/maxresdefault.jpg"; 1221 1222 RatioSettings ratioSettings = GetRatioSettings("desktop"); 1223 1224 <p class="fw-bold m-0">@(fieldName):</p> 1225 <div id="SmallScreenImagesThumbnails_@Model.ID" class="grid grid-2 gap-2 overflow-x-auto my-3"> 1226 <div class="border outline-none @(ratioSettings.CssClass)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to=""> 1227 <a class="d-flex align-items-center justify-content-center" href="@fieldValue" @target @rel> 1228 <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 1229 <img src="@linktTitle" alt="" class="p-0 p-lg-1 w-100 h-100" style="object-fit: contain" data-video-id="@fieldValue"> 1230 </a> 1231 </div> 1232 </div> 1233 1234 } 1235 1236 @helper RenderArticle(string fieldValue, bool dummy) { 1237 1238 if (!string.IsNullOrEmpty(fieldValue)) { 1239 1240 if (dummy) { 1241 //dummy filler 1242 } 1243 else 1244 { 1245 int id = fieldValue != "0" ? Int32.Parse(fieldValue) : 0; 1246 if (id > 0) { 1247 1248 var specialPage = Dynamicweb.Content.Services.Pages.GetPage(id); 1249 string title = specialPage.Item.GetItem("Title").ToString(); 1250 string coverImagePath = !string.IsNullOrEmpty(specialPage.Item.GetItem("CoverImage").ToString()) ? specialPage.Item.GetItem("CoverImage").ToString() : string.Empty; 1251 1252 <article class="d-flex flex-column mb-3 gap-0 theme plus_green-white_block h-100 shadow-hover overflow-hidden lift" itemscope="" itemtype="https://schema.org/CreativeWork" style="z-index:100;"> 1253 1254 <a class="w-100 " title="@specialPage.Item.GetItem("Title")" href="@specialPage.GetPageHrefValue()" tabindex="-1"> 1255 1256 <figure class="h-lg-100 overflow-hidden m-0 mx-auto ratio ratio-16x9" aria-label="@coverImagePath"> 1257 @RenderImage(coverImagePath, title, "50% 50%", "object-fit: cover", "2", "2") 1258 </figure> 1259 </a> 1260 <div class="d-flex flex-column flex-grow-1 gap-3 w-100 p-3 p-md-4"> 1261 <a class="text-decoration-none text-decoration-underline-hover" href="@specialPage.GetPageHrefValue()"> 1262 <h3 class="h3 mb-0" itemprop="headline">@specialPage.Item.GetItem("Title")</h3> 1263 </a> 1264 <p class="m-0 opacity-75">@specialPage.Item.GetItem("Summary")</p> 1265 </div> 1266 </article> 1267 } 1268 1269 } 1270 1271 } 1272 } 1273 1274 @helper RenderImage(string coverImagePath, string title, string cssPosition, string imageObjectFit, string gridSettings, string carouselSettings) 1275 { 1276 switch(coverImagePath) 1277 { 1278 case string a when a.Contains(".jpeg"): 1279 coverImagePath = coverImagePath.Substring(0, coverImagePath.IndexOf(".jpeg") + 5); 1280 break; 1281 case string b when b.Contains(".jpg"): 1282 coverImagePath = coverImagePath.Substring(0, coverImagePath.IndexOf(".jpg") + 4); 1283 break; 1284 case string c when c.Contains(".png"): 1285 coverImagePath = coverImagePath.Substring(0, coverImagePath.IndexOf(".png") + 4); 1286 break; 1287 1288 } 1289 1290 coverImagePath = Dynamicweb.Context.Current.Server.UrlEncode(coverImagePath); 1291 1292 string imgSizeSelector = "50vw"; 1293 1294 if (gridSettings == "1" || carouselSettings == "1") 1295 { 1296 imgSizeSelector = "100vw"; 1297 } 1298 else if (gridSettings == "2" || carouselSettings == "2") 1299 { 1300 imgSizeSelector = "50vw"; 1301 } 1302 else if (gridSettings == "3" || carouselSettings == "3") 1303 { 1304 imgSizeSelector = "33vw"; 1305 } 1306 else if (gridSettings == "4" || carouselSettings == "4") 1307 { 1308 imgSizeSelector = "25vw"; 1309 } 1310 else if (gridSettings == "5" || carouselSettings == "5") 1311 { 1312 imgSizeSelector = "17vw"; 1313 } 1314 1315 string coverImagePathM = $"/Admin/Public/GetImage.ashx?image={coverImagePath}&width=640&quality=85&format=webp"; 1316 string coverImagePathL = $"/Admin/Public/GetImage.ashx?image={coverImagePath}&width=960&quality=85&format=webp"; 1317 string coverImagePathXL = $"/Admin/Public/GetImage.ashx?image={coverImagePath}&width=1280&quality=85&format=webp"; 1318 string coverImagePathXXL = $"/Admin/Public/GetImage.ashx?image={coverImagePath}&width=1920&quality=85&format=webp"; 1319 string imagePathFallBack = coverImagePathM; 1320 1321 <img srcset=" 1322 @coverImagePathM 640w, 1323 @coverImagePathL 960w, 1324 @coverImagePathXL 1280w, 1325 @coverImagePathXXL 1920w" 1326 src="@imagePathFallBack" 1327 sizes="(min-width: 992px) @imgSizeSelector, 100vw" 1328 loading="lazy" 1329 decoding="async" 1330 class="img-fluid image-zoom-lg-1-hover" 1331 style="@imageObjectFit; object-position: @cssPosition;" 1332 alt="@title"> 1333 }