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_882af75652344eb3b009a89118de49c9.<>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_882af75652344eb3b009a89118de49c9.<>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_882af75652344eb3b009a89118de49c9.<>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_882af75652344eb3b009a89118de49c9.<>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_882af75652344eb3b009a89118de49c9.<>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_882af75652344eb3b009a89118de49c9.<>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_882af75652344eb3b009a89118de49c9.<>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_882af75652344eb3b009a89118de49c9.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"> </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"> </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> {{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&height=300&crop=5&Compression=75&FillCanvas=true&DoNotUpscale=true&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> {{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> <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> {{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"> @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> Translate("Modtag en email")</a--> 2866 2867 <p class="{{hideDelivery}}"> 2868 <span>@Translate("Shipping")</span> <span>{{stockDeliveryText}}</span> <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> @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> <span>@GetString("Ecom:Product:Stock.DeliveryText")</span> <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 }
Frakt og leveringsvilkår
Nedenstående frakt og leveringsvilkår for P. Lindbergs nettbutikk, som gjelder både for private, næringsdrivende og offentlige kunder.
Grunnfrakten på alle ordrer er 179,- inkl. mva. Ordrer pålydende 5.000,- inkl. mva. eller mer slipper som hovedregel å betale grunnfrakt, med mindre ordren inneholder varer som er merket med frakttillegg.
Frakttillegg: Enkelte varer kan ha et frakttillegg som faktureres uavhengig av ordresum og grunnfrakt. Disse varene er merket med et lastebil-ikon, og aktuell fraktpris kan ses på produktsiden under fanen «Frakttillegg», samt i handlekurven/kassen i nettbutikken før du gjennomfører ditt kjøp.
Alle våre forsendelser leveres direkte fra vårt hovedlager i Danmark, og selve forsendelsen tar normalt 4-6 virkedager. Av ulike årsaker kan det forekomme lenger leveringstid. En leveringstid utover normalt gir ikke krav på kompensasjon. Vi sender ikke til postboks, og endring av leveringsadresse vil kunne medføre et endringsgebyr som kunde blir belastet.
Våre komplette kjøpsbetingelser finnes her: https://www.p-lindberg.no/kundeservice/kjoepsbetingelser
Frakt og leveringsvilkår
Nedenstående frakt og leveringsvilkår for P. Lindbergs nettbutikk, som gjelder både for private, næringsdrivende og offentlige kunder.
Grunnfrakten på alle ordrer er 179,- inkl. mva. Ordrer pålydende 5.000,- inkl. mva. eller mer slipper som hovedregel å betale grunnfrakt, med mindre ordren inneholder varer som er merket med frakttillegg.
Frakttillegg: Enkelte varer kan ha et frakttillegg som faktureres uavhengig av ordresum og grunnfrakt. Disse varene er merket med et lastebil-ikon, og aktuell fraktpris kan ses på produktsiden under fanen «Frakttillegg», samt i handlekurven/kassen i nettbutikken før du gjennomfører ditt kjøp.
Alle våre forsendelser leveres direkte fra vårt hovedlager i Danmark, og selve forsendelsen tar normalt 4-6 virkedager. Av ulike årsaker kan det forekomme lenger leveringstid. En leveringstid utover normalt gir ikke krav på kompensasjon. Vi sender ikke til postboks, og endring av leveringsadresse vil kunne medføre et endringsgebyr som kunde blir belastet.
Våre komplette kjøpsbetingelser finnes her: https://www.p-lindberg.no/kundeservice/kjoepsbetingelser