Error executing template "Designs/Rapido/eCom/Product/SpProduct.cshtml"
System.IO.IOException: The process cannot access the file 'E:\Dynamicweb\Solutions\Kruuse\Files\Templates\Designs\Rapido\Translations.xml' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at Dynamicweb.Rendering.Translation.Source.WriteDocument(XmlDocument document)
at Dynamicweb.Rendering.Translation.Source.Save()
at Dynamicweb.Rendering.Translation.Source.UpdateTranslationSource(Source source, IEnumerable`1 newKeys, String designName, IEnumerable`1 cultures)
at Dynamicweb.Rendering.Template.TranslateText(String text, String defaultValue, String cultureName)
at Dynamicweb.Rendering.TemplateBase`1.Translate(String text)
at CompiledRazorTemplates.Dynamic.RazorEngine_aafcc94cf2f24f9da9c5f4d94f0ebf8b.Execute() in E:\Dynamicweb\Solutions\Kruuse\Files\Templates\Designs\Rapido\eCom\Product\SpProduct.cshtml:line 2120
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 Dynamicweb.Extensibility
5 @using Dynamicweb.Content
6 @using System
7 @using System.IO
8 @using Dynamicweb.Core
9 @using System.Web
10 @using System.Globalization
11 @using System.Web.UI.HtmlControls
12 @using Dynamicweb.Rapido.Blocks
13
14 @functions {
15 BlocksPage productsPage = BlocksPage.GetBlockPage("Product");
16
17 public static string ToPascalCase(string str)
18 {
19 return CultureInfo.InvariantCulture.TextInfo
20 .ToTitleCase(str.ToLowerInvariant())
21 .Replace("-", "")
22 .Replace("_", "")
23 .Replace(" ", "");
24 }
25 }
26
27 @{
28 Block productTop = new Block()
29 {
30 Id = "Top",
31 SortId = 10,
32 Design = new Design
33 {
34 RenderType = RenderType.Row
35 }
36 };
37 productsPage.Add(productTop);
38
39 Block productMainInfo = new Block()
40 {
41 Id = "MainInformation",
42 SortId = 10,
43 Design = new Design
44 {
45 Size = "auto",
46 RenderType = RenderType.Column
47 }
48 };
49 productsPage.Add("Top", productMainInfo);
50
51 if (!String.IsNullOrWhiteSpace(Pageview.AreaSettings.GetItem("ProductPage").GetString("ImageSectionPosition")))
52 {
53 productMainInfo.SortId = Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue == "left-left" || Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue == "left-right" ? 2 : 1;
54 }
55
56 //Optional mini tabs block
57 Block miniTabsBlock = new Block()
58 {
59 Id = "MiniTabs",
60 SortId = 40,
61 Template = RenderProductMiniTabs(),
62 SkipRenderBlocksList = true
63 };
64 productsPage.Add("MainInformation", miniTabsBlock);
65 //-----
66
67 Block productTabsBlock = new Block()
68 {
69 Id = "Tabs",
70 SortId = 30,
71 Template = RenderProductTabs(),
72 SkipRenderBlocksList = true
73 };
74 productsPage.Add(productTabsBlock);
75
76 Block productDetailsBlock = new Block()
77 {
78 Id = "Section",
79 SortId = 30
80 };
81 productsPage.Add(productDetailsBlock);
82
83 Block productSnippetsBlock = new Block()
84 {
85 Id = "Snippets",
86 SortId = 40
87 };
88 productsPage.Add(productSnippetsBlock);
89 }
90
91 @* Include the required Grid builder (Contains the methods @RenderBlockList and @RenderBlock) *@
92 @using System.Text.RegularExpressions
93 @using System.Collections.Generic
94 @using Dynamicweb.Rapido.Blocks
95
96
97 @*--- START: Base block renderers ---*@
98
99 @helper RenderBlockList(List<Block> blocks)
100 {
101 blocks = blocks.OrderBy(item => item.SortId).ToList();
102
103 foreach (Block item in blocks)
104 {
105 <!-- START: @item.Id -->
106
107 if (item.Design == null)
108 {
109 @RenderBlock(item)
110 }
111 else if (item.Design.RenderType != RenderType.Hide)
112 {
113 if (item.Design.RenderType == RenderType.Row)
114 {
115 <div class="grid grid--align-content-start">
116 @RenderBlock(item)
117 </div>
118 }
119
120 if (item.Design.RenderType == RenderType.Column)
121 {
122 string hidePadding = item.Design.HidePadding ? "u-no-padding" : "";
123 string size = item.Design.Size != null ? item.Design.Size : "12";
124 size = Regex.IsMatch(size, @"\d") ? "md-" + item.Design.Size : item.Design.Size;
125
126 <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">
127 @RenderBlock(item)
128 </div>
129 }
130
131 if (item.SkipRenderBlocksList == true)
132 {
133 @RenderBlock(item)
134 }
135 }
136
137 <!-- END: @item.Id -->
138 }
139 }
140
141 @helper RenderBlock(Block item)
142 {
143 if (item.Template != null)
144 {
145 @BlocksPage.RenderTemplate(item.Template)
146 }
147
148 if (item.BlocksList.Count > 0 && item.SkipRenderBlocksList == false)
149 {
150 @RenderBlockList(item.BlocksList)
151 }
152 }
153
154 @*--- END: Base block renderers ---*@
155
156
157 @* Include the Blocks for the page *@
158 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
159 @using Dynamicweb.Core
160 @using System
161 @using System.Web
162 @using System.Collections.Generic
163 @using System.Text.RegularExpressions;
164 @using Dynamicweb.Rapido.Blocks
165 @using Newtonsoft.Json;
166 @using System.Xml;
167 @using System.Net;
168 @using Dynamicweb.Environment;
169 @using System.Text
170 @using Newtonsoft.Json.Linq
171
172
173
174
175 @functions {
176 BlocksPage mainImagePage = BlocksPage.GetBlockPage("Product");
177 }
178
179 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
180
181
182 @*
183 This is a temporary fallback for the DefaultImage. The image pattern MUST be set up like this:
184
185 ImageSmall = /{ProductNumber}.jpg
186 ImageMedium = /{ProductNumber}{VariantOptionLevel1}.jpg
187 ImageLarge = /{ProductNumber}{VariantComboName}.jpg
188
189 In addition to the ImageDefault setting
190 *@
191
192 @functions {
193 public string GetProductImage(LoopItem productObject = null)
194 {
195 string theImage = "";
196
197 if (productObject == null)
198 {
199 theImage = GetString("Ecom:Product.ImageDefault.Default.Clean");
200 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageLarge.Clean") : theImage;
201 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageMedium.Clean") : theImage;
202 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageSmall.Clean") : theImage;
203 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageLarge.Default.Clean") : theImage;
204 }
205 else
206 {
207 theImage = productObject.GetString("Ecom:Product.ImageDefault.Default.Clean");
208 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageLarge.Clean") : theImage;
209 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageMedium.Clean") : theImage;
210 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageSmall.Clean") : theImage;
211 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageLarge.Default.Clean") : theImage;
212 }
213
214 return theImage;
215 }
216 }
217
218 @{
219 string imageBlockPosition = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ImageSectionPosition")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "right-right";
220 string imageBlockWidth = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("TopLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("TopLayout").SelectedValue : "6";
221 imageBlockWidth = imageBlockPosition == "left-left" || imageBlockPosition == "left-right" ? Converter.ToString(12 - Converter.ToInt32(imageBlockWidth)) : imageBlockWidth;
222
223 Block mainImageBlock = new Block()
224 {
225 Id = "MainImage",
226 SortId = imageBlockPosition == "left-left" || imageBlockPosition == "left-right" ? 1 : 2,
227 Template = RenderMainImageContainer(),
228 Design = new Design
229 {
230 Size = imageBlockWidth,
231 RenderType = RenderType.Column
232 }
233 };
234
235 mainImagePage.Add("Top", mainImageBlock);
236 }
237
238 @helper RenderModal()
239 {
240 string imagePrefix = "/Admin/Public/GetImage.ashx?width=800&height=800&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=";
241
242 <!-- Trigger for the gallery modal -->
243 <input type="checkbox" id="GalleryModalTrigger" class="modal-trigger" />
244
245 if (!String.IsNullOrEmpty(GetProductImage()))
246 {
247 <!-- Gallery modal -->
248 <div class="modal-container custom-gallery-modal">
249 <label for="GalleryModalTrigger" id="GalleryModalOverlay" class="modal-overlay"></label>
250 <div class="modal modal--full" id="GalleryModal">
251 <div class="modal__body modal__body--full">
252 <div class="gallery-slider">
253 <div class="gallery-slider__image" id="FullImage">
254 <img src="@GetProductImage()" class="modal--full__img js-gallery-image" alt="@GetString("Ecom:Product.Name")" />
255 </div>
256 <div class="gallery-slider__image-counter" id="FullImage_counter"></div>
257 <label class="gallery-slider__close-btn" for="GalleryModalTrigger"></label>
258 <button class="gallery-slider__previous-btn" id="FullImage_prev" onclick="Gallery.prevImage('FullImage')"></button>
259 <button class="gallery-slider__next-btn" id="FullImage_next" onclick="Gallery.nextImage('FullImage')"></button>
260 </div>
261 </div>
262 </div>
263 </div>
264 }
265 }
266
267 @helper RenderMainImageContainer()
268 {
269 string imageBlockPosition = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ImageSectionPosition")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "right-right";
270 @RenderModal()
271
272 <div class="grid grid--bleed">
273 @if (imageBlockPosition == "left-left" || imageBlockPosition == "right-left")
274 {
275 @RenderThumbnails()
276 @RenderImage()
277 }
278 else
279 {
280 @RenderImage()
281 @RenderThumbnails()
282 }
283 </div>
284 }
285
286 @helper RenderImage()
287 {
288 string imagePrefix = "/Admin/Public/GetImage.ashx?width=800&height=800&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=";
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"))
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").Count > 0)
312 {
313 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.Price") - GetDouble("Ecom:Product.Price.Price"));
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"))
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"))
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").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.Created").AddDays(Converter.ToDouble(Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetString("Expiration"))) > DateTime.Now)
365 {
366 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div>
367 }
368
369 if (!pointShopOnly && !String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value")))
370 {
371 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div>
372 }
373
374 if (Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetItem("SpDiscontinuedSticker").GetBoolean("Enable"))
375 {
376 if (GetBoolean("Ecom:Product:Field.Discontinued") && GetInteger("Ecom:Product.Stock") == 0)
377 {
378 <div class="stickers-container__tag stickers-container__tag--discontinued dw-mod">@Translate("Discontinued!")</div>
379 }
380 }
381
382 if (Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetItem("SpToBeDiscontinuedSticker").GetBoolean("Enable"))
383 {
384 if (GetBoolean("Ecom:Product:Field.Discontinued") && GetInteger("Ecom:Product.Stock") > 0)
385 {
386 <div class="stickers-container__tag stickers-container__tag--tobediscontinued dw-mod">@Translate("To be discontinued!")</div>
387 }
388 }
389
390 if (Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetItem("SpHillsCampaignSticker").GetBoolean("Enable"))
391 {
392 if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.HillsCampaignSplash"))
393 && (GetDate("Ecom:Product:Field.HillsCampaignFromDate") == DateTime.MinValue || GetDate("Ecom:Product:Field.HillsCampaignFromDate") <= DateTime.Today)
394 && (GetDate("Ecom:Product:Field.HillsCampaignToDate") == DateTime.MinValue || GetDate("Ecom:Product:Field.HillsCampaignToDate") >= DateTime.Today))
395 {
396 <div class="stickers-container__tag stickers-container__tag--hillscampaign dw-mod">
397 @if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.HillsCampaignLink")))
398 {
399 <a href="@GetString("Ecom:Product:Field.HillsCampaignLink")" title="@GetString("Ecom:Product:Field.HillsCampaignSplash")">
400 @GetString("Ecom:Product:Field.HillsCampaignSplash")
401 </a>
402 }
403 else
404 {
405 @GetString("Ecom:Product:Field.HillsCampaignSplash")
406 }
407 </div>
408 }
409 }
410 }
411 </div>
412 <label for="GalleryModalTrigger" class="product__image-container" id="Preview_@GetString("Ecom:Product.ID")">
413 <img class="thumb-image-view product__image-container__image dw-mod b-lazy" src="/Files/Images/placeholder.gif" data-src="@imagePrefix@GetProductImage()" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="0" onclick="Gallery.openImageByNum(this)" />
414 </label>
415 </div>
416 }
417
418 @helper RenderThumbnails()
419 {
420 var cookieBot = new Smartpage.CookieManager.CookieBot();
421
422 <div class="grid__col-2 u-hidden-xxs dw-mod">
423 <div class="product__thumbs dw-mod">
424 <i class="fas fa-circle-notch fa-spin preloader js-remove-after-load"></i> <!--preloader-->
425 <div class="carousel js-carousel-container carousel--hidden dw-mod" id="leftCarousel">
426 <div class="thumb-list carousel__container dw-mod">
427 @*Main image thumb*@
428
429
430 @* Check if products has image and check if it returns default image - if true - print it*@
431 @if (Converter.ToString(GetProductImage()).Contains(GetString("Ecom:Product.ImageLarge.Default.Clean")))
432 {
433 @RenderThumbnail(GetProductImage())
434 }
435
436
437 @{
438 bool youtubevideoIsSet = false;
439 }
440 @foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages"))
441 {
442 if (!String.IsNullOrEmpty(alternativeImage.GetString("Ecom:Product.AlternativeImages.Image")))
443 {
444 @RenderThumbnail(alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"))
445 }
446 if (alternativeImage.GetInteger("Ecom:Product.AlternativeImages.LoopCounter") == 2)
447 {
448 if (cookieBot.Statistics)
449 {
450 youtubevideoIsSet = true;
451 @RenderYoutube()
452 }
453 }
454 }
455
456 @foreach (LoopItem detail in GetLoop("Details"))
457 {
458 if (!String.IsNullOrEmpty(detail.GetString("Ecom:Product:Detail.Image.Clean")))
459 {
460 string ext = Path.GetExtension(detail.GetString("Ecom:Product:Detail.Image.Clean")).ToLower();
461 if (ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".png")
462 {
463 @RenderThumbnail(detail.GetString("Ecom:Product:Detail.Image.Clean"))
464 }
465 if (detail.GetInteger("Ecom:Product.AlternativeImages.LoopCounter") == 2 && youtubevideoIsSet == false)
466 {
467 if (cookieBot.Statistics)
468 {
469 youtubevideoIsSet = true;
470 @RenderYoutube()
471 }
472 }
473 }
474 }
475
476 @if (cookieBot.Statistics && youtubevideoIsSet == false)
477 {
478 @RenderYoutube()
479 }
480 </div>
481 <div class="js-carousel-data" data-carousel-slide-time="0" data-direction="vertical" data-sliding-type="items" data-slides-in-view="5">
482 <div class="carousel-prev-btn carousel-prev-btn--vertical dw-mod" onclick="Carousel.GetPreviousSlide('leftCarousel')"></div>
483 <div class="carousel-next-btn carousel-next-btn--vertical dw-mod" onclick="Carousel.GetNextSlide('leftCarousel')"></div>
484 </div>
485 </div>
486 </div>
487 </div>
488 }
489
490 @helper RenderThumbnail(string image)
491 {
492 string productId = GetString("Ecom:Product.ID");
493 string thumbPrefix = "/Admin/Public/GetImage.ashx?width=200&height=200&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=";
494 string imagePrefix = "/Admin/Public/GetImage.ashx?width=800&height=800&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=";
495
496 <div class="carousel__slide carousel__slide--vertical dw-mod">
497 <div class="thumb-list__item thumb-list__item--active dw-mod js-thumb js-gallery" data-for="Preview_@productId" data-preview="@imagePrefix@image" data-preview-type="img" onmouseover="Gallery.openImage(this)">
498 <label for="GalleryModalTrigger">
499 <img src="@thumbPrefix@image" alt="@GetString("Ecom:Product.Name")" class="js-gallery" data-for="FullImage" data-preview="@image" data-preview-type="img" onclick="Gallery.openImage(this)">
500 </label>
501 </div>
502 </div>
503 }
504
505 @helper RenderYoutube()
506 {
507 string productId = GetString("Ecom:Product.ID");
508 var videos = GetLoop("Smartpage:Product.VideoLoop");
509
510 foreach (var video in videos)
511 {
512
513 <div class="carousel__slide carousel__slide--vertical dw-mod">
514 <div class="thumb-list__item dw-mod js-thumb js-gallery" data-for="Preview_@productId" data-preview="@video.GetString("Preview")" data-preview-type="@video.GetString("PreviewType")" onmouseover="Gallery.openImage(this)">
515 <label for="GalleryModalTrigger" class="u-position-relative">
516 <i class="thumb-play-btn fas fa-play-circle u-brand-color-one" onclick="Gallery.openImage(document.getElementById('thumb-video_@video.GetString("VideoID")'))"></i>
517 <img id="thumb-video_@video.GetString("VideoID")" src="@video.GetString("Thumbnail")" alt="@GetString("Ecom:Product.Name")" class="js-gallery" data-for="FullImage" data-preview="@video.GetString("Preview")" data-preview-type="@video.GetString("PreviewType")" onclick="Gallery.openImage(this)">
518 </label>
519 </div>
520 </div>
521
522 }
523 }
524 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
525 @using Dynamicweb.Core
526 @using System
527 @using System.Web
528 @using System.Collections.Generic
529 @using Dynamicweb.Rapido.Blocks
530 @using Smartpage.CookieManager
531 @using System.Text.RegularExpressions
532 @using Smartpage.Ecommerce.Repo;
533
534 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
535 @using System.Text.RegularExpressions
536 @using Dynamicweb.Core
537 @functions{
538 /*
539 * Price States:
540 * 1: Exact amount is displayed (green)
541 * 2: Currently unavailable (yellow)
542 * NOTE: IF product manufactor is in Website Settings list, then *2-alternative* is used
543 * 3: Not available (red)
544 * 4: Contact Kruuse for buying this product (grey)
545 */
546
547 public class Prices
548 {
549 public string price { get; set; }
550 public double priceDouble { get; set; }
551 public string discount { get; set; }
552 }
553
554 Prices renderPriceObject()
555 {
556 Prices priceOjbect = new Prices();
557
558 if (GetString("Ecom:Product.Discount.Price.PriceFormatted") != GetString("Ecom:Product.Price.PriceFormatted") || GetString("Ecom:Product.Discount.Price.PriceFormatted") != GetString("Ecom:Product.InformativePrice.PriceFormatted"))
559 {
560 priceOjbect.price = GetString("Ecom:Product.Discount.Price.PriceFormatted");
561 priceOjbect.priceDouble = (GetDouble("Ecom:Product.Discount.Price.PricePIP") / 100);
562 priceOjbect.discount = GetString("Ecom:Product.InformativePrice.PriceFormatted");
563 }
564 else
565 {
566 priceOjbect.price = GetString("Ecom:Product.Price.PriceFormatted");
567 priceOjbect.priceDouble = (GetDouble("Ecom:Product.Price.PricePIP") / 100);
568 }
569
570 return priceOjbect;
571 }
572
573 Prices renderPriceObject(LoopItem product)
574 {
575 Prices priceOjbect = new Prices();
576
577 if (product.GetString("Ecom:Product.Discount.Price.PriceFormatted") != product.GetString("Ecom:Product.Price.PriceFormatted") || product.GetString("Ecom:Product.Discount.Price.PriceFormatted") != product.GetString("Ecom:Product.InformativePrice.PriceFormatted"))
578 {
579 priceOjbect.price = product.GetString("Ecom:Product.Discount.Price.PriceFormatted");
580 priceOjbect.priceDouble = (product.GetDouble("Ecom:Product.Discount.Price.PricePIP") / 100);
581 priceOjbect.discount = product.GetString("Ecom:Product.InformativePrice.PriceFormatted");
582 }
583 else
584 {
585 priceOjbect.price = product.GetString("Ecom:Product.Price.PriceFormatted");
586 priceOjbect.priceDouble = (product.GetDouble("Ecom:Product.Price.PricePIP") / 100);
587 }
588
589 return priceOjbect;
590 }
591
592 string renderPriceState()
593 {
594 return renderPriceState(renderPriceObject().priceDouble);
595 }
596
597 string renderPriceState(double price)
598 {
599 if (GetInteger("Smartpage:Product.Prices.Count") == 0 || price >= Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetDouble("SpProductPriceLimit"))
600 {
601 return "4";
602 }
603 else if (GetInteger("Ecom:Product.Stock") <= 0)
604 {
605 if (GetBoolean("Ecom:Product:Field.Discontinued"))
606 {
607 return "3";
608 }
609 else
610 {
611 return "2";
612 }
613 }
614 else
615 {
616 return "1";
617 }
618 }
619
620 string renderPriceState(Dynamicweb.Ecommerce.Products.Product product)
621 {
622 if (product.Prices == null || product.Prices.Count == 0 || product.Price.Price >= Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetDouble("SpProductPriceLimit"))
623 {
624 return "4";
625 }
626 else if (product.Stock <= 0)
627 {
628 if (Converter.ToBoolean(product.GetProductFieldValue("Discontinued")))
629 {
630 return "3";
631 }
632 else
633 {
634 return "2";
635 }
636 }
637 else
638 {
639 return "1";
640 }
641 }
642
643 string renderPriceState(Dynamicweb.Ecommerce.Products.Product product, string stockAmount)
644 {
645 if (product.Prices == null || product.Prices.Count == 0 || product.Price.Price >= Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetDouble("SpProductPriceLimit"))
646 {
647 return "4";
648 }
649 else if (Converter.ToInt32(stockAmount) <= 0)
650 {
651 if (Converter.ToBoolean(product.GetProductFieldValue("Discontinued")))
652 {
653 return "3";
654 }
655 else
656 {
657 return "2";
658 }
659 }
660 else
661 {
662 return "1";
663 }
664 }
665
666 string renderPriceState(LoopItem product)
667 {
668 return renderPriceState(product, renderPriceObject(product).priceDouble);
669 }
670
671
672 string renderPriceState(LoopItem product, double price)
673 {
674 if (product.GetInteger("Smartpage:Product.Prices.Count") == 0 || price >= Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetDouble("SpProductPriceLimit"))
675 {
676 return "4";
677 }
678 else if (product.GetInteger("Ecom:Product.Stock") <= 0)
679 {
680 if (product.GetBoolean("Ecom:Product:Field.Discontinued"))
681 {
682 return "3";
683 }
684 else
685 {
686 return "2";
687 }
688 }
689 else
690 {
691 return "1";
692 }
693 }
694
695
696 string renderPriceState(LoopItem product, string stockAmount)
697 {
698 return renderPriceState(product, renderPriceObject(product).priceDouble, stockAmount);
699 }
700
701 string renderPriceState(LoopItem product, double price, string stockAmount)
702 {
703 if (product.GetInteger("Smartpage:Product.Prices.Count") == 0 || price >= Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetDouble("SpProductPriceLimit"))
704 {
705 return "4";
706 }
707 else if (Converter.ToInt32(stockAmount) <= 0)
708 {
709 if (product.GetBoolean("Ecom:Product:Field.Discontinued"))
710 {
711 return "3";
712 }
713 else
714 {
715 return "2";
716 }
717 }
718 else
719 {
720 return "1";
721 }
722 }
723
724 string renderPrice(string price)
725 {
726 var priceState = renderPriceState();
727 if (priceState != "4")
728 {
729 return price;
730 }
731
732 return "";
733 }
734
735 string renderPrice(LoopItem product, string price)
736 {
737 var priceState = renderPriceState(product);
738 if (priceState != "4")
739 {
740 return price;
741 }
742
743 return "";
744 }
745
746 double renderPrice(double price)
747 {
748 var priceState = renderPriceState(price);
749 if (priceState != "4")
750 {
751 return price;
752 }
753
754 return 0;
755 }
756
757 double renderPrice(LoopItem product, double price)
758 {
759 var priceState = renderPriceState(product, price);
760 if (priceState != "4")
761 {
762 return price;
763 }
764
765 return 0;
766 }
767
768 string renderStockState()
769 {
770 var priceState = renderPriceState();
771
772 return "stock-icon--state" + priceState;
773 }
774
775 string renderStockState(Dynamicweb.Ecommerce.Products.Product product)
776 {
777 var priceState = renderPriceState(product);
778
779 return "stock-icon--state" + priceState;
780 }
781
782 string renderStockState(Dynamicweb.Ecommerce.Products.Product product, string stockAmount)
783 {
784 var priceState = renderPriceState(product, stockAmount);
785
786 return "stock-icon--state" + priceState;
787 }
788
789 string renderStockState(LoopItem product)
790 {
791 var priceState = renderPriceState(product);
792
793 return "stock-icon--state" + priceState;
794 }
795
796 string renderStockText(string stockLevel)
797 {
798 var priceState = renderPriceState();
799 var useAlternative = priceState == "2" && Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetList("SpAlternativeStockTextManufacturers").SelectedValues.Any(i => i == GetString("Ecom:Manufacturer.ID"));
800
801 return string.Format(Translate("State" + priceState + (useAlternative ? "Alternative" : ""), "{0}"), stockLevel);
802 }
803
804 string renderStockText(LoopItem product)
805 {
806 var priceState = renderPriceState(product);
807 var useAlternative = priceState == "2" && Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetList("SpAlternativeStockTextManufacturers").SelectedValues.Any(i => i == product.GetString("Ecom:Manufacturer.ID"));
808
809 return string.Format(Translate("State" + priceState + (useAlternative ? "Alternative" : ""), "{0}"), product.GetString("Ecom:Product.Stock"));
810 }
811
812 string renderStockText(LoopItem product, string stockAmount)
813 {
814 var priceState = renderPriceState(product, stockAmount);
815 var useAlternative = priceState == "2" && Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetList("SpAlternativeStockTextManufacturers").SelectedValues.Any(i => i == product.GetString("Ecom:Manufacturer.ID"));
816
817 return string.Format(Translate("State" + priceState + (useAlternative ? "Alternative" : ""), "{0}"), stockAmount);
818 }
819
820 string renderHideBuyOptions(string option)
821 {
822 var priceState = renderPriceState();
823 if (priceState == "3" || priceState == "4")
824 {
825 return option;
826 }
827
828 return "";
829 }
830
831 string renderHideBuyOptions(LoopItem product, string option)
832 {
833 var priceState = renderPriceState(product);
834 if (priceState == "3" || priceState == "4")
835 {
836 return option;
837 }
838
839 return "";
840 }
841 }
842
843 @functions {
844 bool useFacebookPixel;
845 bool useGoogleTagManager;
846 BlocksPage mainInfoPage = BlocksPage.GetBlockPage("Product");
847
848 CookieBot cookieBot = new CookieBot();
849 }
850
851 @{
852 bool mainInfoRenderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetString("RenderVariantsAsProductList") != null && GetInteger("Ecom:Product.VariantCount") > 1 ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") : false;
853 bool mainPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly");
854 bool mainInfoOnlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
855 string mainInfoVariantId = HttpContext.Current.Request.QueryString.Get("variantId") != null ? HttpContext.Current.Request.QueryString.Get("variantId") : "";
856 string mainInfoFeedId = GetGlobalValue("Global:Page.ID").ToString() + "&ProductID=" + GetString("Ecom:Product.ID") + "&VariantID=" + mainInfoVariantId + "&Feed=True&redirect=false";
857 string mainInfoCartIcon = "fas fa-shopping-cart";
858
859 useFacebookPixel = !string.IsNullOrWhiteSpace(Pageview.AreaSettings.GetItem("Settings").GetString("FacebookPixelID")) && cookieBot.Marketing;
860 useGoogleTagManager = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("GoogleTagManagerID")) && cookieBot.Statistics;
861
862 Block mainInfoHeader = new Block()
863 {
864 Id = "MainInfoHeader",
865 SortId = 10,
866 Template = RenderMainInfoHeader()
867 };
868 mainInfoPage.Add("MainInformation", mainInfoHeader);
869
870 Block mainInfoDescription = new Block()
871 {
872 Id = "ShortDescription",
873 SortId = 30,
874 Template = RenderShortDescription()
875 };
876 mainInfoPage.Add("MainInformation", mainInfoDescription);
877
878 if (!mainInfoRenderVariantsAsProducts)
879 {
880 Block mainInfoVariants = new Block()
881 {
882 Id = "Variants",
883 SortId = 50,
884 Template = RenderMainInfoVariants()
885 };
886 mainInfoPage.Add("MainInformation", mainInfoVariants);
887 }
888
889 Block mainInfoBOM = new Block()
890 {
891 Id = "BOM",
892 SortId = 60,
893 Template = RenderMainInfoBOM()
894 };
895 mainInfoPage.Add("MainInformation", mainInfoBOM);
896
897 if (!mainInfoRenderVariantsAsProducts)
898 {
899 Block mainInfoBuy = new Block()
900 {
901 Id = "Buy",
902 SortId = 80,
903 Template = RenderMainInfoBuy()
904 };
905 mainInfoPage.Add("MainInformation", mainInfoBuy);
906
907 //Block stockAndShipping = new Block()
908 //{
909 // Id = "StockAndShipping",
910 // SortId = 90,
911 // Template = RenderStockAndShipping()
912 //};
913 //mainInfoPage.Add("MainInformation", stockAndShipping);
914 }
915 }
916
917 @helper RenderMainInfoHeader()
918 {
919 bool renderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") != null && GetInteger("Ecom:Product.VariantCount") > 1 ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") : false;
920 string pageId = GetGlobalValue("Global:Page.ID").ToString();
921 //string currentPrice = renderPrice(GetString("Ecom:Product.Discount.Price.PriceFormatted") == GetString("Ecom:Product.Price.PriceFormatted") ? GetString("Ecom:Product.Price.PriceFormatted") : GetString("Ecom:Product.Discount.Price.PriceFormatted"));
922 bool hideProductNumber = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideProductNumber");
923
924 bool useFontAwesomePro = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetBoolean("UseFontAwesomePro");
925 var selectedFavoriteIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon").SelectedValue : "star";
926 string favoriteIcon = "fas fa-" + selectedFavoriteIcon + " fac-red";
927 string favoriteOutlineIcon = "far fa-" + selectedFavoriteIcon + " fac-grey";
928 Dynamicweb.Ecommerce.Products.Product apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductByNumber(GetString("Ecom:Product.Number"), Dynamicweb.Ecommerce.Common.Context.LanguageID);
929
930 <div>
931 <div class="u-pull--left product__title dw-mod">
932 <h1 class="u-no-margin">@GetString("Ecom:Product.Name") @GetString("Ecom:Product.SelectedVariantComboName")</h1>
933
934 @if (!hideProductNumber && apiProduct != null && !apiProduct.IsVariantMaster)
935 {
936 <div class="item-number dw-mod">@GetString("Ecom:Product.Number")</div>
937 }
938 </div>
939 </div>
940 }
941
942 @helper RenderStockAndShipping()
943 {
944 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideStockState") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState") : false;
945 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideShipping") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping") : false;
946 bool onlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
947
948 var stockState = renderStockState();
949 var stockText = renderStockText(GetString("Ecom:Product.Stock"));
950 var deliveryText = string.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText")) ? "" : ", " + Translate("Delivery") + " " + GetString("Ecom:Product:Stock.DeliveryText") + " " + GetString("Ecom:Product:Stock.DeliveryUnit");
951 string variantId = GetString("Ecom:Product.VariantID");
952 int variantCount = GetInteger("Ecom:Product.VariantCount");
953
954 if (!onlyPreview && (!string.IsNullOrEmpty(stockState)) /*|| !string.IsNullOrEmpty(deliveryText)) && !string.IsNullOrEmpty(variantId) && variantCount > 0*/)
955 {
956 <div class="product__stock-delivery dw-mod">
957 <span>
958 @if (!hideStockState)
959 {
960 <span class="stock-icon @stockState u-no-margin dw-mod" title="@stockText"></span> @stockText@deliveryText
961 }
962
963 @if (!string.IsNullOrEmpty(deliveryText) && !hideDelivery)
964 {
965 @deliveryText
966 }
967 </span>
968 </div>
969 }
970 }
971
972 @helper RenderShortDescription()
973 {
974 if (!String.IsNullOrEmpty(GetString("Ecom:Product.ShortDescription")))
975 {
976 var shortDescription = GetString("Ecom:Product.ShortDescription");
977
978 if (!cookieBot.Statistics)
979 {
980 var iframes = Regex.Match(shortDescription, "<iframe[^>]*?(?:\\/>|>[^<]*?<\\/iframe>)");
981 if (iframes.Success)
982 {
983 foreach (Group item in iframes.Groups)
984 {
985 shortDescription = shortDescription.Replace(item.Value, "");
986 }
987 }
988 }
989
990 <div class="introduction-text">
991 @shortDescription
992 </div>
993 }
994 }
995
996 @helper RenderMainInfoVariants()
997 {
998 string pageId = GetGlobalValue("Global:Page.ID").ToString();
999 string productId = GetString("Ecom:Product.ID");
1000 string variantSelection = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("variantId")) ? HttpContext.Current.Request.QueryString.Get("variantId").Replace(".", ",") : "";
1001 string hideHelpText = "";
1002
1003 foreach (LoopItem variantgroup in GetLoop("VariantGroups"))
1004 {
1005 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions"))
1006 {
1007 if (variantoption.GetBoolean("Ecom:VariantOption.Selected"))
1008 {
1009 hideHelpText = "u-hidden";
1010 }
1011 }
1012 }
1013
1014 if (GetLoop("VariantGroups").Count > 0)
1015 {
1016 var variantCombinationsObject = new List<Array>();
1017 foreach (LoopItem variantcomb in GetLoop("VariantStockCombinations"))
1018 {
1019 string[] combinations = variantcomb.GetString("Ecom:VariantStockCombination.VariantID").Split('.');
1020 variantCombinationsObject.Add(combinations);
1021 }
1022
1023 string combinationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantCombinationsObject).Replace("\"", "\'");
1024
1025 var variantGroupsObject = new List<List<String>>();
1026 foreach (LoopItem variantGroup in GetLoop("VariantGroups"))
1027 {
1028 var variantsObject = new List<String>();
1029 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions"))
1030 {
1031 variantsObject.Add(variantOption.GetString("Ecom:VariantOption.ID"));
1032 }
1033 variantGroupsObject.Add(variantsObject);
1034 }
1035 string variantsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantGroupsObject).Replace("\"", "\'");
1036
1037 <div>
1038 <div 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">
1039 @foreach (LoopItem variantGroup in GetLoop("VariantGroups"))
1040 {
1041 string groupId = variantGroup.GetString("Ecom:VariantGroup.ID");
1042
1043 <div>
1044 <div class="u-bold">@variantGroup.GetString("Ecom:VariantGroup.Name")</div>
1045 <div>
1046 @foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions"))
1047 {
1048 Dynamicweb.Ecommerce.Products.Product apiProductVariant = Dynamicweb.Ecommerce.Services.Products.GetProductById(GetString("Ecom:Product.ID"), variantOption.GetString("Ecom:VariantOption.ID"), Dynamicweb.Ecommerce.Common.Context.LanguageID);
1049 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : "";
1050 if (apiProductVariant.Active)
1051 {
1052 if (!string.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.ImgSmall.Clean")))
1053 {
1054 string variantImage = "/Admin/Public/GetImage.ashx?width=100&height=50&crop=5&Compression=75&image=/Images/" + variantOption.GetString("Ecom: VariantOption.ImgSmall.Clean");
1055 <img data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" src="@variantImage" onclick="MatchVariants.SelectThis(event)" alt="@variantOption.GetString("Ecom:VariantOption.Name")" title="@variantOption.GetString("Ecom:VariantOption.Name")" class="btn btn--tag @selected js-variant-option" data-check="@selected" />
1056 }
1057 else
1058 {
1059 <button type="button" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" onclick="MatchVariants.SelectThis(event)" class="btn btn--tag @selected js-variant-option" data-check="@selected">@variantOption.GetString("Ecom:VariantOption.Name")</button>
1060 }
1061 }
1062 }
1063 </div>
1064 </div>
1065 }
1066 </div>
1067 <small class="js-help-text help-text @hideHelpText">@Translate("Please select variant!")</small>
1068 </div>
1069 {
1070 bool mainInfoOnlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
1071 if (!mainInfoOnlyPreview)
1072 {
1073 Dynamicweb.Ecommerce.Products.Product apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductByNumber(GetString("Ecom:Product.Number"), Dynamicweb.Ecommerce.Common.Context.LanguageID);
1074 if (apiProduct != null && apiProduct.IsVariantMaster)
1075 {
1076 VariantPriceService variantPriceService = new VariantPriceService();
1077 var fromPrice = variantPriceService.GetLowestPrice(GetString("Ecom:Product.ID"), Dynamicweb.Ecommerce.Common.Context.Currency.Code, Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser());
1078 <h5>@Translate("Smartpage:Variant.FromPrice.Text", "Fra:") @fromPrice</h5>
1079 }
1080 }
1081 }
1082
1083
1084 }
1085 }
1086
1087 @helper RenderMainInfoBOM()
1088 {
1089 if (GetLoop("BOMProducts").Count > 0)
1090 {
1091 <h2 class="section-title">@Translate("Including products")</h2>
1092 foreach (LoopItem BOMProductItem in GetLoop("BOMProducts"))
1093 {
1094 string link = "/" + BOMProductItem.GetString("Ecom:Product.LinkGroup.Clean") + (!String.IsNullOrEmpty(BOMProductItem.GetString("Ecom:Product.VariantID")) ? "&VariantID=" + BOMProductItem.GetString("Ecom:Product.VariantID") : "");
1095 <div class="grid__col--border grid">
1096 <div class="grid__cell grid__cell--align-middle-left">
1097 <a href="@link" class="u-pull--left u-margin-right">
1098 <img src="/Admin/Public/GetImage.ashx?width=50&image=@BOMProductItem.GetString("Ecom:Product.ImageDefault.Default.Clean")&Compression=99" alt="@BOMProductItem.GetString("Ecom:Product.Name")" />
1099 </a>
1100 <a href="@link">@BOMProductItem.GetString("Ecom:Product.Name")</a>
1101 </div>
1102 </div>
1103 }
1104 }
1105 }
1106
1107 @helper RenderMainInfoBuy()
1108 {
1109 string pageId = GetGlobalValue("Global:Page.ID").ToString();
1110 string variantId = HttpContext.Current.Request.QueryString.Get("variantId");
1111 string productId = GetString("Ecom:Product.ID");
1112 string feedId = pageId + "&ProductID=" + productId + "&VariantID=" + variantId + "&Feed=True&redirect=false";
1113
1114 <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>
1115 <input type="hidden" value="@GetString("Ecom:Product.VariantID.Extented")" name="Variant" id="Variant_@GetString("Ecom:Product.ID")" />
1116 }
1117
1118 @* Handlebars templates *@
1119
1120
1121 <script id="PricesAndActionsTemplate" type="text/x-template">
1122
1123
1124 {{#.}}
1125 {{#if discontinued}}
1126 {{>DiscontinuedTemplate}}
1127 {{else}}
1128 @if (!mainInfoOnlyPreview)
1129 {
1130
1131 <text>{{#if Prices}}</text>
1132 <div class="u-margin-bottom--lg dw-mod">
1133 {{>PriceList}}
1134 </div>
1135 <text>{{/if}}</text>
1136
1137 <div class="product__price-actions__price dw-mod u-margin-bottom--lg">
1138 @if (mainPointShopOnly)
1139 {
1140 <text>
1141 {{#if havePointPrice}}
1142 <div class="price price--product-page dw-mod">{{points}} @Translate("points")</div>
1143 {{else}}
1144 @Translate("Not available")
1145 {{/if}}
1146 </text>
1147 }
1148 else
1149 {
1150 <text>
1151 {{#ifCond variantSelected "!==" "False"}}
1152 <div class="before-price {{onSale}} dw-mod">{{discount}}</div>
1153 <div class="price price--product-page dw-mod">{{price}}</div>
1154 {{#if standardOrderQuantity}}
1155 <div class="{{hideBuyOptions}}">@Translate("Kolli"): {{standardOrderQuantity}}</div>
1156 {{/if}}
1157 {{/ifCond}}
1158 </text>
1159 }
1160 </div>
1161 <div class="buttons-collection buttons-collection--right product__price-actions__actions {{hideBuyOptions}} dw-mod">
1162 <input type="checkbox" id="UnitOptions_{{id}}" class="dropdown-trigger" />
1163 <div class="dropdown u-w150px u-w80px--xs dw-mod {{hasUnits}}">
1164 <label class="dropdown__header dropdown__btn dw-mod" for="UnitOptions_{{id}}">{{unitName}}</label>
1165 <div id="unitOptions" class="dropdown__content dw-mod">
1166 {{#unitOptions}}
1167 {{>UnitOption}}
1168 {{/unitOptions}}
1169 </div>
1170 <label class="dropdown-trigger-off" for="UnitOptions_{{id}}"></label>
1171 </div>
1172
1173 <input type="hidden" value="{{unitId}}" name="Unit" id="Unit_{{id}}" />
1174 @if (mainPointShopOnly)
1175 {
1176 <button type="button" id="CartButton_{{id}}" class="btn btn--primary btn--condensed dw-mod js-cart-btn {{disabledBuyButton}} {{#unless canBePurchasedWithPoints}}js-stay-disabled{{/unless}}" name="CartCmd" value="addWithPoints"
1177 onclick="Cart.AddToCartByObject(event, {
1178 id: '{{productId}}',
1179 variantId: '{{variantid}}',
1180 unitId: '{{unitId}}',
1181 quantity: 1,
1182 buyForPoints: true,
1183 productInfo: {{productInfo}},
1184 multiplum: {{multiplum}},
1185 multiplumUnitId: '{{ProductDefaultUnitId}}',
1186 standardOrderQuantity: {{standardOrderQuantity}}
1187 }); {{facebookPixelAction}}">
1188 <i class="@mainInfoCartIcon"></i><span class="u-hidden-xs u-hidden-xxs"> @Translate("Buy with points")</span>
1189 </button>
1190 <text>
1191 {{#unless canBePurchasedWithPoints}}
1192 {{#if havePointPrice}}
1193 <small class="help-text u-no-margin u-margin-top">@Translate("Not enough points to buy this")</small>
1194 {{/if}}
1195 {{/unless}}
1196 </text>
1197 }
1198 else
1199 {
1200 <text>{{#ifCond multiplum ">" "1"}}
1201 <input type="number" class="u-w70px product-quantity" id="Quantity_{{id}}" name="Quantity" value="{{multiplum}}" min="1">
1202 {{else}}
1203 <input type="number" class="u-w70px product-quantity" id="Quantity_{{id}}" name="Quantity" value="1" min="1">
1204 {{/ifCond}}
1205 </text>
1206 <button type="button" id="CartButton_{{id}}" class="btn btn--primary btn--condensed dw-mod js-cart-btn" name="submit"
1207 onclick="Cart.AddToCartByObject(event, {
1208 id: '{{productId}}',
1209 variantId: '{{variantid}}',
1210 unitId: '{{unitId}}',
1211 quantity: document.getElementById('Quantity_{{id}}').value,
1212 productInfo: {{productInfo}},
1213 multiplum: {{multiplum}},
1214 multiplumUnitId: '{{ProductDefaultUnitId}}',
1215 standardOrderQuantity: {{standardOrderQuantity}}
1216 }); {{facebookPixelAction}}">
1217 <i class="@mainInfoCartIcon"></i><span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span>
1218 </button>
1219 }
1220
1221 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && !(Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") && GetInteger("Ecom:Product.VariantCount") > 1))
1222 {
1223
1224 <text>{{>FavoriteTemplateContainer}}</text>
1225
1226 }
1227
1228 </div>
1229 if (Pageview.User != null && !mainPointShopOnly && Dynamicweb.Security.Licensing.LicenseManager.LicenseHasFeature("LoyaltyPoints"))
1230 {
1231 <text>
1232 {{#if canBePurchasedWithPoints}}
1233 <form method="post" role="form" class="u-no-margin u-margin-top">
1234 <input type="hidden" name="ProductID" value="{{id}}" />
1235 <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>
1236 </form>
1237 {{/if}}
1238 </text>
1239 }
1240 }
1241 else
1242 {
1243 <button type="button" id="CartButton_{{id}}" class="u-hidden"></button>
1244 }
1245 {{/if}}
1246
1247 @{
1248 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideStockState") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState") : false;
1249 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideShipping") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping") : false;
1250 var deliveryText = string.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText")) ? "" : ", " + Translate("Delivery") + " " + GetString("Ecom:Product:Stock.DeliveryText") + " " + GetString("Ecom:Product:Stock.DeliveryUnit");
1251 }
1252 @if (!mainInfoOnlyPreview)
1253 {
1254 <text>
1255 {{#ifCond hasVariants "!==" "disabled"}}
1256 <div class="product__stock-delivery dw-mod">
1257 <span>
1258 @if (!hideStockState)
1259 {
1260 <span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span> @:{{stockText}}
1261 }
1262
1263 @if (!string.IsNullOrEmpty(deliveryText) && !hideDelivery)
1264 {
1265 @deliveryText
1266 }
1267 </span>
1268 </div>
1269 {{/ifCond}}
1270 </text>
1271 }
1272 {{/.}}
1273 </script>
1274
1275
1276 <script id="FavoriteTemplateContainer" type="text/x-template">
1277 {{#Favorite}}
1278 <div id="Favorite_{{id}}" class="u-inline">
1279 <button type="button" id="FavoriteButton_{{id}}" class="btn btn--default btn--condensed u-no-margin dw-mod favorite-btn" onclick="document.getElementById('FavoriteTrigger_{{id}}').click();">
1280 {{#if anyItemsInList}}
1281 <span class="u-hidden-xs u-hidden-xxs favorite-btn-text">{{modifyText}}</span>
1282 {{else}}
1283 <span class="u-hidden-xs u-hidden-xxs favorite-btn-text">{{addText}}</span>
1284 {{/if}}
1285 <i class="{{favoriteIcon}}"></i>
1286 </button>
1287 <input type="checkbox" id="FavoriteTrigger_{{id}}" class="dropdown-trigger" />
1288 <div class="dropdown favorites-dropdown">
1289 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod">
1290 <span class="u-bold">@Translate("Your lists")</span>
1291 <ul class="list list--clean dw-mod" id="FavoriteContainer_{{id}}">
1292 {{#FavoriteLists}}
1293 <li>
1294 {{#if isInThisList}}
1295 <span class="is-in-list">{{name}}</span>
1296 <a class="remove-from-favorites" onclick="{{facebookPixelAction}} List.RemoveFromList('detail', '{{link}}');"><i class="fa fa-times u-color-font-black"></i></a>
1297 {{else}}
1298 <span>{{name}}</span>
1299 <a class="add-to-favorites" onclick="{{facebookPixelAction}} List.AddToList('detail', '{{link}}', '{{id}}', '{{variantId}}', '@GetPageIdByNavigationTag("ProductsPage")', this);">@Translate("Add")</a>
1300 {{/if}}
1301 </li>
1302 {{/FavoriteLists}}
1303 </ul>
1304 </div>
1305 <label class="dropdown-trigger-off" for="FavoriteTrigger_{{id}}"></label>
1306 </div>
1307 </div>
1308 {{/Favorite}}
1309 </script>
1310
1311 <script id="Units" type="text/x-template">
1312 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '/Default.aspx?ID=@mainInfoFeedId&UnitID={{value}}')">{{name}}</div>
1313 </script>
1314
1315 <script id="UnitOption" type="text/x-template">
1316 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '{{link}}&feed=true&UnitID={{value}}&rid={{id}}')">{{name}}</div>
1317 </script>
1318
1319
1320 <script>
1321 document.addEventListener("DOMContentLoaded", function () {
1322 if (document.getElementById("PriceAndActions")) {
1323 document.getElementById("PriceAndActions").addEventListener("contentLoaded", function (event) {
1324 if (document.querySelector(".js-variants") != null) {
1325 MatchVariants.Update(document.querySelector(".js-variants"), "DoNothing");
1326 }
1327 });
1328 }
1329 });
1330 </script>
1331
1332 @if (useGoogleTagManager)
1333 {
1334 var groupObject = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(GetString("Ecom:Product.PrimaryOrFirstGroupID"));
1335
1336 <script>
1337 // Measure a view of product details. This example assumes the detail view occurs on pageload,
1338 // and also tracks a standard pageview of the details page.
1339 dataLayer.push({
1340 'ecommerce': {
1341 'detail': {
1342 'actionField': {}, // 'detail' actions have an optional list property.
1343 'products': [{
1344 'name': '@GetString("Ecom:Product.Name")', // Name or ID is required.
1345 'id': '@GetString("Ecom:Product.ID")',
1346 'price': '@(GetDouble("Ecom:Product.Discount.Price.Price") != GetDouble("Ecom:Product.Price.Price") ? GetDouble("Ecom:Product.Discount.Price.Price") : GetDouble("Ecom:Product.Price.Price"))',
1347 'brand': '@GetString("Ecom:Product:Field.brand.Value")',
1348 'category': '@(groupObject != null ? groupObject.Name : "")',
1349 'variant': '@(!string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"))'
1350 }]
1351 }
1352 }
1353 });
1354 </script>
1355 }
1356 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
1357 @using Dynamicweb.Core
1358 @using System
1359 @using System.Web
1360 @using System.Collections.Generic
1361 @using Dynamicweb.Rapido.Blocks
1362 @using Smartpage.CookieManager
1363 @using System.Text.RegularExpressions
1364
1365 @functions {
1366 BlocksPage productDescriptionPage = BlocksPage.GetBlockPage("Product");
1367 }
1368
1369 @{
1370 string fullDesctiptionLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("FullDescriptionLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue : "Section";
1371 fullDesctiptionLayout = fullDesctiptionLayout == "Ribbon" ? "Section" : fullDesctiptionLayout;
1372
1373 if (!string.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && fullDesctiptionLayout != "hide")
1374 {
1375 Block detailsDescription = new Block()
1376 {
1377 Name = fullDesctiptionLayout != "MainInformation" ? Translate("Description") : "",
1378 Id = "FullDescription",
1379 SortId = 10,
1380 Template = RenderProductDescription(fullDesctiptionLayout),
1381 Design = new Design
1382 {
1383 Size = "12",
1384 RenderType = RenderType.Column,
1385 HidePadding = true
1386 }
1387 };
1388 productDescriptionPage.Add(fullDesctiptionLayout, detailsDescription);
1389 }
1390 }
1391
1392 @helper RenderProductDescription(string layout)
1393 {
1394 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "";
1395 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : "";
1396
1397 <div class="product__section @ribbonClasses dw-mod">
1398 <div class="product__description center-container @ribbonSubClasses dw-mod">
1399 @if (layout == "Section") {
1400 <h2>@Translate("Description")</h2>
1401 }
1402
1403 @{
1404 var longDescription = GetString("Ecom:Product.LongDescription");
1405
1406 if (!new CookieBot().Statistics)
1407 {
1408 var iframes = Regex.Match(longDescription, "<iframe[^>]*?(?:\\/>|>[^<]*?<\\/iframe>)");
1409 if (iframes.Success)
1410 {
1411 foreach (Group item in iframes.Groups)
1412 {
1413 longDescription = longDescription.Replace(item.Value, "");
1414 }
1415 }
1416 }
1417
1418 @longDescription
1419 }
1420 </div>
1421 </div>
1422 }
1423 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
1424 @using Dynamicweb.Core
1425 @using System
1426 @using System.Web
1427 @using System.Globalization;
1428 @using System.Collections.Generic
1429 @using Dynamicweb.Rapido.Blocks
1430 @using System.Linq
1431
1432 @functions {
1433 BlocksPage productFieldsPage = BlocksPage.GetBlockPage("Product");
1434 List<LoopItem> downloadDocuments = new List<LoopItem>();
1435
1436 static string ConvertBytes(long bytes)
1437 {
1438 double size = bytes / 1024; //KB
1439 if (size > 1024)
1440 {
1441 size = (bytes / 1024f) / 1024f; //MB
1442 return string.Format("{0:n1} MB", size);
1443 }
1444 else
1445 {
1446 return string.Format("{0:n0} KB", size);
1447 }
1448 }
1449
1450 static bool isImage(string path)
1451 {
1452 return new List<string> { ".jpg", ".jpeg", ".gif", ".png", ".svg" }.Contains(Path.GetExtension(path).ToLower());
1453 }
1454
1455 string getIconForFile(string fileName)
1456 {
1457 string ext = Path.GetExtension(fileName);
1458 string icon = "";
1459 switch (ext.ToLower())
1460 {
1461 case ".xls":
1462 case ".xlsx":
1463 icon = "fa-file-excel";
1464 break;
1465 case ".ppt":
1466 case ".pptx":
1467 icon = "fa-file-powerpoint";
1468 break;
1469 case ".doc":
1470 case ".docx":
1471 icon = "fa-file-word";
1472 break;
1473 case ".jpg":
1474 case ".jpeg":
1475 case ".png":
1476 case ".gif":
1477 case ".pdf":
1478 return "<img class='product__document-img' alt='" + fileName + "' src='/Admin/Public/GetImage.ashx?crop=5&height=70&width=120&Compression=75&DoNotUpscale=true&image=" + HttpUtility.UrlEncode(fileName) + "' />";
1479 default:
1480 icon = "fa-file";
1481 break;
1482 }
1483 return "<i class='product__document-icon far " + icon + "'></i> ";
1484 }
1485 }
1486
1487 @{
1488 foreach (LoopItem customField in GetLoop("CustomFieldValues"))
1489 {
1490 if (!string.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) && !string.IsNullOrEmpty(customField.GetString("Product.CustomField.Value.Clean")) && customField.GetString("Product.CustomField.Name") != "Custom sticker")
1491 {
1492 if (!string.IsNullOrEmpty(customField.GetString("Document.FullPath")))
1493 {
1494 downloadDocuments.Add(customField);
1495 }
1496 }
1497 }
1498
1499 foreach (LoopItem customField in GetLoop("ProductCategories"))
1500 {
1501 foreach (LoopItem field in customField.GetLoop("ProductCategoryFields"))
1502 {
1503 if (!string.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Label")) && !string.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Value")))
1504 {
1505 if (field.GetString("Ecom:Product.CategoryField.TypeID") == "9")
1506 {
1507 downloadDocuments.Add(field);
1508 }
1509 }
1510 }
1511 }
1512
1513 foreach (LoopItem detail in GetLoop("Details"))
1514 {
1515 if (!string.IsNullOrEmpty(detail.GetString("Ecom:Product:Detail.Image.Clean")))
1516 {
1517 downloadDocuments.Add(detail);
1518 }
1519 }
1520
1521 string detailFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout").SelectedValue : "Section";
1522 detailFieldsLayout = detailFieldsLayout == "Ribbon" || string.IsNullOrEmpty(detailFieldsLayout) ? "Section" : detailFieldsLayout;
1523 string categoryFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout").SelectedValue : "Section";
1524 categoryFieldsLayout = categoryFieldsLayout == "Ribbon" || string.IsNullOrEmpty(categoryFieldsLayout) ? "Section" : categoryFieldsLayout;
1525 string downloadsFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout").SelectedValue : "Section";
1526 downloadsFieldsLayout = downloadsFieldsLayout == "Ribbon" || string.IsNullOrEmpty(downloadsFieldsLayout) ? "Section" : downloadsFieldsLayout;
1527
1528 if (GetLoop("CustomFieldValues").Count > 0 && detailFieldsLayout != "hide")
1529 {
1530 Block detailsCustom = new Block()
1531 {
1532 Name = detailFieldsLayout != "MainInformation" ? Translate("Details") : "",
1533 Id = "CustomFields",
1534 SortId = 30,
1535 Template = RenderCustomData(detailFieldsLayout),
1536 Design = new Design
1537 {
1538 Size = "12",
1539 RenderType = RenderType.Column,
1540 HidePadding = true
1541 }
1542 };
1543
1544 productFieldsPage.Add(detailFieldsLayout, detailsCustom);
1545 }
1546
1547 if (categoryFieldsLayout != "hide")
1548 {
1549 foreach (LoopItem categoryGroup in GetLoop("ProductCategories"))
1550 {
1551 bool hasFields = categoryGroup.GetLoop("ProductCategoryFields").FirstOrDefault(cf => !string.IsNullOrEmpty(cf.GetString("Ecom:Product.CategoryField.Value"))) != null;
1552 if (hasFields)
1553 {
1554 Block detailsCategoryFields = new Block()
1555 {
1556 Name = categoryFieldsLayout != "MainInformation" ? categoryGroup.GetString("Ecom:Product.Category.Name") : "",
1557 Id = ToPascalCase(categoryGroup.GetString("Ecom:Product.Category.Name")),
1558 SortId = 40,
1559 Template = RenderProductCategory(categoryGroup.GetString("Ecom:Product.Category.Name"), categoryGroup, categoryFieldsLayout),
1560 Design = new Design
1561 {
1562 Size = "12",
1563 RenderType = RenderType.Column,
1564 HidePadding = true
1565 }
1566 };
1567
1568 productFieldsPage.Add(categoryFieldsLayout, detailsCategoryFields);
1569 }
1570 }
1571 }
1572
1573 if (downloadDocuments.Count > 0 && downloadsFieldsLayout != "hide")
1574 {
1575 Block detailsDownloads = new Block()
1576 {
1577 Name = downloadsFieldsLayout != "MainInformation" ? Translate("Downloads") : "",
1578 Id = "Downloads",
1579 SortId = 50,
1580 Template = RenderProductDownloads(downloadsFieldsLayout),
1581 Design = new Design
1582 {
1583 Size = "12",
1584 RenderType = RenderType.Column,
1585 HidePadding = true
1586 }
1587 };
1588
1589 productFieldsPage.Add(downloadsFieldsLayout, detailsDownloads);
1590 }
1591 }
1592
1593 @helper RenderCustomData(string layout)
1594 {
1595 string viewType = Pageview.AreaSettings.GetItem("ProductPage").GetString("DetailFieldsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsView").SelectedValue : "grid";
1596 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "";
1597 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : "";
1598
1599 <div class="product__section @ribbonClasses dw-mod">
1600 <div class="center-container @ribbonSubClasses dw-mod">
1601 @if (layout == "Section")
1602 {
1603 <h2>@Translate("Information")</h2>
1604 }
1605
1606 @if (viewType != "table")
1607 {
1608 <div class="grid grid--external-bleed-x u-margin-bottom--lg">
1609 @RenderCustomFields(GetLoop("CustomFieldValues"), viewType)
1610 </div>
1611 }
1612 else
1613 {
1614 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12";
1615
1616 <div class="grid grid--external-bleed-x u-margin-bottom--lg">
1617 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12">
1618 <table class="table--no-top-border">
1619 @RenderCustomFields(GetLoop("CustomFieldValues"), viewType)
1620 </table>
1621 </div>
1622 </div>
1623 }
1624 </div>
1625 </div>
1626 }
1627
1628 @helper RenderCustomFields(List<LoopItem> fieldsLoop, string viewType)
1629 {
1630 var hiddenProductFieldsList = Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetList("SpHiddenProductFields");
1631
1632 foreach (LoopItem customField in fieldsLoop)
1633 {
1634 var fieldHidden = hiddenProductFieldsList.SelectedValues.Any(x => x == customField.GetString("Product.CustomField.Template"));
1635 if (!fieldHidden)
1636 {
1637
1638 string fieldValue = customField.GetString("Product.CustomField.Value.Clean");
1639 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue;
1640 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue;
1641
1642 if (customField.GetLoop("Product.CustomField.Options").Count > 0)
1643 {
1644 fieldValue = customField.GetString("Product.CustomField.Label");
1645 }
1646
1647
1648 if (
1649 !string.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) && !string.IsNullOrEmpty(fieldValue))
1650 {
1651 if (string.IsNullOrEmpty(customField.GetString("Document.FullPath")))
1652 {
1653 @RenderFieldItem(customField.GetString("Product.CustomField.Name"), fieldValue, viewType);
1654 }
1655 }
1656 }
1657 }
1658 }
1659
1660 @helper RenderProductCategory(string name, LoopItem categoryGroup, string layout)
1661 {
1662 string viewType = Pageview.AreaSettings.GetItem("ProductPage").GetString("CategoryFieldsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsView").SelectedValue : "grid";
1663 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "";
1664 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : "";
1665
1666 <div class="product__section @ribbonClasses dw-mod">
1667 <div class="center-container @ribbonSubClasses dw-mod">
1668 @if (layout == "Section")
1669 {
1670 <h2>@name</h2>
1671 }
1672
1673 @if (viewType != "table")
1674 {
1675 <div class="grid grid--external-bleed-x u-margin-bottom--lg">
1676 @RenderProductCategoryFields(categoryGroup.GetLoop("ProductCategoryFields"), viewType)
1677 </div>
1678 }
1679 else
1680 {
1681 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12";
1682
1683 <div class="grid grid--external-bleed-x u-margin-bottom--lg">
1684 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12">
1685 <table class="table--no-top-border">
1686 @RenderProductCategoryFields(categoryGroup.GetLoop("ProductCategoryFields"), viewType)
1687 </table>
1688 </div>
1689 </div>
1690 }
1691 </div>
1692 </div>
1693 }
1694
1695 @helper RenderProductCategoryFields(List<LoopItem> fieldsLoop, string viewType)
1696 {
1697 foreach (LoopItem categoryField in fieldsLoop)
1698 {
1699 string fieldValue = categoryField.GetString("Ecom:Product.CategoryField.Value");
1700 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue;
1701 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue;
1702
1703 if (!string.IsNullOrEmpty(categoryField.GetString("Ecom:Product.CategoryField.Label")) && !string.IsNullOrEmpty(fieldValue))
1704 {
1705 if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") != "9")
1706 {
1707 if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") == "15")
1708 {
1709 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), categoryField.GetString("Ecom:Product.CategoryField.OptionLabel"), viewType);
1710 }
1711 else if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") == "8")
1712 {
1713 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType, "link");
1714 }
1715 else
1716 {
1717 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType);
1718 }
1719 }
1720 }
1721 }
1722 }
1723
1724 @helper RenderProductDownloads(string layout)
1725 {
1726 string viewType = Pageview.AreaSettings.GetItem("ProductPage").GetString("DownloadsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsView").SelectedValue : "grid";
1727 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "";
1728 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : "";
1729
1730 <div class="product__section @ribbonClasses dw-mod">
1731 <div class="center-container @ribbonSubClasses dw-mod">
1732 @if (layout == "Section")
1733 {
1734 <h2>@Translate("Downloads")</h2>
1735 }
1736
1737 @if (viewType != "table")
1738 {
1739 <div class="grid grid--external-bleed-x u-margin-bottom--lg">
1740 @RenderProductDownloadsFields(downloadDocuments, viewType)
1741 </div>
1742 }
1743 else
1744 {
1745 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12";
1746
1747 <div class="grid grid--external-bleed-x u-margin-bottom--lg">
1748 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12">
1749 <table class="table--no-top-border">
1750 @RenderProductDownloadsFields(downloadDocuments, viewType)
1751 </table>
1752 </div>
1753 </div>
1754 }
1755 </div>
1756 </div>
1757 }
1758
1759 @helper RenderProductDownloadsFields(List<LoopItem> fieldsLoop, string viewType)
1760 {
1761 foreach (LoopItem document in fieldsLoop)
1762 {
1763 string fieldValue;
1764 if (!string.IsNullOrEmpty(document.GetString("Document.FullPath")))
1765 {
1766 fieldValue = document.GetString("Product.CustomField.Value.Clean");
1767 @RenderFieldItem(fieldValue, document.GetString("Document.FullPath"), viewType, "download")
1768 }
1769
1770 if (document.GetString("Ecom:Product.CategoryField.TypeID") == "9")
1771 {
1772 fieldValue = document.GetString("Ecom:Product.CategoryField.Value");
1773 @RenderFieldItem(fieldValue, fieldValue, viewType, "download")
1774 }
1775
1776 if (!string.IsNullOrEmpty(document.GetString("Ecom:Product:Detail.Image.Clean")))
1777 {
1778 fieldValue = document.GetString("Ecom:Product:Detail.Image.Clean");
1779 var fileName = System.IO.Path.GetFileName(fieldValue);
1780 @RenderFieldItem(document.GetString("Ecom:Product:Detail.Image.Clean"), document.GetString("Ecom:Product:Detail.Image.Clean"), viewType, "download")
1781 }
1782 }
1783 }
1784
1785 @helper RenderFieldItem(string name, string value, string viewType, string fieldType = "clean")
1786 {
1787 if (viewType != "table")
1788 {
1789 string fieldColumns = viewType == "list" ? "12" : "4";
1790 <div class="grid__col-md-@fieldColumns u-margin-bottom">
1791 @if (fieldType == "download")
1792 {
1793 <div>
1794 @RenderFieldItemContent(name, value, fieldType)
1795 </div>
1796 }
1797 else
1798 {
1799 <div class="u-bold">
1800 @name
1801 </div>
1802 <div>
1803 @RenderFieldItemContent(name, value, fieldType)
1804 </div>
1805 }
1806 </div>
1807 }
1808 else
1809 {
1810 <tr>
1811 @if (fieldType == "download")
1812 {
1813 <td colspan="2">
1814 @RenderFieldItemContent(name, value, fieldType)
1815 </td>
1816 }
1817 else
1818 {
1819 <td class="u-bold">@name</td>
1820 <td>
1821 @RenderFieldItemContent(name, value, fieldType)
1822 </td>
1823 }
1824 </tr>
1825 }
1826 }
1827
1828 @helper RenderFieldItemContent(string name, string value, string fieldType = "clean")
1829 {
1830 if (fieldType == "link")
1831 {
1832 <a target="_blank" href="@value">
1833 @if (isImage(value))
1834 {
1835 @getIconForFile(value)
1836 }
1837 else
1838 {
1839 @value
1840 }
1841 </a>
1842 }
1843 else if (fieldType == "download")
1844 {
1845 FileInfo info = new FileInfo(Dynamicweb.Core.SystemInformation.MapPath(value));
1846
1847 if (info.Exists)
1848 {
1849 <div class="grid grid--no-wrap">
1850 <a href="@name" download title="@Translate("Download")" class="product__document u-min-w120px u-ta-center dw-mod">@getIconForFile(value)</a>
1851 <div class="product__document-info dw-mod">
1852 <a href="@name" download title="@Translate("Download")" class="product__document dw-mod">@Path.GetFileName(value)</a>
1853 <small class="u-block u-margin-top">@ConvertBytes(info.Length)</small>
1854 </div>
1855 </div>
1856 }
1857 }
1858 else
1859 {
1860 @value
1861 }
1862 }
1863
1864 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
1865 @using Dynamicweb.Core
1866 @using System
1867 @using System.Web
1868 @using System.Collections.Generic
1869 @using Dynamicweb.Rapido.Blocks
1870 @using Smartpage.CookieManager
1871
1872 @functions{
1873 BlocksPage productVideoPage = BlocksPage.GetBlockPage("Product");
1874 }
1875
1876 @{
1877 string videosLayout = Pageview.AreaSettings.GetItem("ProductPage").GetString("VideosLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue : "Section";
1878 videosLayout = videosLayout == "Ribbon" || string.IsNullOrEmpty(videosLayout) ? "Section" : videosLayout;
1879
1880 int videosCount = 0;
1881
1882 foreach (LoopItem detailField in GetLoop("Details"))
1883 {
1884 if (detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("youtube.com/embed") != -1)
1885 {
1886 videosCount++;
1887 }
1888 if (detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("vimeo.com") != -1)
1889 {
1890 videosCount++;
1891 }
1892 }
1893
1894 if (videosCount > 0 && videosLayout != "hide")
1895 {
1896 Block detailsVideos = new Block()
1897 {
1898 Name = videosLayout != "MainInformation" ? Translate("Videos") : "",
1899 Id = "Videos",
1900 SortId = 60,
1901 Template = ProductVideos(videosCount, videosLayout),
1902 Design = new Design
1903 {
1904 Size = "12",
1905 RenderType = RenderType.Column,
1906 HidePadding = true
1907 }
1908 };
1909 productVideoPage.Add(videosLayout, detailsVideos);
1910 }
1911 }
1912
1913 @helper ProductVideos(int videosCount, string layout)
1914 {
1915 string videoColumn = "12";
1916 videoColumn = videosCount == 2 ? "6" : videoColumn;
1917 videoColumn = videosCount > 2 ? "4" : videoColumn;
1918 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "";
1919 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : "";
1920 bool showVideo = new CookieBot().Statistics;
1921
1922 <div class="product__section @ribbonClasses dw-mod">
1923 <div class="center-container @ribbonSubClasses dw-mod">
1924 @if (layout == "Section")
1925 {
1926 <h2>@Translate("Videos")</h2>
1927 }
1928
1929 <div class="grid grid--external-bleed-x u-margin-bottom--lg">
1930 @foreach (LoopItem detailField in GetLoop("Details"))
1931 {
1932 if (detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("youtube.com/embed") != -1 || detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("vimeo.com") != -1 && showVideo)
1933 {
1934 <div class="grid__col-md-@videoColumn grid__col-lg-@videoColumn">
1935 <div class="video-wrapper">
1936 @detailField.GetString("Ecom:Product:Detail.Text")
1937 </div>
1938 </div>
1939 }
1940 }
1941 </div>
1942 </div>
1943 </div>
1944 }
1945 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
1946 @using Dynamicweb.Core
1947 @using System
1948 @using System.Web
1949 @using System.Collections.Generic
1950 @using Dynamicweb.Rapido.Blocks
1951
1952 @functions{
1953 BlocksPage productRelatedPage = BlocksPage.GetBlockPage("Product");
1954 }
1955
1956 @{
1957 bool onlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
1958 bool gridViewShowViewButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetString("ShowViewButton") != null ? Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowViewButton") : true;
1959 bool gridViewShowStock = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetString("ShowStockAndShipping") != null ? Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowStockAndShipping") : true;
1960
1961 string relatedProductsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue : "Section";
1962 relatedProductsLayout = relatedProductsLayout == "Ribbon" || string.IsNullOrEmpty(relatedProductsLayout) ? "Section" : relatedProductsLayout;
1963 bool relatedOnlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
1964 bool relatedPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly");
1965
1966 int relatedProductsPageSize = 4;
1967 int relatedProductsColumnWidth = 3;
1968
1969 if (Pageview.Device.ToString() == "Mobile")
1970 {
1971 relatedProductsPageSize = 1;
1972 relatedProductsColumnWidth = 12;
1973 }
1974
1975 if (Pageview.Device.ToString() == "Tablet")
1976 {
1977 relatedProductsPageSize = 3;
1978 relatedProductsColumnWidth = 4;
1979 }
1980
1981 if (relatedProductsLayout != "hide")
1982 {
1983 foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups"))
1984 {
1985 // Replacement products - only shown if product stock is 0 and discontinued
1986 var relatedGroupReplacementGroupId = Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetList("SpReplacementProducts").SelectedValue;
1987 if (relatedGroupReplacementGroupId == relatedGroup.GetString("Ecom:Product:RelatedGroup.GroupID") && !(GetInteger("Ecom:Product.Stock") == 0 && GetBoolean("Ecom:Product:Field.Discontinued")))
1988 {
1989 continue;
1990 }
1991
1992 string relatedGroupId = ToPascalCase(relatedGroup.GetString("Ecom:Product:RelatedGroup.Name"));
1993 string SpRelatedGroupId = relatedGroup.GetString("Ecom:Product:RelatedGroup.GroupID");
1994 string relatedGroupName = relatedProductsLayout != "maininformation" ? relatedGroup.GetString("Ecom:Product:RelatedGroup.Name") : "";
1995 string baseFeedPageUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("RelatedProductsFeed") + "&PageSize=" + relatedProductsPageSize;
1996 string relatedFeed = baseFeedPageUrl + "&" + relatedGroupId + "=" + GetString("Ecom:Product.ID") + "&GroupName=" + relatedGroupId + "&feed=true";
1997
1998 Block detailsRelated = new Block()
1999 {
2000 Name = relatedGroupName,
2001 Id = relatedGroupId,
2002 SortId = 70,
2003 Template = RenderRelatedProducts(relatedGroupName, relatedGroupId, relatedFeed, relatedProductsLayout, SpRelatedGroupId),
2004 Design = new Design
2005 {
2006 Size = "12",
2007 RenderType = RenderType.Column,
2008 HidePadding = true
2009 }
2010 };
2011
2012 productRelatedPage.Add(relatedProductsLayout, detailsRelated);
2013 }
2014 }
2015 }
2016
2017 @helper RenderRelatedProducts(string name, string groupName, string relatedFeedUrl, string layout, string GroupID)
2018 {
2019 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "";
2020 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : "";
2021 var alternativeProductsGroupId = Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetList("SpAlternativeProducts").SelectedValue;
2022 var replacementProductsGroupId = Pageview.AreaSettings.GetItem("Custom").GetItem("CustomSettings").GetList("SpReplacementProducts").SelectedValue;
2023
2024
2025
2026 if (alternativeProductsGroupId != GroupID && replacementProductsGroupId != GroupID)
2027 {
2028 <div class="product__section @ribbonClasses dw-mod">
2029 <div class="center-container @ribbonSubClasses dw-mod">
2030 @if (layout == "Section")
2031 {
2032 <h2 class="u-bold u-ta-center">@name</h2>
2033 }
2034
2035 <div class="js-handlebars-root" id="ProductList_@groupName" data-template="ProductContainer" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedFeedUrl" data-preloader="minimal"></div>
2036 </div>
2037 </div>
2038 }
2039
2040 }
2041
2042 @helper RenderRelatedProductsMini(string name, string groupId, string relatedFeedUrl)
2043 {
2044 <div class="js-handlebars-root" id="ProductList_@groupId" data-template="ProductContainerMini" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedFeedUrl" data-preloader="minimal"></div>
2045 }
2046
2047 @* Script templates for related products *@
2048 <script id="ProductPreRenderContainer" type="text/x-template">
2049 <div class="u-h600px u-full-width">
2050 <div class="grid">
2051 <div class="grid__col-12">
2052 <div class="pre-render-element pre-render-element--md"></div>
2053 </div>
2054 </div>
2055 </div>
2056 </script>
2057
2058 <script id="ProductContainer" type="text/x-template">
2059 {{#.}}
2060 <div class="u-full-width">
2061 <div class="grid">
2062 <div class="grid__col-45px grid__col--bleed-x">
2063 <div class="grid__cell grid__cell--align-middle-left">
2064 <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>
2065 </div>
2066 </div>
2067 <div class="grid__col-auto grid__col--bleed-x">
2068 <div id="ProductsContainer" data-template="ProductGridItemContainer" class="grid product-list dw-mod" data-save-cookie="true">
2069 {{#ProductsContainer}}
2070 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__grid-item dw-mod">
2071 {{#Product}}
2072 @if (useGoogleTagManager)
2073 {
2074 <text>{{{googleEnchantImpression 'Related products' currency googleImpression}}}</text>
2075 }
2076 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}">
2077 <div class="stickers-container dw-mod">
2078 {{#Stickers}}
2079 {{>Sticker}}
2080 {{/Stickers}}
2081 </div>
2082 <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&image={{image}}" alt="{{name}}" /></a>
2083 </div>
2084
2085 <div class="grid__cell product-list__grid-item__price-info related-price-info {{shortGridInfo}} dw-mod">
2086 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6 class="u-condensed-text">{{name}}</h6></a>
2087 {{#if showProductNumber}}
2088 <div class="item-number dw-mod">{{number}}</div>
2089 {{/if}}
2090 @if (!relatedOnlyPreview)
2091 {
2092 if (relatedPointShopOnly)
2093 {
2094 <text>
2095 {{#if havePointPrice}}
2096 <div>{{points}} @Translate("points")</div>
2097 {{else}}
2098 @Translate("Not available")
2099 {{/if}}
2100 </text>
2101 }
2102 else
2103 {
2104 <text>
2105 <div class="price price--product-list dw-mod">{{price}}</div>
2106 <div class="before-price {{onSale}} dw-mod">{{discount}}</div>
2107 {{#if standardOrderQuantity}}
2108 <div>@Translate("Kolli"): {{standardOrderQuantity}}</div>
2109 {{/if}}
2110 </text>
2111 }
2112 }
2113 </div>
2114
2115 <div class="product-list__grid-item__footer dw-mod">
2116
2117 @if (gridViewShowViewButton)
2118 {
2119 <div class="u-ta-center">
2120 <a href="{{link}}" id="CartButton_{{id}}" class="btn btn--primary btn--arrow btn--full u-no-margin dw-mod">@Translate("View")</a>
2121 </div>
2122 }
2123
2124 @if (!onlyPreview && gridViewShowStock)
2125 {
2126 <div>
2127 <span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span> {{stockText}}{{deliveryText}}
2128 </div>
2129 }
2130
2131 </div>
2132 {{/Product}}
2133 </div>
2134 {{/ProductsContainer}}
2135 </div>
2136 </div>
2137 <div class="grid__col-45px grid__col--bleed-x">
2138 <div class="grid__cell grid__cell--align-middle-right">
2139 <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>
2140 </div>
2141 </div>
2142 </div>
2143 </div>
2144 {{/.}}
2145 </script>
2146
2147 <script id="ProductContainerMini" type="text/x-template">
2148 {{#.}}
2149 <div class="u-full-width">
2150 <div class="grid">
2151 <div class="grid__col-45px grid__col--bleed-x">
2152 <div class="grid__cell grid__cell--align-middle-left">
2153 <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>
2154 </div>
2155 </div>
2156 <div class="grid__col-auto grid__col--bleed-x">
2157 <div id="ProductsContainer" class="grid product-list dw-mod">
2158 {{#ProductsContainer}}
2159 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__grid-item dw-mod">
2160 {{#Product}}
2161 @if (useGoogleTagManager)
2162 {
2163 <text>{{{googleEnchantImpression 'Related products' currency googleImpression}}}</text>
2164 }
2165 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}">
2166 <div class="stickers-container dw-mod">
2167 {{#Stickers}}
2168 {{>Sticker}}
2169 {{/Stickers}}
2170 </div>
2171 <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>
2172 </div>
2173
2174 <div class="grid__cell product-list__grid-item__price-info {{shortGridInfo}} dw-mod">
2175 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6 class="u-condensed-text">{{name}}</h6></a>
2176 {{#if showProductNumber}}
2177 <div class="item-number dw-mod">{{number}}</div>
2178 {{/if}}
2179 @if (!relatedOnlyPreview)
2180 {
2181 if (relatedPointShopOnly)
2182 {
2183 <text>
2184 {{#if havePointPrice}}
2185 <div>{{points}} @Translate("points")</div>
2186 {{else}}
2187 @Translate("Not available")
2188 {{/if}}
2189 </text>
2190 }
2191 else
2192 {
2193 <div>{{price}}</div>
2194 <div class="before-price {{onSale}} dw-mod">{{discount}}</div>
2195 }
2196 }
2197 </div>
2198 {{/Product}}
2199 </div>
2200 {{/ProductsContainer}}
2201 </div>
2202 </div>
2203 <div class="grid__col-45px grid__col--bleed-x">
2204 <div class="grid__cell grid__cell--align-middle-right">
2205 <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>
2206 </div>
2207 </div>
2208 </div>
2209 </div>
2210 {{/.}}
2211 </script>
2212
2213 <script id="Sticker" type="text/x-template">
2214 <div class="stickers-container__tag {{className}} dw-mod">{{text}}</div>
2215 </script>
2216
2217 @* Favorites templates *@
2218
2219 <script id="FavoriteTemplate" type="text/x-template">
2220 <div class="favorites-list u-ta-left">
2221 <label for="FavoriteTrigger_{{id}}" class="u-no-margin"><i class="{{favoriteIcon}} fa-1_5x"></i></label>
2222 <input type="checkbox" id="FavoriteTrigger_{{id}}" class="dropdown-trigger" />
2223 <div class="dropdown dropdown--absolute-position">
2224 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod">
2225 <ul class="list list--clean dw-mod">
2226 {{#FavoriteLists}}
2227 {{>FavoriteListItem}}
2228 {{/FavoriteLists}}
2229 </ul>
2230 </div>
2231 <label class="dropdown-trigger-off" for="FavoriteTrigger_{{id}}"></label>
2232 </div>
2233 </div>
2234 </script>
2235
2236 <script id="FavoriteListItem" type="text/x-template">
2237 <li>
2238 <a href="{{link}}" class="list__link u-no-underline dw-mod" onclick="{{facebookPixelAction}}"><i class="{{favoriteIcon}}"></i> {{name}}</a>
2239 </li>
2240 </script>
2241 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
2242 @using Dynamicweb.Core
2243 @using System
2244 @using System.Web
2245 @using System.Collections.Generic
2246 @using Dynamicweb.Rapido.Blocks
2247
2248 @functions {
2249 BlocksPage productVariantsPage = BlocksPage.GetBlockPage("Product");
2250 }
2251
2252 @{
2253 bool renderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetString("RenderVariantsAsProductList") != null && GetInteger("Ecom:Product.VariantCount") > 1 ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList") : false;
2254 bool variantsOnlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
2255 string variantsListPageSize = HttpContext.Current.Request.QueryString.Get("PageSize") != null ? HttpContext.Current.Request.QueryString.Get("PageSize") : "30";
2256 string variantsFeedUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + variantsListPageSize + "&MainProductID=" + GetString("Ecom:Product.ID") + "&OnlyShowVariants=true&feed=true";
2257 string variantsCartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetString("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart";
2258 bool variantsPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly");
2259
2260 string variantsListLayout = Pageview.AreaSettings.GetItem("ProductPage").GetString("VariantsListLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue : "Section";
2261 variantsListLayout = variantsListLayout == "Ribbon" ? "Section" : variantsListLayout;
2262
2263
2264 if (renderVariantsAsProducts && variantsListLayout != "hide")
2265 {
2266 Block detailsVariantsList = new Block()
2267 {
2268 Name = variantsListLayout != "MainInformation" ? Translate("Variants list") : "",
2269 Id = "VariantsList",
2270 SortId = 20,
2271 Template = RenderVariantsProductList(variantsListLayout),
2272 Design = new Design
2273 {
2274 Size = "12",
2275 RenderType = RenderType.Column,
2276 HidePadding = true
2277 }
2278 };
2279 productVariantsPage.Add(variantsListLayout, detailsVariantsList);
2280 }
2281 }
2282
2283 @helper RenderVariantsProductList(string layout)
2284 {
2285 string variantsListPageSize = HttpContext.Current.Request.QueryString.Get("PageSize") != null ? HttpContext.Current.Request.QueryString.Get("PageSize") : "30";
2286 string variantsFeedUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + variantsListPageSize + "&MainProductID=" + GetString("Ecom:Product.ID") + "&OnlyShowVariants=true&feed=true";
2287 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "";
2288 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : "";
2289
2290 <div class="product__section @ribbonClasses dw-mod">
2291 <div class="center-container @ribbonSubClasses dw-mod">
2292 @if (layout == "Section") {
2293 <h2>@Translate("Variants")</h2>
2294 }
2295
2296 <div class="js-handlebars-root" id="VariantsListRoot" data-template="VariantProductsContainer" data-json-feed="@variantsFeedUrl" data-preloader="minimal"></div>
2297 </div>
2298 </div>
2299 }
2300
2301
2302 @* Script templates for variant products *@
2303
2304 <script id="VariantProductsContainer" type="text/x-template">
2305 {{#.}}
2306 <div class="">
2307 <table id="VariantsProductsContainer" class="table u-position-relative dw-mod">
2308 <thead>
2309 <tr>
2310 <td width="75"> </td>
2311 <td>@Translate("Product")</td>
2312 {{#AvailableCustomFields}}
2313 {{>TableFieldNameTemplate}}
2314 {{/AvailableCustomFields}}
2315 @if (Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantGroupsInTable")) {
2316 foreach (LoopItem variantgroup in GetLoop("VariantGroups"))
2317 {
2318 <td>@variantgroup.GetString("Ecom:VariantGroup.Name")</td>
2319 }
2320 }
2321 <td width="360"> </td>
2322 </tr>
2323 </thead>
2324
2325 <tbody id="VariantProductListContainer" data-template="VariantProductItemContainer" data-save-cookie="true">
2326 {{#ProductsContainer}}
2327 {{>VariantProductItemContainer}}
2328 {{/ProductsContainer}}
2329 </tbody>
2330 </table>
2331 </div>
2332
2333 <div class="grid">
2334 <div class="grid__col-12 grid__col--bleed-y">
2335 <button type="button" id="LoadMoreButton" class="btn btn--primary 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>
2336 </div>
2337 </div>
2338 {{/.}}
2339 </script>
2340
2341 <script id="VariantProductItemContainer" type="text/x-template">
2342 {{#.}}
2343 <tr id="VariantProduct{{id}}" data-template="VariantProductItem" data-preloader="overlay" style="z-index: {{zIndex}}">
2344 {{#Product}}
2345 {{>VariantProductItem}}
2346 {{/Product}}
2347 </tr>
2348 {{/.}}
2349 </script>
2350
2351 <script id="VariantProductItem" type="text/x-template">
2352 {{#.}}
2353 <td width="75">
2354 <div class="lightbox u-hidden-xxs">
2355 <a href="{{link}}" onclick="Scroll.SavePosition(event)">
2356 <img class="lightbox__image {{noImage}}" src="/Admin/Public/GetImage.ashx?width=220&height=220&crop=5&Compression=75&image={{image}}" alt="{{name}}" />
2357 <div class="u-margin-right {{noImage}}">
2358 <img src="/Admin/Public/GetImage.ashx?width=75&height=55&crop=5&FillCanvas=true&Compression=75&image={{image}}" alt="{{name}}" />
2359 </div>
2360 </a>
2361 </div>
2362 </td>
2363 <td class="u-va-middle">
2364 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6 class="u-no-margin">{{name}}</h6></a>
2365 <div class="item-number item-number--compressed dw-mod">
2366 {{#if showProductNumber}}{{number}}{{/if}}
2367 @if (!variantsOnlyPreview)
2368 {
2369 <span>
2370 <span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span> {{stockText}}{{deliveryText}}
2371 </span>
2372 }
2373 else
2374 {
2375 <div class="grid__cell-footer stickers-container stickers-container--block dw-mod">
2376 {{#Stickers}}
2377 {{>MiniSticker}}
2378 {{/Stickers}}
2379 </div>
2380 }
2381 </div>
2382 </td>
2383 {{#CustomFields}}
2384 {{>TableFieldValueTemplate}}
2385 {{/CustomFields}}
2386 @if (Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantGroupsInTable"))
2387 {
2388 <text>
2389 {{#VariantSelectionNames}}
2390 {{>TableFieldNameTemplate}}
2391 {{/VariantSelectionNames}}
2392 </text>
2393 }
2394 <td width="320" class="u-va-middle">
2395 @if (variantsOnlyPreview)
2396 {
2397 <div class="u-hidden-sm">
2398 <div class="u-full-width u-ta-right u-padding-right">
2399 <div class="before-price {{onSale}} before-price--micro dw-mod">{{discount}}</div>
2400 <div class="price price--product-list price--micro dw-mod">{{price}}</div>
2401 </div>
2402 </div>
2403 }
2404 else
2405 {
2406 <div class="grid grid--align-center grid--justify-end">
2407 <div class="favorites u-margin-right {{hasVariants}} dw-mod" {{hasVariants}}>
2408 {{#Favorite}}
2409 {{>FavoriteTemplate}}
2410 {{/Favorite}}
2411 </div>
2412 <div class="u-margin-right">
2413 <input type="checkbox" id="UnitOptions_{{id}}" class="dropdown-trigger" />
2414 <div class="dropdown u-w120px {{hasUnits}} dw-mod">
2415 <label class="dropdown__header dropdown__btn dw-mod" for="UnitOptions_{{id}}">{{unitName}}</label>
2416 <div id="unitOptions" class="dropdown__content dw-mod">
2417 {{#unitOptions}}
2418 {{>UnitOption}}
2419 {{/unitOptions}}
2420 </div>
2421 <label class="dropdown-trigger-off" for="UnitOptions_{{id}}"></label>
2422 </div>
2423 <input type="hidden" value="{{unitId}}" name="Unit{{id}}" id="Unit_{{id}}" />
2424 <input type="hidden" value="{{variantid}}" name="VariantID{{id}}" id="Variant_{{id}}" />
2425 </div>
2426 <div class="u-margin-right u-hidden-xs u-hidden-xxs">
2427 @if (variantsPointShopOnly)
2428 {
2429 <text>
2430 {{#if canBePurchasedWithPoints}}
2431 <div class="price price--product-list price--micro dw-mod">{{points}} @Translate("points")</div>
2432 {{else}}
2433 {{#if havePointPrice}}
2434 <small class="help-text u-no-margin u-margin-top">@Translate("Not enough points to buy this")</small>
2435 {{else}}
2436 <small class="help-text u-no-margin u-margin-top">@Translate("Not available")</small>
2437 {{/if}}
2438 {{/if}}
2439 </text>
2440 }
2441 else
2442 {
2443 <div class="before-price before-price--micro {{onSale}} dw-mod">{{discount}}</div>
2444 <div class="price price--condensed price--product-list dw-mod">{{price}}</div>
2445 }
2446 </div>
2447 @if (variantsPointShopOnly)
2448 {
2449 <div>
2450 <button {{#unless canBePurchasedWithPoints}} disabled{{/unless}} type="button"
2451 id="CartButton_{{id}}"
2452 class="btn btn--primary btn--condensed u-no-margin dw-mod js-cart-btn {{#unless canBePurchasedWithPoints}}disabled js-stay-disabled{{/unless}}"
2453 name="CartCmd"
2454 value="addWithPoints"
2455 onclick="Cart.AddToCart(event, {
2456 id: '{{productId}}',
2457 variantId: '{{variantid}}',
2458 unitId: '{{unitId}}',
2459 quantity: 1,
2460 buyForPoints: true,
2461 productInfo: {{productInfo}}
2462 })">
2463 <i class="@variantsCartIcon"></i>
2464 </button>
2465 </div>
2466 }
2467 else
2468 {
2469 <div>
2470 <input type="number" class="u-w80px u-no-margin u-margin-right" id="Quantity_{{id}}" name="Quantity{{id}}" value="1" min="1">
2471 </div>
2472 <div>
2473 <button type="button" id="CartButton_{{id}}" class="btn btn--primary btn--condensed u-no-margin dw-mod" name="submit"
2474 onclick="Cart.AddToCart(event, {
2475 id: '{{productId}}',
2476 variantId: '{{variantid}}',
2477 unitId: '{{unitId}}',
2478 quantity: document.getElementById('Quantity_{{id}}').value,
2479 productInfo: {{productInfo}}
2480 });">
2481 <i class="@variantsCartIcon"></i>
2482 </button>
2483 </div>
2484 }
2485 </div>
2486 }
2487 </td>
2488 {{/.}}
2489 </script>
2490
2491 <script id="TableFieldNameTemplate" type="text/x-template">
2492 <td class="u-va-middle">{{name}}</td>
2493 </script>
2494
2495 <script id="TableFieldValueTemplate" type="text/x-template">
2496 <td class="u-va-middle">{{value}}</td>
2497 </script>
2498
2499 <script id="MiniSticker" type="text/x-template">
2500 <div class="stickers-container__tag stickers-container__tag--micro {{className}} dw-mod">{{text}}</div>
2501 </script>
2502 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
2503 @using Dynamicweb.Core
2504 @using System
2505 @using System.Web
2506 @using System.Collections.Generic
2507 @using Dynamicweb.Rapido.Blocks
2508
2509 @{
2510 BlocksPage customProductBlocks = BlocksPage.GetBlockPage("Product");
2511
2512 customProductBlocks.Add("MainInformation", new Block()
2513 {
2514 Id = "ProductConcepts",
2515 SortId = 35,
2516 Template = RenderProductConceptsCustom()
2517 });
2518 }
2519
2520 @helper RenderProductConceptsCustom()
2521 {
2522 // note: don't include .introduction-concepts element, if product concepts is not used or empty.
2523 var concepts = GetLoop("Smartpage:Product.ConceptLoop");
2524 if (concepts.Any())
2525 {
2526 <div class="introduction-concepts">
2527 @foreach (var concept in concepts)
2528 {
2529 if(!string.IsNullOrEmpty(concept.GetString("Concept"))){
2530
2531 <a href="/Default.aspx?ID=@concept.GetString("PageId")" class="btn btn--primary dw-mod">
2532 <i class="fac fa-book"></i><span>@concept.GetString("Concept")</span><i class="fa fa-angle-right u-inline"></i>
2533 </a>
2534 }
2535 }
2536 </div>
2537 }
2538 }
2539
2540 <script id="PriceList" type="text/x-template">
2541 {{#if Prices}}
2542 {{#ifCond variantSelected "!==" "False"}}
2543 <div class="priceList__prices dw-mod">
2544 {{#Prices}}
2545 <div class="priceList__price dw-mod">
2546 <div>
2547 <span>{{Quantity}}x {{UnitText}}</span>
2548 </div>
2549 <div>
2550 <div class="before-price {{onSale}} dw-mod">{{PriceBeforeDiscount}}</div>
2551 <div class="price price--product-list dw-mod">{{PriceAfterDiscount}}</div>
2552 </div>
2553 </div>
2554 {{/Prices}}
2555 </div>
2556 {{/ifCond}}
2557 {{/if}}
2558 </script>
2559
2560
2561
2562 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
2563
2564 @using Dynamicweb.Rapido.Blocks
2565
2566 @{
2567 BlocksPage productsPageRaptor = BlocksPage.GetBlockPage("Product");
2568
2569 string relatedProductsLayoutRaptor = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue : "Section";
2570 relatedProductsLayoutRaptor = relatedProductsLayoutRaptor == "Ribbon" || string.IsNullOrEmpty(relatedProductsLayoutRaptor) ? "Section" : relatedProductsLayoutRaptor;
2571
2572 if (relatedProductsLayoutRaptor != "hide")
2573 {
2574 productsPageRaptor.Add(relatedProductsLayout, new Block()
2575 {
2576 Id = "RaptorRelated",
2577 Name = "RaptorRelated",
2578 SortId = 10,
2579 Template = RenderRaptorRelatedItems()
2580 });
2581 }
2582 }
2583
2584 @helper RenderRaptorRelatedItems()
2585 {
2586 bool onlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
2587 bool hideRecommendations = !string.IsNullOrWhiteSpace(Dynamicweb.Context.Current.Request.QueryString["ListID"]) || !string.IsNullOrWhiteSpace(Dynamicweb.Context.Current.Request.QueryString["Search"]);
2588 var uri = Dynamicweb.Context.Current.Request.Url;
2589
2590 var url = uri.AbsoluteUri;
2591 if (url.Contains("ID"))
2592 {
2593 url += "&feed=true";
2594 }
2595 else
2596 {
2597 url += "?feed=true";
2598 }
2599
2600 <div class="grid grid--external-bleed grid--align-content-start js-handlebars-root" id="productList" data-template="RecommendationContainer" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@url" data-preloader="overlay"></div>
2601
2602 <script id="RecommendationContainer" type="text/x-template">
2603 @if (!hideRecommendations)
2604 {
2605 <text>
2606 {{RecommendedProducts.length}}
2607 {{#.}}
2608 {{#ifCond RecommendedProducts.length ">" "0"}}
2609 <div class="grid reccomendations">
2610 <span class="u-bold u-ta-center reccomendation-header">@Translate("Recommendations")</span>
2611 {{#RecommendedProducts}}
2612 {{>RecommendationContainerItem}}
2613 {{/RecommendedProducts}}
2614 </div>
2615 {{/ifCond}}
2616 {{/.}}
2617 </text>
2618 }
2619 </script>
2620
2621 <script id="RecommendationContainerItem" type="text/x-template">
2622
2623 <div class="reccomendation grid__col-sm-2 grid__col-xs-12 dw-mod">
2624 <div id="RecommendProductProduct{{id}}" class="reccomendation-container product-list__grid-item dw-mod js-product recommended-product">
2625 <input type="hidden" name="ProductLoopCounter{{id}}" value="{{id}}">
2626 <input type="hidden" name="ProductID{{id}}" value="{{productId}}">
2627 <input type="hidden" value="" name="VariantID{{id}}" id="RecommendVariant_{{id}}">
2628
2629 <div class="grid__cell-footer stickers-container dw-mod">
2630 {{#Stickers}}
2631 {{>MiniStickerRelated}}
2632 {{/Stickers}}
2633 </div>
2634
2635 <div class="reccomendation-image grid__cell product-list__grid-item__image dw-mod ">
2636 <a href="{{link}}" onclick="Scroll.SavePosition(event);" title="{{name}}">
2637 <img class="grid__cell-img--centered u-padding b-lazy b-loaded" src="/Admin/Public/GetImage.ashx?width=300&height=300&crop=5&Compression=75&FillCanvas=true&DoNotUpscale=true&image={{image}}" alt="{{name}}">
2638 </a>
2639 </div>
2640
2641 <div class="reccomendation-price-info grid__cell product-list__grid-item__price-info dw-mod">
2642 <a href="{{link}}" onclick="Scroll.SavePosition(event);" title="{{name}}">
2643 <h6 class="u-condensed-text">{{name}}</h6>
2644 </a>
2645 <div class="item-number dw-mod">{{number}}</div>
2646 @if (!onlyPreview)
2647 {
2648 <div class="{{hideBuyOptions}}">
2649 <div class="price price--product-list dw-mod">{{price}} {{unitName}}</div>
2650 <div class="before-price u-hidden dw-mod"></div>
2651 {{#if standardOrderQuantity}}
2652 <div>@Translate("Kolli"): {{standardOrderQuantity}}</div>
2653 {{/if}}
2654 <input type="hidden" value="" name="Unit{{id}}" id="RecommendUnit_{{id}}">
2655 </div>
2656 }
2657 </div>
2658
2659 <div class="reccomendation-footer product-list__grid-item__footer dw-mod">
2660 <div class="u-ta-center u-inline-block u-margin-top">
2661 @if (onlyPreview)
2662 {
2663 <a href="{{link}}" class="btn btn--primary btn--arrow btn--full u-no-margin dw-mod">@Translate("View")</a>
2664 }
2665 else
2666 {
2667 <div class="buttons-collection {{hideBuyOptions}}">
2668 <button type="button" id="RecommendCartButton_{{id}}" class="js-cart-btn btn btn--primary btn--condensed u-pull--right dw-mod " name="submit" onclick="Cart.AddToCart(event, {
2669 id: '{{productId}}',
2670 variantId: '{{variantId}}',
2671 unitId: '{{unitID}}',
2672 loopId: '{{id}}',
2673 quantity: document.getElementById('RecommendQuantity_{{id}}').value,
2674 productInfo: {{productInfo}},
2675 multiplum: {{multiplum}},
2676 multiplumUnitId: '{{ProductDefaultUnitId}}',
2677 standardOrderQuantity:{{standardOrderQuantity}},
2678 quantityElementId: 'RecommendQuantity_{{id}}'
2679 }); ">
2680 <i class="fas fa-shopping-cart"></i><span class="u-hidden-xs u-hidden-xxs"></span>
2681 </button>
2682
2683 <input type="number" class="u-w80px u-pull--right" id="RecommendQuantity_{{id}}" name="Quantity{{id}}" value="1" min="1">
2684
2685 </div>
2686 }
2687 </div>
2688
2689 @if (!onlyPreview)
2690 {
2691 <div class="u-ta-center u-hidden">
2692 <a href="{{link}}" id="CartButton_{{id}}" class="btn btn--primary btn--full btn--arrow u-no-margin dw-mod" onclick="Scroll.SavePosition(event); {{googleImpressionClick}}" title="@Translate("View more")">@Translate("View more")</a>
2693 </div>
2694 <div>
2695 <span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span> {{stockText}}{{deliveryText}}
2696 </div>
2697 }
2698
2699 </div>
2700 </div>
2701 </div>
2702
2703
2704 </script>
2705
2706 <script id="MiniStickerRelated" type="text/x-template">
2707 <div class="stickers-container__tag stickers-container__tag--micro {{className}} dw-mod">{{text}}</div>
2708 </script>
2709 }
2710
2711 @*@helper RenderStockAndShipping(LoopItem loopItem)
2712 {
2713 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideStockState") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState") : false;
2714 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetString("HideShipping") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping") : false;
2715 bool onlyPreview = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("OnlyPreviewForAnonymous") && Pageview.User == null;
2716
2717 var stockState = renderStockState(loopItem);
2718 var stockText = renderStockText(loopItem);
2719 var deliveryText = string.IsNullOrEmpty(loopItem.GetString("Ecom:Product:Stock.DeliveryText")) ? "" : ", " + Translate("Delivery") + " " + loopItem.GetString("Ecom:Product:Stock.DeliveryText") + " " + loopItem.GetString("Ecom:Product:Stock.DeliveryUnit");
2720
2721 if (!onlyPreview && (!string.IsNullOrEmpty(stockState) || !string.IsNullOrEmpty(deliveryText)))
2722 {
2723 <div>
2724 @if (!hideStockState)
2725 {
2726 <span class="stock-icon @stockState u-no-margin dw-mod" title="@stockText"></span> @stockText@deliveryText
2727 }
2728
2729 @if (!string.IsNullOrEmpty(deliveryText) && !hideDelivery)
2730 {
2731 @deliveryText
2732 }
2733 </div>
2734 }
2735 }*@
2736
2737 <div class="product__info dw-mod u-margin-bottom--lg js-product">
2738 <div class="grid grid--align-content-start">
2739 @* The @RenderBlockList base helper is included in Components/GridBuilder.cshtml *@
2740 @RenderBlockList(productsPage.BlocksRoot.BlocksList)
2741 </div>
2742 </div>
2743
2744 @helper RenderProductMiniTabs()
2745 {
2746 List<Block> subBlocks = productsPage.GetBlockListById("MiniTabs").OrderBy(item => item.SortId).ToList();
2747
2748 if (subBlocks.Count > 0)
2749 {
2750 <div class="grid__col-12 product__info tabs u-no-padding u-margin-bottom--lg dw-mod">
2751 @{
2752 bool firstTab = true;
2753 foreach (Block item in subBlocks)
2754 {
2755 string isChecked = firstTab ? "checked" : "";
2756 firstTab = false;
2757
2758 <input type="radio" class="tabs__trigger" name="productMiniTabs" id="@item.Id" onchange="bLazy.revalidate()" @isChecked />
2759 }
2760 }
2761
2762 <div class="tabs__list dw-mod">
2763 @foreach (Block item in subBlocks)
2764 {
2765 <label for="@item.Id" class="tabs__label dw-mod">@item.Name</label>
2766 }
2767 </div>
2768
2769 <div class="tabs__blocks dw-mod">
2770 @foreach (Block item in subBlocks)
2771 {
2772 string hidePadding = item.Design.HidePadding ? "u-no-padding" : "";
2773
2774 if (item.Design.RenderType != RenderType.Hide)
2775 {
2776 <div class="tabs__block u-border dw-mod" id="Block__@item.Id">
2777 <block class="product__block paragraph-container product__block--bordered dw-mod">
2778 <div class="center-container u-padding--lg dw-mod">
2779 @RenderBlock(item)
2780 </div>
2781 </block>
2782 </div>
2783 }
2784 }
2785 </div>
2786 </div>
2787 }
2788 }
2789
2790 @helper RenderProductTabs()
2791 {
2792 List<Block> subBlocks = productsPage.GetBlockListById("Tabs").OrderBy(item => item.SortId).ToList();
2793
2794 <div class="grid__col-12 product__info tabs u-no-padding dw-mod">
2795 @{
2796 bool firstTab = true;
2797 foreach (Block item in subBlocks)
2798 {
2799 string isChecked = firstTab ? "checked" : "";
2800 firstTab = false;
2801
2802 <input type="radio" class="tabs__trigger" name="productTabs" id="@item.Id" onchange="bLazy.revalidate()" @isChecked />
2803 }
2804 }
2805
2806 <div class="tabs__list dw-mod">
2807 @foreach (Block item in subBlocks)
2808 {
2809 <label for="@item.Id" class="tabs__label dw-mod">@item.Name</label>
2810 }
2811 </div>
2812
2813 <div class="tabs__blocks dw-mod">
2814 @foreach (Block item in subBlocks)
2815 {
2816 string hidePadding = item.Design.HidePadding ? "u-no-padding" : "";
2817
2818 if (item.Design.RenderType != RenderType.Hide)
2819 {
2820 <div class="tabs__block dw-mod" id="Block__@item.Id">
2821 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod">
2822 <div class="center-container u-padding--lg dw-mod">
2823 @RenderBlock(item)
2824 </div>
2825 </section>
2826 </div>
2827 }
2828 }
2829 </div>
2830 </div>
2831 }