Error executing template "Designs/Rapido/eCom/Product/Product.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.<>c__DisplayClass76_0.<RenderVariantStockAndShipping>b__0(TextWriter __razor_helper_writer) in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 3102
   at RazorEngine.Templating.TemplateWriter.ToString()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.<>c__DisplayClass5_0.<RenderBlock>b__0(TextWriter __razor_helper_writer) in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 177
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.<>c__DisplayClass4_0.<RenderBlockList>b__0(TextWriter __razor_helper_writer) in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 143
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.<>c__DisplayClass5_0.<RenderBlock>b__0(TextWriter __razor_helper_writer) in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 184
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.<>c__DisplayClass4_0.<RenderBlockList>b__0(TextWriter __razor_helper_writer) in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 161
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.<>c__DisplayClass5_0.<RenderBlock>b__0(TextWriter __razor_helper_writer) in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 184
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.<>c__DisplayClass4_0.<RenderBlockList>b__0(TextWriter __razor_helper_writer) in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 150
   at CompiledRazorTemplates.Dynamic.RazorEngine_87a8f54d877d43d1838224d1bbe9646a.Execute() in D:\Sites\p-lindberg\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 3328
   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.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 3 @using System.Web 4 @using System 5 @using System.IO 6 @using System.Web 7 @using System.Globalization 8 @using System.Web.UI.HtmlControls 9 10 @using Dynamicweb.Extensibility 11 @using Dynamicweb.Content 12 @using Dynamicweb.Core 13 @using Dynamicweb.Rapido.Blocks 14 15 @using PLindberg.Dynamicweb; 16 @using PLindberg.Website.CustomModules; 17 18 @functions { 19 BlocksPage productsPage = BlocksPage.GetBlockPage("Product"); 20 21 public static string ToPascalCase(string str) 22 { 23 return CultureInfo.InvariantCulture.TextInfo 24 .ToTitleCase(str.ToLowerInvariant()) 25 .Replace("-", "") 26 .Replace("_", "") 27 .Replace(" ", ""); 28 } 29 30 public string GetBreadcrumbHtml(string groupId, string productId) 31 { 32 var productListPageId = GetPageIdByNavigationTag("ProductsListPage"); 33 var productDetailPageId = GetPageIdByNavigationTag("ProductsPage"); 34 35 if (string.IsNullOrWhiteSpace(groupId)) 36 { 37 var product = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, null, true); 38 var primaryGroup = product.Groups.SingleOrDefault(g => g.Id == product.PrimaryGroupId); 39 groupId = primaryGroup?.Id ?? null; 40 } 41 42 return BreadcrumbHelper.GetHtml(productListPageId, productDetailPageId, groupId, productId); 43 } 44 45 public IEnumerable<BreadcrumbHelper.BreadcrumbItem> GetBreadcrumbItems(string groupId, string productId) 46 { 47 var productListPageId = GetPageIdByNavigationTag("ProductsListPage"); 48 var productDetailPageId = GetPageIdByNavigationTag("ProductsPage"); 49 50 if (string.IsNullOrWhiteSpace(groupId)) 51 { 52 var product = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, null, true); 53 var primaryGroup = product.Groups.SingleOrDefault(g => g.Id == product.PrimaryGroupId); 54 groupId = primaryGroup?.Id ?? null; 55 } 56 57 return BreadcrumbHelper.BreadcrumbHierarchyItems(productListPageId, productDetailPageId, groupId); 58 } 59 } 60 61 @{ 62 Block productTop = new Block() 63 { 64 Id = "Top", 65 SortId = 10, 66 Design = new Design 67 { 68 RenderType = RenderType.Row 69 } 70 }; 71 productsPage.Add(productTop); 72 73 Block productMainInfo = new Block() 74 { 75 Id = "MainInformation", 76 SortId = 10, 77 Design = new Design 78 { 79 Size = "auto", 80 RenderType = RenderType.Column 81 } 82 }; 83 productsPage.Add("Top", productMainInfo); 84 85 if (!String.IsNullOrWhiteSpace(Pageview.AreaSettings.GetItem("ProductPage").GetString("ImageSectionPosition"))) 86 { 87 productMainInfo.SortId = Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue == "left-left" || Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue == "left-right" ? 2 : 1; 88 } 89 90 @* custom *@ 91 //Optional mini tabs block 92 Block miniTabsBlock = new Block() 93 { 94 Id = "MiniTabs", 95 SortId = 40, 96 SkipRenderBlocksList = true 97 }; 98 productsPage.Add("MainInformation", miniTabsBlock); 99 //----- 100 101 @* custom *@ 102 Block productTabsBlock = new Block() 103 { 104 Id = "Tabs", 105 SortId = 30, 106 SkipRenderBlocksList = true 107 }; 108 productsPage.Add(productTabsBlock); 109 110 Block productDetailsBlock = new Block() 111 { 112 Id = "Section", 113 SortId = 30 114 }; 115 productsPage.Add(productDetailsBlock); 116 117 Block productSnippetsBlock = new Block() 118 { 119 Id = "Snippets", 120 SortId = 40 121 }; 122 productsPage.Add(productSnippetsBlock); 123 } 124 125 @* Include the required Grid builder (Contains the methods @RenderBlockList and @RenderBlock) *@ 126 @using System.Text.RegularExpressions 127 @using System.Collections.Generic 128 @using Dynamicweb.Rapido.Blocks 129 130 131 @*--- START: Base block renderers ---*@ 132 133 @helper RenderBlockList(List<Block> blocks) 134 { 135 blocks = blocks.OrderBy(item => item.SortId).ToList(); 136 137 foreach (Block item in blocks) 138 { 139 <!-- START: @item.Id --> 140 141 if (item.Design == null) 142 { 143 @RenderBlock(item) 144 } 145 else if (item.Design.RenderType != RenderType.Hide) 146 { 147 if (item.Design.RenderType == RenderType.Row) 148 { 149 <div class="grid grid--align-content-start"> 150 @RenderBlock(item) 151 </div> 152 } 153 154 if (item.Design.RenderType == RenderType.Column) 155 { 156 string hidePadding = item.Design.HidePadding ? "u-no-padding" : ""; 157 string size = item.Design.Size != null ? item.Design.Size : "12"; 158 size = Regex.IsMatch(size, @"\d") ? "md-" + item.Design.Size : item.Design.Size; 159 160 <div class="grid__col-lg-@item.Design.Size grid__col-md-@item.Design.Size grid__col-sm-12 grid__col-xs-12 @hidePadding" id="Block__@item.Id"> 161 @RenderBlock(item) 162 </div> 163 } 164 165 if (item.SkipRenderBlocksList == true) 166 { 167 @RenderBlock(item) 168 } 169 } 170 171 <!-- END: @item.Id --> 172 } 173 } 174 175 @helper RenderBlock(Block item) 176 { 177 if (item.Template != null) 178 { 179 @BlocksPage.RenderTemplate(item.Template) 180 } 181 182 if (item.BlocksList.Count > 0 && item.SkipRenderBlocksList == false) 183 { 184 @RenderBlockList(item.BlocksList) 185 } 186 } 187 188 @*--- END: Base block renderers ---*@ 189 190 191 @* Include the Blocks for the page *@ 192 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 193 @using Dynamicweb.Core 194 @using System 195 @using System.Web 196 @using System.Collections.Generic 197 @using Dynamicweb.Rapido.Blocks 198 @using RazorEngine.Text 199 200 @functions { 201 BlocksPage mainImagePage = BlocksPage.GetBlockPage("Product"); 202 //test 203 } 204 205 @{ 206 string imageBlockPosition = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ImageSectionPosition")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "right-right"; 207 string imageBlockWidth = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("TopLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("TopLayout").SelectedValue : "6"; 208 imageBlockWidth = imageBlockPosition == "left-left" || imageBlockPosition == "left-right" ? Converter.ToString(12 - Converter.ToInt32(imageBlockWidth)) : imageBlockWidth; 209 210 // custom 211 string playThumb = Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetField("VideoThumb").GetFile() != null ? 212 Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetField("VideoThumb").GetFile().Path : string.Empty; 213 214 Block mainImageBlock = new Block() 215 { 216 Id = "MainImage", 217 SortId = imageBlockPosition == "left-left" || imageBlockPosition == "left-right" ? 1 : 2, 218 Template = RenderMainImageContainer(), 219 Design = new Design 220 { 221 Size = imageBlockWidth, 222 RenderType = RenderType.Column 223 } 224 }; 225 226 mainImagePage.Add("Top", mainImageBlock); 227 228 229 } 230 231 @helper RenderModal() 232 { 233 // custom 234 Guid imageGuid = Guid.TryParse(GetString("Ecom:Product:Field.PerfionMainImage.Value.Clean"), out imageGuid) ? imageGuid : Guid.Empty; 235 236 <!-- Trigger for the gallery modal --> 237 <input type="checkbox" id="GalleryModalTrigger" class="modal-trigger" /> 238 239 <!-- custom --> 240 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.PerfionMainImage"))) 241 { 242 <!-- Gallery modal --> 243 <div class="modal-container "> 244 <label for="GalleryModalTrigger" id="GalleryModalOverlay" class="modal-overlay"></label> 245 <div class="modal modal--full" id="GalleryModal"> 246 <div class="modal__body modal__body--full"> 247 <div class="gallery-slider"> 248 <div class="gallery-slider__image"> 249 <!-- custom --> 250 <img id="FullImage" src="~/Files/Images/placeholder.gif" @PerfionImageSrc(imageGuid, 800, 800, "data-src=") class="modal--full__img js-gallery-image" alt="@(new HtmlEncodedString(GetString("Ecom:Product.Name")).ToEncodedString())" /> 251 <iframe id="FullVideo" class="modal--full__img js-gallery-image pp__video" src="" frameborder="0" allowfullscreen></iframe> 252 </div> 253 <div class="gallery-slider__image-counter" id="FullImage_counter"></div> 254 <label class="gallery-slider__close-btn" for="GalleryModalTrigger"></label> 255 <button class="gallery-slider__previous-btn" id="FullImage_prev" onclick="Gallery.prevImage('FullImage')"></button> 256 <button class="gallery-slider__next-btn" id="FullImage_next" onclick="Gallery.nextImage('FullImage')"></button> 257 </div> 258 </div> 259 </div> 260 </div> 261 } 262 } 263 264 @helper RenderMainImageContainer() 265 { 266 string imageBlockPosition = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ImageSectionPosition")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "right-right"; 267 @RenderModal() 268 269 <div class="grid grid--bleed"> 270 @if (imageBlockPosition == "left-left" || imageBlockPosition == "right-left") 271 { 272 @RenderThumbnails() 273 @RenderImage() 274 } 275 else 276 { 277 @RenderImage() 278 @RenderThumbnails() 279 } 280 </div> 281 } 282 283 @helper RenderImage() 284 { 285 // custom 286 Guid imageGuid = Guid.TryParse(GetString("Ecom:Product:Field.PerfionMainImage.Value.Clean"), out imageGuid) ? imageGuid : Guid.Empty; 287 288 Pageview.Meta.AddTag("custom-og-image", "<meta property=\"og:image\" content=\"" + PerfionImageSrc(imageGuid)?.ToString() + "\" />"); 289 string productId = GetString("Ecom:Product.ID"); 290 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly") && Pageview.User == null; 291 292 <div class="grid__col-auto"> 293 <div class="stickers-container dw-mod"> 294 @{ 295 if (Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetBoolean("Enable") && !pointShopOnly) 296 { 297 string contentType = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetString("ContentType"); 298 string text = ""; 299 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 300 301 switch (contentType) 302 { 303 case "Name": 304 foreach (LoopItem discount in GetLoop("ProductDiscounts").Where(p => p.GetString("Ecom:Product.Discount.ID") != "SALESDISCNT4").ToList()) 305 { 306 text = discount.GetString("Ecom:Product.Discount.Name"); 307 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 308 } 309 break; 310 case "Amount": 311 if (GetLoop("ProductDiscounts").Where(p => p.GetString("Ecom:Product.Discount.ID") != "SALESDISCNT4").ToList().Count > 0) 312 { 313 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.PriceWithoutVAT.Value") - GetDouble("Ecom:Product.Price.PriceWithoutVAT.Value")); 314 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 315 } 316 break; 317 case "Percents": 318 double percents = 0; 319 foreach (LoopItem discount in GetLoop("ProductDiscounts").Where(p => p.GetString("Ecom:Product.Discount.ID") != "SALESDISCNT4").ToList()) 320 { 321 percents += discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 322 } 323 if (percents > 0) 324 { 325 text = Math.Round(percents, 0) + "%"; 326 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 327 } 328 break; 329 case "Amount and percents": 330 double amount = 0; 331 double percent = 0; 332 foreach (LoopItem discount in GetLoop("ProductDiscounts").Where(p => p.GetString("Ecom:Product.Discount.ID") != "SALESDISCNT4").ToList()) 333 { 334 if (discount.GetString("Ecom:Product.Discount.Type") == "PERCENT") 335 { 336 percent += discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 337 } 338 else if (discount.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 339 { 340 amount += discount.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 341 } 342 } 343 if (percent > 0) 344 { 345 text = percent + "%"; 346 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 347 } 348 if (amount > 0) 349 { 350 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 351 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 352 } 353 break; 354 default: 355 if (GetLoop("ProductDiscounts").Where(p => p.GetString("Ecom:Product.Discount.ID") != "SALESDISCNT4").ToList().Count > 0) 356 { 357 text = Translate("Sale!"); 358 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 359 } 360 break; 361 } 362 } 363 364 if (!pointShopOnly && Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetBoolean("Enable") && GetDate("Ecom:Product:Field.NewsStart.Value") < DateTime.Now && GetDate("Ecom:Product:Field.NewsEnd.Value") > DateTime.Now.AddDays(-1)) 365 { 366 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div> 367 } 368 369 // custom 370 #region Perfion sticker 371 var stickerName = GetString("Ecom:Product:Field.PerfionSticker.Value.Clean"); 372 if (!pointShopOnly) 373 { 374 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value"))) 375 { 376 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div> 377 } 378 if (!string.IsNullOrEmpty(stickerName)) 379 { 380 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@stickerName</div> 381 } 382 } 383 #endregion 384 } 385 </div> 386 <label for="GalleryModalTrigger" class="product__image-container"> 387 <img class="thumb-image-view product__image-container__image dw-mod b-lazy" src="Files/Images/placeholder.gif" @PerfionImageSrc(imageGuid, 800, 800, "data-src=") alt="@(new HtmlEncodedString(GetString("Ecom:Product.Name")).ToEncodedString())" id="Image_@productId" data-for="FullImage" data-number="0" onclick="Gallery.openImageByNum(this)" /> 388 </label> 389 </div> 390 } 391 392 @helper RenderThumbnails() 393 { 394 var technicalSpecificationsFeed = "/Default.aspx?ID=" + GetPageIdByNavigationTag("PerfionLiveFeed") + "&PerfionProductID=" + GetString("Ecom:Product:Field.PerfionProductId") + "&LanguageID=" + GetString("Ecom:Product.LanguageID") + "&PerfionMainImage=" + GetString("Ecom:Product:Field.PerfionMainImage"); 395 396 <div class="grid__col-2 dw-mod mobilethumbs"> 397 <div class="product__thumbs dw-mod js-handlebars-root" id="GalleryImages" data-template="GalleryImagesContainer" data-pre-render-template="GalleryImagesPreRenderContainer" data-json-feed="@technicalSpecificationsFeed" data-preloader="minimal"> 398 </div> 399 </div> 400 } 401 402 @helper RenderThumbnail(string image) 403 { 404 // custom 405 Guid imageGuid = Guid.TryParse(GetString("Ecom:Product:Field.PerfionMainImage.Value.Clean"), out imageGuid) ? imageGuid : Guid.Empty; 406 string productId = GetString("Ecom:Product.ID"); 407 408 <div class="carousel__slide carousel__slide--vertical dw-mod"> 409 <div class="thumb-list__item thumb-list__item--active dw-mod js-thumb js-gallery" data-for="Image_@productId" @PerfionImageSrc(imageGuid, 800, 800, "data-image=") onmouseover="Gallery.openImage(this)"> 410 <label for="GalleryModalTrigger"> 411 <img src="Files/Images/placeholder.gif" @PerfionImageSrc(imageGuid, 200, 200, "data-src=") alt="@(new HtmlEncodedString(GetString("Ecom:Product.Name")).ToEncodedString())" class="js-gallery b-lazy" data-for="FullImage" @PerfionImageSrc(imageGuid, 800, 800, "data-image=") onclick="Gallery.openImage(this)"> 412 </label> 413 </div> 414 </div> 415 } 416 417 <script id="GalleryImagesPreRenderContainer" type="text/x-template"> 418 <div class="u-h600px u-full-width"> 419 <div class="grid"> 420 <div class="grid__col-12"> 421 <div class="pre-render-element pre-render-element--md"></div> 422 </div> 423 </div> 424 </div> 425 </script> 426 427 <script id="GalleryImagesContainer" type="text/x-template"> 428 <i class="fas fa-circle-notch fa-spin preloader js-remove-after-load"></i> <!--preloader--> 429 <div class="carousel js-carousel-container carousel--hidden dw-mod" id="leftCarousel"> 430 <div class="thumb-list carousel__container dw-mod"> 431 @* custom *@ 432 {{#videos}} 433 {{>RenderProductVideos link=link thumb="@playThumb"}} 434 {{/videos}} 435 @*Main image thumb*@ 436 @RenderThumbnail(GetString("Ecom:Product:Field.PerfionMainImage")) 437 {{#images}} 438 {{>GalleryImage}} 439 {{/images}} 440 </div> 441 <div class="js-carousel-data" data-carousel-slide-time="0" data-direction="vertical" data-sliding-type="items" data-slides-in-view="5"> 442 <div class="carousel-prev-btn carousel-prev-btn--vertical dw-mod" onclick="Carousel.GetPreviousSlide('leftCarousel')"></div> 443 <div class="carousel-next-btn carousel-next-btn--vertical dw-mod" onclick="Carousel.GetNextSlide('leftCarousel')"></div> 444 </div> 445 </div> 446 </script> 447 448 <script id="GalleryImage" type="text/x-template"> 449 <div class="carousel__slide carousel__slide--vertical dw-mod"> 450 <div class="thumb-list__item thumb-list__item--active dw-mod js-thumb js-gallery" data-for="Image_@GetString("Ecom:Product.ID")" data-image="{{PerfionImageSrc guid 800 800}}" onmouseover="Gallery.openImage(this)"> 451 <label for="GalleryModalTrigger"> 452 <img src="Files/Images/placeholder.gif" alt="@(new HtmlEncodedString(GetString("Ecom:Product.Name")).ToEncodedString())" class="js-gallery b-lazy" data-src="{{PerfionImageSrc guid 200 200}}" data-for="FullImage" data-image="{{PerfionImageSrc guid 800 800}}" onclick="Gallery.openImage(this)"> 453 </label> 454 </div> 455 </div> 456 </script> 457 458 @* custom *@ 459 <script id="RenderProductVideos" type="text/x-template"> 460 <div class="carousel__slide carousel__slide--vertical dw-mod"> 461 <div class="thumb-list__item thumb-list__item--active dw-mod js-thumb js-gallery" data-for="Image_@GetString("Ecom:Product.ID")" data-image="{{largeImage}}" data-video="{{link}}" onmouseover="Gallery.openImage(this)"> 462 <label for="GalleryModalTrigger"> 463 <img src="Files/Images/placeholder.gif" alt="@(new HtmlEncodedString(GetString("Ecom:Product.Name")).ToEncodedString())" class="js-gallery b-lazy" data-src="{{smallImage}}" data-image="{{largeImage}}" data-for="FullImage" data-video="{{link}}" onclick="Gallery.openImage(this)"> 464 {{#if thumb}} 465 <img src="Files/Images/placeholder.gif" data-src="{{thumb}}" class="play-thumb b-lazy" alt="@(new HtmlEncodedString(GetString("Ecom:Product.Name")).ToEncodedString())" onclick="Gallery.openImage(this.previousElementSibling)" /> 466 {{/if}} 467 </label> 468 </div> 469 </div> 470 </script> 471 472 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 473 @using Dynamicweb.Core 474 @using System 475 @using System.Linq; 476 @using System.Text; 477 @using System.Web 478 @using System.Collections.Generic 479 @using Dynamicweb.Rapido.Blocks 480 @using Group = Dynamicweb.Ecommerce.Products.Group; 481 482 @using PLindberg.Dynamicweb; 483 @functions { 484 bool useFacebookPixel; 485 bool useGoogleTagManager; 486 BlocksPage mainInfoPage = BlocksPage.GetBlockPage("Product"); 487 } 488 489 @{ 490 bool mainInfoRenderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetString("RenderVariantsAsProductList") != null && GetInteger("Ecom:Product.VariantCount") > 1 ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") : false; 491 bool mainPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 492 bool mainInfoOnlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null; 493 string mainInfoVariantId = HttpContext.Current.Request.QueryString.Get("variantId") != null ? HttpContext.Current.Request.QueryString.Get("variantId") : ""; 494 string mainInfoFeedId = GetGlobalValue("Global:Page.ID").ToString() + "&ProductID=" + GetString("Ecom:Product.ID") + "&VariantID=" + mainInfoVariantId + "&Feed=True&redirect=false"; 495 string mainInfoCartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetString("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 496 useFacebookPixel = !string.IsNullOrWhiteSpace(Pageview.AreaSettings.GetItem("Settings").GetString("FacebookPixelID")); 497 useGoogleTagManager = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("GoogleTagManagerID")); 498 499 Block mainInfoHeader = new Block() 500 { 501 Id = "MainInfoHeader", 502 SortId = 10, 503 Template = RenderMainInfoHeader() 504 }; 505 mainInfoPage.Add("MainInformation", mainInfoHeader); 506 507 Block mainInfoDescription = new Block() 508 { 509 Id = "ShortDescription", 510 SortId = 30, 511 Template = RenderShortDescription() 512 }; 513 mainInfoPage.Add("MainInformation", mainInfoDescription); 514 515 if (!mainInfoRenderVariantsAsProducts) 516 { 517 Block mainInfoVariants = new Block() 518 { 519 Id = "Variants", 520 SortId = 50, 521 Template = RenderMainInfoVariants() 522 }; 523 mainInfoPage.Add("MainInformation", mainInfoVariants); 524 } 525 526 Block mainInfoBOM = new Block() 527 { 528 Id = "BOM", 529 SortId = 60, 530 Template = RenderMainInfoBOM() 531 }; 532 mainInfoPage.Add("MainInformation", mainInfoBOM); 533 534 if (!mainInfoRenderVariantsAsProducts) 535 { 536 Block mainInfoBuy = new Block() 537 { 538 Id = "Buy", 539 SortId = 80, 540 Template = RenderMainInfoBuy() 541 }; 542 mainInfoPage.Add("MainInformation", mainInfoBuy); 543 544 Block stockAndShipping = new Block() 545 { 546 Id = "StockAndShipping", 547 SortId = 90, 548 Template = RenderStockAndShipping() 549 }; 550 mainInfoPage.Add("MainInformation", stockAndShipping); 551 } 552 } 553 554 @* custom *@ 555 @using System; 556 @using System.Web; 557 558 @using PLindberg.Dynamicweb.Common; 559 @using PLindberg.Dynamicweb.Perfion; 560 561 @helper PerfionImageSrc(Guid imageGuid, int width, int height, string prefix = "src=") 562 { 563 if (imageGuid == null || imageGuid == Guid.Empty) 564 { 565 <text>@prefix"@string.Format("Files/Images/missing_image.jpg")"</text> 566 } 567 else 568 { 569 <text>@prefix"@HttpUtility.HtmlEncode(string.Format("{0}/Perfion/Image.aspx?id={1}&size={2}x{3}&format=png", new PerfionSettings().PerfionWebApiUrl(), imageGuid, width, height))"</text> 570 } 571 } 572 573 @helper PerfionImageSrc(Guid imageGuid) 574 { 575 if (imageGuid == Guid.Empty) 576 { 577 <text>@string.Format("Files/Images/missing_image.jpg")</text> 578 } 579 else 580 { 581 <text>@string.Format("{0}/Perfion/Image.aspx?id={1}&format=png", new PerfionSettings().PerfionWebApiUrl(), imageGuid)</text> 582 } 583 } 584 585 @helper RenderMainInfoHeader() 586 { 587 bool renderVariantsAsProducts = GetInteger("Ecom:Product.VariantCount") > 1 ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") : false; 588 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 589 string currentPrice = GetString("Ecom:Product.Discount.Price.PriceFormatted") == GetString("Ecom:Product.Price.PriceFormatted") ? GetString("Ecom:Product.Price.PriceFormatted") : GetString("Ecom:Product.Discount.Price.PriceFormatted"); 590 bool hideProductNumber = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideProductNumber"); 591 592 double metaTagPrice = GetDouble("Ecom:Product.Discount.Price.PriceWithVAT.Value") == GetDouble("Ecom:Product.Price.PriceWithVAT.Value") ? GetDouble("Ecom:Product.Price.PriceWithVAT.Value") : GetDouble("Ecom:Product.Discount.Price.PriceWithVAT.Value"); 593 // main product 594 var variantsLoop = GetLoop("VariantCombinations"); 595 var lowestVariantPrice = variantsLoop.GetLowestVariantPrice(); 596 if (lowestVariantPrice != null && string.IsNullOrEmpty(GetString("Ecom:Product.SelectedVariantComboName"))) 597 { 598 metaTagPrice = lowestVariantPrice.PriceWithVat; 599 } 600 601 Pageview.Meta.AddTag("custom-og-type", "<meta property=\"og:type\" content=\"product\" />"); 602 Pageview.Meta.AddTag("custom-og-price", "<meta property=\"product:price:amount\" content=\"" + metaTagPrice.ToString("0.00", CultureInfo.InvariantCulture) + "\" />"); 603 Pageview.Meta.AddTag("custom-og-currency", "<meta property=\"product:price:currency\" content=\"" + Pageview.Area.EcomCurrencyId + "\" />"); 604 605 bool useFontAwesomePro = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetBoolean("UseFontAwesomePro"); 606 var selectedFavoriteIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon").SelectedValue : "star"; 607 string favoriteIcon = "fas fa-" + selectedFavoriteIcon; 608 string favoriteOutlineIcon = "far fa-" + selectedFavoriteIcon; 609 610 // custom 611 Guid imageGuid = Guid.TryParse(GetString("Ecom:Product:Field.PerfionLogo.Value.Clean"), out imageGuid) ? imageGuid : Guid.Empty; 612 bool isMainProduct = GetString("Ecom:Product.Number").Contains("-main"); 613 <div> 614 <div class="u-pull--left product__title dw-mod"> 615 @* Custom: removed variant combo name *@ 616 <h1 class="u-no-margin">@GetString("Ecom:Product.Name")</h1> 617 618 @if (!hideProductNumber && !isMainProduct) 619 { 620 <div class="item-number dw-mod">@Translate("Productno", "Varenr.") @GetString("Ecom:Product.Number")</div> 621 } 622 @* custom 623 show perfion logo 624 *@ 625 @if (imageGuid.ToString() != "00000000-0000-0000-0000-000000000000") 626 { 627 <div class="logo"> 628 <img class="b-lazy" src="/Files/Images/placeholder.gif" @PerfionImageSrc(imageGuid, 200, 200, "data-src=") /> 629 </div> 630 } 631 632 </div> 633 @* Remove favorites on productpages 634 <div class="u-pull--right"> 635 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && !renderVariantsAsProducts) 636 { 637 string favoriteId = "Favorite" + GetString("Ecom:Product.ID"); 638 <div id="@favoriteId" class="favorites favorites--md u-pull--right js-favorite-btn dw-mod"> 639 <div> 640 @{ 641 string favorite = GetBoolean("Ecom:Product.IsProductInFavoriteList") ? favoriteIcon : favoriteOutlineIcon; 642 643 // custom (Zero Price) 644 string AddToWishlist = null; 645 646 if (GetDouble("Ecom:Product.Price.PriceWithoutVAT.Value") > 0) 647 { 648 AddToWishlist = "fbq('track', 'AddToWishlist', {" + 649 "content_name: '" + GetString("Ecom:Product.Name") + "'," + 650 "content_ids: ['" + GetString("Ecom:Product.Number") + "']," + 651 "value: " + GetDouble("Ecom:Product.Price.PriceWithVAT.Value") + "," + 652 "currency: '" + GetString("Ecom:Product.Price.Currency.Code") + "'" + 653 "});"; 654 } 655 } 656 <label for="FavoriteTrigger"><i class="@favorite fa-1_5x"></i></label> 657 </div> 658 <input type="checkbox" id="FavoriteTrigger" class="dropdown-trigger" /> 659 660 <div class="dropdown"> 661 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 662 <ul class="list list--clean dw-mod"> 663 @if (GetLoop("CustomerCenter.ListTypes").Count > 0) 664 { 665 foreach (LoopItem listType in GetLoop("CustomerCenter.ListTypes")) 666 { 667 foreach (LoopItem list in listType.GetLoop("CustomerCenter.ProductLists")) 668 { 669 string favLinkType = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? list.GetString("Ecom:Product.RemoveFromThisList") : list.GetString("Ecom:Product.AddToThisListAction"); 670 string isInListIcon = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? favoriteIcon : favoriteOutlineIcon; 671 <li> 672 <a href="@favLinkType" class="list__link u-no-underline dw-mod" onclick="@(list.GetString("Ecom:Product.List.IsProductInThisList") != "True" && useFacebookPixel ? AddToWishlist : "")"><i class="@isInListIcon"></i> @list.GetValue("Ecom:CustomerCenter.List.Name")</a> 673 </li> 674 } 675 } 676 } 677 else 678 { 679 string favLinkType = GetString("Ecom:Product.AddToFavorites") + "&CCListType=0&CCCreateNewList=" + Translate("My favorites"); 680 string isInListIcon = favoriteOutlineIcon; 681 <li> 682 <a href="@favLinkType" class="list__link u-no-underline dw-mod" onclick="@(useFacebookPixel ? AddToWishlist : "")"><i class="@isInListIcon"></i> @Translate("My favorites")</a> 683 </li> 684 } 685 </ul> 686 </div> 687 <label class="dropdown-trigger-off" for="FavoriteTrigger"></label> 688 </div> 689 </div> 690 } 691 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) == false) 692 { 693 string favorite = GetBoolean("Ecom:Product.IsProductInFavoriteList") ? favoriteIcon : favoriteOutlineIcon; 694 695 <div class="favorites favorites--md u-pull--right js-favorite-btn dw-mod"> 696 697 <label for="FavoriteTrigger_{{id}}" class="u-no-margin js-favorite-btn"> 698 <label for="SignInModalTrigger" title='@Translate("OpretBruger","Opret bruger eller login således du kan bruge denne funktion")' onclick="setTimeout(function () { document.getElementById('LoginUsername').focus() }, 10)"> 699 <i class="@favorite fa-1_5x"></i> 700 </label> 701 </label> 702 </div> 703 } 704 </div>*@ 705 </div> 706 } 707 708 @helper RenderStockAndShipping() 709 { 710 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideStockState") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState") : false; 711 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideShipping") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping") : false; 712 bool onlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null; 713 714 if (!onlyPreview && (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.Text")) || !String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText")))) 715 { 716 string stockIcon = GetInteger("Ecom:Product.Stock") > 0 ? GetInteger("Ecom:Product.Stock") < 5 ? "stock-icon--few" : "stock-icon--in" : "stock-icon--not"; 717 718 <div class="product__stock-delivery dw-mod"> 719 @if (!hideStockState) 720 { 721 722 723 } 724 725 @if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText")) && !hideDelivery) 726 { 727 <span>@Translate("Shipping")</span> <span>@GetString("Ecom:Product:Stock.DeliveryText")</span> <span>@GetString("Ecom:Product:Stock.DeliveryUnit")</span> 728 } 729 </div> 730 } 731 } 732 733 @helper RenderShortDescription() 734 { 735 if (!String.IsNullOrEmpty(GetString("Ecom:Product.ShortDescription"))) 736 { 737 <div class="introduction-text"> 738 @GetString("Ecom:Product.ShortDescription") 739 </div> 740 } 741 } 742 743 @helper RenderMainInfoVariants() 744 { 745 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 746 string productId = GetString("Ecom:Product.ID"); 747 string variantSelection = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("variantId")) ? HttpContext.Current.Request.QueryString.Get("variantId").Replace(".", ",") : ""; 748 string hideHelpText = ""; 749 750 var products = new Dynamicweb.Ecommerce.Products.ProductService().GetByProductIDs(new string[] { productId }, false, GetString("Ecom:Product.LanguageID"), false, false); 751 var activeVariantList = products.Where(x => x.VariantId != "" && x.Active).SelectMany(x => x.VariantId.Split('.')); 752 753 foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 754 { 755 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions")) 756 { 757 if (variantoption.GetBoolean("Ecom:VariantOption.Selected")) 758 { 759 hideHelpText = "u-hidden"; 760 } 761 } 762 } 763 764 if (GetLoop("VariantGroups").Count > 0) 765 { 766 var variantCombinationsObject = new List<Array>(); 767 foreach (LoopItem variantcomb in GetLoop("VariantStockCombinations")) 768 { 769 string[] combinations = variantcomb.GetString("Ecom:VariantStockCombination.VariantID").Split('.'); 770 variantCombinationsObject.Add(combinations); 771 } 772 773 string combinationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantCombinationsObject).Replace("\"", "\'"); 774 775 var variantGroupsObject = new List<List<String>>(); 776 foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 777 { 778 var variantsObject = new List<String>(); 779 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 780 { 781 variantsObject.Add(variantOption.GetString("Ecom:VariantOption.ID")); 782 } 783 variantGroupsObject.Add(variantsObject); 784 } 785 string variantsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantGroupsObject).Replace("\"", "\'"); 786 787 <div> 788 <div id="variant-options" class="js-variants" data-total-variant-groups="@GetLoop("VariantGroups").Count" data-combinations="@combinationsJson" data-variants="@variantsJson" data-variant-selections="@variantSelection" data-selection-complete="UpdatePage" data-page-id="@pageId" data-product-id="@productId"> 789 @foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 790 { 791 string groupId = variantGroup.GetString("Ecom:VariantGroup.ID"); 792 793 <div> 794 <div class="u-bold">@variantGroup.GetString("Ecom:VariantGroup.Name")</div> 795 <div> 796 <select onchange="VariantHandling.SelectVariant(event)" id="variant-selector-@groupId"> 797 <option class="js-variant-option" data-variant-id="@groupId-select" data-variant-group="@groupId">@Translate("Select variant")</option> 798 @foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions").OrderBy(x=>x.GetString("Ecom:VariantOption.Name")).ThenBy(x=>x.GetString("Ecom:VariantOption.SortOrder"))) 799 { 800 var variantOptionId = variantOption.GetString("Ecom:VariantOption.ID"); 801 if (!activeVariantList.Contains(variantOptionId)) { continue; } 802 803 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "true" : ""; 804 //selected="@selected" 805 806 <option class="js-variant-option" data-variant-id="@variantOptionId" data-variant-group="@groupId"> 807 @variantOption.GetString("Ecom:VariantOption.Name") 808 </option> 809 } 810 </select> 811 </div> 812 </div> 813 } 814 815 </div> 816 817 @*<small class="js-help-text help-text @hideHelpText">@Translate("Please select variant!")</small>*@ 818 </div> 819 } 820 } 821 822 @helper RenderMainInfoBOM() 823 { 824 if (GetLoop("BOMProducts").Count > 0) 825 { 826 <h2 class="section-title">@Translate("Including products")</h2> 827 foreach (LoopItem BOMProductItem in GetLoop("BOMProducts")) 828 { 829 string link = "/" + BOMProductItem.GetString("Ecom:Product.LinkGroup.Clean") + (!String.IsNullOrEmpty(BOMProductItem.GetString("Ecom:Product.VariantID")) ? "&VariantID=" + BOMProductItem.GetString("Ecom:Product.VariantID") : ""); 830 <div class="grid__col--border grid"> 831 <div class="grid__cell grid__cell--align-middle-left"> 832 <a href="@link" class="u-pull--left u-margin-right"> 833 <img src="/Admin/Public/GetImage.ashx?width=50&image=@BOMProductItem.GetString("Ecom:Product.ImageDefault.Default.Clean")&Compression=99" alt="@BOMProductItem.GetString("Ecom:Product.Name")" /> 834 </a> 835 <a href="@link">@BOMProductItem.GetString("Ecom:Product.Name")</a> 836 </div> 837 </div> 838 } 839 } 840 } 841 842 @helper RenderMainInfoBuy() 843 { 844 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 845 string variantId = HttpContext.Current.Request.QueryString.Get("variantId"); 846 string productId = GetString("Ecom:Product.ID"); 847 string feedId = pageId + "&ProductID=" + productId + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 848 849 <div class="product__price-actions js-handlebars-root dw-mod" id="PriceAndActions" data-template="PricesAndActionsTemplate" data-json-feed="/Default.aspx?ID=@feedId" data-preloader="minimal"></div> 850 <input type="hidden" value="@GetString("Ecom:Product.VariantID.Extented")" name="Variant" id="Variant_@GetString("Ecom:Product.ID")" /> 851 } 852 853 854 855 @{ 856 Block AddCostsModalHeaderProduct = new Block() 857 { 858 Id = "AdditionalCostsProductModalHeader", 859 Name = "Modal Header", 860 Template = RenderModalHeaderProduct() 861 }; 862 Block AddCostsModalBodyProduct = new Block() 863 { 864 Id = "AdditionalCostsProductModalBody", 865 Name = "Modal Body", 866 Template = RenderModalBodyProduct() 867 }; 868 } 869 870 871 @RenderModalDialog("additional-costs-product", AddCostsModalHeaderProduct, AddCostsModalBodyProduct, "modal--lg") 872 873 874 @helper RenderModalHeaderProduct() 875 { 876 string additionalCostsHeadline = Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsHeadline") != null ? Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsHeadline") : ""; 877 <h2>@additionalCostsHeadline</h2> 878 879 } 880 @helper RenderModalBodyProduct() 881 { 882 <div class="additional-costs-content"> 883 @{ 884 885 string additionalCostsText = Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsText") != null ? Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsText") : ""; 886 887 <div>@additionalCostsText</div> 888 } 889 </div> 890 891 } 892 893 @* Handlebars templates *@ 894 <script id="PricesAndActionsTemplate" type="text/x-template"> 895 {{#.}} 896 {{#ifCond itemStatus "!==" "Z"}} 897 @if (!mainInfoOnlyPreview) 898 { 899 <div class="product__price-actions__price dw-mod u-margin-bottom--lg "> 900 @if (mainPointShopOnly) 901 { 902 <text> 903 {{#if havePointPrice}} 904 <div class="price price--product-page dw-mod">{{points}} @Translate("points")</div> 905 {{else}} 906 @Translate("Not available") 907 {{/if}} 908 </text> 909 } 910 else 911 { 912 @*Custom*@ 913 <text>{{#if showPrice}}</text> 914 <text>{{#if showinfoPrice}}</text> 915 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 916 <div class="price price--product-page dw-mod newprice"><span>@Translate("Nu", "Nu")</span>{{price}}</div> 917 <div class="price price--product-page dw-mod withoutvat">{{priceWithoutVat}} @Translate("EksMoms", "ex. moms")</div> 918 <div class="price price--product-page dw-mod withoutvat beforeprice"><span>@Translate("Beforeprice", "Før")</span> {{informativePrice.priceWithVat}}</div> 919 <div class="price price--product-page dw-mod withoutvat">{{informativePrice.price}} @Translate("EksMoms", "ex. moms")</div> 920 <text>{{else}}</text> 921 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 922 <div class="price price--product-page dw-mod">{{price}}</div> 923 <div class="price price--product-page dw-mod withoutvat">{{priceWithoutVat}} @Translate("EksMoms", "ex. moms")</div> 924 <text>{{/if}}</text> 925 <text>{{/if}}</text> 926 927 <text>{{#if showContactInfo}}</text> 928 string footeremail = Converter.ToString(Pageview.AreaSettings.GetItem("Settings").GetString("ContactEmail")); 929 string footerphone = Converter.ToString(Pageview.AreaSettings.GetItem("Settings").GetString("ContactNumber")).Replace(" ", ""); 930 <p class="">@Translate("ZeroPriceInfo", "Kontakt os og få oplyst pris.")</p> 931 <a class="btn btn--secondary btn--condensed u-no-margin dw-mod zeroprice" href="tel:@footerphone"><i class="fas fa-mobile-alt"></i> @Translate("ZeroPriceContactcustomservice", "Ring til kundeservice")</a> 932 <a class="btn btn--secondary btn--condensed u-no-margin dw-mod zeroprice" href="mailto:@footeremail"><i class="far fa-envelope"></i> @Translate("ZeroPriceContact-Email", "Skriv til kundeservice")</a> 933 <text>{{/if}}</text> 934 } 935 <p class="priceinfocontainer__additional-costs" onclick="document.getElementById('additional-costs-product-trigger').click(); return false;">@Translate("Additional costs", "Øvrige omk. tillægges")</p> 936 </div> 937 <div class="buttons-collection buttons-collection--right product__price-actions__actions dw-mod"> 938 <input type="checkbox" id="UnitOptions_{{id}}" class="dropdown-trigger" /> 939 <div class="dropdown u-w150px u-w80px--xs dw-mod {{hasUnits}}"> 940 <label class="dropdown__header dropdown__btn dw-mod" for="UnitOptions_{{id}}">{{unitName}}</label> 941 <div id="unitOptions" class="dropdown__content dw-mod"> 942 {{#unitOptions}} 943 {{>UnitOption}} 944 {{/unitOptions}} 945 </div> 946 <label class="dropdown-trigger-off" for="UnitOptions_{{id}}"></label> 947 </div> 948 <input type="hidden" value="{{unitId}}" name="Unit" id="Unit_{{id}}" /> 949 <text>{{#if showPrice}}</text> 950 @if (mainPointShopOnly) 951 { 952 <button type="button" id="CartButton_{{id}}" class="btn btn--primary btn--condensed u-no-margin dw-mod js-cart-btn {{disabledBuyButton}} {{#unless canBePurchasedWithPoints}}js-stay-disabled{{/unless}}" name="CartCmd" value="addWithPoints" 953 onclick="Cart.AddToCart(event, { 954 id: '{{productId}}', 955 variantId: '{{variantid}}', 956 unitId: '{{unitId}}', 957 quantity: 1, 958 buyForPoints: true, 959 productInfo: {{productInfo}} 960 }); {{facebookPixelAction}}"> 961 <i class="@mainInfoCartIcon"></i><span class="u-hidden-xs u-hidden-xxs"> @Translate("Buy with points")</span> 962 </button> 963 <text> 964 {{#unless canBePurchasedWithPoints}} 965 {{#if havePointPrice}} 966 <small class="help-text u-no-margin u-margin-top">@Translate("Not enough points to buy this")</small> 967 {{/if}} 968 {{/unless}} 969 </text> 970 } 971 else 972 { 973 <input type="number" class="u-w70px" id="Quantity_{{id}}" name="Quantity" value="1" min="1"> 974 <button type="button" id="CartButton_{{id}}" class="btn btn--primary btn--condensed u-no-margin dw-mod js-cart-btn" name="submit" 975 onclick="Cart.AddToCart(event, { 976 id: '{{productId}}', 977 variantId: '{{variantid}}', 978 unitId: '{{unitId}}', 979 quantity: document.getElementById('Quantity_{{id}}').value, 980 productInfo: {{productInfo}} 981 }); {{facebookPixelAction}}"> 982 <span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span><i class="@mainInfoCartIcon"></i> 983 </button> 984 } 985 <text>{{/if}}</text> 986 </div> 987 <text>{{#if showPrice}}</text> 988 <text>{{#if unitizedPrice}}</text> 989 <div class="product__unitizedPrice dw-mod"> 990 <div class="dw-mod ">{{#replace "[0]" unitizedPrice.Quantity}}{{#replace "[1]" unitizedPrice.PriceWithVatFormatted}}@Translate("Flerstykspris", "Ved køb af [0] stk. er prisen <span class=\"newprice\">[1]</span> pr. stk."){{/replace}}{{/replace}}</div> 991 <div class="price price--product-page dw-mod withoutvat">{{unitizedPrice.PriceWithoutVatFormatted}} @Translate("EksMoms", "ex. moms")</div> 992 </div> 993 <text>{{/if}}</text> 994 <text>{{/if}}</text> 995 996 997 if (Pageview.User != null && !mainPointShopOnly && Dynamicweb.Security.Licensing.LicenseManager.LicenseHasFeature("LoyaltyPoints")) 998 { 999 <text> 1000 {{#if canBePurchasedWithPoints}} 1001 <form method="post" role="form" class="u-no-margin u-margin-top"> 1002 <input type="hidden" name="ProductID" value="{{id}}" /> 1003 <button type="submit" class="btn btn--loyalty-points u-no-margin dw-mod pull-right u-no-margin js-cart-btn {{disabledBuyButton}}" name="CartCmd" value="addWithPoints">@Translate("Buy for") {{points}} @Translate("points")</button> 1004 </form> 1005 {{/if}} 1006 </text> 1007 } 1008 } 1009 else 1010 { 1011 <button type="button" id="CartButton_{{id}}" class="u-hidden"></button> 1012 } 1013 {{/ifCond}} 1014 {{/.}} 1015 </script> 1016 1017 <script id="Units" type="text/x-template"> 1018 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '/Default.aspx?ID=@mainInfoFeedId&UnitID={{value}}')">{{name}}</div> 1019 </script> 1020 1021 <script id="UnitOption" type="text/x-template"> 1022 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '{{link}}&feed=true&UnitID={{value}}&rid={{id}}')">{{name}}</div> 1023 </script> 1024 1025 1026 <script> 1027 document.addEventListener("DOMContentLoaded", function () { 1028 if (document.getElementById("PriceAndActions")) { 1029 document.getElementById("PriceAndActions").addEventListener("contentLoaded", function (event) { 1030 if (document.querySelector(".js-variants") != null) { 1031 VariantHandling.Update(document.querySelector(".js-variants"), "DoNothing"); 1032 } 1033 }); 1034 } 1035 }); 1036 </script> 1037 1038 @if (useGoogleTagManager) 1039 { 1040 var groupObject = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(GetString("Ecom:Product.PrimaryOrFirstGroupID")); 1041 // find categoryPath 1042 var categoryPath = ""; 1043 1044 1045 var product = Dynamicweb.Ecommerce.Products.Product.GetProductById(GetString("Ecom:Product.ID")); 1046 1047 var primaryGroup = product.Groups.SingleOrDefault(g => g.Id == product.PrimaryGroupId); 1048 1049 1050 if (primaryGroup != null) 1051 { 1052 var groupTextBuilder = new StringBuilder(primaryGroup.Id + "#" + primaryGroup.Id); 1053 1054 while (primaryGroup.ParentGroups.Count > 0) 1055 { 1056 var primaryGroupsText = primaryGroup.ParentGroups.Reverse() 1057 .Aggregate<Group, string, string>(string.Empty, (g1, g2) => string.Format("{1};{0}", g1, g2.Id + "#" + g2.Id), result => result); 1058 groupTextBuilder.Insert(0, primaryGroupsText); 1059 1060 primaryGroup = primaryGroup.ParentGroups[0]; 1061 } 1062 1063 //while (!string.IsNullOrEmpty(primaryGroup.PrimaryParentGroupId)) 1064 //{ 1065 // primaryGroup = primaryGroup.ParentGroups.SingleOrDefault(g => g.Id == primaryGroup.PrimaryParentGroupId); 1066 // groupTextBuilder.Insert(0, string.Format(" > {0}", primaryGroup.Name)); 1067 //} 1068 1069 categoryPath = groupTextBuilder.ToString(); 1070 } 1071 else 1072 { 1073 var groupText = product.Groups.Reverse() 1074 .Aggregate<Group, string, string>(string.Empty, (g1, g2) => string.Format("{1};{0}", g1, g2.Id + "#" + g2.Id), result => result); 1075 var lastIndex = groupText.LastIndexOf(';'); 1076 categoryPath = lastIndex == groupText.Length - 1 ? groupText.Remove(lastIndex - 1) : groupText; 1077 } 1078 1079 <script> 1080 // Measure a view of product details. This example assumes the detail view occurs on pageload, 1081 // and also tracks a standard pageview of the details page. 1082 (function () { 1083 var data = { 1084 'ecommerce': { 1085 'detail': { 1086 'actionField': {}, // 'detail' actions have an optional list property. 1087 'products': [{ 1088 'name': '@GetString("Ecom:Product.Name")', // Name or ID is required. 1089 'id': '@GetString("Ecom:Product.ID")', 1090 'price': '@(GetDouble("Ecom:Product.Discount.Price.PriceWithoutVAT.Value") != GetDouble("Ecom:Product.Price.PriceWithoutVAT.Value") ? GetDouble("Ecom:Product.Discount.Price.PriceWithoutVAT.Value") : GetDouble("Ecom:Product.Price.PriceWithoutVAT.Value"))', // Custom: price without VAT 1091 'brand': '@GetString("Ecom:Product:Field.brand.Value")', 1092 'category': '@(groupObject != null ? groupObject.Name : "")', 1093 'variant': '@(!string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"))' 1094 }] 1095 }, 1096 'categoryPath': '@categoryPath' 1097 } 1098 }; 1099 1100 console.debug("GTM detail: ", data); 1101 1102 dataLayer.push(data); 1103 })(); 1104 </script> 1105 } 1106 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 1107 @using Dynamicweb.Core 1108 @using System 1109 @using System.Web 1110 @using System.Collections.Generic 1111 @using Dynamicweb.Rapido.Blocks 1112 1113 @functions { 1114 BlocksPage productDescriptionPage = BlocksPage.GetBlockPage("Product"); 1115 } 1116 1117 @{ 1118 string fullDesctiptionLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("FullDescriptionLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue : "Section"; 1119 fullDesctiptionLayout = fullDesctiptionLayout == "Ribbon" ? "Section" : fullDesctiptionLayout; 1120 1121 if (!string.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && fullDesctiptionLayout != "hide") 1122 { 1123 Block detailsDescription = new Block() 1124 { 1125 Name = fullDesctiptionLayout != "MainInformation" ? Translate("Description") : "", 1126 Id = "FullDescription", 1127 SortId = 10, 1128 Template = RenderProductDescription(fullDesctiptionLayout), 1129 Design = new Design 1130 { 1131 Size = "12", 1132 RenderType = RenderType.Column, 1133 HidePadding = true 1134 } 1135 }; 1136 productDescriptionPage.Add(fullDesctiptionLayout, detailsDescription); 1137 } 1138 } 1139 1140 @helper RenderProductDescription(string layout) 1141 { 1142 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 1143 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 1144 1145 <div class="product__section @ribbonClasses dw-mod"> 1146 <div class="product__description center-container @ribbonSubClasses dw-mod"> 1147 @if (layout == "Section") { 1148 <h2>@Translate("Description")</h2> 1149 } 1150 1151 @GetString("Ecom:Product.LongDescription") 1152 </div> 1153 </div> 1154 } 1155 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 1156 @using Dynamicweb.Core 1157 @using System 1158 @using System.Web 1159 @using System.Globalization; 1160 @using System.Collections.Generic 1161 @using Dynamicweb.Rapido.Blocks 1162 1163 @functions { 1164 BlocksPage productFieldsPage = BlocksPage.GetBlockPage("Product"); 1165 List<LoopItem> downloadDocuments = new List<LoopItem>(); 1166 1167 static string ConvertBytes(long bytes) 1168 { 1169 double size = bytes / 1024; //KB 1170 if (size > 1024) 1171 { 1172 size = (bytes / 1024f) / 1024f; //MB 1173 return string.Format("{0:n1} MB", size); 1174 } 1175 else 1176 { 1177 return string.Format("{0:n0} KB", size); 1178 } 1179 } 1180 1181 static bool isImage(string path) 1182 { 1183 return new List<string> { ".jpg", ".jpeg", ".gif", ".png", ".svg" }.Contains(Path.GetExtension(path).ToLower()); 1184 } 1185 1186 string getIconForFile(string fileName) 1187 { 1188 string ext = Path.GetExtension(fileName); 1189 string icon = ""; 1190 switch (ext.ToLower()) 1191 { 1192 case ".xls": 1193 case ".xlsx": 1194 icon = "fa-file-excel"; 1195 break; 1196 case ".ppt": 1197 case ".pptx": 1198 icon = "fa-file-powerpoint"; 1199 break; 1200 case ".doc": 1201 case ".docx": 1202 icon = "fa-file-word"; 1203 break; 1204 case ".jpg": 1205 case ".jpeg": 1206 case ".png": 1207 case ".gif": 1208 case ".pdf": 1209 return "<img class='product__document-img' alt='" + fileName + "' src='/Admin/Public/GetImage.ashx?crop=5&height=70&width=120&Compression=75&DoNotUpscale=true&image=" + fileName + "' />"; 1210 default: 1211 icon = "fa-file"; 1212 break; 1213 } 1214 return "<i class='product__document-icon far " + icon + "'></i> "; 1215 } 1216 } 1217 1218 @{ 1219 foreach (LoopItem customField in GetLoop("CustomFieldValues")) 1220 { 1221 if (!string.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) && !string.IsNullOrEmpty(customField.GetString("Product.CustomField.Value.Clean")) && customField.GetString("Product.CustomField.Name") != "Custom sticker") 1222 { 1223 if (!string.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 1224 { 1225 downloadDocuments.Add(customField); 1226 } 1227 } 1228 } 1229 1230 foreach (LoopItem customField in GetLoop("ProductCategories")) 1231 { 1232 foreach (LoopItem field in customField.GetLoop("ProductCategoryFields")) 1233 { 1234 if (!string.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Label")) && !string.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Value"))) 1235 { 1236 if (field.GetString("Ecom:Product.CategoryField.TypeID") == "9") 1237 { 1238 downloadDocuments.Add(field); 1239 } 1240 } 1241 } 1242 } 1243 1244 string detailFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout").SelectedValue : "Section"; 1245 detailFieldsLayout = detailFieldsLayout == "Ribbon" || string.IsNullOrEmpty(detailFieldsLayout) ? "Section" : detailFieldsLayout; 1246 string categoryFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout").SelectedValue : "Section"; 1247 categoryFieldsLayout = categoryFieldsLayout == "Ribbon" || string.IsNullOrEmpty(categoryFieldsLayout) ? "Section" : categoryFieldsLayout; 1248 string downloadsFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout").SelectedValue : "Section"; 1249 downloadsFieldsLayout = downloadsFieldsLayout == "Ribbon" || string.IsNullOrEmpty(downloadsFieldsLayout) ? "Section" : downloadsFieldsLayout; 1250 1251 if (GetLoop("CustomFieldValues").Count > 0 && detailFieldsLayout != "hide") 1252 { 1253 // custom 1254 // dont render custom fields 1255 //Block detailsCustom = new Block() 1256 //{ 1257 // Name = detailFieldsLayout != "MainInformation" ? Translate("Details") : "", 1258 // Id = "CustomFields", 1259 // SortId = 30, 1260 // Template = RenderCustomData(detailFieldsLayout), 1261 // Design = new Design 1262 // { 1263 // Size = "12", 1264 // RenderType = RenderType.Column, 1265 // HidePadding = true 1266 // } 1267 //}; 1268 1269 //productFieldsPage.Add(detailFieldsLayout, detailsCustom); 1270 } 1271 1272 if (categoryFieldsLayout != "hide") { 1273 foreach (LoopItem categoryGroup in GetLoop("ProductCategories")) 1274 { 1275 bool hasFields = categoryGroup.GetLoop("ProductCategoryFields").FirstOrDefault(cf => !string.IsNullOrEmpty(cf.GetString("Ecom:Product.CategoryField.Value"))) != null; 1276 if (hasFields) 1277 { 1278 Block detailsCategoryFields = new Block() 1279 { 1280 Name = categoryFieldsLayout != "MainInformation" ? categoryGroup.GetString("Ecom:Product.Category.Name") : "", 1281 Id = ToPascalCase(categoryGroup.GetString("Ecom:Product.Category.Name")), 1282 SortId = 40, 1283 Template = RenderProductCategory(categoryGroup.GetString("Ecom:Product.Category.Name"), categoryGroup, categoryFieldsLayout), 1284 Design = new Design 1285 { 1286 Size = "12", 1287 RenderType = RenderType.Column, 1288 HidePadding = true 1289 } 1290 }; 1291 1292 productFieldsPage.Add(categoryFieldsLayout, detailsCategoryFields); 1293 } 1294 } 1295 } 1296 1297 if (downloadDocuments.Count > 0 && downloadsFieldsLayout != "hide") 1298 { 1299 Block detailsDownloads = new Block() 1300 { 1301 Name = downloadsFieldsLayout != "MainInformation" ? Translate("Downloads") : "", 1302 Id = "Downloads", 1303 SortId = 50, 1304 Template = RenderProductDownloads(downloadsFieldsLayout), 1305 Design = new Design 1306 { 1307 Size = "12", 1308 RenderType = RenderType.Column, 1309 HidePadding = true 1310 } 1311 }; 1312 1313 productFieldsPage.Add(downloadsFieldsLayout, detailsDownloads); 1314 } 1315 } 1316 1317 @helper RenderCustomData(string layout) 1318 { 1319 string viewType = Pageview.AreaSettings.GetItem("ProductPage").GetString("DetailFieldsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsView").SelectedValue : "grid"; 1320 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 1321 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 1322 1323 <div class="product__section @ribbonClasses dw-mod"> 1324 <div class="center-container @ribbonSubClasses dw-mod"> 1325 @if (layout == "Section") { 1326 <h2>@Translate("Information")</h2> 1327 } 1328 1329 @if (viewType != "table") { 1330 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 1331 @RenderCustomFields(GetLoop("CustomFieldValues"), viewType) 1332 </div> 1333 } else { 1334 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12"; 1335 1336 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 1337 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12"> 1338 <table class="table--no-top-border"> 1339 @RenderCustomFields(GetLoop("CustomFieldValues"), viewType) 1340 </table> 1341 </div> 1342 </div> 1343 } 1344 </div> 1345 </div> 1346 } 1347 1348 @helper RenderCustomFields(List<LoopItem> fieldsLoop, string viewType) 1349 { 1350 foreach (LoopItem customField in fieldsLoop) 1351 { 1352 string fieldValue = customField.GetString("Product.CustomField.Value.Clean"); 1353 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 1354 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 1355 1356 if (customField.GetLoop("Product.CustomField.Options").Count > 0) 1357 { 1358 fieldValue = customField.GetString("Product.CustomField.Label"); 1359 } 1360 1361 if (!string.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) && !string.IsNullOrEmpty(fieldValue) && customField.GetString("Product.CustomField.Name") != "Custom sticker") 1362 { 1363 if (string.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 1364 { 1365 @RenderFieldItem(customField.GetString("Product.CustomField.Name"), fieldValue, viewType); 1366 } 1367 } 1368 } 1369 } 1370 1371 @helper RenderProductCategory(string name, LoopItem categoryGroup, string layout) 1372 { 1373 string viewType = Pageview.AreaSettings.GetItem("ProductPage").GetString("CategoryFieldsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsView").SelectedValue : "grid"; 1374 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 1375 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 1376 1377 <div class="product__section @ribbonClasses dw-mod"> 1378 <div class="center-container @ribbonSubClasses dw-mod"> 1379 @if (layout == "Section") { 1380 <h2>@name</h2> 1381 } 1382 1383 @if (viewType != "table") { 1384 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 1385 @RenderProductCategoryFields(categoryGroup.GetLoop("ProductCategoryFields"), viewType) 1386 </div> 1387 } else { 1388 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12"; 1389 1390 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 1391 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12"> 1392 <table class="table--no-top-border"> 1393 @RenderProductCategoryFields(categoryGroup.GetLoop("ProductCategoryFields"), viewType) 1394 </table> 1395 </div> 1396 </div> 1397 } 1398 </div> 1399 </div> 1400 } 1401 1402 @helper RenderProductCategoryFields(List<LoopItem> fieldsLoop, string viewType) { 1403 foreach (LoopItem categoryField in fieldsLoop) 1404 { 1405 string fieldValue = categoryField.GetString("Ecom:Product.CategoryField.Value"); 1406 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 1407 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 1408 1409 if (!string.IsNullOrEmpty(categoryField.GetString("Ecom:Product.CategoryField.Label")) && !string.IsNullOrEmpty(fieldValue)) 1410 { 1411 if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") != "9") { 1412 if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") == "15") 1413 { 1414 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), categoryField.GetString("Ecom:Product.CategoryField.OptionLabel"), viewType); 1415 } 1416 else if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") == "8") 1417 { 1418 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType, "link"); 1419 } 1420 else 1421 { 1422 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType); 1423 } 1424 } 1425 } 1426 } 1427 } 1428 1429 @helper RenderProductDownloads(string layout) 1430 { 1431 string viewType = Pageview.AreaSettings.GetItem("ProductPage").GetString("DownloadsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsView").SelectedValue : "grid"; 1432 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 1433 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 1434 1435 <div class="product__section @ribbonClasses dw-mod"> 1436 <div class="center-container @ribbonSubClasses dw-mod"> 1437 @if (layout == "Section") { 1438 <h2>@Translate("Downloads")</h2> 1439 } 1440 1441 @if (viewType != "table") { 1442 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 1443 @RenderProductDownloadsFields(downloadDocuments, viewType) 1444 </div> 1445 } else { 1446 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12"; 1447 1448 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 1449 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12"> 1450 <table class="table--no-top-border"> 1451 @RenderProductDownloadsFields(downloadDocuments, viewType) 1452 </table> 1453 </div> 1454 </div> 1455 } 1456 </div> 1457 </div> 1458 } 1459 1460 @helper RenderProductDownloadsFields(List<LoopItem> fieldsLoop, string viewType) { 1461 foreach (LoopItem document in fieldsLoop) 1462 { 1463 string fieldValue; 1464 if (!string.IsNullOrEmpty(document.GetString("Document.FullPath"))) 1465 { 1466 fieldValue = document.GetString("Product.CustomField.Value.Clean"); 1467 @RenderFieldItem(fieldValue, document.GetString("Document.FullPath"), viewType, "download") 1468 } 1469 1470 if (document.GetString("Ecom:Product.CategoryField.TypeID") == "9") 1471 { 1472 fieldValue = document.GetString("Ecom:Product.CategoryField.Value"); 1473 @RenderFieldItem(fieldValue, fieldValue, viewType, "download") 1474 } 1475 } 1476 } 1477 1478 @helper RenderFieldItem(string name, string value, string viewType, string fieldType = "clean") 1479 { 1480 if (viewType != "table") { 1481 string fieldColumns = viewType == "list" ? "12" : "4"; 1482 <div class="grid__col-md-@fieldColumns u-margin-bottom"> 1483 <div class="u-bold"> 1484 @name 1485 </div> 1486 <div> 1487 @RenderFieldItemContent(name, value, fieldType) 1488 </div> 1489 </div> 1490 } else { 1491 <tr> 1492 @if (fieldType == "download") { 1493 <td colspan="2"> 1494 @RenderFieldItemContent(name, value, fieldType) 1495 </td> 1496 } 1497 else 1498 { 1499 <td class="u-bold">@name</td> 1500 <td> 1501 @RenderFieldItemContent(name, value, fieldType) 1502 </td> 1503 } 1504 </tr> 1505 } 1506 } 1507 1508 @helper RenderFieldItemContent(string name, string value, string fieldType = "clean") 1509 { 1510 if (fieldType == "link") 1511 { 1512 <a target="_blank" href="@value"> 1513 @if (isImage(value)) { 1514 @getIconForFile(value) 1515 } else { 1516 @value 1517 } 1518 </a> 1519 } 1520 else if (fieldType == "download") 1521 { 1522 FileInfo info = new FileInfo(Dynamicweb.Core.SystemInformation.MapPath(value)); 1523 1524 if (info.Exists) { 1525 <div class="grid grid--no-wrap"> 1526 <a href="@name" download title="@Translate("Download")" class="product__document u-min-w120px u-ta-center dw-mod">@getIconForFile(value)</a> 1527 <div class="product__document-info dw-mod"> 1528 <a href="@name" download title="@Translate("Download")" class="product__document dw-mod">@Path.GetFileName(value)</a> 1529 <small class="u-block u-margin-top">@ConvertBytes(info.Length)</small> 1530 </div> 1531 </div> 1532 } 1533 } 1534 else 1535 { 1536 @value 1537 } 1538 } 1539 1540 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 1541 @using Dynamicweb.Core 1542 @using System 1543 @using System.Web 1544 @using System.Collections.Generic 1545 @using Dynamicweb.Rapido.Blocks 1546 1547 @functions { 1548 BlocksPage productVariantsPage = BlocksPage.GetBlockPage("Product"); 1549 } 1550 1551 @{ 1552 bool renderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetString("RenderVariantsAsProductList") != null && GetInteger("Ecom:Product.VariantCount") > 1 ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") : false; 1553 bool variantsOnlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null; 1554 string variantsListPageSize = HttpContext.Current.Request.QueryString.Get("PageSize") != null ? HttpContext.Current.Request.QueryString.Get("PageSize") : "30"; 1555 string variantsFeedUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + variantsListPageSize + "&MainProductID=" + GetString("Ecom:Product.ID") + "&OnlyShowVariants=true&feed=true"; 1556 string variantsCartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetString("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 1557 bool variantsPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 1558 1559 string variantsListLayout = Pageview.AreaSettings.GetItem("ProductPage").GetString("VariantsListLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue : "Section"; 1560 variantsListLayout = variantsListLayout == "Ribbon" ? "Section" : variantsListLayout; 1561 1562 if (renderVariantsAsProducts && variantsListLayout != "hide") 1563 { 1564 Block detailsVariantsList = new Block() 1565 { 1566 Name = variantsListLayout != "MainInformation" ? Translate("Variants list") : "", 1567 Id = "VariantsList", 1568 SortId = 20, 1569 Template = RenderVariantsProductList(variantsListLayout), 1570 Design = new Design 1571 { 1572 Size = "12", 1573 RenderType = RenderType.Column, 1574 HidePadding = true 1575 } 1576 }; 1577 productVariantsPage.Add(variantsListLayout, detailsVariantsList); 1578 } 1579 } 1580 1581 @helper RenderVariantsProductList(string layout) 1582 { 1583 string variantsListPageSize = HttpContext.Current.Request.QueryString.Get("PageSize") != null ? HttpContext.Current.Request.QueryString.Get("PageSize") : "30"; 1584 string variantsFeedUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + variantsListPageSize + "&MainProductID=" + GetString("Ecom:Product.ID") + "&OnlyShowVariants=true&feed=true"; 1585 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 1586 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 1587 1588 <div class="product__section @ribbonClasses dw-mod"> 1589 <div class="center-container @ribbonSubClasses dw-mod"> 1590 @if (layout == "Section") 1591 { 1592 <h2>@Translate("Variants")</h2> 1593 } 1594 1595 <div class="js-handlebars-root" id="VariantsListRoot" data-template="VariantProductsContainer" data-json-feed="@variantsFeedUrl" data-preloader="minimal"></div> 1596 </div> 1597 </div> 1598 } 1599 1600 1601 @* Script templates for variant products *@ 1602 1603 <script id="VariantProductsContainer" type="text/x-template"> 1604 {{#.}} 1605 <div class=""> 1606 <table id="VariantsProductsContainer" class="table u-position-relative dw-mod"> 1607 <thead> 1608 <tr> 1609 <td width="75">&nbsp;</td> 1610 <td>@Translate("Product")</td> 1611 {{#AvailableCustomFields}} 1612 {{>TableFieldNameTemplate}} 1613 {{/AvailableCustomFields}} 1614 @if (Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantGroupsInTable")) 1615 { 1616 foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 1617 { 1618 <td>@variantgroup.GetString("Ecom:VariantGroup.Name")</td> 1619 } 1620 } 1621 <td width="360">&nbsp;</td> 1622 </tr> 1623 </thead> 1624 1625 <tbody id="VariantProductListContainer" data-template="VariantProductItemContainer" data-save-cookie="true"> 1626 {{#ProductsContainer}} 1627 {{>VariantProductItemContainer}} 1628 {{/ProductsContainer}} 1629 </tbody> 1630 </table> 1631 </div> 1632 1633 <div class="grid"> 1634 <div class="grid__col-12 grid__col--bleed-y"> 1635 <button type="button" id="LoadMoreButton" class="btn btn--secondary btn--full {{nextdisabled}} dw-mod" data-current="{{currentPage}}" data-page-size="{{pageSize}}" data-total="{{totalPages}}" data-container="VariantProductListContainer" data-feed-url="@variantsFeedUrl{{loadMoreFeedParams}}" onclick="LoadMore.Next(this)" {{nextdisabled}}>@Translate("Load") @Translate("more")</button> 1636 </div> 1637 </div> 1638 {{/.}} 1639 </script> 1640 1641 <script id="VariantProductItemContainer" type="text/x-template"> 1642 {{#.}} 1643 <tr id="VariantProduct{{id}}" data-template="VariantProductItem" data-preloader="overlay" style="z-index: {{zIndex}}"> 1644 {{#Product}} 1645 {{>VariantProductItem}} 1646 {{/Product}} 1647 </tr> 1648 {{/.}} 1649 </script> 1650 1651 <script id="VariantProductItem" type="text/x-template"> 1652 {{#.}} 1653 <td width="75"> 1654 <div class="lightbox u-hidden-xxs"> 1655 <a href="{{link}}" onclick="Scroll.SavePosition(event)"> 1656 <img class="lightbox__image {{noImage}}" src="{{PerfionImageSrc imageGuid 220 220}}" alt="{{name}}" /> 1657 <div class="u-margin-right {{noImage}}"> 1658 <img src="{{PerfionImageSrc imageGuid 75 55}}" alt="{{name}}" /> 1659 </div> 1660 </a> 1661 </div> 1662 </td> 1663 <td class="u-va-middle"> 1664 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6 class="u-no-margin">{{name}}</h6></a> 1665 <div class="item-number item-number--compressed dw-mod"> 1666 {{#if showProductNumber}}{{number}}{{/if}} 1667 @if (!variantsOnlyPreview) 1668 { 1669 @* Custom *@ 1670 <div> 1671 <span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span>&nbsp;{{stockText}} 1672 <p>{{deliveryText}}</p> 1673 </div> 1674 } 1675 else 1676 { 1677 <div class="grid__cell-footer stickers-container stickers-container--block dw-mod"> 1678 {{#Stickers}} 1679 {{>MiniSticker}} 1680 {{/Stickers}} 1681 </div> 1682 } 1683 </div> 1684 </td> 1685 {{#CustomFields}} 1686 {{>TableFieldValueTemplate}} 1687 {{/CustomFields}} 1688 @if (Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantGroupsInTable")) 1689 { 1690 <text> 1691 {{#VariantSelectionNames}} 1692 {{>TableFieldNameTemplate}} 1693 {{/VariantSelectionNames}} 1694 </text> 1695 } 1696 <td width="320" class="u-va-middle"> 1697 @if (!variantsOnlyPreview) 1698 { 1699 <text>{{#if showPrice}}</text> 1700 <div class="u-hidden-sm"> 1701 <div class="u-full-width u-ta-right u-padding-right"> 1702 <div class="before-price {{onSale}} before-price--micro dw-mod">{{discount}}</div> 1703 <div class="price price--product-list price--micro dw-mod">{{price}}</div> 1704 </div> 1705 </div> 1706 <text>{{/if}}</text> 1707 <text>{{#if showContactInfo}}</text> 1708 <p class="pp__zeroprice-text">@Translate("ZeroPriceText", "Kontakt vores kundeservice for at få oplyst pris.")</p> 1709 <p class="pp__zeroprice-contact">@Translate("ZeroPriceContact", "Ring på tlf: 7021 2626 (kl. 8.00-16.00) eller skriv til salg@p-lindberg.dk")</p> 1710 <text>{{/if}}</text> 1711 } 1712 else 1713 { 1714 <div class="grid grid--align-center grid--justify-end"> 1715 <div class="favorites u-margin-right {{hasVariants}} dw-mod" {{hasVariants}}> 1716 {{#Favorite}} 1717 {{>FavoriteTemplate}} 1718 {{/Favorite}} 1719 </div> 1720 <div class="u-margin-right"> 1721 <input type="checkbox" id="UnitOptions_{{id}}" class="dropdown-trigger" /> 1722 <div class="dropdown u-w120px {{hasUnits}} dw-mod"> 1723 <label class="dropdown__header dropdown__btn dw-mod" for="UnitOptions_{{id}}">{{unitName}}</label> 1724 <div id="unitOptions" class="dropdown__content dw-mod"> 1725 {{#unitOptions}} 1726 {{>UnitOption}} 1727 {{/unitOptions}} 1728 </div> 1729 <label class="dropdown-trigger-off" for="UnitOptions_{{id}}"></label> 1730 </div> 1731 <input type="hidden" value="{{unitId}}" name="Unit{{id}}" id="Unit_{{id}}" /> 1732 <input type="hidden" value="{{variantid}}" name="VariantID{{id}}" id="Variant_{{id}}" /> 1733 </div> 1734 <div class="u-margin-right u-hidden-xs u-hidden-xxs"> 1735 @if (variantsPointShopOnly) 1736 { 1737 <text> 1738 {{#if canBePurchasedWithPoints}} 1739 <div class="price price--product-list price--micro dw-mod">{{points}} @Translate("points")</div> 1740 {{else}} 1741 {{#if havePointPrice}} 1742 <small class="help-text u-no-margin u-margin-top">@Translate("Not enough points to buy this")</small> 1743 {{else}} 1744 <small class="help-text u-no-margin u-margin-top">@Translate("Not available")</small> 1745 {{/if}} 1746 {{/if}} 1747 </text> 1748 } 1749 else 1750 { 1751 <text>{{#if showPrice}}</text> 1752 <div class="before-price before-price--micro {{onSale}} dw-mod">{{discount}}</div> 1753 <div class="price price--condensed price--product-list dw-mod">{{price}}</div> 1754 <text>{{/if}}</text> 1755 <text>{{#if showContactInfo}}</text> 1756 <p class="pp__zeroprice-text">@Translate("ZeroPriceText", "Kontakt vores kundeservice for at få oplyst pris.")</p> 1757 <p class="pp__zeroprice-contact">@Translate("ZeroPriceContact", "Ring på tlf: 7021 2626 (kl. 8.00-16.00) eller skriv til salg@p-lindberg.dk")</p> 1758 <text>{{/if}}</text> 1759 } 1760 </div> 1761 <text>{{#if showPrice}}</text> 1762 @if (variantsPointShopOnly) 1763 { 1764 <div> 1765 <button {{#unless canBePurchasedWithPoints}} disabled{{/unless}} type="button" 1766 id="CartButton_{{id}}" 1767 class="btn btn--primary btn--condensed u-no-margin dw-mod js-cart-btn {{#unless canBePurchasedWithPoints}}disabled js-stay-disabled{{/unless}}" 1768 name="CartCmd" 1769 value="addWithPoints" 1770 onclick="Cart.AddToCart(event, { 1771 id: '{{productId}}', 1772 variantId: '{{variantid}}', 1773 unitId: '{{unitId}}', 1774 quantity: 1, 1775 buyForPoints: true, 1776 productInfo: {{productInfo}} 1777 })"> 1778 <i class="@variantsCartIcon"></i> 1779 </button> 1780 </div> 1781 } 1782 else 1783 { 1784 <div> 1785 <input type="number" class="u-w80px u-no-margin u-margin-right" id="Quantity_{{id}}" name="Quantity{{id}}" value="1" min="1"> 1786 </div> 1787 <div> 1788 <button type="button" id="CartButton_{{id}}" class="btn btn--primary btn--condensed u-no-margin dw-mod" name="submit" 1789 onclick="Cart.AddToCart(event, { 1790 id: '{{productId}}', 1791 variantId: '{{variantid}}', 1792 unitId: '{{unitId}}', 1793 quantity: document.getElementById('Quantity_{{id}}').value, 1794 productInfo: {{productInfo}} 1795 });"> 1796 <i class="@variantsCartIcon"></i> 1797 </button> 1798 </div> 1799 } 1800 <text>{{/if}}</text> 1801 </div> 1802 } 1803 </td> 1804 {{/.}} 1805 </script> 1806 1807 <script id="TableFieldNameTemplate" type="text/x-template"> 1808 <td class="u-va-middle">{{name}}</td> 1809 </script> 1810 1811 <script id="TableFieldValueTemplate" type="text/x-template"> 1812 <td class="u-va-middle">{{value}}</td> 1813 </script> 1814 1815 <script id="MiniSticker" type="text/x-template"> 1816 <div class="stickers-container__tag stickers-container__tag--micro {{className}} dw-mod">{{text}}</div> 1817 </script> 1818 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 1819 @using Dynamicweb.Core 1820 @using System 1821 @using System.Web 1822 @using System.Collections.Generic 1823 @using Dynamicweb.Rapido.Blocks 1824 1825 @using PLindberg.Dynamicweb.Common; 1826 1827 @functions{ 1828 BlocksPage productRelatedPage = BlocksPage.GetBlockPage("Product"); 1829 } 1830 1831 @{ 1832 string relatedProductsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue : "Section"; 1833 relatedProductsLayout = relatedProductsLayout == "Ribbon" || string.IsNullOrEmpty(relatedProductsLayout) ? "Section" : relatedProductsLayout; 1834 bool relatedOnlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null; 1835 bool relatedPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 1836 1837 int relatedProductsPageSize = 4; 1838 int relatedProductsColumnWidth = 3; 1839 1840 if (Pageview.Device.ToString() == "Mobile") 1841 { 1842 relatedProductsPageSize = 1; 1843 relatedProductsColumnWidth = 12; 1844 } 1845 1846 if (Pageview.Device.ToString() == "Tablet") 1847 { 1848 relatedProductsPageSize = 2; 1849 relatedProductsColumnWidth = 6; 1850 } 1851 1852 if (relatedProductsLayout != "hide") 1853 { 1854 // custom (only use related product group here) 1855 var relationGroupId = new WebConfigSettings().GetValue("Perfion/Global", "RelatedProductsRelatedGroupId"); 1856 1857 //string relationGroupId = Dynamicweb.Base.GetGs("/Globalsettings/Picopublish/Global/RelatedProductsRelatedGroupId"); 1858 var relatedGroup = GetLoop("ProductRelatedGroups").FirstOrDefault(l => l.GetString("Ecom:Product:RelatedGroup.GroupID") == relationGroupId && l.GetLoop("Products").Count() > 0); 1859 1860 if (relatedGroup != null) 1861 { 1862 // custom 1863 string relatedGroupId = relatedGroup.GetString("Ecom:Product:RelatedGroup.Name"); 1864 string baseFeedPageUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + relatedProductsPageSize + "&ProdID=" + GetString("Ecom:Product.ID") + "&feed=true"; 1865 string relatedFeed = baseFeedPageUrl + "&" + relatedGroupId + "=" + GetString("Ecom:Product.ID") + "&GroupName=" + relatedGroupId; 1866 string relatedGroupName = relatedProductsLayout != "maininformation" ? relatedGroup.GetString("Ecom:Product:RelatedGroup.Name") : ""; 1867 1868 Block detailsRelated = new Block() 1869 { 1870 Name = relatedGroupName, 1871 Id = relatedGroupId, 1872 SortId = 70, 1873 Template = RenderRelatedProducts(relatedGroupName, relatedGroupId, relatedFeed, relatedProductsLayout), 1874 Design = new Design 1875 { 1876 Size = "12", 1877 RenderType = RenderType.Column, 1878 HidePadding = true 1879 } 1880 }; 1881 1882 productRelatedPage.Add(relatedProductsLayout, detailsRelated); 1883 } 1884 } 1885 } 1886 1887 @helper RenderRelatedProducts(string name, string groupId, string relatedFeedUrl, string layout) 1888 { 1889 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 1890 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 1891 1892 <div class="product__section @ribbonClasses dw-mod"> 1893 <div class="center-container @ribbonSubClasses dw-mod "> 1894 @if (layout == "Section") 1895 { 1896 <h2 class="u-margin-top">@Translate("RelatedHeading", "Relaterede varer")</h2> 1897 } 1898 1899 <div class="js-handlebars-root" id="ProductList_@groupId" data-template="ProductContainer" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedFeedUrl" data-preloader="minimal"></div> 1900 </div> 1901 </div> 1902 } 1903 1904 @helper RenderRelatedProductsMini(string name, string groupId, string relatedFeedUrl) 1905 { 1906 <div class="js-handlebars-root" id="ProductList_@groupId" data-template="ProductContainerMini" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedFeedUrl" data-preloader="minimal"></div> 1907 } 1908 1909 @* Script templates for related products *@ 1910 <script id="ProductPreRenderContainer" type="text/x-template"> 1911 <div class="u-h600px u-full-width"> 1912 <div class="grid"> 1913 <div class="grid__col-12"> 1914 <div class="pre-render-element pre-render-element--md"></div> 1915 </div> 1916 </div> 1917 </div> 1918 </script> 1919 1920 <script id="ProductContainer" type="text/x-template"> 1921 {{#.}} 1922 <div class="u-min-h400px u-full-width "> 1923 <div class="grid"> 1924 <div class="grid__col-45px grid__col--bleed-x relatedleft"> 1925 <div class="grid__cell grid__cell--align-middle-left"> 1926 <button class="btn btn--condensed btn--clean {{prevdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{prevPage}}')" {{prevdisabled}}><i class="fas fa-chevron-left fa-2x"></i></button> 1927 </div> 1928 </div> 1929 <div class="grid__col-auto grid__col--bleed-x"> 1930 <div id="ProductsContainer" data-template="ProductGridItemContainer" class="grid product-list dw-mod" data-save-cookie="true"> 1931 {{#ProductsContainer}} 1932 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__grid-item dw-mod"> 1933 {{#Product}} 1934 @if (useGoogleTagManager) 1935 { 1936 <text>{{{googleEnchantImpression 'Related products' currency googleImpression}}}</text> 1937 } 1938 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}"> 1939 <div class="stickers-container dw-mod"> 1940 {{#Stickers}} 1941 {{>Sticker}} 1942 {{/Stickers}} 1943 </div> 1944 {{!-- custom --}} 1945 <a href="{{link}}" onclick="Scroll.SavePosition(event)"><img class="grid__cell-img grid__cell-img--centered u-padding b-lazy" src="/Files/Images/placeholder.gif" data-src="{{PerfionImageSrc imageGuid 200 200}}" alt="{{name}}" /></a> 1946 </div> 1947 <div class="grid__cell product-list__grid-item__price-info {{shortGridInfo}} dw-mod"> 1948 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6>{{name}}</h6></a> 1949 {{#if showProductNumber}} 1950 <div class="item-number dw-mod">{{number}}</div> 1951 {{/if}} 1952 1953 {{#ifCond PerfionProductFreightAddon "==" true }} 1954 <div class="freigtextra related" title='@Translate("Freightaddon", "Fragttillæg")'> 1955 <i class="fas fa-truck"></i> 1956 </div> 1957 {{/ifCond}} 1958 1959 @if (!relatedOnlyPreview) 1960 { 1961 if (relatedPointShopOnly) 1962 { 1963 <text> 1964 {{#if havePointPrice}} 1965 <div>{{points}} @Translate("points")</div> 1966 {{else}} 1967 @Translate("Not available") 1968 {{/if}} 1969 </text> 1970 } 1971 else 1972 { 1973 @* custom *@ 1974 <div class="priceinfocontainer"> 1975 <text>{{#if showPrice}}</text> 1976 <text>{{#if showinfoPrice}}</text> 1977 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 1978 <div class="price price--product-list dw-mod newprice"><span>@Translate("Nu", "Nu")</span>{{price}}</div> 1979 <div class="price price--product-list price withoutvat dw-mod">{{priceWithoutVat}} @Translate("EksMoms", "ex. moms")</div> 1980 <div class="price price--product-list price withoutvat dw-mod beforeprice"><span>@Translate("Beforeprice", "Før")</span> {{informativePrice.priceWithVat}}</div> 1981 <div class="price price--product-list price withoutvat dw-mod">{{informativePrice.price}} @Translate("EksMoms", "ex. moms")</div> 1982 <text>{{else}}</text> 1983 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 1984 <div class="price price--product-list dw-mod">{{price}}</div> 1985 <div class="price price--product-list price withoutvat dw-mod">{{priceWithoutVat}} @Translate("EksMoms", "ex. moms")</div> 1986 <text>{{/if}}</text> 1987 <text>{{/if}}</text> 1988 1989 <text>{{#ifCond startPrice "&&" showVariantPrice}}</text> 1990 <div class="pp__startprice-container"> 1991 {{#if isStartingPrice}} 1992 <span class="price price--product-list dw-mod pp__startprice">@Translate("StartingFrom", "Fra") {{startPrice.priceWithVat}}</span> 1993 <div class="price price--product-list price withoutvat dw-mod">@Translate("StartingFrom", "Fra") {{startPrice.price}} @Translate("EksMoms", "ex. moms")</div> 1994 {{/if}} 1995 {{#unless isStartingPrice}} 1996 <span class="price price--product-list dw-mod pp__startprice">{{startPrice.priceWithVat}}</span> 1997 <div class="price price--product-list price withoutvat dw-mod">{{startPrice.price}} @Translate("EksMoms", "ex. moms")</div> 1998 {{/unless}} 1999 </div> 2000 <text>{{/ifCond}}</text> 2001 <p class="priceinfocontainer__additional-costs" onclick="document.getElementById('additional-costs-related-trigger').click(); return false;">@Translate("Additional costs", "Øvrige omk. tillægges")</p> 2002 </div> 2003 } 2004 } 2005 </div> 2006 2007 <div class="product-list__grid-item__footer dw-mod"> 2008 <div class="u-ta-center"> 2009 <a href="{{link}}" id="CartButton_{{id}}" class="btn btn--primary u-no-margin dw-mod">@Translate("View")</a> 2010 </div> 2011 </div> 2012 {{/Product}} 2013 </div> 2014 {{/ProductsContainer}} 2015 </div> 2016 </div> 2017 <div class="grid__col-45px grid__col--bleed-x relatedright"> 2018 <div class="grid__cell grid__cell--align-middle-right"> 2019 <button class="btn btn--condensed btn--clean {{nextdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{nextPage}}')" {{nextdisabled}}><i class="fas fa-chevron-right fa-2x"></i></button> 2020 </div> 2021 </div> 2022 </div> 2023 </div> 2024 {{/.}} 2025 </script> 2026 2027 <script id="ProductContainerMini" type="text/x-template"> 2028 {{#.}} 2029 <div class="u-full-width"> 2030 <div class="grid"> 2031 <div class="grid__col-45px grid__col--bleed-x relatedleft"> 2032 <div class="grid__cell grid__cell--align-middle-left"> 2033 <button class="btn btn--condensed btn--clean {{prevdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{prevPage}}')" {{prevdisabled}}><i class="fas fa-chevron-left fa-2x"></i></button> 2034 </div> 2035 </div> 2036 <div class="grid__col-auto grid__col--bleed-x"> 2037 <div id="ProductsContainer" class="grid product-list dw-mod"> 2038 {{#ProductsContainer}} 2039 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__grid-item dw-mod"> 2040 {{#Product}} 2041 @if (useGoogleTagManager) 2042 { 2043 <text>{{{googleEnchantImpression 'Related products' currency googleImpression}}}</text> 2044 } 2045 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}"> 2046 <div class="stickers-container dw-mod"> 2047 {{#Stickers}} 2048 {{>Sticker}} 2049 {{/Stickers}} 2050 </div> 2051 <a href="{{link}}" onclick="Scroll.SavePosition(event)"><img class="grid__cell-img grid__cell-img--centered b-lazy" src="/Files/Images/placeholder.gif" data-src="/Admin/Public/GetImage.ashx?width=300&amp;height=300&amp;crop=5&amp;Compression=75&amp;FillCanvas=true&amp;DoNotUpscale=true&amp;image={{image}}" alt="{{name}}" /></a> 2052 </div> 2053 2054 <div class="grid__cell product-list__grid-item__price-info {{shortGridInfo}} dw-mod"> 2055 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6 class="u-condensed-text">{{name}}</h6></a> 2056 {{#if showProductNumber}} 2057 <div class="item-number dw-mod">{{number}}</div> 2058 {{/if}} 2059 @if (!relatedOnlyPreview) 2060 { 2061 if (relatedPointShopOnly) 2062 { 2063 <text> 2064 {{#if havePointPrice}} 2065 <div>{{points}} @Translate("points")</div> 2066 {{else}} 2067 @Translate("Not available") 2068 {{/if}} 2069 </text> 2070 } 2071 else 2072 { 2073 <div>{{price}}</div> 2074 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 2075 } 2076 } 2077 </div> 2078 {{/Product}} 2079 </div> 2080 {{/ProductsContainer}} 2081 </div> 2082 </div> 2083 <div class="grid__col-45px grid__col--bleed-x relatedright"> 2084 <div class="grid__cell grid__cell--align-middle-right"> 2085 <button class="btn btn--condensed btn--clean {{nextdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{nextPage}}')" {{nextdisabled}}><i class="fas fa-chevron-right fa-2x"></i></button> 2086 </div> 2087 </div> 2088 </div> 2089 </div> 2090 {{/.}} 2091 </script> 2092 2093 <script id="Sticker" type="text/x-template"> 2094 <div class="stickers-container__tag {{className}} dw-mod">{{text}}</div> 2095 </script> 2096 2097 @* Favorites templates *@ 2098 2099 <script id="FavoriteTemplate" type="text/x-template"> 2100 <div class="favorites-list u-ta-left"> 2101 <label for="FavoriteTrigger_{{id}}" class="u-no-margin"><i class="{{favoriteIcon}} fa-1_5x"></i></label> 2102 <input type="checkbox" id="FavoriteTrigger_{{id}}" class="dropdown-trigger" /> 2103 <div class="dropdown dropdown--absolute-position"> 2104 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 2105 <ul class="list list--clean dw-mod"> 2106 {{#FavoriteLists}} 2107 {{>FavoriteListItem}} 2108 {{/FavoriteLists}} 2109 </ul> 2110 </div> 2111 <label class="dropdown-trigger-off" for="FavoriteTrigger_{{id}}"></label> 2112 </div> 2113 </div> 2114 </script> 2115 2116 <script id="FavoriteListItem" type="text/x-template"> 2117 <li> 2118 <a href="{{link}}" class="list__link u-no-underline dw-mod" onclick="{{facebookPixelAction}}"><i class="{{favoriteIcon}}"></i> {{name}}</a> 2119 </li> 2120 </script> 2121 2122 2123 2124 @{ 2125 Block AddCostsModalHeaderRelated = new Block() 2126 { 2127 Id = "AdditionalCostsModalRelatedHeader", 2128 Name = "Modal Header", 2129 Template = RenderAddCostsModalHeaderRelated() 2130 }; 2131 Block AddCostsModalBodyRelated = new Block() 2132 { 2133 Id = "AdditionalCostsModalRelatedBody", 2134 Name = "Modal Body", 2135 Template = RenderAddCostsModalBodyRelated() 2136 }; 2137 } 2138 2139 2140 @RenderModalDialog("additional-costs-related", AddCostsModalHeaderRelated, AddCostsModalBodyRelated, "modal--lg") 2141 2142 @helper RenderAddCostsModalHeaderRelated() 2143 { 2144 string additionalCostsHeadline = Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsHeadline") != null ? Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsHeadline") : ""; 2145 <h2>@additionalCostsHeadline</h2> 2146 2147 } 2148 @helper RenderAddCostsModalBodyRelated() 2149 { 2150 <div class="additional-costs-content"> 2151 @{ 2152 2153 string additionalCostsText = Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsText") != null ? Pageview.AreaSettings.GetItem("Custom").GetString("additionalCostsText") : ""; 2154 2155 <div>@additionalCostsText</div> 2156 } 2157 </div> 2158 2159 } 2160 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2161 2162 @* 2163 NOTICE: Some blocks depend on each other, so the priority here matters. 2164 *@ 2165 2166 @* Trustpilot after stock *@ 2167 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2168 @using System.Linq 2169 @using Dynamicweb.Rapido.Blocks 2170 2171 @{ 2172 2173 2174 2175 Block Trustpilot = new Block() 2176 { 2177 Id = "Trustpilot", 2178 SortId = 91, 2179 Template = RenderTrustpilot() 2180 }; 2181 2182 mainInfoPage.Add("MainInformation", Trustpilot); 2183 2184 } 2185 2186 @helper RenderTrustpilot() 2187 { 2188 if (GetString("Ecom:Product.LanguageID") == "LANG2") 2189 { 2190 <!-- TrustBox script --> 2191 <script type="text/javascript" src="//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js" async></script> 2192 <!-- End TrustBox script --> 2193 <div class="trustpilotcontainer product" style="margin-left: -9px;"> 2194 <!-- TrustBox widget - Drop-Down --> 2195 <div class="trustpilot-widget" data-locale="da-DK" data-template-id="5418052cfbfb950d88702476" data-businessunit-id="46a167b20000640005006fd2" data-style-height="30px" data-style-width="305px" data-theme="light" data-stars="1,2,3,4,5" data-review-languages="da"> 2196 <a href="https://dk.trustpilot.com/review/www.p-lindberg.dk" target="_blank" rel="noopener">Trustpilot</a> 2197 </div> 2198 2199 <!-- End TrustBox widget --> 2200 2201 </div> 2202 } 2203 2204 } 2205 2206 2207 2208 2209 @* Description override *@ 2210 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2211 @using Dynamicweb.Core 2212 @using System 2213 @using System.Web 2214 @using System.Collections.Generic 2215 @using Dynamicweb.Rapido.Blocks 2216 2217 @functions { 2218 BlocksPage customProductDescriptionPage = BlocksPage.GetBlockPage("Product"); 2219 } 2220 2221 @{ 2222 string layout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("FullDescriptionLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue : "Section"; 2223 layout = layout == "Ribbon" ? "Section" : layout; 2224 2225 // tabs layout is handled by live integration 2226 if (layout != "Tabs") 2227 { 2228 if (!string.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && layout != "hide") 2229 { 2230 Block detailsDescription = new Block() 2231 { 2232 Name = layout != "MainInformation" ? Translate("Description") : "", 2233 Id = "FullDescription", 2234 SortId = 10, 2235 Template = CustomRenderProductDescription(layout), 2236 Design = new Design 2237 { 2238 Size = "12", 2239 RenderType = RenderType.Column, 2240 HidePadding = true 2241 } 2242 }; 2243 customProductDescriptionPage.ReplaceBlock(detailsDescription); 2244 } 2245 } 2246 } 2247 2248 @helper CustomRenderProductDescription(string layout) 2249 { 2250 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 2251 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 2252 2253 <div class="product__section @ribbonClasses dw-mod"> 2254 <div class="product__description center-container @ribbonSubClasses dw-mod"> 2255 @if (layout == "Section") 2256 { 2257 <h2>@Translate("Description")</h2> 2258 } 2259 2260 @GetString("Ecom:Product.LongDescription") 2261 </div> 2262 </div> 2263 } 2264 2265 @* Chemical section after description *@ 2266 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2267 @using Dynamicweb.Core 2268 @using System 2269 @using System.Linq 2270 @using System.Web 2271 @using System.Collections.Generic 2272 @using Dynamicweb.Ecommerce.International 2273 @using Dynamicweb.Rapido.Blocks 2274 2275 @using PLindberg.Dynamicweb; 2276 @functions { 2277 BlocksPage productPage = BlocksPage.GetBlockPage("Product"); 2278 } 2279 2280 @{ 2281 var chemicalValues = new string[] { 2282 GetString("Ecom:Product:Field.PerfionChemicalHSentences"), 2283 GetString("Ecom:Product:Field.PerfionChemicalEUHSentences"), 2284 GetString("Ecom:Product:Field.PerfionChemicalPSentences"), 2285 GetString("Ecom:Product:Field.PerfionChemicalGHSSentences"), 2286 GetString("Ecom:Product:Field.PerfionChemicalSignalWords"), 2287 GetString("Ecom:Product:Field.PerfionChemicalPictogramImages") 2288 }; 2289 2290 // if there is some chemical information 2291 if (chemicalValues.Any(v => !string.IsNullOrEmpty(v))) 2292 { 2293 string desctiptionLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("FullDescriptionLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue : "Section"; 2294 Block chemicalSectionBlock = new Block() 2295 { 2296 Name = "ChemicalSection", 2297 Id = "ChemicalSection", 2298 SortId = 10, 2299 Template = RenderChemicalLayout(), 2300 SkipRenderBlocksList = false, 2301 Design = new Design 2302 { 2303 Size = "12", 2304 RenderType = RenderType.Column, 2305 HidePadding = false 2306 } 2307 }; 2308 2309 productPage.Add(desctiptionLayout, chemicalSectionBlock); 2310 } 2311 } 2312 2313 @helper RenderChemicalLayout() 2314 { 2315 <div class="chemical__section dw-mod"> 2316 <div class="grid"> 2317 <div class="grid__col-8"> 2318 <h2>@Translate("ChemicalEnvironmentAndSafety")</h2> 2319 <hr class="splitter" /> 2320 @RenderChemicalEnvironment() 2321 </div> 2322 <div class="grid__col-4"> 2323 @RenderDangerImages() 2324 </div> 2325 <div class="grid__col-12"> 2326 @RenderChemicalUN() 2327 </div> 2328 @* Chemical data sheets *@ 2329 {{#if hasDatasheets}} 2330 {{#showFiles files "@currentLanguageId"}} 2331 <div class="grid__col-12"> 2332 <h2>@Translate("Datasheets", "Produktblade")</h2> 2333 <hr class="splitter" /> 2334 </div> 2335 {{/showFiles}} 2336 {{/if}} 2337 {{#files}} 2338 {{#showFile caption "@currentLanguageId"}} 2339 {{#if isDatasheet}} 2340 <div class="grid__col-12"> 2341 <div class="grid__col-12 chemical-download"> 2342 <a href="{{url}}" target="_blank"><i class="fa fa-download"></i>&nbsp;&nbsp;{{caption}}</a> 2343 </div> 2344 </div> 2345 {{/if}} 2346 {{/showFile}} 2347 {{/files}} 2348 </div> 2349 </div> 2350 } 2351 2352 @helper TextList(IEnumerable<string> texts, string @class = "") 2353 { 2354 <ul class="@(@class)"> 2355 @foreach (string text in texts) 2356 { 2357 <li>@text</li> 2358 } 2359 </ul> 2360 } 2361 2362 @helper RenderChemicalEnvironment() 2363 { 2364 var dangerSentences = GetString("Ecom:Product:Field.PerfionChemicalHSentences").SplitOn().Concat(GetString("Ecom:Product:Field.PerfionChemicalEUHSentences").SplitOn()); 2365 var securitySentences = GetString("Ecom:Product:Field.PerfionChemicalPSentences").SplitOn().Concat(GetString("Ecom:Product:Field.PerfionChemicalGHSSentences").SplitOn()); 2366 2367 <div class="chemical__environment center-container dw-mod"> 2368 @if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.PerfionChemicalSignalWords"))) 2369 { 2370 @Translate("ContainsSignalWords")<text>:</text> 2371 @TextList(GetString("Ecom:Product:Field.PerfionChemicalSignalWords").SplitOn(), "chemical__list") 2372 } 2373 2374 @if (dangerSentences.Any(v => !string.IsNullOrEmpty(v))) 2375 { 2376 @Translate("ContainsDangerSentences")<text>:</text> 2377 @TextList(dangerSentences, "chemical__list") 2378 } 2379 2380 @if (securitySentences.Any(v => !string.IsNullOrEmpty(v))) 2381 { 2382 @Translate("ContainsSafetySentences")<text>:</text> 2383 @TextList(securitySentences, "chemical__list") 2384 } 2385 </div> 2386 } 2387 2388 @helper RenderDangerImages() 2389 { 2390 var imageGuids = GetString("Ecom:Product:Field.PerfionChemicalPictogramImages").SplitOn().Select(g => 2391 { 2392 Guid guid; 2393 return Guid.TryParse(g, out guid) ? guid : Guid.Empty; 2394 }); 2395 2396 <div class="chemical__images grid__cell dw-mod"> 2397 <div class="grid"> 2398 @foreach (var guid in imageGuids) 2399 { 2400 <div class="grid-col-2"> 2401 <div class="chemical__image-container grid__cell"> 2402 <img class="chemical__image b-lazy" src="/Files/Images/placeholder.gif" @PerfionImageSrc(guid, 75, 75, "data-src=") /> 2403 </div> 2404 </div> 2405 } 2406 </div> 2407 </div> 2408 } 2409 2410 @helper RenderChemicalUN() 2411 { 2412 var sentences = GetString("Ecom:Product:Field.PerfionChemicalUN").SplitOn(); 2413 2414 <div class="chemical__un"> 2415 @foreach (var sentence in sentences) 2416 { 2417 <p class="chemical__un-sentence">@sentence</p> 2418 } 2419 </div> 2420 } 2421 2422 @* Tabs after chemical section *@ 2423 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2424 @using Dynamicweb.Core 2425 @using System 2426 @using System.Linq 2427 @using System.Web 2428 @using System.Collections.Generic 2429 @using Dynamicweb.Rapido.Blocks 2430 2431 @functions { 2432 Block tabTriggerBlock = new Block() 2433 { 2434 Name = "Tab Triggers", 2435 Id = "TabTriggers", 2436 SortId = 10, 2437 SkipRenderBlocksList = true 2438 }; 2439 Block tabLabelBlock = new Block() 2440 { 2441 Name = "Tab Labels", 2442 Id = "TabLabels", 2443 SortId = 20, 2444 SkipRenderBlocksList = true 2445 }; 2446 Block tabBlock = new Block() 2447 { 2448 Name = "Tab Block", 2449 Id = "TabBlock", 2450 SortId = 30, 2451 SkipRenderBlocksList = true 2452 }; 2453 } 2454 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2455 @using Dynamicweb.Core 2456 @using System 2457 @using System.Web 2458 @using System.Collections.Generic 2459 @using Dynamicweb.Ecommerce.International 2460 @using Dynamicweb.Rapido.Blocks 2461 2462 @functions { 2463 BlocksPage specProductPage = BlocksPage.GetBlockPage("Product"); 2464 string currentLanguageId = Language.GetCultureInfo().Name.Substring(3); 2465 } 2466 2467 @{ 2468 var descriptionLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("FullDescriptionLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue : "Section"; 2469 bool shouldRenderDescription = descriptionLayout == "Tabs"; 2470 2471 Block chemicalSection = specProductPage.GetBlockById("ChemicalSection"); 2472 Block specTriggersBlock = new Block() 2473 { 2474 Name = "SpecTriggerBlock", 2475 Id = "SpecTriggerBlock", 2476 SortId = 10, 2477 Template = RenderSpecTabTriggers(shouldRenderDescription) 2478 }; 2479 Block specLabelsBlock = new Block() 2480 { 2481 Name = "SpecTriggerBlock", 2482 Id = "SpecTriggerBlock", 2483 SortId = 10, 2484 Template = RenderSpecTabLabels(shouldRenderDescription) 2485 }; 2486 Block specTabsBlock = new Block() 2487 { 2488 Name = "SpecTabsBlock", 2489 Id = "SpecTabsBlock", 2490 SortId = 10, 2491 Template = RenderSpecTabBlocks(shouldRenderDescription) 2492 }; 2493 tabTriggerBlock.BlocksList.Add(specTriggersBlock); 2494 tabLabelBlock.BlocksList.Add(specLabelsBlock); 2495 tabBlock.BlocksList.Add(specTabsBlock); 2496 } 2497 2498 @helper RenderSpecTabTriggers(bool shouldRenderDescription) 2499 { 2500 if (shouldRenderDescription) 2501 { 2502 <input type="radio" class="tabs__trigger" name="productTabs" id="FullDescription" onchange="bLazy.revalidate()" checked> 2503 } 2504 <text> 2505 {{#if technicalSpecificationGroups}} 2506 <input type="radio" class="tabs__trigger" name="productTabs" id="TechnicalSpecifications" onchange="bLazy.revalidate()" @(!shouldRenderDescription ? "checked" : string.Empty)> 2507 {{/if}} 2508 {{#if videos}} 2509 <input type="radio" class="tabs__trigger" name="productTabs" id="Videos" onchange="bLazy.revalidate()"> 2510 {{/if}} 2511 {{#showFiles files "@currentLanguageId"}} 2512 {{#unless onlyDatasheets}} 2513 <input type="radio" class="tabs__trigger" name="productTabs" id="Files" onchange="bLazy.revalidate()"> 2514 {{/unless}} 2515 {{/showFiles}} 2516 </text> 2517 } 2518 2519 @helper RenderSpecTabLabels(bool shouldRenderDescription) 2520 { 2521 if (shouldRenderDescription) 2522 { 2523 <label for="FullDescription" class="tabs__label dw-mod">@Translate("Description", "Description")</label> 2524 } 2525 <text> 2526 {{#if technicalSpecificationGroups}} 2527 <label for="TechnicalSpecifications" class="tabs__label dw-mod">@Translate("TechnicalSpecifications", "TechnicalSpecifications")</label> 2528 {{/if}} 2529 {{#if videos}} 2530 <label for="Videos" class="tabs__label dw-mod">@Translate("Videos", "Videos")</label> 2531 {{/if}} 2532 {{#showFiles files "@currentLanguageId"}} 2533 {{#unless onlyDatasheets}} 2534 <label for="Files" class="tabs__label dw-mod">@Translate("Files", "Files")</label> 2535 {{/unless}} 2536 {{/showFiles}} 2537 </text> 2538 } 2539 2540 @helper RenderSpecTabBlocks(bool shouldRenderDescription) 2541 { 2542 if (shouldRenderDescription) 2543 { 2544 <text>{{>DescriptionContainer}}</text> 2545 } 2546 <text> 2547 {{#if technicalSpecificationGroups}} 2548 {{>TechnicalSpecificationGroupsContainer}} 2549 {{/if}} 2550 {{#if videos}} 2551 {{>VideosContainer}} 2552 {{/if}} 2553 {{#showFiles files "@currentLanguageId"}} 2554 {{#unless onlyDatasheets}} 2555 {{>FilesContainer}} 2556 {{/unless}} 2557 {{/showFiles}} 2558 </text> 2559 } 2560 2561 <script id="DescriptionContainer" type="text/x-template"> 2562 <div class="tabs__block dw-mod" id="Block__FullDescription"> 2563 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 2564 <div class="center-container u-padding--lg dw-mod"> 2565 <div class="product__section dw-mod"> 2566 <div class="product__description center-container dw-mod"> 2567 @GetString("Ecom:Product.LongDescription") 2568 2569 @if (chemicalSection != null) 2570 { 2571 @RenderBlock(new Block() 2572 { 2573 Design = new Design() 2574 { 2575 RenderType = RenderType.Row, 2576 Size = "10" 2577 }, 2578 BlocksList = new List<Block> { 2579 chemicalSection 2580 } 2581 }); 2582 } 2583 </div> 2584 </div> 2585 </div> 2586 </section> 2587 </div> 2588 </script> 2589 2590 <script id="TechnicalSpecificationGroupsContainer" type="text/x-template"> 2591 <div class="tabs__block dw-mod" id="Block__TechnicalSpecifications"> 2592 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 2593 <div class="center-container u-padding--lg dw-mod"> 2594 <div class="product__section dw-mod"> 2595 <div class="product__description center-container dw-mod"> 2596 <table class="table--no-top-border"> 2597 <tbody> 2598 {{#technicalSpecificationGroups}} 2599 <tr> 2600 <td class="u-bold"> 2601 {{#if caption}} 2602 {{caption}} 2603 {{else}} 2604 {{name}} 2605 {{/if}} 2606 </td> 2607 <td></td> 2608 </tr> 2609 {{#technicalSpecifications}} 2610 <tr> 2611 <td> 2612 {{#if caption}} 2613 {{caption}} 2614 {{else}} 2615 {{name}} 2616 {{/if}} 2617 </td> 2618 <td> 2619 <span class="TechnicalSpecifications_value">{{text}}</span>&nbsp;<span class="TechnicalSpecifications_unit">{{unit}}</span> 2620 </td> 2621 </tr> 2622 {{/technicalSpecifications}} 2623 {{/technicalSpecificationGroups}} 2624 </tbody> 2625 </table> 2626 </div> 2627 </div> 2628 </div> 2629 </section> 2630 </div> 2631 </script> 2632 2633 <script id="VideosContainer" type="text/x-template"> 2634 <div class="tabs__block dw-mod" id="Block__Videos"> 2635 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 2636 <div class="center-container u-padding--lg dw-mod"> 2637 <div class="product__section dw-mod"> 2638 <div class="center-container dw-mod"> 2639 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 2640 {{#videos}} 2641 <div class="grid__col-md-12 grid__col-lg-12"> 2642 <div class="video-wrapper"> 2643 <iframe id="youtube-video" src="{{link}}"></iframe> 2644 </div> 2645 </div> 2646 {{/videos}} 2647 </div> 2648 </div> 2649 </div> 2650 </div> 2651 </section> 2652 </div> 2653 </script> 2654 2655 <script id="FilesContainer" type="text/x-template"> 2656 <div class="tabs__block dw-mod" id="Block__Files"> 2657 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 2658 <div class="center-container u-padding--lg dw-mod"> 2659 <div class="product__section dw-mod"> 2660 <div class="product__description center-container dw-mod"> 2661 <table class="table--no-top-border"> 2662 <tbody> 2663 {{#files}} 2664 {{#showFile caption "@currentLanguageId"}} 2665 {{#unless isDatasheet}} 2666 <tr> 2667 <td colspan="2"> 2668 <a href="{{url}}" target="_blank"><i class="fa fa-download"></i>&nbsp;&nbsp;{{caption}}</a> 2669 </td> 2670 </tr> 2671 {{/unless}} 2672 {{/showFile}} 2673 {{/files}} 2674 </tbody> 2675 </table> 2676 </div> 2677 </div> 2678 </div> 2679 </section> 2680 </div> 2681 </script> 2682 2683 <script id="TabsPreRenderContainer" type="text/x-template"> 2684 <div class="u-h600px u-full-width"> 2685 <div class="grid"> 2686 <div class="grid__col-12"> 2687 <div class="pre-render-element pre-render-element--md"></div> 2688 </div> 2689 </div> 2690 </div> 2691 </script> 2692 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2693 @using Dynamicweb.Core 2694 @using System 2695 @using System.Linq 2696 @using System.Web 2697 @using System.Collections.Generic 2698 @using Dynamicweb.Rapido.Blocks 2699 2700 @using PLindberg.Dynamicweb.Common; 2701 2702 @using System.Globalization; 2703 2704 @using Dynamicweb.Rendering; 2705 @using Dynamicweb.Rapido.Blocks; 2706 2707 @helper RenderModalDialog(string id, Block header, Block body, string size) 2708 { 2709 var modalSize = (!string.IsNullOrEmpty(size) ? size : "modal--sm"); 2710 <input type="checkbox" id="@id-trigger" class="modal-trigger" /> 2711 <div class="modal-container"> 2712 <label for="@id-trigger" id="notification-email-modaloverlay" class="modal-overlay"></label> 2713 <div class="modal @modalSize" id="@id"> 2714 <label class="modal__close-btn" for="@id-trigger"></label> 2715 <div class="modal__header"> 2716 @RenderBlock(header) 2717 </div> 2718 <div class="modal__body"> 2719 @RenderBlock(body) 2720 </div> 2721 </div> 2722 </div> 2723 } 2724 2725 @{ 2726 var sparePartsGroupId = new WebConfigSettings().GetValue("Perfion/Global","SparePartsRelatedGroupId"); 2727 2728 sparePartsGroupId = !string.IsNullOrEmpty(sparePartsGroupId) ? sparePartsGroupId : ""; 2729 var sparePartsRelatedGroup = GetLoop("ProductRelatedGroups").FirstOrDefault(l => l.GetString("Ecom:Product:RelatedGroup.GroupID") == sparePartsGroupId && l.GetLoop("Products").Count() > 0); 2730 if (sparePartsRelatedGroup != null) 2731 { 2732 Block modalHeader = new Block() 2733 { 2734 Id = "SPStockModalHeader", 2735 Name = "Modal Header", 2736 Template = RenderModalHeader() 2737 }; 2738 Block modalBody = new Block() 2739 { 2740 Id = "SPStockModalBody", 2741 Name = "Modal Body", 2742 Template = RenderModalBody() 2743 }; 2744 Block sparePartTriggersBlock = new Block() 2745 { 2746 Name = "SPTriggerBlock", 2747 Id = "SPTriggerBlock", 2748 SortId = 20, 2749 Template = RenderTabTriggers(), 2750 SkipRenderBlocksList = true 2751 }; 2752 Block sparePartLabelsBlock = new Block() 2753 { 2754 Name = "SPTriggerBlock", 2755 Id = "SPTriggerBlock", 2756 SortId = 20, 2757 Template = RenderTabLabels(), 2758 SkipRenderBlocksList = true 2759 }; 2760 Block sparePartTabsBlock = new Block() 2761 { 2762 Name = "SPTabsBlock", 2763 Id = "SPTabsBlock", 2764 SortId = 20, 2765 Template = RenderTabBlocks(sparePartsRelatedGroup, modalHeader, modalBody), 2766 SkipRenderBlocksList = true 2767 }; 2768 2769 tabTriggerBlock.BlocksList.Add(sparePartTriggersBlock); 2770 tabLabelBlock.BlocksList.Add(sparePartLabelsBlock); 2771 tabBlock.BlocksList.Add(sparePartTabsBlock); 2772 } 2773 } 2774 2775 @helper RenderTabTriggers() 2776 { 2777 <input type="radio" class="tabs__trigger" name="productTabs" id="SpareParts" onchange="bLazy.revalidate()"> 2778 } 2779 2780 @helper RenderTabLabels() 2781 { 2782 <label for="SpareParts" class="tabs__label dw-mod">@Translate("SpareParts")</label> 2783 } 2784 2785 @helper RenderTabBlocks(LoopItem relatedGroup, Block modalHeader, Block modalBody) 2786 { 2787 string sparePartsGroupName = relatedGroup.GetString("Ecom:Product:RelatedGroup.Name"); 2788 string sparePartsGroupId = ToPascalCase(sparePartsGroupName); 2789 string baseFeedPageUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("SpareParts") + "&ProdID=" + GetString("Ecom:Product.ID") + "&feed=true"; 2790 string sparePartsFeed = baseFeedPageUrl + "&" + sparePartsGroupId + "=" + GetString("Ecom:Product.ID") + "&GroupName=" + sparePartsGroupId; 2791 2792 <div class="tabs__block dw-mod" id="Block__SpareParts"> 2793 <div class="pp__spare-parts dw-mod"> 2794 <div class="grid"> 2795 <div class="grid__col-lg-12"> 2796 <div id="SparePartsContainer" data-template="SparePartsTemplate" data-pre-render-template="SparePartsPreRenderContainer" data-json-feed="@sparePartsFeed" data-preloader="minimal"> 2797 </div> 2798 @RenderModalDialog("stock-notify", modalHeader, modalBody, "") 2799 </div> 2800 </div> 2801 </div> 2802 </div> 2803 } 2804 2805 @helper RenderModalHeader() 2806 { 2807 <h2>@Translate("NotificationModalTitle", "Lagerstand email")</h2> 2808 } 2809 2810 @helper RenderModalBody() 2811 { 2812 <p>@Translate("NotificationModalText", "Modtag en email når varren er på lager igen.")</p> 2813 <div class="notification-email-formgroup"> 2814 @*<label for="notification-email">Email: </label>*@ 2815 <input type="text" name="notification-email" id="stock-notify-email-input" value="@GetString("UserManagement:User.Email")" placeholder="@Translate("Emailaddress")" /> 2816 </div> 2817 <div class="notification-email-formgroup"> 2818 <button type="button" id="stock-notify-btn" class="btn btn--primary btn--condensed u-no-margin dw-mod notification-email-button" name="" value=""> 2819 <i class="notification-email-button-icon"></i><span class="u-hidden-xs u-hidden-xxs">&nbsp;@Translate("NotificationButton", "Send")</span> 2820 </button> 2821 </div> 2822 } 2823 2824 2825 <script id="SparePartsPreRenderContainer" type="text/x-template"> 2826 <div class="u-h600px u-full-width"> 2827 <div class="grid"> 2828 <div class="grid__col-12"> 2829 <div class="pre-render-element pre-render-element--md"></div> 2830 </div> 2831 </div> 2832 </div> 2833 </script> 2834 2835 <script id="SparePartsTemplate" type="text/x-template"> 2836 {{#.}} 2837 <table class="spare-parts-form table table-bordered"> 2838 <thead> 2839 <tr> 2840 <td>@Translate("Productnumber", "Varenr.")</td> 2841 <td>@Translate("ProductName", "Vare")</td> 2842 <td>@Translate("Stock state", "Lagerstatus")</td> 2843 <td>@Translate("Price pr unit", "Pris pr. stk")</td> 2844 <td>@Translate("Quantity", "Antal")</td> 2845 <td></td> 2846 </tr> 2847 </thead> 2848 <tbody> 2849 {{#ProductsContainer}} 2850 {{#Product}} 2851 <tr> 2852 <td>{{number}}</td> 2853 <td>{{name}}</td> 2854 <td class="u-ta-left"> 2855 {{#ifCond stockState '===' 'stock-icon--in'}} 2856 <div class="stock-icon stock-icon--in"></div> 2857 {{/ifCond}} 2858 {{#ifCond stockState '===' 'stock-icon--few'}} 2859 <div class="stock-icon stock-icon--few"></div> 2860 {{/ifCond}} 2861 {{#ifCond stockState '===' 'stock-icon--not'}} 2862 <div class="stock-icon stock-icon--not"></div> 2863 <a href="#" class="pp__sparepart-notify-click" onclick="document.getElementById('stock-notify-trigger').click(); return false;" 2864 data-productid="{{productId}}" data-productnumber="{{number}}" data-productvariant="{{variantid}}" data-productlanguage="{{languageId}}" 2865 data-page="@GetPageIdByNavigationTag("AddStockNotification")"><!--i class="far fa-envelope"></!--i>&nbsp;Translate("Modtag en email")</a--> 2866 2867 <p class="{{hideDelivery}}"> 2868 <span>@Translate("Shipping")</span>&nbsp;<span>{{stockDeliveryText}}</span>&nbsp;<span>{{stockDeliveryUnit}}</span> 2869 </p> 2870 {{/ifCond}} 2871 </td> 2872 <td> 2873 <span class="sparepartprice">{{price}} @Translate("InklMoms", "inkl. moms")</span> 2874 <div class="price price--product-page dw-mod withoutvat">{{priceWithoutVat}} @Translate("EksMoms", "ex. moms")</div> 2875 </td> 2876 <td> 2877 <input type="number" min="1" step="1" class="quantity" value="1" /> 2878 </td> 2879 <td class="spareparts-addtobasket"> 2880 <button class="btn btn--primary btn--condensed u-pull--right addtobasket" type="button" data-productid="{{productId}}" data-variantid="{{variantid}}" data-productlink="{{link}}" data-imageguid="{{imageGuid}}"> 2881 <i class="fal fa-shopping-cart"></i> 2882 </button> 2883 </td> 2884 </tr> 2885 {{/Product}} 2886 {{/ProductsContainer}} 2887 </tbody> 2888 </table> 2889 {{/.}} 2890 </script> 2891 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2892 @using Dynamicweb.Core 2893 @using System 2894 @using System.Linq 2895 @using System.Web 2896 @using System.Collections.Generic 2897 @using Dynamicweb.Rapido.Blocks 2898 2899 @functions { 2900 BlocksPage tabsProductPage = BlocksPage.GetBlockPage("Product"); 2901 } 2902 2903 @{ 2904 Block tabsLayoutBlock = new Block() 2905 { 2906 Name = "Tabs Layout", 2907 Id = "TabsLayout", 2908 SortId = 10, 2909 SkipRenderBlocksList = false, 2910 Template = RenderWrapper(tabTriggerBlock, tabLabelBlock, tabBlock), 2911 Design = new Design 2912 { 2913 Size = "12", 2914 RenderType = RenderType.Column, 2915 HidePadding = true 2916 } 2917 }; 2918 2919 tabsProductPage.Add("Section", tabsLayoutBlock); 2920 } 2921 2922 @helper RenderWrapper(Block tabTriggerBlock, Block tabLabelBlock, Block tabBlock) 2923 { 2924 @* Technical Spec *@ 2925 string feed = "/Default.aspx?ID=" + GetPageIdByNavigationTag("PerfionLiveFeed") + "&PerfionProductID=" + GetString("Ecom:Product:Field.PerfionProductId") + "&LanguageID=" + GetString("Ecom:Product.LanguageID") + "&PerfionMainImage=" + (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.PerfionMainImage")) ? GetString("Ecom:Product:Field.PerfionMainImage") : "0") + "&GroupID=" + GetString("Ecom:ProductList:Page.GroupID"); 2926 2927 <div class="grid__col-12 product__info u-no-padding dw-mod js-handlebars-root" id="Tabs" data-template="SpecsTemplate" data-pre-render-template="SpecsPreRenderContainer" data-json-feed="@feed" data-preloader="minimal"> 2928 <div class="tabs__block dw-mod" id="Block__FullDescription"> 2929 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 2930 <div class="center-container u-padding--lg dw-mod"> 2931 <div class="product__section dw-mod"> 2932 <div class="product__description center-container dw-mod"> 2933 @GetString("Ecom:Product.LongDescription") 2934 </div> 2935 </div> 2936 </div> 2937 </section> 2938 </div> 2939 </div> 2940 2941 <script id="SpecsTemplate" type="text/x-template"> 2942 @RenderTabLayoutSection(tabTriggerBlock, tabLabelBlock, tabBlock) 2943 </script> 2944 } 2945 2946 @helper RenderTabLayoutSection(Block tabTriggerBlock, Block tabLabelBlock, Block tabBlock) 2947 { 2948 <div class="pp__tab-triggers"> 2949 @RenderBlockList(tabTriggerBlock.BlocksList) 2950 2951 <div class="tabs__list dw-mod"> 2952 @RenderBlockList(tabLabelBlock.BlocksList) 2953 </div> 2954 2955 <div class="tabs__blocks dw-mod"> 2956 @RenderBlockList(tabBlock.BlocksList) 2957 </div> 2958 </div> 2959 } 2960 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2961 @using System.Globalization 2962 @using System.Linq 2963 @using Dynamicweb.Rapido.Blocks 2964 2965 @{ 2966 BlocksPage mainInfo = BlocksPage.GetBlockPage("Product"); 2967 2968 Block modalStockHeader = new Block() 2969 { 2970 Id = "StockNotifyHeader", 2971 Template = RenderStockNotifyHeader() 2972 }; 2973 Block modalStockBody = new Block() 2974 { 2975 Id = "StockNotifyBody", 2976 Template = RenderStockNotifyBody() 2977 }; 2978 Block stockBlock = new Block() 2979 { 2980 Id = "StockAndShippingNotifyMail", 2981 SortId = 90, 2982 Template = RenderStock(modalStockHeader, modalStockBody) 2983 }; 2984 Block customStockAndShipping = new Block() 2985 { 2986 Id = "StockAndShipping", 2987 SortId = 90, 2988 Template = RenderVariantStockAndShipping(stockBlock) 2989 }; 2990 2991 // overskriv StockAndShipping fra MainInformation 2992 mainInfo.ReplaceBlock(customStockAndShipping); 2993 //mainInfo.Add("MainInformation", stockBlock); 2994 } 2995 2996 @helper RenderStock(Block modalHeader, Block modalBody) 2997 { 2998 string dropshipping = GetString("Ecom:Product:Field.DropShipping"); // custom 2999 3000 var nextAvailableDate = PLindberg.Website.CustomModules.Helpers.GetNextAvailableStockDate(this); 3001 if (GetInteger("Ecom:Product.Stock") < 1 && nextAvailableDate.Length > 0) 3002 { 3003 <div class="appear-stockinfo"> 3004 <p> 3005 <i class="fas fa-reply"></i> 3006 @Translate("AppearStock", "Forventes på lager: ") 3007 @nextAvailableDate 3008 </p> 3009 </div> 3010 } 3011 3012 if (GetString("Ecom:Product:Field.PerfionItemStatus").ToUpper() == "O" && GetInteger("Ecom:Product.Stock") == 0) 3013 { 3014 @* onclick="notificationEmail('@GetString("Ecom:Product.Number")', @(string.IsNullOrEmpty(GetString("UserManagement:User.Email")) ? "null" : "'" + GetString("UserManagement:User.Email") + "'" )); return false;" *@ 3015 <div><a href="#" class="stock-notification-email-link" onclick="document.getElementById('notification-email-modal-trigger').click(); return false;"><i class="far fa-envelope"></i>@Translate("Modtag en email")</a></div> 3016 3017 @RenderModalDialog("notification-email-modal", modalHeader, modalBody, "") 3018 } 3019 3020 if (GetInteger("Ecom:Product.Stock") > 0 && dropshipping != "J") 3021 { 3022 <p class="delivery green"><i class="fa fa-truck" aria-hidden="true"></i>@Translate("deliverytext", "Levering 1-3 dage")</p> 3023 } 3024 3025 3026 } 3027 3028 @helper RenderStockNotifyHeader() 3029 { 3030 <h2>@Translate("NotificationModalTitle", "Lagerstand email")</h2> 3031 } 3032 3033 @helper RenderStockNotifyBody() 3034 { 3035 <p>@Translate("NotificationModalText", "Modtag en email når varren er på lager igen.")</p> 3036 <div class="notification-email-formgroup"> 3037 <input type="text" name="notification-email" id="notification-email-input" value="@GetString("UserManagement:User.Email")" placeholder='@Translate("Emailaddress")' /> 3038 </div> 3039 <div class="notification-email-formgroup"> 3040 <button type="button" id="" class="btn btn--primary btn--condensed u-no-margin dw-mod notification-email-button" name="" value="" 3041 onclick="signupStockEmailNotification('notification-email-modal-trigger', '@GetPageIdByNavigationTag("AddStockNotification")', '@GetString("Ecom:Product.Number")', '@GetString("Ecom:Product.ID")', '@GetString("Ecom:Product.VariantID")', '@GetString("Ecom:Product.LanguageID")', document.getElementById('notification-email-input').value);"> 3042 <i class="notification-email-button-icon"></i><span class="u-hidden-xs u-hidden-xxs"> @Translate("NotificationButton")</span> 3043 </button> 3044 </div> 3045 } 3046 3047 @helper RenderVariantStockAndShipping(Block StockAndShippingNotifyMail) 3048 { 3049 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideStockState") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState") : false; 3050 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideShipping") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping") : false; 3051 bool onlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null; 3052 3053 var variantLoop = GetLoop("VariantCombinations"); 3054 var hasSelectedVariant = !string.IsNullOrEmpty(GetString("Ecom:Product.SelectedVariantComboID")); 3055 var hasVariantCombinations = variantLoop.Count > 0; 3056 var highestStockCount = hasVariantCombinations ? variantLoop[0].GetInteger("Ecom:Product.Stock") : 0; 3057 3058 string stockIcon = "stock-icon--not"; 3059 string stockText = GetString("Ecom:Product:Stock.Text"); 3060 string dropshipping = GetString("Ecom:Product:Field.DropShipping"); // custom 3061 string dropshippingfrase = GetString("Ecom:Product:Field.DropShippingFrase"); // custom 3062 3063 bool PerfionProductFreightAddon = GetBoolean("Ecom:Product:Field.PerfionProductFreightAddon"); //Custom 3064 3065 3066 3067 if (!hasSelectedVariant && hasVariantCombinations) 3068 { 3069 foreach (var variantItem in variantLoop) 3070 { 3071 var stockCount = variantItem.GetInteger("Ecom:Product.Stock"); 3072 3073 if (stockCount >= highestStockCount) 3074 { 3075 highestStockCount = stockCount; 3076 stockText = variantItem.GetString("Ecom:Product:Stock.Text"); 3077 } 3078 } 3079 3080 stockIcon = highestStockCount > 0 ? highestStockCount < 5 ? "stock-icon--few" : "stock-icon--in" : "stock-icon--not"; 3081 } 3082 else if (GetInteger("Ecom:Product.Stock") > 0) 3083 { 3084 stockIcon = GetInteger("Ecom:Product.Stock") < 5 ? "stock-icon--few" : "stock-icon--in"; 3085 stockText = GetString("Ecom:Product:Stock.Text"); 3086 } 3087 3088 if (!onlyPreview) 3089 { 3090 string KlarnaOnsiteLocale = Pageview.AreaSettings.GetItem("Custom").GetString("KlarnaOnsiteLocale") != null ? Pageview.AreaSettings.GetItem("Custom").GetString("KlarnaOnsiteLocale") : ""; 3091 //credit-promotion-badge 3092 string KlarnaOnsiteKey = Pageview.AreaSettings.GetItem("Custom").GetString("KlarnaOnsiteKey") != null ? Pageview.AreaSettings.GetItem("Custom").GetString("KlarnaOnsiteKey") : ""; 3093 3094 double klarnaAmount = 0; 3095 3096 //var variantLoop = GetLoop("VariantCombinations"); 3097 //var hasSelectedVariant = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")); 3098 var lowestVariantPrice = variantLoop.GetLowestVariantPrice(); 3099 // if main product 3100 if (variantLoop.Count() > 0 && !hasSelectedVariant) 3101 { 3102 klarnaAmount = Math.Round(lowestVariantPrice.PriceWithVat * 100,0); 3103 } 3104 else 3105 { 3106 klarnaAmount = Math.Round(GetDouble("Ecom:Product.Price.PriceWithVAT.Value") * 100,0); 3107 } 3108 3109 3110 <div> 3111 <div class="product__stock-delivery dw-mod grid__col-lg-6 grid__col-md-6 grid__col-sm-12 grid__col-xs-12 u-pull--right"> 3112 @if (!string.IsNullOrEmpty(KlarnaOnsiteLocale)){ 3113 <klarna-placement data-key="@KlarnaOnsiteKey" 3114 data-locale="@KlarnaOnsiteLocale" 3115 data-purchase-amount="@klarnaAmount"></klarna-placement> 3116 } 3117 </div> 3118 <div class="product__stock-delivery dw-mod grid__col-lg-6 grid__col-md-6 grid__col-sm-12 grid__col-xs-12"> 3119 @if (!hideStockState) 3120 { 3121 if (dropshipping != "J") 3122 { 3123 <div> 3124 <span class="stock-icon @stockIcon" title="@stockText"></span>&nbsp;@stockText 3125 </div> 3126 } 3127 else 3128 { 3129 <span class="stock-icon stock-icon--in u-no-margin dw-mod"></span>@Translate("From supplier", "Fra leverandør") 3130 <p>@dropshippingfrase</p> 3131 } 3132 3133 3134 } 3135 3136 @if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText")) && !hideDelivery) 3137 { 3138 <p> 3139 <span>@Translate("Shipping")</span>&nbsp;<span>@GetString("Ecom:Product:Stock.DeliveryText")</span>&nbsp;<span>@GetString("Ecom:Product:Stock.DeliveryUnit")</span> 3140 </p> 3141 } 3142 3143 @RenderBlock(StockAndShippingNotifyMail) 3144 </div> 3145 </div> 3146 } 3147 if (PerfionProductFreightAddon == true ) 3148 { 3149 <div class="freigtextra " title='@Translate("Freightaddon", "Fragttillæg")'> 3150 <i class="fas fa-truck"></i> @Translate("Freightaddon", "Fragttillæg") 3151 </div> 3152 3153 } 3154 3155 } 3156 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 3157 @using Dynamicweb.Core 3158 @using System 3159 @using System.Linq 3160 @using System.Web 3161 @using System.Collections.Generic 3162 @using Dynamicweb.Ecommerce.International 3163 @using Dynamicweb.Rapido.Blocks 3164 3165 @functions { 3166 3167 BlocksPage productFreightPage = BlocksPage.GetBlockPage("Product"); 3168 } 3169 3170 3171 @{ 3172 3173 string freightextraLayout = "Section"; 3174 3175 bool PerfionProductFreightAddon = GetBoolean("Ecom:Product:Field.PerfionProductFreightAddon"); 3176 string freightext = GetString("Ecom:Product:Field.PerfionProductFreightText"); 3177 3178 if (PerfionProductFreightAddon == true && freightext != "") 3179 { 3180 Block freightTriggersBlock = new Block() 3181 { 3182 Name = "FTriggerBlock", 3183 Id = "FTriggerBlock", 3184 SortId = 90, 3185 Template = RenderFTabTriggers(), 3186 SkipRenderBlocksList = true 3187 }; 3188 3189 Block freightLabelsBlock = new Block() 3190 { 3191 Name = "FLabelBlock", 3192 SortId = 90, 3193 Template = RenderFTabLabels(), 3194 SkipRenderBlocksList = true 3195 }; 3196 3197 Block freightTabsBlock = new Block() 3198 { 3199 Name = "FTabsBlock", 3200 Id = "FTabsBlock", 3201 SortId = 90, 3202 Template = RenderFTabBlocks(), 3203 SkipRenderBlocksList = true 3204 }; 3205 3206 tabTriggerBlock.BlocksList.Add(freightTriggersBlock); 3207 tabLabelBlock.BlocksList.Add(freightLabelsBlock); 3208 tabBlock.BlocksList.Add(freightTabsBlock); 3209 } 3210 3211 3212 3213 } 3214 @helper RenderFTabTriggers() 3215 { 3216 <input type="radio" class="tabs__trigger" name="productTabs" id="Freight" onchange="bLazy.revalidate()"> 3217 } 3218 @helper RenderFTabLabels() 3219 { 3220 <label for="Freight" class="tabs__label dw-mod">@Translate("Freightaddon", "Fragttillæg")</label> 3221 } 3222 @helper RenderFTabBlocks() 3223 { 3224 3225 <div class="tabs__block dw-mod" id="Block__Freight"> 3226 <div class="pp__freightextra dw-mod"> 3227 <div class="grid"> 3228 <div class="grid__col-lg-12"> 3229 <div class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 3230 <div class="center-container u-padding--lg dw-mod"> 3231 @GetString("Ecom:Product:Field.PerfionProductFreightText") 3232 3233 </div> 3234 </div> 3235 </div> 3236 </div> 3237 </div> 3238 </div> 3239 3240 3241 3242 } 3243 3244 3245 3246 @* Price starting from variant *@ 3247 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 3248 @using Dynamicweb.Core 3249 @using System 3250 @using System.Linq 3251 @using System.Web 3252 @using System.Collections.Generic 3253 @using Dynamicweb.Rapido.Blocks 3254 3255 @using PLindberg.Dynamicweb; 3256 @using PLindberg.Dynamicweb.ProductPrices; 3257 @functions { 3258 BlocksPage startPricePage = BlocksPage.GetBlockPage("Product"); 3259 } 3260 3261 @{ 3262 var variantLoop = GetLoop("VariantCombinations"); 3263 var hasSelectedVariant = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")); 3264 var lowestVariantPrice = variantLoop.GetLowestVariantPrice(); 3265 var isStartingPrice = !variantLoop.VariantsHasSamePrice(); 3266 3267 // has variants 3268 if (variantLoop.Count() > 0 && !hasSelectedVariant) 3269 { 3270 Block startPriceBlock = new Block() 3271 { 3272 Name = "Starting Price", 3273 Id = "StartPrice", 3274 SortId = 50, 3275 Template = RenderStartingPrice(isStartingPrice, lowestVariantPrice), 3276 Design = new Design 3277 { 3278 Size = "12", 3279 RenderType = RenderType.Column, 3280 HidePadding = false 3281 } 3282 }; 3283 3284 startPricePage.Add("MainInformation", startPriceBlock); 3285 } 3286 } 3287 3288 @helper RenderStartingPrice(bool isStartingPrice, Price price) 3289 { 3290 if (price != null) 3291 { 3292 if (isStartingPrice) 3293 { 3294 <div class="pp__startprice-container"> 3295 <span class="price price--product-list dw-mod pp__startprice">@string.Format("{0} {1}", Translate("StartingFrom", "Fra"), price.PriceWithVatFormatted)</span> 3296 <div class="price price--product-list price withoutvat dw-mod">@string.Format("{0} {1} {2}", Translate("StartingFrom", "Fra"), price.PriceWithoutVatFormatted, Translate("EksMoms", "ex. moms"))</div> 3297 </div> 3298 } 3299 else 3300 { 3301 <div class="pp__startprice-container"> 3302 <span class="price price--product-list dw-mod pp__startprice">@price.PriceWithVatFormatted</span> 3303 <div class="price price--product-list price withoutvat dw-mod">@string.Format("{0} {1}", price.PriceWithoutVatFormatted, Translate("EksMoms", "ex. moms"))</div> 3304 </div> 3305 } 3306 } 3307 } 3308 3309 <div class="product__info dw-mod u-margin-bottom--lg js-product"> 3310 3311 @if (Pageview.AreaSettings.GetItem("Custom").GetBoolean("Swift_Templates_Enabled")) 3312 { 3313 @GetBreadcrumbHtml(GetString("Ecom:Group.ID"), GetString("Ecom:Product.ID")) 3314 3315 <script type="application/ld+json"> 3316 { 3317 "@@context": "https://schema.org", 3318 "@@type": "BreadcrumbList", 3319 "itemListElement": [ 3320 @RenderSchemaItems(GetBreadcrumbItems(GetString("Ecom:Group.ID"), GetString("Ecom:Product.ID"))) 3321 ] 3322 } 3323 </script> 3324 } 3325 3326 <div class="grid grid--align-content-start"> 3327 @* The @RenderBlockList base helper is included in Components/GridBuilder.cshtml *@ 3328 @RenderBlockList(productsPage.BlocksRoot.BlocksList) 3329 @*@{ 3330 //var p = ProductPrices.GetBestPrice(GetLoop("Product.Prices"), GetString("Ecom:Product.ID"), GetString("Ecom:Product.VariantID")); 3331 }*@ 3332 </div> 3333 </div> 3334 3335 @helper RenderSchemaItems(IEnumerable<BreadcrumbHelper.BreadcrumbItem> nodes) 3336 { 3337 var position = 1; 3338 var context = HttpContext.Current.Request; 3339 var prefix = context.Url.Scheme + "://" + context.Url.Host; 3340 var nodeCount = nodes.Count(); 3341 3342 foreach (var node in nodes) 3343 { 3344 <text> 3345 { 3346 "@@type": "ListItem", 3347 "position": @position, 3348 "name": "@node.Name", 3349 "item": "@(prefix + node.Url)" 3350 }@if (position < nodeCount) { <text>,</text> } 3351 </text> 3352 3353 position++; 3354 } 3355 }

Liknande produkter

Rekommenderade för dig