• Gratis fragt!
  • 100% tilfredshedsgaranti
Har du brug for hjælp eller vejledning? +45 70226888
Error executing template "Designs/Rapido/eCom/ProductCatalog/SpProduct.cshtml"
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator.MoveNext()
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountService.InitializeLookup()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountService.GetDiscounts(DiscountApplyType[] discountTypes, String[] productKeys, Int32 userId, ICollection`1 groupIds, String customerNumber)
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountService.GetDiscounts(DiscountApplyType discountType, Product product, User user)
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountInfoCollection.LoadDiscounts(User user)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetDiscountInfo(PriceViewModelSettings settings, Product product)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine._Closure$__1-2._Lambda$__29()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine._Closure$__1-2._Lambda$__30()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at CompiledRazorTemplates.Dynamic.RazorEngine_edb5c47e47d44c0a8e2c95281296bb60.Execute() in C:\Dynamicweb.Net\Solutions\Philipson Wine\Files\Templates\Designs\Rapido\eCom\ProductCatalog\SpProduct.cshtml:line 3770
   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.b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits ViewModelTemplate<ProductViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Rendering 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.Ecommerce 13 @using Dynamicweb.Content.Commenting 14 @using Dynamicweb.Rapido.Blocks.Components.General 15 @using Dynamicweb.Rapido.Blocks 16 @using System.Linq 17 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 18 19 20 @functions { 21 22 BlocksPage productsPage = BlocksPage.GetBlockPage("Product"); 23 24 public static string ToPascalCase(string str) 25 { 26 return CultureInfo.InvariantCulture.TextInfo 27 .ToTitleCase(str.ToLowerInvariant()) 28 .Replace("-", "") 29 .Replace("_", "") 30 .Replace(" ", ""); 31 } 32 33 bool eventProduct = false; 34 } 35 36 @{ 37 38 string productBlocksPosition = Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "thumbs-image-info"; 39 bool productInfoOnTheRight = productBlocksPosition.LastIndexOf("info") == productBlocksPosition.Length - 4; 40 41 Pageview.Meta.Title = Model.Name; 42 43 ProductInformation productFields = new ProductInformation(Model); 44 eventProduct = productFields.ProductType == Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("EventProductType") ? true : false; 45 46 Block productTop = new Block() 47 { 48 Id = "Top", 49 SortId = 10, 50 SkipRenderBlocksList = true, 51 Template = RenderProductTop() 52 }; 53 productsPage.Add(productTop); 54 55 Block productMainInfo = new Block() 56 { 57 Id = "MainInformation", 58 SortId = productInfoOnTheRight ? 20 : 10, 59 Design = new Design 60 { 61 Size = "auto", 62 RenderType = RenderType.Column 63 } 64 }; 65 productsPage.Add("Top", productMainInfo); 66 67 Block productAddToCartSection = new Block() 68 { 69 Id = "AddToCartSection", 70 SortId = 30 71 }; 72 productsPage.Add("Top", productAddToCartSection); 73 74 Block productAttributeIconsSection = new Block() 75 { 76 Id = "AttributeIcons", 77 SortId = 31 78 }; 79 productsPage.Add(productAttributeIconsSection); 80 81 // Product details section 82 List<Block> productDetails = new List<Block>(); 83 84 Block descriptionSectionBlock = new Block() 85 { 86 Id = "DescriptionSection", 87 SortId = 32, 88 Template = RenderDescription("DescriptionSection") 89 }; 90 91 // Only render if we have a long description 92 if (!string.IsNullOrWhiteSpace(Model.LongDescription)) 93 { 94 productDetails.Add(descriptionSectionBlock); 95 } 96 97 var comments = Dynamicweb.Content.Commenting.Comment.GetComments("ecomProduct", Model.Id, Model.LanguageId); 98 var activeComments = comments.Where(i => i.Active == true).OrderByDescending(i => i.Rating).ThenBy(i => i.CreatedDate); 99 100 if (activeComments.Any() && !eventProduct) 101 { 102 Block customerRatingBlock = new Block() 103 { 104 Id = "CustomerRating", 105 SortId = 35, 106 Template = RenderCustomerRatings(comments, activeComments, "CustomerRating") 107 }; 108 109 productDetails.Add(customerRatingBlock); 110 } 111 112 //Expert rating 113 var expertRatings = Smartpage.PhilipsonWine.Ratings.Controller.ProductRatings.GetRatingProduct(Model.Id); 114 115 Block expertSectionBlock = new Block() 116 { 117 Id = "ExpertSection", 118 SortId = 33, 119 Template = RenderExpertRatings(expertRatings, "ExpertSection") 120 }; 121 122 if (expertRatings.Any() && !eventProduct) 123 { 124 productDetails.Add(expertSectionBlock); 125 } 126 127 var producerId = new ProductInformation(Model).ProducerId; 128 129 if (!string.IsNullOrEmpty(producerId)) 130 { 131 var producerService = new Smartpage.PhilipsonWine.Producer.Repositories.ProducerService(); 132 var producer = producerService.GetProductProducer(producerId); 133 134 if (producer != null && !string.IsNullOrWhiteSpace(producer.ProducerName) && !string.IsNullOrWhiteSpace(producer.ProducerLink) && !producer.ProducerHidden) 135 { 136 Block producerSectionBlock = new Block() 137 { 138 Id = "ProducerSection", 139 SortId = 34, 140 Template = RenderProducerInfo(producer, "ProducerSection") 141 }; 142 productDetails.Add(producerSectionBlock); 143 } 144 } 145 146 if (!eventProduct) 147 { 148 Block productFieldsBlock = new Block() 149 { 150 Id = "ProductFields", 151 SortId = 36, 152 Template = RenderProductFields("ProductFields") 153 }; 154 productDetails.Add(productFieldsBlock); 155 } 156 157 if (eventProduct) 158 { 159 Block producerSectionBlock = new Block() 160 { 161 Id = "EventSection", 162 SortId = 37, 163 Template = RenderEventInfoSection(productFields) 164 }; 165 productDetails.Add(producerSectionBlock); 166 } 167 168 if (!eventProduct && Smartpage.PhilipsonWine.BomItems.Repositories.BomItemService.GetBomItems(Model.Id) != null && Smartpage.PhilipsonWine.BomItems.Repositories.BomItemService.GetBomItems(Model.Id).Count > 0) 169 { 170 Block BOMItemsSectionBlock = new Block() 171 { 172 Id = "BOMItemsSection", 173 SortId = 35, 174 Template = RenderBOMItemsSection("BOMItemsSection") 175 }; 176 productDetails.Add(BOMItemsSectionBlock); 177 } 178 179 string id = "ClerkOthersAlsoBoughtSection"; 180 Block clerkOthersAlsoBoughtBlock = new Block() 181 { 182 Id = id, 183 SortId = 60, 184 Template = RenderClerkSection(id, "power-step-others-also-bought", "u-white-background") 185 }; 186 productDetails.Add(clerkOthersAlsoBoughtBlock); 187 188 if (!eventProduct) 189 { 190 Block inPageMenuBlock = new Block() 191 { 192 Id = "InPageMenu", 193 SortId = 1, 194 Template = RenderInPageMenu(productDetails) 195 }; 196 productDetails.Add(inPageMenuBlock); 197 } 198 199 Block productSnippetsBlock = new Block() 200 { 201 Id = "Snippets", 202 SortId = 55 203 }; 204 productsPage.Add(productSnippetsBlock); 205 206 207 } 208 209 @* Include the required Grid builder (Contains the methods @RenderBlockList and @RenderBlock) *@ 210 @using System.Text.RegularExpressions 211 @using System.Collections.Generic 212 @using System.Reflection 213 @using System.Web 214 @using System.Web.UI.HtmlControls 215 @using Dynamicweb.Rapido.Blocks.Components 216 @using Dynamicweb.Rapido.Blocks.Components.Articles 217 @using Dynamicweb.Rapido.Blocks.Components.Documentation 218 @using Dynamicweb.Rapido.Blocks 219 220 221 @*--- START: Base block renderers ---*@ 222 223 @helper RenderBlockList(List<Block> blocks) 224 { 225 bool debug = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("debug")) ? Convert.ToBoolean(HttpContext.Current.Request.QueryString.Get("debug")) : false; 226 blocks = blocks.OrderBy(item => item.SortId).ToList(); 227 228 foreach (Block item in blocks) 229 { 230 if (debug) { 231 <!-- Block START: @item.Id --> 232 } 233 234 if (item.Design == null) 235 { 236 @RenderBlock(item) 237 } 238 else if (item.Design.RenderType == RenderType.None) { 239 string cssClass = item.Design.CssClass != null ? item.Design.CssClass : ""; 240 241 <div class="@cssClass dw-mod"> 242 @RenderBlock(item) 243 </div> 244 } 245 else if (item.Design.RenderType != RenderType.Hide) 246 { 247 string cssClass = item.Design.CssClass != null ? item.Design.CssClass : ""; 248 249 if (!item.SkipRenderBlocksList) { 250 if (item.Design.RenderType == RenderType.Row) 251 { 252 <div class="grid grid--align-content-start @cssClass dw-mod" id="Block__@item.Id"> 253 @RenderBlock(item) 254 </div> 255 } 256 257 if (item.Design.RenderType == RenderType.Column) 258 { 259 string hidePadding = item.Design.HidePadding ? "u-no-padding" : ""; 260 string size = item.Design.Size ?? "12"; 261 size = Regex.IsMatch(size, @"\d") ? "md-" + item.Design.Size : item.Design.Size; 262 263 <div class="grid__col-lg-@item.Design.Size grid__col-md-@item.Design.Size grid__col-sm-12 grid__col-xs-12 @hidePadding @cssClass dw-mod" id="Block__@item.Id"> 264 @RenderBlock(item) 265 </div> 266 } 267 268 if (item.Design.RenderType == RenderType.Table) 269 { 270 <table class="table @cssClass dw-mod" id="Block__@item.Id"> 271 @RenderBlock(item) 272 </table> 273 } 274 275 if (item.Design.RenderType == RenderType.TableRow) 276 { 277 <tr class="@cssClass dw-mod" id="Block__@item.Id"> 278 @RenderBlock(item) 279 </tr> 280 } 281 282 if (item.Design.RenderType == RenderType.TableColumn) 283 { 284 <td class="@cssClass dw-mod" id="Block__@item.Id"> 285 @RenderBlock(item) 286 </td> 287 } 288 289 if (item.Design.RenderType == RenderType.CardHeader) 290 { 291 <div class="card-header @cssClass dw-mod"> 292 @RenderBlock(item) 293 </div> 294 } 295 296 if (item.Design.RenderType == RenderType.CardBody) 297 { 298 <div class="card @cssClass dw-mod"> 299 @RenderBlock(item) 300 </div> 301 } 302 303 if (item.Design.RenderType == RenderType.CardFooter) 304 { 305 <div class="card-footer @cssClass dw-mod"> 306 @RenderBlock(item) 307 </div> 308 } 309 } 310 else 311 { 312 @RenderBlock(item) 313 } 314 } 315 316 if (debug) { 317 <!-- Block END: @item.Id --> 318 } 319 } 320 } 321 322 @helper RenderBlock(Block item) 323 { 324 bool debug = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("debug")) ? Convert.ToBoolean(HttpContext.Current.Request.QueryString.Get("debug")) : false; 325 326 if (item.Template != null) 327 { 328 @BlocksPage.RenderTemplate(item.Template) 329 } 330 331 if (item.Component != null) 332 { 333 string customSufix = "Custom"; 334 string methodName = item.Component.HelperName; 335 336 ComponentBase[] methodParameters = new ComponentBase[1]; 337 methodParameters[0] = item.Component; 338 Type methodType = this.GetType(); 339 340 MethodInfo customMethod = methodType.GetMethod(methodName + customSufix); 341 MethodInfo generalMethod = methodType.GetMethod(methodName); 342 343 try { 344 if (debug) { 345 <!-- Component: @methodName.Replace("Render", "") --> 346 } 347 @customMethod.Invoke(this, methodParameters).ToString(); 348 } catch { 349 try { 350 @generalMethod.Invoke(this, methodParameters).ToString(); 351 } catch(Exception ex) { 352 throw new Exception(item.Component.GetType().Name + " method '" + methodName +"' could not be invoked", ex); 353 } 354 } 355 } 356 357 if (item.BlocksList.Count > 0 && !item.SkipRenderBlocksList) 358 { 359 @RenderBlockList(item.BlocksList) 360 } 361 } 362 363 @*--- END: Base block renderers ---*@ 364 365 @using Dynamicweb.Rapido.Blocks.Components 366 @using Dynamicweb.Rapido.Blocks.Components.General 367 @using Dynamicweb.Rapido.Blocks 368 @using System.IO 369 370 @* Required *@ 371 @using Dynamicweb.Rapido.Blocks.Components 372 @using Dynamicweb.Rapido.Blocks.Components.General 373 @using Dynamicweb.Rapido.Blocks 374 375 376 @helper Render(ComponentBase component) 377 { 378 if (component != null) 379 { 380 @component.Render(this) 381 } 382 } 383 384 @* Components *@ 385 @using System.Reflection 386 @using Dynamicweb.Rapido.Blocks.Components.General 387 388 389 @* Component *@ 390 391 @helper RenderIcon(Icon settings) 392 { 393 if (settings != null) 394 { 395 string color = settings.Color != null ? "style=\"color: " + settings.Color + "\"" : ""; 396 397 if (settings.Name != null) 398 { 399 if (string.IsNullOrEmpty(settings.Label)) 400 { 401 <i class="@settings.Prefix @settings.Name @settings.CssClass" @color></i> 402 } 403 else 404 { 405 if (settings.LabelPosition == IconLabelPosition.Before) 406 { 407 <span>@settings.Label <i class="@settings.Prefix @settings.Name @settings.CssClass" @color></i></span> 408 } 409 else 410 { 411 <span><i class="@settings.Prefix @settings.Name u-margin-right--lg @settings.CssClass u-w20px" @color></i>@settings.Label</span> 412 } 413 } 414 } 415 else if (!string.IsNullOrEmpty(settings.Label)) 416 { 417 @settings.Label 418 } 419 } 420 } 421 @using System.Reflection 422 @using Dynamicweb.Rapido.Blocks.Components.General 423 @using Dynamicweb.Rapido.Blocks.Components 424 @using Dynamicweb.Core 425 426 @* Component *@ 427 428 @helper RenderButton(Button settings) 429 { 430 if (settings != null && (!string.IsNullOrEmpty(settings.Title) || settings.Icon != null)) 431 { 432 Dictionary<string, string> attributes = new Dictionary<string, string>(); 433 List<string> classList = settings.CssClass != null ? settings.CssClass.Split(' ').ToList() : new List<string>(); 434 if (settings.Disabled) { 435 attributes.Add("disabled", "true"); 436 classList.Add("disabled"); 437 } 438 439 if (!string.IsNullOrEmpty(settings.ConfirmText) || !string.IsNullOrEmpty(settings.ConfirmTitle)) 440 { 441 settings.Id = !string.IsNullOrEmpty(settings.Id) ? settings.Id : Guid.NewGuid().ToString("N"); 442 @RenderConfirmDialog(settings); 443 settings.OnClick = "document.getElementById('" + settings.Id + "ModalTrigger').checked = true"; 444 } 445 446 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 447 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 448 if (!string.IsNullOrEmpty(settings.AltText)) 449 { 450 attributes.Add("title", settings.AltText); 451 } 452 else if (!string.IsNullOrEmpty(settings.Title)) 453 { 454 attributes.Add("title", settings.Title); 455 } 456 457 var onClickEvents = new List<string>(); 458 if (!string.IsNullOrEmpty(settings.OnClick)) 459 { 460 onClickEvents.Add(settings.OnClick); 461 } 462 if (!string.IsNullOrEmpty(settings.Href)) 463 { 464 onClickEvents.Add("location.href='" + settings.Href + "'"); 465 } 466 if (onClickEvents.Count > 0) 467 { 468 attributes.Add("onClick", string.Join(";", onClickEvents)); 469 } 470 471 if (settings.ButtonLayout != ButtonLayout.None) 472 { 473 classList.Add("btn"); 474 string btnLayout = Enum.GetName(typeof(ButtonLayout), settings.ButtonLayout).ToLower(); 475 if (btnLayout == "linkclean") 476 { 477 btnLayout = "link-clean"; //fix 478 } 479 classList.Add("btn--" + btnLayout); 480 } 481 482 if (settings.Icon == null) 483 { 484 settings.Icon = new Icon(); 485 } 486 settings.Icon.Label = settings.Title; 487 488 attributes.Add("type", Enum.GetName(typeof(ButtonType), settings.ButtonType).ToLower()); 489 490 <button class="@string.Join(" ", classList) dw-mod" @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@Render(settings.Icon)</button> 491 } 492 } 493 494 @helper RenderConfirmDialog(Button settings) 495 { 496 Modal confirmDialog = new Modal { 497 Id = settings.Id, 498 Width = ModalWidth.Sm, 499 Heading = new Heading 500 { 501 Level = 2, 502 Title = settings.ConfirmTitle 503 }, 504 BodyText = settings.ConfirmText 505 }; 506 507 confirmDialog.AddAction(new Button { Title = Translate("Cancel"), ButtonLayout = ButtonLayout.Secondary, OnClick = "document.getElementById('" + settings.Id + "ModalTrigger').checked = false"}); 508 confirmDialog.AddAction(new Button { Title = Translate("OK"), ButtonLayout = ButtonLayout.Primary, OnClick = "document.getElementById('" + settings.Id + "ModalTrigger').checked = false;" + settings.OnClick }); 509 510 @Render(confirmDialog) 511 } 512 @using Dynamicweb.Rapido.Blocks.Components.General 513 @using Dynamicweb.Rapido.Blocks.Components 514 @using Dynamicweb.Core 515 516 @helper RenderDashboard(Dashboard settings) 517 { 518 var widgets = settings.GetWidgets(); 519 520 if (!string.IsNullOrEmpty(settings.WidgetsBaseBackgroundColor)) 521 { 522 //set bg color for them 523 524 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(settings.WidgetsBaseBackgroundColor); 525 int r = Convert.ToInt16(color.R); 526 int g = Convert.ToInt16(color.G); 527 int b = Convert.ToInt16(color.B); 528 529 var count = widgets.Length; 530 var max = Math.Max(r, Math.Max(g, b)); 531 double step = 255.0 / (max * count); 532 var i = 0; 533 foreach (var widget in widgets) 534 { 535 i++; 536 537 var shade = "rgb(" + Converter.ToString(r * step * i).Replace(",", ".") + ", " + Converter.ToString(g * step * i).Replace(",", ".") + ", " + Converter.ToString(b * step * i).Replace(",", ".") + ")"; 538 widget.BackgroundColor = shade; 539 } 540 } 541 542 <div class="dashboard @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 543 @foreach (var widget in widgets) 544 { 545 <div class="dashboard__widget"> 546 @Render(widget) 547 </div> 548 } 549 </div> 550 } 551 @using Dynamicweb.Rapido.Blocks.Components.General 552 @using Dynamicweb.Rapido.Blocks.Components 553 554 @helper RenderDashboardWidgetLink(DashboardWidgetLink settings) 555 { 556 if (!string.IsNullOrEmpty(settings.Link)) 557 { 558 var backgroundStyles = ""; 559 if (!string.IsNullOrEmpty(settings.BackgroundColor)) 560 { 561 backgroundStyles = "style=\"background-color:" + settings.BackgroundColor + "\""; 562 } 563 564 <a href="@settings.Link" class="widget widget--link @settings.CssClass dw-mod" @backgroundStyles title="@settings.Title" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 565 <div class="u-center-middle u-color-light"> 566 @if (settings.Icon != null) 567 { 568 settings.Icon.CssClass += "widget__icon"; 569 @Render(settings.Icon) 570 } 571 <div class="widget__title">@settings.Title</div> 572 </div> 573 </a> 574 } 575 } 576 @using Dynamicweb.Rapido.Blocks.Components.General 577 @using Dynamicweb.Rapido.Blocks.Components 578 579 @helper RenderDashboardWidgetCounter(DashboardWidgetCounter settings) 580 { 581 var backgroundStyles = ""; 582 if (!string.IsNullOrEmpty(settings.BackgroundColor)) 583 { 584 backgroundStyles = "style='background-color:" + settings.BackgroundColor + "'"; 585 } 586 587 <div class="widget @settings.CssClass dw-mod" @backgroundStyles @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 588 <div class="u-center-middle u-color-light"> 589 @if (settings.Icon != null) 590 { 591 settings.Icon.CssClass += "widget__icon"; 592 @Render(settings.Icon) 593 } 594 <div class="widget__counter">@settings.Count</div> 595 <div class="widget__title">@settings.Title</div> 596 </div> 597 </div> 598 } 599 @using System.Reflection 600 @using Dynamicweb.Rapido.Blocks.Components.General 601 @using Dynamicweb.Rapido.Blocks.Components 602 @using Dynamicweb.Core 603 604 @* Component *@ 605 606 @helper RenderLink(Link settings) 607 { 608 if (settings != null && !string.IsNullOrEmpty(settings.Href) && (!string.IsNullOrEmpty(settings.Title) || settings.Icon != null)) 609 { 610 Dictionary<string, string> attributes = new Dictionary<string, string>(); 611 List<string> classList = settings.CssClass != null ? settings.CssClass.Split(' ').ToList() : new List<string>(); 612 if (settings.Disabled) 613 { 614 attributes.Add("disabled", "true"); 615 classList.Add("disabled"); 616 } 617 618 if (!string.IsNullOrEmpty(settings.AltText)) 619 { 620 attributes.Add("title", settings.AltText); 621 } 622 else if (!string.IsNullOrEmpty(settings.Title)) 623 { 624 attributes.Add("title", settings.Title); 625 } 626 627 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 628 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 629 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onClick", settings.OnClick); } 630 attributes.Add("href", settings.Href); 631 632 if (settings.ButtonLayout != ButtonLayout.None) 633 { 634 classList.Add("btn"); 635 string btnLayout = Enum.GetName(typeof(ButtonLayout), settings.ButtonLayout).ToLower(); 636 if (btnLayout == "linkclean") 637 { 638 btnLayout = "link-clean"; //fix 639 } 640 classList.Add("btn--" + btnLayout); 641 } 642 643 if (settings.Icon == null) 644 { 645 settings.Icon = new Icon(); 646 } 647 settings.Icon.Label = settings.Title; 648 649 if (settings.Target == LinkTargetType.Blank && settings.Rel == LinkRelType.None) 650 { 651 settings.Rel = LinkRelType.Noopener; 652 } 653 if (settings.Target != LinkTargetType.None) 654 { 655 attributes.Add("target", "_" + Enum.GetName(typeof(LinkTargetType), settings.Target).ToLower()); 656 } 657 if (settings.Download) 658 { 659 attributes.Add("download", "true"); 660 } 661 if (settings.Rel != LinkRelType.None) 662 { 663 attributes.Add("rel", Enum.GetName(typeof(LinkRelType), settings.Rel).ToLower()); 664 } 665 666 <a class="@string.Join(" ", classList) dw-mod" @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@Render(settings.Icon)</a> 667 } 668 } 669 @using System.Reflection 670 @using Dynamicweb.Rapido.Blocks.Components 671 @using Dynamicweb.Rapido.Blocks.Components.General 672 @using Dynamicweb.Rapido.Blocks 673 674 675 @* Component *@ 676 677 @helper RenderRating(Rating settings) 678 { 679 if (settings.Score > 0) 680 { 681 int rating = settings.Score; 682 string iconType = "fa-star"; 683 684 switch (settings.Type.ToString()) { 685 case "Stars": 686 iconType = "fa-star"; 687 break; 688 case "Hearts": 689 iconType = "fa-heart"; 690 break; 691 case "Lemons": 692 iconType = "fa-lemon"; 693 break; 694 case "Bombs": 695 iconType = "fa-bomb"; 696 break; 697 } 698 699 <div class="u-ta-right"> 700 @for (int i = 0; i < settings.OutOf; i++) 701 { 702 <i class="@(rating > i ? "fas" : "far") @iconType"></i> 703 } 704 </div> 705 } 706 } 707 @using System.Reflection 708 @using Dynamicweb.Rapido.Blocks.Components.General 709 @using Dynamicweb.Rapido.Blocks.Components 710 711 712 @* Component *@ 713 714 @helper RenderSelectFieldOption(SelectFieldOption settings) 715 { 716 Dictionary<string, string> attributes = new Dictionary<string, string>(); 717 if (settings.Checked) { attributes.Add("selected", "true"); } 718 if (settings.Disabled) { attributes.Add("disabled", "true"); } 719 if (settings.Value != null) { attributes.Add("value", settings.Value); } 720 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 721 722 <option @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@settings.Label</option> 723 } 724 @using System.Reflection 725 @using Dynamicweb.Rapido.Blocks.Components.General 726 @using Dynamicweb.Rapido.Blocks.Components 727 728 729 @* Component *@ 730 731 @helper RenderNavigation(Navigation settings) { 732 @RenderNavigation(new 733 { 734 id = settings.Id, 735 cssclass = settings.CssClass, 736 startLevel = settings.StartLevel, 737 endlevel = settings.EndLevel, 738 expandmode = settings.Expandmode, 739 sitemapmode = settings.SitemapMode, 740 template = settings.Template 741 }) 742 } 743 @using Dynamicweb.Rapido.Blocks.Components.General 744 @using Dynamicweb.Rapido.Blocks.Components 745 746 747 @* Component *@ 748 749 @helper RenderBreadcrumbNavigation(BreadcrumbNavigation settings) { 750 settings.Id = String.IsNullOrEmpty(settings.Id) ? "breadcrumb" : settings.Id; 751 settings.Template = String.IsNullOrEmpty(settings.Template) ? "Breadcrumb.xslt" : settings.Template; 752 settings.StartLevel = settings.StartLevel == 0 ? 1 : settings.StartLevel; 753 settings.EndLevel = settings.EndLevel == 10 ? 1 : settings.EndLevel; 754 settings.Expandmode = String.IsNullOrEmpty(settings.Expandmode) ? "all" : settings.Expandmode; 755 settings.SitemapMode = false; 756 757 @RenderNavigation(settings) 758 } 759 @using Dynamicweb.Rapido.Blocks.Components.General 760 @using Dynamicweb.Rapido.Blocks.Components 761 762 763 @* Component *@ 764 765 @helper RenderLeftNavigation(LeftNavigation settings) { 766 settings.Id = String.IsNullOrEmpty(settings.Id) ? "breadcrumb" : settings.Id; 767 settings.Template = String.IsNullOrEmpty(settings.Template) ? "Breadcrumb.xslt" : settings.Template; 768 settings.StartLevel = settings.StartLevel == 0 ? 1 : settings.StartLevel; 769 settings.EndLevel = settings.EndLevel == 10 ? 1 : settings.EndLevel; 770 settings.Expandmode = String.IsNullOrEmpty(settings.Expandmode) ? "all" : settings.Expandmode; 771 772 <div class="grid__cell"> 773 @RenderNavigation(settings) 774 </div> 775 } 776 @using System.Reflection 777 @using Dynamicweb.Rapido.Blocks.Components.General 778 @using Dynamicweb.Core 779 780 @* Component *@ 781 782 @helper RenderHeading(Heading settings) 783 { 784 if (settings != null && !string.IsNullOrEmpty(settings.Title)) 785 { 786 string color = settings.Color != null ? "style=\"color: " + settings.Color + "\"" : ""; 787 string tagName = settings.Level != 0 ? "h" + settings.Level.ToString() : "div"; 788 789 @("<" + tagName + " class=\"" + settings.CssClass + " dw-mod\" " + color + ">") 790 if (!string.IsNullOrEmpty(settings.Link)) 791 { 792 @Render(new Link { Href = settings.Link, Icon = settings.Icon, Title = settings.Title, ButtonLayout = ButtonLayout.None }) 793 } 794 else 795 { 796 if (settings.Icon == null) 797 { 798 settings.Icon = new Icon(); 799 } 800 settings.Icon.Label = settings.Title; 801 @Render(settings.Icon) 802 } 803 @("</" + tagName + ">"); 804 } 805 } 806 @using Dynamicweb.Rapido.Blocks.Components 807 @using Dynamicweb.Rapido.Blocks.Components.General 808 @using Dynamicweb.Rapido.Blocks 809 810 811 @* Component *@ 812 813 @helper RenderImage(Image settings) 814 { 815 if (settings.FilterPrimary != ImageFilter.None || settings.FilterSecondary != ImageFilter.None) 816 { 817 Dictionary<string, string> optionalAttributes = new Dictionary<string, string>(); 818 if (!string.IsNullOrEmpty(settings.FilterColor)) { optionalAttributes.Add("style", "background-color: " + settings.FilterColor); } 819 820 if (settings.Caption != null) 821 { 822 @:<div> 823 } 824 825 var primaryFilterClass = settings.FilterPrimary.ToString().ToLower(); 826 var secondaryFilterClass = settings.FilterSecondary.ToString().ToLower(); 827 828 <div class="image-filter image-filter--@primaryFilterClass u-position-relative dw-mod" @ComponentMethods.AddAttributes(optionalAttributes)> 829 <div class="image-filter image-filter--@secondaryFilterClass dw-mod"> 830 @if (settings.Link != null) 831 { 832 <a href="@settings.Link"> 833 @RenderTheImage(settings) 834 </a> 835 } 836 else 837 { 838 @RenderTheImage(settings) 839 } 840 </div> 841 </div> 842 843 if (settings.Caption != null) 844 { 845 <span class="image-caption dw-mod">@settings.Caption</span> 846 @:</div> 847 } 848 } 849 else 850 { 851 if (settings.Caption != null) 852 { 853 @:<div> 854 } 855 if (!string.IsNullOrEmpty(settings.Link)) 856 { 857 <a href="@settings.Link"> 858 @RenderTheImage(settings) 859 </a> 860 } 861 else 862 { 863 @RenderTheImage(settings) 864 } 865 866 if (settings.Caption != null) 867 { 868 <span class="image-caption dw-mod">@settings.Caption</span> 869 @:</div> 870 } 871 } 872 } 873 874 @helper RenderTheImage(Image settings) 875 { 876 if (settings != null) 877 { 878 string placeholderImage = "/Files/Images/placeholder.gif"; 879 string imageEngine = "/Admin/Public/GetImage.ashx?"; 880 881 // CDN 882 var cdnUrl = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("CDNUrl"); 883 bool cdnActivate = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetBoolean("CDNActivate"); 884 if (!string.IsNullOrWhiteSpace(cdnUrl) && cdnActivate) 885 { 886 imageEngine = cdnUrl + imageEngine; 887 } 888 889 string imageStyle = ""; 890 891 switch (settings.Style) 892 { 893 case ImageStyle.Ball: 894 imageStyle = "grid__cell-img--ball"; 895 break; 896 897 case ImageStyle.Triangle: 898 imageStyle = "grid__cell-img--triangle"; 899 break; 900 } 901 902 if (settings.Style == ImageStyle.Ball || settings.Style == ImageStyle.Circle || settings.Style == ImageStyle.Triangle) 903 { 904 settings.ImageDefault.Crop = settings.ImageDefault.Crop == 5 ? settings.ImageDefault.Crop = 0 : settings.ImageDefault.Crop; 905 906 if (settings.ImageDefault != null) 907 { 908 settings.ImageDefault.Height = settings.ImageDefault.Width; 909 } 910 if (settings.ImageMedium != null) 911 { 912 settings.ImageMedium.Height = settings.ImageMedium.Width; 913 } 914 if (settings.ImageSmall != null) 915 { 916 settings.ImageSmall.Height = settings.ImageSmall.Width; 917 } 918 } 919 920 string defaultImage = imageEngine; 921 string imageSmall = ""; 922 string imageMedium = ""; 923 924 if (settings.DisableImageEngine) 925 { 926 defaultImage = settings.Path; 927 } 928 else 929 { 930 if (settings.ImageDefault != null) 931 { 932 defaultImage += Dynamicweb.Rapido.Services.Images.GetImagePathFromSettings(settings.ImageDefault); 933 934 if (settings.Path.GetType() != typeof(string)) 935 { 936 defaultImage += settings.Path != null ? "Image=" + settings.Path.PathUrlEncoded : ""; 937 defaultImage += settings.Path != null ? "&" + settings.Path.GetFocalPointParameters() : ""; 938 } 939 else 940 { 941 defaultImage += settings.Path != null ? "Image=" + settings.Path : ""; 942 } 943 } 944 945 if (settings.ImageSmall != null) 946 { 947 imageSmall = "data-src-small=\"" + imageEngine; 948 imageSmall += Dynamicweb.Rapido.Services.Images.GetImagePathFromSettings(settings.ImageSmall); 949 950 if (settings.Path.GetType() != typeof(string)) 951 { 952 imageSmall += settings.Path != null ? "Image=" + settings.Path.PathUrlEncoded : ""; 953 imageSmall += settings.Path != null ? "&" + settings.Path.GetFocalPointParameters() : ""; 954 } 955 else 956 { 957 imageSmall += settings.Path != null ? "Image=" + settings.Path : ""; 958 } 959 960 imageSmall += "\""; 961 } 962 963 if (settings.ImageMedium != null) 964 { 965 imageMedium = "data-src-medium=\"" + imageEngine; 966 imageMedium += Dynamicweb.Rapido.Services.Images.GetImagePathFromSettings(settings.ImageMedium); 967 968 if (settings.Path.GetType() != typeof(string)) 969 { 970 imageMedium += settings.Path != null ? "Image=" + settings.Path.PathUrlEncoded : ""; 971 imageMedium += settings.Path != null ? "&" + settings.Path.GetFocalPointParameters() : ""; 972 } 973 else 974 { 975 imageMedium += settings.Path != null ? "Image=" + settings.Path : ""; 976 } 977 978 imageMedium += "\""; 979 } 980 } 981 982 Dictionary<string, string> optionalAttributes = new Dictionary<string, string>(); 983 if (!string.IsNullOrEmpty(settings.OnClick)) { optionalAttributes.Add("onclick", settings.OnClick); } 984 if (!string.IsNullOrEmpty(settings.Title)) 985 { 986 optionalAttributes.Add("alt", settings.Title); 987 optionalAttributes.Add("title", settings.Title); 988 } 989 990 if (settings.DisableLazyLoad) 991 { 992 <img id="@settings.Id" class="@imageStyle @settings.CssClass dw-mod" src="@defaultImage" @ComponentMethods.AddAttributes(optionalAttributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes) /> 993 } 994 else 995 { 996 <img id="@settings.Id" class="b-lazy @imageStyle @settings.CssClass dw-mod" src="@placeholderImage" data-src="@defaultImage" @imageSmall @imageMedium @ComponentMethods.AddAttributes(optionalAttributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes) /> 997 } 998 } 999 } 1000 @using System.Reflection 1001 @using Dynamicweb.Rapido.Blocks.Components.General 1002 @using Dynamicweb.Rapido.Blocks.Components 1003 1004 @* Component *@ 1005 1006 @helper RenderFileField(FileField settings) 1007 { 1008 var attributes = new Dictionary<string, string>(); 1009 if (string.IsNullOrEmpty(settings.Id)) 1010 { 1011 settings.Id = Guid.NewGuid().ToString("N"); 1012 } 1013 1014 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1015 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1016 if (settings.Required) { attributes.Add("required", "true"); } 1017 if (settings.Multiple) { attributes.Add("multiple", "true"); } 1018 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1019 if (string.IsNullOrEmpty(settings.ChooseFileText)) 1020 { 1021 settings.ChooseFileText = Translate("Choose file"); 1022 } 1023 if (string.IsNullOrEmpty(settings.NoFilesChosenText)) 1024 { 1025 settings.NoFilesChosenText = Translate("No files chosen..."); 1026 } 1027 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1028 1029 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1030 1031 string setValueToFakeInput = "FileUpload.setValueToFakeInput(this)"; 1032 attributes.Add("onchange", setValueToFakeInput + (!string.IsNullOrEmpty(settings.OnChange) ? settings.OnChange : "")); 1033 1034 attributes.Add("type", "file"); 1035 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1036 settings.CssClass = "u-full-width " + settings.CssClass; 1037 1038 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1039 1040 <div class="form__field-group u-full-width @settings.WrapperCssClass dw-mod"> 1041 @if (!string.IsNullOrEmpty(settings.Label)) 1042 { 1043 <label for="@settings.Id">@settings.Label</label> 1044 } 1045 @if (!string.IsNullOrEmpty(settings.HelpText)) 1046 { 1047 <small class="form__help-text">@settings.HelpText</small> 1048 } 1049 1050 <div class="form__field-combi file-input u-no-margin dw-mod"> 1051 <input @ComponentMethods.AddAttributes(resultAttributes) class="file-input__real-input" data-no-files-text="@settings.NoFilesChosenText" data-many-files-text="@Translate("files")" /> 1052 <label for="@settings.Id" class="file-input__btn btn--secondary btn dw-mod">@settings.ChooseFileText</label> 1053 <label for="@settings.Id" class="@settings.CssClass file-input__fake-input js-fake-input dw-mod">@settings.NoFilesChosenText</label> 1054 @if (settings.UploadButton != null) 1055 { 1056 settings.UploadButton.CssClass += " btn--condensed u-no-margin"; 1057 @Render(settings.UploadButton) 1058 } 1059 </div> 1060 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1061 </div> 1062 } 1063 @using System.Reflection 1064 @using Dynamicweb.Rapido.Blocks.Components.General 1065 @using Dynamicweb.Rapido.Blocks.Components 1066 @using Dynamicweb.Core 1067 @using System.Linq 1068 1069 @* Component *@ 1070 1071 @helper RenderDateTimeField(DateTimeField settings) 1072 { 1073 if (string.IsNullOrEmpty(settings.Id)) 1074 { 1075 settings.Id = Guid.NewGuid().ToString("N"); 1076 } 1077 1078 var textField = new TextField { 1079 Name = settings.Name, 1080 Id = settings.Id, 1081 Label = settings.Label, 1082 HelpText = settings.HelpText, 1083 Value = settings.Value, 1084 Disabled = settings.Disabled, 1085 Required = settings.Required, 1086 ErrorMessage = settings.ErrorMessage, 1087 CssClass = settings.CssClass, 1088 WrapperCssClass = settings.WrapperCssClass, 1089 OnChange = settings.OnChange, 1090 OnClick = settings.OnClick, 1091 ExtraAttributes = settings.ExtraAttributes, 1092 // 1093 Placeholder = settings.Placeholder 1094 }; 1095 1096 @Render(textField) 1097 1098 List<string> jsAttributes = new List<string>(); 1099 1100 jsAttributes.Add("mode: '" + Enum.GetName(typeof(DateTimeFieldMode), settings.Mode).ToLower() + "'"); 1101 1102 if (!string.IsNullOrEmpty(settings.DateFormat)) 1103 { 1104 jsAttributes.Add("dateFormat: '" + settings.DateFormat + "'"); 1105 } 1106 if (!string.IsNullOrEmpty(settings.MinDate)) 1107 { 1108 jsAttributes.Add("minDate: '" + settings.MinDate + "'"); 1109 } 1110 if (!string.IsNullOrEmpty(settings.MaxDate)) 1111 { 1112 jsAttributes.Add("maxDate: '" + settings.MaxDate + "'"); 1113 } 1114 if (settings.IsInline) 1115 { 1116 jsAttributes.Add("inline: " + Converter.ToString(settings.IsInline).ToLower()); 1117 } 1118 if (settings.EnableTime) 1119 { 1120 jsAttributes.Add("enableTime: " + Converter.ToString(settings.EnableTime).ToLower()); 1121 } 1122 if (settings.EnableWeekNumbers) 1123 { 1124 jsAttributes.Add("weekNumbers: " + Converter.ToString(settings.EnableWeekNumbers).ToLower()); 1125 } 1126 1127 jsAttributes.AddRange(settings.GetFlatPickrOptions().Select(x => x.Key + ": " + x.Value)); 1128 1129 <script> 1130 document.addEventListener("DOMContentLoaded", function () { 1131 flatpickr("#@textField.Id", { 1132 @string.Join(",", jsAttributes) 1133 }); 1134 }); 1135 </script> 1136 } 1137 @using System.Reflection 1138 @using Dynamicweb.Rapido.Blocks.Components.General 1139 @using Dynamicweb.Rapido.Blocks.Components 1140 1141 @* Component *@ 1142 1143 @helper RenderTextField(TextField settings) 1144 { 1145 var attributes = new Dictionary<string, string>(); 1146 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1147 { 1148 settings.Id = Guid.NewGuid().ToString("N"); 1149 } 1150 1151 /*base settings*/ 1152 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1153 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1154 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1155 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1156 if (settings.Required) { attributes.Add("required", "true"); } 1157 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1158 /*end*/ 1159 1160 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 1161 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 1162 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 1163 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 1164 if (settings.MaxLength != 0) { attributes.Add("maxlength", settings.MaxLength.ToString()); } 1165 if (!string.IsNullOrEmpty(settings.Placeholder)) { attributes.Add("placeholder", settings.Placeholder); } 1166 attributes.Add("type", Enum.GetName(typeof(TextFieldType), settings.Type).ToLower()); 1167 if (settings.Type == TextFieldType.Password) { attributes.Add("autocomplete", "off"); }; 1168 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1169 1170 settings.CssClass = "u-full-width " + settings.CssClass; 1171 1172 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1173 1174 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1175 1176 string noMargin = "u-no-margin"; 1177 if (!settings.ReadOnly) { 1178 noMargin = ""; 1179 } 1180 1181 <div class="form__field-group u-full-width @noMargin @settings.WrapperCssClass dw-mod"> 1182 @if (!string.IsNullOrEmpty(settings.Label)) 1183 { 1184 <label for="@settings.Id">@settings.Label</label> 1185 } 1186 @if (!string.IsNullOrEmpty(settings.HelpText)) 1187 { 1188 <small class="form__help-text">@settings.HelpText</small> 1189 } 1190 1191 @if (settings.ActionButton != null) 1192 { 1193 settings.ActionButton.CssClass += " btn--condensed u-no-margin"; 1194 <div class="form__field-combi u-no-margin dw-mod"> 1195 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1196 @Render(settings.ActionButton) 1197 </div> 1198 } 1199 else 1200 { 1201 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1202 } 1203 1204 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1205 </div> 1206 } 1207 @using System.Reflection 1208 @using Dynamicweb.Rapido.Blocks.Components.General 1209 @using Dynamicweb.Rapido.Blocks.Components 1210 1211 @* Component *@ 1212 1213 @helper RenderNumberField(NumberField settings) 1214 { 1215 var attributes = new Dictionary<string, string>(); 1216 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1217 { 1218 settings.Id = Guid.NewGuid().ToString("N"); 1219 } 1220 1221 /*base settings*/ 1222 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1223 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1224 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1225 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1226 if (settings.Required) { attributes.Add("required", "true"); } 1227 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1228 /*end*/ 1229 1230 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 1231 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 1232 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 1233 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 1234 if (settings.Max != null) { attributes.Add("max", settings.Max.ToString()); } 1235 if (settings.Min != null) { attributes.Add("min", settings.Min.ToString()); } 1236 if (settings.Step != 0) { attributes.Add("step", settings.Step.ToString()); } 1237 if (settings.Value != null && !string.IsNullOrEmpty(settings.Value.ToString())) { attributes.Add("value", settings.Value.ToString()); } 1238 attributes.Add("type", "number"); 1239 1240 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1241 1242 <div class="form__field-group u-full-width @settings.WrapperCssClass dw-mod"> 1243 @if (!string.IsNullOrEmpty(settings.Label)) 1244 { 1245 <label for="@settings.Id">@settings.Label</label> 1246 } 1247 @if (!string.IsNullOrEmpty(settings.HelpText)) 1248 { 1249 <small class="form__help-text">@settings.HelpText</small> 1250 } 1251 1252 @if (settings.ActionButton != null) 1253 { 1254 settings.ActionButton.CssClass += " btn--condensed u-no-margin"; 1255 <div class="form__field-combi u-no-margin dw-mod"> 1256 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1257 @Render(settings.ActionButton) 1258 </div> 1259 } 1260 else 1261 { 1262 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1263 } 1264 1265 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1266 </div> 1267 } 1268 @using System.Reflection 1269 @using Dynamicweb.Rapido.Blocks.Components.General 1270 @using Dynamicweb.Rapido.Blocks.Components 1271 1272 1273 @* Component *@ 1274 1275 @helper RenderTextareaField(TextareaField settings) 1276 { 1277 Dictionary<string, string> attributes = new Dictionary<string, string>(); 1278 string id = settings.Id; 1279 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(id)) 1280 { 1281 id = Guid.NewGuid().ToString("N"); 1282 } 1283 1284 if (!string.IsNullOrEmpty(id)) { attributes.Add("id", id); } 1285 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1286 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 1287 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 1288 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 1289 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1290 if (!string.IsNullOrEmpty(settings.Placeholder)) { attributes.Add("placeholder", settings.Placeholder); } 1291 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1292 if (settings.Required) { attributes.Add("required", "true"); } 1293 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 1294 if (settings.MaxLength != 0) { attributes.Add("maxlength", settings.MaxLength.ToString()); } 1295 if (settings.Rows != 0) { attributes.Add("rows", settings.Rows.ToString()); } 1296 attributes.Add("name", settings.Name); 1297 1298 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1299 1300 <div class="form__field-group @settings.WrapperCssClass dw-mod"> 1301 @if (!string.IsNullOrEmpty(settings.Label)) 1302 { 1303 <label for="@id">@settings.Label</label> 1304 } 1305 @if (!string.IsNullOrEmpty(settings.HelpText)) 1306 { 1307 <small class="form__help-text">@settings.HelpText</small> 1308 } 1309 1310 <textarea class="u-full-width @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@settings.Value</textarea> 1311 1312 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1313 </div> 1314 } 1315 @using System.Reflection 1316 @using Dynamicweb.Rapido.Blocks.Components.General 1317 @using Dynamicweb.Rapido.Blocks.Components 1318 1319 1320 @* Component *@ 1321 1322 @helper RenderHiddenField(HiddenField settings) { 1323 var attributes = new Dictionary<string, string>(); 1324 attributes.Add("type", "hidden"); 1325 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1326 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1327 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1328 1329 <input @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)/> 1330 } 1331 @using System.Reflection 1332 @using Dynamicweb.Rapido.Blocks.Components.General 1333 @using Dynamicweb.Rapido.Blocks.Components 1334 1335 @* Component *@ 1336 1337 @helper RenderCheckboxField(CheckboxField settings) 1338 { 1339 var attributes = new Dictionary<string, string>(); 1340 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1341 { 1342 settings.Id = Guid.NewGuid().ToString("N"); 1343 } 1344 1345 /*base settings*/ 1346 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1347 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1348 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1349 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1350 if (settings.Required) { attributes.Add("required", "true"); } 1351 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1352 /*end*/ 1353 1354 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1355 1356 attributes.Add("type", "checkbox"); 1357 if (settings.Checked) { attributes.Add("checked", "true"); } 1358 settings.CssClass = "form__control " + settings.CssClass; 1359 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1360 1361 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1362 1363 <div class="form__field-group @settings.WrapperCssClass dw-mod"> 1364 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1365 @if (!string.IsNullOrEmpty(settings.Label)) 1366 { 1367 <label for="@settings.Id" class="dw-mod">@settings.Label</label> 1368 } 1369 @if (!string.IsNullOrEmpty(settings.HelpText)) 1370 { 1371 <small class="form__help-text">@settings.HelpText</small> 1372 } 1373 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1374 </div> 1375 } 1376 @using System.Reflection 1377 @using Dynamicweb.Rapido.Blocks.Components.General 1378 @using Dynamicweb.Rapido.Blocks.Components 1379 1380 1381 @* Component *@ 1382 1383 @helper RenderCheckboxListField(CheckboxListField settings) 1384 { 1385 <div class="form__field-group @settings.WrapperCssClass u-margin-bottom dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1386 @if (!string.IsNullOrEmpty(settings.Label)) 1387 { 1388 <label>@settings.Label</label> 1389 } 1390 @if (!string.IsNullOrEmpty(settings.HelpText)) 1391 { 1392 <small class="form__help-text">@settings.HelpText</small> 1393 } 1394 1395 @foreach (var item in settings.Options) 1396 { 1397 if (settings.Required) 1398 { 1399 item.Required = true; 1400 } 1401 if (settings.Disabled) 1402 { 1403 item.Disabled = true; 1404 } 1405 if (!string.IsNullOrEmpty(settings.Name)) 1406 { 1407 item.Name = settings.Name; 1408 } 1409 if (!string.IsNullOrEmpty(settings.CssClass)) 1410 { 1411 item.CssClass += settings.CssClass; 1412 } 1413 1414 /* value is not supported */ 1415 1416 if (!string.IsNullOrEmpty(settings.OnClick)) 1417 { 1418 item.OnClick += settings.OnClick; 1419 } 1420 if (!string.IsNullOrEmpty(settings.OnChange)) 1421 { 1422 item.OnChange += settings.OnChange; 1423 } 1424 @Render(item) 1425 } 1426 1427 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1428 </div> 1429 } 1430 @using Dynamicweb.Rapido.Blocks.Components.General 1431 1432 @* Component *@ 1433 1434 @helper RenderSearch(Search settings) 1435 { 1436 var searchValue = HttpContext.Current.Request.QueryString.Get(settings.SearchParameter) ?? ""; 1437 var groupValue = HttpContext.Current.Request.QueryString.Get(settings.GroupsParameter) ?? ""; 1438 1439 if (string.IsNullOrEmpty(settings.Id)) 1440 { 1441 settings.Id = Guid.NewGuid().ToString("N"); 1442 } 1443 1444 var resultAttributes = new Dictionary<string, string>(); 1445 1446 if (settings.PageSize != 0) 1447 { 1448 resultAttributes.Add("data-page-size", settings.PageSize.ToString()); 1449 } 1450 if (!string.IsNullOrEmpty(settings.GroupItemsFeedUrl)) 1451 { 1452 resultAttributes.Add("data-groups-feed-url", settings.GroupItemsFeedUrl); 1453 if (!string.IsNullOrEmpty(groupValue)) 1454 { 1455 resultAttributes.Add("data-selected-group", groupValue); 1456 } 1457 if (!string.IsNullOrEmpty(settings.GroupsParameter)) 1458 { 1459 resultAttributes.Add("data-groups-parameter", settings.GroupsParameter); 1460 } 1461 } 1462 resultAttributes.Add("data-force-init", "true"); 1463 if (settings.GoToFirstSearchResultOnEnter) 1464 { 1465 resultAttributes.Add("data-go-to-first-search-result-on-enter", settings.GoToFirstSearchResultOnEnter.ToString().ToLower()); 1466 } 1467 if (!string.IsNullOrEmpty(settings.SearchParameter)) 1468 { 1469 resultAttributes.Add("data-search-parameter", settings.SearchParameter); 1470 } 1471 resultAttributes.Add("data-search-feed-url", settings.SearchData.SearchFeedUrl); 1472 resultAttributes.Add("data-results-template-id", settings.SearchData.ResultsTemplateId); 1473 1474 if (settings.SecondSearchData != null) 1475 { 1476 resultAttributes.Add("data-second-search-feed-url", settings.SecondSearchData.SearchFeedUrl); 1477 resultAttributes.Add("data-second-results-template-id", settings.SecondSearchData.ResultsTemplateId); 1478 } 1479 if (!string.IsNullOrEmpty(settings.ResultsPageUrl)) 1480 { 1481 resultAttributes.Add("data-results-page-url", settings.ResultsPageUrl); 1482 } 1483 1484 resultAttributes = resultAttributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1485 1486 string searchFieldCss = (settings.SearchButton == null) ? "search--with-icon" : ""; 1487 1488 <div class="search @settings.CssClass @searchFieldCss js-search-data-source dw-mod" id="@settings.Id" @ComponentMethods.AddAttributes(resultAttributes)> 1489 @if (!string.IsNullOrEmpty(settings.GroupItemsFeedUrl)) 1490 { 1491 <button type="button" class="search__groups-btn dw-mod js-search-groups-btn">@Translate("All")</button> 1492 <ul class="dropdown dropdown--absolute-position dw-mod search__groups-results js-search-groups-list"></ul> 1493 } 1494 1495 <input type="text" class="search__field dw-mod js-search-field" placeholder="@settings.Placeholder" value="@searchValue"> 1496 1497 <div class="dropdown dropdown--absolute-position search__results dw-mod js-search-results @(settings.SecondSearchData != null ? "search__results--combined" : "")"> 1498 @if (settings.SecondSearchData != null) 1499 { 1500 <div class="search__column search__column--products dw-mod"> 1501 <div class="search__column-header dw-mod">@Translate("Products")</div> 1502 <ul class="search__results-list dw-mod js-search-results-list" id="@(settings.Id)_ResultsList"></ul> 1503 @if (!string.IsNullOrEmpty(settings.SearchData.ResultsPageUrl)) 1504 { 1505 @Render(new Link { 1506 Title = Translate("View all"), 1507 CssClass = "js-view-all-button u-margin", 1508 Href = settings.SearchData.ResultsPageUrl 1509 }); 1510 } 1511 </div> 1512 <div class="search__column search__column--pages dw-mod"> 1513 <div class="search__column-header">@Translate("Pages")</div> 1514 <ul class="search__results-list dw-mod js-search-results-second-list" id="@(settings.Id)_SecondResultsList"></ul> 1515 @if (!string.IsNullOrEmpty(settings.SecondSearchData.ResultsPageUrl)) 1516 { 1517 @Render(new Link 1518 { 1519 Title = Translate("View all"), 1520 CssClass = "js-view-all-button u-margin", 1521 Href = settings.SecondSearchData.ResultsPageUrl 1522 }); 1523 } 1524 </div> 1525 } 1526 else 1527 { 1528 <div class="search__column search__column--only dw-mod"> 1529 <ul class="search__results-list dw-mod js-search-results-list" id="@(settings.Id)_ResultsList"></ul> 1530 @if (!string.IsNullOrEmpty(settings.SearchData.ResultsPageUrl)) 1531 { 1532 @Render(new Link { 1533 Title = Translate("View all"), 1534 CssClass = "js-view-all-button u-margin", 1535 Href = settings.SearchData.ResultsPageUrl 1536 }); 1537 } 1538 </div> 1539 } 1540 </div> 1541 1542 @if (settings.SearchButton != null) 1543 { 1544 settings.SearchButton.CssClass += " search__btn js-search-btn"; 1545 if (settings.RenderDefaultSearchIcon) 1546 { 1547 settings.SearchButton.Icon = new Icon { Name = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("SearchIcon").SelectedValue }; 1548 } 1549 @Render(settings.SearchButton); 1550 } 1551 </div> 1552 } 1553 @using System.Reflection 1554 @using Dynamicweb.Rapido.Blocks.Components.General 1555 @using Dynamicweb.Rapido.Blocks.Components 1556 1557 1558 @* Component *@ 1559 1560 @helper RenderSelectField(SelectField settings) 1561 { 1562 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1563 { 1564 settings.Id = Guid.NewGuid().ToString("N"); 1565 } 1566 1567 <div class="form__field-group u-full-width @settings.WrapperCssClass dw-mod"> 1568 @if (!string.IsNullOrEmpty(settings.Label)) 1569 { 1570 <label for="@settings.Id">@settings.Label</label> 1571 } 1572 @if (!string.IsNullOrEmpty(settings.HelpText)) 1573 { 1574 <small class="form__help-text">@settings.HelpText</small> 1575 } 1576 1577 @if (settings.ActionButton != null) 1578 { 1579 settings.ActionButton.CssClass += " btn--condensed u-no-margin"; 1580 <div class="form__field-combi u-no-margin dw-mod"> 1581 @RenderSelectBase(settings) 1582 @Render(settings.ActionButton) 1583 </div> 1584 } 1585 else 1586 { 1587 @RenderSelectBase(settings) 1588 } 1589 1590 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1591 </div> 1592 } 1593 1594 @helper RenderSelectBase(SelectField settings) 1595 { 1596 var attributes = new Dictionary<string, string>(); 1597 1598 /*base settings*/ 1599 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1600 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1601 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1602 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1603 if (settings.Required) { attributes.Add("required", "true"); } 1604 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1605 /*end*/ 1606 1607 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1608 1609 <select @ComponentMethods.AddAttributes(resultAttributes) class="u-full-width @settings.CssClass dw-mod"> 1610 @if (settings.Default != null) 1611 { 1612 @Render(settings.Default) 1613 } 1614 1615 @foreach (var item in settings.Options) 1616 { 1617 if (settings.Value != null) { 1618 item.Checked = item.Value == settings.Value; 1619 } 1620 @Render(item) 1621 } 1622 </select> 1623 } 1624 @using System.Reflection 1625 @using Dynamicweb.Rapido.Blocks.Components.General 1626 @using Dynamicweb.Rapido.Blocks.Components 1627 1628 @* Component *@ 1629 1630 @helper RenderRadioButtonField(RadioButtonField settings) 1631 { 1632 var attributes = new Dictionary<string, string>(); 1633 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1634 { 1635 settings.Id = Guid.NewGuid().ToString("N"); 1636 } 1637 1638 /*base settings*/ 1639 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1640 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1641 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1642 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1643 if (settings.Required) { attributes.Add("required", "true"); } 1644 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1645 /*end*/ 1646 1647 attributes.Add("type", "radio"); 1648 if (settings.Checked) { attributes.Add("checked", "true"); } 1649 settings.CssClass = "form__control " + settings.CssClass; 1650 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1651 1652 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1653 1654 <div class="form__field-group @settings.WrapperCssClass dw-mod"> 1655 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1656 @if (!string.IsNullOrEmpty(settings.Label)) 1657 { 1658 <label for="@settings.Id" class="dw-mod">@settings.Label</label> 1659 } 1660 @if (!string.IsNullOrEmpty(settings.HelpText)) 1661 { 1662 <small class="form__help-text">@settings.HelpText</small> 1663 } 1664 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1665 </div> 1666 } 1667 @using System.Reflection 1668 @using Dynamicweb.Rapido.Blocks.Components.General 1669 @using Dynamicweb.Rapido.Blocks.Components 1670 1671 1672 @* Component *@ 1673 1674 @helper RenderRadioButtonListField(RadioButtonListField settings) 1675 { 1676 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1677 1678 <div class="form__field-group @settings.WrapperCssClass u-margin-bottom dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1679 @if (!string.IsNullOrEmpty(settings.Label)) 1680 { 1681 <label>@settings.Label</label> 1682 } 1683 @if (!string.IsNullOrEmpty(settings.HelpText)) 1684 { 1685 <small class="form__help-text">@settings.HelpText</small> 1686 } 1687 1688 @foreach (var item in settings.Options) 1689 { 1690 if (settings.Required) 1691 { 1692 item.Required = true; 1693 } 1694 if (settings.Disabled) 1695 { 1696 item.Disabled = true; 1697 } 1698 if (!string.IsNullOrEmpty(settings.Name)) 1699 { 1700 item.Name = settings.Name; 1701 } 1702 if (settings.Value != null && settings.Value == item.Value) 1703 { 1704 item.Checked = true; 1705 } 1706 if (!string.IsNullOrEmpty(settings.OnClick)) 1707 { 1708 item.OnClick += settings.OnClick; 1709 } 1710 if (!string.IsNullOrEmpty(settings.OnChange)) 1711 { 1712 item.OnChange += settings.OnChange; 1713 } 1714 if (!string.IsNullOrEmpty(settings.CssClass)) 1715 { 1716 item.CssClass += settings.CssClass; 1717 } 1718 @Render(item) 1719 } 1720 1721 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1722 </div> 1723 } 1724 @using System.Reflection 1725 @using Dynamicweb.Rapido.Blocks.Components.General 1726 @using Dynamicweb.Rapido.Blocks.Components 1727 1728 1729 @* Component *@ 1730 1731 @helper RenderNotificationMessage(NotificationMessage settings) 1732 { 1733 if (!string.IsNullOrEmpty(settings.Message)) 1734 { 1735 var attributes = new Dictionary<string, string>(); 1736 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1737 1738 string messageTypeClass = Enum.GetName(typeof(NotificationMessageType), settings.MessageType).ToLower(); 1739 <div class="field-@messageTypeClass @settings.CssClass u-full-width dw-mod" @ComponentMethods.AddAttributes(attributes)>@settings.Message</div> 1740 } 1741 } 1742 @using Dynamicweb.Rapido.Blocks.Components.General 1743 1744 1745 @* Component *@ 1746 1747 @helper RenderHandlebarsRoot(HandlebarsRoot settings) { 1748 string preRender = !String.IsNullOrEmpty(settings.PreRenderScriptTemplate) ? "data-pre-render-template=\"" + settings.PreRenderScriptTemplate + "\"" : ""; 1749 1750 <div class="@settings.CssClass dw-mod js-handlebars-root" id="@settings.Id" data-template="@settings.ScriptTemplate" data-json-feed="@settings.FeedUrl" data-init-onload="@settings.InitOnLoad.ToString()" data-preloader="@settings.Preloader" @preRender> 1751 @if (settings.SubBlocks != null) { 1752 @RenderBlockList(settings.SubBlocks) 1753 } 1754 </div> 1755 } 1756 @using System.Reflection 1757 @using Dynamicweb.Rapido.Blocks.Components.General 1758 @using Dynamicweb.Rapido.Blocks.Components 1759 @using System.Text.RegularExpressions 1760 1761 1762 @* Component *@ 1763 1764 @helper RenderSticker(Sticker settings) { 1765 if (!String.IsNullOrEmpty(settings.Title)) { 1766 string size = settings.Size.ToString() != "None" ? "" + "stickers-container__tag--" + settings.Size.ToString().ToLower() : ""; 1767 string style = settings.Style.ToString() != "None" ? "" + "stickers-container__tag--" + settings.Style.ToString().ToLower() : ""; 1768 1769 Dictionary<String, String> optionalAttributes = new Dictionary<string, string>(); 1770 if (!String.IsNullOrEmpty(settings.Color) || !String.IsNullOrEmpty(settings.BackgroundColor)) { 1771 string styleTag = !String.IsNullOrEmpty(settings.Color) ? "color: " + settings.Color + "; " : ""; 1772 styleTag += !String.IsNullOrEmpty(settings.BackgroundColor) ? "background-color: " + settings.BackgroundColor + "; " : ""; 1773 optionalAttributes.Add("style", styleTag); 1774 } 1775 1776 <div class="stickers-container__tag @size @style @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(optionalAttributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@settings.Title</div> 1777 } 1778 } 1779 1780 @using System.Reflection 1781 @using Dynamicweb.Rapido.Blocks.Components.General 1782 @using Dynamicweb.Rapido.Blocks.Components 1783 1784 1785 @* Component *@ 1786 1787 @helper RenderStickersCollection(StickersCollection settings) 1788 { 1789 if (settings.Stickers.Count > 0) 1790 { 1791 string position = "stickers-container--" + Regex.Replace(settings.Position.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower(); 1792 1793 <div class="stickers-container @position @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1794 @foreach (Sticker sticker in settings.Stickers) 1795 { 1796 @Render(sticker) 1797 } 1798 </div> 1799 } 1800 } 1801 1802 @using Dynamicweb.Rapido.Blocks.Components.General 1803 1804 1805 @* Component *@ 1806 1807 @helper RenderForm(Form settings) { 1808 if (settings != null) 1809 { 1810 Dictionary<string, string> optionalAttributes = new Dictionary<string, string>(); 1811 if (!string.IsNullOrEmpty(settings.Action)) { optionalAttributes.Add("action", settings.Action); }; 1812 if (!string.IsNullOrEmpty(settings.Name)) { optionalAttributes.Add("name", settings.Name); }; 1813 if (!string.IsNullOrEmpty(settings.OnSubmit)) { optionalAttributes.Add("onsubmit", settings.OnSubmit); }; 1814 var enctypes = new Dictionary<string, string> 1815 { 1816 { "multipart", "multipart/form-data" }, 1817 { "text", "text/plain" }, 1818 { "application", "application/x-www-form-urlencoded" } 1819 }; 1820 if (settings.Enctype != FormEnctype.none) { optionalAttributes.Add("enctype", enctypes[Enum.GetName(typeof(FormEnctype), settings.Enctype).ToLower()]); }; 1821 optionalAttributes.Add("method", settings.Method.ToString()); 1822 1823 if (!string.IsNullOrEmpty(settings.FormStartMarkup)) 1824 { 1825 @settings.FormStartMarkup 1826 } 1827 else 1828 { 1829 @:<form class="@settings.CssClass u-no-margin dw-mod" @ComponentMethods.AddAttributes(optionalAttributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1830 } 1831 1832 foreach (var field in settings.GetFields()) 1833 { 1834 @Render(field) 1835 } 1836 1837 @:</form> 1838 } 1839 } 1840 @using System.Reflection 1841 @using Dynamicweb.Rapido.Blocks.Components.General 1842 @using Dynamicweb.Rapido.Blocks.Components 1843 1844 1845 @* Component *@ 1846 1847 @helper RenderText(Text settings) 1848 { 1849 @settings.Content 1850 } 1851 @using System.Reflection 1852 @using Dynamicweb.Rapido.Blocks.Components.General 1853 @using Dynamicweb.Rapido.Blocks.Components 1854 1855 1856 @* Component *@ 1857 1858 @helper RenderContentModule(ContentModule settings) { 1859 if (!string.IsNullOrEmpty(settings.Content)) 1860 { 1861 @settings.Content 1862 } 1863 } 1864 @using System.Reflection 1865 @using Dynamicweb.Rapido.Blocks.Components.General 1866 @using Dynamicweb.Rapido.Blocks.Components 1867 1868 1869 @* Component *@ 1870 1871 @helper RenderModal(Modal settings) { 1872 if (settings != null) 1873 { 1874 string modalId = !string.IsNullOrEmpty(settings.Id) ? settings.Id : Guid.NewGuid().ToString("N"); 1875 1876 string onchange = !string.IsNullOrEmpty(settings.OnClose) ? "onchange=\"if(!this.checked){" + settings.OnClose + "}\"" : ""; 1877 1878 <input type="checkbox" id="@(modalId)ModalTrigger" class="modal-trigger" @onchange /> 1879 1880 <div class="modal-container"> 1881 @if (!settings.DisableDarkOverlay) 1882 { 1883 <label for="@(modalId)ModalTrigger" id="@(modalId)ModalOverlay" class="modal-overlay"></label> 1884 } 1885 <div class="modal modal--@settings.Width.ToString().ToLower() modal-height--@settings.Height.ToString().ToLower()" id="@(modalId)Modal"> 1886 @if (settings.Heading != null) 1887 { 1888 if (!string.IsNullOrEmpty(settings.Heading.Title)) 1889 { 1890 <div class="modal__header"> 1891 @Render(settings.Heading) 1892 </div> 1893 } 1894 } 1895 <div class="modal__body @(settings.Width.ToString().ToLower() == "full" ? "modal__body--full" : "")"> 1896 @if (!string.IsNullOrEmpty(settings.BodyText)) 1897 { 1898 @settings.BodyText 1899 } 1900 @if (settings.BodyTemplate != null) 1901 { 1902 @settings.BodyTemplate 1903 } 1904 @{ 1905 var actions = settings.GetActions(); 1906 } 1907 </div> 1908 @if (actions.Length > 0) 1909 { 1910 <div class="modal__footer"> 1911 @foreach (var action in actions) 1912 { 1913 if (Pageview.Device.ToString() != "Mobile") { 1914 action.CssClass += " u-no-margin"; 1915 } else { 1916 action.CssClass += " u-full-width u-margin-bottom"; 1917 } 1918 1919 @Render(action) 1920 } 1921 </div> 1922 } 1923 <label class="modal__close-btn" for="@(modalId)ModalTrigger"></label> 1924 </div> 1925 </div> 1926 } 1927 } 1928 @using Dynamicweb.Rapido.Blocks.Components.General 1929 1930 @* Component *@ 1931 1932 @helper RenderMediaListItem(MediaListItem settings) 1933 { 1934 <div class="media-list-item @settings.CssClass dw-mod" @(!string.IsNullOrEmpty(settings.Id) ? "id=\"" + settings.Id + "\"" : "")> 1935 @if (!string.IsNullOrEmpty(settings.Label)) 1936 { 1937 if (!string.IsNullOrEmpty(settings.Link)) 1938 { 1939 @Render(new Link 1940 { 1941 Href = settings.Link, 1942 CssClass = "media-list-item__sticker dw-mod", 1943 ButtonLayout = ButtonLayout.None, 1944 Title = settings.Label, 1945 OnClick = !string.IsNullOrEmpty(settings.OnClick) ? settings.OnClick : "" 1946 }) 1947 } 1948 else if (!string.IsNullOrEmpty(settings.OnClick)) 1949 { 1950 <span class="media-list-item__sticker dw-mod" onclick="@(settings.OnClick)"> 1951 <span class="u-uppercase">@settings.Label</span> 1952 </span> 1953 } 1954 else 1955 { 1956 <span class="media-list-item__sticker media-list-item__sticker--no-link dw-mod"> 1957 <span class="u-uppercase">@settings.Label</span> 1958 </span> 1959 } 1960 } 1961 <div class="media-list-item__wrap"> 1962 <div class="media-list-item__info dw-mod"> 1963 <div class="media-list-item__header dw-mod"> 1964 @if (!string.IsNullOrEmpty(settings.Title)) 1965 { 1966 if (!string.IsNullOrEmpty(settings.Link)) 1967 { 1968 @Render(new Link 1969 { 1970 Href = settings.Link, 1971 CssClass = "media-list-item__name dw-mod", 1972 ButtonLayout = ButtonLayout.None, 1973 Title = settings.Title, 1974 OnClick = !string.IsNullOrEmpty(settings.OnClick) ? settings.OnClick : "" 1975 }) 1976 } 1977 else if (!string.IsNullOrEmpty(settings.OnClick)) 1978 { 1979 <span class="media-list-item__name dw-mod" onclick="@(settings.OnClick)">@settings.Title</span> 1980 } 1981 else 1982 { 1983 <span class="media-list-item__name media-list-item__name--no-link dw-mod">@settings.Title</span> 1984 } 1985 } 1986 1987 @if (!string.IsNullOrEmpty(settings.Status)) 1988 { 1989 <div class="media-list-item__state dw-mod">@settings.Status</div> 1990 } 1991 </div> 1992 @{ 1993 settings.InfoTable.CssClass += " media-list-item__parameters-table"; 1994 } 1995 1996 @Render(settings.InfoTable) 1997 </div> 1998 <div class="media-list-item__actions dw-mod"> 1999 <div class="media-list-item__actions-list dw-mod"> 2000 @{ 2001 var actions = settings.GetActions(); 2002 2003 foreach (ButtonBase action in actions) 2004 { 2005 action.ButtonLayout = ButtonLayout.None; 2006 action.CssClass += " media-list-item__action link"; 2007 2008 @Render(action) 2009 } 2010 } 2011 </div> 2012 2013 @if (settings.SelectButton != null && !string.IsNullOrEmpty(settings.SelectButton.Title)) 2014 { 2015 settings.SelectButton.CssClass += " u-no-margin"; 2016 2017 <div class="media-list-item__action-button"> 2018 @Render(settings.SelectButton) 2019 </div> 2020 } 2021 </div> 2022 </div> 2023 </div> 2024 } 2025 @using Dynamicweb.Rapido.Blocks.Components.General 2026 @using Dynamicweb.Rapido.Blocks.Components 2027 2028 @helper RenderTable(Table settings) 2029 { 2030 Dictionary<string, string> attributes = new Dictionary<string, string>(); 2031 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2032 2033 var enumToClasses = new Dictionary<TableDesign, string> 2034 { 2035 { TableDesign.Clean, "table--clean" }, 2036 { TableDesign.Bordered, "table--bordered" }, 2037 { TableDesign.Striped, "table--striped" }, 2038 { TableDesign.Hover, "table--hover" }, 2039 { TableDesign.Compact, "table--compact" }, 2040 { TableDesign.Condensed, "table--condensed" }, 2041 { TableDesign.NoTopBorder, "table--no-top-border" } 2042 }; 2043 string tableDesignClass = ""; 2044 if (settings.Design != TableDesign.None) 2045 { 2046 tableDesignClass = enumToClasses[settings.Design]; 2047 } 2048 2049 if (!string.IsNullOrEmpty(settings.CssClass) || settings.Design != TableDesign.None) { attributes.Add("class", "table " + tableDesignClass + " " + settings.CssClass + " dw-mod"); } 2050 2051 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.Last().Value); 2052 2053 <table @ComponentMethods.AddAttributes(resultAttributes)> 2054 @if (settings.Header != null) 2055 { 2056 <thead> 2057 @Render(settings.Header) 2058 </thead> 2059 } 2060 <tbody> 2061 @foreach (var row in settings.Rows) 2062 { 2063 @Render(row) 2064 } 2065 </tbody> 2066 @if (settings.Footer != null) 2067 { 2068 <tfoot> 2069 @Render(settings.Footer) 2070 </tfoot> 2071 } 2072 </table> 2073 } 2074 @using Dynamicweb.Rapido.Blocks.Components.General 2075 @using Dynamicweb.Rapido.Blocks.Components 2076 2077 @helper RenderTableRow(TableRow settings) 2078 { 2079 Dictionary<string, string> attributes = new Dictionary<string, string>(); 2080 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2081 2082 var enumToClasses = new Dictionary<TableRowDesign, string> 2083 { 2084 { TableRowDesign.NoBorder, "table__row--no-border" }, 2085 { TableRowDesign.Border, "table__row--border" }, 2086 { TableRowDesign.TopBorder, "table__row--top-line" }, 2087 { TableRowDesign.BottomBorder, "table__row--bottom-line" }, 2088 { TableRowDesign.Solid, "table__row--solid" } 2089 }; 2090 2091 string tableRowDesignClass = ""; 2092 if (settings.Design != TableRowDesign.None) 2093 { 2094 tableRowDesignClass = enumToClasses[settings.Design]; 2095 } 2096 2097 if (!string.IsNullOrEmpty(settings.CssClass) || settings.Design != TableRowDesign.None) { attributes.Add("class", "table__row " + tableRowDesignClass + " " + settings.CssClass + " dw-mod"); } 2098 2099 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.Last().Value); 2100 2101 <tr @ComponentMethods.AddAttributes(resultAttributes)> 2102 @foreach (var cell in settings.Cells) 2103 { 2104 if (settings.IsHeaderRow) 2105 { 2106 cell.IsHeader = true; 2107 } 2108 @Render(cell) 2109 } 2110 </tr> 2111 } 2112 @using Dynamicweb.Rapido.Blocks.Components.General 2113 @using Dynamicweb.Rapido.Blocks.Components 2114 @using Dynamicweb.Core 2115 2116 @helper RenderTableCell(TableCell settings) 2117 { 2118 Dictionary<string, string> attributes = new Dictionary<string, string>(); 2119 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2120 if (settings.Colspan != 0) { attributes.Add("colspan", Converter.ToString(settings.Colspan)); } 2121 if (settings.Rowspan != 0) { attributes.Add("rowspan", Converter.ToString(settings.Rowspan)); } 2122 if (!string.IsNullOrEmpty(settings.CssClass)) { attributes.Add("class", settings.CssClass + " dw-mod"); } 2123 2124 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.Last().Value); 2125 2126 string tagName = settings.IsHeader ? "th" : "td"; 2127 2128 @("<" + tagName + " " + ComponentMethods.AddAttributes(resultAttributes) + ">") 2129 @settings.Content 2130 @("</" + tagName + ">"); 2131 } 2132 @using System.Linq 2133 @using Dynamicweb.Rapido.Blocks.Components.General 2134 2135 @* Component *@ 2136 2137 @helper RenderPagination(Dynamicweb.Rapido.Blocks.Components.General.Pagination settings) 2138 { 2139 var pageNumberQueryStringName = Dynamicweb.Rapido.Services.Pagination.GetPageNumberQueryStringName(settings); // Get the proper 'page number' query string parameter 2140 var queryParameters = Dynamicweb.Rapido.Services.Url.GetQueryParameters(pageNumberQueryStringName); // Get the NameValueCollection from the querystring 2141 2142 if (settings.NumberOfPages > 1) 2143 { 2144 string url = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + "/Default.aspx"; 2145 string ariaLabel = !string.IsNullOrWhiteSpace(settings.AriaLabel) ? settings.AriaLabel : Translate("Page navigation"); 2146 Dictionary<string, int> startAndEndPageNumber = Dynamicweb.Rapido.Services.Pagination.GetStartAndEndPageNumber(settings); 2147 2148 <div class="pager u-margin-top dw-mod @settings.CssClass" aria-label="@ariaLabel"> 2149 @if (settings.ShowPagingInfo) 2150 { 2151 <div class="pager__info dw-mod"> 2152 @Translate("Page") @settings.CurrentPageNumber @Translate("of") @settings.NumberOfPages 2153 </div> 2154 } 2155 <ul class="pager__list dw-mod"> 2156 @if (!string.IsNullOrWhiteSpace(settings.FirstPageUrl) && settings.ShowFirstAndLastControls) 2157 { 2158 @Render(new PaginationItem { Link = settings.FirstPageUrl, Icon = settings.FirstIcon }) 2159 } 2160 @if (!string.IsNullOrWhiteSpace(settings.PreviousPageUrl) && settings.ShowNextAndPrevControls) 2161 { 2162 @Render(new PaginationItem { Link = settings.PreviousPageUrl, Icon = settings.PrevIcon }) 2163 } 2164 @if (settings.GetPages().Any()) 2165 { 2166 foreach (var page in settings.GetPages()) 2167 { 2168 @Render(page) 2169 } 2170 } 2171 else 2172 { 2173 for (var page = startAndEndPageNumber["StartPage"]; page <= startAndEndPageNumber["EndPage"]; page++) 2174 { 2175 queryParameters = Dynamicweb.Rapido.Services.Url.UpdateQueryStringParameter(queryParameters, pageNumberQueryStringName, page.ToString()); 2176 @Render(new PaginationItem { Label = page.ToString(), Link = Dynamicweb.Rapido.Services.Url.BuildUri(url, queryParameters).PathAndQuery, IsActive = (settings.CurrentPageNumber == page) }); 2177 } 2178 } 2179 @if (!string.IsNullOrWhiteSpace(settings.NextPageUrl) && settings.ShowNextAndPrevControls) 2180 { 2181 @Render(new PaginationItem { Link = settings.NextPageUrl, Icon = settings.NextIcon }) 2182 } 2183 @if (!string.IsNullOrWhiteSpace(settings.LastPageUrl) && settings.ShowFirstAndLastControls) 2184 { 2185 @Render(new PaginationItem { Link = settings.LastPageUrl, Icon = settings.LastIcon }) 2186 } 2187 </ul> 2188 </div> 2189 } 2190 } 2191 2192 @helper RenderPaginationItem(PaginationItem settings) 2193 { 2194 if (settings.Icon == null) 2195 { 2196 settings.Icon = new Icon(); 2197 } 2198 2199 settings.Icon.Label = settings.Label; 2200 <li class="pager__btn dw-mod"> 2201 @if (settings.IsActive) 2202 { 2203 <span class="pager__num pager__num--current dw-mod"> 2204 @Render(settings.Icon) 2205 </span> 2206 } 2207 else 2208 { 2209 <a href="@settings.Link" class="pager__num dw-mod"> 2210 @Render(settings.Icon) 2211 </a> 2212 } 2213 </li> 2214 } 2215 2216 2217 @using Dynamicweb.Rapido.Blocks.Components.General 2218 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2219 2220 2221 @using Dynamicweb.Rapido.Blocks.Components 2222 @using Dynamicweb.Rapido.Blocks.Components.General 2223 @using Dynamicweb.Rapido.Blocks 2224 @using System.IO 2225 2226 2227 @using Dynamicweb.Rapido.Blocks.Components.General 2228 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2229 2230 2231 @* Component *@ 2232 2233 @helper RenderVariantMatrix(VariantMatrix settings) { 2234 if (settings != null) 2235 { 2236 int productLoopCounter = 0; 2237 int groupCount = 0; 2238 List<VariantOption> firstDimension = new List<VariantOption>(); 2239 List<VariantOption> secondDimension = new List<VariantOption>(); 2240 List<VariantOption> thirdDimension = new List<VariantOption>(); 2241 2242 foreach (VariantGroup variantGroup in settings.GetVariantGroups()) 2243 { 2244 foreach (VariantOption variantOptions in variantGroup.GetVariantOptions()) 2245 { 2246 if (groupCount == 0) { 2247 firstDimension.Add(variantOptions); 2248 } 2249 if (groupCount == 1) 2250 { 2251 secondDimension.Add(variantOptions); 2252 } 2253 if (groupCount == 2) 2254 { 2255 thirdDimension.Add(variantOptions); 2256 } 2257 } 2258 groupCount++; 2259 } 2260 2261 int rowCount = 0; 2262 int columnCount = 0; 2263 2264 <script> 2265 var variantsCollection = []; 2266 </script> 2267 2268 <table class="table table--compact js-variants-matrix dw-mod" id="VariantMatrixTable_@settings.ProductId"> 2269 @if (groupCount == 1) 2270 { 2271 <tbody> 2272 @foreach (VariantOption firstVariantOption in firstDimension) 2273 { 2274 var variantId = firstVariantOption.Id; 2275 <tr> 2276 <td class="u-bold"> 2277 @firstVariantOption.Name 2278 </td> 2279 <td> 2280 @RenderVariantMatrixQuantityField(variantId, settings, productLoopCounter, rowCount, columnCount) 2281 </td> 2282 </tr> 2283 productLoopCounter++; 2284 } 2285 2286 <tr> 2287 <td>&nbsp;</td> 2288 <td> 2289 <div class="qty-field js-total-qty-column-@columnCount dw-mod">0</div> 2290 </td> 2291 </tr> 2292 </tbody> 2293 } 2294 @if (groupCount == 2) 2295 { 2296 <thead> 2297 <tr> 2298 <td>&nbsp;</td> 2299 @foreach (VariantOption variant in secondDimension) 2300 { 2301 <td>@variant.Name</td> 2302 } 2303 </tr> 2304 </thead> 2305 <tbody> 2306 @foreach (VariantOption firstVariantOption in firstDimension) 2307 { 2308 string variantId = ""; 2309 columnCount = 0; 2310 2311 <tr> 2312 <td class="u-min-w120px">@firstVariantOption.Name</td> 2313 2314 @foreach (VariantOption secondVariantOption in secondDimension) 2315 { 2316 variantId = firstVariantOption.Id + "." + secondVariantOption.Id; 2317 <td> 2318 @RenderVariantMatrixQuantityField(variantId, settings, productLoopCounter, rowCount, columnCount) 2319 </td> 2320 2321 columnCount++; 2322 2323 productLoopCounter++; 2324 } 2325 2326 <td> 2327 <div class="qty-field js-total-qty-row-@rowCount dw-mod">0</div> 2328 </td> 2329 </tr> 2330 2331 rowCount++; 2332 } 2333 2334 @{ 2335 columnCount = 0; 2336 } 2337 2338 <tr> 2339 <td>&nbsp;</td> 2340 @foreach (VariantOption secondVariantOption in secondDimension) 2341 { 2342 <td> 2343 <div class="qty-field js-total-qty-column-@columnCount dw-mod">0</div> 2344 </td> 2345 2346 columnCount++; 2347 } 2348 <td>&nbsp;</td> 2349 </tr> 2350 </tbody> 2351 } 2352 @if (groupCount == 3) 2353 { 2354 <thead> 2355 <tr> 2356 <td>&nbsp;</td> 2357 @foreach (VariantOption thirdVariantOption in thirdDimension) 2358 { 2359 <td>@thirdVariantOption.Name</td> 2360 } 2361 </tr> 2362 </thead> 2363 <tbody> 2364 @foreach (VariantOption firstVariantOption in firstDimension) 2365 { 2366 int colspan = (thirdDimension.Count + 1); 2367 2368 <tr> 2369 <td colspan="@colspan" class="u-color-light-gray--bg u-bold">@firstVariantOption.Name</td> 2370 </tr> 2371 2372 foreach (VariantOption secondVariantOption in secondDimension) 2373 { 2374 string variantId = ""; 2375 columnCount = 0; 2376 2377 <tr> 2378 <td class="u-min-w120px">@secondVariantOption.Name</td> 2379 2380 @foreach (VariantOption thirdVariantOption in thirdDimension) 2381 { 2382 variantId = firstVariantOption.Id + "." + secondVariantOption.Id + "." + thirdVariantOption.Id; 2383 2384 <td> 2385 @RenderVariantMatrixQuantityField(variantId, settings, productLoopCounter, rowCount, columnCount) 2386 </td> 2387 2388 columnCount++; 2389 productLoopCounter++; 2390 } 2391 2392 <td> 2393 <div class="qty-field js-total-qty-row-@rowCount dw-mod">0</div> 2394 </td> 2395 </tr> 2396 rowCount++; 2397 } 2398 } 2399 2400 @{ 2401 columnCount = 0; 2402 } 2403 2404 <tr> 2405 <td>&nbsp;</td> 2406 @foreach (VariantOption thirdVariantOption in thirdDimension) 2407 { 2408 <td> 2409 <div class="qty-field js-total-qty-column-@columnCount dw-mod">0</div> 2410 </td> 2411 2412 columnCount++; 2413 } 2414 <td>&nbsp;</td> 2415 </tr> 2416 </tbody> 2417 } 2418 </table> 2419 2420 <script> 2421 document.addEventListener("DOMContentLoaded", function (event) { 2422 MatrixUpdateQuantity("@settings.ProductId"); 2423 }); 2424 2425 MatrixUpdateQuantity = function (productId) { 2426 var currentMatrix = document.getElementById("VariantMatrixTable_" + productId); 2427 var allQtyFields = currentMatrix.getElementsByClassName("js-qty"); 2428 2429 var qtyRowArr = []; 2430 var qtyColumnArr = []; 2431 2432 var totalQty = 0; 2433 2434 for (var i = 0; i < allQtyFields.length; i++) { 2435 qtyRowArr[allQtyFields[i].getAttribute("data-qty-row-group")] = 0; 2436 qtyColumnArr[allQtyFields[i].getAttribute("data-qty-column-group")] = 0; 2437 } 2438 2439 for (var i = 0; i < allQtyFields.length; i++) { 2440 qtyRowArr[allQtyFields[i].getAttribute("data-qty-row-group")] += parseFloat(allQtyFields[i].value); 2441 qtyColumnArr[allQtyFields[i].getAttribute("data-qty-column-group")] += parseFloat(allQtyFields[i].value); 2442 totalQty += parseFloat(allQtyFields[i].value); 2443 } 2444 2445 //Update row counters 2446 for (var i = 0; i < qtyRowArr.length; i++) { 2447 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-row-" + i)[0]; 2448 2449 if (qtyRowArr[i] != undefined && qtyCounter != null) { 2450 var currentCount = qtyCounter.innerHTML; 2451 qtyCounter.innerHTML = qtyRowArr[i]; 2452 2453 if (currentCount != qtyCounter.innerHTML) { 2454 qtyCounter.classList.add("qty-field--active"); 2455 } 2456 } 2457 2458 } 2459 2460 //Update column counters 2461 for (var i = 0; i < qtyColumnArr.length; i++) { 2462 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-column-" + i)[0]; 2463 2464 if (qtyColumnArr[i] != undefined && qtyCounter != null) { 2465 var currentCount = qtyCounter.innerHTML; 2466 qtyCounter.innerHTML = qtyColumnArr[i]; 2467 2468 if (currentCount != qtyCounter.innerHTML) { 2469 qtyCounter.classList.add("qty-field--active"); 2470 } 2471 } 2472 } 2473 2474 if (document.getElementById("TotalQtyCount_" + productId)) { 2475 document.getElementById("TotalQtyCount_" + productId).innerHTML = totalQty; 2476 } 2477 2478 //Clean up animations 2479 setTimeout(function () { 2480 for (var i = 0; i < qtyRowArr.length; i++) { 2481 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-row-" + i)[0]; 2482 if (qtyCounter != null) { 2483 qtyCounter.classList.remove("qty-field--active"); 2484 } 2485 } 2486 for (var i = 0; i < qtyColumnArr.length; i++) { 2487 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-column-" + i)[0]; 2488 if (qtyCounter != null) { 2489 qtyCounter.classList.remove("qty-field--active"); 2490 } 2491 } 2492 }, 1000); 2493 } 2494 </script> 2495 } 2496 } 2497 2498 @helper RenderVariantMatrixQuantityField(string variantId, VariantMatrix settings, int productLoopCounter, int rowCount, int columnCount) 2499 { 2500 string loopCount = productLoopCounter.ToString(); 2501 2502 bool combinationFound = false; 2503 double stock = 0; 2504 double quantityValue = 0; 2505 string note = ""; 2506 2507 VariantProduct variantProduct = null; 2508 2509 if (settings.GetVariantProducts().TryGetValue(variantId, out variantProduct)) 2510 { 2511 stock = variantProduct.Stock; 2512 quantityValue = variantProduct.Quantity; 2513 combinationFound = true; 2514 } 2515 2516 if (combinationFound) 2517 { 2518 <input type="hidden" name="ProductLoopCounter@(loopCount)" value="@loopCount" /> 2519 <input type="hidden" name="ProductID@(loopCount)" value="@settings.ProductId" /> 2520 <input type="hidden" name="VariantID@(loopCount)" value="@variantId" /> 2521 <input type="hidden" name="CurrentNote@(loopCount)" id="CurrentNote_@(settings.ProductId)_@variantId" value="@note" /> 2522 <input type="number" name="Quantity@(loopCount)" id="Quantity_@(settings.ProductId)_@variantId" value="@quantityValue" min="0" class="js-qty u-no-margin u-full-max-width" style="width: 100%; max-width: 100%" onkeyup="MatrixUpdateQuantity('@settings.ProductId')" onmouseup="MatrixUpdateQuantity('@settings.ProductId')" data-qty-row-group="@rowCount" data-qty-column-group="@columnCount"> 2523 2524 if (stock != 0) 2525 { 2526 <small>@Translate("Stock") @stock</small> 2527 } 2528 2529 <script> 2530 var variants = '{ "ProductId" :' + '"@settings.ProductId"' + ', "VariantId": ' + '"@variantId"' +'}'; 2531 variantsCollection.push(variants); 2532 document.getElementById("Quantity_@(settings.ProductId)_@variantId").closest(".js-variants-matrix").setAttribute("data-variants-collection", "[" + variantsCollection + "]" ); 2533 </script> 2534 } 2535 else 2536 { 2537 <div class="use-btn-height" style="background-color: #a8a8a8"></div> 2538 } 2539 } 2540 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2541 2542 @* Component *@ 2543 2544 @helper RenderAddToCart(AddToCart settings) 2545 { 2546 //set Id for quantity selector to get it's value from button 2547 if (settings.QuantitySelector != null) 2548 { 2549 if (string.IsNullOrEmpty(settings.QuantitySelector.Id)) 2550 { 2551 settings.QuantitySelector.Id = Guid.NewGuid().ToString("N"); 2552 } 2553 2554 settings.AddButton.QuantitySelectorId = settings.QuantitySelector.Id; 2555 2556 if (settings.Disabled) 2557 { 2558 settings.QuantitySelector.Disabled = true; 2559 } 2560 2561 if (string.IsNullOrEmpty(settings.QuantitySelector.Name)) 2562 { 2563 settings.QuantitySelector.Name = settings.QuantitySelector.Id; 2564 } 2565 } 2566 2567 if (settings.Disabled) 2568 { 2569 settings.AddButton.Disabled = true; 2570 } 2571 2572 settings.AddButton.CssClass += " btn--condensed"; 2573 2574 //unitsSelector 2575 if (settings.UnitSelector != null) 2576 { 2577 if (settings.Disabled) 2578 { 2579 settings.QuantitySelector.Disabled = true; 2580 } 2581 } 2582 2583 <div class="buttons-collection @settings.WrapperCssClass" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 2584 @if (settings.UnitSelector != null) 2585 { 2586 @Render(settings.UnitSelector) 2587 } 2588 @if (settings.QuantitySelector != null) 2589 { 2590 @Render(settings.QuantitySelector) 2591 } 2592 @Render(settings.AddButton) 2593 </div> 2594 } 2595 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2596 2597 @* Component *@ 2598 2599 @helper RenderAddToCartButton(AddToCartButton settings) 2600 { 2601 if (!settings.HideTitle) 2602 { 2603 if (string.IsNullOrEmpty(settings.Title)) 2604 { 2605 if (settings.BuyForPoints) 2606 { 2607 settings.Title = Translate("Buy with points"); 2608 } 2609 else 2610 { 2611 settings.Title = Translate("Add to cart"); 2612 } 2613 } 2614 } 2615 else 2616 { 2617 settings.Title = ""; 2618 } 2619 2620 if (settings.Icon == null) 2621 { 2622 settings.Icon = new Icon(); 2623 settings.Icon.LabelPosition = Dynamicweb.Rapido.Blocks.Components.General.IconLabelPosition.After; 2624 } 2625 2626 if (string.IsNullOrEmpty(settings.Icon.Name)) 2627 { 2628 settings.Icon.Name = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue; 2629 } 2630 2631 settings.OnClick = "Cart.AddToCart(event, { " + 2632 "id: '" + settings.ProductId + "'," + 2633 (!string.IsNullOrEmpty(settings.VariantId) ? "variantId: '" + settings.VariantId + "'," : "") + 2634 (!string.IsNullOrEmpty(settings.UnitId) ? "unitId: '" + settings.UnitId + "'," : "") + 2635 (settings.BuyForPoints ? "buyForPoints: true," : "") + 2636 (!string.IsNullOrEmpty(settings.ProductInfo) ? "productInfo: " + settings.ProductInfo + "," : "") + 2637 "quantity: " + (string.IsNullOrEmpty(settings.QuantitySelectorId) ? "1" : "parseFloat(document.getElementById('" + settings.QuantitySelectorId + "').value)") + 2638 "});" + settings.OnClick; 2639 2640 @RenderButton(settings) 2641 } 2642 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2643 2644 @* Component *@ 2645 2646 @helper RenderUnitSelector(UnitSelector settings) 2647 { 2648 if (string.IsNullOrEmpty(settings.Id)) 2649 { 2650 settings.Id = Guid.NewGuid().ToString("N"); 2651 } 2652 var disabledClass = settings.Disabled ? "disabled" : ""; 2653 2654 <input type="checkbox" id="@settings.Id" class="dropdown-trigger" /> 2655 <div class="dropdown unit-selector @settings.CssClass @disabledClass dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 2656 <label class="dropdown__header dropdown__btn dropdown__btn--unit-selector dw-mod" for="@settings.Id">@settings.SelectedOption</label> 2657 <div class="dropdown__content dw-mod"> 2658 @settings.OptionsContent 2659 </div> 2660 <label class="dropdown-trigger-off" for="@settings.Id"></label> 2661 </div> 2662 } 2663 @using System.Reflection 2664 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2665 2666 @* Component *@ 2667 2668 @helper RenderQuantitySelector(QuantitySelector settings) 2669 { 2670 var attributes = new Dictionary<string, string>(); 2671 2672 /*base settings*/ 2673 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2674 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 2675 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 2676 if (settings.Disabled) { attributes.Add("disabled", "true"); } 2677 if (settings.Required) { attributes.Add("required", "true"); } 2678 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 2679 /*end*/ 2680 2681 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 2682 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 2683 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 2684 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 2685 if (settings.Max != null) { attributes.Add("max", settings.Max.ToString()); } 2686 if (settings.Min == null) { settings.Min = 1; } 2687 attributes.Add("min", settings.Min.ToString()); 2688 if (settings.Step != null && !string.IsNullOrEmpty(settings.Step.ToString())) { attributes.Add("step", settings.Step.ToString()); } 2689 if (settings.Value == null) { settings.Value = 1; } 2690 attributes.Add("value", settings.Value.ToString()); 2691 attributes.Add("type", "number"); 2692 2693 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2694 2695 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 2696 } 2697 @using Dynamicweb.Rapido.Blocks.Components 2698 2699 @using Dynamicweb.Frontend 2700 @using Dynamicweb.Frontend.Devices 2701 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2702 @using Dynamicweb.Rapido.Blocks.Components.General 2703 @using System.Collections.Generic; 2704 2705 @* Component *@ 2706 2707 @helper RenderCustomerCenterList(CustomerCenterList settings) 2708 { 2709 bool isTouchDevice = Pageview.Device.ToString() == "Mobile" || Pageview.Device.ToString() == "Tablet" ? true : false; 2710 string hideActions = isTouchDevice ? "u-block" : ""; 2711 2712 <table class="table data-list dw-mod"> 2713 @if (settings.GetHeaders().Length > 0) { 2714 <thead> 2715 <tr class="u-bold"> 2716 @foreach (CustomerCenterListHeaderItem header in settings.GetHeaders()) 2717 { 2718 var attributes = new Dictionary<string, string>(); 2719 if (!string.IsNullOrEmpty(header.Id)) { attributes.Add("id", header.Id); } 2720 if (!string.IsNullOrEmpty(header.CssClass)) { attributes.Add("class", header.CssClass); } 2721 attributes.Add("align", header.Align.ToString()); 2722 attributes = attributes.Concat(header.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2723 2724 <td @ComponentMethods.AddAttributes(attributes)>@header.Title</td> 2725 } 2726 </tr> 2727 </thead> 2728 } 2729 @foreach (CustomerCenterListItem listItem in settings.GetItems()) 2730 { 2731 int columnCount = 0; 2732 int totalColumns = listItem.GetInfoItems().Length; 2733 string rowHasActions = listItem.GetActions().Length > 0 ? "data-list__item--has-acions" : ""; 2734 listItem.Id = !string.IsNullOrEmpty(listItem.Id) ? listItem.Id : Guid.NewGuid().ToString("N"); 2735 2736 var attributes = new Dictionary<string, string>(); 2737 if (!string.IsNullOrEmpty(listItem.Title)) { attributes.Add("title", listItem.Title); }; 2738 2739 attributes = attributes.Concat(listItem.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2740 <tbody class="data-list__item @rowHasActions @listItem.CssClass dw-mod" @ComponentMethods.AddAttributes(attributes)> 2741 <tr> 2742 @if (!string.IsNullOrEmpty(listItem.Title) || !string.IsNullOrEmpty(listItem.Description)) { 2743 <td rowspan="2" onclick="@listItem.OnClick" class="data-list__main-item dw-mod"> 2744 @if (!string.IsNullOrEmpty(listItem.Title)) { 2745 <div class="u-bold">@listItem.Title</div> 2746 } 2747 @if (!string.IsNullOrEmpty(listItem.Description)) { 2748 <div>@listItem.Description</div> 2749 } 2750 </td> 2751 } 2752 2753 @foreach (CustomerCenterListInfoItem infoItem in listItem.GetInfoItems()) 2754 { 2755 var infoAttributes = new Dictionary<string, string>(); 2756 if (!string.IsNullOrEmpty(infoItem.Id)) { infoAttributes.Add("id", infoItem.Id); }; 2757 if (!string.IsNullOrEmpty(infoItem.OnClick)) { infoAttributes.Add("onclick", infoItem.OnClick); }; 2758 infoAttributes.Add("align", infoItem.Align.ToString()); 2759 2760 infoAttributes = infoAttributes.Concat(infoItem.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2761 string columnClick = columnCount < (totalColumns-1) ? "onclick=\"" + listItem.OnClick + "\"" : ""; 2762 2763 <td @ComponentMethods.AddAttributes(infoAttributes) @columnClick class="data-list__info-item dw-mod"> 2764 @if (!string.IsNullOrEmpty(infoItem.Title)) { 2765 <div>@infoItem.Title</div> 2766 } 2767 @if (!string.IsNullOrEmpty(infoItem.Subtitle)) { 2768 <div><small>@infoItem.Subtitle</small></div> 2769 } 2770 </td> 2771 2772 columnCount++; 2773 } 2774 </tr> 2775 <tr> 2776 <td colspan="7" align="right" class="u-va-bottom u-no-border"> 2777 <div class="data-list__actions @hideActions dw-mod" id="ActionsMenu_@listItem.Id"> 2778 @foreach (ButtonBase action in listItem.GetActions()) 2779 { 2780 action.ButtonLayout = ButtonLayout.LinkClean; 2781 action.CssClass += " data-list__action-button link"; 2782 2783 @Render(action) 2784 } 2785 </div> 2786 </td> 2787 </tr> 2788 </tbody> 2789 } 2790 </table> 2791 } 2792 2793 @* Include the Blocks for the page *@ 2794 @using Dynamicweb.Ecommerce.ProductCatalog 2795 @using Dynamicweb.Rendering 2796 @using Smartpage.PhilipsonWine.Ratings 2797 @using Smartpage.PhilipsonWine.Ratings.Model 2798 @using System 2799 @using System.Web 2800 2801 @functions 2802 { 2803 //Expert rating values 2804 private (string ratingName, string ratingText, string ratingPercentage, string ratingImage) GetExpertRatingValues(ProductRating ExpertRating) 2805 { 2806 string ratingName = ""; 2807 string ratingText = ""; 2808 double ratingValue = 0; 2809 string ratingPercentage = ""; 2810 string ratingImage = ""; 2811 2812 if (ExpertRating != null) 2813 { 2814 ratingName = ExpertRating.RatingMedia; 2815 2816 if (ExpertRating.RatingType != "2") 2817 { 2818 if (ExpertRating.RatingScoreFrom == ExpertRating.RatingScoreTo) 2819 { 2820 ratingText = ExpertRating.RatingScoreTo; 2821 ratingValue = ((Converter.ToDouble(ExpertRating.RatingScoreTo) / Converter.ToDouble(ExpertRating.RatingMaxScore)) * 100); 2822 } 2823 else 2824 { 2825 ratingText = (ExpertRating.RatingScoreFrom + "<span class='small'>-</span>" + ExpertRating.RatingScoreTo); 2826 ratingValue = ((Converter.ToDouble(ExpertRating.RatingScoreFrom) / Converter.ToDouble(ExpertRating.RatingScoreTo)) * 100); 2827 } 2828 } 2829 else 2830 { 2831 ratingText = (ExpertRating.RatingScoreTo + "<span class='small'>/" + ExpertRating.RatingMaxScore + "</span>"); 2832 ratingValue = ((Converter.ToDouble(ExpertRating.RatingScoreTo) / Converter.ToDouble(ExpertRating.RatingMaxScore)) * 100); 2833 } 2834 2835 if (Double.IsNaN(ratingValue) || Double.IsInfinity(ratingValue)) 2836 { 2837 ratingPercentage = "100"; 2838 } 2839 else 2840 { 2841 ratingPercentage = Converter.ToString(ratingValue); 2842 } 2843 2844 ratingImage = ExpertRating.RatingImageMedia; 2845 } 2846 2847 return (ratingName: ratingName, ratingText: ratingText, ratingPercentage: ratingPercentage, ratingImage: ratingImage); 2848 } 2849 2850 2851 //Customer rating values 2852 2853 private (double ratingInPercent, string ratingInText, double ratingInDouble) GetCustomerRatingValues(double rating) 2854 { 2855 var ratingInPercent = ((rating / 5) * 100); 2856 string ratingInText = Converter.ToString(rating); 2857 2858 return (ratingInPercent: ratingInPercent, ratingInText: ratingInText, ratingInDouble: rating); 2859 } 2860 } 2861 2862 2863 @helper RenderRatingBadge(double ratingInPercent, string name, string value, bool customerRating = true, string image = "") 2864 { 2865 if (!string.IsNullOrEmpty(image)) 2866 { 2867 2868 var imagePath = "/Files/Images/ExpertRatings/" + image + ".png"; 2869 2870 var imagePrefix = "/Admin/Public/GetImage.ashx?width=46&amp;height=46&amp;crop=5&amp;Compression=75&amp;FillCanvas=true&amp;DoNotUpscale=true&amp;image=" + imagePath; 2871 2872 // CDN 2873 var cdnUrl = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("CDNUrl"); 2874 bool cdnActivate = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetBoolean("CDNActivate"); 2875 if (!string.IsNullOrWhiteSpace(cdnUrl) && cdnActivate) 2876 { 2877 imagePrefix = cdnUrl + imagePrefix; 2878 } 2879 2880 <div class="expert-rating-image"> 2881 <img class="rating-image" src="@imagePrefix" alt="@HttpUtility.HtmlAttributeEncode(name)" /> 2882 <span class="rating-image--score">@(new HtmlString(value))</span> 2883 </div> 2884 } 2885 else 2886 { 2887 <div class="rating-badge c100 @(customerRating ? "": "dark") js-badge" data-percent="@ratingInPercent"> 2888 <span class="rating-badge--text">@name</span> 2889 <span class="rating-badge--score">@(new HtmlString(value))</span> 2890 <div class="slice"> 2891 <div class="bar"></div> 2892 <div class="fill"></div> 2893 </div> 2894 </div> 2895 } 2896 } 2897 2898 @inherits ViewModelTemplate<ProductViewModel> 2899 @using Dynamicweb.Ecommerce.ProductCatalog 2900 @using Dynamicweb.Rendering 2901 @using Dynamicweb.Core 2902 @using System.Collections.Generic 2903 @using Dynamicweb.Rapido.Blocks 2904 @using Dynamicweb.Rapido.Blocks.Components.General 2905 @using System.Linq 2906 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 2907 2908 @using System.Linq; 2909 @using Dynamicweb.Rapido.Blocks.Components.General 2910 @using System.Collections.Generic 2911 @using Dynamicweb.Core 2912 @using Dynamicweb.Ecommerce.ProductCatalog 2913 @using Dynamicweb.Frontend 2914 @using Dynamicweb.Rendering 2915 2916 2917 @functions{ 2918 Dictionary<string, StickersListPosition> stickerPositions = new Dictionary<string, StickersListPosition> 2919 { 2920 { "top-left", StickersListPosition.TopLeft }, 2921 { "top-right", StickersListPosition.TopRight }, 2922 { "bottom-left", StickersListPosition.BottomLeft }, 2923 { "bottom-right", StickersListPosition.BottomRight } 2924 }; 2925 2926 public void AddSticker(List<StickersCollection> list, Sticker sticker, StickersListPosition stickerPosition) 2927 { 2928 StickersCollection stickersContainerTemp = list.FirstOrDefault(stickersContainer => stickersContainer.Position == stickerPosition); 2929 if (stickersContainerTemp == null) 2930 { 2931 stickersContainerTemp = new StickersCollection() 2932 { 2933 Position = stickerPosition, 2934 Stickers = new List<Sticker>() 2935 }; 2936 list.Add(stickersContainerTemp); 2937 } 2938 stickersContainerTemp.Stickers.Add(sticker); 2939 } 2940 2941 public List<StickersCollection> GetStickersContainersList(IEnumerable<Dynamicweb.Ecommerce.Orders.Discounts.Discount> discountsLoop, double discountPrice, double price, DateTime createdDate, string customStickerValue, double percentSaved = 0) 2942 { 2943 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 2944 bool isSaleStickersEnabled = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetBoolean("Enable"); 2945 bool isNewsStickersEnabled = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetBoolean("Enable"); 2946 bool isCustomStickersEnabled = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("CustomSticker").GetBoolean("Enable"); 2947 2948 List<StickersCollection> resultList = new List<StickersCollection>(); 2949 2950 if (!pointShopOnly && isSaleStickersEnabled) 2951 { 2952 string contentType = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetString("ContentType"); 2953 contentType = !string.IsNullOrEmpty(contentType) ? contentType : "Name"; 2954 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 2955 Sticker saleSticker = new Sticker(); 2956 saleSticker.CssClass = "stickers-container__tag--sale"; 2957 2958 switch (contentType) 2959 { 2960 case "Name": 2961 foreach (var discount in discountsLoop) 2962 { 2963 saleSticker.Title = discount.Name; 2964 } 2965 break; 2966 case "Amount": 2967 if (discountsLoop.Count() > 0) 2968 { 2969 saleSticker.Title = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, discountPrice - price); 2970 } 2971 break; 2972 case "Percents": 2973 if (percentSaved > 0) 2974 { 2975 saleSticker.Title = "-" + percentSaved + "%"; 2976 } 2977 //NF20201015 - disabled because discount percent is calculated in PriceObject 2978 //else 2979 //{ 2980 // double percents = 0; 2981 // foreach (var discount in discountsLoop) 2982 // { 2983 // percents += discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 2984 // percents += discount.Percentage; 2985 // } 2986 // if (percents > 0) 2987 // { 2988 // saleSticker.Title = "-" + Math.Round(percents, 0) + "%"; 2989 // } 2990 //} 2991 break; 2992 case "Amount and percents": 2993 double amount = 0; 2994 double percent = 0; 2995 foreach (var discount in discountsLoop) 2996 { 2997 if (Converter.ToString(discount.DiscountType) == "Percentage") 2998 { 2999 percent += discount.Percentage; 3000 } 3001 else if (Converter.ToString(discount.DiscountType) == "Amount") 3002 { 3003 amount += discount.Amount; 3004 } 3005 } 3006 3007 if (percent > 0) 3008 { 3009 saleSticker.Title = percent + "%"; 3010 } 3011 else if (amount > 0) 3012 { 3013 saleSticker.Title = "-" + Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 3014 } 3015 break; 3016 default: 3017 if (discountsLoop.Count() > 0) 3018 { 3019 saleSticker.Title = Translate("Sale!"); 3020 } 3021 break; 3022 } 3023 StickersListPosition saleStickerPosition = StickersListPosition.TopLeft; 3024 if (Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetList("Position") != null) 3025 { 3026 string value = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetList("Position").SelectedValue; 3027 saleStickerPosition = stickerPositions.ContainsKey(value) ? stickerPositions[value] : stickerPositions["top-left"]; 3028 } 3029 if (!string.IsNullOrEmpty(saleSticker.Title)) 3030 { 3031 AddSticker(resultList, saleSticker, saleStickerPosition); 3032 } 3033 } 3034 3035 if (!pointShopOnly && isNewsStickersEnabled && createdDate.AddDays(Converter.ToDouble(Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetString("Expiration"))) > DateTime.Now) 3036 { 3037 Sticker newSticker = new Sticker(); 3038 newSticker.CssClass = "stickers-container__tag--new"; 3039 newSticker.Title = Translate("New!"); 3040 3041 StickersListPosition newStickerPosition = StickersListPosition.TopLeft; 3042 if (Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetList("Position") != null) 3043 { 3044 string value = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetList("Position").SelectedValue; 3045 newStickerPosition = stickerPositions.ContainsKey(value) ? stickerPositions[value] : stickerPositions["top-left"]; 3046 } 3047 if (!string.IsNullOrEmpty(newSticker.Title)) 3048 { 3049 AddSticker(resultList, newSticker, newStickerPosition); 3050 } 3051 } 3052 3053 if (!pointShopOnly && isCustomStickersEnabled && !string.IsNullOrEmpty(customStickerValue)) 3054 { 3055 Sticker customSticker = new Sticker(); 3056 customSticker.CssClass = "stickers-container__tag--custom"; 3057 customSticker.Title = customStickerValue; 3058 3059 StickersListPosition customStickerPosition = StickersListPosition.TopLeft; 3060 if (Pageview.AreaSettings.GetItem("Ecommerce").GetItem("CustomSticker").GetList("Position") != null) 3061 { 3062 string value = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("CustomSticker").GetList("Position").SelectedValue; 3063 customStickerPosition = stickerPositions.ContainsKey(value) ? stickerPositions[value] : stickerPositions["top-left"]; 3064 } 3065 if (!string.IsNullOrEmpty(customSticker.Title)) 3066 { 3067 AddSticker(resultList, customSticker, customStickerPosition); 3068 } 3069 } 3070 3071 return resultList; 3072 } 3073 } 3074 3075 @functions { 3076 BlocksPage mainImagePage = BlocksPage.GetBlockPage("Product"); 3077 bool showThumbs; 3078 bool thumbsOnTheSide; 3079 } 3080 3081 @{ 3082 int imageBlockWidth = Pageview.AreaSettings.GetItem("ProductPage").GetList("TopLayout") != null ? Converter.ToInt32(Pageview.AreaSettings.GetItem("ProductPage").GetList("TopLayout").SelectedValue) : 6; 3083 string blocksPosition = Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "thumbs-image-info"; 3084 bool infoOnTheRight = blocksPosition.LastIndexOf("info") == blocksPosition.Length - 4; 3085 showThumbs = blocksPosition.IndexOf("thumbs") != -1; 3086 thumbsOnTheSide = showThumbs && blocksPosition.IndexOf("thumbsBottom") == -1; 3087 bool thumbsOnTheLeft = blocksPosition.IndexOf("image") > blocksPosition.IndexOf("thumbs"); 3088 if (infoOnTheRight) 3089 { 3090 imageBlockWidth = 12 - imageBlockWidth; 3091 if (imageBlockWidth == 0) 3092 { 3093 imageBlockWidth = 12; 3094 } 3095 } 3096 3097 if (Pageview.Device.ToString() == "Mobile" || Pageview.Device.ToString() == "Tablet") 3098 { 3099 thumbsOnTheSide = false; 3100 } 3101 3102 Block mainImageBlock = new Block() 3103 { 3104 Id = "MainImage", 3105 SortId = infoOnTheRight ? 10 : 20, 3106 Design = new Design 3107 { 3108 Size = "4", 3109 RenderType = RenderType.Column, 3110 CssClass = "u-flex--row" 3111 }, 3112 BlocksList = new List<Block> 3113 { 3114 new Block { 3115 Id = "MainImageRow", 3116 SortId = 10, 3117 Design = new Design 3118 { 3119 RenderType = RenderType.Row 3120 }, 3121 //BlocksList = new List<Block> 3122 //{ 3123 // new Block 3124 // { 3125 // Id = "Carousel", 3126 // SortId = 10, 3127 // Template = RenderThumbnails(), 3128 // Design = new Design 3129 // { 3130 // Size = thumbsOnTheSide ? "2" : "12", 3131 // RenderType = RenderType.Column 3132 // } 3133 // } 3134 //} 3135 } 3136 } 3137 }; 3138 mainImagePage.Add("Top", mainImageBlock); 3139 3140 mainImagePage.Add("MainImageRow", 3141 new Block() 3142 { 3143 Id = "ProductImageModal", 3144 SortId = 0, 3145 Component = new Modal 3146 { 3147 Id = "Gallery", 3148 Width = ModalWidth.Lg, 3149 Height = ModalHeight.Full, 3150 BodyTemplate = RenderProductImagesCarousel("modalCarousel", 1, "horizontal", 3, true) 3151 } 3152 }); 3153 3154 if (showThumbs) 3155 { 3156 mainImagePage.Add("MainImageRow", 3157 new Block 3158 { 3159 Id = "Image", 3160 SortId = thumbsOnTheLeft ? 20 : 0, 3161 Template = RenderProductImage(), 3162 Design = new Design 3163 { 3164 Size = "10", 3165 RenderType = RenderType.Column 3166 } 3167 }); 3168 } 3169 } 3170 3171 @helper RenderProductStickers() 3172 { 3173 ProductInformation productInformation = new ProductInformation(Model); 3174 var priceObject = new Smartpage.PhilipsonWine.Ecommerce.Prices.PriceObject(Model.Id, productInformation.MaxPriceBasedOn, Model.Discount.Price, productInformation.OnSale); 3175 string customSticker = !string.IsNullOrWhiteSpace(productInformation.CustomSticker) ? productInformation.CustomSticker : ""; 3176 var discounts = Dynamicweb.Ecommerce.Services.Discounts.GetApplicableDiscountsForProduct(Model.Id, Model.VariantId, Dynamicweb.Ecommerce.Common.Context.LanguageID, Dynamicweb.Ecommerce.Common.Context.Currency, Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser()); 3177 3178 List<StickersCollection> StickersContainers = GetStickersContainersList( 3179 discounts, 3180 Model.Discount.Price, 3181 Model.Price.Price, 3182 Converter.ToDateTime(Model.Created), 3183 customSticker, 3184 priceObject.PercentSaved 3185 ); 3186 3187 foreach (StickersCollection stickersContainer in StickersContainers) 3188 { 3189 @Render(new StickersCollection { Stickers = stickersContainer.Stickers, Position = stickersContainer.Position }) 3190 } 3191 } 3192 3193 @helper RenderProductImage() 3194 { 3195 var productInformation = new ProductInformation(Model); 3196 string defaultImage = Model.ImagePatternImages.Any(i => i.Name == "Default") ? Model.ImagePatternImages.First(i => i.Name == "Default").Value : "Files/Images/missing_image.jpg"; 3197 //Add product image to the og meta data 3198 Pageview.Meta.AddTag("og:image", defaultImage); 3199 3200 <label for="GalleryModalTrigger" class="product__image-container u-position-relative"> 3201 @{ 3202 // Fetch image from ImagePattern images to take advantage of improved image patterns functionality 3203 Image productImage = new Image 3204 { 3205 Path = defaultImage, 3206 Id = "Image_" + Model.Id, 3207 CssClass = "u-middle product__image-container__image dw-mod", 3208 Title = HttpUtility.HtmlAttributeEncode(Model.Name), 3209 OnClick = "modalCarousel.GoToSlide('modalCarousel', this.getAttribute('data-number'))", 3210 ImageDefault = new ImageSettings 3211 { 3212 Width = 180, 3213 Height = 430, 3214 Crop = 5, 3215 FillCanvas = true 3216 }, 3217 ImageSmall = new ImageSettings 3218 { 3219 Width = 130, 3220 Height = 300, 3221 Crop = 5, 3222 FillCanvas = true 3223 } 3224 }; 3225 productImage.ExtraAttributes.Add("data-number", "0"); 3226 } 3227 @Render(productImage) 3228 @RenderProductStickers() 3229 @if (productInformation.Primeur) 3230 { 3231 <span class="top-label top-label--product-page"> 3232 <span class="top-label__label"> 3233 @Translate("Primeur", "Primeur") 3234 </span> 3235 </span> 3236 } 3237 </label> 3238 } 3239 3240 @helper RenderThumbnails() 3241 { 3242 <div class="@(showThumbs ? "product__thumbs" : "") dw-mod"> 3243 @RenderProductImagesCarousel( 3244 "productCarousel", 3245 !showThumbs ? 1 : 5, 3246 thumbsOnTheSide ? "vertical" : "horizontal", 3247 !showThumbs ? 3 : 2 3248 ) 3249 @if (!showThumbs) 3250 { 3251 @RenderProductStickers() 3252 } 3253 </div> 3254 } 3255 3256 @helper RenderProductImagesCarousel(string id, int slidesInView, string direction, int preloaderSize, bool isModal = false) 3257 { 3258 //var apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(Model.Id, Model.VariantId, true); 3259 3260 HashSet<string> images = new HashSet<string>(); 3261 3262 foreach (var alternativeImage in Model.ImagePatternImages) 3263 { 3264 string alt_image = alternativeImage.Value; 3265 3266 if (!string.IsNullOrEmpty(alt_image)) 3267 { 3268 images.Add(alt_image); 3269 } 3270 } 3271 3272 foreach (var detail in Model.AssetCategories) 3273 { 3274 foreach (var asset in detail.Assets) 3275 { 3276 string detail_image = asset.Value; 3277 3278 if (!string.IsNullOrEmpty(detail_image)) 3279 { 3280 string ext = Path.GetExtension(detail_image).ToLower(); 3281 if (ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".png") 3282 { 3283 images.Add(detail_image); 3284 } 3285 } 3286 3287 } 3288 } 3289 3290 // If no images then add default image to carousel 3291 if (!images.Any()) 3292 { 3293 images.Add("Files/Images/missing_image.jpg"); 3294 } 3295 3296 <div class="carousel dw-mod" id="@id"> 3297 <div class="thumb-list carousel__container @(slidesInView != 1 ? "carousel__container--hidden" : "") js-carousel-slides dw-mod"> 3298 @{ var i = 0; } 3299 @foreach (var image in images) 3300 { 3301 @RenderProductImage(image, slidesInView == 1, isModal ? "modal--full__img" : "", i == 0, isModal) 3302 i++; //first is active 3303 } 3304 </div> 3305 3306 <script> 3307 document.addEventListener("DOMContentLoaded", function () { 3308 @id = new CarouselModule('#@id', { 3309 slidesInView: @slidesInView, 3310 direction: "@direction", 3311 preloaderSize: @preloaderSize, 3312 showCounter: @isModal.ToString().ToLower() 3313 }); 3314 }); 3315 </script> 3316 </div> 3317 } 3318 3319 @helper RenderProductImage(string image, bool isBig, string cssClass = "", bool isActive = false, bool isModal = false) 3320 { 3321 string productId = Model.Id; 3322 string imagePrefix = "/Admin/Public/GetImage.ashx?width=800&amp;height=800&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image="; 3323 3324 Image productImage = new Image 3325 { 3326 Path = image, 3327 Title = HttpUtility.HtmlAttributeEncode(Model.Name), 3328 ImageDefault = new ImageSettings 3329 { 3330 Width = 800, 3331 Height = 800, 3332 Crop = 5, 3333 FillCanvas = true 3334 }, 3335 CssClass = "u-middle " + cssClass, 3336 OnClick = "modalCarousel.GoToSlide('modalCarousel', this.closest('.carousel__slide').index());" 3337 }; 3338 productImage.ExtraAttributes.Add("data-image", image); 3339 3340 <div class="carousel__slide dw-mod"> 3341 @if (isModal) 3342 { 3343 @Render(productImage) 3344 @*@Render(new Image { Path = image, CssClass = cssClass, Title = Model.Name, DisableImageEngine = true });*@ 3345 } 3346 else if (isBig) 3347 { 3348 <label for="GalleryModalTrigger" class="u-middle"> 3349 @Render(productImage) 3350 </label> 3351 } 3352 else 3353 { 3354 Image productThumb = productImage; 3355 productThumb.ImageDefault = new ImageSettings 3356 { 3357 Width = 200, 3358 Height = 200, 3359 Crop = 5, 3360 FillCanvas = true 3361 }; 3362 productImage.CssClass += " thumb-list__image"; 3363 <div class="thumb-list__item dw-mod js-thumb js-gallery @(isActive ? "js-thumb--active thumb-list__item--active" : "")" data-for="Image_@productId" data-image="@imagePrefix@image" onmouseover="Gallery.openImage(this)"> 3364 <label for="GalleryModalTrigger" class="thumb-list__image-label"> 3365 @Render(productThumb) 3366 </label> 3367 </div> 3368 } 3369 </div> 3370 } 3371 @inherits ViewModelTemplate<ProductViewModel> 3372 @using Dynamicweb.Ecommerce.ProductCatalog 3373 @using Dynamicweb.Rendering 3374 @using Dynamicweb.Core 3375 @using System 3376 @using System.Web 3377 @using System.Collections.Generic 3378 @using Dynamicweb.Rapido.Services 3379 @using Dynamicweb.Rapido.Blocks 3380 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 3381 @using Dynamicweb.Rapido.Blocks.Components.General 3382 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 3383 @using Smartpage.PhilipsonWine.Ratings; 3384 @using Smartpage.PhilipsonWine.Ratings.Model; 3385 3386 @functions { 3387 bool useFacebookPixel; 3388 bool useGoogleTagManager; 3389 BlocksPage mainInfoPage = BlocksPage.GetBlockPage("Product"); 3390 } 3391 3392 @{ 3393 var user = Dynamicweb.Security.UserManagement.User.get_Current(Dynamicweb.Security.UserManagement.PagePermissionLevels.Frontend); 3394 useFacebookPixel = !string.IsNullOrWhiteSpace(Pageview.AreaSettings.GetItem("Settings").GetString("FacebookPixelID")); 3395 useGoogleTagManager = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("GoogleTagManagerID")); 3396 bool hidePrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 3397 bool hideAddToCartButton = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("hideAddToCartButton"); 3398 3399 var productRatings = Dynamicweb.Content.Commenting.Comment.GetComments("ecomProduct", Model.Id, Model.LanguageId); 3400 var activeProductRatings = productRatings.Where(i => i.Active == true).OrderByDescending(i => i.Rating).ThenBy(i => i.CreatedDate); 3401 double totalRatingAmount = 0.0; 3402 //var mainInfoApiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(Model.Id, Model.VariantId, true); 3403 ProductInformation mainInformationProductInformation = new ProductInformation(Model); 3404 3405 3406 foreach (var comment in activeProductRatings) 3407 { 3408 totalRatingAmount += comment.Rating; 3409 } 3410 3411 totalRatingAmount = (totalRatingAmount / activeProductRatings.Count()); 3412 3413 Block mainInfoHeader = new Block() 3414 { 3415 Id = "MainInfoHeader", 3416 SortId = 10, 3417 Template = RenderMainInfoHeader(productFields) 3418 }; 3419 mainInfoPage.Add("MainInformation", mainInfoHeader); 3420 3421 if (Model.Rating > 0 && !eventProduct) 3422 { 3423 Block mainInfoCustomerRatings = new Block() 3424 { 3425 Id = "MainInfoCustomerRatings", 3426 SortId = 11, 3427 Template = RenderCustomerRatings(Model.Rating) 3428 }; 3429 mainInfoPage.Add("MainInformation", mainInfoCustomerRatings); 3430 } 3431 3432 // Render divider if there are customer ratings or short description on the product 3433 if (Model.Rating > 0 || !string.IsNullOrWhiteSpace(Model.ShortDescription)) 3434 { 3435 Block mainInfoDivider = new Block() 3436 { 3437 Id = "MainInfoDivider", 3438 SortId = 12, 3439 Template = RenderDivider() 3440 }; 3441 mainInfoPage.Add("MainInformation", mainInfoDivider); 3442 } 3443 3444 if (!eventProduct) 3445 { 3446 Block mainInfoRatings = new Block() 3447 { 3448 Id = "MainInfoRatings", 3449 SortId = 13, 3450 Template = RenderRatings() 3451 }; 3452 mainInfoPage.Add("MainInformation", mainInfoRatings); 3453 } 3454 else 3455 { 3456 Block mainInfoEvent = new Block() 3457 { 3458 Id = "MainInfoEvent", 3459 SortId = 13, 3460 Template = RenderEventInfo(productFields) 3461 }; 3462 mainInfoPage.Add("MainInformation", mainInfoEvent); 3463 } 3464 3465 Block mainInfoDescription = new Block() 3466 { 3467 Id = "ShortDescription", 3468 SortId = 20, 3469 Template = RenderShortDescription() 3470 }; 3471 mainInfoPage.Add("MainInformation", mainInfoDescription); 3472 3473 string[] recommendations = !string.IsNullOrWhiteSpace(productFields.RecommendedTo) ? productFields.RecommendedTo.Split(',') : new string[] { }; 3474 3475 if (!eventProduct) 3476 { 3477 Block mainInfoRecommendations = new Block() 3478 { 3479 Id = "MainInfoRecommendations", 3480 SortId = 21, 3481 Template = RenderRecomendations(recommendations) 3482 }; 3483 mainInfoPage.Add("MainInformation", mainInfoRecommendations); 3484 } 3485 3486 if (user != null && User.IsBuyingAllowed() && GetPageIdByNavigationTag("OrderDraft") != 0) 3487 { 3488 Modal selectDraftModal = new Modal 3489 { 3490 Id = "OrderDraftSelect", 3491 Heading = new Heading { Title = Translate("Select draft cart"), Level = 2 }, 3492 BodyTemplate = RenderOrderDraftSelectModalContent(), 3493 Width = ModalWidth.Md 3494 }; 3495 selectDraftModal.AddAction(new Button { Title = Translate("Cancel"), OnClick = "document.getElementById('OrderDraftSelectModalTrigger').checked = false", ButtonLayout = ButtonLayout.Secondary }); 3496 selectDraftModal.AddAction(new Button { Title = Translate("Add"), OnClick = "addToSelectedCart()" }); 3497 3498 Block orderDraftSelect = new Block 3499 { 3500 Id = "OrderDraft", 3501 SortId = 90, 3502 Component = selectDraftModal 3503 }; 3504 mainInfoPage.Add("MainInformation", orderDraftSelect); 3505 3506 Modal notificationDraftModal = new Modal 3507 { 3508 Id = "OrderDraftNotification", 3509 Heading = new Heading { Title = Translate("Added to cart"), Level = 2 }, 3510 BodyText = Translate("The product has been added to the selected cart"), 3511 Width = ModalWidth.Md 3512 }; 3513 notificationDraftModal.AddAction(new Button { Title = Translate("View draft"), OnClick = "goToSelectedCart()", ButtonLayout = ButtonLayout.Secondary }); 3514 notificationDraftModal.AddAction(new Button { Title = Translate("Continue shopping"), OnClick = "document.getElementById('OrderDraftNotificationModalTrigger').checked = false" }); 3515 3516 Block orderDraftComplete = new Block 3517 { 3518 Id = "OrderDraftComplete", 3519 SortId = 100, 3520 Component = notificationDraftModal 3521 }; 3522 mainInfoPage.Add("MainInformation", orderDraftComplete); 3523 3524 3525 Block orderDraftScripts = new Block 3526 { 3527 Id = "OrderDraftScripts", 3528 SortId = 110, 3529 Template = RenderOrderDraftScripts() 3530 }; 3531 mainInfoPage.Add("MainInformation", orderDraftScripts); 3532 } 3533 } 3534 3535 @helper RenderMainInfoHeader(ProductInformation productInfo) 3536 { 3537 string producerId = productInfo.ProducerId; 3538 var producerService = new Smartpage.PhilipsonWine.Producer.Repositories.ProducerService(); 3539 var producer = producerService.GetProductProducer(producerId); 3540 3541 <div> 3542 <div class="u-pull--left product__title dw-mod"> 3543 @if (eventProduct) 3544 { 3545 <span class="area">@productInfo.EventRestaurantName - @productInfo.EventAddressShort - @productInfo.EventPromotionText</span> 3546 } 3547 else if (producer != null && !string.IsNullOrWhiteSpace(producer.ProducerName)) 3548 { 3549 <span class="area">@producer.ProducerName</span> 3550 } 3551 3552 <h1 class="u-no-margin product-name">@Model.Name </h1> 3553 </div> 3554 </div> 3555 } 3556 3557 @helper RenderCustomerRatings(double? rating, int padding = 0, bool showMore = true) 3558 { 3559 double ratingPercentage = (Converter.ToDouble(rating) / 5) * 100; 3560 3561 <div class="customer-ratings-container u-margin-top-big u-margin-bottom"> 3562 <div class="hearts" data-average-rating-percentage="@ratingPercentage" data-heart-padding="@padding"> 3563 <div class="hearts-outer"> 3564 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 3565 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 3566 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 3567 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 3568 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 3569 <div class="hearts-inner"> 3570 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 3571 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 3572 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 3573 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 3574 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 3575 </div> 3576 </div> 3577 </div> 3578 @if (showMore) 3579 { 3580 <div class="rating">@rating <span class="rating__info-text">@Translate("Smartpage:ProductDetail.Rating.OutOfFive", "(ud af 5)") <a href="javascript:void(0)" onclick="scrollToNode('.js-customer-ratings-section')" class="rating__info-text--link small-link">@Translate("Smartpage:ProductDetail.Rating.SeeAll", "Se alle")</a></span></div> 3581 } 3582 </div> 3583 } 3584 3585 @helper RenderDivider() 3586 { 3587 <div class="divider"> 3588 <hr class="u-margin-top-big u-margin-bottom-big" /> 3589 </div> 3590 } 3591 3592 @helper RenderRatings() 3593 { 3594 3595 var ratings = Smartpage.PhilipsonWine.Ratings.Controller.ProductRatings.GetRatingProduct(Model.Id); 3596 if (ratings.Any()) 3597 { 3598 <div class="main-expert-ratings u-margin-top u-margin-bottom"> 3599 @foreach (var item in ratings.Where(x => x.RatingType != Converter.ToString((int)Smartpage.PhilipsonWine.Ratings.Controller.ProductRatings.RatingTypes.FullRating)).Take(3)) 3600 { 3601 <div class="main-expert-ratings__li"> 3602 <label class="main-expert-ratings__label">@item.RatingMedia</label> 3603 <span class="main-expert-ratings__span"> @RenderExpertRating(item.RatingScoreTo, item.RatingScoreFrom, item.RatingMaxScore, item.RatingType, item.RatingTextScore)</span> 3604 </div> 3605 } 3606 <span class="main-expert-ratings__link" onclick="scrollToNode('.js-expert-ratings', -56)">@Translate("Smartpage:Product.ViewAllExpertRatings", "Vis alle")</span> 3607 </div> 3608 } 3609 } 3610 3611 @helper RenderEventInfo(ProductInformation productInfo) 3612 { 3613 3614 <div class="event-info"><i class="far fa-calendar-alt event-info__icon"></i>@Converter.ToDateTime(productInfo.EventDate).ToString("dd. MMMM yyyy")</div> 3615 <div class="event-info"><i class="far fa-clock event-info__icon clock"></i> @Translate("Kl") @productInfo.EventFromTime @(!string.IsNullOrEmpty(productInfo.EventEndTime) ? Translate("til") + " " + Translate("Kl") + " " + productInfo.EventEndTime : "") </div> 3616 <div class="event-info"><i class="fas fa-map-marker-alt event-info__icon"></i>@productInfo.EventAddressLong</div> 3617 3618 @RenderDivider() 3619 } 3620 3621 @helper RenderExpertRating(string scoreTo, string scoreFrom, string scoreMax, string scoreType, string textScore) 3622 { 3623 3624 if (scoreType != "2" && scoreType != "3") 3625 { 3626 if (scoreFrom == scoreTo) 3627 { 3628 @(scoreTo + " " + Translate("point")) 3629 } 3630 else 3631 { 3632 @(scoreFrom + "/" + scoreTo) 3633 } 3634 3635 } 3636 else if (scoreType == "3") 3637 { 3638 @textScore 3639 } 3640 else 3641 { 3642 var missingStars = (Converter.ToInt32(scoreMax) - Converter.ToInt32(scoreTo)); 3643 3644 for (int i = 0; i < Converter.ToInt32(scoreTo); i++) 3645 { 3646 <i class="fas fa-star"></i> 3647 } 3648 3649 for (int i = 0; i < missingStars; i++) 3650 { 3651 <i class="fas fa-star u-color-light-gray"></i> 3652 } 3653 } 3654 } 3655 3656 @helper RenderShortDescription() 3657 { 3658 if (!string.IsNullOrEmpty(Model.ShortDescription)) 3659 { 3660 var description = Regex.Replace(Model.ShortDescription, "<.*?>", String.Empty); 3661 Pageview.Meta.AddTag("description", description); 3662 Pageview.Meta.AddTag("og:description", description); 3663 3664 <div class="introduction-text u-margin-top u-margin-bottom"> 3665 @Model.ShortDescription 3666 <a class="small-link" href="javascript:void(0)" onclick="scrollToNode('.js-long-description', -56)">@Translate("Smartpage:ProductDetail.ShortDescription.ReadMore", "Læs mere")</a> 3667 </div> 3668 } 3669 } 3670 3671 @helper RenderRecomendations(string[] recommendations) 3672 { 3673 if (recommendations.Any()) 3674 { 3675 <div> 3676 <hr class="u-margin-top-big u-margin-bottom-big" /> 3677 <div class="reccommendations-container"> 3678 <span class="reccomendations-header">@Translate("Smartpage:ProductDetail.ReccomendedTo", "Anbefalet til")</span> 3679 <div class="reccomendations"> 3680 @foreach (var recommendation in recommendations) 3681 { 3682 <div class="reccomendations__reccommendation">@recommendation</div> 3683 } 3684 </div> 3685 </div> 3686 </div> 3687 } 3688 } 3689 3690 @helper RenderOrderDraftSelectModalContent() 3691 { 3692 var customerId = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId(); 3693 var shopId = Pageview.Area.EcomShopId; 3694 var orderType = Dynamicweb.Ecommerce.Orders.OrderType.Order; 3695 var cartsList = (List<Dynamicweb.Ecommerce.Orders.Order>)Dynamicweb.Ecommerce.Services.Orders.GetCustomerOrdersByType(customerId, shopId, orderType, 0, false, "", DateTime.MinValue, false, true); 3696 3697 SelectField cartSelector = new SelectField 3698 { 3699 Id = "CartSelector", 3700 Label = Translate("I want to add this product to") 3701 }; 3702 3703 foreach (Dynamicweb.Ecommerce.Orders.Order cart in cartsList) 3704 { 3705 string name = !string.IsNullOrEmpty(cart.DisplayName) ? cart.DisplayName : cart.Id; 3706 cartSelector.Options.Add(new SelectFieldOption { Label = name, Value = cart.Id }); 3707 } 3708 3709 @Render(cartSelector) 3710 } 3711 3712 @helper RenderOrderDraftScripts() 3713 { 3714 //var apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(Model.Id, Model.VariantId, true); 3715 string productId = Model.Id; 3716 string variantId = !string.IsNullOrEmpty(Model.VariantId) ? Model.VariantId : Model.VariantId; 3717 string unitId = Model.DefaultUnitId; 3718 var cartCmdUrl = "/Default.aspx?ID=" + Pageview.Page.ID; 3719 int orderDraftPageId = GetPageIdByNavigationTag("DraftDetails"); 3720 int orderDraftParagraphId = Dynamicweb.Services.Paragraphs.GetParagraphsByPageId(orderDraftPageId).ToList().First().ID; 3721 3722 <script> 3723 function addToSelectedCart() { 3724 var requestUrl = "@cartCmdUrl" + "&cartcmd=Add&Quantity=1" + "&CartId=" + document.getElementById("CartSelector").value + "&ProductId=@productId" + "&VariantId=@variantId" + "&UnitId=@unitId"; 3725 3726 console.log(requestUrl) 3727 3728 document.getElementById('OrderDraftSelectModalTrigger').checked = false; 3729 3730 var overlayElement = document.createElement('div'); 3731 overlayElement.className = "preloader-overlay"; 3732 overlayElement.setAttribute('id', "CartOverlay"); 3733 var overlayElementIcon = document.createElement('div'); 3734 overlayElementIcon.className = "preloader-overlay__icon dw-mod"; 3735 overlayElementIcon.style.top = window.pageYOffset + "px"; 3736 overlayElement.appendChild(overlayElementIcon); 3737 document.getElementById('content').parentNode.insertBefore(overlayElement, document.getElementById('content')); 3738 3739 Request.Fetch().get( 3740 requestUrl, 3741 function () { 3742 var overlayNode = document.getElementById('CartOverlay'); 3743 overlayNode.parentNode.removeChild(overlayNode); 3744 document.getElementById('OrderDraftNotificationModalTrigger').checked = true; 3745 }, 3746 null, 3747 false 3748 ); 3749 } 3750 3751 function goToSelectedCart() { 3752 window.location = "/Default.aspx?ID=" + "@orderDraftPageId" + "&CartID=" + document.getElementById('CartSelector').value + "&CartCmd=setcart" + "&redirect=false"; 3753 } 3754 </script> 3755 } 3756 3757 @if (useGoogleTagManager) 3758 { 3759 string mainInformationProducerId = mainInformationProductInformation.ProducerId; 3760 var producerService = new Smartpage.PhilipsonWine.Producer.Repositories.ProducerService(); 3761 var producer = producerService.GetProductProducer(mainInformationProducerId); 3762 3763 <script> 3764 // Measure a view of product details. This example assumes the detail view occurs on pageload, 3765 // and also tracks a standard pageview of the details page. 3766 dataLayer.push({ 3767 'event': 'productDetails', 3768 "ecommerce": { 3769 "detail": { 3770 "currencyCode": "@Model.Price.CurrencyCode", 3771 "actionField": {}, // 'detail' actions have an optional list property. 3772 "products": [{ 3773 "name": "@HttpUtility.HtmlEncode(Model.Name)", // Name or ID is required. 3774 "id": "@Model.Id", 3775 "price": "@(Model.Price.Price != Model.PriceBeforeDiscount.Price ? Model.Price.Price : Model.PriceBeforeDiscount.Price)", 3776 "brand": "@(producer != null ? producer.ProducerName : "")", 3777 "category": "@Model.PrimaryOrDefaultGroup.Name", 3778 "variant": "@(!string.IsNullOrEmpty(Model.VariantId) ? Model.VariantId : Model.VariantId)" 3779 }] 3780 } 3781 } 3782 }); 3783 </script> 3784 } 3785 @inherits ViewModelTemplate<ProductViewModel> 3786 @using Dynamicweb.Ecommerce.ProductCatalog 3787 @using Dynamicweb.Rendering 3788 @using Dynamicweb.Core 3789 @using System 3790 @using System.Web 3791 @using System.Collections.Generic 3792 @using Dynamicweb.Rapido.Services 3793 @using Dynamicweb.Rapido.Blocks 3794 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 3795 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 3796 @using Smartpage.PhilipsonWine.FavoriteList.Controller; 3797 @using Smartpage.PhilipsonWine.EcomPrices; 3798 @using Smartpage.PhilipsonWine.EcomPrices.Models; 3799 3800 3801 @using Dynamicweb.Ecommerce.ProductCatalog 3802 @using Dynamicweb.Rendering 3803 3804 @functions 3805 { 3806 private string FormatPrice(double price) 3807 { 3808 return price.ToString("N2"); 3809 } 3810 } 3811 3812 @functions 3813 { 3814 BlocksPage productAddedToCartProductPage = BlocksPage.GetBlockPage("Product"); 3815 bool addToCartUseFacebookPixel; 3816 bool addToCartUseGoogleTagManager; 3817 3818 public class GoogleImpression 3819 { 3820 public string name { get; set; } 3821 public string id { get; set; } 3822 public string price { get; set; } 3823 public string brand { get; set; } 3824 public string category { get; set; } 3825 public string variant { get; set; } 3826 public string currency { get; set; } 3827 public string list { get; set; } 3828 public int position { get; set; } 3829 } 3830 public class FacebookAction 3831 { 3832 public string content_name { get; set; } 3833 public List<string> content_ids { get; set; } 3834 public string content_type { get; set; } 3835 public double value { get; set; } 3836 public string currency { get; set; } 3837 } 3838 } 3839 3840 @{ 3841 3842 addToCartUseFacebookPixel = !string.IsNullOrWhiteSpace(Pageview.AreaSettings.GetItem("Settings").GetString("FacebookPixelID")); 3843 addToCartUseGoogleTagManager = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("GoogleTagManagerID")); 3844 3845 Block addedToCartSectionBlock = new Block() 3846 { 3847 Id = "MainAddToCartSection", 3848 SortId = 10, 3849 Template = RenderAddToCartSection() 3850 }; 3851 productAddedToCartProductPage.Add("AddToCartSection", addedToCartSectionBlock); 3852 3853 Block simpleAddedToCartSectionBlock = new Block() 3854 { 3855 Id = "MainSimpleAddToCartSection", 3856 SortId = 11, 3857 Template = RenderSimpleAddToCartSection() 3858 }; 3859 productAddedToCartProductPage.Add("AddToCartSection", simpleAddedToCartSectionBlock); 3860 3861 } 3862 3863 @helper RenderAddToCartSection() 3864 { 3865 var currentUser = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser(); 3866 3867 //Get customer specific price and quantity 3868 CustomPrice customPrice = null; 3869 CustomPriceService.GetCustomPriceProducts(currentUser)?.TryGetValue(Model.Id, out customPrice); 3870 3871 <div class="add-to-cart-section-container"> 3872 <section class="add-to-cart-section js-add-to-cart-section"> 3873 @if (Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 3874 { 3875 @RenderPriceInfo(false, customPrice?.PriceQuantity) 3876 } 3877 <div class="product__price-actions dw-mod" id="PriceAndActions"> 3878 @RenderBuyInfo(false, customPrice?.PriceQuantity) 3879 </div> 3880 <input type="hidden" value="@Model.VariantId" name="Variant" id="Variant_@Model.Id" /> 3881 </section> 3882 </div> 3883 3884 //Customer rating 3885 var dwPageId = Dynamicweb.Frontend.PageView.Current().Page.ID; 3886 string currentUrl = Convert.ToString(HttpContext.Current.Request.Url.PathAndQuery); 3887 var pageViewUrl = currentUrl + "#commented"; 3888 var productId = Model.Id; 3889 var langId = Model.LanguageId; 3890 var accessUserName = currentUser != null ? Dynamicweb.Frontend.PageView.Current().User.Name : ""; 3891 var accessUserEmail = currentUser != null ? Dynamicweb.Frontend.PageView.Current().User.Email : ""; 3892 var notify = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("ActiveNotificationEmail"); 3893 var notifySenderEmail = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("NotifySenderEmail"); 3894 var notifyEmail = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("NotifyEmail"); 3895 var notifySenderName = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("NotifySenderName"); 3896 3897 <input type="checkbox" id="rateProductModalTrigger" class="modal-trigger"> 3898 <div class="modal-container"> 3899 <label for="rateProductModalTrigger" id="rateProductModalOverlay" class="modal-overlay"></label> 3900 <div class="modal modal--lg modal-height--auto" id="rateProductModal"> 3901 <div class="modal__header u-no-padding-x u-no-border--bottom"> 3902 <div class="u-ta-center u-bold dw-mod">@Translate("Anmeld")<br />@Model.Name</div> 3903 </div> 3904 3905 <div class="full-stars-customer-rating u-padding-top--lg u-padding-bottom--lg"> 3906 <div class="rating-group"> 3907 <input disabled checked class="rating__input rating__input--none" name="rating3" id="rating3-none" value="0" type="radio"> 3908 <label aria-label="1 star" class="rating__label" for="rating3-1"><i class="rating__icon rating__icon--star fas fa-heart"></i></label> 3909 <input class="rating__input js-rating" name="rating3" id="rating3-1" value="1" type="radio"> 3910 <label aria-label="2 stars" class="rating__label" for="rating3-2"><i class="rating__icon rating__icon--star fas fa-heart"></i></label> 3911 <input class="rating__input js-rating" name="rating3" id="rating3-2" value="2" type="radio"> 3912 <label aria-label="3 stars" class="rating__label" for="rating3-3"><i class="rating__icon rating__icon--star fas fa-heart"></i></label> 3913 <input class="rating__input js-rating" name="rating3" id="rating3-3" value="3" type="radio"> 3914 <label aria-label="4 stars" class="rating__label" for="rating3-4"><i class="rating__icon rating__icon--star fas fa-heart"></i></label> 3915 <input class="rating__input js-rating" name="rating3" id="rating3-4" value="4" type="radio"> 3916 <label aria-label="5 stars" class="rating__label" for="rating3-5"><i class="rating__icon rating__icon--star fas fa-heart"></i></label> 3917 <input class="rating__input js-rating" name="rating3" id="rating3-5" value="5" type="radio"> 3918 </div> 3919 </div> 3920 <p class="u-ta-center u-color-danger js-rate-error u-hidden">@Translate("Vurder vinen fra 1 til 5")</p> 3921 3922 <div class="modal__body "> 3923 <form method="post" class="u-ta-center js-comment-form" id="commentform"> 3924 <input type="hidden" name="Comment.Command" id="Comment.Command" value="create" /> 3925 <!--Set active to false if you want to approve comments before publishing on the page--> 3926 <input type="hidden" name="Comment.Active" value="false" /> 3927 <!-- product catalog level comments params --> 3928 <input type="hidden" name="Comment.ItemType" value="ecomProduct" /> 3929 <input type="hidden" name="Comment.ItemID" value="@productId" /> 3930 <input type="hidden" name="Comment.LangID" value="@langId" /> 3931 <!-- end product catalog level comments params --> 3932 <input type="hidden" name="Comment.Continue" value="@pageViewUrl" /> 3933 <input type="hidden" name="Comment.ParentID" id="Comment.ParentID" value="0" /> 3934 3935 <!--Notify info--> 3936 <input type="hidden" name="Comment.Notify" value="@notify" /> 3937 <input type="hidden" name="Comment.NotifyTemplate" value="Comments/Notify.cshtml" /> 3938 <input type="hidden" name="Comment.NotifySubject" id="Comment.NotifySubject" value="@Translate("Ny anmeldelse af produkt"): @productId" /> 3939 <input type="hidden" name="Comment.NotifySenderEmail" value="@notifySenderEmail" /> 3940 <input type="hidden" name="Comment.NotifySenderName" value="@notifySenderName" /> 3941 <input type="hidden" name="Comment.NotifyEmail" value="@notifyEmail" /> 3942 3943 <!--User info--> 3944 <input type="hidden" name="Comment.Rating" id="Comment.Rating" value="0" /> 3945 <input type="hidden" name="Comment.Name" id="Comment.Name" value="@accessUserName" /> 3946 <input type="hidden" name="Comment.Email" id="Comment.Email" value="@accessUserEmail" /> 3947 <input type="hidden" name="Comment.Website" id="Comment.Website" value="" /> 3948 <textarea name="Comment.Text" id="Comment.Text" rows="20" cols="50" class="comment-custom-rating" placeholder="@Translate("Skriv din anmeldelse")"></textarea><br /> 3949 3950 <input type="submit" class="btn btn--primary dw-mod" value="@Translate("Anmeld vin")" /> 3951 </form> 3952 </div> 3953 <label class="modal__close-btn" for="rateProductModalTrigger"></label> 3954 </div> 3955 </div> 3956 3957 3958 <input type="checkbox" id="productRatedModalTrigger" class="modal-trigger"> 3959 <div class="modal-container"> 3960 <label for="productRatedModalTrigger" id="productRatedModalOverlay" class="modal-overlay"></label> 3961 <div class="modal modal--md modal-height--auto u-padding--lg" id="productRatedModal"> 3962 <div class="modal__header u-no-padding-x u-no-border--bottom u-no-padding u-padding-top"> 3963 <div class="u-ta-center u-bold dw-mod">@Translate("Tak for din anmeldelse!")</div> 3964 </div> 3965 <div class="modal__body u-no-padding u-padding-bottom u-ta-center"> 3966 <p>@Translate("Din anmeldelse vises i løbet af 24 timer")</p> 3967 <label for="productRatedModalTrigger" class="js-close-rated btn btn--primary u-no-margin u-margin-top--lg dw-mod">@Translate("Luk")</label> 3968 </div> 3969 </div> 3970 </div> 3971 } 3972 3973 @helper RenderSimpleAddToCartSection() 3974 { 3975 string defaultImage = Model.ImagePatternImages.Any(i => i.Name == "Default") ? Model.ImagePatternImages.First(i => i.Name == "Default").Value : "Files/Images/missing_image.jpg"; 3976 string imagePrefix = "/Admin/Public/GetImage.ashx?width=77&amp;height=180&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image=" + defaultImage; 3977 // CDN 3978 var cdnUrl = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("CDNUrl"); 3979 bool cdnActivate = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetBoolean("CDNActivate"); 3980 if (!string.IsNullOrWhiteSpace(cdnUrl) && cdnActivate) 3981 { 3982 imagePrefix = cdnUrl + imagePrefix; 3983 } 3984 <div class="simple-add-to-cart-section-container add-to-cart-section-container"> 3985 <section class="add-to-cart-section js-add-to-cart-section"> 3986 3987 <div class="add-to-cart-section__image"> 3988 <img class="u-full-height u-center-middle" src="@imagePrefix" alt="@HttpUtility.HtmlAttributeEncode(Model.Name)"/> 3989 </div> 3990 3991 @if (Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 3992 { 3993 @RenderPriceInfo(true) 3994 } 3995 <div class="product__price-actions dw-mod" id="PriceAndActions"> 3996 @RenderBuyInfo(true) 3997 </div> 3998 <input type="hidden" value="@Model.VariantId" name="Variant" id="Variant_@Model.Id" /> 3999 </section> 4000 </div> 4001 } 4002 4003 @helper RenderBuyInfo(bool useSimpleLayout = false, int? customPriceQuantity = null) 4004 { 4005 var user = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser(); 4006 bool showPrice = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 4007 bool showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 4008 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 4009 string variantId = HttpContext.Current.Request.QueryString.Get("variantId") ?? ""; 4010 string feedId = Dynamicweb.Context.Current.Request["ID"] + "&ProductID=" + Model.Id + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 4011 string cartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 4012 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("ShowBothPricesWithWithoutVAT"); 4013 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 4014 4015 var customerId = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId(); 4016 var shopId = Pageview.Area.EcomShopId; 4017 var orderType = Dynamicweb.Ecommerce.Orders.OrderType.Order; 4018 var cartsList = (List<Dynamicweb.Ecommerce.Orders.Order>)Dynamicweb.Ecommerce.Services.Orders.GetCustomerOrdersByType(customerId, shopId, orderType, 0, false, "", DateTime.MinValue, false, true); 4019 4020 ProductInformation productInformation = new ProductInformation(Model); 4021 string linkGroup = "Default.aspx?Id=" + GetPageIdByNavigationTag("ProductsPage") + "&GroupId=" + (Model.PrimaryOrDefaultGroup != null ? Model.PrimaryOrDefaultGroup.Id : "") + "&ProductId=" + Model.Id; 4022 string link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(linkGroup); 4023 string image = System.Web.HttpContext.Current.Server.UrlEncode(Model.DefaultImage.Value); 4024 double priceDouble = Model.Price.Price != Model.PriceBeforeDiscount.Price ? Model.Price.Price : Model.PriceBeforeDiscount.Price; 4025 priceDouble = Dynamicweb.Rapido.Services.User.IsPricesAllowed() ? priceDouble : 0; 4026 4027 bool isActive = !productInformation.Blocked && (productInformation.SpProductActive || (user != null && user.CurrentSecondaryUser != null)); 4028 bool availableForPurchase = ProductInformation.OnCustomerStock(Model.Id) && productInformation.SpProductActive ? true : isActive; 4029 string encodedProductName = HttpUtility.JavaScriptStringEncode(Model.Name); 4030 4031 var googleImpression = new GoogleImpression(); 4032 if (addToCartUseGoogleTagManager) 4033 { 4034 googleImpression.name = encodedProductName; 4035 googleImpression.brand = !string.IsNullOrWhiteSpace(productInformation.Brand) ? productInformation.Brand : ""; 4036 googleImpression.category = Model.PrimaryOrDefaultGroup.Name; 4037 googleImpression.id = Model.Id; 4038 googleImpression.position = 1; 4039 googleImpression.price = Converter.ToString((Model.Price.Price != Model.PriceBeforeDiscount.Price ? Model.Price.Price : Model.PriceBeforeDiscount.Price)); 4040 googleImpression.variant = Model.VariantId; 4041 googleImpression.list = "Product catalogue"; 4042 googleImpression.currency = Model.Price.CurrencyCode; 4043 } 4044 4045 string productInfo = HttpUtility.HtmlEncode(Newtonsoft.Json.JsonConvert.SerializeObject(new 4046 { 4047 link = link, 4048 image = image, 4049 name = encodedProductName, 4050 variantName = Dynamicweb.Ecommerce.Services.Variants.GetVariantName(Model.VariantId), 4051 unitName = "", 4052 googleImpression = Newtonsoft.Json.JsonConvert.SerializeObject(googleImpression) 4053 })); 4054 4055 var facebookPixelAction = new FacebookAction(); 4056 if (addToCartUseFacebookPixel) 4057 { 4058 facebookPixelAction.content_name = encodedProductName; 4059 facebookPixelAction.content_ids = new List<string>(new string[] { Model.Number }); 4060 facebookPixelAction.content_type = "product"; 4061 facebookPixelAction.value = priceDouble; 4062 facebookPixelAction.currency = Model.Price.CurrencyCode; 4063 } 4064 4065 int quantity = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("quantity")) ? Converter.ToInt32(HttpContext.Current.Request.QueryString.Get("quantity")) : 1; 4066 double points = Converter.ToDouble(Model.PointPrice) * quantity; 4067 bool havePointPrice = points != 0; 4068 bool canBePurchasedWithPoints = false; 4069 string onSale = Model.Discount.PriceFormatted == Model.Price.PriceFormatted ? "u-hidden" : ""; 4070 4071 if (user != null) 4072 { 4073 var availablePoints = user.PointBalance; 4074 var cart = Dynamicweb.Ecommerce.Common.Context.Cart; 4075 var pointsUsedInCart = cart != null ? cart.TotalPoints : 0; 4076 canBePurchasedWithPoints = points > 0 && availablePoints - pointsUsedInCart >= points; 4077 } 4078 string disabledBuyButton = (pointShopOnly && !canBePurchasedWithPoints) ? "disabled" : ""; 4079 4080 if (showCartButton && Dynamicweb.Rapido.Services.User.IsBuyingAllowed() && availableForPurchase) 4081 { 4082 var addToCartBtn = new AddToCart 4083 { 4084 WrapperCssClass = "product__price-actions-flex-wrap buttons-collection--right dw-mod", 4085 AddButton = new AddToCartButton 4086 { 4087 ProductId = Model.Id, 4088 VariantId = Model.VariantId, 4089 UnitId = "", 4090 ProductInfo = productInfo, 4091 BuyForPoints = pointShopOnly, 4092 ExtraAttributes = new Dictionary<string, string> 4093 { 4094 { disabledBuyButton, "" } 4095 }, 4096 CssClass = "product__price-buy-button" 4097 } 4098 }; 4099 4100 if (!pointShopOnly) 4101 { 4102 addToCartBtn.QuantitySelector = new QuantitySelector 4103 { 4104 Id = "Quantity_" + Model.Id 4105 }; 4106 } 4107 4108 int kolli = productInformation.MaxPriceBasedOn > 0 ? productInformation.MaxPriceBasedOn : 1; 4109 4110 if (customPriceQuantity != null && customPriceQuantity > 0) 4111 { 4112 kolli = Converter.ToInt32(customPriceQuantity); 4113 } 4114 4115 var priceObject = new Smartpage.PhilipsonWine.Ecommerce.Prices.PriceObject(Model.Id, kolli, Model.Discount.Price, productInformation.OnSale); 4116 4117 // In case of 1 stk. price is as good as volume price 4118 if (priceObject.DiscountPrice == priceObject.NormalPrice) 4119 { 4120 kolli = 1; 4121 } 4122 4123 <div class="product__price-actions-wrap dw-mod u-margin-top-big u-margin-bottom-big"> 4124 <div class="buttons-collection"> 4125 @if (Model.StockLevel > 0) 4126 { 4127 <input id="Quantity_@Model.Id" name="Quantity_@Model.Id" min="1" max="@Model.StockLevel" value="@kolli" type="number" class="quantity dw-mod js-stockcheck js-change-quantity"> 4128 } 4129 @{ 4130 4131 if (Model.StockLevel > 0) 4132 { 4133 <button class="btn btn--add-to-cart" title="@Translate("Smartpage:ProductDetail.Buy", "Køb")" onclick='Cart.AddToCart(event, { "id": "@Model.Id", "unitId": "@Model.DefaultUnitId", "productInfo": @productInfo, "quantity": parseInt(document.getElementById("Quantity_@Model.Id").value), "SpPrimeur": "@Converter.ToString(productInformation.Primeur)" });' type="button" data-product-id="@Model.Id" data-one-unit-price="@priceObject.NormalPrice" data-volume-unit-price="@priceObject.DiscountPrice" data-volume-unit-threshold="@kolli" data-currency-code="@Model.Price.CurrencyCode"><span><i class="fas fa-shopping-cart shopping-cart u-w20px"></i>@Translate("Smartpage:ProductDetail.Buy", "Køb")</span></button> 4134 } 4135 else 4136 { 4137 <button disabled class="btn btn--add-to-cart" title="@Translate("Smartpage:Product.Buy.OutOfStock", "Udsolgt")" onclick='Cart.AddToCart(event, { "id": "@Model.Id", "unitId": "@Model.DefaultUnitId", "productInfo": @productInfo, "quantity": parseInt(document.getElementById("Quantity_@Model.Id").value), "SpPrimeur": "@Converter.ToString(productInformation.Primeur)"});' type="button"><span><i class="fas fa-shopping-cart shopping-cart u-w20px"></i>@Translate("Smartpage:Product.Buy.OutOfStock", "Udsolgt")</span></button> 4138 } 4139 } 4140 </div> 4141 </div> 4142 } 4143 else 4144 { 4145 <button type="button" id="CartButton_@Model.Id" class="u-hidden"></button> 4146 } 4147 4148 if (!useSimpleLayout) 4149 { 4150 @RenderStockAndShipping() 4151 4152 if (user != null && !eventProduct) 4153 { 4154 @RenderAddToFavoriteList() 4155 } 4156 4157 if (!eventProduct) 4158 { 4159 @RenderCustomerRatingLink() 4160 } 4161 4162 4163 @RenderUSPList(productInformation) 4164 } 4165 4166 4167 @*<script id="UnitOption" type="text/x-template"> 4168 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '{{link}}&feed=true&UnitID={{value}}')">{{name}}</div> 4169 </script>*@ 4170 4171 <script> 4172 document.addEventListener("DOMContentLoaded", function () { 4173 if (document.getElementById("PriceAndActions")) { 4174 document.getElementById("PriceAndActions").addEventListener("contentLoaded", function (event) { 4175 if (document.querySelector(".js-variants") != null) { 4176 MatchVariants.Update(document.querySelector(".js-variants"), "DoNothing"); 4177 } 4178 }); 4179 } 4180 }); 4181 </script> 4182 } 4183 4184 @helper RenderPriceInfo(bool useSimpleLayout = false, int? customPriceQuantity = null) 4185 { 4186 ProductInformation productInformation = new ProductInformation(Model); 4187 int priceQuantity = customPriceQuantity != null && customPriceQuantity > 0 ? Converter.ToInt32(customPriceQuantity) : productInformation.MaxPriceBasedOn; 4188 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 4189 bool showPrice = !Pageview.AreaSettings.GetItem("ProductList").GetBoolean("HidePrice"); 4190 bool showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 4191 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 4192 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 4193 var priceObject = new Smartpage.PhilipsonWine.Ecommerce.Prices.PriceObject(Model.Id, priceQuantity, Model.Discount.Price, productInformation.OnSale); 4194 double savings = priceObject.AmountSaved; 4195 double price = Dynamicweb.Rapido.Services.User.IsPricesAllowed() ? priceObject.DiscountPrice : 0; 4196 string priceWithoutVAT = Converter.ToString(Model.Price.PriceWithoutVat); 4197 priceWithoutVAT = Dynamicweb.Rapido.Services.User.IsPricesAllowed() ? priceWithoutVAT : "0"; 4198 string priceWithVAT = Converter.ToString(Model.Price.PriceWithVat); 4199 priceWithVAT = Dynamicweb.Rapido.Services.User.IsPricesAllowed() ? priceWithVAT : "0"; 4200 string priceRRP = Model.PriceInformative != null && !string.IsNullOrEmpty(Model.PriceInformative.PriceFormatted) ? Model.PriceInformative.PriceFormatted : ""; 4201 priceRRP = Dynamicweb.Rapido.Services.User.IsPricesAllowed() ? priceRRP : "0"; 4202 int quantity = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("quantity")) ? Converter.ToInt32(HttpContext.Current.Request.QueryString.Get("quantity")) : 1; 4203 double points = Converter.ToDouble(Model.PointPrice) * quantity; 4204 bool havePointPrice = points != 0; 4205 bool canBePurchasedWithPoints = false; 4206 string onSale = Model.Discount.PriceFormatted == Model.Price.PriceFormatted ? "u-hidden" : ""; 4207 string currencySymbol = Dynamicweb.Ecommerce.Common.Context.Currency.Symbol; 4208 4209 // In case of 1 stk. price is as good as volume price 4210 if (priceObject.DiscountPrice == priceObject.NormalPrice) 4211 { 4212 priceQuantity = 1; 4213 } 4214 4215 var user = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser(); 4216 if (user != null) 4217 { 4218 var availablePoints = user.PointBalance; 4219 var cart = Dynamicweb.Ecommerce.Common.Context.Cart; 4220 var pointsUsedInCart = cart != null ? cart.TotalPoints : 0; 4221 canBePurchasedWithPoints = points > 0 && availablePoints - pointsUsedInCart >= points; 4222 } 4223 4224 string simpleLayoutClass = useSimpleLayout ? "simple-layout" : ""; 4225 4226 4227 if (showPrice && Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 4228 { 4229 <div class="prices @simpleLayoutClass"> 4230 4231 @if (savings > 0) 4232 { 4233 <span class="savings">@Translate("Smartpage:ProductDetail.Save", "Spar") @FormatPrice(savings) @currencySymbol @Translate("Smartpage:ProductDetail.pr.", "pr.") @productInformation.Unit.ShortDescription</span> 4234 } 4235 4236 <div class="price price--product-page"> 4237 @priceObject.DiscountPriceFormattedWithoutSymbol 4238 <span class="currency-symbol">@currencySymbol</span> 4239 <span class="quantity-price__amount--mobile"><strong>@Translate("Smartpage:ProductDetail.pr.", "pr.") @productInformation.Unit.ShortDescription v/@priceQuantity</strong></span> 4240 </div> 4241 4242 @if (eventProduct) 4243 { 4244 <div class="quantity-price"> 4245 <span class="u-block u-color-font-black quantity-price__amount"><strong>@Translate("Pr. billet")</strong></span> 4246 </div> 4247 } 4248 else 4249 { 4250 <div class="quantity-price"> 4251 <span class="u-block u-color-font-black quantity-price__amount"><strong>@Translate("Smartpage:ProductDetail.Pr.", "Pr.") @productInformation.Unit.ShortDescription v/@priceQuantity @Translate("Smartpage:ProductDetail.Unit.Stk", "stk.")</strong></span> 4252 @priceObject.NormalPriceFormatted @Translate("Smartpage:ProductDetail.pr.", "pr.") @productInformation.Unit.LongDescription 4253 </div> 4254 } 4255 4256 </div> 4257 } 4258 } 4259 4260 @helper RenderStockAndShipping() 4261 { 4262 4263 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState"); 4264 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping"); 4265 4266 var apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(Model.Id, Model.VariantId, true); 4267 var stockStatus = Dynamicweb.Ecommerce.Services.Products.GetStockStatus(apiProduct, apiProduct.LanguageId); 4268 string stockText = stockStatus != null ? stockStatus.Text : ""; 4269 string stockState = Model.StockLevel > 0 ? "stock-icon--in" : "stock-icon--not"; 4270 string deliveryText = stockStatus != null && !string.IsNullOrEmpty(stockStatus.ExpectedDeliveryText) ? stockStatus.ExpectedDeliveryText : ""; 4271 ProductInformation productinfo = new ProductInformation(Model); 4272 bool isPrimeur = productinfo.Primeur; 4273 string primeruDeliveryDate = productinfo.PrimeurIncomingDate != DateTime.MinValue ? productinfo.PrimeurIncomingDate.ToString("dd/MM/yyyy") : Translate("Smartpage:ProductDetail.PrimeurDateNotKnown", "Ukendt"); 4274 4275 if (User.IsStockInfoAllowed()) 4276 { 4277 if (!string.IsNullOrWhiteSpace(stockText)) 4278 { 4279 <div class="product__stock-delivery dw-mod"> 4280 @if (!hideStockState) 4281 { 4282 if (!isPrimeur) 4283 { 4284 <span class="stock-icon @stockState u-no-margin dw-mod" title="@stockText"></span> 4285 <span> 4286 @stockText 4287 @if (!hideDelivery && !string.IsNullOrWhiteSpace(deliveryText)) 4288 { 4289 <text>: @deliveryText</text> 4290 } 4291 </span> 4292 } 4293 else 4294 { 4295 <span class="stock-icon stock-icon--comming u-no-margin dw-mod" title="stock-icon--not"></span> 4296 <span> 4297 @Translate("Smarptage:ProductDetail.PrimeurStockState", "Leveringsdato") 4298 @if (!hideDelivery && !string.IsNullOrWhiteSpace(primeruDeliveryDate)) 4299 { 4300 <text>: @primeruDeliveryDate</text> 4301 } 4302 </span> 4303 } 4304 4305 4306 } 4307 </div> 4308 } 4309 } 4310 } 4311 4312 @helper RenderCustomerRatingLink() 4313 { 4314 4315 var modalTrigger = ""; 4316 4317 if (Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser() != null) 4318 { 4319 modalTrigger = "rateProductModalTrigger"; 4320 } 4321 else 4322 { 4323 modalTrigger = "SignInModalTrigger"; 4324 } 4325 4326 <div class="product__customer-rating-link"> 4327 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 4328 <strong><label for="@modalTrigger" class="medium-link">@Translate("Smartpage:ProductDetail.ReviewThisWine", "Anmeld denne vin")</label></strong> 4329 </div> 4330 } 4331 4332 @helper RenderUSPList(ProductInformation productInfo) 4333 { 4334 4335 string eventUSP = productInfo.EventUSP; 4336 string[] eventUSPs = eventUSP.Split('#'); 4337 4338 <div class="product__usp-list"> 4339 @if (eventProduct) 4340 { 4341 if (eventUSPs != null && eventUSPs.Length > 0) 4342 { 4343 foreach (var usp in eventUSPs) 4344 { 4345 if (!string.IsNullOrEmpty(usp)) 4346 { 4347 <div class="usp"> 4348 <i class="fas fa-check usp-icon"></i> 4349 <span>@usp</span> 4350 </div> 4351 } 4352 } 4353 } 4354 } 4355 else 4356 { 4357 <div class="usp"> 4358 <i class="fas fa-truck usp-icon"></i> 4359 <span>@Translate("Smartpage:ProductDetail.FreeShipping", "FRI FRAGT!")</span> 4360 </div> 4361 <div class="usp"> 4362 <i class="fas fa-lock usp-icon"></i> 4363 <span>@Translate("Smartpage:ProductDetail.SecurePayment", "Sikker betaling")</span> 4364 </div> 4365 } 4366 </div> 4367 } 4368 4369 @helper RenderAddToFavoriteList() 4370 { 4371 var user = Dynamicweb.Security.UserManagement.User.get_Current(Dynamicweb.Security.UserManagement.PagePermissionLevels.Frontend); 4372 string pageId = Dynamicweb.Context.Current.Request["ID"]; 4373 string currentPrice = Model.Price.PriceFormatted != Model.PriceBeforeDiscount.PriceFormatted ? Model.Price.PriceFormatted : Model.PriceBeforeDiscount.PriceFormatted; 4374 bool hideFavorites = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideFavoriteButton"); 4375 bool hideProductNumber = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideProductNumber"); 4376 4377 bool useFontAwesomePro = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetBoolean("UseFontAwesomePro"); 4378 var selectedFavoriteIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon").SelectedValue : "star"; 4379 string favoriteIcon = "fas fa-" + selectedFavoriteIcon; 4380 string favoriteOutlineIcon = "fal fa-" + selectedFavoriteIcon; 4381 4382 if (!hideFavorites && user != null) 4383 { 4384 string favoriteId = "Favorite" + Model.Id; 4385 var customerCenterLists = Dynamicweb.Ecommerce.CustomerCenter.CustomerProductList.GetListByCustomerId(user.ID); 4386 4387 // This page needs to be used since View Model catalogue can't handle adding to favorites 4388 // Use standard product catalogue instead 4389 string modifyFavoriteListPage = Converter.ToString(GetPageIdByNavigationTag("ModifyFavoriteListPage")); 4390 4391 <div id="@favoriteId" class="favorites js-favorite-btn product__add-to-favorites-link"> 4392 <div> 4393 @{ 4394 string favorite = customerCenterLists.Any(l => l.Products.Any(p => p.ProductId == Model.Id)) ? favoriteIcon : favoriteOutlineIcon; 4395 string AddToWishlist = "fbq('track', 'AddToWishlist', {" + 4396 "content_name: '" + Model.Name + "'," + 4397 "content_ids: ['" + Model.Number + "']," + 4398 "value: " + Model.Price.Price + "," + 4399 "currency: '" + Model.Price.CurrencyCode + "'" + 4400 "});"; 4401 } 4402 <strong><label for="FavoriteTrigger" class="medium-link"><i class="@favorite favorite-icon"></i>@Translate("Smartpage:ProductDetail.AddToFavorites", "Føj til favoritter")</label></strong> 4403 </div> 4404 <input type="checkbox" id="FavoriteTrigger" class="dropdown-trigger" /> 4405 4406 <div class="dropdown"> 4407 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 4408 <ul class="list list--clean dw-mod"> 4409 @if (customerCenterLists.Count() > 0) 4410 { 4411 4412 4413 //Custom 4414 FavoriteLists favoriteLists = new FavoriteLists(); 4415 4416 foreach (var list in customerCenterLists) 4417 { 4418 bool isInFavoriteList = list.Products.Any(p => p.ProductId == Model.Id); 4419 string addLink = "/Default.aspx?ID=" + modifyFavoriteListPage + "&feed=true&CCAddToMyLists=" + Model.Id + "&CCAddToListVariantID=" + Model.VariantId + "&CCAddToListLanguageID=" + Model.LanguageId + "&CCAddToListID=" + list.ListId + "&CCListType=" + list.Type; 4420 string removeLink = "/Default.aspx?ID=" + modifyFavoriteListPage + "&feed=true&CCRemoveFromMyLists=" + Model.Id + "&CCRemoveFromListVariantID=" + Model.VariantId + "&CCRemoveFromListLanguageID=" + Model.LanguageId + "&ListID=" + list.ListId + "&CCListType=" + list.Type; 4421 string favLinkType = isInFavoriteList ? removeLink : addLink; 4422 string isInListIcon = isInFavoriteList ? favoriteIcon : favoriteOutlineIcon; 4423 bool fromImport = false; 4424 4425 //Custom 4426 if (list.Type == "Favorites") 4427 { 4428 fromImport = favoriteLists.IsProductFromImport(Converter.ToString(Model.Id), Converter.ToString(list.ListId)); 4429 } 4430 4431 if (fromImport == false) 4432 { 4433 <li> 4434 <a href="@favLinkType" class="list__link u-no-underline dw-mod" onclick="@(isInFavoriteList && useFacebookPixel ? AddToWishlist : "")"><i class="@isInListIcon u-margin-right--lg"></i> @list.Name</a> 4435 </li> 4436 } 4437 } 4438 } 4439 else 4440 { 4441 string favLinkType = "/Default.aspx?ID=" + modifyFavoriteListPage + "&feed=true&DoNotShowVariantsAsSingleProducts=True&CCAddToMyLists=" + Model.Id + "&CCAddToListVariantID=" + Model.VariantId + "&CCAddToListLanguageID=" + Model.LanguageId + "&CCListType=0&CCCreateNewList=My favorites"; 4442 string isInListIcon = favoriteOutlineIcon; 4443 <li> 4444 <a href="@favLinkType" class="list__link u-no-underline dw-mod" onclick="@(useFacebookPixel ? AddToWishlist : "")"><i class="@isInListIcon u-margin-right--lg"></i> @Translate("My favorites")</a> 4445 </li> 4446 } 4447 </ul> 4448 </div> 4449 <label class="dropdown-trigger-off" for="FavoriteTrigger"></label> 4450 </div> 4451 </div> 4452 } 4453 } 4454 @inherits ViewModelTemplate<ProductViewModel> 4455 @using Dynamicweb.Ecommerce.ProductCatalog 4456 @using Dynamicweb.Rendering 4457 @using Dynamicweb.Core 4458 @using System 4459 @using System.Web 4460 @using System.Collections.Generic 4461 @using Dynamicweb.Rapido.Blocks 4462 @using Dynamicweb.Rapido.Blocks.Components.General 4463 4464 @functions { 4465 BlocksPage productAssetsPage = BlocksPage.GetBlockPage("Product"); 4466 } 4467 4468 @{ 4469 string productAssetsLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ProductAssetsLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductAssetsLayout").SelectedValue : "Section"; 4470 productAssetsLayout = productAssetsLayout == "Ribbon" ? "Section" : productAssetsLayout; 4471 4472 if (productAssetsLayout != "hide") 4473 { 4474 @*TODO: Determine if this should be used*@ 4475 //Block productAssetsBlock = new Block() 4476 //{ 4477 // Name = productAssetsLayout != "MainInformation" ? Translate("Product assets") : "", 4478 // Id = "ProductAssets", 4479 // SortId = 10, 4480 // Template = RenderProductAssets(productAssetsLayout, downloadDocuments), 4481 // Design = new Design 4482 // { 4483 // Size = "12", 4484 // RenderType = RenderType.Column, 4485 // HidePadding = true 4486 // } 4487 //}; 4488 //productAssetsPage.Add(productAssetsLayout, productAssetsBlock); 4489 } 4490 } 4491 4492 @*TODO: Determine if this should be used*@ 4493 @*@helper RenderProductAssets(string layout, List<LoopItem> documents) 4494 { 4495 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductAssetsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 4496 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductAssetsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 4497 string exportPageId = GetPageIdByNavigationTag("ProductExportFeed").ToString(); 4498 4499 //images 4500 4501 HashSet<string> images = new HashSet<string>(); 4502 4503 images.Add(GetProductImage()); 4504 4505 foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 4506 { 4507 string alt_image = alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 4508 4509 if (!string.IsNullOrEmpty(alt_image)) 4510 { 4511 images.Add(alt_image); 4512 } 4513 } 4514 4515 foreach (LoopItem detail in GetLoop("Details")) 4516 { 4517 string detail_image = detail.GetString("Ecom:Product:Detail.Image.Clean"); 4518 4519 if (!string.IsNullOrEmpty(detail_image)) 4520 { 4521 images.Add(detail_image); 4522 } 4523 } 4524 4525 <div class="product__section @ribbonClasses dw-mod"> 4526 <div class="product__description center-container @ribbonSubClasses dw-mod"> 4527 @if (layout == "Section") 4528 { 4529 @Render(new Heading { Title = Translate("Product assets"), Level = 2 }) 4530 } 4531 4532 <form action="/Default.aspx?ID=@exportPageId&ProductID=@System.Web.HttpContext.Current.Request.QueryString.Get("ProductID")&VariantID=@System.Web.HttpContext.Current.Request.QueryString.Get("VariantID")" method="post" class="u-flex grid--direction-column u-no-margin"> 4533 <div class="grid"> 4534 @if (images.Count > 0) 4535 { 4536 <div class="grid__col-md-4 js-checkboxes-list"> 4537 @Render(new CheckboxField { Id = "allImages", OnChange = "selectAll(this)", Label = Translate("Images") + "(" + images.Count + ")" }) 4538 4539 <ul class="panel-list"> 4540 @foreach (string image in images) 4541 { 4542 @RenderProductPanelListItem(image) 4543 } 4544 </ul> 4545 </div> 4546 } 4547 4548 @if (documents.Count > 0) 4549 { 4550 <div class="grid__col-md-4 js-checkboxes-list"> 4551 @Render(new CheckboxField { Id = "allDocuments", OnChange = "selectAll(this)", Label = Translate("Documents") + "(" + documents.Count + ")" }) 4552 4553 <ul class="panel-list"> 4554 @foreach (LoopItem document in documents) 4555 { 4556 string fieldValue; 4557 if (!string.IsNullOrEmpty(document.GetString("Document.FullPath"))) 4558 { 4559 fieldValue = document.GetString("Product.CustomField.Value.Clean"); 4560 @RenderDocument(fieldValue) 4561 } 4562 if (document.GetString("Ecom:Product.CategoryField.TypeID") == "9") 4563 { 4564 fieldValue = document.GetString("Ecom:Product.CategoryField.Value"); 4565 @RenderDocument(fieldValue) 4566 } 4567 } 4568 </ul> 4569 </div> 4570 } 4571 <div class="grid__col-md-4"> 4572 @Render(new HiddenField { Id = "ID", Name = "ID", Value = "532" }) 4573 @Render(new HiddenField { Id = "download", Name = "download", Value = "true" }) 4574 @Render(new HiddenField { Id = "siteUrl", Name = "siteUrl", Value = string.Format("{0}://{1}", GetGlobalValue("Global:Request.Scheme"), GetGlobalValue("Global:Request.Host")) }) 4575 4576 <div class="u-bold u-margin-bottom">@Translate("Export")</div> 4577 4578 @{ 4579 SelectField languageSelect = new SelectField 4580 { 4581 Id = "exportLanguage", 4582 Label = Translate("Language"), 4583 Name = "RequestLanguageId", 4584 CssClass = "u-full-width" 4585 }; 4586 foreach (var lang in Services.Languages.GetLanguages().OrderBy(l => l.Name)) 4587 { 4588 var selected = lang.IsDefault ? true : false; 4589 languageSelect.Options.Add(new SelectFieldOption { Label = lang.Name, Value = lang.LanguageId, Checked = selected }); 4590 } 4591 @Render(languageSelect) 4592 4593 SelectField purposeSelect = new SelectField 4594 { 4595 Id = "purpose", 4596 Label = Translate("Image purpose"), 4597 Name = "purpose", 4598 CssClass = "u-full-width" 4599 }; 4600 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Office"), Value = "Office" }); 4601 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Original"), Value = "Original" }); 4602 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Print"), Value = "Print" }); 4603 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Web"), Value = "Web" }); 4604 @Render(purposeSelect) 4605 4606 SelectField formatSelect = new SelectField 4607 { 4608 Id = "exportFormat", 4609 Label = Translate("Export format"), 4610 Name = "format", 4611 CssClass = "u-full-width" 4612 }; 4613 formatSelect.Options.Add(new SelectFieldOption { Label = Translate("Csv"), Value = "csv" }); 4614 formatSelect.Options.Add(new SelectFieldOption { Label = Translate("Json"), Value = "json" }); 4615 formatSelect.Options.Add(new SelectFieldOption { Label = Translate("Xml"), Value = "xml" }); 4616 @Render(formatSelect) 4617 } 4618 4619 @Render(new Button { ButtonType = ButtonType.Submit, ButtonLayout = ButtonLayout.Primary, CssClass = "btn--full u-no-margin", Title = Translate("Download") }) 4620 </div> 4621 </div> 4622 </form> 4623 </div> 4624 </div> 4625 <script> 4626 function selectAll(checkbox) { 4627 checkbox.closest(".js-checkboxes-list").querySelectorAll(".js-checkbox").forEach(function (input) { 4628 input.checked = checkbox.checked; 4629 }); 4630 } 4631 </script> 4632 }*@ 4633 4634 @helper RenderProductPanelListItem(string imageName) 4635 { 4636 <li class="panel-list__item"> 4637 <div class="panel-list__item-check"> 4638 <input id="Image_@imageName" name="Image_@imageName" type="checkbox" class="form__control u-no-margin dw-mod js-checkbox" /> 4639 <label for="Image_@imageName"></label> 4640 </div> 4641 <div class="panel-list__item-image"> 4642 <label for="Image_@imageName" class="u-no-margin"> 4643 @Render(new Image { Path = imageName, Title = Path.GetFileName(imageName), ImageDefault = new ImageSettings { Width = 55, Height = 55, Crop = 5, FillCanvas = true } }) 4644 </label> 4645 </div> 4646 <div class="panel-list__item-name"> 4647 <label for="Image_@imageName" class="u-truncate-text u-w170px" title="@Path.GetFileName(imageName)"> 4648 @Path.GetFileName(imageName) 4649 </label> 4650 </div> 4651 </li> 4652 } 4653 4654 @helper RenderDocument(string fieldValue) 4655 { 4656 <li class="panel-list__item"> 4657 <div class="panel-list__item-check"> 4658 <input id="Document_@fieldValue" name="Document_@fieldValue" type="checkbox" class="form__control u-no-margin js-checkbox dw-mod"> 4659 <label for="Document_@fieldValue"></label> 4660 </div> 4661 <div class="panel-list__item-name"> 4662 <label for="Document_@fieldValue" class="u-truncate-text u-no-margin u-max-w220px" title="@Path.GetFileName(fieldValue)"> 4663 @Path.GetFileName(fieldValue) 4664 </label> 4665 </div> 4666 </li> 4667 } 4668 @inherits ViewModelTemplate<ProductViewModel> 4669 @using Dynamicweb.Ecommerce.ProductCatalog 4670 @using Dynamicweb.Rendering 4671 @using Dynamicweb.Core 4672 @using System 4673 @using System.Web 4674 @using System.Collections.Generic 4675 @using Dynamicweb.Rapido.Blocks 4676 @using Dynamicweb.Rapido.Blocks.Components.General 4677 4678 @functions { 4679 BlocksPage productGeneratePDFPage = BlocksPage.GetBlockPage("Product"); 4680 } 4681 4682 @{ 4683 string generatePDFLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("GeneratePDFLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("GeneratePDFLayout").SelectedValue : "Section"; 4684 generatePDFLayout = generatePDFLayout == "Ribbon" ? "Section" : generatePDFLayout; 4685 4686 if (GetPageIdByNavigationTag("ProductPagePDFTemplates") > 0 && generatePDFLayout != "hide") 4687 { 4688 Block generatePDFBlock = new Block() 4689 { 4690 Name = generatePDFLayout != "MainInformation" ? Translate("Generate PDF") : "", 4691 Id = "GeneratePDF", 4692 SortId = 10, 4693 Template = RenderGeneratePDF(generatePDFLayout), 4694 Design = new Design 4695 { 4696 Size = "12", 4697 RenderType = RenderType.Column, 4698 HidePadding = true 4699 } 4700 }; 4701 4702 productGeneratePDFPage.Add(generatePDFLayout, generatePDFBlock); 4703 } 4704 } 4705 4706 @helper RenderGeneratePDF(string layout) 4707 { 4708 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("GeneratePDFLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 4709 ribbonClasses = layout == "Tabs" ? "u-no-padding" : ribbonClasses; 4710 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("GeneratePDFLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 4711 string exportPageId = GetPageIdByNavigationTag("ProductExportFeed").ToString(); 4712 int pdfFolderId = GetPageIdByNavigationTag("ProductPagePDFTemplates"); 4713 4714 Form form = new Form { Action = "/Default.aspx?MainProductID=" + System.Web.HttpContext.Current.Request.QueryString.Get("ProductID") + "&VariantID=" + System.Web.HttpContext.Current.Request.QueryString.Get("VariantID") + "&Pdf=true", Method = FormMethod.Post, CssClass = "u-no-margin" }; 4715 form.Add(new HiddenField { Name = "siteUrl", Value = string.Format("{0}://{1}", Dynamicweb.Context.Current.Request.Url.Scheme, Dynamicweb.Context.Current.Request.Url.Host) }); 4716 4717 //Select languages 4718 SelectField languagesList = new SelectField 4719 { 4720 Id = "RequestLanguageID", 4721 Name = "RequestLanguageID", 4722 Label = Translate("Language"), 4723 CssClass = "u-full-width" 4724 }; 4725 4726 foreach (var lang in Dynamicweb.Ecommerce.Services.Languages.GetLanguages().OrderBy(l => l.Name)) 4727 { 4728 languagesList.Options.Add(new SelectFieldOption 4729 { 4730 Label = lang.Name, 4731 Value = lang.LanguageId, 4732 Checked = lang.IsDefault ? true : false 4733 }); 4734 } 4735 form.Add(languagesList); 4736 4737 //Select pages 4738 SelectField pagesList = new SelectField 4739 { 4740 Id = "PDFTemplate", 4741 Name = "ID", 4742 Label = Translate("Generate PDF"), 4743 CssClass = "u-full-width" 4744 }; 4745 4746 foreach (Dynamicweb.Content.Page page in ServiceLocator.Current.GetPageService().GetPagesByParentID(pdfFolderId)) 4747 { 4748 pagesList.Options.Add(new SelectFieldOption 4749 { 4750 Label = page.MenuText, 4751 Value = Converter.ToString(page.ID) 4752 }); 4753 } 4754 form.Add(pagesList); 4755 4756 form.Add(new Button { ButtonType = ButtonType.Submit, Title = Translate("Generate PDF"), CssClass = "btn--full u-no-margin" }); 4757 4758 <div class="product__section @ribbonClasses grid dw-mod"> 4759 <div class="dw-mod grid__col-md-4 @ribbonSubClasses"> 4760 @if (layout == "Section") 4761 { 4762 @Render(new Heading { Title = Translate("Generate PDF"), Level = 2 }) 4763 } 4764 @Render(form) 4765 </div> 4766 </div> 4767 } 4768 4769 @inherits ViewModelTemplate<ProductViewModel> 4770 @using Dynamicweb.Ecommerce.ProductCatalog 4771 @using Dynamicweb.Rendering 4772 @using System.Text.RegularExpressions; 4773 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 4774 4775 @helper RenderDescription(string id) 4776 { 4777 ProductInformation productInformation = new ProductInformation(Model); 4778 int maxLength = 400; 4779 string maxLengthPaddingClass = Model.LongDescription.Length > maxLength ? "u-padding-bottom-30" : ""; 4780 4781 <div id="@id" class="paragraph-container paragraph-container--full-width long-description js-long-description @maxLengthPaddingClass"> 4782 <div class="grid grid--justify-center"> 4783 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 4784 <h2 class="long-description__header">@productInformation.LongDescriptionHeading</h2> 4785 @*Regex used to determine to amount of HTML elements to decide whether or not to show Read more text*@ 4786 @{ 4787 string pattern = "<.*?>(.*?)<\\/.*?>"; 4788 MatchCollection matches = Regex.Matches(Model.LongDescription, pattern); 4789 4790 bool hasHtmlMarkup = matches.Count > 0; 4791 4792 <div class="long-description__content js-long-description__content @(Model.LongDescription.Length > maxLength ? "fade-end" : "")"> 4793 @Model.LongDescription 4794 </div> 4795 4796 if (Model.LongDescription.Length > maxLength) 4797 { 4798 <span class="link-small js-show-description alternative-link-small" data-open="true" data-show-description="@Translate("Smartpage:ProductDetail.Description.ReadMore", "+ læs mere")" data-hide-description="@Translate("Smartpage:ProductDetail.Description.ReadLess", "- læs mindre")">@Translate("Smartpage:ProductDetail.Description.ReadMore", "+ læs mere")</span> 4799 } 4800 4801 } 4802 </div> 4803 </div> 4804 </div> 4805 } 4806 @inherits ViewModelTemplate<ProductViewModel> 4807 @using Dynamicweb.Ecommerce.ProductCatalog 4808 @using Dynamicweb.Rendering 4809 @using Dynamicweb.Core 4810 @using System.Linq 4811 4812 @helper RenderCustomerRatings(Dynamicweb.Content.Commenting.CommentCollection comments, System.Linq.IOrderedEnumerable<Dynamicweb.Content.Commenting.Comment> activeComments, string id) 4813 { 4814 4815 double totalRatingAmount = 0.0; 4816 var commentIndex = 0; 4817 4818 foreach (var comment in activeComments) 4819 { 4820 totalRatingAmount += comment.Rating; 4821 } 4822 4823 var ratingInPercent = ((totalRatingAmount / activeComments.Count()) / 5 * 100); 4824 string ratingInText = Converter.ToString(totalRatingAmount / activeComments.Count()); 4825 4826 <div id="@id" class="paragraph-container paragraph-container--full-width customer-ratings-section"> 4827 <div class="grid grid--justify-center js-customer-ratings-section"> 4828 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 4829 <h3 class="u-ta-center u-no-margin--bottom heading-reviews">@Translate("Brugernes anmeldelser")</h3> 4830 <div class="total-ratings"> 4831 @RenderCustomerRatings((totalRatingAmount / activeComments.Count()), 0, false) 4832 </div> 4833 @RenderRatingBadge(ratingInPercent, Translate("Philipson Wine"), Converter.ToString(Model.Rating)) 4834 <hr class="horizontal-line"> 4835 @foreach (var comment in activeComments) 4836 { 4837 commentIndex++; 4838 if (commentIndex == 3) 4839 { 4840 @:<div class="js-hidden-ratings u-hidden"> 4841 } 4842 if (commentIndex > 1) 4843 { 4844 <hr class="separation-line--width-full u-margin-top--lg u-margin-bottom--lg" /> 4845 } 4846 <div class="customer-rating"> 4847 <div class="u-bold">@comment.Name <span class="date">@comment.CreatedDate.ToString("dd. MMMM yyyy")</span></div> 4848 @RenderCustomerRatings(comment.Rating, 0, false) 4849 <p class="u-no-margin u-italic">@comment.Text</p> 4850 </div> 4851 if (commentIndex == activeComments.Count() && commentIndex >= 3) 4852 { 4853 @:</div> 4854 } 4855 } 4856 @if (commentIndex > 2) 4857 { 4858 <label class="u-margin-top--lg u-bold show-more js-show-more" data-show-description="@Translate("- skjul anmeldelser")">@Translate("+ flere anmeldelser")</label> 4859 } 4860 </div> 4861 </div> 4862 </div> 4863 } 4864 @inherits ViewModelTemplate<ProductViewModel> 4865 @using Dynamicweb.Ecommerce.ProductCatalog 4866 @using Dynamicweb.Rendering 4867 @using Dynamicweb.Rapido.Blocks 4868 4869 @helper RenderProducerInfo(Smartpage.PhilipsonWine.Producer.Model.Producer producer, string id) 4870 { 4871 <div id="@id" class="paragraph-container paragraph-container--full-width producer-section"> 4872 <div class="grid grid--justify-center"> 4873 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 4874 <h2 class="producer-section__header u-ta-center">@producer.ProducerName</h2> 4875 <p class="producer-section__text u-ta-center">@producer.ProducerDescription</p> 4876 <a href="/Default.aspx?ID=@producer.ProducerLink" class="producer-section__link">@Translate("Læs om producenten") <i class="fas fa-angle-right producer-section__link-arrow"></i></a> 4877 <div class="u-flex u-justify-content--center producer-section__image-section"> 4878 <div class="grid__col-md-6 producer-section__image" style="background-image: url('@producer.ProducerImageFirst')"></div> 4879 <div class="grid__col-md-6 producer-section__image" style="background-image: url('@producer.ProducerImageSecond')"></div> 4880 </div> 4881 </div> 4882 </div> 4883 </div> 4884 } 4885 @inherits ViewModelTemplate<ProductViewModel> 4886 @using Dynamicweb.Ecommerce.ProductCatalog 4887 @using Dynamicweb.Rendering 4888 @using Dynamicweb.Rapido.Blocks 4889 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 4890 4891 @functions 4892 { 4893 BlocksPage productAttributeIconsProductPage = BlocksPage.GetBlockPage("Product"); 4894 } 4895 4896 @{ 4897 if (!eventProduct) 4898 { 4899 Block attributeIconsBlock = new Block() 4900 { 4901 Id = "MainProductAttributeIconSection", 4902 SortId = 10, 4903 Template = RenderProductAttributeIcons() 4904 }; 4905 productAttributeIconsProductPage.Add("AttributeIcons", attributeIconsBlock); 4906 } 4907 } 4908 4909 @helper RenderProductAttributeIcons() 4910 { 4911 ProductInformation productInformation = new ProductInformation(Model); 4912 4913 string type = productInformation.Type; 4914 string country = productInformation.Country; 4915 string primaryGrape = productInformation.PrimaryGrape; 4916 string secondaryGrape = productInformation.SecondaryGrape; 4917 string grapeToShow = !string.IsNullOrWhiteSpace(secondaryGrape) ? Translate("Smartpage:ProductDetail.Information.Blend", "Blend") : primaryGrape; 4918 string area = productInformation.Area; 4919 string year = productInformation.Year == "0" ? Translate("Smartpage:ProductDetail.Information.NonVintage", "NV") : productInformation.Year; 4920 4921 <div class="paragraph-container paragraph-container--full-width product-information"> 4922 <div class="grid grid--justify-center"> 4923 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4 js-product-information-swiper-container"> 4924 <div class="product-attributes"> 4925 @if (!string.IsNullOrWhiteSpace(type)) 4926 { 4927 <div class="product-attributes__attribute js-attribute"> 4928 <div class="icon"> 4929 @RenderTypeIcon() 4930 </div> 4931 @type 4932 </div> 4933 } 4934 @if (!string.IsNullOrWhiteSpace(grapeToShow)) 4935 { 4936 <div class="product-attributes__attribute js-attribute"> 4937 <div class="icon"> 4938 @RenderGrapeIcon() 4939 </div> 4940 @grapeToShow 4941 </div> 4942 } 4943 @if (!string.IsNullOrWhiteSpace(country)) 4944 { 4945 <div class="product-attributes__attribute js-attribute"> 4946 <div class="icon"> 4947 @RenderCountryIcon() 4948 </div> 4949 @country 4950 </div> 4951 } 4952 @if (!string.IsNullOrWhiteSpace(area)) 4953 { 4954 <div class="product-attributes__attribute js-attribute"> 4955 <div class="icon"> 4956 @RenderAreaIcon() 4957 </div> 4958 @area 4959 </div> 4960 } 4961 @if (!string.IsNullOrWhiteSpace(year)) 4962 { 4963 <div class="product-attributes__attribute js-attribute"> 4964 <div class="icon"> 4965 @RenderYearIcon() 4966 </div> 4967 @year 4968 </div> 4969 } 4970 </div> 4971 </div> 4972 </div> 4973 </div> 4974 } 4975 4976 @helper RenderTypeIcon() 4977 { 4978 <svg width="28" height="35" xmlns="http://www.w3.org/2000/svg"> 4979 <g fill="#000" fill-rule="nonzero"> 4980 <path d="M9.9 10.753a10.818 10.818 0 01-.951-4.444V3.5a.59.59 0 00.596-.583V.583A.59.59 0 008.95 0H4.176a.59.59 0 00-.596.583v2.334a.59.59 0 00.596.583v2.81a10.822 10.822 0 01-.95 4.443L1.55 14.496A17.628 17.628 0 000 21.744v12.673A.59.59 0 00.597 35h11.931a.59.59 0 00.597-.583V21.744a17.623 17.623 0 00-1.551-7.248l-1.675-3.743zM4.772 1.167h3.58v1.166h-3.58V1.167zm7.159 32.666H1.193v-12.09a16.495 16.495 0 011.451-6.78l1.675-3.744a11.958 11.958 0 001.05-4.91V3.5h2.387v2.81a11.954 11.954 0 001.05 4.91l1.675 3.743a16.495 16.495 0 011.45 6.78v12.09z" /> 4981 <path d="M7.066 14.884l.547 1.175c.283.609.524 1.234.722 1.871.082.264.34.445.632.445a.707.707 0 00.185-.025c.349-.095.548-.44.446-.767a16.303 16.303 0 00-.782-2.02l-.547-1.174a.652.652 0 00-.53-.384.677.677 0 00-.615.251.588.588 0 00-.06.627h.002zM6.62 12.828c.105.18.34.297.601.297.09 0 .18-.014.262-.042.33-.11.482-.4.337-.65l-.448-.775c-.152-.242-.53-.348-.854-.242-.324.107-.478.39-.346.637l.449.775zM3.188 20.125c-.311 0-.563.268-.563.599V30.9c0 .33.252.599.563.599h6.75c.31 0 .562-.268.562-.599V20.724c0-.33-.252-.599-.563-.599h-6.75zm6.187 10.178H3.75v-8.98h5.625v8.98zM26.09 33.6a7.914 7.914 0 00-4.056-1.493v-8.22c3.377-.304 5.962-3.072 5.966-6.387a.564.564 0 00-.006-.083l-.314-2.15v-.004l-.879-6.013a.593.593 0 00-.59-.5h-9.546a.592.592 0 00-.59.5l-1.194 8.167a.564.564 0 00-.006.083c.004 3.315 2.59 6.083 5.966 6.387v8.22a7.911 7.911 0 00-4.057 1.494l-.477.35a.576.576 0 00-.207.65.596.596 0 00.565.399h9.545c.257 0 .485-.16.566-.399a.576.576 0 00-.208-.65l-.477-.35zM17.183 9.917h8.51l.717 4.9-1.148.125a10.303 10.303 0 01-3.888-.317l-.072-.02c-1.465-.407-3-.52-4.512-.333l-.248.03.641-4.385zm-1.114 7.623l.298-2.042.57-.068c1.35-.17 2.72-.07 4.03.292l.07.02c1.414.397 2.895.518 4.357.357l1.185-.13.229 1.571c0 2.9-2.404 5.25-5.37 5.25-2.965 0-5.369-2.35-5.369-5.25zm2.64 16.293a6.812 6.812 0 015.46 0h-5.46z" /> 4982 </g> 4983 </svg> 4984 } 4985 4986 @helper RenderGrapeIcon() 4987 { 4988 <img src="~/Files/Images/philipsonwine/ikoner/drue.png" alt="Drue" /> 4989 } 4990 4991 @helper RenderCountryIcon() 4992 { 4993 <svg width="36" height="35" xmlns="http://www.w3.org/2000/svg"> 4994 <path d="M18.12 0C10.995-.001 4.556 4.174 1.751 10.612l-.221.072.086.254c-3.693 8.952.696 19.15 9.803 22.78 2.127.848 4.4 1.283 6.696 1.282 9.833.001 17.805-7.832 17.806-17.497C35.923 7.838 27.953 0 18.121 0zm13.965 26.323l-.914-.898v-2.092a.574.574 0 00-.06-.26l-2.314-4.544v-2.196a.58.58 0 00-.264-.485l-1.78-1.167a.602.602 0 00-.475-.08l-2.18.535-3.663-1.544-.503-3.47 1.396-1.372h2.997l1.01 1.49a.594.594 0 00.396.252l3.56.583a.598.598 0 00.285-.022l3.28-1.075a16.037 16.037 0 01-.771 16.345zM29.637 5.748l-.965.632-2.69-.529-1.745-.57a.592.592 0 00-.331-.014l-2.207.542-.967-.316.717-1.41h2.007c.092 0 .183-.02.265-.06l2.054-1.01a16.673 16.673 0 013.862 2.735zM11.615 2.47l1.424.934c.07.045.15.076.232.09l2.876.47-.28.826-1.499.492a.592.592 0 00-.321.252l-1.704 2.792L9.605 9.94l-4.035.566a.587.587 0 00-.51.577v1.75c0 .155.062.303.173.413l1.013.995v1.003l-2.469-1.619-.895-2.64c1.704-3.827 4.827-6.872 8.733-8.516zm-1.69 19.126l-2.682-.528-.997-1.955v-1.37l2.211-2.174.819 1.61c.1.197.306.322.53.322h3.82l1.607 2.634c.107.175.3.283.508.283h1.65l-.415 2.045-2.247 2.209a.579.579 0 00-.175.412v1.459l-2.136 1.575a.58.58 0 00-.237.466v2.107l-.739-.24-1.042-2.562v-5.721a.586.586 0 00-.474-.572zm-1.783 8.967C2.546 26.436.18 19.307 2.223 12.731l.493 1.453a.584.584 0 00.234.301l2.958 1.939-.675.664a.578.578 0 00-.174.412v1.75c0 .09.022.18.063.26l1.187 2.334a.592.592 0 00.415.311l2.492.49V28c0 .074.015.148.043.216l1.186 2.917a.59.59 0 00.364.337l1.78.583a.592.592 0 00.779-.553v-2.625l2.136-1.575a.58.58 0 00.237-.467v-1.508l2.2-2.163a.58.58 0 00.162-.298l.594-2.916a.584.584 0 00-.582-.698h-2.038l-1.607-2.634a.596.596 0 00-.509-.283h-3.787l-1.02-2.01a.593.593 0 00-.436-.315.588.588 0 00-.515.163l-.77.754V14a.578.578 0 00-.174-.412l-1.013-.996v-1.003l3.645-.512a.603.603 0 00.221-.077l2.968-1.75a.588.588 0 00.203-.2L14.95 6.32l1.572-.516a.582.582 0 00.375-.369l.594-1.75a.581.581 0 00-.465-.758l-3.435-.563-.604-.395a16.84 16.84 0 0111.413.417l-1.084.532h-2.234a.595.595 0 00-.534.322l-1.187 2.334a.579.579 0 00.344.813l1.78.584c.107.035.222.04.331.012l2.207-.541 1.616.529a.442.442 0 00.072.018l2.967.584c.154.03.315 0 .445-.087l1.351-.885a16.482 16.482 0 011.785 2.344l-2.92.957-3.16-.518-1.045-1.54a.596.596 0 00-.491-.26h-3.56a.599.599 0 00-.42.171l-1.78 1.75a.577.577 0 00-.169.495l.594 4.084c.03.202.165.374.356.453l4.154 1.75c.12.05.252.061.377.03l2.12-.521 1.295.85v2.022c0 .09.02.18.06.26l2.314 4.544v2.196c0 .154.063.303.174.412l1.241 1.221c-5.506 7.214-15.918 8.675-23.257 3.262z" fill="#000" fill-rule="nonzero" /> 4995 </svg> 4996 } 4997 4998 @helper RenderAreaIcon() 4999 { 5000 <svg width="37" height="37" xmlns="http://www.w3.org/2000/svg"> 5001 <g fill="#000" fill-rule="nonzero"> 5002 <path d="M36.293 28.59c-5.907 0-11.704 2.595-15.905 7.119a.795.795 0 00.002 1.07c.138.148.319.221.5.221a.682.682 0 00.5-.223c3.938-4.24 9.37-6.671 14.903-6.671.39 0 .707-.34.707-.758s-.317-.757-.707-.757zM21.736 28.077a.742.742 0 00-1.03-.2 29.285 29.285 0 00-7.966 7.968.742.742 0 101.232.827 27.8 27.8 0 017.565-7.566c.34-.229.429-.69.2-1.03zM36.262 22.705c-3.298 0-6.562.61-9.702 1.812-.384.147-.585.603-.45 1.019a.743.743 0 00.696.532.687.687 0 00.246-.046 25.668 25.668 0 019.21-1.72c.408 0 .738-.358.738-.799 0-.441-.33-.798-.738-.798z" /> 5003 <path d="M10.354 32.041c4.754-6.199 11.636-10.503 19.23-12.116h.005a32.209 32.209 0 016.688-.705.723.723 0 000-1.446c-2.054 0-4.101.188-6.113.556v-1.56c2.612-2.21 4.045-5.108 4.045-8.194 0-3.19-1.532-6.179-4.315-8.417a.723.723 0 00-.906 0c-2.783 2.238-4.316 5.227-4.316 8.417 0 3.086 1.434 5.983 4.046 8.194v1.856c-1.373.312-2.726.71-4.051 1.19v-4.23a.72.72 0 00-.21-.51l-4.047-4.071a.723.723 0 00-.513-.213h-8.262a.723.723 0 00-.513.213l-4.046 4.07a.72.72 0 00-.21.51v2.76a33.809 33.809 0 00-1.518-.243v-2.576c1.975-1.7 3.059-3.915 3.059-6.276 0-2.466-1.183-4.775-3.33-6.501a.723.723 0 00-.905 0C2.026 4.475.843 6.784.843 9.249c0 2.361 1.084 4.577 3.06 6.276v2.41a34.156 34.156 0 00-3.18-.149.723.723 0 100 1.446c5.778 0 11.43 1.529 16.413 4.429a34.114 34.114 0 00-3.414 2.651C9.685 24.256 5.2 23.17.722 23.17a.723.723 0 000 1.445c4.074 0 8.156.948 11.865 2.747a34.154 34.154 0 00-3.074 3.402 22.605 22.605 0 00-8.79-1.776.723.723 0 000 1.445c2.71 0 5.36.514 7.89 1.525-.5.694-.974 1.407-1.42 2.139L6.092 35.9a.722.722 0 101.233.753l1.102-1.804a32.082 32.082 0 011.856-2.716.684.684 0 00.071-.093zM26.118 8.576c0-2.568 1.175-5.001 3.323-6.908 2.148 1.907 3.323 4.34 3.323 6.908 0 2.264-.913 4.422-2.6 6.208V9.25a.723.723 0 10-1.446 0v5.534c-1.687-1.786-2.6-3.944-2.6-6.208zm-23.83.674c0-1.843.826-3.594 2.337-4.985 1.511 1.39 2.336 3.142 2.336 4.985 0 1.523-.564 2.984-1.613 4.23V8.673a.723.723 0 10-1.446 0v4.809C2.853 12.234 2.29 10.773 2.29 9.25zm19.919 5.612h-6.225l-2.61-2.625h6.225l2.61 2.625zM11.635 12.54l2.31 2.323h-4.62l2.31-2.323zM8.31 16.308h6.648v4.595a34.266 34.266 0 00-1.012-.446V18.03a.723.723 0 00-.722-.723h-3.18a.723.723 0 00-.723.723v.86c-.336-.088-.673-.171-1.011-.249v-2.333zm4.191 3.579a33.933 33.933 0 00-1.734-.587v-.547h1.734v1.134zm3.902 1.723v-5.302h6.818v4.07a33.917 33.917 0 00-4.732 2.409 34.266 34.266 0 00-2.086-1.177z" /> 5004 <path d="M29.432 7.568c.22 0 .438-.09.594-.247a.847.847 0 00.247-.594.846.846 0 00-.247-.594.846.846 0 00-.594-.247.845.845 0 00-.841.841.846.846 0 00.84.841zM22.95 26.315a.848.848 0 00-.245.594c0 .222.09.438.246.595a.847.847 0 00.594.246c.222 0 .439-.09.595-.246a.846.846 0 00.246-.595.846.846 0 00-.84-.84.847.847 0 00-.595.246z" /> 5005 </g> 5006 </svg> 5007 } 5008 5009 @helper RenderYearIcon() 5010 { 5011 <svg width="35" height="35" xmlns="http://www.w3.org/2000/svg"> 5012 <g fill="#000" fill-rule="nonzero"> 5013 <path d="M33.25 2.333h-2.917V1.75A1.75 1.75 0 0028.583 0h-1.166a1.75 1.75 0 00-1.75 1.75v.583H9.333V1.75A1.75 1.75 0 007.583 0H6.417a1.75 1.75 0 00-1.75 1.75v.583H1.75A1.75 1.75 0 000 4.083V33.25C0 34.216.784 35 1.75 35h31.5A1.75 1.75 0 0035 33.25V4.083a1.75 1.75 0 00-1.75-1.75zm-6.417-.583c0-.322.262-.583.584-.583h1.166c.322 0 .584.26.584.583v3.5a.583.583 0 01-.584.583h-1.166a.583.583 0 01-.584-.583v-3.5zm-21 0c0-.322.262-.583.584-.583h1.166c.322 0 .584.26.584.583v3.5a.583.583 0 01-.584.583H6.417a.583.583 0 01-.584-.583v-3.5zM1.167 4.083c0-.322.26-.583.583-.583h2.917v1.75c0 .966.783 1.75 1.75 1.75h1.166a1.75 1.75 0 001.75-1.75V3.5h16.334v1.75c0 .966.783 1.75 1.75 1.75h1.166a1.75 1.75 0 001.75-1.75V3.5h2.917c.322 0 .583.261.583.583v4.084H1.167V4.083zM33.833 33.25a.583.583 0 01-.583.583H1.75a.583.583 0 01-.583-.583V9.333h32.666V33.25z" /> 5014 <path d="M18.667 23.333h-2.334a.583.583 0 01-.583-.583v-2.333c0-.322.261-.584.583-.584h2.334c.322 0 .583.262.583.584v2.333a.583.583 0 01-.583.583zm-1.75-1.166h1.166V21h-1.166v1.167zM24.5 23.333h-2.333a.583.583 0 01-.584-.583v-2.333c0-.322.262-.584.584-.584H24.5c.322 0 .583.262.583.584v2.333a.583.583 0 01-.583.583zm-1.75-1.166h1.167V21H22.75v1.167zM12.833 23.333H10.5a.583.583 0 01-.583-.583v-2.333c0-.322.26-.584.583-.584h2.333c.322 0 .584.262.584.584v2.333a.583.583 0 01-.584.583zm-1.75-1.166h1.167V21h-1.167v1.167zM30.333 23.333H28a.583.583 0 01-.583-.583v-2.333c0-.322.26-.584.583-.584h2.333c.322 0 .584.262.584.584v2.333a.583.583 0 01-.584.583zm-1.75-1.166h1.167V21h-1.167v1.167zM7 23.333H4.667a.583.583 0 01-.584-.583v-2.333c0-.322.262-.584.584-.584H7c.322 0 .583.262.583.584v2.333a.583.583 0 01-.583.583zm-1.75-1.166h1.167V21H5.25v1.167zM18.667 17.5h-2.334a.583.583 0 01-.583-.583v-2.334c0-.322.261-.583.583-.583h2.334c.322 0 .583.261.583.583v2.334a.583.583 0 01-.583.583zm-1.75-1.167h1.166v-1.166h-1.166v1.166zM24.5 17.5h-2.333a.583.583 0 01-.584-.583v-2.334c0-.322.262-.583.584-.583H24.5c.322 0 .583.261.583.583v2.334a.583.583 0 01-.583.583zm-1.75-1.167h1.167v-1.166H22.75v1.166zM12.833 17.5H10.5a.583.583 0 01-.583-.583v-2.334c0-.322.26-.583.583-.583h2.333c.322 0 .584.261.584.583v2.334a.583.583 0 01-.584.583zm-1.75-1.167h1.167v-1.166h-1.167v1.166zM30.333 17.5H28a.583.583 0 01-.583-.583v-2.334c0-.322.26-.583.583-.583h2.333c.322 0 .584.261.584.583v2.334a.583.583 0 01-.584.583zm-1.75-1.167h1.167v-1.166h-1.167v1.166zM7 17.5H4.667a.583.583 0 01-.584-.583v-2.334c0-.322.262-.583.584-.583H7c.322 0 .583.261.583.583v2.334A.583.583 0 017 17.5zm-1.75-1.167h1.167v-1.166H5.25v1.166zM18.667 29.167h-2.334a.583.583 0 01-.583-.584V26.25c0-.322.261-.583.583-.583h2.334c.322 0 .583.26.583.583v2.333a.583.583 0 01-.583.584zM16.917 28h1.166v-1.167h-1.166V28zM24.5 29.167h-2.333a.583.583 0 01-.584-.584V26.25c0-.322.262-.583.584-.583H24.5c.322 0 .583.26.583.583v2.333a.583.583 0 01-.583.584zM22.75 28h1.167v-1.167H22.75V28zM12.833 29.167H10.5a.583.583 0 01-.583-.584V26.25c0-.322.26-.583.583-.583h2.333c.322 0 .584.26.584.583v2.333a.583.583 0 01-.584.584zM11.083 28h1.167v-1.167h-1.167V28zM30.333 29.167H28a.583.583 0 01-.583-.584V26.25c0-.322.26-.583.583-.583h2.333c.322 0 .584.26.584.583v2.333a.583.583 0 01-.584.584zM28.583 28h1.167v-1.167h-1.167V28zM7 29.167H4.667a.583.583 0 01-.584-.584V26.25c0-.322.262-.583.584-.583H7c.322 0 .583.26.583.583v2.333a.583.583 0 01-.583.584zM5.25 28h1.167v-1.167H5.25V28z" /> 5015 </g> 5016 </svg> 5017 } 5018 @inherits ViewModelTemplate<ProductViewModel> 5019 @using Dynamicweb.Ecommerce.ProductCatalog 5020 @using Dynamicweb.Rendering 5021 @using Dynamicweb.Rapido.Blocks 5022 5023 @helper RenderInPageMenu(List<Block> sections) 5024 { 5025 var excludedSections = new List<string> { 5026 "InPageMenu", 5027 "ClerkAlternativesSection", 5028 "ClerkOthersAlsoBoughtSection" 5029 }; 5030 <div class="paragraph-container paragraph-container--full-width in-page-menu"> 5031 <div class="grid grid--justify-center"> 5032 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 5033 <div class="in-page-menu__wrapper"> 5034 @foreach (var productSection in sections.OrderBy(x => x.SortId)) 5035 { 5036 if (!excludedSections.Contains(productSection.Id)) 5037 { 5038 <div class="in-page-menu__wrapper__item js-in-page-menu__wrapper__item hover hover-3" onclick="scrollToNode('#@productSection.Id', -56)" data-id="@productSection.Id"> 5039 @Translate("Smartpage:Product.InPageMenu.Title." + productSection.Id, productSection.Id) 5040 </div> 5041 } 5042 } 5043 </div> 5044 </div> 5045 </div> 5046 </div> 5047 } 5048 @inherits ViewModelTemplate<ProductViewModel> 5049 @using Dynamicweb.Ecommerce.ProductCatalog 5050 @using Dynamicweb.Rendering 5051 @using Dynamicweb.Rapido.Blocks 5052 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 5053 @using Dynamicweb.Core 5054 5055 @functions 5056 { 5057 public string createFilterCheckboxLink(string key, string value) 5058 { 5059 string filterValue = "[" + value + "]"; 5060 string link = "&" + key + "=" + HttpUtility.UrlEncode(filterValue); 5061 return link; 5062 } 5063 } 5064 5065 @helper RenderProductFields(string id) 5066 { 5067 ProductInformation productInformation = new ProductInformation(Model); 5068 string type = productInformation.Type; 5069 int bottleSizeCl = productInformation.BottleSizeCl; 5070 string producerId = productInformation.ProducerId; 5071 string country = productInformation.Country; 5072 string area = productInformation.Area; 5073 string primaryGrape = productInformation.PrimaryGrape; 5074 string recommendedTo = productInformation.RecommendedTo; 5075 string storage = productInformation.Storage; 5076 int alcoholPercentage = Converter.ToInt32(productInformation.AlcoholPercentage); 5077 string acidityLevel = productInformation.AcidityLevel; 5078 string restSweet = productInformation.RestSweet; 5079 bool ecological = productInformation.Ecological; 5080 5081 string perfionId = productInformation.PerfionId; 5082 string perfionDataSheetPageId = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("PerfionDataSheetPageId"); 5083 string datasheetUrl = string.Empty; 5084 5085 if (!string.IsNullOrEmpty(perfionId) && !string.IsNullOrEmpty(perfionDataSheetPageId)) 5086 { 5087 datasheetUrl = string.Format("/Default.aspx?ID={0}&ReportId={1}", perfionDataSheetPageId, perfionId); 5088 } 5089 5090 string keyColClasses = "grid__col-5 grid__col-sm-4"; 5091 string valueColClasses = "grid__col-7 grid__col-sm-8"; 5092 5093 <div id="@id" class="paragraph-container paragraph-container--full-width product-fields"> 5094 <div class="grid grid--justify-center"> 5095 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4 product-fields-section"> 5096 <h3 class="product-fields-section__header">@Translate("Smartpage:ProductDetail.ProductFields.Header", "Informationer")</h3> 5097 <div class="product-fields-section__fields"> 5098 <div class="field grid"> 5099 <div class="@keyColClasses field__key"> 5100 @Translate("Smartpage:ProductDetail.ProductFields.ProductNumber", "Varenummer") 5101 </div> 5102 <div class="@valueColClasses field__value">@Model.Id</div> 5103 </div> 5104 @if (!string.IsNullOrWhiteSpace(type)) 5105 { 5106 string link = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + createFilterCheckboxLink("Type", type); 5107 <div class="field grid"> 5108 <div class="@keyColClasses field__key"> 5109 @Translate("Smartpage:ProductDetail.ProductFields.Type", "Type") 5110 </div> 5111 <div class="@valueColClasses field__value"> 5112 <a class="link" href="@link">@type</a> 5113 </div> 5114 </div> 5115 } 5116 @if (bottleSizeCl > 0) 5117 { 5118 <div class="field grid"> 5119 <div class="@keyColClasses field__key"> 5120 @Translate("Smartpage:ProductDetail.ProductFields.BottleSize", "Flaskestørrelse") 5121 </div> 5122 <div class="@valueColClasses field__value"> 5123 @productInformation.BottleSize 5124 </div> 5125 </div> 5126 } 5127 @if (productInformation.Kolli > 1) 5128 { 5129 <div class="field grid"> 5130 <div class="@keyColClasses field__key"> 5131 @Translate("Smartpage:ProductDetail.ProductFields.DeliveredIn", "Leveres i") 5132 </div> 5133 <div class="@valueColClasses field__value"> 5134 @Translate("Smartpage:ProductDetail.ProductFields.DeliveredIn.CartonWith", "Leveres i karton med") @productInformation.Kolli @Translate("Smartpage:ProductDetail.ProductFields.DeliveredIn.Unit", "stk.") 5135 </div> 5136 </div> 5137 } 5138 @if (alcoholPercentage > 0) 5139 { 5140 <div class="field grid"> 5141 <div class="@keyColClasses field__key"> 5142 @Translate("Smartpage:ProductDetail.ProductFields.AlcoholPercentage", "Alkoholprocent") 5143 </div> 5144 <div class="@valueColClasses field__value"> 5145 @alcoholPercentage% 5146 </div> 5147 </div> 5148 } 5149 @if (!string.IsNullOrWhiteSpace(acidityLevel)) 5150 { 5151 <div class="field grid"> 5152 <div class="@keyColClasses field__key"> 5153 @Translate("Smartpage:ProductDetail.ProductFields.AcidityLevel", "Syreniveau") 5154 </div> 5155 <div class="@valueColClasses field__value"> 5156 @acidityLevel% 5157 </div> 5158 </div> 5159 } 5160 @if (!string.IsNullOrWhiteSpace(producerId)) 5161 { 5162 var producerService = new Smartpage.PhilipsonWine.Producer.Repositories.ProducerService(); 5163 var producer = producerService.GetProductProducer(producerId); 5164 5165 if (producer != null && !string.IsNullOrWhiteSpace(producer.ProducerName) && !string.IsNullOrWhiteSpace(producer.ProducerLink) && !producer.ProducerHidden) 5166 { 5167 <div class="field grid"> 5168 <div class="@keyColClasses field__key"> 5169 @Translate("Smartpage:ProductDetail.ProductFields.Producer", "Producent") 5170 </div> 5171 <div class="@valueColClasses field__value"> 5172 <a class="link" href="/Default.aspx?ID=@producer.ProducerLink">@producer.ProducerName</a> 5173 </div> 5174 </div> 5175 } 5176 } 5177 @if (!string.IsNullOrWhiteSpace(country)) 5178 { 5179 string link = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + createFilterCheckboxLink("Country", country); 5180 <div class="field grid"> 5181 <div class="@keyColClasses field__key"> 5182 @Translate("Smartpage:ProductDetail.ProductFields.Country", "Land") 5183 </div> 5184 <div class="@valueColClasses field__value"> 5185 <a class="link" href="@link">@country</a> 5186 </div> 5187 </div> 5188 } 5189 @if (!string.IsNullOrWhiteSpace(area)) 5190 { 5191 string link = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + createFilterCheckboxLink("Region", area); 5192 <div class="field grid"> 5193 <div class="@keyColClasses field__key"> 5194 @Translate("Smartpage:ProductDetail.ProductFields.Area", "Area") 5195 </div> 5196 <div class="@valueColClasses field__value"> 5197 <a class="link" href="@link">@area</a> 5198 </div> 5199 </div> 5200 } 5201 @if (!string.IsNullOrWhiteSpace(primaryGrape)) 5202 { 5203 string primaryGrapeLink = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&Grape=" + HttpUtility.UrlEncode("[" + primaryGrape + "]"); 5204 string secondaryGrape = productInformation.SecondaryGrape; 5205 string grapeComposition = productInformation.GrapeComposition; 5206 5207 <div class="field grid"> 5208 <div class="@keyColClasses field__key"> 5209 @Translate("Smartpage:ProductDetail.ProductFields.Grapes", "Druesorter") 5210 </div> 5211 <div class="@valueColClasses field__value"> 5212 @if (string.IsNullOrWhiteSpace(secondaryGrape)) 5213 { 5214 <a class="link" href="@primaryGrapeLink">@grapeComposition</a> 5215 } 5216 else 5217 { 5218 string blendLink = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&Grape=" + HttpUtility.UrlEncode("[" + primaryGrape + "],") + HttpUtility.UrlEncode("[" + secondaryGrape + "]"); 5219 <a class="link" href="@blendLink">@grapeComposition</a> 5220 } 5221 </div> 5222 </div> 5223 } 5224 @if (!string.IsNullOrWhiteSpace(recommendedTo)) 5225 { 5226 string recommendedToFormatted = recommendedTo.Replace(",", ", "); 5227 <div class="field grid"> 5228 <div class="@keyColClasses field__key"> 5229 @Translate("Smartpage:ProductDetail.ProductFields.ReccommendedTo", "Anbefalet til") 5230 </div> 5231 <div class="@valueColClasses field__value"> 5232 @recommendedToFormatted 5233 </div> 5234 </div> 5235 } 5236 @if (!string.IsNullOrWhiteSpace(storage)) 5237 { 5238 <div class="field grid"> 5239 <div class="@keyColClasses field__key"> 5240 @Translate("Smartpage:ProductDetail.ProductFields.Storage", "Lagring") 5241 </div> 5242 <div class="@valueColClasses field__value"> 5243 @storage 5244 </div> 5245 </div> 5246 } 5247 @if (!string.IsNullOrWhiteSpace(restSweet)) 5248 { 5249 <div class="field grid"> 5250 <div class="@keyColClasses field__key"> 5251 @Translate("Smartpage:ProductDetail.ProductFields.RestSweet", "Restsukker") 5252 </div> 5253 <div class="@valueColClasses field__value"> 5254 @restSweet 5255 </div> 5256 </div> 5257 } 5258 @if (ecological) 5259 { 5260 <div class="field grid"> 5261 <div class="@keyColClasses field__key"> 5262 @Translate("Smartpage:ProductDetail.ProductFields.Ecological", "Økologisk") 5263 </div> 5264 <div class="@valueColClasses field__value"> 5265 @Translate("Smartpage:ProductDetail.ProductFields.Ecological.Yes", "Ja") 5266 </div> 5267 </div> 5268 } 5269 @if (!string.IsNullOrWhiteSpace(datasheetUrl)) 5270 { 5271 <a href="@datasheetUrl" class="btn btn--download-datasheet">@Translate("Smartpage:ProductDetail.ProductFields.DownloadDatasheet", "Download produktblad") <i class="fal fa-arrow-to-bottom"></i></a> 5272 } 5273 </div> 5274 </div> 5275 </div> 5276 </div> 5277 } 5278 @inherits ViewModelTemplate<ProductViewModel> 5279 @using Dynamicweb.Ecommerce.ProductCatalog 5280 @using Dynamicweb.Rendering 5281 @using System.Collections.Generic 5282 5283 @helper RenderExpertRatings(List<Smartpage.PhilipsonWine.Ratings.Model.ProductRating> rating, string id) 5284 { 5285 var expertRatingsCounter = 0; 5286 5287 <div id="@id" class="paragraph-container paragraph-container--full-width expert-ratings js-expert-ratings"> 5288 <div class="grid grid--justify-center"> 5289 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 5290 <h3 class="u-no-margin heading-reviews">@Translate("Anmeldelser")</h3> 5291 <hr class="horizontal-line" /> 5292 5293 @foreach (var item in rating) 5294 { 5295 5296 expertRatingsCounter++; 5297 if (expertRatingsCounter == 3) 5298 { 5299 @:<div class="js-hidden-ratings u-hidden"> 5300 } 5301 if (expertRatingsCounter > 1) 5302 { 5303 <hr class="separation-line--width-full u-margin-top--lg u-margin-bottom--lg" /> 5304 } 5305 5306 if (item.RatingType == "4") 5307 { 5308 var count = 0; 5309 5310 <div class="customer-rating"> 5311 5312 @foreach (var cr in item.CombinedRatings) 5313 { 5314 count++; 5315 5316 if (count == 1) 5317 { 5318 <label class="u-bold">@cr.RatingMedia</label> 5319 5320 } 5321 5322 <div class="expert-ratings__rating"> 5323 @RenderExpertRating(cr.RatingScoreTo, cr.RatingScoreFrom, cr.RatingMaxScore, cr.RatingType, cr.RatingTextScore) 5324 </div> 5325 5326 if (count == item.CombinedRatings.Count) 5327 { 5328 <p class="u-no-margin u-italic">@cr.RatingQuote</p> 5329 } 5330 } 5331 </div> 5332 5333 } 5334 else 5335 { 5336 <div class="customer-rating"> 5337 <label class="u-bold">@item.RatingMedia</label> 5338 <div class="expert-ratings__rating"> 5339 @RenderExpertRating(item.RatingScoreTo, item.RatingScoreFrom, item.RatingMaxScore, item.RatingType, item.RatingTextScore) 5340 </div> 5341 <p class="u-no-margin u-italic">@item.RatingQuote</p> 5342 </div> 5343 } 5344 5345 if (expertRatingsCounter == rating.Count && expertRatingsCounter >= 3) 5346 { 5347 @:</div> 5348 } 5349 } 5350 @if (expertRatingsCounter > 2) 5351 { 5352 <label class="u-margin-top--lg u-bold show-more js-show-more" data-show-description="@Translate("- skjul anmeldelser")">@Translate("+ flere anmeldelser")</label> 5353 } 5354 </div> 5355 </div> 5356 </div> 5357 } 5358 5359 @inherits ViewModelTemplate<ProductViewModel> 5360 @using Dynamicweb.Ecommerce.ProductCatalog 5361 @using Dynamicweb.Rendering 5362 @using Dynamicweb.Core 5363 @using System 5364 @using System.Web 5365 @using System.Collections.Generic 5366 @using Dynamicweb.Rapido.Services 5367 @using Dynamicweb.Rapido.Blocks 5368 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 5369 @using Dynamicweb.Rapido.Blocks.Components.General 5370 @using System.Text.RegularExpressions; 5371 @using Smartpage.PhilipsonWine.Ratings; 5372 @using Smartpage.PhilipsonWine.Ratings.Model; 5373 5374 5375 @functions 5376 { 5377 BlocksPage ratingBadgesSectionProductPage = BlocksPage.GetBlockPage("Product"); 5378 BlocksPage ratingBadgeSvgFooterBlock = BlocksPage.GetBlockPage("Master"); 5379 } 5380 5381 @{ 5382 5383 var customerRating = GetCustomerRatingValues(Converter.ToDouble(Model.Rating)); 5384 5385 //Getting expert rating data 5386 var expertRatingsBadge = Smartpage.PhilipsonWine.Ratings.Controller.ProductRatings.GetRatingProduct(Model.Id); 5387 5388 //Adding rating badges section to document 5389 Block ratingBadgesSectionBlock = new Block() 5390 { 5391 Id = "ratingBadgesSection", 5392 Template = RenderRatingsBadges(expertRatingsBadge, customerRating) 5393 }; 5394 5395 if (expertRatingsBadge.Any() || customerRating.ratingInDouble > 0) 5396 { 5397 ratingBadgesSectionProductPage.Add("MainImage", ratingBadgesSectionBlock); 5398 } 5399 } 5400 5401 @helper RenderRatingsBadges(List<ProductRating> expertRatings, (double ratingInPercent, string ratingInText, double ratingInDouble) customerRating) 5402 { 5403 <div class="grid grid__col-3 grid--align-content-center u-no-padding jus badges dw-mod"> 5404 @if (customerRating.ratingInDouble > 0) 5405 { 5406 <div class="u-margin-top"> 5407 @RenderRatingBadge(customerRating.ratingInPercent, Translate("Smartpage:CustomerRating.Philipson Wine", "Philipson Wine"), customerRating.ratingInText) 5408 </div> 5409 } 5410 5411 @foreach (var expertRating in expertRatings.Where(x => x.RatingType != Converter.ToString((int)Smartpage.PhilipsonWine.Ratings.Controller.ProductRatings.RatingTypes.FullRating) && x.RatingType != Converter.ToString((int)Smartpage.PhilipsonWine.Ratings.Controller.ProductRatings.RatingTypes.FreeText) && !string.Equals(x.RatingMedia, "den korte avis", StringComparison.InvariantCultureIgnoreCase)).Take(3)) 5412 { 5413 var item = GetExpertRatingValues(expertRating); 5414 5415 <div class="u-margin-top"> 5416 @RenderRatingBadge(Converter.ToDouble(item.ratingPercentage), item.ratingName, item.ratingText, false, item.ratingImage) 5417 </div> 5418 } 5419 5420 </div> 5421 } 5422 5423 5424 @inherits ViewModelTemplate<ProductViewModel> 5425 @using Dynamicweb.Ecommerce.ProductCatalog 5426 @using Dynamicweb.Rendering 5427 @using Dynamicweb.Rapido.Blocks 5428 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 5429 @using Smartpage.PhilipsonWine.BomItems 5430 5431 5432 @*@using Dynamicweb.Ecommerce.ProductCatalog 5433 @using Dynamicweb.Rendering 5434 @using Dynamicweb.Core 5435 @using System 5436 @using System.Web 5437 @using System.Collections.Generic 5438 @using Dynamicweb.Rapido.Blocks 5439 @using Dynamicweb.Rapido.Blocks.Components 5440 @using Dynamicweb.Rapido.Blocks.Components.General 5441 @using Dynamicweb.Rapido.Services 5442 5443 @helper GridView(Dynamicweb.Frontend.ItemViewModel gridViewSettings) 5444 { 5445 int columnsCount = gridViewSettings.GetList("Columns") != null ? Converter.ToInt32(gridViewSettings.GetList("Columns").SelectedValue) : 3; 5446 string imageZoomOnHover = gridViewSettings.GetBoolean("HoverImageZoom") ? "image-hover--zoom" : ""; 5447 5448 <script id="ProductGridItemContainer" type="text/x-template"> 5449 {{#.}} 5450 <div id="Product{{id}}" data-template="GridViewItem" data-preloader="overlay" class="grid__col-lg-@(12 / columnsCount) grid__col-md-6 grid__col-sm-6 grid__col-xs-6 product-list__grid-item @imageZoomOnHover dw-mod product-list-product"> 5451 {{#Product}} 5452 {{>GridViewItem}} 5453 {{/Product}} 5454 </div> 5455 {{/.}} 5456 </script> 5457 } 5458 5459 @helper RenderGridViewItem(BlocksPage page) 5460 { 5461 List<Block> subBlocks = page.GetBlockListById("GridViewItem"); 5462 5463 <script id="GridViewItem" type="text/x-template"> 5464 {{#.}} 5465 <div class="grid__col--auto js-product-scroll-trigger u-no-padding u-full-height u-grey-border u-white-background u-padding-sides-8px" data-params="{{googleImpression}}"> 5466 {{>RenderRatingsBadges}} 5467 @RenderBlockList(subBlocks) 5468 </div> 5469 {{/.}} 5470 </script> 5471 5472 <script id="RenderRatingsBadges" type="text/x-template"> 5473 <div class="productlist-rating-badges"> 5474 {{#if CustomerRatingActive}} 5475 <div class="rating-badge c100 js-badge" data-percent="{{CustomerRatingInPercent}}"> 5476 <span class="rating-badge--text">@Translate("Smartpage:CustomerRating.Philipson Wine", "Philipson Wine")</span> 5477 <span class="rating-badge--score">{{{CustomerRatingInText}}}</span> 5478 <div class="slice"> 5479 <div class="bar"></div> 5480 <div class="fill"></div> 5481 </div> 5482 </div> 5483 {{/if}} 5484 {{#ExpertRatings}} 5485 {{#if image}} 5486 <div class="expert-rating-image"> 5487 @{ 5488 var imagePrefix = "/Admin/Public/GetImage.ashx?width=46&amp;height=46&amp;crop=5&amp;Compression=75&amp;FillCanvas=true&amp;DoNotUpscale=true&amp;image=/Files/Images/ExpertRatings/{{image}}.png"; 5489 5490 // CDN 5491 var cdnUrl = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("CDNUrl"); 5492 bool cdnActivate = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetBoolean("CDNActivate"); 5493 if (!string.IsNullOrWhiteSpace(cdnUrl) && cdnActivate) 5494 { 5495 imagePrefix = cdnUrl + imagePrefix; 5496 } 5497 } 5498 <img class="rating-image" src="@imagePrefix" alt="{{name}}" /> 5499 <span class="rating-image--score">{{{text}}}</span> 5500 </div> 5501 {{else}} 5502 <div class="rating-badge c100 dark js-badge" data-percent="{{percentage}}"> 5503 <span class="rating-badge--text">{{name}}</span> 5504 <span class="rating-badge--score">{{{text}}}</span> 5505 <div class="slice"> 5506 <div class="bar"></div> 5507 <div class="fill"></div> 5508 </div> 5509 </div> 5510 {{/if}} 5511 {{/ExpertRatings}} 5512 </div> 5513 </script> 5514 5515 5516 5517 } 5518 5519 @helper RenderGridViewItemHiddenProperties() 5520 { 5521 <input type="hidden" name="ProductLoopCounter{{id}}" value="{{id}}" /> 5522 <input type="hidden" name="ProductID{{id}}" value="{{productId}}" /> 5523 <input type="hidden" name="VariantID{{id}}" value="{{variantid}}" id="Variant_{{id}}" /> 5524 <input type="hidden" name="UnitID{{id}}" value="{{unitId}}" id="Unit_{{id}}" /> 5525 } 5526 5527 @helper RenderGridViewItemImageContainer(BlocksPage page) 5528 { 5529 List<Block> subBlocks = page.GetBlockListById("GridViewItemImageContainer"); 5530 5531 <text> 5532 {{#if eventProduct}} 5533 {{#if eventPromotionText}} 5534 <div class="top-label"> 5535 <div class="top-label__label"> 5536 {{eventPromotionText}} 5537 </div> 5538 </div> 5539 {{/if}} 5540 {{else if isPrimeur}} 5541 <div class="top-label"> 5542 <div class="top-label__label"> 5543 {{isPrimeurText}} 5544 </div> 5545 </div> 5546 {{else}} 5547 {{#if promotionText}} 5548 <div class="top-label"> 5549 <div class="top-label__label"> 5550 {{promotionText}} 5551 </div> 5552 </div> 5553 {{/if}} 5554 {{/if}} 5555 </text> 5556 5557 <div class="product-list__grid-item__image dw-mod {{noImage}}"> 5558 @RenderBlockList(subBlocks) 5559 </div> 5560 } 5561 5562 @helper RenderGridViewItemImage() 5563 { 5564 var imagePrefix = "/Admin/Public/GetImage.ashx?width=300&amp;height=300&amp;crop=5&amp;Compression=75&amp;FillCanvas=true&amp;DoNotUpscale=true&amp;image="; 5565 5566 // CDN 5567 var cdnUrl = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("CDNUrl"); 5568 bool cdnActivate = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetBoolean("CDNActivate"); 5569 if (!string.IsNullOrWhiteSpace(cdnUrl) && cdnActivate) 5570 { 5571 imagePrefix = cdnUrl + imagePrefix; 5572 } 5573 5574 <a href="{{link}}" 5575 onclick="Scroll.SavePosition(event); {{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" 5576 title="{{{name}}}" 5577 class="u-block u-position-relative image-hover__wrapper dw-mod"> 5578 <img class="grid__cell-img grid__cell-img--centered u-padding b-lazy u-full-height" src="/Files/Images/placeholder.gif" 5579 data-src="@imagePrefix{{image}}" alt="{{name}}" /> 5580 </a> 5581 } 5582 5583 @helper RenderGridViewItemStickers() 5584 { 5585 <text> 5586 {{#StickersContainers}} 5587 {{>StickersContainer}} 5588 {{/StickersContainers}} 5589 </text> 5590 } 5591 5592 @helper RenderGridViewItemFavorites() 5593 { 5594 <div class="favorites favorites--for-grid-view u-pull--right {{favoriteProductFromImport}} dw-mod" {{favoriteProductFromImport}}> 5595 {{#Favorite}} 5596 {{>FavoriteTemplate}} 5597 {{/Favorite}} 5598 </div> 5599 } 5600 5601 @helper RenderGridViewItemInfoContainer(BlocksPage page) 5602 { 5603 List<Block> subBlocks = page.GetBlockListById("GridViewItemInfoContainer"); 5604 5605 <div class="grid__cell product-list__grid-item__price-info dw-mod"> 5606 @RenderBlockList(subBlocks) 5607 </div> 5608 } 5609 5610 @helper RenderGridViewItemTitle() 5611 { 5612 <a href="{{link}}" class="u-color-inherit" onclick="{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" title="{{name}}{{#if variantName}}, {{variantName}}{{/if}}"> 5613 <h6 class="u-condensed-text u-bold">{{{name}}}{{#if variantName}}, {{variantName}}{{/if}}</h6> 5614 </a> 5615 } 5616 5617 @helper RenderGridViewItemNumber() 5618 { 5619 <div class="item-number dw-mod">{{number}}</div> 5620 } 5621 5622 @helper RenderGridViewItemPrice(Dynamicweb.Frontend.ItemViewModel gridViewSettings) 5623 { 5624 int columnsCount = gridViewSettings.GetList("Columns") != null ? Converter.ToInt32(gridViewSettings.GetList("Columns").SelectedValue) : 4; 5625 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 5626 bool showCartButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToCartButton"); 5627 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 5628 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 5629 5630 if (pointShopOnly) 5631 { 5632 <text> 5633 {{#if havePointPrice}} 5634 <div class="price price--product-list dw-mod">{{points}} @Translate("points")</div> 5635 @if (showCartButton) 5636 { 5637 <text> 5638 {{#unless canBePurchasedWithPoints}} 5639 <small class="help-text u-no-margin">@Translate("Not enough points to buy this")</small> 5640 {{/unless}} 5641 </text> 5642 } 5643 {{else}} 5644 @Translate("Not available") 5645 {{/if}} 5646 </text> 5647 5648 } 5649 else 5650 { 5651 <div class="price price--product-list dw-mod">{{price}}</div> 5652 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 5653 if (showVATPrice) 5654 { 5655 <div class="vat-price vat-price--product-list u-margin-top dw-mod"> 5656 @if (columnsCount <= 4) 5657 { 5658 if (isPricesWithVATEnabled) 5659 { 5660 <span>@Translate("excl. VAT")</span><span> ({{priceWithoutVAT}})</span> 5661 } 5662 else 5663 { 5664 <span>@Translate("incl. VAT")</span><span> ({{priceWithVAT}})</span> 5665 } 5666 } 5667 else 5668 { 5669 if (isPricesWithVATEnabled) 5670 { 5671 <div>@Translate("excl. VAT")</div><div>({{priceWithoutVAT}})</div> 5672 } 5673 else 5674 { 5675 <div>@Translate("incl. VAT")</div><div>({{priceWithVAT}})</div> 5676 } 5677 } 5678 </div> 5679 } 5680 <text> 5681 {{#if priceRRP}} 5682 <div><small>@Translate("RRP") {{priceRRP}}</small></div> 5683 {{/if}} 5684 </text> 5685 } 5686 } 5687 5688 @helper RenderGridViewItemFooter(BlocksPage page, Dynamicweb.Frontend.ItemViewModel gridViewSettings) 5689 { 5690 List<Block> subBlocks = page.GetBlockListById("GridViewItemFooter"); 5691 bool showStaticVariants = gridViewSettings.GetBoolean("ShowStaticVariants"); 5692 string footerClasses = showStaticVariants ? "u-min-h120px" : ""; 5693 5694 <div class="product-list__grid-item__footer @footerClasses dw-mod u-padding-1px"> 5695 @RenderBlockList(subBlocks) 5696 </div> 5697 } 5698 5699 @helper RenderGridViewItemViewButton(Dynamicweb.Frontend.ItemViewModel gridViewSettings) 5700 { 5701 string viewMoreText = gridViewSettings.GetString("ViewMoreText"); 5702 viewMoreText = !string.IsNullOrEmpty(viewMoreText) ? viewMoreText : "View"; 5703 5704 @Render(new Link 5705 { 5706 Href = "{{link}}", 5707 Id = "CartButton_{{id}}", 5708 Title = Translate(viewMoreText), 5709 OnClick = "{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}", 5710 ButtonLayout = ButtonLayout.Secondary, 5711 CssClass = "u-no-margin" 5712 }); 5713 } 5714 5715 @helper RenderGridViewItemPricesAndAddToCart(Dynamicweb.Frontend.ItemViewModel gridViewSettings, int customerRatingHeartsPadding = 3, bool hideAddToCart = false) 5716 { 5717 5718 int columnsCount = gridViewSettings.GetList("Columns") != null ? Converter.ToInt32(gridViewSettings.GetList("Columns").SelectedValue) : 4; 5719 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 5720 bool showCartButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToCartButton"); 5721 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 5722 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 5723 string addToCartSectionCol = hideAddToCart ? "d-none" : "grid__col-6"; 5724 string pricesSectionCol = hideAddToCart ? "grid__col-12" : "grid__col-6"; 5725 5726 <div class="grid"> 5727 <div class="grid__col-12 {{#if eventProduct}}event-{{/if}}title-container " style="height: 85px;"> 5728 {{#unless eventProduct}} 5729 <span class="area u-ta-center">{{producerName}}</span> 5730 {{/unless}} 5731 <a href="{{link}}" class="u-color-inherit" onclick="Scroll.SavePosition(event); {{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" title="{{name}}"> 5732 <h6 class="u-bold title js-title u-ta-center">{{name}}</h6> 5733 </a> 5734 {{#if eventProduct}} 5735 <p class="event-place"> 5736 {{eventRestaurantName}}, {{eventAddressShort}} 5737 <span class="event-time">{{eventDate}}, {{eventTime}}</span> 5738 </p> 5739 {{/if}} 5740 </div> 5741 </div> 5742 <text> 5743 {{#unless eventProduct}} 5744 <div class="grid"> 5745 <div class="grid__col-12"> 5746 <div class="tags"> 5747 {{#if type}} 5748 <span class="tags__tag">{{type}}</span> 5749 {{/if}} 5750 {{#if area}} 5751 <span class="tags__tag">{{area}}</span> 5752 {{/if}} 5753 {{#if country}} 5754 <span class="tags__tag">{{country}}</span> 5755 {{/if}} 5756 </div> 5757 </div> 5758 </div> 5759 {{/unless}} 5760 </text> 5761 <div class="grid"> 5762 <div class="grid__col-12"> 5763 <div class="customer-ratings-container {{showRating}}"> 5764 <div class="hearts" data-average-rating-percentage="{{ratingPercentage}}" data-heart-padding="@customerRatingHeartsPadding"> 5765 <div class="hearts-outer"> 5766 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 5767 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 5768 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 5769 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 5770 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 5771 <div class="hearts-inner"> 5772 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 5773 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 5774 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 5775 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 5776 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 5777 </div> 5778 </div> 5779 </div> 5780 <span class="rating">({{rating}})</span> 5781 </div> 5782 </div> 5783 </div> 5784 5785 <div class="grid"> 5786 <div class="grid__col-12"> 5787 <p class="short-description">{{description}}</p> 5788 </div> 5789 </div> 5790 5791 <div class="grid"> 5792 <div class="@pricesSectionCol"> 5793 <div class="prices"> 5794 {{#unless eventProduct}} 5795 {{#if savings}} 5796 <div class="savings">@Translate("Smartpage:ProductList.Product.Save", "Spar") {{savings}} @Translate("Smartpage:ProductList.Product.PerUnit", "PR. STK.")</div> 5797 {{/if}} 5798 {{/unless}} 5799 <div class="price price--product-list dw-mod">{{price}}</div> 5800 <div class="quantity-price">{{#if eventProduct}} @Translate("Smartpage:ProductList.Product.Pr.", "Pr.") @Translate("Smartpage:ProductList.Product.Ticket", "billet") {{else}}@Translate("Smartpage:ProductList.Product.Pr.", "Pr.") {{unitShortDescription}} v/{{kolli}} @Translate("Smartpage:ProductList.Product.Unit.Stk", "stk.") {{#if bottleSizeCl}}({{bottleSizeCl}} @Translate("Smartpage:ProductList.Product.Unit.Cl", "cl.")){{/if}}{{/if}}</div> 5801 </div> 5802 </div> 5803 {{#if availableForPurchase}} 5804 <div class="@addToCartSectionCol add-to-cart"> 5805 <div class="grid"> 5806 {{#unless disabledBuyButton}} 5807 <div class="grid__col-5 u-no-padding"> 5808 <input id="Quantity{{id}}" name="Quantity{{id}}" min="1" max="{{stockLevel}}" value="{{kolli}}" type="number" class="quantity dw-mod js-stockcheck js-change-quantity"> 5809 </div> 5810 {{/unless}} 5811 {{#if disabledBuyButton}} 5812 <div class="grid__col-12 u-no-padding"> 5813 <button class="btn btn--add-to-cart {{disabledBuyButton}}" title="@Translate("Smartpage:Product.Buy.OutOfStock", "Udsolgt")" onclick="Cart.AddToCart(event, { id: '{{productId}}', variantId: '{{variantid}}', unitId: '{{unitId}}', productInfo: {{productInfo}}, quantity: parseInt(document.getElementById('Quantity{{id}}').value), SpPrimeur: '{{isPrimeur}}'}); {{facebookPixelAction}}" type="button"> 5814 <span>@Translate("Smartpage:Product.Buy.OutOfStock", "Udsolgt")</span> 5815 </button> 5816 </div> 5817 {{/if}} 5818 {{#unless disabledBuyButton}} 5819 <div class="grid__col-7 u-no-padding"> 5820 <button class="btn btn--add-to-cart {{disabledBuyButton}}" title="@Translate("Smartpage:Product.Buy", "Køb")" onclick="Cart.AddToCart(event, { id: '{{productId}}', variantId: '{{variantid}}', unitId: '{{unitId}}', productInfo: {{productInfo}}, quantity: parseInt(document.getElementById('Quantity{{id}}').value), SpPrimeur: '{{isPrimeur}}'}); {{facebookPixelAction}}" type="button" data-product-id="{{productId}}" data-one-unit-price="{{oneUnitPrice}}" data-volume-unit-price="{{volumeUnitPrice}}" data-volume-unit-threshold="{{kolli}}" data-currency-code="{{currency}}"> 5821 <span>@Translate("Smartpage:Product.Buy", "Køb")</span> 5822 </button> 5823 </div> 5824 {{/unless}} 5825 </div> 5826 </div> 5827 {{/if}} 5828 </div> 5829 5830 } 5831 5832 @helper RenderGridViewItemActions(Dynamicweb.Frontend.ItemViewModel gridViewSettings, int customerRatingHeartsPadding = 2, bool hideAddToCart = false) 5833 { 5834 if (Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 5835 { 5836 @RenderGridViewItemPricesAndAddToCart(gridViewSettings, customerRatingHeartsPadding, hideAddToCart) 5837 } 5838 }*@ 5839 5840 @functions{ 5841 BlocksPage productSliderBlock = new BlocksPage(); 5842 //Dynamicweb.Frontend.ItemViewModel gridViewSettings = null; 5843 } 5844 5845 @{ 5846 gridViewSettings = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView"); 5847 5848 5849 Block bomItemsBlock = new Block 5850 { 5851 Id = "GridViewItem", 5852 SortId = 10, 5853 Template = RenderGridViewItem(productSliderBlock), 5854 SkipRenderBlocksList = true, 5855 BlocksList = new List<Block> { 5856 new Block 5857 { 5858 Id = "GridViewItemHiddenProperties", 5859 SortId = 10, 5860 Template = RenderGridViewItemHiddenProperties() 5861 }, 5862 new Block 5863 { 5864 Id = "GridViewItemImageContainer", 5865 SortId = 20, 5866 SkipRenderBlocksList = true, 5867 Template = RenderGridViewItemImageContainer(productSliderBlock), 5868 BlocksList = new List<Block> { 5869 new Block 5870 { 5871 Id = "GridViewItemImage", 5872 SortId = 10, 5873 Template = RenderGridViewItemImage() 5874 }, 5875 new Block 5876 { 5877 Id = "GridViewItemStickers", 5878 SortId = 20, 5879 Template = RenderGridViewItemStickers() 5880 } 5881 } 5882 }, 5883 new Block 5884 { 5885 Id = "GridViewItemFooter", 5886 SortId = 40, 5887 SkipRenderBlocksList = true, 5888 Template = RenderGridViewItemFooter(productSliderBlock, gridViewSettings), 5889 BlocksList = new List<Block> { 5890 new Block 5891 { 5892 Id = "GridViewItemActions", 5893 SortId = 10, 5894 Template = RenderGridViewItemActions(gridViewSettings, 2, true) 5895 } 5896 } 5897 } 5898 } 5899 }; 5900 5901 productSliderBlock.Add(bomItemsBlock); 5902 5903 } 5904 5905 @helper RenderBOMItemsSection(string id) 5906 { 5907 var bomItems = Smartpage.PhilipsonWine.BomItems.Repositories.BomItemService.GetBomItems(Model.Id); 5908 5909 List<string> productIds = new List<string>(); 5910 5911 foreach (var product in bomItems) 5912 { 5913 productIds.Add(product.No); 5914 } 5915 5916 string feedUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&Feed=true&IsBomProduct=true&MainProductId=" + string.Join(",", productIds); 5917 5918 string sliderId = "ProductSlider_Slider" + Model.Id; 5919 5920 @RenderBlockList(productSliderBlock.BlocksRoot.BlocksList) 5921 5922 5923 <script id="@("ProductContainer_" + Model.Id)" type="text/x-template"> 5924 {{#each .}} 5925 {{#each ProductsContainer}} 5926 <div id="Product{{id}}" data-template="GridViewItem" data-preloader="overlay" class="product-list__grid-item product-list__bom-item dw-mod product-list-product grid__col-12 grid__col-sm-6"> 5927 {{#each Product}} 5928 {{>GridViewItem}} 5929 {{/each}} 5930 </div> 5931 {{/each}} 5932 {{/each}} 5933 </script> 5934 5935 5936 <script id="ProductPreRenderContainer" type="text/x-template"> 5937 <div class="grid__col-auto"> 5938 <div class="pre-render-element pre-render-element--lg" style="height: 570px;"></div> 5939 </div> 5940 </script> 5941 5942 <script id="StickersContainer" type="text/x-template"> 5943 <div class="stickers-container stickers-container--{{{convertStickerPositionToClassName Position}}} dw-mod"> 5944 {{#Stickers}} 5945 {{>Sticker}} 5946 {{/Stickers}} 5947 </div> 5948 </script> 5949 5950 <script id="Sticker" type="text/x-template"> 5951 @Render(new Sticker { Title = "{{Title}}", CssClass = "{{CssClass}}" }) 5952 </script> 5953 5954 if (bomItems.Any()) 5955 { 5956 <div id="@id" class="paragraph-container paragraph-container--full-width u-white-background bom-items"> 5957 <div class="grid grid--justify-center"> 5958 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 5959 <h2 class="bom-items__header u-ta-center">@Translate("Smartpage:ProductDetail.BOMItems.Header", "Smagekassen indeholder")</h2> 5960 <div class="js-handlebars-root grid" id="@sliderId" data-template="@("ProductContainer_" + Model.Id)" data-json-feed="@feedUrl" data-preloader="minimal"></div> 5961 </div> 5962 </div> 5963 </div> 5964 } 5965 } 5966 @inherits ViewModelTemplate<ProductViewModel> 5967 @using Dynamicweb.Ecommerce.ProductCatalog 5968 @using Dynamicweb.Rendering 5969 @using Dynamicweb.Core 5970 @using System 5971 @using System.Web 5972 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 5973 5974 5975 @helper RenderEventInfoSection(ProductInformation productInfo) 5976 { 5977 var url = productInfo.EventVideo; 5978 var videoId = string.Empty; 5979 5980 if (!string.IsNullOrEmpty(url)) 5981 { 5982 var uri = new Uri(url); 5983 var query = HttpUtility.ParseQueryString(uri.Query); 5984 5985 if (query.AllKeys.Contains("v")) 5986 { 5987 videoId = query["v"]; 5988 } 5989 else 5990 { 5991 videoId = uri.Segments.Last(); 5992 } 5993 5994 } 5995 string producers = productInfo.ProducerId; 5996 string[] producerIds = producers.Split(','); 5997 5998 <div class="paragraph-container paragraph-container--full-width event-section"> 5999 <div class="grid grid--justify-center"> 6000 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 6001 @if (!string.IsNullOrEmpty(videoId)) // VIDEO 6002 { 6003 <div class="video-wrapper"> 6004 <iframe class="event-video" src="//www.youtube.com/embed/@videoId" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> 6005 </div> 6006 <br /> 6007 } 6008 <div class="grid"> 6009 @if (productInfo != null) 6010 { 6011 <div class="grid__col-md-6 no-padding-left"> 6012 <h2 class="event__header dw-mod">@Translate("Smartpage:ProductPage.Event.Menu", "Menu")</h2> 6013 <div class="js-menu-list menu-list closed"> 6014 @productInfo.EventMenu 6015 </div> 6016 <span class="link-small js-show-menu alternative-link-small" data-open="true" data-show-description="+ @Translate("Smartpage:ProductPage.Event.SeeTheFullMenu", "Se hele menuen")" data-hide-description="- @Translate("Smartpage:ProductPage.Event.HideMenu", "Skjul menuen")">+ @Translate("Smartpage:ProductPage.Event.ShowMenu", "Se hele menuen")</span> 6017 </div> 6018 } 6019 <div class="grid__col-md-6 no-padding-right"> 6020 <h2 class="event__header dw-mod">@Translate("Smartpage:ProductPage.Event.Restaurant", "Restaurant")</h2> 6021 <label class="restaurant-name">@productInfo.EventRestaurantName</label> 6022 <p>@productInfo.EventAddressLong</p> 6023 <a href="//www.google.com/maps/place/@productInfo.EventAddressLong" class="link-maps" target="_blank">@Translate("Smartpage:ProductPage.Event.LookAtMap","Se på kort")</a> 6024 </div> 6025 @if (producerIds != null && producerIds.Length > 0) 6026 { 6027 <div class="grid__col-md-12 u-no-padding-x"> 6028 <h2 class="event__header dw-mod">@Translate("Smartpage:ProductPage.Event.TheProducers", "Producenterne")</h2> 6029 @foreach (var producerId in producerIds) 6030 { 6031 if (!string.IsNullOrEmpty(producerId)) 6032 { 6033 var producerService = new Smartpage.PhilipsonWine.Producer.Repositories.ProducerService(); 6034 var producer = producerService.GetProductProducer(producerId); 6035 6036 <div class="u-margin-bottom producer"> 6037 <label class="producer-name">@producer.ProducerName</label> 6038 <p class="producer-text">@producer.ProducerDescription</p> 6039 <span class="link-small" onclick="window.location = 'Default.aspx?ID=@producer.ProducerLink'">Læs mere</span> 6040 </div> 6041 } 6042 } 6043 </div> 6044 } 6045 </div> 6046 </div> 6047 </div> 6048 </div> 6049 6050 <div class="paragraph-container paragraph-container--full-width event-section-note"> 6051 <div class="grid grid--justify-center"> 6052 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 6053 <h2 class="event-note__header dw-mod">@Translate("Smartpage:ProductPage.Event.Attention", "Bemærk")</h2> 6054 <p class="u-margin-top u-margin-bottom">@productInfo.EventAttention</p> 6055 </div> 6056 </div> 6057 </div> 6058 } 6059 @inherits ViewModelTemplate<ProductViewModel> 6060 @using Dynamicweb.Ecommerce.ProductCatalog 6061 @using Dynamicweb.Rendering 6062 6063 @helper RenderClerkSection(string id, string clerkTemplate, string containerClass = "") 6064 { 6065 <div id="@id" class="paragraph-container paragraph-container--full-width js-product-slider-container @containerClass" data-swiper-config="clerk-slider-product-page"> 6066 <div class="grid grid--justify-center"> 6067 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 6068 <h3 class="heading-clerk">@Translate("Smartpage:ClerkRecommendations." + id, id)</h3> 6069 <div class=""> 6070 @{ 6071 string swiperContainerClass = "SliderContainer_" + id; 6072 string swiperPaginationClass = id + "_SwiperPagination"; 6073 string swiperPrevButtonClass = id + "_SwiperButtonPrev"; 6074 string swiperNextButtonClass = id + "_SwiperButtonNext"; 6075 } 6076 <div id="@swiperContainerClass" class="swiper-container product-slider-container @swiperContainerClass"> 6077 <span class="clerk swiper-wrapper" 6078 data-template="@("@" + clerkTemplate)" 6079 data-products="[@Model.Id]"> 6080 </span> 6081 </div> 6082 <div id="@swiperPrevButtonClass" class="swiper-button-prev @swiperPrevButtonClass"></div> 6083 <div id="@swiperNextButtonClass" class="swiper-button-next @swiperNextButtonClass"></div> 6084 <div class="clerk-preloader js-clerk-preloader clerk-preloader--loading"> 6085 <div class="preloader-overlay__icon js-clerk-preloader-icon"></div> 6086 </div> 6087 </div> 6088 </div> 6089 </div> 6090 </div> 6091 } 6092 @inherits ViewModelTemplate<ProductViewModel> 6093 @using Dynamicweb.Ecommerce.ProductCatalog 6094 @using Dynamicweb.Rendering 6095 @using Dynamicweb.Core 6096 @using System 6097 @using System.Web 6098 @using System.Collections.Generic 6099 @using Dynamicweb.Rapido.Blocks 6100 @using Dynamicweb.Rapido.Blocks.Components.General 6101 6102 @functions{ 6103 BlocksPage productVideoPage = BlocksPage.GetBlockPage("Product"); 6104 } 6105 6106 @{ 6107 //var apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(Model.Id, Model.VariantId, true); 6108 string videosLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue : "Section"; 6109 videosLayout = videosLayout == "Ribbon" || string.IsNullOrEmpty(videosLayout) ? "Section" : videosLayout; 6110 6111 int videosCount = 0; 6112 6113 foreach (var detailField in Model.AssetCategories) 6114 { 6115 foreach (var asset in detailField.Assets) 6116 { 6117 if (asset.Value.IndexOf("iframe") != -1 && asset.Value.IndexOf("youtube.com/embed") != -1) 6118 { 6119 videosCount++; 6120 } 6121 if (asset.Value.IndexOf("iframe") != -1 && asset.Value.IndexOf("vimeo.com") != -1) 6122 { 6123 videosCount++; 6124 } 6125 } 6126 } 6127 6128 if (videosCount > 0 && videosLayout != "hide") 6129 { 6130 Block detailsVideos = new Block() 6131 { 6132 Name = videosLayout != "MainInformation" ? Translate("Videos") : "", 6133 Id = "Videos", 6134 SortId = 60, 6135 Template = RenderProductVideos(videosCount, videosLayout), 6136 Design = new Design 6137 { 6138 Size = "12", 6139 RenderType = RenderType.Column, 6140 HidePadding = true 6141 } 6142 }; 6143 productVideoPage.Add(videosLayout, detailsVideos); 6144 } 6145 } 6146 6147 @helper RenderProductVideos(int videosCount, string layout) { 6148 //var apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(Model.Id, Model.VariantId, true); 6149 string videoColumn = "12"; 6150 videoColumn = videosCount == 2 ? "6" : videoColumn; 6151 videoColumn = videosCount > 2 ? "4" : videoColumn; 6152 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 6153 ribbonClasses = layout == "Tabs" ? "u-no-padding" : ribbonClasses; 6154 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 6155 6156 <div class="product__section @ribbonClasses dw-mod"> 6157 <div class="center-container @ribbonSubClasses dw-mod"> 6158 @if (layout == "Section") { 6159 @Render(new Heading { Title = Translate("Videos"), Level = 2 }) 6160 } 6161 6162 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 6163 @foreach (var detailField in Model.AssetCategories) 6164 { 6165 foreach (var asset in detailField.Assets) 6166 { 6167 if (asset.Value.IndexOf("iframe") != -1 && asset.Value.IndexOf("youtube.com/embed") != -1 || asset.Value.IndexOf("iframe") != -1 && asset.Value.IndexOf("vimeo.com") != -1) 6168 { 6169 <div class="grid__col-md-@videoColumn grid__col-lg-@videoColumn"> 6170 <div class="video-wrapper"> 6171 @asset.Value 6172 </div> 6173 </div> 6174 } 6175 } 6176 } 6177 </div> 6178 </div> 6179 </div> 6180 } 6181 @inherits ViewModelTemplate<ProductViewModel> 6182 @using Dynamicweb.Ecommerce.ProductCatalog 6183 @using Dynamicweb.Rendering 6184 @using System.Collections.Generic 6185 @using Dynamicweb.Rapido.Blocks.Components.General 6186 @using Dynamicweb.Rapido.Blocks 6187 6188 @using Dynamicweb.Ecommerce.ProductCatalog 6189 @using Dynamicweb.Rendering 6190 @using Dynamicweb.Core 6191 @using System 6192 @using System.Web 6193 @using System.Collections.Generic 6194 @using Dynamicweb.Rapido.Blocks 6195 @using Dynamicweb.Rapido.Blocks.Components 6196 @using Dynamicweb.Rapido.Blocks.Components.General 6197 @using Dynamicweb.Rapido.Services 6198 6199 @helper GridView(Dynamicweb.Frontend.ItemViewModel gridViewSettings) 6200 { 6201 int columnsCount = gridViewSettings.GetList("Columns") != null ? Converter.ToInt32(gridViewSettings.GetList("Columns").SelectedValue) : 3; 6202 string imageZoomOnHover = gridViewSettings.GetBoolean("HoverImageZoom") ? "image-hover--zoom" : ""; 6203 6204 <script id="ProductGridItemContainer" type="text/x-template"> 6205 {{#.}} 6206 <div id="Product{{id}}" data-template="GridViewItem" data-preloader="overlay" class="grid__col-lg-@(12 / columnsCount) grid__col-md-6 grid__col-sm-6 grid__col-xs-6 product-list__grid-item @imageZoomOnHover dw-mod product-list-product"> 6207 {{#Product}} 6208 {{>GridViewItem}} 6209 {{/Product}} 6210 </div> 6211 {{/.}} 6212 </script> 6213 } 6214 6215 @helper RenderGridViewItem(BlocksPage page) 6216 { 6217 List<Block> subBlocks = page.GetBlockListById("GridViewItem"); 6218 6219 <script id="GridViewItem" type="text/x-template"> 6220 {{#.}} 6221 <div class="grid__col--auto js-product-scroll-trigger u-no-padding u-full-height u-grey-border u-white-background u-padding-sides-8px" data-params="{{googleImpression}}"> 6222 {{>RenderRatingsBadges}} 6223 @RenderBlockList(subBlocks) 6224 </div> 6225 {{/.}} 6226 </script> 6227 6228 <script id="RenderRatingsBadges" type="text/x-template"> 6229 <div class="productlist-rating-badges"> 6230 {{#if CustomerRatingActive}} 6231 <div class="rating-badge c100 js-badge" data-percent="{{CustomerRatingInPercent}}"> 6232 <span class="rating-badge--text">@Translate("Smartpage:CustomerRating.Philipson Wine", "Philipson Wine")</span> 6233 <span class="rating-badge--score">{{{CustomerRatingInText}}}</span> 6234 <div class="slice"> 6235 <div class="bar"></div> 6236 <div class="fill"></div> 6237 </div> 6238 </div> 6239 {{/if}} 6240 {{#ExpertRatings}} 6241 {{#if image}} 6242 <div class="expert-rating-image"> 6243 @{ 6244 var imagePrefix = "/Admin/Public/GetImage.ashx?width=46&amp;height=46&amp;crop=5&amp;Compression=75&amp;FillCanvas=true&amp;DoNotUpscale=true&amp;image=/Files/Images/ExpertRatings/{{image}}.png"; 6245 6246 // CDN 6247 var cdnUrl = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("CDNUrl"); 6248 bool cdnActivate = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetBoolean("CDNActivate"); 6249 if (!string.IsNullOrWhiteSpace(cdnUrl) && cdnActivate) 6250 { 6251 imagePrefix = cdnUrl + imagePrefix; 6252 } 6253 } 6254 <img class="rating-image" src="@imagePrefix" alt="{{name}}" /> 6255 <span class="rating-image--score">{{{text}}}</span> 6256 </div> 6257 {{else}} 6258 <div class="rating-badge c100 dark js-badge" data-percent="{{percentage}}"> 6259 <span class="rating-badge--text">{{name}}</span> 6260 <span class="rating-badge--score">{{{text}}}</span> 6261 <div class="slice"> 6262 <div class="bar"></div> 6263 <div class="fill"></div> 6264 </div> 6265 </div> 6266 {{/if}} 6267 {{/ExpertRatings}} 6268 </div> 6269 </script> 6270 6271 6272 6273 } 6274 6275 @helper RenderGridViewItemHiddenProperties() 6276 { 6277 <input type="hidden" name="ProductLoopCounter{{id}}" value="{{id}}" /> 6278 <input type="hidden" name="ProductID{{id}}" value="{{productId}}" /> 6279 <input type="hidden" name="VariantID{{id}}" value="{{variantid}}" id="Variant_{{id}}" /> 6280 <input type="hidden" name="UnitID{{id}}" value="{{unitId}}" id="Unit_{{id}}" /> 6281 } 6282 6283 @helper RenderGridViewItemImageContainer(BlocksPage page) 6284 { 6285 List<Block> subBlocks = page.GetBlockListById("GridViewItemImageContainer"); 6286 6287 <text> 6288 {{#if eventProduct}} 6289 {{#if eventPromotionText}} 6290 <div class="top-label"> 6291 <div class="top-label__label"> 6292 {{eventPromotionText}} 6293 </div> 6294 </div> 6295 {{/if}} 6296 {{else if isPrimeur}} 6297 <div class="top-label"> 6298 <div class="top-label__label"> 6299 {{isPrimeurText}} 6300 </div> 6301 </div> 6302 {{else}} 6303 {{#if promotionText}} 6304 <div class="top-label"> 6305 <div class="top-label__label"> 6306 {{promotionText}} 6307 </div> 6308 </div> 6309 {{/if}} 6310 {{/if}} 6311 </text> 6312 6313 <div class="product-list__grid-item__image dw-mod {{noImage}}"> 6314 @RenderBlockList(subBlocks) 6315 </div> 6316 } 6317 6318 @helper RenderGridViewItemImage() 6319 { 6320 var imagePrefix = "/Admin/Public/GetImage.ashx?width=300&amp;height=300&amp;crop=5&amp;Compression=75&amp;FillCanvas=true&amp;DoNotUpscale=true&amp;image="; 6321 6322 // CDN 6323 var cdnUrl = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetString("CDNUrl"); 6324 bool cdnActivate = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItem("Custom").GetBoolean("CDNActivate"); 6325 if (!string.IsNullOrWhiteSpace(cdnUrl) && cdnActivate) 6326 { 6327 imagePrefix = cdnUrl + imagePrefix; 6328 } 6329 6330 <a href="{{link}}" 6331 onclick="Scroll.SavePosition(event); {{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" 6332 title="{{{name}}}" 6333 class="u-block u-position-relative image-hover__wrapper dw-mod"> 6334 <img class="grid__cell-img grid__cell-img--centered u-padding b-lazy u-full-height" src="/Files/Images/placeholder.gif" 6335 data-src="@imagePrefix{{image}}" alt="{{name}}" /> 6336 </a> 6337 } 6338 6339 @helper RenderGridViewItemStickers() 6340 { 6341 <text> 6342 {{#StickersContainers}} 6343 {{>StickersContainer}} 6344 {{/StickersContainers}} 6345 </text> 6346 } 6347 6348 @helper RenderGridViewItemFavorites() 6349 { 6350 <div class="favorites favorites--for-grid-view u-pull--right {{favoriteProductFromImport}} dw-mod" {{favoriteProductFromImport}}> 6351 {{#Favorite}} 6352 {{>FavoriteTemplate}} 6353 {{/Favorite}} 6354 </div> 6355 } 6356 6357 @helper RenderGridViewItemInfoContainer(BlocksPage page) 6358 { 6359 List<Block> subBlocks = page.GetBlockListById("GridViewItemInfoContainer"); 6360 6361 <div class="grid__cell product-list__grid-item__price-info dw-mod"> 6362 @RenderBlockList(subBlocks) 6363 </div> 6364 } 6365 6366 @helper RenderGridViewItemTitle() 6367 { 6368 <a href="{{link}}" class="u-color-inherit" onclick="{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" title="{{name}}{{#if variantName}}, {{variantName}}{{/if}}"> 6369 <h6 class="u-condensed-text u-bold">{{{name}}}{{#if variantName}}, {{variantName}}{{/if}}</h6> 6370 </a> 6371 } 6372 6373 @helper RenderGridViewItemNumber() 6374 { 6375 <div class="item-number dw-mod">{{number}}</div> 6376 } 6377 6378 @helper RenderGridViewItemPrice(Dynamicweb.Frontend.ItemViewModel gridViewSettings) 6379 { 6380 int columnsCount = gridViewSettings.GetList("Columns") != null ? Converter.ToInt32(gridViewSettings.GetList("Columns").SelectedValue) : 4; 6381 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 6382 bool showCartButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToCartButton"); 6383 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 6384 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 6385 6386 if (pointShopOnly) 6387 { 6388 <text> 6389 {{#if havePointPrice}} 6390 <div class="price price--product-list dw-mod">{{points}} @Translate("points")</div> 6391 @if (showCartButton) 6392 { 6393 <text> 6394 {{#unless canBePurchasedWithPoints}} 6395 <small class="help-text u-no-margin">@Translate("Not enough points to buy this")</small> 6396 {{/unless}} 6397 </text> 6398 } 6399 {{else}} 6400 @Translate("Not available") 6401 {{/if}} 6402 </text> 6403 6404 } 6405 else 6406 { 6407 <div class="price price--product-list dw-mod">{{price}}</div> 6408 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 6409 if (showVATPrice) 6410 { 6411 <div class="vat-price vat-price--product-list u-margin-top dw-mod"> 6412 @if (columnsCount <= 4) 6413 { 6414 if (isPricesWithVATEnabled) 6415 { 6416 <span>@Translate("excl. VAT")</span><span> ({{priceWithoutVAT}})</span> 6417 } 6418 else 6419 { 6420 <span>@Translate("incl. VAT")</span><span> ({{priceWithVAT}})</span> 6421 } 6422 } 6423 else 6424 { 6425 if (isPricesWithVATEnabled) 6426 { 6427 <div>@Translate("excl. VAT")</div><div>({{priceWithoutVAT}})</div> 6428 } 6429 else 6430 { 6431 <div>@Translate("incl. VAT")</div><div>({{priceWithVAT}})</div> 6432 } 6433 } 6434 </div> 6435 } 6436 <text> 6437 {{#if priceRRP}} 6438 <div><small>@Translate("RRP") {{priceRRP}}</small></div> 6439 {{/if}} 6440 </text> 6441 } 6442 } 6443 6444 @helper RenderGridViewItemFooter(BlocksPage page, Dynamicweb.Frontend.ItemViewModel gridViewSettings) 6445 { 6446 List<Block> subBlocks = page.GetBlockListById("GridViewItemFooter"); 6447 bool showStaticVariants = gridViewSettings.GetBoolean("ShowStaticVariants"); 6448 string footerClasses = showStaticVariants ? "u-min-h120px" : ""; 6449 6450 <div class="product-list__grid-item__footer @footerClasses dw-mod u-padding-1px"> 6451 @RenderBlockList(subBlocks) 6452 </div> 6453 } 6454 6455 @helper RenderGridViewItemViewButton(Dynamicweb.Frontend.ItemViewModel gridViewSettings) 6456 { 6457 string viewMoreText = gridViewSettings.GetString("ViewMoreText"); 6458 viewMoreText = !string.IsNullOrEmpty(viewMoreText) ? viewMoreText : "View"; 6459 6460 @Render(new Link 6461 { 6462 Href = "{{link}}", 6463 Id = "CartButton_{{id}}", 6464 Title = Translate(viewMoreText), 6465 OnClick = "{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}", 6466 ButtonLayout = ButtonLayout.Secondary, 6467 CssClass = "u-no-margin" 6468 }); 6469 } 6470 6471 @helper RenderGridViewItemPricesAndAddToCart(Dynamicweb.Frontend.ItemViewModel gridViewSettings, int customerRatingHeartsPadding = 3, bool hideAddToCart = false) 6472 { 6473 6474 int columnsCount = gridViewSettings.GetList("Columns") != null ? Converter.ToInt32(gridViewSettings.GetList("Columns").SelectedValue) : 4; 6475 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 6476 bool showCartButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToCartButton"); 6477 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 6478 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 6479 string addToCartSectionCol = hideAddToCart ? "d-none" : "grid__col-6"; 6480 string pricesSectionCol = hideAddToCart ? "grid__col-12" : "grid__col-6"; 6481 6482 <div class="grid"> 6483 <div class="grid__col-12 {{#if eventProduct}}event-{{/if}}title-container " style="height: 85px;"> 6484 {{#unless eventProduct}} 6485 <span class="area u-ta-center">{{producerName}}</span> 6486 {{/unless}} 6487 <a href="{{link}}" class="u-color-inherit" onclick="Scroll.SavePosition(event); {{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" title="{{name}}"> 6488 <h6 class="u-bold title js-title u-ta-center">{{name}}</h6> 6489 </a> 6490 {{#if eventProduct}} 6491 <p class="event-place"> 6492 {{eventRestaurantName}}, {{eventAddressShort}} 6493 <span class="event-time">{{eventDate}}, {{eventTime}}</span> 6494 </p> 6495 {{/if}} 6496 </div> 6497 </div> 6498 <text> 6499 {{#unless eventProduct}} 6500 <div class="grid"> 6501 <div class="grid__col-12"> 6502 <div class="tags"> 6503 {{#if type}} 6504 <span class="tags__tag">{{type}}</span> 6505 {{/if}} 6506 {{#if area}} 6507 <span class="tags__tag">{{area}}</span> 6508 {{/if}} 6509 {{#if country}} 6510 <span class="tags__tag">{{country}}</span> 6511 {{/if}} 6512 </div> 6513 </div> 6514 </div> 6515 {{/unless}} 6516 </text> 6517 <div class="grid"> 6518 <div class="grid__col-12"> 6519 <div class="customer-ratings-container {{showRating}}"> 6520 <div class="hearts" data-average-rating-percentage="{{ratingPercentage}}" data-heart-padding="@customerRatingHeartsPadding"> 6521 <div class="hearts-outer"> 6522 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 6523 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 6524 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 6525 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 6526 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-grey-heart.svg" class="full-heart" /> 6527 <div class="hearts-inner"> 6528 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 6529 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 6530 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 6531 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 6532 <img src="/Files/Templates/Designs/Rapido/Images/VectorItemTypes/rating-full-red-heart.svg" class="full-heart" /> 6533 </div> 6534 </div> 6535 </div> 6536 <span class="rating">({{rating}})</span> 6537 </div> 6538 </div> 6539 </div> 6540 6541 <div class="grid"> 6542 <div class="grid__col-12"> 6543 <p class="short-description">{{description}}</p> 6544 </div> 6545 </div> 6546 6547 <div class="grid"> 6548 <div class="@pricesSectionCol"> 6549 <div class="prices"> 6550 {{#unless eventProduct}} 6551 {{#if savings}} 6552 <div class="savings">@Translate("Smartpage:ProductList.Product.Save", "Spar") {{savings}} @Translate("Smartpage:ProductList.Product.PerUnit", "PR. STK.")</div> 6553 {{/if}} 6554 {{/unless}} 6555 <div class="price price--product-list dw-mod">{{price}}</div> 6556 <div class="quantity-price">{{#if eventProduct}} @Translate("Smartpage:ProductList.Product.Pr.", "Pr.") @Translate("Smartpage:ProductList.Product.Ticket", "billet") {{else}}@Translate("Smartpage:ProductList.Product.Pr.", "Pr.") {{unitShortDescription}} v/{{kolli}} @Translate("Smartpage:ProductList.Product.Unit.Stk", "stk.") {{#if bottleSizeCl}}({{bottleSizeCl}} @Translate("Smartpage:ProductList.Product.Unit.Cl", "cl.")){{/if}}{{/if}}</div> 6557 </div> 6558 </div> 6559 {{#if availableForPurchase}} 6560 <div class="@addToCartSectionCol add-to-cart"> 6561 <div class="grid"> 6562 {{#unless disabledBuyButton}} 6563 <div class="grid__col-5 u-no-padding"> 6564 <input id="Quantity{{id}}" name="Quantity{{id}}" min="1" max="{{stockLevel}}" value="{{kolli}}" type="number" class="quantity dw-mod js-stockcheck js-change-quantity"> 6565 </div> 6566 {{/unless}} 6567 {{#if disabledBuyButton}} 6568 <div class="grid__col-12 u-no-padding"> 6569 <button class="btn btn--add-to-cart {{disabledBuyButton}}" title="@Translate("Smartpage:Product.Buy.OutOfStock", "Udsolgt")" onclick="Cart.AddToCart(event, { id: '{{productId}}', variantId: '{{variantid}}', unitId: '{{unitId}}', productInfo: {{productInfo}}, quantity: parseInt(document.getElementById('Quantity{{id}}').value), SpPrimeur: '{{isPrimeur}}'}); {{facebookPixelAction}}" type="button"> 6570 <span>@Translate("Smartpage:Product.Buy.OutOfStock", "Udsolgt")</span> 6571 </button> 6572 </div> 6573 {{/if}} 6574 {{#unless disabledBuyButton}} 6575 <div class="grid__col-7 u-no-padding"> 6576 <button class="btn btn--add-to-cart {{disabledBuyButton}}" title="@Translate("Smartpage:Product.Buy", "Køb")" onclick="Cart.AddToCart(event, { id: '{{productId}}', variantId: '{{variantid}}', unitId: '{{unitId}}', productInfo: {{productInfo}}, quantity: parseInt(document.getElementById('Quantity{{id}}').value), SpPrimeur: '{{isPrimeur}}'}); {{facebookPixelAction}}" type="button" data-product-id="{{productId}}" data-one-unit-price="{{oneUnitPrice}}" data-volume-unit-price="{{volumeUnitPrice}}" data-volume-unit-threshold="{{kolli}}" data-currency-code="{{currency}}"> 6577 <span>@Translate("Smartpage:Product.Buy", "Køb")</span> 6578 </button> 6579 </div> 6580 {{/unless}} 6581 </div> 6582 </div> 6583 {{/if}} 6584 </div> 6585 6586 } 6587 6588 @helper RenderGridViewItemActions(Dynamicweb.Frontend.ItemViewModel gridViewSettings, int customerRatingHeartsPadding = 2, bool hideAddToCart = false) 6589 { 6590 if (Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 6591 { 6592 @RenderGridViewItemPricesAndAddToCart(gridViewSettings, customerRatingHeartsPadding, hideAddToCart) 6593 } 6594 } 6595 6596 @functions { 6597 BlocksPage productRelatedPage = BlocksPage.GetBlockPage("Product"); 6598 Dynamicweb.Frontend.ItemViewModel gridViewSettings = null; 6599 } 6600 6601 @{ 6602 string pageId = Dynamicweb.Context.Current.Request["ID"]; 6603 string relatedProductsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue : "Section"; 6604 relatedProductsLayout = relatedProductsLayout == "Ribbon" || string.IsNullOrEmpty(relatedProductsLayout) ? "Section" : relatedProductsLayout; 6605 6606 gridViewSettings = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView"); 6607 6608 int relatedProductsPageSize = 2; 6609 6610 if (Pageview.Device.ToString() == "Mobile") 6611 { 6612 relatedProductsPageSize = 1; 6613 } 6614 6615 if (Pageview.Device.ToString() == "Tablet") 6616 { 6617 relatedProductsPageSize = 2; 6618 } 6619 6620 int relatedProductsColumnWidth = 12 / relatedProductsPageSize; 6621 6622 if (relatedProductsLayout != "hide") 6623 { 6624 var i = 0; 6625 6626 var relatedGroups = Dynamicweb.Ecommerce.Services.ProductRelated.GetRelations(Model.Id).GroupBy(p => p.RelatedGroupId); 6627 foreach (var relatedGroup in relatedGroups) 6628 { 6629 string baseFeedPageUrl = "/Default.aspx?ID=" + pageId + "&feed=true&PageSize=" + relatedProductsPageSize + "&ProdID=" + Model.Id; 6630 string relatedGroupName = Dynamicweb.Ecommerce.Services.ProductRelatedGroups.GetProductRelatedGroup(relatedGroup.Key, Dynamicweb.Ecommerce.Common.Context.LanguageID) != null ? Dynamicweb.Ecommerce.Services.ProductRelatedGroups.GetProductRelatedGroup(relatedGroup.Key, "LANG2").Name : ""; 6631 string relatedFeed = baseFeedPageUrl + "&" + relatedGroupName.Replace(" ", "") + "=" + Model.Id + "&GroupName=" + relatedGroupName; 6632 6633 i++; 6634 6635 Block gridViewItem = new Block 6636 { 6637 Id = "GridViewItem", 6638 SortId = 10, 6639 Template = RenderGridViewItem(productRelatedPage), 6640 SkipRenderBlocksList = true, 6641 BlocksList = new List<Block> { 6642 new Block 6643 { 6644 Id = "GridViewItemHiddenProperties", 6645 SortId = 10, 6646 Template = RenderGridViewItemHiddenProperties() 6647 }, 6648 new Block 6649 { 6650 Id = "GridViewItemImageContainer", 6651 SortId = 20, 6652 SkipRenderBlocksList = true, 6653 Template = RenderGridViewItemImageContainer(productRelatedPage), 6654 BlocksList = new List<Block> { 6655 new Block 6656 { 6657 Id = "GridViewItemImage", 6658 SortId = 10, 6659 Template = RenderGridViewItemImage() 6660 }, 6661 new Block 6662 { 6663 Id = "GridViewItemStickers", 6664 SortId = 20, 6665 Template = RenderGridViewItemStickers() 6666 } 6667 } 6668 }, 6669 new Block 6670 { 6671 Id = "GridViewItemFooter", 6672 SortId = 40, 6673 SkipRenderBlocksList = true, 6674 Template = RenderGridViewItemFooter(productRelatedPage, gridViewSettings), 6675 BlocksList = new List<Block> { 6676 new Block 6677 { 6678 Id = "GridViewItemActions", 6679 SortId = 10, 6680 Template = RenderGridViewItemActions(gridViewSettings, 0) 6681 } 6682 } 6683 } 6684 } 6685 }; 6686 6687 @*if (eventProduct) 6688 { 6689 productRelatedPage.Add(relatedProductsLayout, gridViewItem); 6690 } 6691 6692 Block detailsRelated = new Block() 6693 { 6694 Name = relatedGroupName, 6695 Id = relatedGroupName, 6696 SortId = 70 + i, 6697 Template = RenderRelatedProducts(relatedGroupName, relatedGroupName, relatedFeed, relatedProductsLayout), 6698 Design = new Design 6699 { 6700 Size = "12", 6701 RenderType = RenderType.Column, 6702 HidePadding = true 6703 } 6704 }; 6705 if (eventProduct) 6706 { 6707 productRelatedPage.Add(relatedProductsLayout, detailsRelated); 6708 }*@ 6709 } 6710 } 6711 } 6712 6713 @helper RenderRelatedProducts(string name, string groupId, string relatedFeedUrl, string layout) 6714 { 6715 <div class="paragraph-container paragraph-container--full-width product-slider"> 6716 <div class="grid grid--justify-center"> 6717 <div class="grid__col-md-6 grid__col-lg-6 grid__col-xlg-5 grid__col-xxlg-4"> 6718 <div class="grid__col-12"> 6719 @if (layout == "Section") { 6720 @Render(new Heading { Title = Translate("Smartpage:ProductDetail.RelatedProducts.Header." + name, name), Level = 2, CssClass = "product-slider__header" }) 6721 } 6722 </div> 6723 <div class="js-handlebars-root" id="ProductList_@groupId" data-template="ProductContainer" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedFeedUrl" data-preloader="overlay"></div> 6724 </div> 6725 </div> 6726 </div> 6727 } 6728 6729 @* Script templates for related products *@ 6730 <script id="ProductPreRenderContainer" type="text/x-template"> 6731 <div class="u-h600px u-full-width"> 6732 <div class="grid"> 6733 <div class="grid__col-12"> 6734 <div class="pre-render-element pre-render-element--md"></div> 6735 </div> 6736 </div> 6737 </div> 6738 </script> 6739 6740 <script id="ProductContainer" type="text/x-template"> 6741 {{#.}} 6742 <div class="product-slider__prev-btn"> 6743 @{ 6744 Button prevButton = new Button { Icon = new Icon { Prefix = "fas", Name = "fa-chevron-left fa-2x", LabelPosition = IconLabelPosition.After }, ButtonLayout = ButtonLayout.Clean, CssClass = "btn--condensed {{prevdisabled}} u-position-relative", OnClick = "HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{prevPage}}')" }; 6745 prevButton.ExtraAttributes.Add("", "{{prevdisabled}}"); 6746 } 6747 @Render(prevButton) 6748 </div> 6749 <div class="grid"> 6750 {{#ProductsContainer}} 6751 <div id="Product{{id}}" data-template="GridViewItem" data-preloader="overlay" class="grid__col-lg-6 grid__col-md-12 grid__col-sm-6 grid__col-xs-6 product-list__grid-item dw-mod product-list-product"> 6752 {{#Product}} 6753 {{>GridViewItem}} 6754 {{/Product}} 6755 </div> 6756 {{/ProductsContainer}} 6757 </div> 6758 6759 <div class="product-slider__next-btn"> 6760 @{ 6761 Button nextButton = new Button { Icon = new Icon { Prefix = "fas", Name = "fa-chevron-right fa-2x", LabelPosition = IconLabelPosition.After }, ButtonLayout = ButtonLayout.Clean, CssClass = "btn--condensed {{nextdisabled}} u-position-relative", OnClick = "HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{nextPage}}')" }; 6762 nextButton.ExtraAttributes.Add("", "{{nextdisabled}}"); 6763 } 6764 @Render(nextButton) 6765 </div> 6766 6767 {{/.}} 6768 </script> 6769 6770 <script id="StickersContainer" type="text/x-template"> 6771 <div class="stickers-container stickers-container--{{{convertStickerPositionToClassName Position}}} dw-mod"> 6772 {{#Stickers}} 6773 {{>Sticker}} 6774 {{/Stickers}} 6775 </div> 6776 </script> 6777 6778 <script id="Sticker" type="text/x-template"> 6779 @Render(new Sticker { Title = "{{Title}}", CssClass = "{{CssClass}}" }) 6780 </script> 6781 6782 <script> 6783 @{ 6784 bool relatedUseGoogleTagManager = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("GoogleTagManagerID")); 6785 6786 if (relatedUseGoogleTagManager) 6787 { 6788 <text> 6789 document.addEventListener("DOMContentLoaded", function (event) { 6790 Scroll.AddIsInViewportListener(".js-product-scroll-trigger", function (elem) { 6791 let googleImpression = JSON.parse(elem.getAttribute("data-params")); 6792 googleImpression.list = "Related products"; 6793 googleEnchantImpression(googleImpression); 6794 elem.classList.remove("js-product-scroll-trigger"); 6795 }); 6796 }); 6797 </text> 6798 } 6799 } 6800 </script> 6801 @inherits ViewModelTemplate<ProductViewModel> 6802 @using Dynamicweb.Ecommerce.ProductCatalog 6803 @using Dynamicweb.Rendering 6804 @using Dynamicweb.Core 6805 @using Dynamicweb.Rapido.Blocks 6806 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation 6807 6808 @functions { 6809 BlocksPage productSnippetsPage = BlocksPage.GetBlockPage("Product"); 6810 } 6811 6812 @{ 6813 Block googleProductSchema = new Block() 6814 { 6815 Id = "GoogleProductSchema", 6816 SortId = 10, 6817 Template = RenderGoogleProductSchema() 6818 }; 6819 6820 productSnippetsPage.Add("Snippets", googleProductSchema); 6821 } 6822 6823 @helper RenderGoogleProductSchema() 6824 { 6825 ProductInformation productInformation = new ProductInformation(Model); 6826 var siteURL = Dynamicweb.Context.Current.Request.Url.Scheme + "://" + Dynamicweb.Context.Current.Request.Url.Host; 6827 var image = Model.DefaultImage.Value; 6828 var brand = !string.IsNullOrWhiteSpace(productInformation.Brand) ? productInformation.Brand : ""; 6829 var variantid = !string.IsNullOrEmpty(Model.VariantId) ? Model.VariantId : Model.VariantId; 6830 string linkGroup = "Default.aspx?Id=" + GetPageIdByNavigationTag("ProductsPage") + "&GroupId=" + (Model.PrimaryOrDefaultGroup != null ? Model.PrimaryOrDefaultGroup.Id : "") + "&ProductId=" + Model.Id; 6831 var url = Dynamicweb.Context.Current.Request.Url.Scheme + "://" + Dynamicweb.Context.Current.Request.Url.Host + Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(linkGroup + (!string.IsNullOrWhiteSpace(variantid) ? "&VariantID=" + variantid : "")); 6832 var priceObject = new Smartpage.PhilipsonWine.Ecommerce.Prices.PriceObject(Model.Id, productInformation.MaxPriceBasedOn, Model.Discount.Price); 6833 6834 <script type="application/ld+json"> 6835 { 6836 "@@context": "http://schema.org/", 6837 "@@type": "Product", 6838 "name": "@HttpUtility.HtmlAttributeEncode(Model.Name)", 6839 @if (!string.IsNullOrEmpty(image)) 6840 { 6841 <text>"image": [ 6842 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=400&crop=0&Compression=75&DoNotUpscale=true&image=@image", 6843 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=300&crop=0&Compression=75&DoNotUpscale=true&image=@image", 6844 "@siteURL/Admin/Public/GetImage.ashx?width=448&height=225&crop=0&Compression=75&DoNotUpscale=true&image=@image" 6845 ],</text> 6846 } 6847 "description": "@HttpUtility.HtmlAttributeEncode(Model.ShortDescription)", 6848 "mpn": "925872", 6849 @if (!string.IsNullOrEmpty(brand)) 6850 { 6851 <text>"brand": { 6852 "@@type": "Thing", 6853 "name": "@brand" 6854 },</text> 6855 } 6856 "offers": { 6857 "@@type": "Offer", 6858 "priceCurrency": "@Model.Price.CurrencyCode", 6859 "price": "@priceObject.DiscountPriceFormattedWithoutSymbol.Replace(",", ".")", 6860 "availability": "@(Model.StockLevel > 0 ? "InStock" : "OutOfStock")", 6861 "url": "@url" 6862 }, 6863 "sku": "@Model.Id" 6864 } 6865 </script> 6866 } 6867 6868 @inherits ViewModelTemplate<ProductViewModel> 6869 @using Dynamicweb.Ecommerce.ProductCatalog 6870 @using Dynamicweb.Rendering 6871 @using Dynamicweb.Rapido.Blocks 6872 6873 @functions { 6874 BlocksPage snippetsTemplatesPage = BlocksPage.GetBlockPage("Product"); 6875 } 6876 6877 @{ 6878 snippetsTemplatesPage.Add(new Block { 6879 Id = "FavoritesTemplates", 6880 SortId = 100, 6881 Template = RenderFavoritesTemplates() 6882 }); 6883 } 6884 6885 @helper RenderFavoritesTemplates() 6886 { 6887 var selectedFavoriteIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon").SelectedValue : "star"; 6888 string favoriteIcon = "fas fa-" + selectedFavoriteIcon; 6889 string favoriteOutlineIcon = "fal fa-" + selectedFavoriteIcon; 6890 bool useFacebookPixel = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("FacebookPixelID")); 6891 string currentFavoriteListId = HttpContext.Current.Request.QueryString.Get("ListID"); 6892 6893 <script id="FavoriteTemplate" type="text/x-template"> 6894 <div class="favorites-list u-ta-left js-favorites-list"> 6895 @Render(new Button { 6896 CssClass = "u-no-margin js-favorite-btn", 6897 Icon = new Icon 6898 { 6899 Name = "{{#if isInAnyFavoriteList}}" + favoriteIcon + "{{else}}" + favoriteOutlineIcon + "{{/if}}", 6900 CssClass = "fa-1_5x", 6901 LabelPosition = IconLabelPosition.After 6902 }, 6903 ButtonLayout = ButtonLayout.LinkClean, 6904 ButtonType = ButtonType.Button, 6905 OnClick = "document.getElementById('FavoriteTrigger_{{id}}').checked = true" 6906 }) 6907 <input type="checkbox" id="FavoriteTrigger_{{id}}" class="dropdown-trigger" /> 6908 <div class="dropdown dropdown--position-32px"> 6909 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 6910 <ul class="list list--clean dw-mod"> 6911 {{#FavoriteLists}} 6912 {{>FavoriteListItem}} 6913 {{/FavoriteLists}} 6914 </ul> 6915 </div> 6916 <label class="dropdown-trigger-off" for="FavoriteTrigger_{{id}}"></label> 6917 </div> 6918 </div> 6919 </script> 6920 6921 <script id="FavoriteListItem" type="text/x-template"> 6922 <li> 6923 @{ 6924 var button = new Button { 6925 CssClass = "list__link u-no-underline", 6926 OnClick = "toggleFavAction(this, event)", 6927 Icon = new Icon { Name = "{{#if isInFavoriteList}}" + favoriteIcon + "{{else}}" + favoriteOutlineIcon + "{{/if}}", LabelPosition = IconLabelPosition.After }, 6928 AltText = "{{#if isInFavoriteList}}" + Translate("Remove from") + " {{name}}{{else}}" + Translate("Add to") + " {{name}}{{/if}}", 6929 Title = "{{name}}", 6930 ButtonType = ButtonType.Button, 6931 ButtonLayout = ButtonLayout.LinkClean, 6932 ExtraAttributes = new Dictionary<string, string> 6933 { 6934 { "data-list-id", "{{listId}}" }, 6935 { "data-list-name", "{{name}}" }, 6936 { "data-remove-link", "{{removeLink}}" }, 6937 { "data-add-link", "{{addLink}}" }, 6938 { "data-is-in-list", "{{isInFavoriteList}}" }, 6939 6940 } 6941 }; 6942 if (useFacebookPixel) 6943 { 6944 button.ExtraAttributes.Add("data-facebook-object", "{{facebookPixelAddAction}}"); 6945 } 6946 } 6947 <div class="grid__cell"> 6948 @Render(button) 6949 </div> 6950 </li> 6951 </script> 6952 6953 <script> 6954 @if (!string.IsNullOrEmpty(currentFavoriteListId)) 6955 { 6956 <text> 6957 window.currentFavoriteListId = "@currentFavoriteListId"; 6958 </text> 6959 } 6960 function toggleFavAction(button, event) { 6961 if (button.getAttribute('data-add-link').indexOf('CCCreateNewList') > -1) { 6962 Scroll.SavePosition(event); 6963 @if (useFacebookPixel) 6964 { 6965 <text> 6966 fbq('track', 'AddToWishlist', JSON.parse(button.getAttribute('data-facebook-object'))); 6967 </text> 6968 } 6969 location.href = button.getAttribute('data-add-link'); 6970 return; 6971 } 6972 let isAdd = button.getAttribute('data-is-in-list') == "false"; 6973 Request.Fetch().get( 6974 isAdd ? button.getAttribute('data-add-link') : button.getAttribute('data-remove-link'), 6975 function (result) { 6976 button.querySelector('i').className = isAdd ? '@favoriteIcon u-margin-right--lg' : '@favoriteOutlineIcon u-margin-right--lg'; 6977 button.setAttribute('data-is-in-list', isAdd); 6978 button.setAttribute('title', (!isAdd ? '@Translate("Add to") ' : '@Translate("Remove from") ') + button.getAttribute('data-list-name')) 6979 let favList = button.closest('.js-favorites-list'); 6980 let favBtn = favList.querySelector('.js-favorite-btn i'); 6981 let isInAnyFavoriteList = favList.querySelector('[data-is-in-list=true]') != null; 6982 if (isInAnyFavoriteList) { 6983 favBtn.className = '@favoriteIcon' + ' fa-1_5x'; 6984 } else { 6985 favBtn.className = '@favoriteOutlineIcon' + ' fa-1_5x'; 6986 } 6987 @if (useFacebookPixel) 6988 { 6989 <text> 6990 if (isAdd) { 6991 fbq('track', 'AddToWishlist', JSON.parse(button.getAttribute('data-facebook-object'))); 6992 } 6993 </text> 6994 } 6995 if (window.currentFavoriteListId != null) { //if this page is favorite list 6996 let listId = button.getAttribute("data-list-id"); 6997 if (listId == window.currentFavoriteListId && !isAdd) { 6998 location.reload(); 6999 } 7000 } 7001 }, 7002 function () { 7003 console.error("FavoriteLists: Error in ToggleFavAction request"); 7004 }, 7005 false 7006 ); 7007 } 7008 </script> 7009 } 7010 @inherits ViewModelTemplate<ProductViewModel> 7011 @using Dynamicweb.Ecommerce.ProductCatalog 7012 @using Dynamicweb.Rendering 7013 @using Dynamicweb.Rapido.Blocks 7014 7015 @{ 7016 BlocksPage customProductBlocks = BlocksPage.GetBlockPage("Product"); 7017 7018 } 7019 7020 7021 <div class="product__info dw-mod js-product"> 7022 7023 @{ 7024 var navigationSettingsBreadcrump = new Dynamicweb.Frontend.Navigation.NavigationSettings() 7025 { 7026 StartLevel = 2, 7027 StopLevel = 10, 7028 ExpandMode = Dynamicweb.Frontend.Navigation.ExpandMode.PathOnly 7029 }; 7030 } 7031 7032 @if (GetNavigation(navigationSettingsBreadcrump).Nodes.Any()) 7033 { 7034 <ul class="breadcrumb dw-mod"> 7035 @RenderNavigationNodes(GetNavigation(navigationSettingsBreadcrump).Nodes) 7036 7037 @helper RenderNavigationNodes(IEnumerable<Dynamicweb.Frontend.Navigation.NavigationTreeNodeViewModel> nodes) 7038 { 7039 foreach (var node in nodes) 7040 { 7041 if (node.InPath) 7042 { 7043 <li class="breadcrumb__item dw-mod"> 7044 <a href="@node.Link">@node.Name</a> 7045 </li> 7046 @RenderNavigationNodes(node.Nodes); 7047 } 7048 } 7049 } 7050 </ul> 7051 } 7052 7053 <div class="grid grid--direction-column"> 7054 @* The @RenderBlockList base helper is included in Components/GridBuilder.cshtml *@ 7055 @RenderBlockList(productsPage.BlocksRoot.BlocksList) 7056 <div class="paragraph-container--full-width"> 7057 @RenderBlockList(productDetails) 7058 </div> 7059 </div> 7060 </div> 7061 7062 @helper RenderProductTop() 7063 { 7064 List<Block> subBlocks = productsPage.GetBlockListById("Top").OrderBy(item => item.SortId).ToList(); 7065 7066 <div class="product__top paragraph-container paragraph-container--full-width u-grey-border-bottom"> 7067 <div class="center-container dw-mod"> 7068 <div class="grid"> 7069 @RenderBlockList(subBlocks) 7070 </div> 7071 </div> 7072 </div> 7073 } 7074 7075 7076 @helper RenderProductMiniTabs() 7077 { 7078 List<Block> subBlocks = productsPage.GetBlockListById("MiniTabs").OrderBy(item => item.SortId).ToList(); 7079 7080 if (subBlocks.Count > 0) 7081 { 7082 <div class="grid__col-12 product__info tabs u-no-padding u-margin-bottom--lg dw-mod"> 7083 @{ 7084 bool firstTab = true; 7085 foreach (Block item in subBlocks) 7086 { 7087 string isChecked = firstTab ? "checked" : ""; 7088 firstTab = false; 7089 7090 <input type="radio" class="tabs__trigger" name="productMiniTabs" id="@item.Id" onchange="bLazy.revalidate()" @isChecked /> 7091 } 7092 } 7093 7094 <div class="tabs__list dw-mod"> 7095 @foreach (Block item in subBlocks) 7096 { 7097 <label for="@item.Id" class="tabs__label dw-mod">@item.Name</label> 7098 } 7099 </div> 7100 7101 <div class="tabs__blocks dw-mod"> 7102 @foreach (Block item in subBlocks) 7103 { 7104 string hidePadding = item.Design.HidePadding ? "u-no-padding" : ""; 7105 7106 if (item.Design.RenderType != RenderType.Hide) 7107 { 7108 <div class="tabs__block u-border dw-mod" id="Block__@item.Id"> 7109 <block class="product__block paragraph-container product__block--bordered dw-mod"> 7110 <div class="center-container dw-mod"> 7111 @RenderBlock(item) 7112 </div> 7113 </block> 7114 </div> 7115 } 7116 } 7117 </div> 7118 </div> 7119 } 7120 } 7121 7122 @helper RenderProductTabs() 7123 { 7124 List<Block> subBlocks = productsPage.GetBlockListById("Tabs").OrderBy(item => item.SortId).ToList(); 7125 7126 <div class="grid__col-12 product__info product__info--tabs tabs dw-mod"> 7127 @{ 7128 bool firstTab = true; 7129 foreach (Block item in subBlocks) 7130 { 7131 string isChecked = firstTab ? "checked" : ""; 7132 firstTab = false; 7133 7134 <input type="radio" class="tabs__trigger" name="productTabs" id="@item.Id" onchange="bLazy.revalidate()" @isChecked /> 7135 } 7136 } 7137 7138 <div class="tabs__list dw-mod"> 7139 @foreach (Block item in subBlocks) 7140 { 7141 <label for="@item.Id" class="tabs__label dw-mod">@item.Name</label> 7142 } 7143 </div> 7144 7145 <div class="tabs__blocks dw-mod"> 7146 @foreach (Block item in subBlocks) 7147 { 7148 string hidePadding = item.Design.HidePadding ? "u-no-padding" : ""; 7149 7150 if (item.Design.RenderType != RenderType.Hide) 7151 { 7152 <div class="tabs__block dw-mod" id="Block__@item.Id"> 7153 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 7154 <div class="center-container u-padding--lg dw-mod"> 7155 @RenderBlock(item) 7156 </div> 7157 </section> 7158 </div> 7159 } 7160 } 7161 </div> 7162 </div> 7163 } 7164 7165