Error executing template "Designs/Rapido/eCom/Product/Product.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at CompiledRazorTemplates.Dynamic.RazorEngine_dd5045f76783495bb8dc170ca10111c3.<RenderMainInfoConfiguratorCustom>b__163_0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\composeit\Variant\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 8932 at RazorEngine.Templating.TemplateWriter.ToString() at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at CompiledRazorTemplates.Dynamic.RazorEngine_dd5045f76783495bb8dc170ca10111c3.<>c__DisplayClass4_0.<RenderBlock>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\composeit\Variant\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 208 at CompiledRazorTemplates.Dynamic.RazorEngine_dd5045f76783495bb8dc170ca10111c3.<>c__DisplayClass3_0.<RenderBlockList>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\composeit\Variant\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 118 at CompiledRazorTemplates.Dynamic.RazorEngine_dd5045f76783495bb8dc170ca10111c3.Execute() in D:\dynamicweb.net\Solutions\composeit\Variant\Files\Templates\Designs\Rapido\eCom\Product\Product.cshtml:line 10419 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 3 @using System.Web 4 @using Dynamicweb.Extensibility 5 @using Dynamicweb.Content 6 @using System 7 @using System.IO 8 @using Dynamicweb.Core 9 @using System.Web 10 @using System.Globalization 11 @using System.Web.UI.HtmlControls 12 @using Dynamicweb.Rapido.Blocks 13 @using Dynamicweb.Ecommerce 14 15 @functions { 16 List<LoopItem> downloadDocuments = new List<LoopItem>(); 17 //downloadDocuments variable, will be defined in Fields.cshtml and used in ProductAssets.cshtml 18 19 BlocksPage productsPage = BlocksPage.GetBlockPage("Product"); 20 21 public static string ToPascalCase(string str) 22 { 23 return CultureInfo.InvariantCulture.TextInfo 24 .ToTitleCase(str.ToLowerInvariant()) 25 .Replace("-", "") 26 .Replace("_", "") 27 .Replace(" ", ""); 28 } 29 } 30 31 @{ 32 string productBlocksPosition = Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "thumbs-image-info"; 33 bool productInfoOnTheRight = productBlocksPosition.LastIndexOf("info") == productBlocksPosition.Length - 4; 34 35 Block productTop = new Block() 36 { 37 Id = "Top", 38 SortId = 10, 39 SkipRenderBlocksList = true, 40 Template = RenderProductTop() 41 }; 42 productsPage.Add(productTop); 43 44 Block productMainInfo = new Block() 45 { 46 Id = "MainInformation", 47 SortId = productInfoOnTheRight ? 20 : 10, 48 Design = new Design 49 { 50 Size = "auto", 51 RenderType = RenderType.Column 52 } 53 }; 54 productsPage.Add("Top", productMainInfo); 55 56 //Optional mini tabs block 57 Block miniTabsBlock = new Block() 58 { 59 Id = "MiniTabs", 60 SortId = 40, 61 Template = RenderProductMiniTabs(), 62 SkipRenderBlocksList = true 63 }; 64 productsPage.Add("MainInformation", miniTabsBlock); 65 //----- 66 67 Block productTabsBlock = new Block() 68 { 69 Id = "Tabs", 70 SortId = 20, 71 Template = RenderProductTabs(), 72 SkipRenderBlocksList = true 73 }; 74 productsPage.Add(productTabsBlock); 75 76 Block productDetailsBlock = new Block() 77 { 78 Id = "Section", 79 SortId = 30 80 }; 81 productsPage.Add(productDetailsBlock); 82 83 Block productSnippetsBlock = new Block() 84 { 85 Id = "Snippets", 86 SortId = 40 87 }; 88 productsPage.Add(productSnippetsBlock); 89 } 90 91 @* Include the required Grid builder (Contains the methods @RenderBlockList and @RenderBlock) *@ 92 @using System.Text.RegularExpressions 93 @using System.Collections.Generic 94 @using System.Reflection 95 @using System.Web 96 @using System.Web.UI.HtmlControls 97 @using Dynamicweb.Rapido.Blocks.Components 98 @using Dynamicweb.Rapido.Blocks.Components.Articles 99 @using Dynamicweb.Rapido.Blocks.Components.Documentation 100 @using Dynamicweb.Rapido.Blocks 101 102 103 @*--- START: Base block renderers ---*@ 104 105 @helper RenderBlockList(List<Block> blocks) 106 { 107 bool debug = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("debug")) ? Convert.ToBoolean(HttpContext.Current.Request.QueryString.Get("debug")) : false; 108 blocks = blocks.OrderBy(item => item.SortId).ToList(); 109 110 foreach (Block item in blocks) 111 { 112 if (debug) { 113 <!-- Block START: @item.Id --> 114 } 115 116 if (item.Design == null) 117 { 118 @RenderBlock(item) 119 } 120 else if (item.Design.RenderType == RenderType.None) { 121 string cssClass = item.Design.CssClass != null ? item.Design.CssClass : ""; 122 123 <div class="@cssClass dw-mod"> 124 @RenderBlock(item) 125 </div> 126 } 127 else if (item.Design.RenderType != RenderType.Hide) 128 { 129 string cssClass = item.Design.CssClass != null ? item.Design.CssClass : ""; 130 131 if (!item.SkipRenderBlocksList) { 132 if (item.Design.RenderType == RenderType.Row) 133 { 134 <div class="grid grid--align-content-start @cssClass dw-mod" id="Block__@item.Id"> 135 @RenderBlock(item) 136 </div> 137 } 138 139 if (item.Design.RenderType == RenderType.Column) 140 { 141 string hidePadding = item.Design.HidePadding ? "u-no-padding" : ""; 142 string size = item.Design.Size ?? "12"; 143 size = Regex.IsMatch(size, @"\d") ? "md-" + item.Design.Size : item.Design.Size; 144 145 <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"> 146 @RenderBlock(item) 147 </div> 148 } 149 150 if (item.Design.RenderType == RenderType.Table) 151 { 152 <table class="table @cssClass dw-mod" id="Block__@item.Id"> 153 @RenderBlock(item) 154 </table> 155 } 156 157 if (item.Design.RenderType == RenderType.TableRow) 158 { 159 <tr class="@cssClass dw-mod" id="Block__@item.Id"> 160 @RenderBlock(item) 161 </tr> 162 } 163 164 if (item.Design.RenderType == RenderType.TableColumn) 165 { 166 <td class="@cssClass dw-mod" id="Block__@item.Id"> 167 @RenderBlock(item) 168 </td> 169 } 170 171 if (item.Design.RenderType == RenderType.CardHeader) 172 { 173 <div class="card-header @cssClass dw-mod"> 174 @RenderBlock(item) 175 </div> 176 } 177 178 if (item.Design.RenderType == RenderType.CardBody) 179 { 180 <div class="card @cssClass dw-mod"> 181 @RenderBlock(item) 182 </div> 183 } 184 185 if (item.Design.RenderType == RenderType.CardFooter) 186 { 187 <div class="card-footer @cssClass dw-mod"> 188 @RenderBlock(item) 189 </div> 190 } 191 } 192 else 193 { 194 @RenderBlock(item) 195 } 196 } 197 198 if (debug) { 199 <!-- Block END: @item.Id --> 200 } 201 } 202 } 203 204 @helper RenderBlock(Block item) 205 { 206 bool debug = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("debug")) ? Convert.ToBoolean(HttpContext.Current.Request.QueryString.Get("debug")) : false; 207 208 if (item.Template != null) 209 { 210 @BlocksPage.RenderTemplate(item.Template) 211 } 212 213 if (item.Component != null) 214 { 215 string customSufix = "Custom"; 216 string methodName = item.Component.HelperName; 217 218 ComponentBase[] methodParameters = new ComponentBase[1]; 219 methodParameters[0] = item.Component; 220 Type methodType = this.GetType(); 221 222 MethodInfo customMethod = methodType.GetMethod(methodName + customSufix); 223 MethodInfo generalMethod = methodType.GetMethod(methodName); 224 225 try { 226 if (debug) { 227 <!-- Component: @methodName.Replace("Render", "") --> 228 } 229 @customMethod.Invoke(this, methodParameters).ToString(); 230 } catch { 231 try { 232 @generalMethod.Invoke(this, methodParameters).ToString(); 233 } catch(Exception ex) { 234 throw new Exception(item.Component.GetType().Name + " method '" + methodName +"' could not be invoked", ex); 235 } 236 } 237 } 238 239 if (item.BlocksList.Count > 0 && !item.SkipRenderBlocksList) 240 { 241 @RenderBlockList(item.BlocksList) 242 } 243 } 244 245 @*--- END: Base block renderers ---*@ 246 247 @using Dynamicweb.Rapido.Blocks.Components 248 @using Dynamicweb.Rapido.Blocks.Components.General 249 @using Dynamicweb.Rapido.Blocks 250 @using System.IO 251 252 @* Required *@ 253 @using Dynamicweb.Rapido.Blocks.Components 254 @using Dynamicweb.Rapido.Blocks.Components.General 255 @using Dynamicweb.Rapido.Blocks 256 257 258 @helper Render(ComponentBase component) 259 { 260 if (component != null) 261 { 262 @component.Render(this) 263 } 264 } 265 266 @* Components *@ 267 @using System.Reflection 268 @using Dynamicweb.Rapido.Blocks.Components.General 269 270 271 @* Component *@ 272 273 @helper RenderIcon(Icon settings) 274 { 275 if (settings != null) 276 { 277 string color = settings.Color != null ? "style=\"color: " + settings.Color + "\"" : ""; 278 279 if (settings.Name != null) 280 { 281 if (string.IsNullOrEmpty(settings.Label)) 282 { 283 <i class="@settings.Prefix @settings.Name @settings.CssClass" @color></i> 284 } 285 else 286 { 287 if (settings.LabelPosition == IconLabelPosition.Before) 288 { 289 <div class="u-flex u-flex--align-items-center @settings.CssClass">@settings.Label <i class="@settings.Prefix @settings.Name u-margin-left" @color></i></div> 290 } 291 else 292 { 293 <div class="u-flex u-flex--align-items-center @settings.CssClass"><i class="@settings.Prefix @settings.Name u-margin-right--lg u-w20px" @color></i>@settings.Label</div> 294 } 295 } 296 } 297 else if (!string.IsNullOrEmpty(settings.Label)) 298 { 299 @settings.Label 300 } 301 } 302 } 303 @using System.Reflection 304 @using Dynamicweb.Rapido.Blocks.Components.General 305 @using Dynamicweb.Rapido.Blocks.Components 306 @using Dynamicweb.Core 307 308 @* Component *@ 309 310 @helper RenderButton(Button settings) 311 { 312 if (settings != null && (!string.IsNullOrEmpty(settings.Title) || settings.Icon != null)) 313 { 314 Dictionary<string, string> attributes = new Dictionary<string, string>(); 315 List<string> classList = settings.CssClass != null ? settings.CssClass.Split(' ').ToList() : new List<string>(); 316 if (settings.Disabled) { 317 attributes.Add("disabled", "true"); 318 classList.Add("disabled"); 319 } 320 321 if (!string.IsNullOrEmpty(settings.ConfirmText) || !string.IsNullOrEmpty(settings.ConfirmTitle)) 322 { 323 settings.Id = !string.IsNullOrEmpty(settings.Id) ? settings.Id : Guid.NewGuid().ToString("N"); 324 @RenderConfirmDialog(settings); 325 settings.OnClick = "document.getElementById('" + settings.Id + "ModalTrigger').checked = true"; 326 } 327 328 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 329 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 330 if (!string.IsNullOrEmpty(settings.AltText)) 331 { 332 attributes.Add("title", settings.AltText); 333 } 334 else if (!string.IsNullOrEmpty(settings.Title)) 335 { 336 attributes.Add("title", settings.Title); 337 } 338 339 var onClickEvents = new List<string>(); 340 if (!string.IsNullOrEmpty(settings.OnClick)) 341 { 342 onClickEvents.Add(settings.OnClick); 343 } 344 if (!string.IsNullOrEmpty(settings.Href)) 345 { 346 onClickEvents.Add("location.href='" + settings.Href + "'"); 347 } 348 if (onClickEvents.Count > 0) 349 { 350 attributes.Add("onClick", string.Join(";", onClickEvents)); 351 } 352 353 if (settings.ButtonLayout != ButtonLayout.None) 354 { 355 classList.Add("btn"); 356 string btnLayout = Enum.GetName(typeof(ButtonLayout), settings.ButtonLayout).ToLower(); 357 if (btnLayout == "linkclean") 358 { 359 btnLayout = "link-clean"; //fix 360 } 361 classList.Add("btn--" + btnLayout); 362 } 363 364 if (settings.Icon == null) 365 { 366 settings.Icon = new Icon(); 367 } 368 369 settings.Icon.CssClass += Enum.GetName(typeof(ButtonLayout), settings.ButtonLayout).ToLower() != "linkclean" ? " u-flex--align-center" : ""; 370 settings.Icon.Label = settings.Title; 371 372 attributes.Add("type", Enum.GetName(typeof(ButtonType), settings.ButtonType).ToLower()); 373 374 <button class="@string.Join(" ", classList) dw-mod" @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@Render(settings.Icon)</button> 375 } 376 } 377 378 @helper RenderConfirmDialog(Button settings) 379 { 380 Modal confirmDialog = new Modal { 381 Id = settings.Id, 382 Width = ModalWidth.Sm, 383 Heading = new Heading 384 { 385 Level = 2, 386 Title = settings.ConfirmTitle 387 }, 388 BodyText = settings.ConfirmText 389 }; 390 391 confirmDialog.AddAction(new Button { Title = Translate("Cancel"), ButtonLayout = ButtonLayout.Secondary, OnClick = "document.getElementById('" + settings.Id + "ModalTrigger').checked = false"}); 392 confirmDialog.AddAction(new Button { Title = Translate("OK"), ButtonLayout = ButtonLayout.Primary, OnClick = "document.getElementById('" + settings.Id + "ModalTrigger').checked = false;" + settings.OnClick }); 393 394 @Render(confirmDialog) 395 } 396 @using Dynamicweb.Rapido.Blocks.Components.General 397 @using Dynamicweb.Rapido.Blocks.Components 398 @using Dynamicweb.Core 399 400 @helper RenderDashboard(Dashboard settings) 401 { 402 var widgets = settings.GetWidgets(); 403 404 if (!string.IsNullOrEmpty(settings.WidgetsBaseBackgroundColor)) 405 { 406 //set bg color for them 407 408 System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(settings.WidgetsBaseBackgroundColor); 409 int r = Convert.ToInt16(color.R); 410 int g = Convert.ToInt16(color.G); 411 int b = Convert.ToInt16(color.B); 412 413 var count = widgets.Length; 414 var max = Math.Max(r, Math.Max(g, b)); 415 double step = 255.0 / (max * count); 416 var i = 0; 417 foreach (var widget in widgets) 418 { 419 i++; 420 421 var shade = "rgb(" + Converter.ToString(r * step * i).Replace(",", ".") + ", " + Converter.ToString(g * step * i).Replace(",", ".") + ", " + Converter.ToString(b * step * i).Replace(",", ".") + ")"; 422 widget.BackgroundColor = shade; 423 } 424 } 425 426 <div class="dashboard @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 427 @foreach (var widget in widgets) 428 { 429 <div class="dashboard__widget"> 430 @Render(widget) 431 </div> 432 } 433 </div> 434 } 435 @using Dynamicweb.Rapido.Blocks.Components.General 436 @using Dynamicweb.Rapido.Blocks.Components 437 438 @helper RenderDashboardWidgetLink(DashboardWidgetLink settings) 439 { 440 if (!string.IsNullOrEmpty(settings.Link)) 441 { 442 var backgroundStyles = ""; 443 if (!string.IsNullOrEmpty(settings.BackgroundColor)) 444 { 445 backgroundStyles = "style=\"background-color:" + settings.BackgroundColor + "\""; 446 } 447 448 <a href="@settings.Link" class="widget widget--link @settings.CssClass dw-mod" @backgroundStyles title="@settings.Title" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 449 <div class="u-center-middle u-color-light"> 450 @if (settings.Icon != null) 451 { 452 settings.Icon.CssClass += "widget__icon"; 453 @Render(settings.Icon) 454 } 455 <div class="widget__title">@settings.Title</div> 456 </div> 457 </a> 458 } 459 } 460 @using Dynamicweb.Rapido.Blocks.Components.General 461 @using Dynamicweb.Rapido.Blocks.Components 462 463 @helper RenderDashboardWidgetCounter(DashboardWidgetCounter settings) 464 { 465 var backgroundStyles = ""; 466 if (!string.IsNullOrEmpty(settings.BackgroundColor)) 467 { 468 backgroundStyles = "style='background-color:" + settings.BackgroundColor + "'"; 469 } 470 471 <div class="widget @settings.CssClass dw-mod" @backgroundStyles @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 472 <div class="u-center-middle u-color-light"> 473 @if (settings.Icon != null) 474 { 475 settings.Icon.CssClass += "widget__icon"; 476 @Render(settings.Icon) 477 } 478 <div class="widget__counter">@settings.Count</div> 479 <div class="widget__title">@settings.Title</div> 480 </div> 481 </div> 482 } 483 @using System.Reflection 484 @using Dynamicweb.Rapido.Blocks.Components.General 485 @using Dynamicweb.Rapido.Blocks.Components 486 @using Dynamicweb.Core 487 488 @* Component *@ 489 490 @helper RenderLink(Link settings) 491 { 492 if (settings != null && !string.IsNullOrEmpty(settings.Href) && (!string.IsNullOrEmpty(settings.Title) || settings.Icon != null)) 493 { 494 Dictionary<string, string> attributes = new Dictionary<string, string>(); 495 List<string> classList = settings.CssClass != null ? settings.CssClass.Split(' ').ToList() : new List<string>(); 496 if (settings.Disabled) 497 { 498 attributes.Add("disabled", "true"); 499 classList.Add("disabled"); 500 } 501 502 if (!string.IsNullOrEmpty(settings.AltText)) 503 { 504 attributes.Add("title", settings.AltText); 505 } 506 else if (!string.IsNullOrEmpty(settings.Title)) 507 { 508 attributes.Add("title", settings.Title); 509 } 510 511 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 512 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 513 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onClick", settings.OnClick); } 514 attributes.Add("href", settings.Href); 515 516 if (settings.ButtonLayout != ButtonLayout.None) 517 { 518 classList.Add("btn"); 519 string btnLayout = Enum.GetName(typeof(ButtonLayout), settings.ButtonLayout).ToLower(); 520 if (btnLayout == "linkclean") 521 { 522 btnLayout = "link-clean"; //fix 523 } 524 classList.Add("btn--" + btnLayout); 525 } 526 527 if (settings.Icon == null) 528 { 529 settings.Icon = new Icon(); 530 } 531 settings.Icon.Label = settings.Title; 532 533 if (settings.Target == LinkTargetType.Blank && settings.Rel == LinkRelType.None) 534 { 535 settings.Rel = LinkRelType.Noopener; 536 } 537 if (settings.Target != LinkTargetType.None) 538 { 539 attributes.Add("target", "_" + Enum.GetName(typeof(LinkTargetType), settings.Target).ToLower()); 540 } 541 if (settings.Download) 542 { 543 attributes.Add("download", "true"); 544 } 545 if (settings.Rel != LinkRelType.None) 546 { 547 attributes.Add("rel", Enum.GetName(typeof(LinkRelType), settings.Rel).ToLower()); 548 } 549 550 <a class="@string.Join(" ", classList) dw-mod" @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@Render(settings.Icon)</a> 551 } 552 } 553 @using System.Reflection 554 @using Dynamicweb.Rapido.Blocks.Components 555 @using Dynamicweb.Rapido.Blocks.Components.General 556 @using Dynamicweb.Rapido.Blocks 557 558 559 @* Component *@ 560 561 @helper RenderRating(Rating settings) 562 { 563 if (settings.Score > 0) 564 { 565 int rating = settings.Score; 566 string iconType = "fa-star"; 567 568 switch (settings.Type.ToString()) { 569 case "Stars": 570 iconType = "fa-star"; 571 break; 572 case "Hearts": 573 iconType = "fa-heart"; 574 break; 575 case "Lemons": 576 iconType = "fa-lemon"; 577 break; 578 case "Bombs": 579 iconType = "fa-bomb"; 580 break; 581 } 582 583 <div class="u-ta-right"> 584 @for (int i = 0; i < settings.OutOf; i++) 585 { 586 <i class="@(rating > i ? "fas" : "far") @iconType"></i> 587 } 588 </div> 589 } 590 } 591 @using System.Reflection 592 @using Dynamicweb.Rapido.Blocks.Components.General 593 @using Dynamicweb.Rapido.Blocks.Components 594 595 596 @* Component *@ 597 598 @helper RenderSelectFieldOption(SelectFieldOption settings) 599 { 600 Dictionary<string, string> attributes = new Dictionary<string, string>(); 601 if (settings.Checked) { attributes.Add("selected", "true"); } 602 if (settings.Disabled) { attributes.Add("disabled", "true"); } 603 if (settings.Value != null) { attributes.Add("value", settings.Value); } 604 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 605 606 <option @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@settings.Label</option> 607 } 608 @using System.Reflection 609 @using Dynamicweb.Rapido.Blocks.Components.General 610 @using Dynamicweb.Rapido.Blocks.Components 611 612 613 @* Component *@ 614 615 @helper RenderNavigation(Navigation settings) { 616 @RenderNavigation(new 617 { 618 id = settings.Id, 619 cssclass = settings.CssClass, 620 startLevel = settings.StartLevel, 621 endlevel = settings.EndLevel, 622 expandmode = settings.Expandmode, 623 sitemapmode = settings.SitemapMode, 624 template = settings.Template 625 }) 626 } 627 @using Dynamicweb.Rapido.Blocks.Components.General 628 @using Dynamicweb.Rapido.Blocks.Components 629 630 631 @* Component *@ 632 633 @helper RenderBreadcrumbNavigation(BreadcrumbNavigation settings) { 634 settings.Id = String.IsNullOrEmpty(settings.Id) ? "breadcrumb" : settings.Id; 635 settings.Template = String.IsNullOrEmpty(settings.Template) ? "Breadcrumb.xslt" : settings.Template; 636 settings.StartLevel = settings.StartLevel == 0 ? 1 : settings.StartLevel; 637 settings.EndLevel = settings.EndLevel == 10 ? 1 : settings.EndLevel; 638 settings.Expandmode = String.IsNullOrEmpty(settings.Expandmode) ? "all" : settings.Expandmode; 639 settings.SitemapMode = false; 640 641 @RenderNavigation(settings) 642 } 643 @using Dynamicweb.Rapido.Blocks.Components.General 644 @using Dynamicweb.Rapido.Blocks.Components 645 646 647 @* Component *@ 648 649 @helper RenderLeftNavigation(LeftNavigation settings) { 650 settings.Id = String.IsNullOrEmpty(settings.Id) ? "breadcrumb" : settings.Id; 651 settings.Template = String.IsNullOrEmpty(settings.Template) ? "Breadcrumb.xslt" : settings.Template; 652 settings.StartLevel = settings.StartLevel == 0 ? 1 : settings.StartLevel; 653 settings.EndLevel = settings.EndLevel == 10 ? 1 : settings.EndLevel; 654 settings.Expandmode = String.IsNullOrEmpty(settings.Expandmode) ? "all" : settings.Expandmode; 655 656 <div class="grid__cell"> 657 @RenderNavigation(settings) 658 </div> 659 } 660 @using System.Reflection 661 @using Dynamicweb.Rapido.Blocks.Components.General 662 @using Dynamicweb.Core 663 664 @* Component *@ 665 666 @helper RenderHeading(Heading settings) 667 { 668 if (settings != null && !string.IsNullOrEmpty(settings.Title)) 669 { 670 string color = settings.Color != null ? "style=\"color: " + settings.Color + "\"" : ""; 671 string tagName = settings.Level != 0 ? "h" + settings.Level.ToString() : "div"; 672 673 @("<" + tagName + " class=\"" + settings.CssClass + " dw-mod\" " + color + ">") 674 if (!string.IsNullOrEmpty(settings.Link)) 675 { 676 @Render(new Link { Href = settings.Link, Icon = settings.Icon, Title = settings.Title, ButtonLayout = ButtonLayout.None }) 677 } 678 else 679 { 680 if (settings.Icon == null) 681 { 682 settings.Icon = new Icon(); 683 } 684 settings.Icon.Label = settings.Title; 685 @Render(settings.Icon) 686 } 687 @("</" + tagName + ">"); 688 } 689 } 690 @using Dynamicweb.Rapido.Blocks.Components 691 @using Dynamicweb.Rapido.Blocks.Components.General 692 @using Dynamicweb.Rapido.Blocks 693 694 695 @* Component *@ 696 697 @helper RenderImage(Image settings) 698 { 699 if (settings.FilterPrimary != ImageFilter.None || settings.FilterSecondary != ImageFilter.None) 700 { 701 Dictionary<string, string> optionalAttributes = new Dictionary<string, string>(); 702 if (!string.IsNullOrEmpty(settings.FilterColor)) { optionalAttributes.Add("style", "background-color: " + settings.FilterColor); } 703 704 if (settings.Caption != null) 705 { 706 @:<div> 707 } 708 709 var primaryFilterClass = settings.FilterPrimary.ToString().ToLower(); 710 var secondaryFilterClass = settings.FilterSecondary.ToString().ToLower(); 711 712 <div class="image-filter image-filter--@primaryFilterClass u-position-relative dw-mod" @ComponentMethods.AddAttributes(optionalAttributes)> 713 <div class="image-filter image-filter--@secondaryFilterClass dw-mod"> 714 @if (settings.Link != null) 715 { 716 <a href="@settings.Link"> 717 @RenderTheImage(settings) 718 </a> 719 } 720 else 721 { 722 @RenderTheImage(settings) 723 } 724 </div> 725 </div> 726 727 if (settings.Caption != null) 728 { 729 <span class="image-caption dw-mod">@settings.Caption</span> 730 @:</div> 731 } 732 } 733 else 734 { 735 if (settings.Caption != null) 736 { 737 @:<div> 738 } 739 if (!string.IsNullOrEmpty(settings.Link)) 740 { 741 <a href="@settings.Link"> 742 @RenderTheImage(settings) 743 </a> 744 } 745 else 746 { 747 @RenderTheImage(settings) 748 } 749 750 if (settings.Caption != null) 751 { 752 <span class="image-caption dw-mod">@settings.Caption</span> 753 @:</div> 754 } 755 } 756 } 757 758 @helper RenderTheImage(Image settings) 759 { 760 if (settings != null) 761 { 762 string alternativeImage = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("AlternativeImage")) ? Pageview.AreaSettings.GetItem("Settings").GetFile("AlternativeImage").PathUrlEncoded : "/Images/missing_image.jpg"; 763 string placeholderImage = "/Files/Images/placeholder.gif"; 764 string imageEngine = "/Admin/Public/GetImage.ashx?"; 765 766 string imageStyle = ""; 767 768 switch (settings.Style) 769 { 770 case ImageStyle.Ball: 771 imageStyle = "grid__cell-img--ball"; 772 break; 773 774 case ImageStyle.Triangle: 775 imageStyle = "grid__cell-img--triangle"; 776 break; 777 } 778 779 if (settings.Style == ImageStyle.Ball || settings.Style == ImageStyle.Circle || settings.Style == ImageStyle.Triangle) 780 { 781 settings.ImageDefault.Crop = settings.ImageDefault.Crop == 5 ? settings.ImageDefault.Crop = 0 : settings.ImageDefault.Crop; 782 783 if (settings.ImageDefault != null) 784 { 785 settings.ImageDefault.Height = settings.ImageDefault.Width; 786 } 787 if (settings.ImageMedium != null) 788 { 789 settings.ImageMedium.Height = settings.ImageMedium.Width; 790 } 791 if (settings.ImageSmall != null) 792 { 793 settings.ImageSmall.Height = settings.ImageSmall.Width; 794 } 795 } 796 797 string defaultImage = imageEngine; 798 string imageSmall = ""; 799 string imageMedium = ""; 800 801 if (settings.DisableImageEngine) 802 { 803 defaultImage = settings.Path; 804 } 805 else 806 { 807 if (settings.ImageDefault != null) 808 { 809 if (settings.ImageDefault.Format == ImageFormat.Default) 810 { 811 settings.ImageDefault.Format = ImageFormat.WebP; 812 } 813 814 defaultImage += Dynamicweb.Rapido.Services.Images.GetImagePathFromSettings(settings.ImageDefault); 815 816 if (settings.Path.GetType() != typeof(string)) 817 { 818 defaultImage += settings.Path != null ? "Image=" + settings.Path.PathUrlEncoded : ""; 819 defaultImage += settings.Path != null ? "&" + settings.Path.GetFocalPointParameters() : ""; 820 } 821 else 822 { 823 defaultImage += settings.Path != null ? "Image=" + settings.Path : ""; 824 } 825 826 defaultImage += "&AlternativeImage=" + alternativeImage; 827 } 828 829 if (settings.ImageSmall != null) 830 { 831 if (settings.ImageSmall.Format == ImageFormat.Default) 832 { 833 settings.ImageSmall.Format = ImageFormat.WebP; 834 } 835 836 imageSmall = "data-src-small=\"" + imageEngine; 837 imageSmall += Dynamicweb.Rapido.Services.Images.GetImagePathFromSettings(settings.ImageSmall); 838 839 if (settings.Path.GetType() != typeof(string)) 840 { 841 imageSmall += settings.Path != null ? "Image=" + settings.Path.PathUrlEncoded : ""; 842 imageSmall += settings.Path != null ? "&" + settings.Path.GetFocalPointParameters() : ""; 843 } 844 else 845 { 846 imageSmall += settings.Path != null ? "Image=" + settings.Path : ""; 847 } 848 849 imageSmall += "&alternativeImage=" + alternativeImage; 850 851 imageSmall += "\""; 852 } 853 854 if (settings.ImageMedium != null) 855 { 856 if (settings.ImageMedium.Format == ImageFormat.Default) 857 { 858 settings.ImageMedium.Format = ImageFormat.WebP; 859 } 860 861 imageMedium = "data-src-medium=\"" + imageEngine; 862 imageMedium += Dynamicweb.Rapido.Services.Images.GetImagePathFromSettings(settings.ImageMedium); 863 864 if (settings.Path.GetType() != typeof(string)) 865 { 866 imageMedium += settings.Path != null ? "Image=" + settings.Path.PathUrlEncoded : ""; 867 imageMedium += settings.Path != null ? "&" + settings.Path.GetFocalPointParameters() : ""; 868 } 869 else 870 { 871 imageMedium += settings.Path != null ? "Image=" + settings.Path : ""; 872 } 873 874 imageMedium += "&alternativeImage=" + alternativeImage; 875 876 imageMedium += "\""; 877 } 878 } 879 880 Dictionary<string, string> optionalAttributes = new Dictionary<string, string>(); 881 if (!string.IsNullOrEmpty(settings.OnClick)) { optionalAttributes.Add("onclick", settings.OnClick); } 882 if (!string.IsNullOrEmpty(settings.Title)) 883 { 884 optionalAttributes.Add("alt", settings.Title); 885 optionalAttributes.Add("title", settings.Title); 886 } 887 888 if (settings.DisableLazyLoad) 889 { 890 <img id="@settings.Id" class="@imageStyle @settings.CssClass dw-mod" src="@defaultImage" @ComponentMethods.AddAttributes(optionalAttributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes) /> 891 } 892 else 893 { 894 <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) /> 895 } 896 } 897 } 898 @using System.Reflection 899 @using Dynamicweb.Rapido.Blocks.Components.General 900 @using Dynamicweb.Rapido.Blocks.Components 901 902 @* Component *@ 903 904 @helper RenderFileField(FileField settings) 905 { 906 var attributes = new Dictionary<string, string>(); 907 if (string.IsNullOrEmpty(settings.Id)) 908 { 909 settings.Id = Guid.NewGuid().ToString("N"); 910 } 911 912 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 913 if (settings.Disabled) { attributes.Add("disabled", "true"); } 914 if (settings.Required) { attributes.Add("required", "true"); } 915 if (settings.Multiple) { attributes.Add("multiple", "true"); } 916 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 917 if (string.IsNullOrEmpty(settings.ChooseFileText)) 918 { 919 settings.ChooseFileText = Translate("Choose file"); 920 } 921 if (string.IsNullOrEmpty(settings.NoFilesChosenText)) 922 { 923 settings.NoFilesChosenText = Translate("No files chosen..."); 924 } 925 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 926 927 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 928 929 string setValueToFakeInput = "FileUpload.setValueToFakeInput(this)"; 930 attributes.Add("onchange", setValueToFakeInput + (!string.IsNullOrEmpty(settings.OnChange) ? settings.OnChange : "")); 931 932 attributes.Add("type", "file"); 933 if (settings.Value != null) { attributes.Add("value", settings.Value); } 934 settings.CssClass = "u-full-width " + settings.CssClass; 935 936 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 937 938 <div class="form__field-group u-full-width @settings.WrapperCssClass dw-mod"> 939 @if (!string.IsNullOrEmpty(settings.Label) || settings.Link != null ) 940 { 941 <div class="u-full-width"> 942 @if (!string.IsNullOrEmpty(settings.Label)) { <label for="@settings.Id" class="u-pull--left">@settings.Label</label> } 943 @if (settings.Link != null) { 944 <div class="u-pull--right"> 945 @{ settings.Link.ButtonLayout = ButtonLayout.LinkClean; } 946 @Render(settings.Link) 947 </div> 948 } 949 </div> 950 951 } 952 953 @if (!string.IsNullOrEmpty(settings.HelpText)) 954 { 955 <small class="form__help-text">@settings.HelpText</small> 956 } 957 958 <div class="form__field-combi file-input u-no-margin dw-mod"> 959 <input @ComponentMethods.AddAttributes(resultAttributes) class="file-input__real-input" data-no-files-text="@settings.NoFilesChosenText" data-many-files-text="@Translate("files")" /> 960 <label for="@settings.Id" class="file-input__btn btn--secondary btn dw-mod">@settings.ChooseFileText</label> 961 <label for="@settings.Id" class="@settings.CssClass file-input__fake-input js-fake-input dw-mod">@settings.NoFilesChosenText</label> 962 @if (settings.UploadButton != null) 963 { 964 settings.UploadButton.CssClass += " btn--condensed u-no-margin"; 965 @Render(settings.UploadButton) 966 } 967 </div> 968 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 969 </div> 970 } 971 @using System.Reflection 972 @using Dynamicweb.Rapido.Blocks.Components.General 973 @using Dynamicweb.Rapido.Blocks.Components 974 @using Dynamicweb.Core 975 @using System.Linq 976 977 @* Component *@ 978 979 @helper RenderDateTimeField(DateTimeField settings) 980 { 981 if (string.IsNullOrEmpty(settings.Id)) 982 { 983 settings.Id = Guid.NewGuid().ToString("N"); 984 } 985 986 var textField = new TextField { 987 Name = settings.Name, 988 Id = settings.Id, 989 Label = settings.Label, 990 HelpText = settings.HelpText, 991 Value = settings.Value, 992 Disabled = settings.Disabled, 993 Required = settings.Required, 994 ErrorMessage = settings.ErrorMessage, 995 CssClass = settings.CssClass, 996 WrapperCssClass = settings.WrapperCssClass, 997 OnChange = settings.OnChange, 998 OnClick = settings.OnClick, 999 Link = settings.Link, 1000 ExtraAttributes = settings.ExtraAttributes, 1001 // 1002 Placeholder = settings.Placeholder 1003 }; 1004 1005 @Render(textField) 1006 1007 List<string> jsAttributes = new List<string>(); 1008 1009 jsAttributes.Add("mode: '" + Enum.GetName(typeof(DateTimeFieldMode), settings.Mode).ToLower() + "'"); 1010 1011 if (!string.IsNullOrEmpty(settings.DateFormat)) 1012 { 1013 jsAttributes.Add("dateFormat: '" + settings.DateFormat + "'"); 1014 } 1015 if (!string.IsNullOrEmpty(settings.MinDate)) 1016 { 1017 jsAttributes.Add("minDate: '" + settings.MinDate + "'"); 1018 } 1019 if (!string.IsNullOrEmpty(settings.MaxDate)) 1020 { 1021 jsAttributes.Add("maxDate: '" + settings.MaxDate + "'"); 1022 } 1023 if (settings.IsInline) 1024 { 1025 jsAttributes.Add("inline: " + Converter.ToString(settings.IsInline).ToLower()); 1026 } 1027 if (settings.EnableTime) 1028 { 1029 jsAttributes.Add("enableTime: " + Converter.ToString(settings.EnableTime).ToLower()); 1030 } 1031 if (settings.EnableWeekNumbers) 1032 { 1033 jsAttributes.Add("weekNumbers: " + Converter.ToString(settings.EnableWeekNumbers).ToLower()); 1034 } 1035 1036 jsAttributes.AddRange(settings.GetFlatPickrOptions().Select(x => x.Key + ": " + x.Value)); 1037 1038 <script> 1039 document.addEventListener("DOMContentLoaded", function () { 1040 flatpickr("#@textField.Id", { 1041 @string.Join(",", jsAttributes) 1042 }); 1043 }); 1044 </script> 1045 } 1046 @using System.Reflection 1047 @using Dynamicweb.Rapido.Blocks.Components.General 1048 @using Dynamicweb.Rapido.Blocks.Components 1049 1050 @* Component *@ 1051 1052 @helper RenderTextField(TextField settings) 1053 { 1054 var attributes = new Dictionary<string, string>(); 1055 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1056 { 1057 settings.Id = Guid.NewGuid().ToString("N"); 1058 } 1059 1060 /*base settings*/ 1061 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1062 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1063 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1064 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1065 if (settings.Required) { attributes.Add("required", "true"); } 1066 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1067 /*end*/ 1068 1069 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 1070 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 1071 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 1072 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 1073 if (settings.MaxLength != 0) { attributes.Add("maxlength", settings.MaxLength.ToString()); } 1074 if (!string.IsNullOrEmpty(settings.Placeholder)) { attributes.Add("placeholder", settings.Placeholder); } 1075 attributes.Add("type", Enum.GetName(typeof(TextFieldType), settings.Type).ToLower()); 1076 if (settings.Type == TextFieldType.Password) { attributes.Add("autocomplete", "off"); }; 1077 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1078 1079 settings.CssClass = "u-full-width " + settings.CssClass; 1080 1081 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1082 1083 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1084 1085 string noMargin = "u-no-margin"; 1086 if (!settings.ReadOnly) { 1087 noMargin = ""; 1088 } 1089 1090 <div class="form__field-group u-full-width @noMargin @settings.WrapperCssClass dw-mod"> 1091 @if (!string.IsNullOrEmpty(settings.Label) || settings.Link != null ) 1092 { 1093 <div class="u-full-width"> 1094 @if (!string.IsNullOrEmpty(settings.Label)) { <label for="@settings.Id" class="u-pull--left">@settings.Label</label> } 1095 @if (settings.Link != null) { 1096 settings.Link.ButtonLayout = ButtonLayout.LinkClean; 1097 1098 <div class="u-pull--right"> 1099 @Render(settings.Link) 1100 </div> 1101 } 1102 </div> 1103 1104 } 1105 1106 @if (!string.IsNullOrEmpty(settings.HelpText)) 1107 { 1108 <small class="form__help-text">@settings.HelpText</small> 1109 } 1110 1111 @if (settings.ActionButton != null) 1112 { 1113 settings.ActionButton.CssClass += " btn--condensed u-no-margin"; 1114 <div class="form__field-combi u-no-margin dw-mod"> 1115 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1116 @Render(settings.ActionButton) 1117 </div> 1118 } 1119 else 1120 { 1121 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1122 } 1123 1124 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1125 </div> 1126 } 1127 @using System.Reflection 1128 @using Dynamicweb.Rapido.Blocks.Components.General 1129 @using Dynamicweb.Rapido.Blocks.Components 1130 1131 @* Component *@ 1132 1133 @helper RenderNumberField(NumberField settings) 1134 { 1135 var attributes = new Dictionary<string, string>(); 1136 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1137 { 1138 settings.Id = Guid.NewGuid().ToString("N"); 1139 } 1140 1141 /*base settings*/ 1142 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1143 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1144 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1145 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1146 if (settings.Required) { attributes.Add("required", "true"); } 1147 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1148 /*end*/ 1149 1150 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 1151 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 1152 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 1153 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 1154 if (settings.Max != null) { attributes.Add("max", settings.Max.ToString()); } 1155 if (settings.Min != null) { attributes.Add("min", settings.Min.ToString()); } 1156 if (settings.Step != 0) { attributes.Add("step", settings.Step.ToString()); } 1157 if (settings.Value != null && !string.IsNullOrEmpty(settings.Value.ToString())) { attributes.Add("value", settings.Value.ToString()); } 1158 attributes.Add("type", "number"); 1159 1160 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1161 1162 <div class="form__field-group u-full-width @settings.WrapperCssClass dw-mod"> 1163 @if (!string.IsNullOrEmpty(settings.Label) || settings.Link != null ) 1164 { 1165 <div class="u-full-width"> 1166 @if (!string.IsNullOrEmpty(settings.Label)) { <label for="@settings.Id" class="u-pull--left">@settings.Label</label> } 1167 @if (settings.Link != null) { 1168 <div class="u-pull--right"> 1169 @{ settings.Link.ButtonLayout = ButtonLayout.LinkClean; } 1170 @Render(settings.Link) 1171 </div> 1172 } 1173 </div> 1174 1175 } 1176 1177 @if (!string.IsNullOrEmpty(settings.HelpText)) 1178 { 1179 <small class="form__help-text">@settings.HelpText</small> 1180 } 1181 1182 @if (settings.ActionButton != null) 1183 { 1184 settings.ActionButton.CssClass += " btn--condensed u-no-margin"; 1185 <div class="form__field-combi u-no-margin dw-mod"> 1186 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1187 @Render(settings.ActionButton) 1188 </div> 1189 } 1190 else 1191 { 1192 <div class="form__field-combi u-no-margin dw-mod"> 1193 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1194 </div> 1195 } 1196 1197 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1198 </div> 1199 } 1200 @using System.Reflection 1201 @using Dynamicweb.Rapido.Blocks.Components.General 1202 @using Dynamicweb.Rapido.Blocks.Components 1203 1204 1205 @* Component *@ 1206 1207 @helper RenderTextareaField(TextareaField settings) 1208 { 1209 Dictionary<string, string> attributes = new Dictionary<string, string>(); 1210 string id = settings.Id; 1211 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(id)) 1212 { 1213 id = Guid.NewGuid().ToString("N"); 1214 } 1215 1216 if (!string.IsNullOrEmpty(id)) { attributes.Add("id", id); } 1217 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1218 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 1219 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 1220 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 1221 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1222 if (!string.IsNullOrEmpty(settings.Placeholder)) { attributes.Add("placeholder", settings.Placeholder); } 1223 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1224 if (settings.Required) { attributes.Add("required", "true"); } 1225 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 1226 if (settings.MaxLength != 0) { attributes.Add("maxlength", settings.MaxLength.ToString()); } 1227 if (settings.Rows != 0) { attributes.Add("rows", settings.Rows.ToString()); } 1228 attributes.Add("name", settings.Name); 1229 1230 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1231 1232 <div class="form__field-group @settings.WrapperCssClass dw-mod"> 1233 @if (!string.IsNullOrEmpty(settings.Label) || settings.Link != null ) 1234 { 1235 <div class="u-full-width"> 1236 @if (!string.IsNullOrEmpty(settings.Label)) { <label for="@settings.Id" class="u-pull--left">@settings.Label</label> } 1237 @if (settings.Link != null) { 1238 <div class="u-pull--right"> 1239 @{ settings.Link.ButtonLayout = ButtonLayout.LinkClean; } 1240 @Render(settings.Link) 1241 </div> 1242 } 1243 </div> 1244 } 1245 1246 @if (!string.IsNullOrEmpty(settings.HelpText)) 1247 { 1248 <small class="form__help-text">@settings.HelpText</small> 1249 } 1250 1251 <textarea class="u-full-width @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@settings.Value</textarea> 1252 1253 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1254 </div> 1255 } 1256 @using System.Reflection 1257 @using Dynamicweb.Rapido.Blocks.Components.General 1258 @using Dynamicweb.Rapido.Blocks.Components 1259 1260 1261 @* Component *@ 1262 1263 @helper RenderHiddenField(HiddenField settings) { 1264 var attributes = new Dictionary<string, string>(); 1265 attributes.Add("type", "hidden"); 1266 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1267 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1268 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1269 1270 <input @ComponentMethods.AddAttributes(attributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)/> 1271 } 1272 @using System.Reflection 1273 @using Dynamicweb.Rapido.Blocks.Components.General 1274 @using Dynamicweb.Rapido.Blocks.Components 1275 1276 @* Component *@ 1277 1278 @helper RenderCheckboxField(CheckboxField settings) 1279 { 1280 var attributes = new Dictionary<string, string>(); 1281 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1282 { 1283 settings.Id = Guid.NewGuid().ToString("N"); 1284 } 1285 1286 /*base settings*/ 1287 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1288 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1289 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1290 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1291 if (settings.Required) { attributes.Add("required", "true"); } 1292 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1293 /*end*/ 1294 1295 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1296 1297 attributes.Add("type", "checkbox"); 1298 if (settings.Checked) { attributes.Add("checked", "true"); } 1299 settings.CssClass = "form__control " + settings.CssClass; 1300 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1301 1302 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1303 1304 <div class="form__field-group @settings.WrapperCssClass dw-mod"> 1305 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1306 @if (!string.IsNullOrEmpty(settings.Label)) 1307 { 1308 <label for="@settings.Id" class="dw-mod">@settings.Label</label> 1309 } 1310 1311 @if (settings.Link != null) { 1312 <span> 1313 @{ settings.Link.ButtonLayout = ButtonLayout.LinkClean; } 1314 @Render(settings.Link) 1315 </span> 1316 } 1317 1318 @if (!string.IsNullOrEmpty(settings.HelpText)) 1319 { 1320 <small class="form__help-text checkbox-help dw-mod">@settings.HelpText</small> 1321 } 1322 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1323 </div> 1324 } 1325 @using System.Reflection 1326 @using Dynamicweb.Rapido.Blocks.Components.General 1327 @using Dynamicweb.Rapido.Blocks.Components 1328 1329 1330 @* Component *@ 1331 1332 @helper RenderCheckboxListField(CheckboxListField settings) 1333 { 1334 <div class="form__field-group @settings.WrapperCssClass u-margin-bottom dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1335 @if (!string.IsNullOrEmpty(settings.Label) || settings.Link != null ) 1336 { 1337 <div class="u-full-width"> 1338 @if (!string.IsNullOrEmpty(settings.Label)) { <label for="@settings.Id" class="u-pull--left">@settings.Label</label> } 1339 @if (settings.Link != null) { 1340 <div class="u-pull--right"> 1341 @{ settings.Link.ButtonLayout = ButtonLayout.LinkClean; } 1342 @Render(settings.Link) 1343 </div> 1344 } 1345 </div> 1346 1347 } 1348 1349 <div class="u-pull--left"> 1350 @if (!string.IsNullOrEmpty(settings.HelpText)) 1351 { 1352 <small class="form__help-text">@settings.HelpText</small> 1353 } 1354 1355 @foreach (var item in settings.Options) 1356 { 1357 if (settings.Required) 1358 { 1359 item.Required = true; 1360 } 1361 if (settings.Disabled) 1362 { 1363 item.Disabled = true; 1364 } 1365 if (!string.IsNullOrEmpty(settings.Name)) 1366 { 1367 item.Name = settings.Name; 1368 } 1369 if (!string.IsNullOrEmpty(settings.CssClass)) 1370 { 1371 item.CssClass += settings.CssClass; 1372 } 1373 1374 /* value is not supported */ 1375 1376 if (!string.IsNullOrEmpty(settings.OnClick)) 1377 { 1378 item.OnClick += settings.OnClick; 1379 } 1380 if (!string.IsNullOrEmpty(settings.OnChange)) 1381 { 1382 item.OnChange += settings.OnChange; 1383 } 1384 @Render(item) 1385 } 1386 1387 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1388 </div> 1389 1390 </div> 1391 } 1392 @using Dynamicweb.Rapido.Blocks.Components.General 1393 1394 @* Component *@ 1395 1396 @helper RenderSearch(Search settings) 1397 { 1398 var searchValue = HttpContext.Current.Request.QueryString.Get(settings.SearchParameter) ?? ""; 1399 var groupValue = HttpContext.Current.Request.QueryString.Get(settings.GroupsParameter) ?? ""; 1400 1401 if (string.IsNullOrEmpty(settings.Id)) 1402 { 1403 settings.Id = Guid.NewGuid().ToString("N"); 1404 } 1405 1406 var resultAttributes = new Dictionary<string, string>(); 1407 1408 if (settings.PageSize != 0) 1409 { 1410 resultAttributes.Add("data-page-size", settings.PageSize.ToString()); 1411 } 1412 if (!string.IsNullOrEmpty(settings.GroupItemsFeedUrl)) 1413 { 1414 resultAttributes.Add("data-groups-feed-url", settings.GroupItemsFeedUrl); 1415 if (!string.IsNullOrEmpty(groupValue)) 1416 { 1417 resultAttributes.Add("data-selected-group", groupValue); 1418 } 1419 if (!string.IsNullOrEmpty(settings.GroupsParameter)) 1420 { 1421 resultAttributes.Add("data-groups-parameter", settings.GroupsParameter); 1422 } 1423 } 1424 resultAttributes.Add("data-force-init", "true"); 1425 if (settings.GoToFirstSearchResultOnEnter) 1426 { 1427 resultAttributes.Add("data-go-to-first-search-result-on-enter", settings.GoToFirstSearchResultOnEnter.ToString().ToLower()); 1428 } 1429 if (!string.IsNullOrEmpty(settings.SearchParameter)) 1430 { 1431 resultAttributes.Add("data-search-parameter", settings.SearchParameter); 1432 } 1433 resultAttributes.Add("data-search-feed-url", settings.SearchData.SearchFeedUrl); 1434 resultAttributes.Add("data-results-template-id", settings.SearchData.ResultsTemplateId); 1435 1436 if (settings.SecondSearchData != null) 1437 { 1438 resultAttributes.Add("data-second-search-feed-url", settings.SecondSearchData.SearchFeedUrl); 1439 resultAttributes.Add("data-second-results-template-id", settings.SecondSearchData.ResultsTemplateId); 1440 } 1441 if (!string.IsNullOrEmpty(settings.ResultsPageUrl)) 1442 { 1443 resultAttributes.Add("data-results-page-url", settings.ResultsPageUrl); 1444 } 1445 1446 resultAttributes = resultAttributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1447 1448 string searchFieldCss = (settings.SearchButton == null) ? "search--with-icon" : ""; 1449 1450 <div class="search @settings.CssClass @searchFieldCss js-search-data-source dw-mod" id="@settings.Id" @ComponentMethods.AddAttributes(resultAttributes)> 1451 @if (!string.IsNullOrEmpty(settings.GroupItemsFeedUrl)) 1452 { 1453 <button type="button" class="search__groups-btn dw-mod js-search-groups-btn">@Translate("All")</button> 1454 <ul class="dropdown dropdown--absolute-position dw-mod search__groups-results js-search-groups-list"></ul> 1455 } 1456 1457 <input type="text" class="search__field dw-mod js-search-field" placeholder="@settings.Placeholder" value="@searchValue"> 1458 1459 <div class="dropdown dropdown--absolute-position search__results dw-mod js-search-results @(settings.SecondSearchData != null ? "search__results--combined" : "")"> 1460 @if (settings.SecondSearchData != null) 1461 { 1462 <div class="search__column search__column--products dw-mod"> 1463 <div class="search__column-header dw-mod">@Translate("Products")</div> 1464 <ul class="search__results-list dw-mod js-search-results-list" id="@(settings.Id)_ResultsList"></ul> 1465 @if (!string.IsNullOrEmpty(settings.SearchData.ResultsPageUrl)) 1466 { 1467 @Render(new Link { 1468 Title = Translate("View all"), 1469 CssClass = "js-view-all-button u-margin", 1470 Href = settings.SearchData.ResultsPageUrl 1471 }); 1472 } 1473 </div> 1474 <div class="search__column search__column--pages dw-mod"> 1475 <div class="search__column-header">@Translate("Pages")</div> 1476 <ul class="search__results-list dw-mod js-search-results-second-list" id="@(settings.Id)_SecondResultsList"></ul> 1477 @if (!string.IsNullOrEmpty(settings.SecondSearchData.ResultsPageUrl)) 1478 { 1479 @Render(new Link 1480 { 1481 Title = Translate("View all"), 1482 CssClass = "js-view-all-button u-margin", 1483 Href = settings.SecondSearchData.ResultsPageUrl 1484 }); 1485 } 1486 </div> 1487 } 1488 else 1489 { 1490 <div class="search__column search__column--only dw-mod"> 1491 <ul class="search__results-list dw-mod js-search-results-list" id="@(settings.Id)_ResultsList"></ul> 1492 @if (!string.IsNullOrEmpty(settings.SearchData.ResultsPageUrl)) 1493 { 1494 @Render(new Link { 1495 Title = Translate("View all"), 1496 CssClass = "js-view-all-button u-margin", 1497 Href = settings.SearchData.ResultsPageUrl 1498 }); 1499 } 1500 </div> 1501 } 1502 </div> 1503 1504 @if (settings.SearchButton != null) 1505 { 1506 settings.SearchButton.CssClass += " search__btn js-search-btn"; 1507 if (settings.RenderDefaultSearchIcon) 1508 { 1509 settings.SearchButton.Icon = new Icon { Name = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("SearchIcon").SelectedValue }; 1510 } 1511 @Render(settings.SearchButton); 1512 } 1513 </div> 1514 } 1515 @using System.Reflection 1516 @using Dynamicweb.Rapido.Blocks.Components.General 1517 @using Dynamicweb.Rapido.Blocks.Components 1518 1519 1520 @* Component *@ 1521 1522 @helper RenderSelectField(SelectField settings) 1523 { 1524 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1525 { 1526 settings.Id = Guid.NewGuid().ToString("N"); 1527 } 1528 1529 <div class="form__field-group u-full-width @settings.WrapperCssClass dw-mod"> 1530 @if (!string.IsNullOrEmpty(settings.Label) || settings.Link != null ) 1531 { 1532 <div class="u-full-width"> 1533 @if (!string.IsNullOrEmpty(settings.Label)) { <label for="@settings.Id" class="u-pull--left">@settings.Label</label> } 1534 @if (settings.Link != null) { 1535 <div class="u-pull--right"> 1536 @{ settings.Link.ButtonLayout = ButtonLayout.LinkClean; } 1537 @Render(settings.Link) 1538 </div> 1539 } 1540 </div> 1541 } 1542 1543 @if (!string.IsNullOrEmpty(settings.HelpText)) 1544 { 1545 <small class="form__help-text">@settings.HelpText</small> 1546 } 1547 1548 @if (settings.ActionButton != null) 1549 { 1550 settings.ActionButton.CssClass += " btn--condensed u-no-margin"; 1551 <div class="form__field-combi u-no-margin dw-mod"> 1552 @RenderSelectBase(settings) 1553 @Render(settings.ActionButton) 1554 </div> 1555 } 1556 else 1557 { 1558 @RenderSelectBase(settings) 1559 } 1560 1561 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1562 </div> 1563 } 1564 1565 @helper RenderSelectBase(SelectField settings) 1566 { 1567 var attributes = new Dictionary<string, string>(); 1568 1569 /*base settings*/ 1570 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1571 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1572 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1573 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1574 if (settings.Required) { attributes.Add("required", "true"); } 1575 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1576 /*end*/ 1577 1578 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1579 1580 <select @ComponentMethods.AddAttributes(resultAttributes) class="u-full-width @settings.CssClass dw-mod"> 1581 @if (settings.Default != null) 1582 { 1583 @Render(settings.Default) 1584 } 1585 1586 @foreach (var item in settings.Options) 1587 { 1588 if (settings.Value != null) { 1589 item.Checked = item.Value == settings.Value; 1590 } 1591 @Render(item) 1592 } 1593 </select> 1594 } 1595 @using System.Reflection 1596 @using Dynamicweb.Rapido.Blocks.Components.General 1597 @using Dynamicweb.Rapido.Blocks.Components 1598 1599 @* Component *@ 1600 1601 @helper RenderRadioButtonField(RadioButtonField settings) 1602 { 1603 var attributes = new Dictionary<string, string>(); 1604 if (!string.IsNullOrEmpty(settings.Label) && string.IsNullOrEmpty(settings.Id)) 1605 { 1606 settings.Id = Guid.NewGuid().ToString("N"); 1607 } 1608 1609 /*base settings*/ 1610 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1611 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 1612 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 1613 if (settings.Disabled) { attributes.Add("disabled", "true"); } 1614 if (settings.Required) { attributes.Add("required", "true"); } 1615 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 1616 /*end*/ 1617 1618 attributes.Add("type", "radio"); 1619 if (settings.Checked) { attributes.Add("checked", "true"); } 1620 settings.CssClass = "form__control " + settings.CssClass; 1621 if (settings.Value != null) { attributes.Add("value", settings.Value); } 1622 1623 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 1624 1625 <div class="form__field-group @settings.WrapperCssClass dw-mod"> 1626 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 1627 @if (!string.IsNullOrEmpty(settings.Label)) 1628 { 1629 <label for="@settings.Id" class="dw-mod">@settings.Label</label> 1630 } 1631 @if (!string.IsNullOrEmpty(settings.HelpText)) 1632 { 1633 <small class="form__help-text">@settings.HelpText</small> 1634 } 1635 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1636 </div> 1637 } 1638 @using System.Reflection 1639 @using Dynamicweb.Rapido.Blocks.Components.General 1640 @using Dynamicweb.Rapido.Blocks.Components 1641 1642 1643 @* Component *@ 1644 1645 @helper RenderRadioButtonListField(RadioButtonListField settings) 1646 { 1647 if (settings.Required && !String.IsNullOrEmpty(settings.Label)) { settings.Label += " <span class=\"required dw-mod\">*</span>"; } 1648 1649 <div class="form__field-group @settings.WrapperCssClass u-margin-bottom dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1650 @if (!string.IsNullOrEmpty(settings.Label)) 1651 { 1652 <label>@settings.Label</label> 1653 } 1654 @if (!string.IsNullOrEmpty(settings.HelpText)) 1655 { 1656 <small class="form__help-text">@settings.HelpText</small> 1657 } 1658 1659 @foreach (var item in settings.Options) 1660 { 1661 if (settings.Required) 1662 { 1663 item.Required = true; 1664 } 1665 if (settings.Disabled) 1666 { 1667 item.Disabled = true; 1668 } 1669 if (!string.IsNullOrEmpty(settings.Name)) 1670 { 1671 item.Name = settings.Name; 1672 } 1673 if (settings.Value != null && settings.Value == item.Value) 1674 { 1675 item.Checked = true; 1676 } 1677 if (!string.IsNullOrEmpty(settings.OnClick)) 1678 { 1679 item.OnClick += settings.OnClick; 1680 } 1681 if (!string.IsNullOrEmpty(settings.OnChange)) 1682 { 1683 item.OnChange += settings.OnChange; 1684 } 1685 if (!string.IsNullOrEmpty(settings.CssClass)) 1686 { 1687 item.CssClass += settings.CssClass; 1688 } 1689 @Render(item) 1690 } 1691 1692 @Render(new NotificationMessage { Message = settings.ErrorMessage }) 1693 </div> 1694 } 1695 @using System.Reflection 1696 @using Dynamicweb.Rapido.Blocks.Components.General 1697 @using Dynamicweb.Rapido.Blocks.Components 1698 1699 1700 @* Component *@ 1701 1702 @helper RenderNotificationMessage(NotificationMessage settings) 1703 { 1704 if (!string.IsNullOrEmpty(settings.Message)) 1705 { 1706 var attributes = new Dictionary<string, string>(); 1707 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 1708 1709 string messageTypeClass = Enum.GetName(typeof(NotificationMessageType), settings.MessageType).ToLower(); 1710 string messageLayoutClass = Enum.GetName(typeof(NotificationMessageLayout), settings.MessageLayout).ToLower(); 1711 string minHeightClass = settings.Icon != null ? "u-min-h70px" : ""; 1712 1713 <div class="notification-message-@messageTypeClass notification-message-@messageLayoutClass @messageLayoutClass @minHeightClass @settings.CssClass u-full-width dw-mod" @ComponentMethods.AddAttributes(attributes)> 1714 @if (settings.Icon != null) { 1715 settings.Icon.Label = !string.IsNullOrEmpty(settings.Icon.Label) ? settings.Message + settings.Icon.Label : settings.Message; 1716 @Render(settings.Icon) 1717 } else { 1718 @settings.Message 1719 } 1720 </div> 1721 } 1722 } 1723 @using Dynamicweb.Rapido.Blocks.Components.General 1724 1725 1726 @* Component *@ 1727 1728 @helper RenderHandlebarsRoot(HandlebarsRoot settings) { 1729 string preRender = !String.IsNullOrEmpty(settings.PreRenderScriptTemplate) ? "data-pre-render-template=\"" + settings.PreRenderScriptTemplate + "\"" : ""; 1730 1731 <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> 1732 @if (settings.SubBlocks != null) { 1733 @RenderBlockList(settings.SubBlocks) 1734 } 1735 </div> 1736 } 1737 @using System.Reflection 1738 @using Dynamicweb.Rapido.Blocks.Components.General 1739 @using Dynamicweb.Rapido.Blocks.Components 1740 @using System.Text.RegularExpressions 1741 1742 1743 @* Component *@ 1744 1745 @helper RenderSticker(Sticker settings) { 1746 if (!String.IsNullOrEmpty(settings.Title)) { 1747 string size = settings.Size.ToString() != "None" ? "" + "stickers-container__tag--" + settings.Size.ToString().ToLower() : ""; 1748 string style = settings.Style.ToString() != "None" ? "" + "stickers-container__tag--" + settings.Style.ToString().ToLower() : ""; 1749 1750 Dictionary<String, String> optionalAttributes = new Dictionary<string, string>(); 1751 if (!String.IsNullOrEmpty(settings.Color) || !String.IsNullOrEmpty(settings.BackgroundColor)) { 1752 string styleTag = !String.IsNullOrEmpty(settings.Color) ? "color: " + settings.Color + "; " : ""; 1753 styleTag += !String.IsNullOrEmpty(settings.BackgroundColor) ? "background-color: " + settings.BackgroundColor + "; " : ""; 1754 optionalAttributes.Add("style", styleTag); 1755 } 1756 1757 <div class="stickers-container__tag @size @style @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(optionalAttributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)>@settings.Title</div> 1758 } 1759 } 1760 1761 @using System.Reflection 1762 @using Dynamicweb.Rapido.Blocks.Components.General 1763 @using Dynamicweb.Rapido.Blocks.Components 1764 1765 1766 @* Component *@ 1767 1768 @helper RenderStickersCollection(StickersCollection settings) 1769 { 1770 if (settings.Stickers.Count > 0) 1771 { 1772 string position = "stickers-container--" + Regex.Replace(settings.Position.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower(); 1773 1774 <div class="stickers-container @position @settings.CssClass dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1775 @foreach (Sticker sticker in settings.Stickers) 1776 { 1777 @Render(sticker) 1778 } 1779 </div> 1780 } 1781 } 1782 1783 @using Dynamicweb.Rapido.Blocks.Components.General 1784 1785 1786 @* Component *@ 1787 1788 @helper RenderForm(Form settings) { 1789 if (settings != null) 1790 { 1791 Dictionary<string, string> optionalAttributes = new Dictionary<string, string>(); 1792 if (!string.IsNullOrEmpty(settings.Action)) { optionalAttributes.Add("action", settings.Action); }; 1793 if (!string.IsNullOrEmpty(settings.Name)) { optionalAttributes.Add("name", settings.Name); }; 1794 if (!string.IsNullOrEmpty(settings.OnSubmit)) { optionalAttributes.Add("onsubmit", settings.OnSubmit); }; 1795 var enctypes = new Dictionary<string, string> 1796 { 1797 { "multipart", "multipart/form-data" }, 1798 { "text", "text/plain" }, 1799 { "application", "application/x-www-form-urlencoded" } 1800 }; 1801 if (settings.Enctype != FormEnctype.none) { optionalAttributes.Add("enctype", enctypes[Enum.GetName(typeof(FormEnctype), settings.Enctype).ToLower()]); }; 1802 optionalAttributes.Add("method", settings.Method.ToString()); 1803 1804 if (!string.IsNullOrEmpty(settings.FormStartMarkup)) 1805 { 1806 @settings.FormStartMarkup 1807 } 1808 else 1809 { 1810 @:<form class="@settings.CssClass u-no-margin dw-mod" @ComponentMethods.AddAttributes(optionalAttributes) @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 1811 } 1812 1813 foreach (var field in settings.GetFields()) 1814 { 1815 @Render(field) 1816 } 1817 1818 @:</form> 1819 } 1820 } 1821 @using System.Reflection 1822 @using Dynamicweb.Rapido.Blocks.Components.General 1823 @using Dynamicweb.Rapido.Blocks.Components 1824 1825 1826 @* Component *@ 1827 1828 @helper RenderText(Text settings) 1829 { 1830 @settings.Content 1831 } 1832 @using System.Reflection 1833 @using Dynamicweb.Rapido.Blocks.Components.General 1834 @using Dynamicweb.Rapido.Blocks.Components 1835 1836 1837 @* Component *@ 1838 1839 @helper RenderContentModule(ContentModule settings) { 1840 if (!string.IsNullOrEmpty(settings.Content)) 1841 { 1842 @settings.Content 1843 } 1844 } 1845 @using System.Reflection 1846 @using Dynamicweb.Rapido.Blocks.Components.General 1847 @using Dynamicweb.Rapido.Blocks.Components 1848 1849 1850 @* Component *@ 1851 1852 @helper RenderModal(Modal settings) { 1853 if (settings != null) 1854 { 1855 string modalId = !string.IsNullOrEmpty(settings.Id) ? settings.Id : Guid.NewGuid().ToString("N"); 1856 1857 string onchange = !string.IsNullOrEmpty(settings.OnClose) ? "onchange=\"if(!this.checked){" + settings.OnClose + "}\"" : ""; 1858 1859 <input type="checkbox" id="@(modalId)ModalTrigger" class="modal-trigger" @onchange /> 1860 1861 <div class="modal-container"> 1862 @if (!settings.DisableDarkOverlay) 1863 { 1864 <label for="@(modalId)ModalTrigger" id="@(modalId)ModalOverlay" class="modal-overlay"></label> 1865 } 1866 <div class="modal modal--@settings.Width.ToString().ToLower() modal-height--@settings.Height.ToString().ToLower()" id="@(modalId)Modal"> 1867 @if (settings.Heading != null) 1868 { 1869 if (!string.IsNullOrEmpty(settings.Heading.Title)) 1870 { 1871 <div class="modal__header"> 1872 @Render(settings.Heading) 1873 </div> 1874 } 1875 } 1876 <div class="modal__body @(settings.Width.ToString().ToLower() == "full" ? "modal__body--full" : "")"> 1877 @if (!string.IsNullOrEmpty(settings.BodyText)) 1878 { 1879 @settings.BodyText 1880 } 1881 @if (settings.BodyTemplate != null) 1882 { 1883 @settings.BodyTemplate 1884 } 1885 @{ 1886 var actions = settings.GetActions(); 1887 } 1888 </div> 1889 @if (actions.Length > 0) 1890 { 1891 <div class="modal__footer"> 1892 @foreach (var action in actions) 1893 { 1894 if (Pageview.Device.ToString() != "Mobile") { 1895 action.CssClass += " u-no-margin"; 1896 } else { 1897 action.CssClass += " u-full-width u-margin-bottom"; 1898 } 1899 1900 @Render(action) 1901 } 1902 </div> 1903 } 1904 <label class="modal__close-btn" for="@(modalId)ModalTrigger"></label> 1905 </div> 1906 </div> 1907 } 1908 } 1909 @using Dynamicweb.Rapido.Blocks.Components.General 1910 1911 @* Component *@ 1912 1913 @helper RenderMediaListItem(MediaListItem settings) 1914 { 1915 <div class="media-list-item @settings.CssClass dw-mod" @(!string.IsNullOrEmpty(settings.Id) ? "id=\"" + settings.Id + "\"" : "")> 1916 @if (!string.IsNullOrEmpty(settings.Label)) 1917 { 1918 if (!string.IsNullOrEmpty(settings.Link)) 1919 { 1920 @Render(new Link 1921 { 1922 Href = settings.Link, 1923 CssClass = "media-list-item__sticker dw-mod", 1924 ButtonLayout = ButtonLayout.None, 1925 Title = settings.Label, 1926 OnClick = !string.IsNullOrEmpty(settings.OnClick) ? settings.OnClick : "" 1927 }) 1928 } 1929 else if (!string.IsNullOrEmpty(settings.OnClick)) 1930 { 1931 <span class="media-list-item__sticker dw-mod" onclick="@(settings.OnClick)"> 1932 <span class="u-uppercase">@settings.Label</span> 1933 </span> 1934 } 1935 else 1936 { 1937 <span class="media-list-item__sticker media-list-item__sticker--no-link dw-mod"> 1938 <span class="u-uppercase">@settings.Label</span> 1939 </span> 1940 } 1941 } 1942 <div class="media-list-item__wrap"> 1943 <div class="media-list-item__info dw-mod"> 1944 <div class="media-list-item__header dw-mod"> 1945 @if (!string.IsNullOrEmpty(settings.Title)) 1946 { 1947 if (!string.IsNullOrEmpty(settings.Link)) 1948 { 1949 @Render(new Link 1950 { 1951 Href = settings.Link, 1952 CssClass = "media-list-item__name dw-mod", 1953 ButtonLayout = ButtonLayout.None, 1954 Title = settings.Title, 1955 OnClick = !string.IsNullOrEmpty(settings.OnClick) ? settings.OnClick : "" 1956 }) 1957 } 1958 else if (!string.IsNullOrEmpty(settings.OnClick)) 1959 { 1960 <span class="media-list-item__name dw-mod" onclick="@(settings.OnClick)">@settings.Title</span> 1961 } 1962 else 1963 { 1964 <span class="media-list-item__name media-list-item__name--no-link dw-mod">@settings.Title</span> 1965 } 1966 } 1967 1968 @if (!string.IsNullOrEmpty(settings.Status)) 1969 { 1970 <div class="media-list-item__state dw-mod">@settings.Status</div> 1971 } 1972 </div> 1973 @{ 1974 settings.InfoTable.CssClass += " media-list-item__parameters-table"; 1975 } 1976 1977 @Render(settings.InfoTable) 1978 </div> 1979 <div class="media-list-item__actions dw-mod"> 1980 <div class="media-list-item__actions-list dw-mod"> 1981 @{ 1982 var actions = settings.GetActions(); 1983 1984 foreach (ButtonBase action in actions) 1985 { 1986 action.ButtonLayout = ButtonLayout.None; 1987 action.CssClass += " media-list-item__action link"; 1988 1989 @Render(action) 1990 } 1991 } 1992 </div> 1993 1994 @if (settings.SelectButton != null && !string.IsNullOrEmpty(settings.SelectButton.Title)) 1995 { 1996 settings.SelectButton.CssClass += " u-no-margin"; 1997 1998 <div class="media-list-item__action-button"> 1999 @Render(settings.SelectButton) 2000 </div> 2001 } 2002 </div> 2003 </div> 2004 </div> 2005 } 2006 @using Dynamicweb.Rapido.Blocks.Components.General 2007 @using Dynamicweb.Rapido.Blocks.Components 2008 2009 @helper RenderTable(Table settings) 2010 { 2011 Dictionary<string, string> attributes = new Dictionary<string, string>(); 2012 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2013 2014 var enumToClasses = new Dictionary<TableDesign, string> 2015 { 2016 { TableDesign.Clean, "table--clean" }, 2017 { TableDesign.Bordered, "table--bordered" }, 2018 { TableDesign.Striped, "table--striped" }, 2019 { TableDesign.Hover, "table--hover" }, 2020 { TableDesign.Compact, "table--compact" }, 2021 { TableDesign.Condensed, "table--condensed" }, 2022 { TableDesign.NoTopBorder, "table--no-top-border" } 2023 }; 2024 string tableDesignClass = ""; 2025 if (settings.Design != TableDesign.None) 2026 { 2027 tableDesignClass = enumToClasses[settings.Design]; 2028 } 2029 2030 if (!string.IsNullOrEmpty(settings.CssClass) || settings.Design != TableDesign.None) { attributes.Add("class", "table " + tableDesignClass + " " + settings.CssClass + " dw-mod"); } 2031 2032 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.Last().Value); 2033 2034 <table @ComponentMethods.AddAttributes(resultAttributes)> 2035 @if (settings.Header != null) 2036 { 2037 <thead> 2038 @Render(settings.Header) 2039 </thead> 2040 } 2041 <tbody> 2042 @foreach (var row in settings.Rows) 2043 { 2044 @Render(row) 2045 } 2046 </tbody> 2047 @if (settings.Footer != null) 2048 { 2049 <tfoot> 2050 @Render(settings.Footer) 2051 </tfoot> 2052 } 2053 </table> 2054 } 2055 @using Dynamicweb.Rapido.Blocks.Components.General 2056 @using Dynamicweb.Rapido.Blocks.Components 2057 2058 @helper RenderTableRow(TableRow settings) 2059 { 2060 Dictionary<string, string> attributes = new Dictionary<string, string>(); 2061 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2062 2063 var enumToClasses = new Dictionary<TableRowDesign, string> 2064 { 2065 { TableRowDesign.NoBorder, "table__row--no-border" }, 2066 { TableRowDesign.Border, "table__row--border" }, 2067 { TableRowDesign.TopBorder, "table__row--top-line" }, 2068 { TableRowDesign.BottomBorder, "table__row--bottom-line" }, 2069 { TableRowDesign.Solid, "table__row--solid" } 2070 }; 2071 2072 string tableRowDesignClass = ""; 2073 if (settings.Design != TableRowDesign.None) 2074 { 2075 tableRowDesignClass = enumToClasses[settings.Design]; 2076 } 2077 2078 if (!string.IsNullOrEmpty(settings.CssClass) || settings.Design != TableRowDesign.None) { attributes.Add("class", "table__row " + tableRowDesignClass + " " + settings.CssClass + " dw-mod"); } 2079 2080 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.Last().Value); 2081 2082 <tr @ComponentMethods.AddAttributes(resultAttributes)> 2083 @foreach (var cell in settings.Cells) 2084 { 2085 if (settings.IsHeaderRow) 2086 { 2087 cell.IsHeader = true; 2088 } 2089 @Render(cell) 2090 } 2091 </tr> 2092 } 2093 @using Dynamicweb.Rapido.Blocks.Components.General 2094 @using Dynamicweb.Rapido.Blocks.Components 2095 @using Dynamicweb.Core 2096 2097 @helper RenderTableCell(TableCell settings) 2098 { 2099 Dictionary<string, string> attributes = new Dictionary<string, string>(); 2100 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2101 if (settings.Colspan != 0) { attributes.Add("colspan", Converter.ToString(settings.Colspan)); } 2102 if (settings.Rowspan != 0) { attributes.Add("rowspan", Converter.ToString(settings.Rowspan)); } 2103 if (!string.IsNullOrEmpty(settings.CssClass)) { attributes.Add("class", settings.CssClass + " dw-mod"); } 2104 2105 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.Last().Value); 2106 2107 string tagName = settings.IsHeader ? "th" : "td"; 2108 2109 @("<" + tagName + " " + ComponentMethods.AddAttributes(resultAttributes) + ">") 2110 @settings.Content 2111 @("</" + tagName + ">"); 2112 } 2113 @using System.Linq 2114 @using Dynamicweb.Rapido.Blocks.Components.General 2115 2116 @* Component *@ 2117 2118 @helper RenderPagination(Dynamicweb.Rapido.Blocks.Components.General.Pagination settings) 2119 { 2120 var pageNumberQueryStringName = Dynamicweb.Rapido.Services.Pagination.GetPageNumberQueryStringName(settings); // Get the proper 'page number' query string parameter 2121 var queryParameters = Dynamicweb.Rapido.Services.Url.GetQueryParameters(pageNumberQueryStringName); // Get the NameValueCollection from the querystring 2122 2123 if (settings.NumberOfPages > 1) 2124 { 2125 string url = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + "/Default.aspx"; 2126 string ariaLabel = !string.IsNullOrWhiteSpace(settings.AriaLabel) ? settings.AriaLabel : Translate("Page navigation"); 2127 Dictionary<string, int> startAndEndPageNumber = Dynamicweb.Rapido.Services.Pagination.GetStartAndEndPageNumber(settings); 2128 2129 <div class="pager u-margin-top dw-mod @settings.CssClass" aria-label="@ariaLabel"> 2130 @if (settings.ShowPagingInfo) 2131 { 2132 <div class="pager__info dw-mod"> 2133 @Translate("Page") @settings.CurrentPageNumber @Translate("of") @settings.NumberOfPages 2134 </div> 2135 } 2136 <ul class="pager__list dw-mod"> 2137 @if (!string.IsNullOrWhiteSpace(settings.FirstPageUrl) && settings.ShowFirstAndLastControls) 2138 { 2139 @Render(new PaginationItem { Link = settings.FirstPageUrl, Icon = settings.FirstIcon }) 2140 } 2141 @if (!string.IsNullOrWhiteSpace(settings.PreviousPageUrl) && settings.ShowNextAndPrevControls) 2142 { 2143 @Render(new PaginationItem { Link = settings.PreviousPageUrl, Icon = settings.PrevIcon }) 2144 } 2145 @if (settings.GetPages().Any()) 2146 { 2147 foreach (var page in settings.GetPages()) 2148 { 2149 @Render(page) 2150 } 2151 } 2152 else 2153 { 2154 for (var page = startAndEndPageNumber["StartPage"]; page <= startAndEndPageNumber["EndPage"]; page++) 2155 { 2156 queryParameters = Dynamicweb.Rapido.Services.Url.UpdateQueryStringParameter(queryParameters, pageNumberQueryStringName, page.ToString()); 2157 @Render(new PaginationItem { Label = page.ToString(), Link = Dynamicweb.Rapido.Services.Url.BuildUri(url, queryParameters).PathAndQuery, IsActive = (settings.CurrentPageNumber == page) }); 2158 } 2159 } 2160 @if (!string.IsNullOrWhiteSpace(settings.NextPageUrl) && settings.ShowNextAndPrevControls) 2161 { 2162 @Render(new PaginationItem { Link = settings.NextPageUrl, Icon = settings.NextIcon }) 2163 } 2164 @if (!string.IsNullOrWhiteSpace(settings.LastPageUrl) && settings.ShowFirstAndLastControls) 2165 { 2166 @Render(new PaginationItem { Link = settings.LastPageUrl, Icon = settings.LastIcon }) 2167 } 2168 </ul> 2169 </div> 2170 } 2171 } 2172 2173 @helper RenderPaginationItem(PaginationItem settings) 2174 { 2175 if (settings.Icon == null) 2176 { 2177 settings.Icon = new Icon(); 2178 } 2179 2180 settings.Icon.Label = settings.Label; 2181 <li class="pager__btn dw-mod"> 2182 @if (settings.IsActive) 2183 { 2184 <span class="pager__num pager__num--current dw-mod"> 2185 @Render(settings.Icon) 2186 </span> 2187 } 2188 else 2189 { 2190 <a href="@settings.Link" class="pager__num dw-mod"> 2191 @Render(settings.Icon) 2192 </a> 2193 } 2194 </li> 2195 } 2196 2197 2198 @using Dynamicweb.Rapido.Blocks.Components.General 2199 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2200 2201 2202 @using Dynamicweb.Rapido.Blocks.Components 2203 @using Dynamicweb.Rapido.Blocks.Components.General 2204 @using Dynamicweb.Rapido.Blocks 2205 @using System.IO 2206 2207 2208 @using Dynamicweb.Rapido.Blocks.Components.General 2209 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2210 2211 2212 @* Component *@ 2213 2214 @helper RenderVariantMatrix(VariantMatrix settings) { 2215 if (settings != null) 2216 { 2217 int productLoopCounter = 0; 2218 int groupCount = 0; 2219 List<VariantOption> firstDimension = new List<VariantOption>(); 2220 List<VariantOption> secondDimension = new List<VariantOption>(); 2221 List<VariantOption> thirdDimension = new List<VariantOption>(); 2222 2223 foreach (VariantGroup variantGroup in settings.GetVariantGroups()) 2224 { 2225 foreach (VariantOption variantOptions in variantGroup.GetVariantOptions()) 2226 { 2227 if (groupCount == 0) { 2228 firstDimension.Add(variantOptions); 2229 } 2230 if (groupCount == 1) 2231 { 2232 secondDimension.Add(variantOptions); 2233 } 2234 if (groupCount == 2) 2235 { 2236 thirdDimension.Add(variantOptions); 2237 } 2238 } 2239 groupCount++; 2240 } 2241 2242 int rowCount = 0; 2243 int columnCount = 0; 2244 2245 <script> 2246 var variantsCollection = []; 2247 </script> 2248 2249 <table class="table table--compact js-variants-matrix dw-mod" id="VariantMatrixTable_@settings.ProductId"> 2250 @if (groupCount == 1) 2251 { 2252 <tbody> 2253 @foreach (VariantOption firstVariantOption in firstDimension) 2254 { 2255 var variantId = firstVariantOption.Id; 2256 <tr> 2257 <td class="u-bold"> 2258 @firstVariantOption.Name 2259 </td> 2260 <td> 2261 @RenderVariantMatrixQuantityField(variantId, settings, productLoopCounter, rowCount, columnCount) 2262 </td> 2263 </tr> 2264 productLoopCounter++; 2265 } 2266 2267 <tr> 2268 <td> </td> 2269 <td> 2270 <div class="qty-field js-total-qty-column-@columnCount dw-mod">0</div> 2271 </td> 2272 </tr> 2273 </tbody> 2274 } 2275 @if (groupCount == 2) 2276 { 2277 <thead> 2278 <tr> 2279 <td> </td> 2280 @foreach (VariantOption variant in secondDimension) 2281 { 2282 <td>@variant.Name</td> 2283 } 2284 </tr> 2285 </thead> 2286 <tbody> 2287 @foreach (VariantOption firstVariantOption in firstDimension) 2288 { 2289 string variantId = ""; 2290 columnCount = 0; 2291 2292 <tr> 2293 <td class="u-min-w120px">@firstVariantOption.Name</td> 2294 2295 @foreach (VariantOption secondVariantOption in secondDimension) 2296 { 2297 variantId = firstVariantOption.Id + "." + secondVariantOption.Id; 2298 <td> 2299 @RenderVariantMatrixQuantityField(variantId, settings, productLoopCounter, rowCount, columnCount) 2300 </td> 2301 2302 columnCount++; 2303 2304 productLoopCounter++; 2305 } 2306 2307 <td> 2308 <div class="qty-field js-total-qty-row-@rowCount dw-mod">0</div> 2309 </td> 2310 </tr> 2311 2312 rowCount++; 2313 } 2314 2315 @{ 2316 columnCount = 0; 2317 } 2318 2319 <tr> 2320 <td> </td> 2321 @foreach (VariantOption secondVariantOption in secondDimension) 2322 { 2323 <td> 2324 <div class="qty-field js-total-qty-column-@columnCount dw-mod">0</div> 2325 </td> 2326 2327 columnCount++; 2328 } 2329 <td> </td> 2330 </tr> 2331 </tbody> 2332 } 2333 @if (groupCount == 3) 2334 { 2335 <thead> 2336 <tr> 2337 <td> </td> 2338 @foreach (VariantOption thirdVariantOption in thirdDimension) 2339 { 2340 <td>@thirdVariantOption.Name</td> 2341 } 2342 </tr> 2343 </thead> 2344 <tbody> 2345 @foreach (VariantOption firstVariantOption in firstDimension) 2346 { 2347 int colspan = (thirdDimension.Count + 1); 2348 2349 <tr> 2350 <td colspan="@colspan" class="u-color-light-gray--bg u-bold">@firstVariantOption.Name</td> 2351 </tr> 2352 2353 foreach (VariantOption secondVariantOption in secondDimension) 2354 { 2355 string variantId = ""; 2356 columnCount = 0; 2357 2358 <tr> 2359 <td class="u-min-w120px">@secondVariantOption.Name</td> 2360 2361 @foreach (VariantOption thirdVariantOption in thirdDimension) 2362 { 2363 variantId = firstVariantOption.Id + "." + secondVariantOption.Id + "." + thirdVariantOption.Id; 2364 2365 <td> 2366 @RenderVariantMatrixQuantityField(variantId, settings, productLoopCounter, rowCount, columnCount) 2367 </td> 2368 2369 columnCount++; 2370 productLoopCounter++; 2371 } 2372 2373 <td> 2374 <div class="qty-field js-total-qty-row-@rowCount dw-mod">0</div> 2375 </td> 2376 </tr> 2377 rowCount++; 2378 } 2379 } 2380 2381 @{ 2382 columnCount = 0; 2383 } 2384 2385 <tr> 2386 <td> </td> 2387 @foreach (VariantOption thirdVariantOption in thirdDimension) 2388 { 2389 <td> 2390 <div class="qty-field js-total-qty-column-@columnCount dw-mod">0</div> 2391 </td> 2392 2393 columnCount++; 2394 } 2395 <td> </td> 2396 </tr> 2397 </tbody> 2398 } 2399 </table> 2400 2401 <script> 2402 document.addEventListener("DOMContentLoaded", function (event) { 2403 MatrixUpdateQuantity("@settings.ProductId"); 2404 }); 2405 2406 MatrixUpdateQuantity = function (productId) { 2407 var currentMatrix = document.getElementById("VariantMatrixTable_" + productId); 2408 var allQtyFields = currentMatrix.getElementsByClassName("js-qty"); 2409 2410 var qtyRowArr = []; 2411 var qtyColumnArr = []; 2412 2413 var totalQty = 0; 2414 2415 for (var i = 0; i < allQtyFields.length; i++) { 2416 qtyRowArr[allQtyFields[i].getAttribute("data-qty-row-group")] = 0; 2417 qtyColumnArr[allQtyFields[i].getAttribute("data-qty-column-group")] = 0; 2418 } 2419 2420 for (var i = 0; i < allQtyFields.length; i++) { 2421 qtyRowArr[allQtyFields[i].getAttribute("data-qty-row-group")] += parseFloat(allQtyFields[i].value); 2422 qtyColumnArr[allQtyFields[i].getAttribute("data-qty-column-group")] += parseFloat(allQtyFields[i].value); 2423 totalQty += parseFloat(allQtyFields[i].value); 2424 } 2425 2426 //Update row counters 2427 for (var i = 0; i < qtyRowArr.length; i++) { 2428 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-row-" + i)[0]; 2429 2430 if (qtyRowArr[i] != undefined && qtyCounter != null) { 2431 var currentCount = qtyCounter.innerHTML; 2432 qtyCounter.innerHTML = qtyRowArr[i]; 2433 2434 if (currentCount != qtyCounter.innerHTML) { 2435 qtyCounter.classList.add("qty-field--active"); 2436 } 2437 } 2438 2439 } 2440 2441 //Update column counters 2442 for (var i = 0; i < qtyColumnArr.length; i++) { 2443 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-column-" + i)[0]; 2444 2445 if (qtyColumnArr[i] != undefined && qtyCounter != null) { 2446 var currentCount = qtyCounter.innerHTML; 2447 qtyCounter.innerHTML = qtyColumnArr[i]; 2448 2449 if (currentCount != qtyCounter.innerHTML) { 2450 qtyCounter.classList.add("qty-field--active"); 2451 } 2452 } 2453 } 2454 2455 if (document.getElementById("TotalQtyCount_" + productId)) { 2456 document.getElementById("TotalQtyCount_" + productId).innerHTML = totalQty; 2457 } 2458 2459 //Clean up animations 2460 setTimeout(function () { 2461 for (var i = 0; i < qtyRowArr.length; i++) { 2462 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-row-" + i)[0]; 2463 if (qtyCounter != null) { 2464 qtyCounter.classList.remove("qty-field--active"); 2465 } 2466 } 2467 for (var i = 0; i < qtyColumnArr.length; i++) { 2468 var qtyCounter = currentMatrix.getElementsByClassName("js-total-qty-column-" + i)[0]; 2469 if (qtyCounter != null) { 2470 qtyCounter.classList.remove("qty-field--active"); 2471 } 2472 } 2473 }, 1000); 2474 } 2475 </script> 2476 } 2477 } 2478 2479 @helper RenderVariantMatrixQuantityField(string variantId, VariantMatrix settings, int productLoopCounter, int rowCount, int columnCount) 2480 { 2481 string loopCount = productLoopCounter.ToString(); 2482 2483 bool combinationFound = false; 2484 double stock = 0; 2485 double quantityValue = 0; 2486 string note = ""; 2487 2488 VariantProduct variantProduct = null; 2489 2490 if (settings.GetVariantProducts().TryGetValue(variantId, out variantProduct)) 2491 { 2492 stock = variantProduct.Stock; 2493 quantityValue = variantProduct.Quantity; 2494 combinationFound = true; 2495 } 2496 2497 if (combinationFound) 2498 { 2499 <input type="hidden" name="ProductLoopCounter@(loopCount)" value="@loopCount" /> 2500 <input type="hidden" name="ProductID@(loopCount)" value="@settings.ProductId" /> 2501 <input type="hidden" name="VariantID@(loopCount)" value="@variantId" /> 2502 <input type="hidden" name="CurrentNote@(loopCount)" id="CurrentNote_@(settings.ProductId)_@variantId" value="@note" /> 2503 <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"> 2504 2505 if (stock != 0) 2506 { 2507 <small>@Translate("Stock") @stock</small> 2508 } 2509 2510 <script> 2511 var variants = '{ "ProductId" :' + '"@settings.ProductId"' + ', "VariantId": ' + '"@variantId"' +'}'; 2512 variantsCollection.push(variants); 2513 document.getElementById("Quantity_@(settings.ProductId)_@variantId").closest(".js-variants-matrix").setAttribute("data-variants-collection", "[" + variantsCollection + "]" ); 2514 </script> 2515 } 2516 else 2517 { 2518 <div class="use-btn-height" style="background-color: #a8a8a8"></div> 2519 } 2520 } 2521 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2522 2523 @* Component *@ 2524 2525 @helper RenderAddToCart(AddToCart settings) 2526 { 2527 //set Id for quantity selector to get it's value from button 2528 if (settings.QuantitySelector != null) 2529 { 2530 if (string.IsNullOrEmpty(settings.QuantitySelector.Id)) 2531 { 2532 settings.QuantitySelector.Id = Guid.NewGuid().ToString("N"); 2533 } 2534 2535 settings.AddButton.QuantitySelectorId = settings.QuantitySelector.Id; 2536 2537 if (settings.Disabled) 2538 { 2539 settings.QuantitySelector.Disabled = true; 2540 } 2541 2542 if (string.IsNullOrEmpty(settings.QuantitySelector.Name)) 2543 { 2544 settings.QuantitySelector.Name = settings.QuantitySelector.Id; 2545 } 2546 } 2547 2548 if (settings.Disabled) 2549 { 2550 settings.AddButton.Disabled = true; 2551 } 2552 2553 settings.AddButton.CssClass += " btn--condensed"; 2554 2555 //unitsSelector 2556 if (settings.UnitSelector != null) 2557 { 2558 if (settings.Disabled) 2559 { 2560 settings.QuantitySelector.Disabled = true; 2561 } 2562 } 2563 2564 <div class="buttons-collection @settings.WrapperCssClass" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 2565 @if (settings.UnitSelector != null) 2566 { 2567 @Render(settings.UnitSelector) 2568 } 2569 @if (settings.QuantitySelector != null) 2570 { 2571 @Render(settings.QuantitySelector) 2572 } 2573 @Render(settings.AddButton) 2574 </div> 2575 } 2576 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2577 2578 @* Component *@ 2579 2580 @helper RenderAddToCartButton(AddToCartButton settings) 2581 { 2582 if (!settings.HideTitle) 2583 { 2584 if (string.IsNullOrEmpty(settings.Title)) 2585 { 2586 if (settings.BuyForPoints) 2587 { 2588 settings.Title = Translate("Buy with points"); 2589 } 2590 else 2591 { 2592 settings.Title = Translate("Add to cart"); 2593 } 2594 } 2595 } 2596 else 2597 { 2598 settings.Title = ""; 2599 } 2600 2601 if (settings.Icon == null) 2602 { 2603 settings.Icon = new Icon(); 2604 settings.Icon.LabelPosition = Dynamicweb.Rapido.Blocks.Components.General.IconLabelPosition.After; 2605 } 2606 2607 if (string.IsNullOrEmpty(settings.Icon.Name)) 2608 { 2609 settings.Icon.Name = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue; 2610 } 2611 2612 settings.OnClick = "Cart.AddToCart(event, { " + 2613 "id: '" + settings.ProductId + "'," + 2614 (!string.IsNullOrEmpty(settings.VariantId) ? "variantId: '" + settings.VariantId + "'," : "") + 2615 (!string.IsNullOrEmpty(settings.UnitId) ? "unitId: '" + settings.UnitId + "'," : "") + 2616 (settings.BuyForPoints ? "buyForPoints: true," : "") + 2617 (!string.IsNullOrEmpty(settings.ProductInfo) ? "productInfo: " + settings.ProductInfo + "," : "") + 2618 "quantity: " + (string.IsNullOrEmpty(settings.QuantitySelectorId) ? "1" : "parseFloat(document.getElementById('" + settings.QuantitySelectorId + "').value)") + 2619 "});" + settings.OnClick; 2620 2621 @RenderButton(settings) 2622 } 2623 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2624 2625 @* Component *@ 2626 2627 @helper RenderUnitSelector(UnitSelector settings) 2628 { 2629 if (string.IsNullOrEmpty(settings.Id)) 2630 { 2631 settings.Id = Guid.NewGuid().ToString("N"); 2632 } 2633 var disabledClass = settings.Disabled ? "disabled" : ""; 2634 2635 <input type="checkbox" id="@settings.Id" class="dropdown-trigger" /> 2636 <div class="dropdown unit-selector @settings.CssClass @disabledClass dw-mod" @ComponentMethods.AddAttributes(settings.ExtraAttributes)> 2637 <label class="dropdown__header dropdown__btn dropdown__btn--unit-selector dw-mod" for="@settings.Id">@settings.SelectedOption</label> 2638 <div class="dropdown__content dw-mod"> 2639 @settings.OptionsContent 2640 </div> 2641 <label class="dropdown-trigger-off" for="@settings.Id"></label> 2642 </div> 2643 } 2644 @using System.Reflection 2645 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2646 2647 @* Component *@ 2648 2649 @helper RenderQuantitySelector(QuantitySelector settings) 2650 { 2651 var attributes = new Dictionary<string, string>(); 2652 2653 /*base settings*/ 2654 if (!string.IsNullOrEmpty(settings.Id)) { attributes.Add("id", settings.Id); } 2655 if (!string.IsNullOrEmpty(settings.OnClick)) { attributes.Add("onclick", settings.OnClick); } 2656 if (!string.IsNullOrEmpty(settings.OnChange)) { attributes.Add("onchange", settings.OnChange); } 2657 if (settings.Disabled) { attributes.Add("disabled", "true"); } 2658 if (settings.Required) { attributes.Add("required", "true"); } 2659 if (!string.IsNullOrEmpty(settings.Name)) { attributes.Add("name", settings.Name); } 2660 /*end*/ 2661 2662 if (!string.IsNullOrEmpty(settings.OnKeyUp)) { attributes.Add("onkeyup", settings.OnKeyUp); } 2663 if (!string.IsNullOrEmpty(settings.OnInput)) { attributes.Add("oninput", settings.OnInput); } 2664 if (!string.IsNullOrEmpty(settings.OnFocus)) { attributes.Add("onfocus", settings.OnFocus); } 2665 if (settings.ReadOnly) { attributes.Add("readonly", "true"); } 2666 if (settings.Max != null) { attributes.Add("max", settings.Max.ToString()); } 2667 if (settings.Min == null) { settings.Min = 1; } 2668 attributes.Add("min", settings.Min.ToString()); 2669 if (settings.Step != null && !string.IsNullOrEmpty(settings.Step.ToString())) { attributes.Add("step", settings.Step.ToString()); } 2670 if (settings.Value == null) { settings.Value = 1; } 2671 attributes.Add("value", settings.Value.ToString()); 2672 attributes.Add("type", "number"); 2673 2674 var resultAttributes = attributes.Concat(settings.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2675 2676 <input @ComponentMethods.AddAttributes(resultAttributes) class="@settings.CssClass dw-mod" /> 2677 } 2678 @using Dynamicweb.Rapido.Blocks.Components 2679 2680 @using Dynamicweb.Frontend 2681 @using Dynamicweb.Frontend.Devices 2682 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 2683 @using Dynamicweb.Rapido.Blocks.Components.General 2684 @using System.Collections.Generic; 2685 2686 @* Component *@ 2687 2688 @helper RenderCustomerCenterList(CustomerCenterList settings) 2689 { 2690 bool isTouchDevice = Pageview.Device.ToString() == "Mobile" || Pageview.Device.ToString() == "Tablet" ? true : false; 2691 string hideActions = isTouchDevice ? "u-block" : ""; 2692 2693 <table class="table data-list dw-mod"> 2694 @if (settings.GetHeaders().Length > 0) { 2695 <thead> 2696 <tr class="u-bold"> 2697 @foreach (CustomerCenterListHeaderItem header in settings.GetHeaders()) 2698 { 2699 var attributes = new Dictionary<string, string>(); 2700 if (!string.IsNullOrEmpty(header.Id)) { attributes.Add("id", header.Id); } 2701 if (!string.IsNullOrEmpty(header.CssClass)) { attributes.Add("class", header.CssClass); } 2702 attributes.Add("align", header.Align.ToString()); 2703 attributes = attributes.Concat(header.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2704 2705 <td @ComponentMethods.AddAttributes(attributes)>@header.Title</td> 2706 } 2707 </tr> 2708 </thead> 2709 } 2710 @foreach (CustomerCenterListItem listItem in settings.GetItems()) 2711 { 2712 int columnCount = 0; 2713 int totalColumns = listItem.GetInfoItems().Length; 2714 string rowHasActions = listItem.GetActions().Length > 0 ? "data-list__item--has-actions" : ""; 2715 listItem.Id = !string.IsNullOrEmpty(listItem.Id) ? listItem.Id : Guid.NewGuid().ToString("N"); 2716 2717 var attributes = new Dictionary<string, string>(); 2718 if (!string.IsNullOrEmpty(listItem.Title)) { attributes.Add("title", listItem.Title); }; 2719 2720 attributes = attributes.Concat(listItem.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2721 <tbody class="data-list__item @rowHasActions @listItem.CssClass dw-mod" @ComponentMethods.AddAttributes(attributes)> 2722 <tr> 2723 @if (!string.IsNullOrEmpty(listItem.Title) || !string.IsNullOrEmpty(listItem.Description)) { 2724 string onClick = !string.IsNullOrEmpty(listItem.OnClick) ? "onclick=\"" + listItem.OnClick + "\"" : ""; 2725 2726 <td rowspan="2" @onClick class="data-list__main-item dw-mod"> 2727 @if (!string.IsNullOrEmpty(listItem.Title)) { 2728 <div class="u-bold">@listItem.Title</div> 2729 } 2730 @if (!string.IsNullOrEmpty(listItem.Description)) { 2731 <div>@listItem.Description</div> 2732 } 2733 </td> 2734 } 2735 2736 @foreach (CustomerCenterListInfoItem infoItem in listItem.GetInfoItems()) 2737 { 2738 var infoAttributes = new Dictionary<string, string>(); 2739 if (!string.IsNullOrEmpty(infoItem.Id)) { infoAttributes.Add("id", infoItem.Id); }; 2740 if (!string.IsNullOrEmpty(infoItem.OnClick)) { infoAttributes.Add("onclick", infoItem.OnClick); }; 2741 infoAttributes.Add("align", infoItem.Align.ToString()); 2742 2743 infoAttributes = infoAttributes.Concat(infoItem.ExtraAttributes).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.Last().Value); 2744 string columnClick = columnCount < (totalColumns-1) && !string.IsNullOrEmpty(listItem.OnClick) ? "onclick=\"" + listItem.OnClick + "\"" : ""; 2745 2746 <td @ComponentMethods.AddAttributes(infoAttributes) @columnClick class="data-list__info-item dw-mod"> 2747 @if (!string.IsNullOrEmpty(infoItem.Title)) { 2748 <div>@infoItem.Title</div> 2749 } 2750 @if (!string.IsNullOrEmpty(infoItem.Subtitle)) { 2751 <div><small>@infoItem.Subtitle</small></div> 2752 } 2753 </td> 2754 2755 columnCount++; 2756 } 2757 </tr> 2758 <tr> 2759 <td colspan="7" align="right" class="u-va-bottom u-no-border"> 2760 <div class="data-list__actions @hideActions dw-mod" id="ActionsMenu_@listItem.Id"> 2761 @foreach (ButtonBase action in listItem.GetActions()) 2762 { 2763 action.ButtonLayout = ButtonLayout.LinkClean; 2764 action.Icon.CssClass += " u-full-height"; 2765 action.CssClass += " data-list__action-button link"; 2766 2767 @Render(action) 2768 } 2769 </div> 2770 </td> 2771 </tr> 2772 </tbody> 2773 } 2774 </table> 2775 } 2776 2777 @* Include the Blocks for the page *@ 2778 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2779 @using Dynamicweb.Core 2780 @using System 2781 @using System.Web 2782 @using System.Collections.Generic 2783 @using Dynamicweb.Rapido.Blocks 2784 @using Dynamicweb.Rapido.Blocks.Components.General 2785 2786 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2787 @using System.Linq; 2788 @using Dynamicweb.Rapido.Blocks.Components.General 2789 @using System.Collections.Generic 2790 2791 @functions{ 2792 Dictionary<string, StickersListPosition> stickerPositions = new Dictionary<string, StickersListPosition> 2793 { 2794 { "top-left", StickersListPosition.TopLeft }, 2795 { "top-right", StickersListPosition.TopRight }, 2796 { "bottom-left", StickersListPosition.BottomLeft }, 2797 { "bottom-right", StickersListPosition.BottomRight } 2798 }; 2799 2800 public void AddSticker(List<StickersCollection> list, Sticker sticker, StickersListPosition stickerPosition) 2801 { 2802 StickersCollection stickersContainerTemp = list.FirstOrDefault(stickersContainer => stickersContainer.Position == stickerPosition); 2803 if (stickersContainerTemp == null) 2804 { 2805 stickersContainerTemp = new StickersCollection() 2806 { 2807 Position = stickerPosition, 2808 Stickers = new List<Sticker>() 2809 }; 2810 list.Add(stickersContainerTemp); 2811 } 2812 stickersContainerTemp.Stickers.Add(sticker); 2813 } 2814 2815 public List<StickersCollection> GetStickersContainersList(List<LoopItem> discountsLoop, double discountPrice, double price, DateTime createdDate, string customStickerValue) 2816 { 2817 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 2818 bool isSaleStickersEnabled = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetBoolean("Enable"); 2819 bool isNewsStickersEnabled = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetBoolean("Enable"); 2820 bool isCustomStickersEnabled = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("CustomSticker").GetBoolean("Enable"); 2821 2822 List<StickersCollection> resultList = new List<StickersCollection>(); 2823 2824 if (!pointShopOnly && isSaleStickersEnabled) 2825 { 2826 string contentType = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetString("ContentType"); 2827 contentType = !string.IsNullOrEmpty(contentType) ? contentType : "Name"; 2828 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 2829 Sticker saleSticker = new Sticker(); 2830 saleSticker.CssClass = "stickers-container__tag--sale"; 2831 2832 switch (contentType) 2833 { 2834 case "Name": 2835 foreach (LoopItem discount in discountsLoop) 2836 { 2837 saleSticker.Title = discount.GetString("Ecom:Product.Discount.Name"); 2838 } 2839 break; 2840 case "Amount": 2841 if (discountsLoop.Count > 0) 2842 { 2843 saleSticker.Title = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, discountPrice - price); 2844 } 2845 break; 2846 case "Percents": 2847 double percents = 0; 2848 foreach (LoopItem discount in discountsLoop) 2849 { 2850 percents += discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 2851 } 2852 if (percents > 0) 2853 { 2854 saleSticker.Title = Math.Round(percents, 0) + "%"; 2855 } 2856 break; 2857 case "Amount and percents": 2858 double amount = 0; 2859 double percent = 0; 2860 foreach (LoopItem discount in discountsLoop) 2861 { 2862 if (discount.GetString("Ecom:Product.Discount.Type") == "PERCENT") 2863 { 2864 percent += discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 2865 } 2866 else if (discount.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 2867 { 2868 amount += discount.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 2869 } 2870 } 2871 2872 if (percent > 0) 2873 { 2874 saleSticker.Title = percent + "%"; 2875 } 2876 else if (amount > 0) 2877 { 2878 saleSticker.Title = "-" + Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 2879 } 2880 break; 2881 default: 2882 if (discountsLoop.Count > 0) 2883 { 2884 saleSticker.Title = Translate("Sale!"); 2885 } 2886 break; 2887 } 2888 StickersListPosition saleStickerPosition = StickersListPosition.TopLeft; 2889 if (Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetList("Position") != null) 2890 { 2891 string value = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("SaleSticker").GetList("Position").SelectedValue; 2892 saleStickerPosition = stickerPositions.ContainsKey(value) ? stickerPositions[value] : stickerPositions["top-left"]; 2893 } 2894 if (!string.IsNullOrEmpty(saleSticker.Title)) 2895 { 2896 AddSticker(resultList, saleSticker, saleStickerPosition); 2897 } 2898 } 2899 2900 if (!pointShopOnly && isNewsStickersEnabled && createdDate.AddDays(Converter.ToDouble(Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetString("Expiration"))) > DateTime.Now) 2901 { 2902 Sticker newSticker = new Sticker(); 2903 newSticker.CssClass = "stickers-container__tag--new"; 2904 newSticker.Title = Translate("New!"); 2905 2906 StickersListPosition newStickerPosition = StickersListPosition.TopLeft; 2907 if (Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetList("Position") != null) 2908 { 2909 string value = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("NewSticker").GetList("Position").SelectedValue; 2910 newStickerPosition = stickerPositions.ContainsKey(value) ? stickerPositions[value] : stickerPositions["top-left"]; 2911 } 2912 if (!string.IsNullOrEmpty(newSticker.Title)) 2913 { 2914 AddSticker(resultList, newSticker, newStickerPosition); 2915 } 2916 } 2917 2918 if (!pointShopOnly && isCustomStickersEnabled && !string.IsNullOrEmpty(customStickerValue)) 2919 { 2920 Sticker customSticker = new Sticker(); 2921 customSticker.CssClass = "stickers-container__tag--custom"; 2922 customSticker.Title = customStickerValue; 2923 2924 StickersListPosition customStickerPosition = StickersListPosition.TopLeft; 2925 if (Pageview.AreaSettings.GetItem("Ecommerce").GetItem("CustomSticker").GetList("Position") != null) 2926 { 2927 string value = Pageview.AreaSettings.GetItem("Ecommerce").GetItem("CustomSticker").GetList("Position").SelectedValue; 2928 customStickerPosition = stickerPositions.ContainsKey(value) ? stickerPositions[value] : stickerPositions["top-left"]; 2929 } 2930 if (!string.IsNullOrEmpty(customSticker.Title)) 2931 { 2932 AddSticker(resultList, customSticker, customStickerPosition); 2933 } 2934 } 2935 2936 return resultList; 2937 } 2938 } 2939 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2940 2941 2942 @* 2943 This is a temporary fallback for the DefaultImage. The image pattern MUST be set up like this: 2944 2945 ImageSmall = /{ProductNumber}.jpg 2946 ImageMedium = /{ProductNumber}{VariantOptionLevel1}.jpg 2947 ImageLarge = /{ProductNumber}{VariantComboName}.jpg 2948 2949 In addition to the ImageDefault setting 2950 *@ 2951 2952 @functions { 2953 public string GetProductImage(LoopItem productObject = null) 2954 { 2955 string theImage = ""; 2956 2957 if (productObject == null) { 2958 theImage = GetString("Ecom:Product.ImageDefault.Default.Clean"); 2959 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageLarge.Clean") : theImage; 2960 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageMedium.Clean") : theImage; 2961 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageSmall.Clean") : theImage; 2962 theImage = String.IsNullOrEmpty(theImage) ? GetString("Ecom:Product.ImageLarge.Default.Clean") : theImage; 2963 } else { 2964 theImage = productObject.GetString("Ecom:Product.ImageDefault.Default.Clean"); 2965 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageLarge.Clean") : theImage; 2966 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageMedium.Clean") : theImage; 2967 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageSmall.Clean") : theImage; 2968 theImage = String.IsNullOrEmpty(theImage) ? productObject.GetString("Ecom:Product.ImageLarge.Default.Clean") : theImage; 2969 } 2970 2971 return theImage; 2972 } 2973 } 2974 2975 @functions { 2976 BlocksPage mainImagePage = BlocksPage.GetBlockPage("Product"); 2977 bool showThumbs; 2978 bool thumbsOnTheSide; 2979 } 2980 2981 @{ 2982 int imageBlockWidth = Pageview.AreaSettings.GetItem("ProductPage").GetList("TopLayout") != null ? Converter.ToInt32(Pageview.AreaSettings.GetItem("ProductPage").GetList("TopLayout").SelectedValue) : 6; 2983 string blocksPosition = Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "thumbs-image-info"; 2984 bool infoOnTheRight = blocksPosition.LastIndexOf("info") == blocksPosition.Length - 4; 2985 showThumbs = blocksPosition.IndexOf("thumbs") != -1; 2986 thumbsOnTheSide = showThumbs && blocksPosition.IndexOf("thumbsBottom") == -1; 2987 bool thumbsOnTheLeft = blocksPosition.IndexOf("image") > blocksPosition.IndexOf("thumbs"); 2988 if (infoOnTheRight) 2989 { 2990 imageBlockWidth = 12 - imageBlockWidth; 2991 if (imageBlockWidth == 0) 2992 { 2993 imageBlockWidth = 12; 2994 } 2995 } 2996 2997 if (Pageview.Device.ToString() == "Mobile" || Pageview.Device.ToString() == "Tablet") 2998 { 2999 thumbsOnTheSide = false; 3000 } 3001 Block mainImageBlock = new Block() 3002 { 3003 Id = "MainImage", 3004 SortId = infoOnTheRight ? 10 : 20, 3005 Design = new Design 3006 { 3007 Size = Converter.ToString(imageBlockWidth), 3008 RenderType = RenderType.Column 3009 }, 3010 BlocksList = new List<Block> 3011 { 3012 new Block { 3013 Id = "MainImageRow", 3014 SortId = 10, 3015 Design = new Design 3016 { 3017 RenderType = RenderType.Row 3018 }, 3019 BlocksList = new List<Block> 3020 { 3021 new Block 3022 { 3023 Id = "Icons", 3024 SortId = 5, 3025 Template = RenderProductIcons() 3026 }, 3027 new Block 3028 { 3029 Id = "Carousel", 3030 SortId = 10, 3031 Template = RenderThumbnails(), 3032 Design = new Design 3033 { 3034 Size = thumbsOnTheSide ? "2" : "12", 3035 RenderType = RenderType.Column 3036 } 3037 } 3038 } 3039 } 3040 } 3041 }; 3042 mainImagePage.Add("Top", mainImageBlock); 3043 3044 mainImagePage.Add("MainImageRow", 3045 new Block() 3046 { 3047 Id = "ProductImageModal", 3048 SortId = 0, 3049 Component = new Modal 3050 { 3051 Id = "Gallery", 3052 Width = ModalWidth.Lg, 3053 Height = ModalHeight.Full, 3054 BodyTemplate = RenderProductImagesCarousel("modalCarousel", 1, "horizontal", 3, true) 3055 } 3056 }); 3057 3058 3059 if (showThumbs) 3060 { 3061 mainImagePage.Add("MainImageRow", 3062 new Block 3063 { 3064 Id = "Image", 3065 SortId = thumbsOnTheLeft ? 20 : 0, 3066 Template = RenderProductImage(), 3067 Design = new Design 3068 { 3069 Size = thumbsOnTheSide ? "auto" : "12", 3070 RenderType = RenderType.Column 3071 } 3072 }); 3073 } 3074 } 3075 3076 @helper RenderProductStickers() 3077 { 3078 List<StickersCollection> StickersContainers = GetStickersContainersList( 3079 GetLoop("ProductDiscounts"), 3080 GetDouble("Ecom:Product.Discount.Price.Price"), 3081 GetDouble("Ecom:Product.Price.Price"), 3082 GetDate("Ecom:Product.Created"), 3083 GetString("Ecom:Product:Field.CustomSticker.Value") 3084 ); 3085 3086 foreach (StickersCollection stickersContainer in StickersContainers) 3087 { 3088 @Render(new StickersCollection { Stickers = stickersContainer.Stickers, Position = stickersContainer.Position }) 3089 } 3090 } 3091 3092 @helper RenderProductIcons() 3093 { 3094 <table border="0" cellpadding="0" cellspacing="0" width="100%" style="text-align: center; margin: 0;"> 3095 <tr style="display: flex; justify-content:center;"> 3096 @if (GetBoolean("Ecom:Product:Field.Campaign_item")) 3097 { 3098 string campaignImagePath = "/Admin/Public/GetImage.ashx?Image=" + Pageview.AreaSettings.GetItem("Custom").GetString("CampaignIcon") + "&width=145&height=auto&compression=75&format=webp"; 3099 string campaignTdStyling = "text-align: -webkit-right; border: none; padding: 0 15px;"; 3100 <td class="icon-hover" style="@campaignTdStyling"> 3101 <div> 3102 <div class="icon-hover-text"> 3103 @Translate("IconsHover.Campaign", "I am for sale!") 3104 </div> 3105 <img src="@campaignImagePath" class="product__icon" /> 3106 </div> 3107 </td> 3108 } 3109 @foreach (var category in GetLoop("ProductCategories")) 3110 { 3111 foreach (var field in category.GetLoop("ProductCategoryFields")) 3112 { 3113 string categoryFieldId = field.GetString("Ecom:Product.CategoryField.ID"); 3114 string categoryFieldValue = field.GetString("Ecom:Product.CategoryField.Value"); 3115 if ((!string.IsNullOrEmpty(categoryFieldId) && categoryFieldId.Equals("TrailerCategory")) && (!string.IsNullOrEmpty(categoryFieldValue))) 3116 { 3117 string categoryImageName = categoryFieldValue + "Icon"; 3118 string categoryImagePath = "/Admin/Public/GetImage.ashx?Image=" + Pageview.AreaSettings.GetItem("Custom").GetString(categoryImageName) + "&width=145&height=auto&compression=75&format=webp"; 3119 <td class="icon-hover product__icon-container" style="width: 17%;"> 3120 <div> 3121 <div class="icon-hover-text"> 3122 @Translate("IconsHover." + categoryFieldValue, categoryFieldValue) 3123 </div> 3124 <img src="@categoryImagePath" class="product__icon" /> 3125 </div> 3126 </td> 3127 } 3128 } 3129 } 3130 @if (GetString("LEDLight").Equals("Standard")) 3131 { 3132 string ledImagePath = "/Admin/Public/GetImage.ashx?Image=" + Pageview.AreaSettings.GetItem("Custom").GetString("LEDIcon") + "&width=145&height=auto&compression=75&format=webp"; 3133 <td class="icon-hover product__icon-container" style="width: 14%;"> 3134 <div> 3135 <div class="icon-hover-text"> 3136 @Translate("IconsHover.LED", "LEEED's") 3137 </div> 3138 <img src="@ledImagePath" class="product__icon" /> 3139 </div> 3140 </td> 3141 } 3142 </tr> 3143 </table> 3144 } 3145 3146 @helper RenderProductImage() 3147 { 3148 //Add product image to the og meta data 3149 Pageview.Meta.AddTag("og:image", GetProductImage()); 3150 3151 <label for="GalleryModalTrigger" class="product__image-container u-position-relative"> 3152 @{ 3153 Image productImage = new Image 3154 { 3155 Path = GetProductImage(), 3156 Id = "Image_" + GetString("Ecom:Product.ID"), 3157 CssClass = "u-middle product__image-container__image dw-mod", 3158 Title = GetString("Ecom:Product.Name"), 3159 OnClick = "modalCarousel.GoToSlide('modalCarousel', this.getAttribute('data-number'))", 3160 ImageDefault = new ImageSettings 3161 { 3162 Width = 800, 3163 Height = 800, 3164 Crop = 5, 3165 FillCanvas = true 3166 } 3167 }; 3168 productImage.ExtraAttributes.Add("data-number", "0"); 3169 } 3170 @Render(productImage) 3171 @RenderProductStickers() 3172 </label> 3173 } 3174 3175 @helper RenderThumbnails() 3176 { 3177 <div class="@(showThumbs ? "product__thumbs" : "") dw-mod"> 3178 @RenderProductImagesCarousel( 3179 "productCarousel", 3180 !showThumbs ? 1 : 5, 3181 thumbsOnTheSide ? "vertical" : "horizontal", 3182 !showThumbs ? 3 : 2 3183 ) 3184 @if (!showThumbs) 3185 { 3186 @RenderProductStickers() 3187 } 3188 </div> 3189 } 3190 3191 @helper RenderProductImagesCarousel(string id, int slidesInView, string direction, int preloaderSize, bool isModal = false) 3192 { 3193 3194 var selectedImageCategories = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductImagesInTopSection").SelectedValues; 3195 var imagesFromAssets = GetLoop("ImageCategories").Where(x => selectedImageCategories.Contains(x.GetString("Category.Id"))); 3196 3197 HashSet<string> images = new HashSet<string>(); 3198 3199 images.Add(GetProductImage()); 3200 3201 foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 3202 { 3203 string alt_image = alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 3204 3205 if (!string.IsNullOrEmpty(alt_image)) 3206 { 3207 images.Add(alt_image); 3208 } 3209 } 3210 3211 int assetImagesCount = 0; 3212 foreach (LoopItem category in imagesFromAssets) 3213 { 3214 foreach (LoopItem asset in category.GetLoop("Category.Images")) 3215 { 3216 assetImagesCount++; 3217 } 3218 } 3219 3220 if (assetImagesCount > 0) 3221 { 3222 foreach (LoopItem category in imagesFromAssets) 3223 { 3224 foreach (LoopItem asset in category.GetLoop("Category.Images")) 3225 { 3226 images.Add(asset.GetString("Ecom:Product:Detail.Image.Clean")); 3227 } 3228 } 3229 } 3230 else 3231 { 3232 foreach (LoopItem detail in GetLoop("Details")) 3233 { 3234 string detail_image = detail.GetString("Ecom:Product:Detail.Image.Clean"); 3235 3236 if (!string.IsNullOrEmpty(detail_image)) 3237 { 3238 string ext = Path.GetExtension(detail_image).ToLower(); 3239 if (ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".png") 3240 { 3241 images.Add(detail_image); 3242 } 3243 } 3244 } 3245 } 3246 3247 <div class="carousel dw-mod" id="@id"> 3248 <div class="thumb-list carousel__container @(slidesInView != 1 ? "carousel__container--hidden" : "") js-carousel-slides dw-mod"> 3249 @{ var i = 0; } 3250 @foreach (var image in images) 3251 { 3252 @RenderProductImage(image, slidesInView == 1, isModal ? "modal--full__img" : "", i == 0, isModal) 3253 i++; //first is active 3254 } 3255 </div> 3256 3257 <script> 3258 document.addEventListener("DOMContentLoaded", function () { 3259 @id = new CarouselModule('#@id', { 3260 slidesInView: @slidesInView, 3261 direction: "@direction", 3262 preloaderSize: @preloaderSize, 3263 showCounter: @isModal.ToString().ToLower() 3264 }); 3265 }); 3266 </script> 3267 </div> 3268 } 3269 3270 @helper RenderProductImage(string image, bool isBig, string cssClass = "", bool isActive = false, bool isModal = false) 3271 { 3272 3273 string productId = GetString("Ecom:Product.ID"); 3274 string imagePrefix = "/Admin/Public/GetImage.ashx?width=800&height=800&crop=5&FillCanvas=True&DoNotUpscale=true&format=webp&Compression=75&image="; 3275 3276 Image productImage = new Image 3277 { 3278 Path = image, 3279 Title = GetString("Ecom:Product.Name"), 3280 ImageDefault = new ImageSettings 3281 { 3282 Width = 800, 3283 Height = 800, 3284 Crop = 5, 3285 FillCanvas = true 3286 }, 3287 CssClass = "u-middle " + cssClass, 3288 OnClick = "modalCarousel.GoToSlide('modalCarousel', this.closest('.carousel__slide').index());" 3289 }; 3290 productImage.ExtraAttributes.Add("data-image", image); 3291 3292 <div class="carousel__slide dw-mod"> 3293 @if (isModal) 3294 { 3295 @Render(new Image 3296 { 3297 Path = image, 3298 CssClass = cssClass, 3299 Title = GetString("Ecom:Product.Name"), 3300 DisableImageEngine = false, 3301 ImageDefault = new ImageSettings 3302 { 3303 Width = 1920, 3304 Height = 1080, 3305 Crop = 5 3306 } 3307 }); 3308 } 3309 else if (isBig) 3310 { 3311 <label for="GalleryModalTrigger" class="u-middle"> 3312 3313 @Render(productImage) 3314 </label> 3315 } 3316 else 3317 { 3318 Image productThumb = productImage; 3319 productThumb.ImageDefault = new ImageSettings 3320 { 3321 Width = 200, 3322 Height = 200, 3323 Crop = 5, 3324 FillCanvas = true 3325 }; 3326 productImage.CssClass += " thumb-list__image"; 3327 <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)"> 3328 <label for="GalleryModalTrigger" class="thumb-list__image-label"> 3329 @Render(productThumb) 3330 </label> 3331 </div> 3332 } 3333 </div> 3334 } 3335 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 3336 @using Dynamicweb.Core 3337 @using System 3338 @using System.Web 3339 @using System.Collections.Generic 3340 @using Dynamicweb.Rapido.Services 3341 @using Dynamicweb.Rapido.Blocks 3342 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 3343 @using Dynamicweb.Rapido.Blocks.Components.General 3344 3345 @functions { 3346 bool useFacebookPixel; 3347 BlocksPage mainInfoPage = BlocksPage.GetBlockPage("Product"); 3348 } 3349 3350 @{ 3351 var mainInfoVariantsCount = GetInteger("Ecom:Product.VariantCount"); 3352 useFacebookPixel = !string.IsNullOrWhiteSpace(Pageview.AreaSettings.GetItem("Settings").GetString("FacebookPixelID")); 3353 bool hideAddToCartButton = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("hideAddToCartButton"); 3354 3355 //family members 3356 bool mainInfoIsFamilyMember = false; 3357 bool mainInfoIsFamilyMaster = false; 3358 var mainInfoVariantGroups = GetLoop("VariantGroups"); 3359 var mainInfoVariantGroupCount = mainInfoVariantGroups.Count; 3360 if (mainInfoVariantGroupCount == 1) 3361 { 3362 var firstVariantGroup = Dynamicweb.Ecommerce.Services.VariantGroups.GetVariantGroup(Dynamicweb.Ecommerce.Common.Context.LanguageID, mainInfoVariantGroups[0]?.GetString("Ecom:VariantGroup.ID")); 3363 if (firstVariantGroup != null) 3364 { 3365 mainInfoIsFamilyMember = firstVariantGroup.Family; 3366 string variantId = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"); 3367 mainInfoIsFamilyMaster = string.IsNullOrEmpty(variantId); 3368 } 3369 } 3370 3371 bool mainInfoRenderVariantsAsProducts = mainInfoVariantsCount > 1 && Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList"); 3372 3373 if (mainInfoIsFamilyMember) 3374 { 3375 mainInfoRenderVariantsAsProducts = mainInfoVariantsCount > 1 && Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderFamilyVariantsAsProducts") && mainInfoIsFamilyMaster; 3376 } 3377 3378 if (Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout") != null && mainInfoVariantsCount > 1) 3379 { 3380 mainInfoRenderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout").SelectedValue != "hide" && Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("EnableVariantMatrix") ? true : mainInfoRenderVariantsAsProducts; 3381 } 3382 3383 Block mainInfoHeader = new Block() 3384 { 3385 Id = "MainInfoHeader", 3386 SortId = 10, 3387 Template = RenderMainInfoHeader() 3388 }; 3389 mainInfoPage.Add("MainInformation", mainInfoHeader); 3390 3391 Block mainInfoDescription = new Block() 3392 { 3393 Id = "ShortDescription", 3394 SortId = 20, 3395 Template = RenderShortDescription() 3396 }; 3397 mainInfoPage.Add("MainInformation", mainInfoDescription); 3398 3399 if (!mainInfoRenderVariantsAsProducts && !mainInfoIsFamilyMember) 3400 { 3401 Block mainInfoVariants = new Block() 3402 { 3403 Id = "Variants", 3404 SortId = 50, 3405 Template = RenderMainInfoVariants() 3406 }; 3407 mainInfoPage.Add("MainInformation", mainInfoVariants); 3408 } 3409 3410 Block mainInfoBOM = new Block() 3411 { 3412 Id = "BOM", 3413 SortId = 60, 3414 Template = RenderMainInfoBOM() 3415 }; 3416 mainInfoPage.Add("MainInformation", mainInfoBOM); 3417 3418 if (!mainInfoRenderVariantsAsProducts) 3419 { 3420 if (!hideAddToCartButton) 3421 { 3422 Block mainInfoBuy = new Block() 3423 { 3424 Id = "Buy", 3425 SortId = 80, 3426 Template = RenderMainInfoBuy() 3427 }; 3428 mainInfoPage.Add("MainInformation", mainInfoBuy); 3429 } 3430 } 3431 3432 if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && User.IsBuyingAllowed() && GetPageIdByNavigationTag("OrderDraft") != 0) { 3433 Modal selectDraftModal = new Modal 3434 { 3435 Id = "OrderDraftSelect", 3436 Heading = new Heading { Title = Translate("Select draft cart"), Level = 2 }, 3437 BodyTemplate = RenderOrderDraftSelectModalContent(), 3438 Width = ModalWidth.Md 3439 }; 3440 selectDraftModal.AddAction(new Button { Title = Translate("Cancel"), OnClick = "document.getElementById('OrderDraftSelectModalTrigger').checked = false", ButtonLayout = ButtonLayout.Secondary }); 3441 selectDraftModal.AddAction(new Button { Title = Translate("Add"), OnClick = "addToSelectedCart()" }); 3442 3443 Block orderDraftSelect = new Block 3444 { 3445 Id = "OrderDraft", 3446 SortId = 90, 3447 Component = selectDraftModal 3448 }; 3449 mainInfoPage.Add("MainInformation", orderDraftSelect); 3450 3451 Modal notificationDraftModal = new Modal 3452 { 3453 Id = "OrderDraftNotification", 3454 Heading = new Heading { Title = Translate("Added to cart"), Level = 2 }, 3455 BodyText = Translate("The product has been added to the selected cart"), 3456 Width = ModalWidth.Md 3457 }; 3458 notificationDraftModal.AddAction(new Button { Title = Translate("View draft"), OnClick = "goToSelectedCart()", ButtonLayout = ButtonLayout.Secondary }); 3459 notificationDraftModal.AddAction(new Button { Title = Translate("Continue shopping"), OnClick = "document.getElementById('OrderDraftNotificationModalTrigger').checked = false" }); 3460 3461 Block orderDraftComplete = new Block 3462 { 3463 Id = "OrderDraftComplete", 3464 SortId = 100, 3465 Component = notificationDraftModal 3466 }; 3467 mainInfoPage.Add("MainInformation", orderDraftComplete); 3468 3469 3470 Block orderDraftScripts = new Block 3471 { 3472 Id = "OrderDraftScripts", 3473 SortId = 110, 3474 Template = RenderOrderDraftScripts() 3475 }; 3476 mainInfoPage.Add("MainInformation", orderDraftScripts); 3477 3478 Block googleTagManagerScripts = new Block 3479 { 3480 Id = "GoogleTagManagerScripts", 3481 SortId = 120, 3482 Template = RenderGoogleTagManagerScripts() 3483 }; 3484 mainInfoPage.Add("MainInformation", googleTagManagerScripts); 3485 } 3486 } 3487 3488 @helper RenderMainInfoHeader() 3489 { 3490 bool renderVariantsAsProducts = GetInteger("Ecom:Product.VariantCount") > 1 && Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList"); 3491 if (Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout") != null && GetInteger("Ecom:Product.VariantCount") > 1) 3492 { 3493 renderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout").SelectedValue != "hide" && Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("EnableVariantMatrix") ? true : renderVariantsAsProducts; 3494 } 3495 3496 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 3497 string currentPrice = GetString("Ecom:Product.Discount.Price.PriceFormatted") == GetString("Ecom:Product.Price.PriceFormatted") ? GetString("Ecom:Product.Price.PriceFormatted") : GetString("Ecom:Product.Discount.Price.PriceFormatted"); 3498 bool hideFavorites = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideFavoriteButton"); 3499 bool hideProductNumber = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideProductNumber"); 3500 3501 bool useFontAwesomePro = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetBoolean("UseFontAwesomePro"); 3502 var selectedFavoriteIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon").SelectedValue : "star"; 3503 string favoriteIcon = "fas fa-" + selectedFavoriteIcon; 3504 string favoriteOutlineIcon = "fal fa-" + selectedFavoriteIcon; 3505 3506 <div> 3507 <div class="u-pull--left product__title dw-mod"> 3508 <h1 class="u-no-margin">@GetString("Ecom:Product.Name") </h1> 3509 <h2>@GetString("Ecom:Product.SelectedVariantComboName")</h2> 3510 3511 @if (!hideProductNumber) 3512 { 3513 <div class="item-number dw-mod">@GetString("Ecom:Product.Number")</div> 3514 } 3515 </div> 3516 <div class="u-pull--right"> 3517 @if (!hideFavorites && Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && !renderVariantsAsProducts) 3518 { 3519 string favoriteId = "Favorite" + GetString("Ecom:Product.ID"); 3520 <div id="@favoriteId" class="favorites favorites--md u-pull--right js-favorite-btn dw-mod"> 3521 <div> 3522 @{ 3523 string favorite = GetBoolean("Ecom:Product.IsProductInFavoriteList") ? favoriteIcon : favoriteOutlineIcon; 3524 string AddToWishlist = "fbq('track', 'AddToWishlist', {" + 3525 "content_name: '" + GetString("Ecom:Product.Name") + "'," + 3526 "content_ids: ['" + GetString("Ecom:Product.Number") + "']," + 3527 "value: " + GetDouble("Ecom:Product.Price.Price") + "," + 3528 "currency: '" + GetString("Ecom:Product.Price.Currency.Code") + "'" + 3529 "});"; 3530 } 3531 <label for="FavoriteTrigger"><i class="@favorite fa-1_5x"></i></label> 3532 </div> 3533 <input type="checkbox" id="FavoriteTrigger" class="dropdown-trigger" /> 3534 3535 <div class="dropdown"> 3536 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 3537 <ul class="list list--clean dw-mod"> 3538 @if (GetLoop("CustomerCenter.ListTypes").Count > 0) 3539 { 3540 foreach (LoopItem listType in GetLoop("CustomerCenter.ListTypes")) 3541 { 3542 foreach (LoopItem list in listType.GetLoop("CustomerCenter.ProductLists")) 3543 { 3544 string favLinkType = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? list.GetString("Ecom:Product.RemoveFromThisList") : list.GetString("Ecom:Product.AddToThisListAction"); 3545 string isInListIcon = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? favoriteIcon : favoriteOutlineIcon; 3546 <li> 3547 <a href="@favLinkType" class="list__link u-no-underline dw-mod" onclick="@(list.GetString("Ecom:Product.List.IsProductInThisList") != "True" && useFacebookPixel ? AddToWishlist : "")"><i class="@isInListIcon u-margin-right--lg"></i> @list.GetValue("Ecom:CustomerCenter.List.Name")</a> 3548 </li> 3549 } 3550 } 3551 } 3552 else 3553 { 3554 string favLinkType = GetString("Ecom:Product.AddToFavorites") + "&CCListType=0&CCCreateNewList=" + Translate("My favorites"); 3555 string isInListIcon = favoriteOutlineIcon; 3556 <li> 3557 <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> 3558 </li> 3559 } 3560 </ul> 3561 </div> 3562 <label class="dropdown-trigger-off" for="FavoriteTrigger"></label> 3563 </div> 3564 </div> 3565 } 3566 </div> 3567 </div> 3568 } 3569 3570 @helper RenderStockAndShipping() 3571 { 3572 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState"); 3573 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping"); 3574 3575 if (User.IsStockInfoAllowed()) 3576 { 3577 <text>{{#if stockText}}</text> 3578 <div class="product__stock-delivery dw-mod"> 3579 @if (!hideStockState) 3580 { 3581 <span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span> 3582 <span class="u-margin-right--lg"> {{stockText}}</span> 3583 } 3584 @if (!hideDelivery) 3585 { 3586 <text>{{deliveryText}}</text> 3587 } 3588 </div> 3589 <text>{{/if}}</text> 3590 } 3591 } 3592 3593 @helper RenderShortDescription() 3594 { 3595 if (!String.IsNullOrEmpty(GetString("Ecom:Product.ShortDescription"))) 3596 { 3597 Pageview.Meta.AddTag("og:description", GetString("Ecom:Product.ShortDescription")); 3598 3599 <div class="introduction-text"> 3600 @GetString("Ecom:Product.ShortDescription") 3601 </div> 3602 } 3603 } 3604 3605 @helper RenderMainInfoVariants() 3606 { 3607 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 3608 string productId = GetString("Ecom:Product.ID"); 3609 string variantSelection = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("variantId")) ? HttpContext.Current.Request.QueryString.Get("variantId").Replace(".", ",") : ""; 3610 string hideHelpText = ""; 3611 string variantsLayout = Pageview.AreaSettings.GetItem("Ecommerce").GetString("VariantsLayout") != null ? Pageview.AreaSettings.GetItem("Ecommerce").GetList("VariantsLayout").SelectedValue : "buttons"; 3612 3613 foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 3614 { 3615 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions")) 3616 { 3617 if (variantoption.GetBoolean("Ecom:VariantOption.Selected")) 3618 { 3619 hideHelpText = "u-hidden"; 3620 } 3621 } 3622 } 3623 3624 if (GetLoop("VariantGroups").Count > 0) 3625 { 3626 var variantCombinationsObject = new List<Array>(); 3627 foreach (LoopItem variantcomb in GetLoop("VariantCombinations")) 3628 { 3629 string[] combinations = variantcomb.GetString("Ecom:VariantCombination.VariantID").Split('.'); 3630 variantCombinationsObject.Add(combinations); 3631 } 3632 3633 string combinationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantCombinationsObject).Replace("\"", "\'"); 3634 3635 var variantGroupsObject = new List<List<String>>(); 3636 foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 3637 { 3638 var variantsObject = new List<String>(); 3639 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 3640 { 3641 variantsObject.Add(variantOption.GetString("Ecom:VariantOption.ID")); 3642 } 3643 variantGroupsObject.Add(variantsObject); 3644 } 3645 3646 string variantsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantGroupsObject).Replace("\"", "\'"); 3647 string productGroupId = HttpContext.Current.Request["GroupId"]; 3648 3649 <div> 3650 <div class="js-variants" data-total-variant-groups="@GetLoop("VariantGroups").Count" data-combinations="@combinationsJson" data-variants="@variantsJson" data-variant-selections="@variantSelection" data-selection-complete="UpdatePage" data-page-id="@pageId" data-product-id="@productId" data-group-id="@productGroupId"> 3651 @foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 3652 { 3653 string groupId = variantGroup.GetString("Ecom:VariantGroup.ID"); 3654 3655 <div> 3656 <div class="product__variant-group-name u-bold dw-mod">@variantGroup.GetString("Ecom:VariantGroup.Name")</div> 3657 <div class="u-margin-top"> 3658 @if (variantsLayout == "buttons") 3659 { 3660 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 3661 { 3662 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 3663 string color = !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Colorcode")) ? variantOption.GetString("Ecom:VariantOption.Colorcode") : null; 3664 color = color == null && !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Color")) ? variantOption.GetString("Ecom:VariantOption.Color") : color; 3665 3666 if (!String.IsNullOrEmpty(color)) 3667 { 3668 <button type="button" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" onclick="MatchVariants.SelectThis(event)" class="btn btn--colorbox u-margin-right @selected js-variant-option" data-check="@selected" style="background-color: @color"></button> 3669 } 3670 else 3671 { 3672 <button type="button" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" onclick="MatchVariants.SelectThis(event)" class="btn btn--tag @selected js-variant-option" data-check="@selected">@variantOption.GetString("Ecom:VariantOption.Name")</button> 3673 } 3674 } 3675 } 3676 else 3677 { 3678 <select id="VariantSelector_@groupId" class="u-full-width dw-mod" name="VariantSelector_@groupId" onchange="MatchVariants.SelectOnChange(event)" > 3679 <option>@Translate("Choose")</option> 3680 @foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 3681 { 3682 string check = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 3683 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "selected" : ""; 3684 string color = !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Colorcode")) ? variantOption.GetString("Ecom:VariantOption.Colorcode") : null; 3685 color = color == null && !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Color")) ? variantOption.GetString("Ecom:VariantOption.Color") : color; 3686 3687 <option class="js-variant-option @selected" id="@(groupId)_@variantOption.GetString("Ecom:VariantOption.ID")" value="@(groupId)_@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" @selected data-check="@check">@variantOption.GetString("Ecom:VariantOption.Name")</option> 3688 } 3689 </select> 3690 } 3691 </div> 3692 </div> 3693 } 3694 </div> 3695 <small class="js-help-text help-text @hideHelpText">@Translate("Please select variant!")</small> 3696 </div> 3697 } 3698 } 3699 3700 @helper RenderMainInfoBOM() 3701 { 3702 if (GetLoop("BOMProducts").Count > 0) 3703 { 3704 <h2 class="section-title">@Translate("Including products")</h2> 3705 foreach (LoopItem BOMProductItem in GetLoop("BOMProducts")) 3706 { 3707 string link = "/" + BOMProductItem.GetString("Ecom:Product.LinkGroup.Clean") + (!String.IsNullOrEmpty(BOMProductItem.GetString("Ecom:Product.VariantID")) ? "&VariantID=" + BOMProductItem.GetString("Ecom:Product.VariantID") : ""); 3708 <div class="grid__col--border grid"> 3709 <div class="grid__cell grid__cell--align-middle-left"> 3710 <a href="@link" class="u-pull--left u-margin-right"> 3711 <img class="b-lazy" src="/Files/Images/placeholder.gif" data-src="/Admin/Public/GetImage.ashx?width=50&image=@GetProductImage(BOMProductItem)&Compression=99&format=webp" alt="@BOMProductItem.GetString("Ecom:Product.Name")" /> 3712 </a> 3713 <a href="@link">@BOMProductItem.GetString("Ecom:Product.Name")</a> 3714 </div> 3715 </div> 3716 } 3717 } 3718 } 3719 3720 @helper RenderMainInfoBuy() 3721 { 3722 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 3723 string variantId = HttpContext.Current.Request.QueryString.Get("variantId"); 3724 string productId = GetString("Ecom:Product.ID"); 3725 string feedId = pageId + "&ProductID=" + productId + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 3726 3727 3728 <div class="product__price-actions js-handlebars-root dw-mod" id="PriceAndActions" data-template="PricesAndActionsTemplate" data-json-feed="/Default.aspx?ID=@feedId" data-preloader="minimal"></div> 3729 <input type="hidden" value="@GetString("Ecom:Product.VariantID.Extented")" name="Variant" id="Variant_@GetString("Ecom:Product.ID")" /> 3730 @RenderMainInfoBuyScripts() 3731 } 3732 3733 @helper RenderPriceInfo() 3734 { 3735 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 3736 bool showPrice = !Pageview.AreaSettings.GetItem("ProductList").GetBoolean("HidePrice"); 3737 bool showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 3738 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 3739 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 3740 3741 if (showPrice && Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 3742 { 3743 if (pointShopOnly) 3744 { 3745 <text> 3746 {{#if havePointPrice}} 3747 <div class="price price--product-page dw-mod">{{points}} @Translate("points")</div> 3748 @if (showCartButton) 3749 { 3750 <text> 3751 {{#unless canBePurchasedWithPoints}} 3752 <small class="help-text u-no-margin">@Translate("Not enough points to buy this")</small> 3753 {{/unless}} 3754 </text> 3755 } 3756 {{else}} 3757 @Translate("Not available") 3758 {{/if}} 3759 </text> 3760 3761 } 3762 else 3763 { 3764 <div class="price price--product-page dw-mod">{{price}}</div> 3765 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 3766 if (showVATPrice) 3767 { 3768 <div class="vat-price vat-price--product-page u-margin-top dw-mod"> 3769 @if (isPricesWithVATEnabled) 3770 { 3771 <span>@Translate("excl. VAT")</span><span> ({{priceWithoutVAT}})</span> 3772 } 3773 else 3774 { 3775 <span>@Translate("incl. VAT")</span><span> ({{priceWithVAT}})</span> 3776 } 3777 </div> 3778 } 3779 <text> 3780 {{#if priceRRP}} 3781 <div><small>@Translate("RRP") {{priceRRP}}</small></div> 3782 {{/if}} 3783 </text> 3784 } 3785 } 3786 } 3787 3788 @helper RenderMainInfoBuyScripts() 3789 { 3790 bool showPrice = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 3791 bool showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 3792 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 3793 string variantId = HttpContext.Current.Request.QueryString.Get("variantId") ?? ""; 3794 string feedId = GetGlobalValue("Global:Page.ID").ToString() + "&ProductID=" + GetString("Ecom:Product.ID") + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 3795 string cartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 3796 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("ShowBothPricesWithWithoutVAT"); 3797 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 3798 3799 var customerId = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId(); 3800 var shopId = Pageview.Area.EcomShopId; 3801 var orderType = Dynamicweb.Ecommerce.Orders.OrderType.Order; 3802 var cartsList = (List<Dynamicweb.Ecommerce.Orders.Order>)Dynamicweb.Ecommerce.Services.Orders.GetCustomerOrdersByType(customerId, shopId, orderType, 0, false, "", DateTime.MinValue, false, true); 3803 bool hidePrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 3804 3805 @* Handlebars templates *@ 3806 <script id="PricesAndActionsTemplate" type="text/x-template"> 3807 {{#.}} 3808 @if (Dynamicweb.Rapido.Services.User.IsPricesAllowed() && !hidePrice) 3809 { 3810 <div class="product__price-wrap dw-mod"> 3811 @RenderPriceInfo() 3812 </div> 3813 } 3814 3815 @if (showCartButton && Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 3816 { 3817 var addToCartBtn = new AddToCart 3818 { 3819 WrapperCssClass = "product__price-actions-flex-wrap buttons-collection--right dw-mod", 3820 AddButton = new AddToCartButton 3821 { 3822 ProductId = "{{productId}}", 3823 VariantId = "{{variantid}}", 3824 UnitId = "{{unitId}}", 3825 ProductInfo = "{{productInfo}}", 3826 BuyForPoints = pointShopOnly, 3827 OnClick = "{{facebookPixelAction}}", 3828 ExtraAttributes = new Dictionary<string, string> 3829 { 3830 { "{{disabledBuyButton}}", "" } 3831 }, 3832 CssClass = "product__price-buy-button" 3833 }, 3834 UnitSelector = new UnitSelector 3835 { 3836 OptionsContent = "{{#unitOptions}}{{>UnitOption}}{{/unitOptions}}", 3837 Id = "UnitOptions_{{id}}", 3838 SelectedOption = "{{unitName}}", 3839 CssClass = "{{#if hasOnlyOneUnit}}unit-selector--readonly{{/if}} {{hasUnits}}" 3840 } 3841 }; 3842 3843 if (!pointShopOnly) 3844 { 3845 addToCartBtn.QuantitySelector = new QuantitySelector 3846 { 3847 Id = "Quantity_{{id}}" 3848 }; 3849 } 3850 3851 <div class="product__price-actions-wrap dw-mod"> 3852 @Render(addToCartBtn) 3853 3854 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && User.IsBuyingAllowed() && cartsList.Count > 0 && GetPageIdByNavigationTag("OrderDraft") != 0) { 3855 var addToDraftCart = new Button 3856 { 3857 Id = "AddToDraftCart", 3858 Title = Translate("Add to draft"), 3859 ButtonLayout = ButtonLayout.Secondary, 3860 OnClick = "document.getElementById('OrderDraftSelectModalTrigger').checked = true", 3861 CssClass = "u-w220px u-margin-top" 3862 }; 3863 3864 @Render(addToDraftCart) 3865 } 3866 3867 @if (Pageview.User != null && !pointShopOnly && Dynamicweb.Security.Licensing.LicenseManager.LicenseHasFeature("LoyaltyPoints")) 3868 { 3869 <text> 3870 {{#if canBePurchasedWithPoints}} 3871 <form method="post" role="form" class="u-no-margin u-margin-top"> 3872 <input type="hidden" name="ProductID" value="{{id}}" /> 3873 <button type="submit" class="btn btn--loyalty-points product__price-points-buy-button u-no-margin dw-mod pull-right u-no-margin js-cart-btn {{disabledBuyButton}}" name="CartCmd" value="addWithPoints">@Translate("Buy for") {{points}} @Translate("points")</button> 3874 </form> 3875 {{/if}} 3876 </text> 3877 } 3878 </div> 3879 } 3880 else 3881 { 3882 <button type="button" id="CartButton_{{id}}" class="u-hidden"></button> 3883 } 3884 @RenderStockAndShipping() 3885 {{/.}} 3886 </script> 3887 3888 <script id="UnitOption" type="text/x-template"> 3889 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '{{link}}&feed=true&UnitID={{value}}')">{{name}}</div> 3890 </script> 3891 3892 <script> 3893 document.addEventListener("DOMContentLoaded", function () { 3894 if (document.getElementById("PriceAndActions")) { 3895 document.getElementById("PriceAndActions").addEventListener("contentLoaded", function (event) { 3896 if (document.querySelector(".js-variants") != null) { 3897 MatchVariants.Update(document.querySelector(".js-variants"), "DoNothing"); 3898 } 3899 }); 3900 } 3901 }); 3902 </script> 3903 } 3904 3905 @helper RenderOrderDraftSelectModalContent() { 3906 var customerId = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId(); 3907 var shopId = Pageview.Area.EcomShopId; 3908 var orderType = Dynamicweb.Ecommerce.Orders.OrderType.Order; 3909 var cartsList = (List<Dynamicweb.Ecommerce.Orders.Order>)Dynamicweb.Ecommerce.Services.Orders.GetCustomerOrdersByType(customerId, shopId, orderType, 0, false, "", DateTime.MinValue, false, true); 3910 3911 SelectField cartSelector = new SelectField 3912 { 3913 Id = "CartSelector", 3914 Label = Translate("I want to add this product to") 3915 }; 3916 3917 foreach (Dynamicweb.Ecommerce.Orders.Order cart in cartsList) { 3918 string name = !string.IsNullOrEmpty(cart.DisplayName) ? cart.DisplayName : cart.Id; 3919 cartSelector.Options.Add(new SelectFieldOption { Label = name, Value = cart.Id }); 3920 } 3921 3922 @Render(cartSelector) 3923 } 3924 3925 @helper RenderOrderDraftScripts() { 3926 string productId = GetString("Ecom:Product.ID"); 3927 string variantId = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"); 3928 string unitId = GetString("Ecom:Product.DefaultUnitID"); 3929 var cartCmdUrl = "/Default.aspx?ID=" + Pageview.Page.ID; 3930 int orderDraftPageId = GetPageIdByNavigationTag("DraftDetails"); 3931 int orderDraftParagraphId = Dynamicweb.Services.Paragraphs.GetParagraphsByPageId(orderDraftPageId).ToList().First().ID; 3932 3933 foreach (LoopItem unitOption in GetLoop("Units")) 3934 { 3935 if (unitOption.GetString("Ecom:VariantOption.Selected") == "SELECTED") 3936 { 3937 unitId = unitOption.GetString("Ecom:VariantOption.ID"); 3938 } 3939 } 3940 3941 <script> 3942 function addToSelectedCart() { 3943 var requestUrl = "@cartCmdUrl" + "&cartcmd=Add&Quantity=1" + "&CartId=" + document.getElementById("CartSelector").value + "&ProductId=@productId" + "&VariantId=@variantId" + "&UnitId=@unitId"; 3944 3945 console.log(requestUrl) 3946 3947 document.getElementById('OrderDraftSelectModalTrigger').checked = false; 3948 3949 var overlayElement = document.createElement('div'); 3950 overlayElement.className = "preloader-overlay"; 3951 overlayElement.setAttribute('id', "CartOverlay"); 3952 var overlayElementIcon = document.createElement('div'); 3953 overlayElementIcon.className = "preloader-overlay__icon dw-mod"; 3954 overlayElementIcon.style.top = window.pageYOffset + "px"; 3955 overlayElement.appendChild(overlayElementIcon); 3956 document.getElementById('content').parentNode.insertBefore(overlayElement, document.getElementById('content')); 3957 3958 Request.Fetch().get( 3959 requestUrl, 3960 function () { 3961 var overlayNode = document.getElementById('CartOverlay'); 3962 overlayNode.parentNode.removeChild(overlayNode); 3963 document.getElementById('OrderDraftNotificationModalTrigger').checked = true; 3964 }, 3965 null, 3966 false 3967 ); 3968 } 3969 3970 function goToSelectedCart() { 3971 window.location = "/Default.aspx?ID=" + "@orderDraftPageId" + "&CartID=" + document.getElementById('CartSelector').value + "&CartCmd=setcart" + "&redirect=false"; 3972 } 3973 </script> 3974 } 3975 3976 @helper RenderGoogleTagManagerScripts() { 3977 bool useGoogleTagManager = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("GoogleTagManagerID")); 3978 3979 if (useGoogleTagManager) 3980 { 3981 var groupObject = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(GetString("Ecom:Product.PrimaryOrFirstGroupID")); 3982 3983 <script> 3984 // Measure a view of product details. This example assumes the detail view occurs on pageload, 3985 // and also tracks a standard pageview of the details page. 3986 dataLayer.push({ 3987 'event': 'productDetails', 3988 "ecommerce": { 3989 "detail": { 3990 "currencyCode": "@GetString("Ecom:Product.Price.Currency.Code")", 3991 "actionField": {}, // 'detail' actions have an optional list property. 3992 "products": [{ 3993 "name": "@GetString("Ecom:Product.Name")", // Name or ID is required. 3994 "id": "@GetString("Ecom:Product.ID")", 3995 "price": "@(GetDouble("Ecom:Product.Discount.Price.Price") != GetDouble("Ecom:Product.Price.Price") ? GetDouble("Ecom:Product.Discount.Price.Price") : GetDouble("Ecom:Product.Price.Price"))", 3996 "brand": "@GetString("Ecom:Product:Field.brand.Value")", 3997 "category": "@(groupObject != null ? groupObject.Name : "")", 3998 "variant": "@(!string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"))" 3999 }] 4000 } 4001 } 4002 }); 4003 </script> 4004 } 4005 } 4006 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 4007 @using Dynamicweb.Core 4008 @using System 4009 @using System.Web 4010 @using System.Collections.Generic 4011 @using Dynamicweb.Rapido.Blocks 4012 @using Dynamicweb.Rapido.Blocks.Components.General 4013 4014 @functions { 4015 BlocksPage productAssetsPage = BlocksPage.GetBlockPage("Product"); 4016 } 4017 4018 @{ 4019 string productAssetsLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ProductAssetsLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductAssetsLayout").SelectedValue : "Section"; 4020 productAssetsLayout = productAssetsLayout == "Ribbon" ? "Section" : productAssetsLayout; 4021 4022 if (productAssetsLayout != "hide") 4023 { 4024 Block productAssetsBlock = new Block() 4025 { 4026 Name = productAssetsLayout != "MainInformation" ? Translate("Product assets") : "", 4027 Id = "ProductAssets", 4028 SortId = 10, 4029 Template = RenderProductAssets(productAssetsLayout, downloadDocuments), @*downloadDocuments variable, declared in Product.cshtml and defined in Fields.cshtml*@ 4030 Design = new Design 4031 { 4032 Size = "12", 4033 RenderType = RenderType.Column, 4034 HidePadding = true 4035 } 4036 }; 4037 productAssetsPage.Add(productAssetsLayout, productAssetsBlock); 4038 } 4039 } 4040 4041 @helper RenderProductAssets(string layout, List<LoopItem> documents) 4042 { 4043 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductAssetsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 4044 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductAssetsLayout").SelectedValue == "Ribbon" ? "u-padding--lg" : ""; 4045 string exportPageId = GetPageIdByNavigationTag("ProductExportFeed").ToString(); 4046 4047 //images 4048 4049 HashSet<string> images = new HashSet<string>(); 4050 4051 images.Add(GetProductImage()); 4052 4053 foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 4054 { 4055 string alt_image = alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 4056 4057 if (!string.IsNullOrEmpty(alt_image)) 4058 { 4059 images.Add(alt_image); 4060 } 4061 } 4062 4063 foreach (LoopItem detail in GetLoop("Details")) 4064 { 4065 string detail_image = detail.GetString("Ecom:Product:Detail.Image.Clean"); 4066 4067 if (!string.IsNullOrEmpty(detail_image)) 4068 { 4069 images.Add(detail_image); 4070 } 4071 } 4072 4073 <div class="product__section @ribbonClasses dw-mod"> 4074 <div class="product__description center-container @ribbonSubClasses dw-mod"> 4075 @if (layout == "Section") 4076 { 4077 @Render(new Heading { Title = Translate("Product assets"), Level = 2 }) 4078 } 4079 4080 <form action="/Default.aspx?ID=@exportPageId&ProductIds=@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"> 4081 <div class="grid"> 4082 @if (images.Count > 0) 4083 { 4084 <div class="grid__col-md-4 js-checkboxes-list"> 4085 @Render(new CheckboxField { Id = "allImages", OnChange = "selectAll(this)", Label = Translate("Images") + "(" + images.Count + ")" }) 4086 4087 <ul class="panel-list"> 4088 @foreach (string image in images) 4089 { 4090 @RenderProductPanelListItem(image) 4091 } 4092 </ul> 4093 </div> 4094 } 4095 4096 @if (documents.Count > 0) 4097 { 4098 <div class="grid__col-md-4 js-checkboxes-list"> 4099 @Render(new CheckboxField { Id = "allDocuments", OnChange = "selectAll(this)", Label = Translate("Documents") + "(" + documents.Count + ")" }) 4100 4101 <ul class="panel-list"> 4102 @foreach (LoopItem document in documents) 4103 { 4104 string fieldValue; 4105 if (!string.IsNullOrEmpty(document.GetString("Document.FullPath"))) 4106 { 4107 fieldValue = document.GetString("Product.CustomField.Value.Clean"); 4108 @RenderDocument(fieldValue) 4109 } 4110 if (document.GetString("Ecom:Product.CategoryField.TypeID") == "9") 4111 { 4112 fieldValue = document.GetString("Ecom:Product.CategoryField.Value"); 4113 @RenderDocument(fieldValue) 4114 } 4115 if (!string.IsNullOrEmpty(document.GetString("Ecom:Product:Detail.Image.Clean"))) 4116 { 4117 fieldValue = document.GetString("Ecom:Product:Detail.Image.Clean"); 4118 @RenderDocument(fieldValue) 4119 } 4120 } 4121 </ul> 4122 </div> 4123 } 4124 <div class="grid__col-md-4"> 4125 @Render(new HiddenField { Id = "ID", Name = "ID", Value = "532" }) 4126 @Render(new HiddenField { Id = "download", Name = "download", Value = "true" }) 4127 @Render(new HiddenField { Id = "siteUrl", Name = "siteUrl", Value = string.Format("{0}://{1}", GetGlobalValue("Global:Request.Scheme"), GetGlobalValue("Global:Request.Host")) }) 4128 4129 <div class="u-bold u-margin-bottom">@Translate("Export")</div> 4130 4131 @{ 4132 SelectField languageSelect = new SelectField 4133 { 4134 Id = "exportLanguage", 4135 Label = Translate("Language"), 4136 Name = "RequestLanguageId", 4137 CssClass = "u-full-width" 4138 }; 4139 foreach (var lang in Dynamicweb.Ecommerce.Services.Languages.GetLanguages().OrderBy(l => l.Name)) 4140 { 4141 var selected = lang.IsDefault ? true : false; 4142 languageSelect.Options.Add(new SelectFieldOption { Label = lang.Name, Value = lang.LanguageId, Checked = selected }); 4143 } 4144 @Render(languageSelect) 4145 4146 SelectField purposeSelect = new SelectField 4147 { 4148 Id = "purpose", 4149 Label = Translate("Image purpose"), 4150 Name = "purpose", 4151 CssClass = "u-full-width" 4152 }; 4153 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Office"), Value = "Office" }); 4154 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Original"), Value = "Original" }); 4155 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Print"), Value = "Print" }); 4156 purposeSelect.Options.Add(new SelectFieldOption { Label = Translate("Web"), Value = "Web" }); 4157 @Render(purposeSelect) 4158 4159 SelectField formatSelect = new SelectField 4160 { 4161 Id = "exportFormat", 4162 Label = Translate("Export format"), 4163 Name = "format", 4164 CssClass = "u-full-width" 4165 }; 4166 formatSelect.Options.Add(new SelectFieldOption { Label = Translate("Csv"), Value = "csv" }); 4167 formatSelect.Options.Add(new SelectFieldOption { Label = Translate("Json"), Value = "json" }); 4168 formatSelect.Options.Add(new SelectFieldOption { Label = Translate("Xml"), Value = "xml" }); 4169 @Render(formatSelect) 4170 } 4171 4172 @Render(new Button { ButtonType = ButtonType.Submit, ButtonLayout = ButtonLayout.Primary, CssClass = "btn--full u-no-margin", Title = Translate("Download") }) 4173 </div> 4174 </div> 4175 </form> 4176 </div> 4177 </div> 4178 <script> 4179 function selectAll(checkbox) { 4180 checkbox.closest(".js-checkboxes-list").querySelectorAll(".js-checkbox").forEach(function (input) { 4181 input.checked = checkbox.checked; 4182 }); 4183 } 4184 </script> 4185 } 4186 4187 @helper RenderProductPanelListItem(string imageName) 4188 { 4189 <li class="panel-list__item"> 4190 <div class="panel-list__item-check"> 4191 <input id="Image_@imageName" name="Image_@imageName" type="checkbox" class="form__control u-no-margin dw-mod js-checkbox" /> 4192 <label for="Image_@imageName"></label> 4193 </div> 4194 <div class="panel-list__item-image"> 4195 <label for="Image_@imageName" class="u-no-margin"> 4196 @Render(new Image { Path = imageName, Title = Path.GetFileName(imageName), ImageDefault = new ImageSettings { Width = 55, Height = 55, Crop = 5, FillCanvas = true } }) 4197 </label> 4198 </div> 4199 <div class="panel-list__item-name"> 4200 <label for="Image_@imageName" class="u-truncate-text u-w170px" title="@Path.GetFileName(imageName)"> 4201 @Path.GetFileName(imageName) 4202 </label> 4203 </div> 4204 </li> 4205 } 4206 4207 @helper RenderDocument(string fieldValue) 4208 { 4209 <li class="panel-list__item"> 4210 <div class="panel-list__item-check"> 4211 <input id="Document_@fieldValue" name="Document_@fieldValue" type="checkbox" class="form__control u-no-margin js-checkbox dw-mod"> 4212 <label for="Document_@fieldValue"></label> 4213 </div> 4214 <div class="panel-list__item-name"> 4215 <label for="Document_@fieldValue" class="u-truncate-text u-no-margin u-max-w220px" title="@Path.GetFileName(fieldValue)"> 4216 @Path.GetFileName(fieldValue) 4217 </label> 4218 </div> 4219 </li> 4220 } 4221 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 4222 @using Dynamicweb.Core 4223 @using System 4224 @using System.Web 4225 @using System.Collections.Generic 4226 @using Dynamicweb.Rapido.Blocks 4227 @using Dynamicweb.Rapido.Blocks.Components.General 4228 4229 @functions { 4230 BlocksPage productGeneratePDFPage = BlocksPage.GetBlockPage("Product"); 4231 } 4232 4233 @{ 4234 string generatePDFLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("GeneratePDFLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("GeneratePDFLayout").SelectedValue : "Section"; 4235 generatePDFLayout = generatePDFLayout == "Ribbon" ? "Section" : generatePDFLayout; 4236 4237 if (GetPageIdByNavigationTag("ProductPagePDFTemplates") > 0 && generatePDFLayout != "hide") 4238 { 4239 Block generatePDFBlock = new Block() 4240 { 4241 Name = generatePDFLayout != "MainInformation" ? Translate("Generate PDF") : "", 4242 Id = "GeneratePDF", 4243 SortId = 10, 4244 Template = RenderGeneratePDF(generatePDFLayout), 4245 Design = new Design 4246 { 4247 Size = "12", 4248 RenderType = RenderType.Column, 4249 HidePadding = true 4250 } 4251 }; 4252 4253 productGeneratePDFPage.Add(generatePDFLayout, generatePDFBlock); 4254 } 4255 } 4256 4257 @helper RenderGeneratePDF(string layout) 4258 { 4259 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("GeneratePDFLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 4260 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 4261 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("GeneratePDFLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 4262 string exportPageId = GetPageIdByNavigationTag("ProductExportFeed").ToString(); 4263 int pdfFolderId = GetPageIdByNavigationTag("ProductPagePDFTemplates"); 4264 4265 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" }; 4266 form.Add(new HiddenField { Name = "siteUrl", Value = string.Format("{0}://{1}", GetGlobalValue("Global:Request.Scheme"), GetGlobalValue("Global:Request.Host")) }); 4267 4268 //Select languages 4269 SelectField languagesList = new SelectField 4270 { 4271 Id = "RequestLanguageID", 4272 Name = "RequestLanguageID", 4273 Label = Translate("Language"), 4274 CssClass = "u-full-width" 4275 }; 4276 4277 foreach (var lang in Dynamicweb.Ecommerce.Services.Languages.GetLanguages().OrderBy(l => l.Name)) 4278 { 4279 languagesList.Options.Add(new SelectFieldOption 4280 { 4281 Label = lang.Name, 4282 Value = lang.LanguageId, 4283 Checked = lang.IsDefault ? true : false 4284 }); 4285 } 4286 form.Add(languagesList); 4287 4288 //Select pages 4289 SelectField pagesList = new SelectField 4290 { 4291 Id = "PDFTemplate", 4292 Name = "ID", 4293 Label = Translate("Generate PDF"), 4294 CssClass = "u-full-width" 4295 }; 4296 4297 foreach (Dynamicweb.Content.Page page in ServiceLocator.Current.GetPageService().GetPagesByParentID(pdfFolderId)) 4298 { 4299 pagesList.Options.Add(new SelectFieldOption 4300 { 4301 Label = page.MenuText, 4302 Value = Converter.ToString(page.ID) 4303 }); 4304 } 4305 form.Add(pagesList); 4306 4307 form.Add(new Button { ButtonType = ButtonType.Submit, Title = Translate("Generate PDF"), CssClass = "btn--full u-no-margin" }); 4308 4309 <div class="product__section @ribbonClasses grid dw-mod"> 4310 <div class="dw-mod grid__col-md-4 @ribbonSubClasses"> 4311 @if (layout == "Section") 4312 { 4313 @Render(new Heading { Title = Translate("Generate PDF"), Level = 2 }) 4314 } 4315 @Render(form) 4316 </div> 4317 </div> 4318 } 4319 4320 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 4321 @using Dynamicweb.Core 4322 @using System 4323 @using System.Web 4324 @using System.Collections.Generic 4325 @using Dynamicweb.Rapido.Blocks 4326 @using Dynamicweb.Rapido.Blocks.Components.General 4327 4328 @functions { 4329 BlocksPage productDescriptionPage = BlocksPage.GetBlockPage("Product"); 4330 } 4331 4332 @{ 4333 string fullDesctiptionLayout = !String.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("FullDescriptionLayout")) ? Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue : "Section"; 4334 fullDesctiptionLayout = fullDesctiptionLayout == "Ribbon" ? "Section" : fullDesctiptionLayout; 4335 4336 if (!string.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && fullDesctiptionLayout != "hide") 4337 { 4338 Block detailsDescription = new Block() 4339 { 4340 Name = fullDesctiptionLayout != "MainInformation" ? Translate("Description") : "", 4341 Id = "FullDescription", 4342 SortId = 30, 4343 Template = RenderProductDescription(fullDesctiptionLayout), 4344 Design = new Design 4345 { 4346 Size = "12", 4347 RenderType = RenderType.Column, 4348 HidePadding = true 4349 } 4350 }; 4351 productDescriptionPage.Add(fullDesctiptionLayout, detailsDescription); 4352 } 4353 } 4354 4355 @helper RenderProductDescription(string layout) 4356 { 4357 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 4358 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 4359 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 4360 4361 <div class="product__section @ribbonClasses dw-mod"> 4362 <div class="product__description center-container @ribbonSubClasses dw-mod"> 4363 @if (layout == "Section") { 4364 @Render(new Heading { Title = Translate("Description"), Level = 2 }) 4365 } 4366 @Render(new Text { Content = GetString("Ecom:Product.LongDescription") }) 4367 </div> 4368 </div> 4369 } 4370 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 4371 @using Dynamicweb.Core 4372 @using System 4373 @using System.Web 4374 @using System.Globalization; 4375 @using System.Collections.Generic 4376 @using Dynamicweb.Rapido.Blocks 4377 4378 @functions { 4379 BlocksPage productFieldsPage = BlocksPage.GetBlockPage("Product"); 4380 4381 static string ConvertBytes(long bytes) 4382 { 4383 double size = bytes / 1024; //KB 4384 if (size > 1024) 4385 { 4386 size = (bytes / 1024f) / 1024f; //MB 4387 return string.Format("{0:n1} MB", size); 4388 } 4389 else 4390 { 4391 return string.Format("{0:n0} KB", size); 4392 } 4393 } 4394 4395 static bool isImage(string path) 4396 { 4397 return new List<string> { ".jpg", ".jpeg", ".gif", ".png", ".svg" }.Contains(Path.GetExtension(path).ToLower()); 4398 } 4399 4400 string getIconForFile(string fileName) 4401 { 4402 string ext = Path.GetExtension(fileName); 4403 string icon = ""; 4404 switch (ext.ToLower()) 4405 { 4406 case ".xls": 4407 case ".xlsx": 4408 icon = "fa-file-excel"; 4409 break; 4410 case ".ppt": 4411 case ".pptx": 4412 icon = "fa-file-powerpoint"; 4413 break; 4414 case ".doc": 4415 case ".docx": 4416 icon = "fa-file-word"; 4417 break; 4418 case ".jpg": 4419 case ".jpeg": 4420 case ".png": 4421 case ".gif": 4422 case ".pdf": 4423 return "<img class='product__document-img' alt='" + fileName + "' src='/Admin/Public/GetImage.ashx?crop=5&height=70&width=120&format=webp&Compression=75&DoNotUpscale=true&image=" + fileName + "' />"; 4424 default: 4425 icon = "fa-file"; 4426 break; 4427 } 4428 return "<i class='product__document-icon far " + icon + "'></i> "; 4429 } 4430 } 4431 4432 @*downloadDocuments variable, declared in Product.cshtml - this variable also will be used in ProductAssets.cshtml*@ 4433 4434 4435 4436 @{ 4437 var selectedDownloadCategories = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadAssets").SelectedValues; 4438 var downloadsFromAssets = GetLoop("ImageCategories").Where(x => selectedDownloadCategories.Contains(x.GetString("Category.Id"))); 4439 4440 if (string.IsNullOrEmpty(selectedDownloadCategories.ToString())) { 4441 foreach (LoopItem customField in GetLoop("CustomFieldValues")) 4442 { 4443 if (!string.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) && !string.IsNullOrEmpty(customField.GetString("Product.CustomField.Value.Clean")) && customField.GetString("Product.CustomField.Name") != "Custom sticker" && customField.GetString("Product.CustomField.Name") != "RRP") 4444 { 4445 if (!string.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 4446 { 4447 downloadDocuments.Add(customField); 4448 } 4449 } 4450 } 4451 4452 foreach (LoopItem customField in GetLoop("ProductCategories")) 4453 { 4454 foreach (LoopItem field in customField.GetLoop("ProductCategoryFields")) 4455 { 4456 if (!string.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Label")) && !string.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Value"))) 4457 { 4458 if (field.GetString("Ecom:Product.CategoryField.TypeID") == "9") 4459 { 4460 downloadDocuments.Add(field); 4461 } 4462 } 4463 } 4464 } 4465 } else { 4466 foreach (LoopItem category in downloadsFromAssets) { 4467 foreach (LoopItem asset in category.GetLoop("Category.Images")) { 4468 downloadDocuments.Add(asset); 4469 } 4470 } 4471 } 4472 4473 bool collectAllDownloads = Pageview.AreaSettings.GetItem("ProductPage").GetString("CollectAllDownloads") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("CollectAllDownloads") : true; 4474 string detailFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsLayout").SelectedValue : "Section"; 4475 detailFieldsLayout = detailFieldsLayout == "Ribbon" || string.IsNullOrEmpty(detailFieldsLayout) ? "Section" : detailFieldsLayout; 4476 string categoryFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsLayout").SelectedValue : "Section"; 4477 categoryFieldsLayout = categoryFieldsLayout == "Ribbon" || string.IsNullOrEmpty(categoryFieldsLayout) ? "Section" : categoryFieldsLayout; 4478 string displayGroupsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("DisplayGroupsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DisplayGroupsLayout").SelectedValue : "Section"; 4479 displayGroupsLayout = displayGroupsLayout == "Ribbon" || string.IsNullOrEmpty(displayGroupsLayout) ? "Section" : displayGroupsLayout; 4480 string downloadsFieldsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsLayout").SelectedValue : "Section"; 4481 downloadsFieldsLayout = downloadsFieldsLayout == "Ribbon" || string.IsNullOrEmpty(downloadsFieldsLayout) ? "Section" : downloadsFieldsLayout; 4482 4483 string detailFieldsView = Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DetailFieldsView").SelectedValue : "grid"; 4484 string categoryFieldsView = Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("CategoryFieldsView").SelectedValue : "grid"; 4485 string downloadsFieldsView = Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsFieldsView") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("DownloadsFieldsView").SelectedValue : "grid"; 4486 4487 if (GetLoop("CustomFieldValues").Count > 0 && detailFieldsLayout != "hide") 4488 { 4489 if (string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ProductDetailFields"))) { 4490 Block detailsCustom = new Block() 4491 { 4492 Name = detailFieldsLayout != "MainInformation" ? Translate("Details") : "", 4493 Id = "CustomFields", 4494 SortId = 30, 4495 Design = new Design 4496 { 4497 Size = "12", 4498 RenderType = RenderType.Column, 4499 HidePadding = true 4500 } 4501 }; 4502 4503 detailsCustom.Template = RenderProductSection(detailFieldsLayout, detailFieldsView, Translate("Information"), RenderCustomFields(GetLoop("CustomFieldValues"), detailFieldsView)); 4504 productFieldsPage.Add(detailFieldsLayout, detailsCustom); 4505 } else { 4506 var detailFieldsDisplayGroups = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductDetailFields").SelectedValues; 4507 var displayGroups = GetLoop("FieldDisplayGroups").Where(x => detailFieldsDisplayGroups.Contains(x.GetString("Ecom:FieldDisplayGroup.ID"))); 4508 4509 foreach (var group in displayGroups) { 4510 Block detailsCustom = new Block() 4511 { 4512 Name = detailFieldsLayout != "MainInformation" ? group.GetString("Ecom:FieldDisplayGroup.Name") : "", 4513 Id = "DetailFields_" + group.GetString("Ecom:FieldDisplayGroup.ID"), 4514 SortId = 30, 4515 Design = new Design 4516 { 4517 Size = "12", 4518 RenderType = RenderType.Column, 4519 HidePadding = true 4520 } 4521 }; 4522 4523 detailsCustom.Template = RenderProductSection(detailFieldsLayout, detailFieldsView, Translate("Information"), RenderDetailsFields(group.GetLoop("Fields"), detailFieldsView)); 4524 productFieldsPage.Add(detailFieldsLayout, detailsCustom); 4525 } 4526 } 4527 } 4528 4529 if (categoryFieldsLayout != "hide") 4530 { 4531 foreach (LoopItem categoryGroup in GetLoop("ProductCategories")) 4532 { 4533 bool hasFields = categoryGroup.GetLoop("ProductCategoryFields").FirstOrDefault(cf => !string.IsNullOrEmpty(cf.GetString("Ecom:Product.CategoryField.Value"))) != null; 4534 4535 if (collectAllDownloads) 4536 { 4537 int downloadableCount = 0; 4538 foreach (LoopItem field in categoryGroup.GetLoop("ProductCategoryFields")) 4539 { 4540 if (field.GetString("Ecom:Product.CategoryField.TypeID") == "9") 4541 { 4542 downloadableCount++; 4543 } 4544 } 4545 4546 if (downloadableCount == categoryGroup.GetLoop("ProductCategoryFields").Count) 4547 { 4548 hasFields = false; 4549 } 4550 } 4551 4552 if (hasFields) 4553 { 4554 Block detailsCategoryFields = new Block() 4555 { 4556 Name = categoryFieldsLayout != "MainInformation" ? categoryGroup.GetString("Ecom:Product.Category.Name") : "", 4557 Id = ToPascalCase(categoryGroup.GetString("Ecom:Product.Category.Name")), 4558 SortId = 40, 4559 Template = RenderProductSection(categoryFieldsLayout, categoryFieldsView, categoryGroup.GetString("Ecom:Product.Category.Name"), RenderProductCategoryFields(categoryGroup.GetLoop("ProductCategoryFields"), categoryFieldsView)), 4560 Design = new Design 4561 { 4562 Size = "12", 4563 RenderType = RenderType.Column, 4564 HidePadding = true 4565 } 4566 }; 4567 4568 productFieldsPage.Add(categoryFieldsLayout, detailsCategoryFields); 4569 } 4570 } 4571 } 4572 4573 if (displayGroupsLayout != "hide") 4574 { 4575 var detailFieldsDisplayGroups = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductDetailFields").SelectedValues; 4576 var displayGroups = GetLoop("FieldDisplayGroups").Where(x => !detailFieldsDisplayGroups.Contains(x.GetString("Ecom:FieldDisplayGroup.ID"))); 4577 4578 foreach (LoopItem group in displayGroups) 4579 { 4580 Block displayGroup = new Block() 4581 { 4582 Name = displayGroupsLayout != "MainInformation" ? group.GetString("Ecom:FieldDisplayGroup.Name") : "", 4583 Id = "DisplayGroup_" + group.GetString("Ecom:FieldDisplayGroup.ID"), 4584 SortId = 40, 4585 Template = RenderProductSection(displayGroupsLayout, categoryFieldsView, group.GetString("Ecom:FieldDisplayGroup.Name"), RenderDetailsFields(group.GetLoop("Fields"), categoryFieldsView)), 4586 Design = new Design 4587 { 4588 Size = "12", 4589 RenderType = RenderType.Column, 4590 HidePadding = true 4591 } 4592 }; 4593 4594 productFieldsPage.Add(displayGroupsLayout, displayGroup); 4595 } 4596 } 4597 4598 if (downloadDocuments.Count > 0 && downloadsFieldsLayout != "hide" && collectAllDownloads == true) 4599 { 4600 Block detailsDownloads = new Block() 4601 { 4602 Name = downloadsFieldsLayout != "MainInformation" ? Translate("Downloads") : "", 4603 Id = "StandardDownloads", 4604 SortId = 50, 4605 Template = RenderProductSection(downloadsFieldsLayout, downloadsFieldsView, Translate("Downloads"), RenderProductDownloadsFields(downloadDocuments, downloadsFieldsView)), 4606 Design = new Design 4607 { 4608 Size = "12", 4609 RenderType = RenderType.Column, 4610 HidePadding = true 4611 } 4612 }; 4613 4614 productFieldsPage.Add(downloadsFieldsLayout, detailsDownloads); 4615 } 4616 } 4617 4618 @helper RenderCustomFields(List<LoopItem> fieldsLoop, string viewType) 4619 { 4620 bool collectAllDownloads = Pageview.AreaSettings.GetItem("ProductPage").GetString("CollectAllDownloads") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("CollectAllDownloads") : true; 4621 4622 foreach (LoopItem customField in fieldsLoop) 4623 { 4624 string fieldValue = customField.GetString("Product.CustomField.Value.Clean"); 4625 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 4626 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 4627 4628 if (customField.GetLoop("Product.CustomField.Options").Count > 0) 4629 { 4630 List<string> accumulatedValues = new List<string> (); 4631 4632 foreach (var option in customField.GetLoop("Product.CustomField.Options")) 4633 { 4634 if (option.GetBoolean("Product.CustomField.Option.IsSelected")) 4635 { 4636 accumulatedValues.Add(option.GetString("Product.CustomField.Option.Name")); 4637 } 4638 } 4639 fieldValue = string.Join(", ", accumulatedValues); 4640 } 4641 4642 if (!string.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) && !string.IsNullOrEmpty(fieldValue) && customField.GetString("Product.CustomField.Name") != "Custom sticker" && customField.GetString("Product.CustomField.Name") != "RRP") 4643 { 4644 if (string.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 4645 { 4646 @RenderFieldItem(customField.GetString("Product.CustomField.Name"), fieldValue, viewType); 4647 } 4648 else if (collectAllDownloads == false) 4649 { 4650 @RenderFieldItem(customField.GetString("Product.CustomField.Name"), fieldValue, viewType, "download"); 4651 } 4652 } 4653 } 4654 } 4655 4656 @helper RenderProductSection(string layout, string viewType, string name, RazorEngine.Templating.TemplateWriter writer) 4657 { 4658 string ribbonClasses = layout == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "u-no-padding"; 4659 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 4660 string ribbonSubClasses = layout == "Ribbon" ? "center-container--ribbon" : ""; 4661 4662 4663 <div class="product__section @ribbonClasses dw-mod"> 4664 <div class="center-container @ribbonSubClasses dw-mod"> 4665 @if (layout == "Section") 4666 { 4667 @Render(new Heading { Title = name, Level = 2 }) 4668 } 4669 4670 @if (viewType != "table") 4671 { 4672 <div class="grid grid--bleed u-margin-bottom--lg"> 4673 @writer 4674 </div> 4675 } 4676 else 4677 { 4678 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12"; 4679 4680 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 4681 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12"> 4682 <table class="table--no-top-border"> 4683 @writer 4684 </table> 4685 </div> 4686 </div> 4687 } 4688 </div> 4689 </div> 4690 } 4691 4692 @helper RenderProductCategoryFields(List<LoopItem> fieldsLoop, string viewType) 4693 { 4694 bool collectAllDownloads = Pageview.AreaSettings.GetItem("ProductPage").GetString("CollectAllDownloads") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("CollectAllDownloads") : true; 4695 4696 foreach (LoopItem categoryField in fieldsLoop) 4697 { 4698 string fieldValue = categoryField.GetString("Ecom:Product.CategoryField.Value"); 4699 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 4700 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 4701 4702 if (!string.IsNullOrEmpty(categoryField.GetString("Ecom:Product.CategoryField.Label")) && !string.IsNullOrEmpty(fieldValue)) 4703 { 4704 if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") != "9" || collectAllDownloads == false) 4705 { 4706 if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") == "15") 4707 { 4708 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), categoryField.GetString("Ecom:Product.CategoryField.OptionLabel"), viewType); 4709 } 4710 else if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") == "8") 4711 { 4712 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType, "link"); 4713 } 4714 else if (categoryField.GetString("Ecom:Product.CategoryField.TypeID") == "9") 4715 { 4716 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType, "download"); 4717 } 4718 else 4719 { 4720 @RenderFieldItem(categoryField.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType); 4721 } 4722 } 4723 } 4724 } 4725 } 4726 4727 @helper RenderDetailsFields(IEnumerable<LoopItem> fields, string viewType) 4728 { 4729 foreach (LoopItem field in fields) 4730 { 4731 string fieldValue = field.GetString("Ecom:FieldDisplayGroup.Field.Value"); 4732 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 4733 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 4734 4735 if (!string.IsNullOrEmpty(field.GetString("Ecom:FieldDisplayGroup.Field.Name")) && !string.IsNullOrEmpty(fieldValue)) 4736 { 4737 if (field.GetString("Ecom:FieldDisplayGroup.Field.TypeId") == "15") 4738 { 4739 @RenderFieldItem(field.GetString("Ecom:FieldDisplayGroup.Field.Name"), field.GetString("Ecom:FieldDisplayGroup.Field.OptionLabel"), viewType); 4740 } 4741 else if (field.GetString("Ecom:FieldDisplayGroup.Field.TypeId") == "8") 4742 { 4743 @RenderFieldItem(field.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType, "link"); 4744 } 4745 else if (field.GetString("Ecom:FieldDisplayGroup.Field.TypeId") == "9") 4746 { 4747 @RenderFieldItem(field.GetString("Ecom:FieldDisplayGroup.Field.Name"), fieldValue, viewType, "download"); 4748 } 4749 else 4750 { 4751 @RenderFieldItem(field.GetString("Ecom:FieldDisplayGroup.Field.Name"), fieldValue, viewType); 4752 } 4753 } 4754 } 4755 } 4756 4757 @helper RenderProductDownloadsFields(List<LoopItem> fieldsLoop, string viewType) 4758 { 4759 foreach (LoopItem document in fieldsLoop) 4760 { 4761 string fieldValue; 4762 if (!string.IsNullOrEmpty(document.GetString("Document.FullPath"))) 4763 { 4764 fieldValue = document.GetString("Product.CustomField.Value.Clean"); 4765 @RenderFieldItem(fieldValue, document.GetString("Document.FullPath"), viewType, "download") 4766 } 4767 4768 if (document.GetString("Ecom:Product.CategoryField.TypeID") == "9") 4769 { 4770 fieldValue = document.GetString("Ecom:Product.CategoryField.Value"); 4771 @RenderFieldItem(fieldValue, fieldValue, viewType, "download") 4772 } 4773 if (!string.IsNullOrEmpty(document.GetString("Ecom:Product:Detail.Image.Clean"))) 4774 { 4775 fieldValue = document.GetString("Ecom:Product:Detail.Image.Clean"); 4776 @RenderFieldItem("", fieldValue, viewType, "download") 4777 } 4778 } 4779 } 4780 4781 @helper RenderFieldItem(string name, string value, string viewType, string fieldType = "clean") 4782 { 4783 if (viewType != "table") 4784 { 4785 string fieldColumns = viewType == "list" ? "12" : "4"; 4786 <div class="grid__col-md-@fieldColumns grid__col-sm-12 u-margin-bottom"> 4787 <div class="u-bold"> 4788 @name 4789 </div> 4790 <div> 4791 @RenderFieldItemContent(name, value, fieldType) 4792 </div> 4793 </div> 4794 } 4795 else 4796 { 4797 <tr> 4798 <th>@name</th> 4799 <td> 4800 @RenderFieldItemContent(name, value, fieldType) 4801 </td> 4802 </tr> 4803 } 4804 } 4805 4806 @helper RenderFieldItemContent(string name, string value, string fieldType = "clean") 4807 { 4808 if (fieldType == "link") 4809 { 4810 <a target="_blank" rel="noopener" href="@value"> 4811 @if (isImage(value)) 4812 { 4813 @getIconForFile(value) 4814 } 4815 else 4816 { 4817 @value 4818 } 4819 </a> 4820 } 4821 else if (fieldType == "download") 4822 { 4823 FileInfo info = new FileInfo(Dynamicweb.Core.SystemInformation.MapPath(value)); 4824 4825 if (info.Exists) 4826 { 4827 <div class="grid grid--no-wrap"> 4828 <a href="@value" download title="@Translate("Download")" class="product__document dw-mod">@getIconForFile(value)</a> 4829 <div class="product__document-info dw-mod"> 4830 <a href="@value" download title="@Translate("Download")" class="product__document dw-mod">@Path.GetFileName(value)</a> 4831 <small class="u-block u-margin-top">@ConvertBytes(info.Length)</small> 4832 </div> 4833 </div> 4834 } 4835 } 4836 else 4837 { 4838 @value 4839 } 4840 } 4841 4842 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 4843 @using Dynamicweb.Core 4844 @using System.Text.RegularExpressions 4845 @using System 4846 @using System.Web 4847 @using System.Collections.Generic 4848 @using Dynamicweb.Rapido.Blocks 4849 @using Dynamicweb.Rapido.Blocks.Components.General 4850 4851 @functions{ 4852 BlocksPage productVideoPage = BlocksPage.GetBlockPage("Product"); 4853 } 4854 4855 @{ 4856 var selectedVideoCategories = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideoAssets").SelectedValues; 4857 var videosFromAssets = GetLoop("ImageCategories").Where(x => selectedVideoCategories.Contains(x.GetString("Category.Id"))); 4858 4859 string videosLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue : "Section"; 4860 videosLayout = videosLayout == "Ribbon" || string.IsNullOrEmpty(videosLayout) ? "Section" : videosLayout; 4861 4862 int videosCount = 0; 4863 4864 if (videosFromAssets != null) 4865 { 4866 foreach (LoopItem category in videosFromAssets) { 4867 foreach (LoopItem asset in category.GetLoop("Category.Images")) { 4868 videosCount++; 4869 } 4870 } 4871 } else { 4872 foreach (LoopItem detailField in GetLoop("Details")) 4873 { 4874 if (detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("youtube.com/embed") != -1) 4875 { 4876 videosCount++; 4877 } 4878 if (detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("vimeo.com") != -1) 4879 { 4880 videosCount++; 4881 } 4882 } 4883 } 4884 4885 if (videosCount > 0 && videosLayout != "hide") 4886 { 4887 Block detailsVideos = new Block() 4888 { 4889 Name = videosLayout != "MainInformation" ? Translate("Videos") : "", 4890 Id = "Videos", 4891 SortId = 60, 4892 Template = RenderProductVideos(videosCount, videosLayout), 4893 Design = new Design 4894 { 4895 Size = "12", 4896 RenderType = RenderType.Column, 4897 HidePadding = true 4898 } 4899 }; 4900 productVideoPage.Add(videosLayout, detailsVideos); 4901 } 4902 } 4903 4904 @helper RenderProductVideos(int videosCount, string layout) { 4905 var selectedVideoCategories = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideoAssets").SelectedValues; 4906 var videosFromAssets = GetLoop("ImageCategories").Where(x => selectedVideoCategories.Contains(x.GetString("Category.Id"))); 4907 4908 string videoColumn = "12"; 4909 videoColumn = videosCount == 2 ? "6" : videoColumn; 4910 videoColumn = videosCount > 2 ? "4" : videoColumn; 4911 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 4912 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 4913 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VideosLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 4914 4915 <div class="product__section @ribbonClasses dw-mod"> 4916 <div class="center-container @ribbonSubClasses dw-mod"> 4917 @if (layout == "Section") { 4918 @Render(new Heading { Title = Translate("Videos"), Level = 2 }) 4919 } 4920 4921 <div class="grid u-margin-bottom--lg"> 4922 @if (videosFromAssets != null) { 4923 foreach (LoopItem category in videosFromAssets) { 4924 foreach (LoopItem asset in category.GetLoop("Category.Images")) { 4925 //getting video ID from youtube URL 4926 string videoCode = asset.GetString("Ecom:Product:Detail.Image.Clean"); 4927 Regex regex = new Regex(@".be\/(.[^?]*)"); 4928 Match match = regex.Match(videoCode); 4929 string videoId = ""; 4930 if (match.Success) 4931 { 4932 videoId = match.Groups[1].Value; 4933 } 4934 else 4935 { 4936 regex = new Regex(@"v=([^&]+)"); 4937 match = regex.Match(videoCode); 4938 if (match.Success) 4939 { 4940 videoId = match.Groups[1].Value; 4941 } 4942 } 4943 4944 <div class="grid__col-md-@videoColumn grid__col-lg-@videoColumn"> 4945 <div class="video-wrapper"> 4946 <div class="js-youtube-video" data-video="@videoId" id="ytPlayer@(Guid.NewGuid().ToString("N"))" data-auto-play="False" data-enable-controls="1"></div> 4947 </div> 4948 </div> 4949 } 4950 } 4951 } else { 4952 foreach (LoopItem detailField in GetLoop("Details")) 4953 { 4954 if (detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("youtube.com/embed") != -1 || detailField.GetString("Ecom:Product:Detail.Text").IndexOf("iframe") != -1 && detailField.GetString("Ecom:Product:Detail.Text").IndexOf("vimeo.com") != -1) 4955 { 4956 <div class="grid__col-md-@videoColumn grid__col-lg-@videoColumn"> 4957 <div class="video-wrapper"> 4958 @detailField.GetString("Ecom:Product:Detail.Text") 4959 </div> 4960 </div> 4961 } 4962 } 4963 } 4964 </div> 4965 </div> 4966 </div> 4967 } 4968 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 4969 @using Dynamicweb.Core 4970 @using System 4971 @using System.Web 4972 @using System.Collections.Generic 4973 @using Dynamicweb.Rapido.Blocks.Components.General 4974 @using Dynamicweb.Rapido.Blocks 4975 @using Dynamicweb.Rapido.Services 4976 4977 4978 @functions{ 4979 BlocksPage productRelatedPage = BlocksPage.GetBlockPage("Product"); 4980 } 4981 4982 @{ 4983 string relatedProductsLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue : "Section"; 4984 relatedProductsLayout = relatedProductsLayout == "Ribbon" || string.IsNullOrEmpty(relatedProductsLayout) ? "Section" : relatedProductsLayout; 4985 bool relatedShowStock = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowStockAndShipping"); 4986 bool showAddToDownloadButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToDownloadButton"); 4987 bool relatedShowPrice = !Pageview.AreaSettings.GetItem("ProductList").GetBoolean("HidePrice"); 4988 bool relatedShowFavoriteButton = !Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("HideFavoriteButton") && Pageview.User != null; 4989 bool relatedPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 4990 bool relatedShowCartButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToCartButton"); 4991 bool relatedShowViewButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowViewButton"); 4992 string relatedCartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 4993 string relatedMoreText = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetString("ViewMoreText")) ? Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetString("ViewMoreText") : "View"; 4994 bool relatedShowNumber = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowProductNumber"); 4995 string relatedImageZoomOnHover = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("HoverImageZoom") ? "image-hover--zoom" : ""; 4996 4997 int relatedProductsPageSize = 4; 4998 4999 if (Pageview.Device.ToString() == "Mobile") 5000 { 5001 relatedProductsPageSize = 1; 5002 } 5003 5004 if (Pageview.Device.ToString() == "Tablet") 5005 { 5006 relatedProductsPageSize = 3; 5007 } 5008 5009 int relatedProductsColumnWidth = 12 / relatedProductsPageSize; 5010 5011 if (relatedProductsLayout != "hide") 5012 { 5013 var i = 0; 5014 foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups")) 5015 { 5016 string relatedGroupId = ToPascalCase(relatedGroup.GetString("Ecom:Product:RelatedGroup.Name")); 5017 string baseFeedPageUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + relatedProductsPageSize + "&ProdID=" + GetString("Ecom:Product.ID") + "&feed=true"; 5018 string relatedFeed = baseFeedPageUrl + "&" + relatedGroupId + "=" + GetString("Ecom:Product.ID")+ GetString("Ecom:Product.VariantID") + "&GroupName=" + relatedGroupId; 5019 string relatedGroupName = relatedProductsLayout != "maininformation" ? relatedGroup.GetString("Ecom:Product:RelatedGroup.Name") : ""; 5020 5021 i++; 5022 5023 Block detailsRelated = new Block() 5024 { 5025 Name = relatedGroupName, 5026 Id = relatedGroupId, 5027 SortId = 70 + i, 5028 Template = RenderRelatedProducts(relatedGroupName, relatedGroupId, relatedFeed, relatedProductsLayout), 5029 Design = new Design 5030 { 5031 Size = "12", 5032 RenderType = RenderType.Column, 5033 HidePadding = true 5034 } 5035 }; 5036 5037 productRelatedPage.Add(relatedProductsLayout, detailsRelated); 5038 } 5039 } 5040 } 5041 5042 @helper RenderRelatedProducts(string name, string groupId, string relatedFeedUrl, string layout) 5043 { 5044 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 5045 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 5046 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 5047 5048 <div class="product__section @ribbonClasses dw-mod"> 5049 <div class="center-container @ribbonSubClasses dw-mod"> 5050 @if (layout == "Section") { 5051 @Render(new Heading { Title = name, Level = 2 }) 5052 } 5053 <div class="js-handlebars-root" id="ProductList_@groupId" data-template="ProductContainer" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedFeedUrl" data-preloader="overlay"></div> 5054 </div> 5055 </div> 5056 } 5057 5058 @* Script templates for related products *@ 5059 <script id="ProductPreRenderContainer" type="text/x-template"> 5060 <div class="u-h600px u-full-width"> 5061 <div class="grid"> 5062 <div class="grid__col-12"> 5063 <div class="pre-render-element pre-render-element--md"></div> 5064 </div> 5065 </div> 5066 </div> 5067 </script> 5068 5069 @helper RenderGridViewPriceInfo() 5070 { 5071 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 5072 bool showPrice = !Pageview.AreaSettings.GetItem("ProductList").GetBoolean("HidePrice"); 5073 bool showCartButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToCartButton"); 5074 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 5075 bool isPricesWithVATEnabled = Dynamicweb.Ecommerce.Common.Context.DisplayPricesWithVat; 5076 5077 if (showPrice && Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 5078 { 5079 if (pointShopOnly) 5080 { 5081 <text> 5082 {{#if havePointPrice}} 5083 <div class="price price--product-list dw-mod">{{points}} @Translate("points")</div> 5084 @if (showCartButton) 5085 { 5086 <text> 5087 {{#unless canBePurchasedWithPoints}} 5088 <small class="help-text u-no-margin">@Translate("Not enough points to buy this")</small> 5089 {{/unless}} 5090 </text> 5091 } 5092 {{else}} 5093 @Translate("Not available") 5094 {{/if}} 5095 </text> 5096 } 5097 else 5098 { 5099 <div class="price price--product-list dw-mod">{{price}}</div> 5100 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 5101 if (showVATPrice) 5102 { 5103 <div class="vat-price vat-price--product-list u-margin-top dw-mod"> 5104 @if (isPricesWithVATEnabled) 5105 { 5106 <span>@Translate("excl. VAT")</span><span> ({{priceWithoutVAT}})</span> 5107 } 5108 else 5109 { 5110 <span>@Translate("incl. VAT")</span><span> ({{priceWithVAT}})</span> 5111 } 5112 </div> 5113 } 5114 <text> 5115 {{#if priceRRP}} 5116 <div><small>@Translate("RRP") {{priceRRP}}</small></div> 5117 {{/if}} 5118 </text> 5119 } 5120 } 5121 } 5122 5123 @helper RenderProductGridItemAddToCart() { 5124 var gridViewSettings = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView"); 5125 var ecommerceSettings = Pageview.AreaSettings.GetItem("Ecommerce"); 5126 5127 bool pointShopOnly = ecommerceSettings.GetBoolean("PointShopOnly"); 5128 bool showCartButton = gridViewSettings.GetBoolean("ShowAddToCartButton"); 5129 bool showViewButton = gridViewSettings.GetBoolean("ShowViewButton"); 5130 string viewMoreText = gridViewSettings.GetString("ViewMoreText"); 5131 viewMoreText = !string.IsNullOrEmpty(viewMoreText) ? viewMoreText : "View"; 5132 string wrapperClass = "buttons-collection--center"; 5133 int columnsCount = gridViewSettings.GetList("Columns") != null ? Converter.ToInt32(gridViewSettings.GetList("Columns").SelectedValue) : 4; 5134 bool hideButtonText = columnsCount >= 4 || Pageview.Device.ToString() == "Mobile" || Pageview.Device.ToString() == "Tablet"; 5135 5136 if (pointShopOnly && columnsCount <= 4) 5137 { 5138 hideButtonText = false; 5139 } 5140 5141 var viewBtn = new Link 5142 { 5143 Href = "{{link}}", 5144 Id = "CartButton_{{id}}", 5145 Title = Translate(viewMoreText), 5146 OnClick = "{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}", 5147 ButtonLayout = ButtonLayout.Secondary, 5148 CssClass = "u-no-margin" 5149 }; 5150 5151 if (Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 5152 { 5153 var addToCartBtn = new AddToCart 5154 { 5155 WrapperCssClass = wrapperClass, 5156 AddButton = new AddToCartButton 5157 { 5158 ProductId = "{{productId}}", 5159 VariantId = "{{variantid}}", 5160 UnitId = "{{unitId}}", 5161 ProductInfo = "{{productInfo}}", 5162 BuyForPoints = pointShopOnly, 5163 HideTitle = hideButtonText, 5164 OnClick = "{{facebookPixelAction}}", 5165 ExtraAttributes = new Dictionary<string, string> 5166 { 5167 { "{{disabledBuyButton}}", "" } 5168 } 5169 } 5170 }; 5171 5172 if (!pointShopOnly) 5173 { 5174 addToCartBtn.QuantitySelector = new QuantitySelector 5175 { 5176 Id = "Quantity{{id}}" 5177 }; 5178 } 5179 5180 if (showCartButton && Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 5181 { 5182 if (!showViewButton) 5183 { 5184 @Render(addToCartBtn) 5185 } 5186 else 5187 { 5188 <text>{{#if hideAddToCartButton}}</text> 5189 <div>@Render(viewBtn)</div> 5190 <text>{{else}}</text> 5191 @Render(addToCartBtn) 5192 <text>{{/if}}</text> 5193 } 5194 } 5195 else if (showViewButton) 5196 { 5197 <div>@Render(viewBtn)</div> 5198 } 5199 } 5200 else if (showViewButton) 5201 { 5202 <div>@Render(viewBtn)</div> 5203 } 5204 } 5205 5206 <script id="ProductContainer" type="text/x-template"> 5207 {{#.}} 5208 <div class="u-min-h400px u-full-width"> 5209 <div class="grid"> 5210 <div class="grid__col-45px grid__col--bleed-x"> 5211 <div class="grid__cell grid__cell--align-middle-left"> 5212 @{ 5213 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}}')" }; 5214 prevButton.ExtraAttributes.Add("", "{{prevdisabled}}"); 5215 } 5216 @Render(prevButton) 5217 </div> 5218 </div> 5219 <div class="grid__col-auto grid__col--bleed-x"> 5220 <div id="ProductsContainer" data-template="ProductGridItemContainer" class="grid product-list dw-mod" data-save-cookie="true"> 5221 {{#ProductsContainer}} 5222 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__grid-item @relatedImageZoomOnHover dw-mod"> 5223 {{#Product}} 5224 <div class="grid__col--auto product-scroll js-product-scroll-trigger u-no-padding u-full-height" data-params="{{googleImpression}}"> 5225 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}"> 5226 <a href="{{link}}" 5227 onclick="{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" 5228 class="u-block u-position-relative image-hover__wrapper dw-mod"> 5229 @Render(new Image { Path = "{{image}}", ImageDefault = new ImageSettings { Width = 300, Height = 300, Crop = 5, FillCanvas = true, DoNotUpscale = true }, Title = "{{name}}", CssClass = "grid__cell-img grid__cell-img--centered u-min-h180px" }) 5230 {{#StickersContainers}} 5231 {{>StickersContainer}} 5232 {{/StickersContainers}} 5233 </a> 5234 @if (relatedShowFavoriteButton) 5235 { 5236 <div class="favorites favorites--for-grid-view u-pull--right {{hasVariants}} dw-mod" {{hasVariants}}> 5237 {{#Favorite}} 5238 {{>FavoriteTemplate}} 5239 {{/Favorite}} 5240 </div> 5241 } 5242 </div> 5243 5244 <div class="grid__cell product-list__grid-item__price-info dw-mod"> 5245 <a href="{{link}}" onclick="{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" title="{{name}}" class="u-color-inherit"> 5246 @Render(new Heading { Title = "{{name}}", Level = 6, CssClass = "u-condensed-text u-bold" }) 5247 </a> 5248 5249 @if (relatedShowNumber) 5250 { 5251 <div class="item-number dw-mod">{{number}}</div> 5252 } 5253 5254 @RenderGridViewPriceInfo() 5255 </div> 5256 5257 <div class="product-list__grid-item__footer dw-mod"> 5258 @RenderProductGridItemAddToCart() 5259 5260 @if (User.IsStockInfoAllowed() && relatedShowStock) 5261 { 5262 <div class="u-margin-top"> 5263 <div><span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span> {{stockText}}</div> 5264 <div> 5265 {{#if deliveryText}} 5266 {{deliveryText}} 5267 {{else}} 5268 - 5269 {{/if}} 5270 </div> 5271 </div> 5272 } 5273 5274 @if (showAddToDownloadButton && Pageview.User != null) 5275 { 5276 Button addButton = new Button { Title = "<span class='js-button-text'>" + Translate("Add") + "</span>", ButtonLayout = ButtonLayout.Primary, CssClass = "u-no-margin u-margin-top btn--condensed dw-mod js-add-to-downloads", Icon = new Icon { Prefix = "fas", Name = "fa-plus", CssClass = "js-button-icon", LabelPosition = IconLabelPosition.After } }; 5277 addButton.ExtraAttributes.Add("data-product-id", "{{productId}}"); 5278 @Render(addButton) 5279 } 5280 </div> 5281 </div> 5282 {{/Product}} 5283 </div> 5284 {{/ProductsContainer}} 5285 </div> 5286 </div> 5287 <div class="grid__col-45px grid__col--bleed-x"> 5288 <div class="grid__cell grid__cell--align-middle-right"> 5289 @{ 5290 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}}')" }; 5291 nextButton.ExtraAttributes.Add("", "{{nextdisabled}}"); 5292 } 5293 @Render(nextButton) 5294 </div> 5295 </div> 5296 </div> 5297 </div> 5298 {{/.}} 5299 </script> 5300 5301 <script id="StickersContainer" type="text/x-template"> 5302 <div class="stickers-container stickers-container--{{{convertStickerPositionToClassName Position}}} dw-mod"> 5303 {{#Stickers}} 5304 {{>Sticker}} 5305 {{/Stickers}} 5306 </div> 5307 </script> 5308 5309 <script id="Sticker" type="text/x-template"> 5310 @Render(new Sticker { Title = "{{Title}}", CssClass = "{{CssClass}}" }) 5311 </script> 5312 5313 <script> 5314 @{ 5315 bool relatedUseGoogleTagManager = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("GoogleTagManagerID")); 5316 5317 if (relatedUseGoogleTagManager) 5318 { 5319 <text> 5320 document.addEventListener("DOMContentLoaded", function (event) { 5321 Scroll.AddIsInViewportListener(".js-product-scroll-trigger", function (elem) { 5322 let googleImpression = JSON.parse(elem.getAttribute("data-params")); 5323 googleImpression.list = "Related products"; 5324 googleEnchantImpression(googleImpression); 5325 elem.classList.remove("js-product-scroll-trigger"); 5326 }); 5327 }); 5328 </text> 5329 } 5330 } 5331 </script> 5332 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 5333 @using Dynamicweb.Core 5334 @using System 5335 @using System.Web 5336 @using System.Collections.Generic 5337 @using Dynamicweb.Rapido.Blocks 5338 @using Dynamicweb.Rapido.Blocks.Components.General 5339 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 5340 @using Dynamicweb.Rapido.Services 5341 5342 @functions { 5343 BlocksPage productVariantsListPage = BlocksPage.GetBlockPage("Product"); 5344 Dictionary<string, object> variantListSettings = new Dictionary<string, object> { 5345 { "RenderVariantsAsProducts", false }, 5346 { "RenderVariantGroupsInTable", false }, 5347 { "HideImage", false }, 5348 { "HideProductNumbers", false } 5349 }; 5350 } 5351 5352 @{ 5353 var variantsCount = GetInteger("Ecom:Product.VariantCount"); 5354 string variantsListLayout = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue : "Section"; 5355 variantsListLayout = variantsListLayout == "Ribbon" ? "Section" : variantsListLayout; 5356 5357 //family members 5358 bool isFamilyMember = false; 5359 var variantGroups = GetLoop("VariantGroups"); 5360 var variantGroupCount = variantGroups.Count; 5361 if (variantGroupCount == 1) 5362 { 5363 var firstVariantGroup = Dynamicweb.Ecommerce.Services.VariantGroups.GetVariantGroup(Dynamicweb.Ecommerce.Common.Context.LanguageID, variantGroups[0]?.GetString("Ecom:VariantGroup.ID")); 5364 if (firstVariantGroup != null) 5365 { 5366 isFamilyMember = firstVariantGroup.Family; 5367 } 5368 } 5369 if (isFamilyMember) 5370 { 5371 variantListSettings["RenderVariantsAsProducts"] = variantsCount > 1 && Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderFamilyVariantsAsProducts"); 5372 variantListSettings["RenderVariantGroupsInTable"] = false; 5373 variantListSettings["HideImage"] = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideImageForEachFamilyVariant"); 5374 variantListSettings["HideProductNumbers"] = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideFamilyProductNumbers"); 5375 } 5376 else 5377 { 5378 variantListSettings["RenderVariantsAsProducts"] = variantsCount > 1 && Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList"); 5379 variantListSettings["RenderVariantGroupsInTable"] = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantGroupsInTable"); 5380 variantListSettings["HideImage"] = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideImageForEachVariant"); 5381 variantListSettings["HideProductNumbers"] = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideProductNumbers"); 5382 } 5383 5384 if (Converter.ToBoolean(variantListSettings["RenderVariantsAsProducts"]) && variantsListLayout != "hide" && (isFamilyMember || !isFamilyMember)) 5385 { 5386 productVariantsListPage.Add(variantsListLayout, new Block 5387 { 5388 Name = variantsListLayout != "MainInformation" ? Translate("Variants list") : "", 5389 Id = "VariantsList", 5390 SortId = 20, 5391 Template = RenderVariantsProductList(variantsListLayout), 5392 Design = new Design 5393 { 5394 Size = "12", 5395 RenderType = RenderType.Column, 5396 HidePadding = true 5397 } 5398 }); 5399 5400 productVariantsListPage.Add("Section", new Block 5401 { 5402 Id = "VariantListScripts", 5403 SortId = 100, 5404 Template = RenderVariantListScripts(), 5405 Design = new Design {} 5406 }); 5407 } 5408 } 5409 5410 @helper RenderVariantsProductList(string layout) 5411 { 5412 string variantsListPageSize = HttpContext.Current.Request.QueryString.Get("PageSize") ?? "30"; 5413 string variantsFeedUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + variantsListPageSize + "&MainProductID=" + GetString("Ecom:Product.ID") + "&OnlyShowVariants=true&feed=true"; 5414 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 5415 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 5416 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 5417 5418 <div class="product__section @ribbonClasses dw-mod"> 5419 <div class="center-container @ribbonSubClasses dw-mod"> 5420 @if (layout == "Section") 5421 { 5422 @Render(new Heading { Title = Translate("Variants"), Level = 2 }) 5423 } 5424 <div class="js-handlebars-root" id="VariantsListRoot" data-template="VariantProductsContainer" data-json-feed="@variantsFeedUrl" data-preloader="minimal"></div> 5425 </div> 5426 </div> 5427 } 5428 5429 @helper RenderVariantListScripts() 5430 { 5431 bool showProductNumberForVariants = !Converter.ToBoolean(variantListSettings["HideProductNumbers"]); 5432 bool showImageForEachVariant = !Converter.ToBoolean(variantListSettings["HideImage"]); 5433 bool variantsPointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 5434 string variantsListPageSize = HttpContext.Current.Request.QueryString.Get("PageSize") ?? "30"; 5435 string variantsFeedUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + variantsListPageSize + "&MainProductID=" + GetString("Ecom:Product.ID") + "&OnlyShowVariants=true&feed=true"; 5436 string variantsCartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 5437 5438 <script id="VariantProductsContainer" type="text/x-template"> 5439 {{#.}} 5440 <div> 5441 <table id="VariantsProductsContainer" class="table u-position-relative dw-mod"> 5442 <thead> 5443 <tr> 5444 @if (showImageForEachVariant) 5445 { 5446 <td width="75"> </td> 5447 } 5448 <td>@Translate("Product")</td> 5449 {{#AvailableCustomFields}} 5450 {{>TableFieldNameTemplate}} 5451 {{/AvailableCustomFields}} 5452 @if (Converter.ToBoolean(variantListSettings["RenderVariantGroupsInTable"])) { 5453 foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 5454 { 5455 <td>@variantgroup.GetString("Ecom:VariantGroup.Name")</td> 5456 } 5457 } 5458 <td> </td> 5459 </tr> 5460 </thead> 5461 5462 <tbody id="VariantProductListContainer" data-template="VariantProductItemContainer" data-save-cookie="true"> 5463 {{#ProductsContainer}} 5464 {{>VariantProductItemContainer}} 5465 {{/ProductsContainer}} 5466 </tbody> 5467 </table> 5468 </div> 5469 5470 <div class="grid"> 5471 <div class="grid__col-12 grid__col--bleed-y"> 5472 @{ 5473 Button moreButton = new Button { Id = "LoadMoreButton", ButtonLayout = ButtonLayout.Primary, CssClass = "btn--full {{nextdisabled}}", Title = Translate("Load") + " " + Translate("more"), OnClick = "LoadMore.Next(this)" }; 5474 moreButton.ExtraAttributes.Add("data-current", "{{currentPage}}"); 5475 moreButton.ExtraAttributes.Add("data-page-size", "{{pageSize}}"); 5476 moreButton.ExtraAttributes.Add("data-total", "{{totalPages}}"); 5477 moreButton.ExtraAttributes.Add("data-container", "VariantProductListContainer"); 5478 moreButton.ExtraAttributes.Add("data-feed-url", variantsFeedUrl + "{{loadMoreFeedParams}}"); 5479 moreButton.ExtraAttributes.Add("", "{{nextdisabled}}"); 5480 } 5481 @Render(moreButton) 5482 </div> 5483 </div> 5484 {{/.}} 5485 </script> 5486 5487 <script id="VariantProductItemContainer" type="text/x-template"> 5488 {{#.}} 5489 <tr id="VariantProduct{{id}}" class="js-product" data-template="VariantProductItem" data-preloader="overlay" style="z-index: {{zIndex}}"> 5490 {{#Product}} 5491 {{>VariantProductItem}} 5492 {{/Product}} 5493 </tr> 5494 {{/.}} 5495 </script> 5496 5497 <script id="VariantProductItem" type="text/x-template"> 5498 {{#.}} 5499 @if (showImageForEachVariant) 5500 { 5501 <td width="75"> 5502 <div class="lightbox u-hidden-xxs"> 5503 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}{{#if variantName}}, {{variantName}}{{/if}}"> 5504 <img class="lightbox__image {{noImage}}" src="/Admin/Public/GetImage.ashx?width=220&height=220&format=webp&crop=5&Compression=75&image={{image}}" alt="{{name}}{{#if variantName}}, {{variantName}}{{/if}}" /> 5505 <div class="u-margin-right {{noImage}}"> 5506 <img src="/Admin/Public/GetImage.ashx?width=75&height=55&format=webp&crop=5&FillCanvas=true&Compression=75&image={{image}}" alt="{{name}}{{#if variantName}}, {{variantName}}{{/if}}" /> 5507 </div> 5508 </a> 5509 </div> 5510 </td> 5511 } 5512 5513 <td class="u-va-middle"> 5514 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}{{#if variantName}}, {{variantName}}{{/if}}"> 5515 <h6 class="u-no-margin">{{name}}{{#if variantName}}, {{variantName}}{{/if}}</h6> 5516 </a> 5517 @if (showProductNumberForVariants) 5518 { 5519 <div class="item-number item-number--compressed u-margin-bottom dw-mod"> 5520 <div>{{number}}</div> 5521 </div> 5522 } 5523 @if (User.IsStockInfoAllowed()) 5524 { 5525 <text>{{#if stockText}}</text> 5526 <div class="item-number item-number--compressed dw-mod"> 5527 <span> 5528 <span class="stock-icon {{stockState}} u-no-margin dw-mod" title="{{stockText}}"></span> 5529 <span class="u-margin-right--lg"> {{stockText}}</span> 5530 {{deliveryText}} 5531 </span> 5532 </div> 5533 <text>{{/if}}</text> 5534 } 5535 else 5536 { 5537 <div class="grid__cell-footer stickers-container stickers-container--block dw-mod"> 5538 {{#Stickers}} 5539 {{>MiniSticker}} 5540 {{/Stickers}} 5541 </div> 5542 } 5543 </td> 5544 {{#CustomFields}} 5545 {{>TableFieldValueTemplate}} 5546 {{/CustomFields}} 5547 @if (Converter.ToBoolean(variantListSettings["RenderVariantGroupsInTable"])) 5548 { 5549 <text> 5550 {{#VariantSelectionNames}} 5551 {{>TableFieldNameTemplate}} 5552 {{/VariantSelectionNames}} 5553 </text> 5554 } 5555 <td class="u-va-middle"> 5556 @if (Dynamicweb.Rapido.Services.User.IsPricesAllowed() && !Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 5557 { 5558 <div class="u-hidden-sm"> 5559 <div class="u-full-width u-ta-right u-padding-right"> 5560 <div class="before-price {{onSale}} before-price--micro dw-mod">{{discount}}</div> 5561 <div class="price price--product-list price--micro dw-mod">{{price}}</div> 5562 </div> 5563 </div> 5564 } 5565 5566 <div class="grid grid--align-center grid--justify-end"> 5567 <div class="u-margin-right u-hidden-xs u-hidden-xxs"> 5568 @if (variantsPointShopOnly) 5569 { 5570 <text> 5571 {{#if canBePurchasedWithPoints}} 5572 <div class="price price--product-list price--micro dw-mod">{{points}} @Translate("points")</div> 5573 {{else}} 5574 {{#if havePointPrice}} 5575 <small class="help-text u-no-margin u-margin-top">@Translate("Not enough points to buy this")</small> 5576 {{else}} 5577 <small class="help-text u-no-margin u-margin-top">@Translate("Not available")</small> 5578 {{/if}} 5579 {{/if}} 5580 </text> 5581 } 5582 else if (Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 5583 { 5584 <div class="before-price before-price--micro {{onSale}} dw-mod">{{discount}}</div> 5585 <div class="price price--condensed price--product-list dw-mod">{{price}}</div> 5586 } 5587 </div> 5588 5589 @if (Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 5590 { 5591 var addToCartBtn = new AddToCart 5592 { 5593 AddButton = new AddToCartButton 5594 { 5595 HideTitle = true, 5596 ProductId = "{{productId}}", 5597 VariantId = "{{variantid}}", 5598 UnitId = "{{unitId}}", 5599 ProductInfo = "{{productInfo}}", 5600 BuyForPoints = variantsPointShopOnly, 5601 OnClick = "{{facebookPixelAction}}" 5602 }, 5603 UnitSelector = new UnitSelector 5604 { 5605 OptionsContent = "{{#unitOptions}}{{>VariantUnitOption}}{{/unitOptions}}", 5606 Id = "UnitOptions_{{id}}", 5607 SelectedOption = "{{unitName}}", 5608 CssClass = "{{hasUnits}}" 5609 } 5610 }; 5611 5612 if (!variantsPointShopOnly) 5613 { 5614 addToCartBtn.QuantitySelector = new QuantitySelector 5615 { 5616 Id = "Quantity_{{id}}" 5617 }; 5618 } 5619 5620 <div class="grid__cell u-flex-grow--0"> 5621 @Render(addToCartBtn) 5622 </div> 5623 } 5624 <div class="favorites u-margin-left dw-mod"> 5625 {{#Favorite}} 5626 {{>FavoriteTemplate}} 5627 {{/Favorite}} 5628 </div> 5629 </div> 5630 </td> 5631 {{/.}} 5632 </script> 5633 5634 <script id="TableFieldNameTemplate" type="text/x-template"> 5635 <td class="u-va-middle">{{name}}</td> 5636 </script> 5637 5638 <script id="TableFieldValueTemplate" type="text/x-template"> 5639 <td class="u-va-middle">{{value}}</td> 5640 </script> 5641 5642 <script id="MiniSticker" type="text/x-template"> 5643 <div class="stickers-container__tag stickers-container__tag--micro {{CssClass}} dw-mod">{{Title}}</div> 5644 </script> 5645 5646 <script id="VariantUnitOption" type="text/x-template"> 5647 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent(this.closest('.js-product').id, '{{link}}&feed=true&UnitID={{value}}')">{{name}}</div> 5648 </script> 5649 } 5650 5651 5652 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 5653 @using Dynamicweb.Core 5654 @using System 5655 @using System.Web 5656 @using System.Collections.Generic 5657 @using Dynamicweb.Rapido.Blocks 5658 @using Dynamicweb.Rapido.Blocks.Components.General 5659 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 5660 5661 @functions { 5662 BlocksPage productVariantsMatrixPage = BlocksPage.GetBlockPage("Product"); 5663 } 5664 5665 5666 @{ 5667 var matrixLayoutSetting = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout"); 5668 string variantsMatrixLayout = matrixLayoutSetting != null && !string.IsNullOrEmpty(matrixLayoutSetting.SelectedValue) ? matrixLayoutSetting.SelectedValue : "Section"; 5669 variantsMatrixLayout = variantsMatrixLayout == "Ribbon" ? "Section" : variantsMatrixLayout; 5670 bool renderVariantsAsMatrix = GetInteger("Ecom:Product.VariantCount") > 1 && variantsMatrixLayout.ToLower() != "hide" && Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("EnableVariantMatrix"); 5671 5672 if (renderVariantsAsMatrix) 5673 { 5674 Block variantsMatrix = new Block() 5675 { 5676 Name = Translate("Variants"), 5677 Id = "VariantsMatrix", 5678 SortId = 15, 5679 Template = RenderVariantsMatrixSection(variantsMatrixLayout), 5680 Design = new Design 5681 { 5682 Size = "12", 5683 RenderType = RenderType.Column, 5684 HidePadding = true 5685 } 5686 }; 5687 5688 if (variantsMatrixLayout == "Section") { 5689 productVariantsMatrixPage.Add(variantsMatrix); 5690 } else { 5691 productVariantsMatrixPage.Add(variantsMatrixLayout, variantsMatrix); 5692 } 5693 } 5694 } 5695 5696 @helper RenderVariantsMatrixSection(string layout) 5697 { 5698 string cartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 5699 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 5700 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 5701 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsListLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 5702 5703 List<LoopItem> variantInfos = GetLoop("VariantInfos"); 5704 string productId = GetString("Ecom:Product.ID"); 5705 string pageId = Pageview.Page.ID.ToString(); 5706 5707 5708 <div class="product__section u-no-padding @ribbonClasses dw-mod"> 5709 <div class="center-container @ribbonSubClasses dw-mod"> 5710 @RenderVariantInfoMatrix(variantInfos, productId, pageId, 0, "add") 5711 </div> 5712 </div> 5713 } 5714 5715 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 5716 @using Dynamicweb.Rendering 5717 @using Dynamicweb.Core 5718 @using System 5719 @using System.Web 5720 @using System.Collections.Generic 5721 @using Dynamicweb.Rapido.Blocks 5722 @using Dynamicweb.Rapido.Blocks.Components 5723 @using Dynamicweb.Rapido.Blocks.Components.General 5724 5725 5726 @* Component - Variant Info Matrix. This replaces the old Variant Matrix with a much cleaner approach *@ 5727 5728 @helper RenderVariantInfoMatrix(List<LoopItem> variantInfos, string productId, string pageId, double totalPrice = 0, string actionType = "update") { 5729 string cartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 5730 bool hideAddToCartButton = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("hideAddToCartButton"); 5731 5732 string currencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code; 5733 string countryCode = Pageview.Area.CultureInfo != null ? Pageview.Area.CultureInfo.Name : "en-US"; 5734 5735 int loopCount = 0; 5736 int dimensionsCount = 0; 5737 bool firstRun = true; 5738 List<string> headerLabels = new List<string>(); 5739 5740 //Collect the missing data needed to render matrixes 5741 foreach (var variantInfoFirst in variantInfos) 5742 { 5743 dimensionsCount = 1; 5744 5745 foreach (var variantInfoSecond in variantInfoFirst.GetLoop("VariantInfos")) 5746 { 5747 dimensionsCount = 2; 5748 5749 if (firstRun) { 5750 headerLabels.Add(variantInfoSecond.GetString("OptionName")); 5751 } 5752 5753 foreach (var variantInfoThird in variantInfoSecond.GetLoop("VariantInfos")) 5754 { 5755 dimensionsCount = 3; 5756 } 5757 } 5758 5759 firstRun = false; 5760 } 5761 5762 @*One dimension*@ 5763 if (dimensionsCount == 1) 5764 { 5765 int totalQuantity = 0; 5766 5767 <table cellspacing="0" class="table matrix js-matrix dw-mod"> 5768 <thead class="matrix__head dw-mod"> 5769 <tr> 5770 @foreach (var variantInfoFirst in variantInfos) 5771 { 5772 <td class="u-bold u-ta-center" width="80" > 5773 <div>@variantInfoFirst.GetString("OptionName")</div> 5774 <small>@variantInfoFirst.GetString("VariantId")</small> 5775 </td> 5776 } 5777 <td width="80px" align="right" class="matrix-label-field-right dw-mod">@Translate("Totals")</td> 5778 <td> </td> 5779 </tr> 5780 </thead> 5781 <tbody> 5782 <tr> 5783 @foreach (var variantInfoFirst in variantInfos) 5784 { 5785 double price = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, variantInfoFirst.GetString("VariantId"), Dynamicweb.Ecommerce.Common.Context.LanguageID).GetPrice(Dynamicweb.Ecommerce.Common.Context.Currency.Code, Dynamicweb.Ecommerce.Common.Context.Country.Code2).Price; 5786 5787 loopCount++; 5788 totalQuantity += variantInfoFirst.GetInteger("Quantity"); 5789 5790 <td class="matrix__input-cell dw-mod"> 5791 @if (variantInfoFirst.GetBoolean("IsProduct")) 5792 { 5793 <input type="hidden" name="ProductLoopCounter@(loopCount)" value="@(loopCount)" /> 5794 <input type="hidden" name="ProductID@(loopCount)" value="@productId" /> 5795 <input type="hidden" name="VariantID@(loopCount)" value="@variantInfoFirst.GetString("VariantId")" /> 5796 <input type="number" name="Quantity@(loopCount)" value="@variantInfoFirst.GetString("Quantity")" data-price="@price" min="0" step="1" oninput="validity.valid||(value='');" class="matrix-input-field dw-mod" onchange="Matrix.UpdateQuantities(this)" data-row-id="ONE"> 5797 } else { 5798 <div class="matrix__cell-disabled dw-mod"></div> 5799 } 5800 </td> 5801 } 5802 <td class="u-va-middle"> 5803 <div class="u-bold u-ta-right matrix-label-field-right dw-mod" data-row-total="ONE"> 5804 @totalQuantity 5805 </div> 5806 </td> 5807 <td class="u-bold u-va-middle u-ta-right matrix-label-field-right dw-mod"> 5808 <div class="js-total-price" data-currency-code="@currencyCode" data-country-code="@countryCode"></div> 5809 </td> 5810 </tr> 5811 </tbody> 5812 <tfoot> 5813 <tr> 5814 <td colspan="@(variantInfos.Count + 2)"> </td> 5815 </tr> 5816 @if (!hideAddToCartButton) 5817 { 5818 <tr> 5819 <td colspan="@(variantInfos.Count + 2)" class="u-ta-right"> 5820 <div class="u-padding--lg"> 5821 @if (actionType == "update") { 5822 @Render(new Button { OnClick = "Matrix.UpdateCart(this, '" + pageId + "');", Title = Translate("Update"), ButtonLayout = ButtonLayout.Tertiary, Icon = new Icon { Prefix = "fal", Name = "fa-redo", LabelPosition = IconLabelPosition.After }, CssClass = "u-no-margin" }) 5823 } else if (actionType == "justadd") { 5824 @Render(new Button { OnClick = "Matrix.AddToCart(this, '" + pageId + "');", Title = Translate("Add"), ButtonLayout = ButtonLayout.Tertiary, CssClass = "u-no-margin" }) 5825 } else { 5826 @Render(new Button { OnClick = "Matrix.AddToCart(this, '" + pageId + "');", Title = Translate("Add to cart"), ButtonLayout = ButtonLayout.Tertiary, Icon = new Icon { Name = cartIcon, LabelPosition = IconLabelPosition.After }, CssClass = "u-no-margin" }) 5827 } 5828 </div> 5829 </td> 5830 </tr> 5831 } 5832 </tfoot> 5833 </table> 5834 } 5835 5836 @*Two dimensions*@ 5837 if (dimensionsCount == 2) 5838 { 5839 Dictionary<string, int> columnTotals = new Dictionary<string, int>(); 5840 int counter = 0; 5841 int totalProducts = 0; 5842 int totalColumns = 0; 5843 5844 <table class="table matrix js-matrix dw-mod" cellspacing="0"> 5845 <thead class="matrix__head dw-mod"> 5846 <tr> 5847 <td width="160"> </td> 5848 @foreach (string label in headerLabels) 5849 { 5850 <td class="u-bold u-ta-center" width="80">@label</td> 5851 } 5852 <td align="right" width="80" class="matrix-label-field-right dw-mod">@Translate("Totals")</td> 5853 <td> </td> 5854 </tr> 5855 </thead> 5856 <tbody> 5857 @foreach (var variantInfoFirst in variantInfos) 5858 { 5859 int totalRowQuantity = 0; 5860 counter += variantInfoFirst.GetInteger("Quantity"); 5861 totalColumns = variantInfoFirst.GetLoop("VariantInfos").Count; 5862 5863 <tr> 5864 <td class="matrix-label-field-left dw-mod"> 5865 <div class="u-pull--left"> 5866 <div>@variantInfoFirst.GetString("OptionName")</div> 5867 <small>@variantInfoFirst.GetString("VariantId")</small> 5868 </div> 5869 5870 @if (!string.IsNullOrEmpty(variantInfoFirst.GetString("Image"))) { 5871 <div class="matrix-option-image u-pull--right dw-mod" onclick="Matrix.ShowOptionImageModal(this)" data-img-src="/files/@variantInfoFirst.GetString("Image")"> 5872 @Render(new Image { 5873 Path = variantInfoFirst.GetString("Image"), 5874 ImageDefault = new ImageSettings { 5875 Width = 28, 5876 Height = 28 5877 }, 5878 ImageMedium = new ImageSettings { 5879 Width = 28, 5880 Height = 28 5881 }, 5882 ImageSmall = new ImageSettings { 5883 Width = 28, 5884 Height = 28 5885 } 5886 }) 5887 </div> 5888 } 5889 </td> 5890 @foreach (var variantInfoSecond in variantInfoFirst.GetLoop("VariantInfos")) 5891 { 5892 loopCount++; 5893 totalRowQuantity += variantInfoSecond.GetInteger("Quantity"); 5894 5895 string optionName = variantInfoSecond.GetString("OptionName"); 5896 int optionQuantity = variantInfoSecond.GetInteger("Quantity"); 5897 if (columnTotals.ContainsKey(optionName)) { 5898 columnTotals[optionName] += optionQuantity; 5899 } else { 5900 columnTotals.Add(optionName, optionQuantity); 5901 } 5902 5903 <td class="matrix__input-cell dw-mod"> 5904 @if (variantInfoSecond.GetBoolean("IsProduct")) { 5905 double price = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, variantInfoSecond.GetString("VariantId"), Dynamicweb.Ecommerce.Common.Context.LanguageID).GetPrice(Dynamicweb.Ecommerce.Common.Context.Currency.Code, Dynamicweb.Ecommerce.Common.Context.Country.Code2).Price; 5906 5907 <input type="hidden" name="ProductLoopCounter@(loopCount)" value="@(loopCount)" /> 5908 <input type="hidden" name="ProductID@(loopCount)" value="@productId" /> 5909 <input type="hidden" name="VariantID@(loopCount)" value="@variantInfoSecond.GetString("VariantId")" /> 5910 <input type="number" name="Quantity@(loopCount)" value="@variantInfoSecond.GetString("Quantity")" data-price="@price" min="0" step="1" oninput="validity.valid||(value='');" class="matrix-input-field dw-mod" onchange="Matrix.UpdateQuantities(this)" data-row-id="@variantInfoFirst.GetString("OptionName")" data-column-id="@variantInfoSecond.GetString("OptionName")"> 5911 } else { 5912 <div class="matrix__cell-disabled dw-mod"></div> 5913 } 5914 </td> 5915 } 5916 <td class="u-va-middle matrix-label-field-right dw-mod"> 5917 <div class="u-bold u-ta-right" data-row-total="@variantInfoFirst.GetString("OptionName")"> 5918 @totalRowQuantity 5919 </div> 5920 </td> 5921 <td> </td> 5922 </tr> 5923 } 5924 </tbody> 5925 <tfoot> 5926 <tr> 5927 <td class="u-bold u-va-middle matrix-label-field-left dw-mod">@Translate("Totals")</td> 5928 @foreach (var item in columnTotals) 5929 { 5930 totalProducts += item.Value; 5931 5932 <td> 5933 <div class="u-bold u-ta-center u-padding--lg" data-column-total="@item.Key"> 5934 @item.Value 5935 </div> 5936 </td> 5937 } 5938 <td class="u-bold u-va-middle u-ta-right matrix-label-field-right dw-mod" align="right"> 5939 <div class="js-total-quantity">@totalProducts</div> 5940 </td> 5941 <td class="u-bold u-va-middle u-ta-right matrix-label-field-right dw-mod"> 5942 <div class="js-total-price" data-currency-code="@currencyCode" data-country-code="@countryCode"></div> 5943 </td> 5944 </tr> 5945 <tr> 5946 <td colspan="@(totalColumns + 4)" class="u-ta-right u-no-padding"> 5947 <div class="u-padding--lg"> 5948 @if (actionType == "update") { 5949 @Render(new Button { OnClick = "Matrix.UpdateCart(this, '" + pageId + "');", Title = Translate("Update"), ButtonLayout = ButtonLayout.Tertiary, Icon = new Icon { Prefix = "fal", Name = "fa-redo", LabelPosition = IconLabelPosition.After }, CssClass = "u-no-margin" }) 5950 } else { 5951 @Render(new Button { OnClick = "Matrix.AddToCart(this, '" + pageId + "');", Title = Translate("Add to cart"), ButtonLayout = ButtonLayout.Tertiary, Icon = new Icon { Name = cartIcon, LabelPosition = IconLabelPosition.After }, CssClass = "u-no-margin" }) 5952 } 5953 </div> 5954 </td> 5955 </tr> 5956 </tfoot> 5957 </table> 5958 } 5959 5960 5961 Modal optionColorImage = new Modal { 5962 Id = "OptionColorImage", 5963 BodyTemplate = @Render(new Image { Path = "/Files/Images/placeholder.gif", Id = "OptionColorImageElement", DisableImageEngine = true, DisableLazyLoad = true }), 5964 Width = ModalWidth.Full 5965 }; 5966 5967 @Render(optionColorImage) 5968 } 5969 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 5970 @using Dynamicweb.Core 5971 @using System 5972 @using System.Web 5973 @using System.Collections.Generic 5974 @using Dynamicweb.Rapido.Blocks 5975 @functions { 5976 BlocksPage productSnippetsPage = BlocksPage.GetBlockPage("Product"); 5977 } 5978 5979 @{ 5980 Block googleProductSchema = new Block() 5981 { 5982 Id = "GoogleProductSchema", 5983 SortId = 10, 5984 Template = RenderGoogleProductSchema() 5985 }; 5986 5987 productSnippetsPage.Add("Snippets", googleProductSchema); 5988 } 5989 5990 @helper RenderGoogleProductSchema() 5991 { 5992 var siteURL = Dynamicweb.Context.Current.Request.Url.Scheme + "://" + Dynamicweb.Context.Current.Request.Url.Host; 5993 var image = GetProductImage(); 5994 var brand = GetString("Ecom:Product:Field.brand.Value"); 5995 var variantid = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"); 5996 var url = Dynamicweb.Context.Current.Request.Url.Scheme + "://" + GetGlobalValue("Global:Request.Host") + Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetString("Ecom:Product.LinkGroup.Clean") + (!string.IsNullOrWhiteSpace(variantid) ? "&VariantID=" + variantid : "")); 5997 5998 <script type="application/ld+json"> 5999 { 6000 "@@context": "http://schema.org/", 6001 "@@type": "Product", 6002 "name": "@GetString("Ecom:Product.Name")", 6003 @if (!string.IsNullOrEmpty(image)) 6004 { 6005 <text>"image": [ 6006 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=400&crop=0&format=webp&Compression=75&DoNotUpscale=true&image=@image", 6007 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=300&crop=0&format=webp&Compression=75&DoNotUpscale=true&image=@image", 6008 "@siteURL/Admin/Public/GetImage.ashx?width=448&height=225&crop=0&format=webp&Compression=75&DoNotUpscale=true&image=@image" 6009 ],</text> 6010 } 6011 "description": "@GetString("Ecom:Product.ShortDescription")", 6012 "mpn": "925872", 6013 @if (!string.IsNullOrEmpty(brand)) 6014 { 6015 <text>"brand": { 6016 "@@type": "Thing", 6017 "name": "@brand" 6018 },</text> 6019 } 6020 "offers": { 6021 "@@type": "Offer", 6022 "priceCurrency": "@GetString("Ecom:Product.Price.Currency.Code")", 6023 "price": "@GetString("Ecom:Product.Price.Price")", 6024 "availability": "@(GetInteger("Ecom:Product.Stock") > 0 ? "InStock" : "OutOfStock")", 6025 "url": "@url" 6026 } 6027 } 6028 </script> 6029 } 6030 6031 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 6032 6033 @using Dynamicweb.Rapido.Blocks 6034 6035 @functions { 6036 BlocksPage snippetsTemplatesPage = BlocksPage.GetBlockPage("Product"); 6037 } 6038 6039 @{ 6040 snippetsTemplatesPage.Add(new Block { 6041 Id = "FavoritesTemplates", 6042 SortId = 100, 6043 Template = RenderFavoritesTemplates() 6044 }); 6045 } 6046 6047 @helper RenderFavoritesTemplates() 6048 { 6049 var selectedFavoriteIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon").SelectedValue : "star"; 6050 string favoriteIcon = "fas fa-" + selectedFavoriteIcon; 6051 string favoriteOutlineIcon = "fal fa-" + selectedFavoriteIcon; 6052 bool useFacebookPixel = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Settings").GetString("FacebookPixelID")); 6053 string currentFavoriteListId = HttpContext.Current.Request.QueryString.Get("ListID"); 6054 6055 <script id="FavoriteTemplate" type="text/x-template"> 6056 <div class="favorites-list u-ta-left js-favorites-list"> 6057 @Render(new Button { 6058 CssClass = "u-no-margin js-favorite-btn", 6059 Icon = new Icon 6060 { 6061 Name = "{{#if isInAnyFavoriteList}}" + favoriteIcon + "{{else}}" + favoriteOutlineIcon + "{{/if}}", 6062 CssClass = "fa-1_5x", 6063 LabelPosition = IconLabelPosition.After 6064 }, 6065 ButtonLayout = ButtonLayout.LinkClean, 6066 ButtonType = ButtonType.Button, 6067 OnClick = "document.getElementById('FavoriteTrigger_{{id}}').checked = true" 6068 }) 6069 <input type="checkbox" id="FavoriteTrigger_{{id}}" class="dropdown-trigger" /> 6070 <div class="dropdown dropdown--position-32px"> 6071 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 6072 <ul class="list list--clean dw-mod"> 6073 {{#FavoriteLists}} 6074 {{>FavoriteListItem}} 6075 {{/FavoriteLists}} 6076 </ul> 6077 </div> 6078 <label class="dropdown-trigger-off" for="FavoriteTrigger_{{id}}"></label> 6079 </div> 6080 </div> 6081 </script> 6082 6083 <script id="FavoriteListItem" type="text/x-template"> 6084 <li> 6085 @{ 6086 var button = new Button { 6087 CssClass = "list__link u-no-underline", 6088 OnClick = "toggleFavAction(this, event)", 6089 Icon = new Icon { Name = "{{#if isInFavoriteList}}" + favoriteIcon + "{{else}}" + favoriteOutlineIcon + "{{/if}}", LabelPosition = IconLabelPosition.After }, 6090 AltText = "{{#if isInFavoriteList}}" + Translate("Remove from") + " {{name}}{{else}}" + Translate("Add to") + " {{name}}{{/if}}", 6091 Title = "{{name}}", 6092 ButtonType = ButtonType.Button, 6093 ButtonLayout = ButtonLayout.LinkClean, 6094 ExtraAttributes = new Dictionary<string, string> 6095 { 6096 { "data-list-id", "{{listId}}" }, 6097 { "data-list-name", "{{name}}" }, 6098 { "data-remove-link", "{{removeLink}}" }, 6099 { "data-add-link", "{{addLink}}" }, 6100 { "data-is-in-list", "{{isInFavoriteList}}" }, 6101 6102 } 6103 }; 6104 if (useFacebookPixel) 6105 { 6106 button.ExtraAttributes.Add("data-facebook-object", "{{facebookPixelAddAction}}"); 6107 } 6108 } 6109 <div class="grid__cell"> 6110 @Render(button) 6111 </div> 6112 </li> 6113 </script> 6114 6115 <script> 6116 @if (!string.IsNullOrEmpty(currentFavoriteListId)) 6117 { 6118 <text> 6119 window.currentFavoriteListId = "@currentFavoriteListId"; 6120 </text> 6121 } 6122 function toggleFavAction(button, event) { 6123 if (button.getAttribute('data-add-link').indexOf('CCCreateNewList') > -1) { 6124 Scroll.SavePosition(event); 6125 @if (useFacebookPixel) 6126 { 6127 <text> 6128 fbq('track', 'AddToWishlist', JSON.parse(button.getAttribute('data-facebook-object'))); 6129 </text> 6130 } 6131 location.href = button.getAttribute('data-add-link'); 6132 return; 6133 } 6134 let isAdd = button.getAttribute('data-is-in-list') == "false"; 6135 Request.Fetch().get( 6136 isAdd ? button.getAttribute('data-add-link') : button.getAttribute('data-remove-link'), 6137 function (result) { 6138 button.querySelector('i').className = isAdd ? '@favoriteIcon u-margin-right--lg' : '@favoriteOutlineIcon u-margin-right--lg'; 6139 button.setAttribute('data-is-in-list', isAdd); 6140 button.setAttribute('title', (!isAdd ? '@Translate("Add to") ' : '@Translate("Remove from") ') + button.getAttribute('data-list-name')) 6141 let favList = button.closest('.js-favorites-list'); 6142 let favBtn = favList.querySelector('.js-favorite-btn i'); 6143 let isInAnyFavoriteList = favList.querySelector('[data-is-in-list=true]') != null; 6144 if (isInAnyFavoriteList) { 6145 favBtn.className = '@favoriteIcon' + ' fa-1_5x'; 6146 } else { 6147 favBtn.className = '@favoriteOutlineIcon' + ' fa-1_5x'; 6148 } 6149 @if (useFacebookPixel) 6150 { 6151 <text> 6152 if (isAdd) { 6153 fbq('track', 'AddToWishlist', JSON.parse(button.getAttribute('data-facebook-object'))); 6154 } 6155 </text> 6156 } 6157 if (window.currentFavoriteListId != null) { //if this page is favorite list 6158 let listId = button.getAttribute("data-list-id"); 6159 if (listId == window.currentFavoriteListId && !isAdd) { 6160 location.reload(); 6161 } 6162 } 6163 }, 6164 function () { 6165 console.error("FavoriteLists: Error in ToggleFavAction request"); 6166 }, 6167 false 6168 ); 6169 } 6170 </script> 6171 } 6172 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 6173 @using Dynamicweb.Core 6174 @using System 6175 @using System.Web 6176 @using System.Collections.Generic 6177 @using Dynamicweb.Rapido.Blocks 6178 6179 @{ 6180 BlocksPage customProductBlocks = BlocksPage.GetBlockPage("Product"); 6181 6182 } 6183 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 6184 @using Dynamicweb.Core 6185 @using System 6186 @using System.Web 6187 @using System.Collections.Generic 6188 @using Dynamicweb.Rapido.Services 6189 @using Dynamicweb.Rapido.Blocks 6190 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 6191 @using Dynamicweb.Rapido.Blocks.Components.General 6192 @using Dynamicweb.Logging 6193 @using Variant.VariantConfigurator; 6194 @using Dynamicweb.Frontend.Devices 6195 6196 @functions { 6197 6198 BlocksPage mainInfoPageCustom = BlocksPage.GetBlockPage("Product"); 6199 6200 VariantConfigurationsHelper configurationsHelper = new VariantConfigurationsHelper(); 6201 Dynamicweb.Ecommerce.Products.ProductImageService imageService; 6202 int Categories = 0; 6203 ILogger logger; 6204 string feedId; 6205 bool isMobileOrTablet; 6206 6207 6208 dynamic GetEnumSetting(dynamic enumSetting, string name = null) 6209 { 6210 string enumName = name == null ? enumSetting.GetType().Name : name; 6211 enumSetting = HttpContext.Current.Request.QueryString.Get(enumName) != null ? System.Enum.Parse(enumSetting.GetType(), HttpContext.Current.Request.QueryString.Get(enumName)) : enumSetting; 6212 return enumSetting; 6213 } 6214 6215 string priceWithVat; 6216 bool isPricesWithVATEnabled; 6217 bool mainInfoRenderVariantsAsProducts; 6218 bool hideAddToCartButton; 6219 int mainInfoVariantsCount; 6220 bool showCartButton; 6221 6222 } 6223 6224 @{ 6225 isMobileOrTablet = Pageview.Device == DeviceType.Tablet || Pageview.Device == DeviceType.Mobile; 6226 6227 feedId = GetGlobalValue("Global:Page.ID").ToString() + "&ProductID=" + GetString("Ecom:Product.ID") + "&VariantID=" + HttpContext.Current.Request.QueryString.Get("variantId") + "&Feed=True&redirect=false"; 6228 logger = LogManager.Current.GetLogger("Configurator"); 6229 6230 showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 6231 6232 if (Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout") != null && mainInfoVariantsCount > 1) 6233 { 6234 mainInfoRenderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout").SelectedValue != "hide" && Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("EnableVariantMatrix") ? true : mainInfoRenderVariantsAsProducts; 6235 } 6236 mainInfoVariantsCount = GetInteger("Ecom:Product.VariantCount"); 6237 mainInfoRenderVariantsAsProducts = mainInfoVariantsCount > 1 && Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList"); 6238 hideAddToCartButton = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("hideAddToCartButton"); 6239 isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 6240 imageService = new Dynamicweb.Ecommerce.Products.ProductImageService(); 6241 6242 Block mainInfoHeaderCustom = new Block() 6243 { 6244 Id = "MainInfoHeader", 6245 SortId = 10, 6246 Template = RenderMainInfoHeaderCustom() 6247 }; 6248 mainInfoPageCustom.ReplaceBlock(mainInfoHeaderCustom); 6249 6250 mainInfoPageCustom.RemoveBlockById("Buy"); 6251 6252 mainInfoPageCustom.Add("MainInformation", new Block() 6253 { 6254 Id = "ShowExtraOptions", 6255 SortId = 100, 6256 Template = RenderShowExtraOptions() 6257 }); 6258 Block mainInfoDescriptionCustom = new Block() 6259 { 6260 Id = "ShortDescription", 6261 SortId = 10, 6262 Template = RenderShortDescriptionCustom() 6263 }; 6264 mainInfoPageCustom.ReplaceBlock(mainInfoDescriptionCustom); 6265 } 6266 @helper RenderShortDescriptionCustom() 6267 { 6268 bool renderVariantsAsProducts = GetInteger("Ecom:Product.VariantCount") > 1 && Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("RenderVariantsAsProductList"); 6269 if (Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout") != null && GetInteger("Ecom:Product.VariantCount") > 1) 6270 { 6271 renderVariantsAsProducts = Pageview.AreaSettings.GetItem("ProductPage").GetList("VariantsMatrixLayout").SelectedValue != "hide" && Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("EnableVariantMatrix") ? true : renderVariantsAsProducts; 6272 } 6273 bool hideFavorites = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideFavoriteButton"); 6274 bool hideProductNumber = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideProductNumber"); 6275 6276 bool useFontAwesomePro = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetBoolean("UseFontAwesomePro"); 6277 var selectedFavoriteIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("FavoriteIcon").SelectedValue : "star"; 6278 string favoriteIcon = "fas fa-" + selectedFavoriteIcon; 6279 string favoriteOutlineIcon = "fal fa-" + selectedFavoriteIcon; 6280 string favoriteId = "Favorite" + GetString("Ecom:Product.ID"); 6281 if (!String.IsNullOrEmpty(GetString("Ecom:Product.ShortDescription"))) 6282 { 6283 Pageview.Meta.AddTag("og:description", GetString("Ecom:Product.ShortDescription")); 6284 6285 <div class="introduction-text u-no-margin--bottom"> 6286 <br/> 6287 @GetString("Ecom:Product.ShortDescription") 6288 </div> 6289 } 6290 <div class="grid__col-md-12"> 6291 6292 6293 <div id="@favoriteId" class="favorites favorites--md u-pull--right dw-mod u-no-padding-left"> 6294 <div class="grid"> 6295 @if (!hideFavorites && Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && !renderVariantsAsProducts) 6296 { 6297 <div class="grid__col-6-auto u-no-padding-left js-favorite-btn"> 6298 @{ 6299 string favorite = GetBoolean("Ecom:Product.IsProductInFavoriteList") ? favoriteIcon : favoriteOutlineIcon; 6300 string AddToWishlist = "fbq('track', 'AddToWishlist', {" + 6301 "content_name: '" + GetString("Ecom:Product.Name") + "'," + 6302 "content_ids: ['" + GetString("Ecom:Product.Number") + "']," + 6303 "value: " + GetDouble("Ecom:Product.Price.Price") + "," + 6304 "currency: '" + GetString("Ecom:Product.Price.Currency.Code") + "'" + 6305 "});"; 6306 } 6307 <label for="FavoriteTrigger"><i class="@favorite fa-1_5x u-flex u-flex--align-items-center"><span class="product__icon-text js-favorite-btn">@Translate("Tilføj til favoritter")</span></i></label> 6308 <input type="checkbox" id="FavoriteTrigger" class="dropdown-trigger" /> 6309 6310 <div class="dropdown u-block"> 6311 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod" style="right:auto"> 6312 <ul class="list list--clean dw-mod"> 6313 @if (GetLoop("CustomerCenter.ListTypes").Where(x => x.GetString("Ecom:Product.List.Type") == "Frontend").Count() > 0) 6314 { 6315 foreach (LoopItem listType in GetLoop("CustomerCenter.ListTypes").Where(x => x.GetString("Ecom:Product.List.Type") == "Frontend")) 6316 { 6317 foreach (LoopItem list in listType.GetLoop("CustomerCenter.ProductLists")) 6318 { 6319 string favLinkType = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? list.GetString("Ecom:Product.RemoveFromThisList") : list.GetString("Ecom:Product.AddToThisListAction"); 6320 string isInListIcon = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? favoriteIcon : favoriteOutlineIcon; 6321 <li> 6322 <a href="@favLinkType" class="list__link u-no-underline dw-mod" onclick="@(list.GetString("Ecom:Product.List.IsProductInThisList") != "True" && useFacebookPixel ? AddToWishlist : "")"><i class="@isInListIcon u-margin-right--lg"></i> @list.GetValue("Ecom:CustomerCenter.List.Name")</a> 6323 </li> 6324 } 6325 } 6326 } 6327 else 6328 { 6329 string favLinkType = GetString("Ecom:Product.AddToFavorites") + "&CCListType=Frontend&CCCreateNewList=" + Translate("My favorites"); 6330 string isInListIcon = favoriteOutlineIcon; 6331 <li> 6332 <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> 6333 </li> 6334 } 6335 </ul> 6336 </div> 6337 <label class="dropdown-trigger-off" for="FavoriteTrigger"></label> 6338 </div> 6339 </div> 6340 } 6341 <div class="grid__col-6-auto"> 6342 <i class="fas fa-arrow-down fa-1_5x u-flex u-flex--align-items-center" style="cursor: pointer" onclick="navigateToSpecifications()"> 6343 <span class="product__icon-text">@Translate("Læs alle specifikationer")</span> 6344 </i> 6345 </div> 6346 </div> 6347 6348 6349 </div> 6350 6351 6352 </div> 6353 } 6354 @helper RenderShowExtraOptions() 6355 { 6356 if (configurationsItems.Categories.Count() > 0) 6357 { 6358 var url = string.Format("'/Default.aspx?ID={0}&vinNumber={1}'", GetPageIdByNavigationTag("SearchByVin"), GetString("Ecom:Product.Number")); 6359 <div> 6360 <div class="grid grid__col-12 grid--direction-row grid--align-center gray-background u-margin-top--lg"> 6361 <div class="grid__col-md-@(Pageview.User == null ? "12" : "6") grid__col-xs-12"> 6362 @Render(new Button() { Id = "ShowExtraOptionsBtn", OnClick = "navigateToConfiguratorOptions()", CssClass = "u-margin u-black-background", Title = Translate("Se ekstra tilvalg"), Name = Translate("Se ekstra tilvalg"), Icon = new Icon { Prefix = "fas", Name = "fa-arrow-down", LabelPosition = IconLabelPosition.After } }) 6363 </div> 6364 @if (Pageview.User != null && GetString("Ecom:Product:Field.VareKategoriKode")?.ToLower() == "trailer") 6365 { 6366 <div class="grid__col-md-6 grid__col-xs-12 "> 6367 @Render(new Button() { Id = "ShowExtraOptionsBtnSpareParts", OnClick = $"window.location.href = {url}", CssClass = "u-margin u-black-background", Title = Translate("See spareparts"), Name = Translate("See spareparts"), Icon = new Icon { Prefix = "fas", Name = "fa-wrench", LabelPosition = IconLabelPosition.After } }) 6368 </div> 6369 } 6370 </div> 6371 </div> 6372 } 6373 6374 6375 <script> 6376 function navigateToConfiguratorOptions() { 6377 const element = document.getElementById('configuratorCategoryList'); 6378 const offset = 45; 6379 const bodyRect = document.body.getBoundingClientRect().top; 6380 const elementRect = element.getBoundingClientRect().top; 6381 const elementPosition = elementRect - bodyRect; 6382 const offsetPosition = elementPosition - offset; 6383 6384 window.scrollTo({ 6385 top: offsetPosition, 6386 behavior: 'smooth', 6387 }); 6388 } 6389 document.getElementById("ShowExtraOptionsBtnSpareParts")?.addEventListener("click", function () { 6390 var overlayElement = document.createElement('div'); 6391 overlayElement.className = "preloader-overlay"; 6392 overlayElement.setAttribute('id', "overlay"); 6393 var overlayElementIcon = document.createElement('div'); 6394 overlayElementIcon.className = "preloader-overlay__icon dw-mod"; 6395 overlayElementIcon.style.top = window.pageYOffset + "px"; 6396 overlayElement.appendChild(overlayElementIcon); 6397 6398 if (document.getElementById("content")) { 6399 document.getElementById("content").parentNode.insertBefore(overlayElement, document.getElementById("content")); 6400 } 6401 }); 6402 </script> 6403 } 6404 6405 @helper RenderMainInfoBuyCustomWithoutConfigurator() 6406 { 6407 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 6408 string variantId = HttpContext.Current.Request.QueryString.Get("variantId"); 6409 string productId = GetString("Ecom:Product.ID"); 6410 string feedId = pageId + "&ProductID=" + productId + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 6411 6412 6413 <div class="product__price-actions js-handlebars-root dw-mod" id="PriceAndActions" data-template="PricesAndActionsTemplate" data-json-feed="/Default.aspx?ID=@feedId" data-preloader="minimal"></div> 6414 <input type="hidden" value="@GetString("Ecom:Product.VariantID.Extented")" name="Variant" id="Variant_@GetString("Ecom:Product.ID")" /> 6415 @RenderMainInfoBuyScriptsCustomWithoutConfigurator() 6416 } 6417 6418 @helper RenderMainInfoBuyScriptsCustomWithoutConfigurator() 6419 { 6420 bool showPrice = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 6421 bool showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 6422 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 6423 string variantId = HttpContext.Current.Request.QueryString.Get("variantId") ?? ""; 6424 string feedId = GetGlobalValue("Global:Page.ID").ToString() + "&ProductID=" + GetString("Ecom:Product.ID") + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 6425 string cartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 6426 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("ShowBothPricesWithWithoutVAT"); 6427 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 6428 6429 var customerId = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId(); 6430 var shopId = Pageview.Area.EcomShopId; 6431 var orderType = Dynamicweb.Ecommerce.Orders.OrderType.Order; 6432 var cartsList = (List<Dynamicweb.Ecommerce.Orders.Order>)Dynamicweb.Ecommerce.Services.Orders.GetCustomerOrdersByType(customerId, shopId, orderType, 0, false, "", DateTime.MinValue, false, true); 6433 bool hidePrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 6434 6435 @* Handlebars templates *@ 6436 <script id="PricesAndActionsTemplate" type="text/x-template"> 6437 {{#.}} 6438 @if (Dynamicweb.Rapido.Services.User.IsPricesAllowed() && !hidePrice) 6439 { 6440 <div class="product__price-wrap dw-mod"> 6441 @RenderPriceInfoCustom() 6442 </div> 6443 } 6444 6445 @if (showCartButton && Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 6446 { 6447 var addToCartBtn = new AddToCart 6448 { 6449 WrapperCssClass = "product__price-actions-flex-wrap buttons-collection--right dw-mod", 6450 AddButton = new AddToCartButton 6451 { 6452 ProductId = "{{productId}}", 6453 VariantId = "{{variantid}}", 6454 UnitId = "{{unitId}}", 6455 ProductInfo = "{{productInfo}}", 6456 BuyForPoints = pointShopOnly, 6457 OnClick = "{{facebookPixelAction}}", 6458 ExtraAttributes = new Dictionary<string, string> 6459 { 6460 { "{{disabledBuyButton}}", "" } 6461 }, 6462 CssClass = "product__price-buy-button" 6463 }, 6464 UnitSelector = new UnitSelector 6465 { 6466 OptionsContent = "{{#unitOptions}}{{>UnitOption}}{{/unitOptions}}", 6467 Id = "UnitOptions_{{id}}", 6468 SelectedOption = "{{unitName}}", 6469 CssClass = "{{#if hasOnlyOneUnit}}unit-selector--readonly{{/if}} {{hasUnits}}" 6470 } 6471 }; 6472 6473 if (!pointShopOnly) 6474 { 6475 addToCartBtn.QuantitySelector = new QuantitySelector 6476 { 6477 Id = "Quantity_{{id}}" 6478 }; 6479 } 6480 6481 <div class="product__price-actions-wrap dw-mod"> 6482 @Render(addToCartBtn) 6483 6484 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && User.IsBuyingAllowed() && cartsList.Count > 0 && GetPageIdByNavigationTag("OrderDraft") != 0) 6485 { 6486 var addToDraftCart = new Button 6487 { 6488 Id = "AddToDraftCart", 6489 Title = Translate("Add to draft"), 6490 ButtonLayout = ButtonLayout.Secondary, 6491 OnClick = "document.getElementById('OrderDraftSelectModalTrigger').checked = true", 6492 CssClass = "u-w220px u-margin-top" 6493 }; 6494 6495 @Render(addToDraftCart) 6496 } 6497 6498 @if (Pageview.User != null && !pointShopOnly && Dynamicweb.Security.Licensing.LicenseManager.LicenseHasFeature("LoyaltyPoints")) 6499 { 6500 <text> 6501 {{#if canBePurchasedWithPoints}} 6502 <form method="post" role="form" class="u-no-margin u-margin-top"> 6503 <input type="hidden" name="ProductID" value="{{id}}" /> 6504 <button type="submit" class="btn btn--loyalty-points product__price-points-buy-button u-no-margin dw-mod pull-right u-no-margin js-cart-btn {{disabledBuyButton}}" name="CartCmd" value="addWithPoints">@Translate("Buy for") {{points}} @Translate("points")</button> 6505 </form> 6506 {{/if}} 6507 </text> 6508 } 6509 </div> 6510 } 6511 else 6512 { 6513 <button type="button" id="CartButton_{{id}}" class="u-hidden"></button> 6514 } 6515 @RenderStockAndShippingCustom() 6516 {{/.}} 6517 </script> 6518 6519 <script id="UnitOption" type="text/x-template"> 6520 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '{{link}}&feed=true&UnitID={{value}}')">{{name}}</div> 6521 </script> 6522 6523 <script> 6524 document.addEventListener("DOMContentLoaded", function () { 6525 if (document.getElementById("PriceAndActions")) { 6526 document.getElementById("PriceAndActions").addEventListener("contentLoaded", function (event) { 6527 if (document.querySelector(".js-variants") != null) { 6528 MatchVariants.Update(document.querySelector(".js-variants"), "DoNothing"); 6529 } 6530 }); 6531 } 6532 }); 6533 </script> 6534 } 6535 6536 @helper RenderMainInfoHeaderCustom() 6537 { 6538 6539 bool hideProductNumber = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideProductNumber"); 6540 6541 6542 6543 <div class=""> 6544 <div class="grid__col-12 product__title u-no-padding-y dw-mod@(isMobileOrTablet ? " u-flex--align-items-center u-full-width" : "")"> 6545 <h1 class="u-no-margin">@GetString("Ecom:Product.Name") </h1> 6546 @if (!hideProductNumber) 6547 { 6548 <div class="item-number dw-mod">@Translate("Varenummer"): @GetString("Ecom:Product.Number")</div> 6549 } 6550 </div> 6551 <div class="grid__col-12 u-no-padding-y" id="trailerMeasurements" data-preloader="minimal"></div> 6552 <script type="text/x-template" id="trailerMeasurementsTemplate"> 6553 {{#.}} 6554 <span class="product__trailer-fields-text {{#if hasTrailerExtraFields}} u-padding-y {{/if}} @(isMobileOrTablet ? "text-center-custom" : "")"> 6555 {{#if trailerMeasurements}} 6556 <strong class="bold-900">@Translate("Mål: ")</strong><span>{{trailerMeasurements}}</span> 6557 6558 {{/if}} 6559 {{#if trailerPayload}} 6560 <strong class="bold-900 {{#if trailerMeasurements}}margin-left-large{{/if}}">@Translate("Nyttelast: ")</strong><span>{{trailerPayload}}</span> 6561 {{/if}} 6562 </span> 6563 {{/.}} 6564 6565 </script> 6566 <hr> 6567 6568 </div> 6569 6570 <script> 6571 function navigateToSpecifications() { 6572 const element = document.getElementById('@(isMobileOrTablet ? "details_blocks__mobile" : "tabs-list")'); 6573 const offset = 45; 6574 const bodyRect = document.body.getBoundingClientRect().top; 6575 const elementRectBottom = element.getBoundingClientRect().bottom; 6576 const elementRectTop = element.getBoundingClientRect().top; 6577 const elementPosition = elementRectBottom - bodyRect; 6578 const offsetPosition = @(isMobileOrTablet ? "elementRectTop + 100" : "elementPosition - offset"); 6579 6580 window.scrollTo({ 6581 top: offsetPosition, 6582 behavior: 'smooth', 6583 }); 6584 } 6585 6586 </script> 6587 6588 6589 6590 } 6591 6592 @helper RenderPriceInfoCustom() 6593 { 6594 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 6595 bool showPrice = !Pageview.AreaSettings.GetItem("ProductList").GetBoolean("HidePrice"); 6596 bool showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 6597 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 6598 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 6599 6600 if (showPrice && Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 6601 { 6602 if (pointShopOnly) 6603 { 6604 <text> 6605 {{#if havePointPrice}} 6606 <div class="price price--product-page dw-mod">{{points}} @Translate("points")</div> 6607 @if (showCartButton) 6608 { 6609 <text> 6610 {{#unless canBePurchasedWithPoints}} 6611 <small class="help-text u-no-margin">@Translate("Not enough points to buy this")</small> 6612 {{/unless}} 6613 </text> 6614 } 6615 {{else}} 6616 @Translate("Not available") 6617 {{/if}} 6618 </text> 6619 6620 } 6621 else 6622 { 6623 <div class="price price--product-page dw-mod">{{price}}</div> 6624 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 6625 if (showVATPrice) 6626 { 6627 <div class="vat-price vat-price--product-page u-margin-top dw-mod"> 6628 @if (isPricesWithVATEnabled) 6629 { 6630 <span>@Translate("excl. VAT")</span><span> ({{priceWithoutVAT}})</span> 6631 } 6632 else 6633 { 6634 <span>@Translate("incl. VAT")</span><span> ({{priceWithVAT}})</span> 6635 } 6636 </div> 6637 } 6638 <text> 6639 {{#if priceRRP}} 6640 <div><small>@Translate("RRP") {{priceRRP}}</small></div> 6641 {{/if}} 6642 </text> 6643 } 6644 } 6645 } 6646 6647 @helper RenderStockAndShippingCustom() 6648 { 6649 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState"); 6650 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping"); 6651 6652 if (User.IsStockInfoAllowed()) 6653 { 6654 if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.ProductStockColor.Value"))) 6655 { 6656 <div class="dw-mod @(isMobileOrTablet? "u-no-margin " : "")"> 6657 @if (!hideStockState) 6658 { 6659 <span class="stock-icon @("stock-"+GetString("Ecom:Product:Field.ProductStockColor.Value")) u-no-margin dw-mod" title="@GetString("Ecom:Product:Field.ProductStockColor.Value")"></span> 6660 <span class="u-margin-right--lg">@Translate(GetString("Ecom:Product:Field.ProductStockColorText.Value"))</span> 6661 } 6662 @if (!hideDelivery) 6663 { 6664 <text>{{deliveryText}}</text> 6665 } 6666 </div> 6667 } 6668 6669 } 6670 } 6671 6672 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 6673 @using Dynamicweb.Core 6674 @using System 6675 @using System.Web 6676 @using System.Globalization; 6677 @using System.Collections.Generic 6678 @using Dynamicweb.Rapido.Blocks 6679 6680 @functions { 6681 BlocksPage productFieldsPageCustom = BlocksPage.GetBlockPage("Product"); 6682 } 6683 6684 @{ 6685 6686 if (string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("ProductPage").GetString("ProductDetailFields"))) 6687 { 6688 Block detailsCustom = new Block() 6689 { 6690 Name = detailFieldsLayout != "MainInformation" ? Translate("Details") : "", 6691 Id = "CustomFields", 6692 SortId = 9, 6693 Design = new Design 6694 { 6695 Size = "12", 6696 RenderType = RenderType.Column, 6697 HidePadding = true 6698 } 6699 }; 6700 6701 bool hasGroupFields = false; 6702 var detailFieldsDisplayGroups = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductDetailFields").SelectedValues; 6703 var displayGroups = GetLoop("FieldDisplayGroups").Where(x => !detailFieldsDisplayGroups.Contains(x.GetString("Ecom:FieldDisplayGroup.ID"))); 6704 foreach (LoopItem group in displayGroups) 6705 { 6706 foreach (LoopItem field in group.GetLoop("Fields")) 6707 { 6708 string fieldValue = !string.IsNullOrEmpty(field.GetString("Ecom:FieldDisplayGroup.Field.Value")) ? field.GetString("Ecom:FieldDisplayGroup.Field.Value") : "0"; 6709 6710 if (fieldValue != "0" && fieldValue != "0 x 0 x 0" && fieldValue != "0x0x0" && fieldValue != "0,00") 6711 { 6712 hasGroupFields = true; 6713 } 6714 } 6715 } 6716 6717 if (hasGroupFields) 6718 { 6719 6720 detailsCustom.Template = RenderProductSectionCustom(detailFieldsLayout, detailFieldsView, Translate("Information"), RenderCustomFieldsCustom(GetLoop("CustomFieldValues"), detailFieldsView)); 6721 productFieldsPageCustom.ReplaceBlock(detailsCustom); 6722 } 6723 else 6724 { 6725 productFieldsPageCustom.RemoveBlockById("CustomFields"); 6726 } 6727 } 6728 6729 if (displayGroupsLayout != "hide") 6730 { 6731 var detailFieldsDisplayGroups = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductDetailFields").SelectedValues; 6732 var displayGroups = GetLoop("FieldDisplayGroups").Where(x => !detailFieldsDisplayGroups.Contains(x.GetString("Ecom:FieldDisplayGroup.ID"))); 6733 6734 foreach (LoopItem group in displayGroups) 6735 { 6736 Block displayGroup = new Block() 6737 { 6738 Name = displayGroupsLayout != "MainInformation" ? group.GetString("Ecom:FieldDisplayGroup.Name") : "", 6739 Id = "DisplayGroup_" + group.GetString("Ecom:FieldDisplayGroup.ID"), 6740 SortId = 40, 6741 Template = RenderProductSection(displayGroupsLayout, categoryFieldsView, group.GetString("Ecom:FieldDisplayGroup.Name"), RenderDetailsFields(group.GetLoop("Fields"), categoryFieldsView)), 6742 Design = new Design 6743 { 6744 Size = "12", 6745 RenderType = RenderType.Column, 6746 HidePadding = true 6747 } 6748 }; 6749 6750 productFieldsPageCustom.RemoveBlock(displayGroup); 6751 } 6752 } 6753 6754 if (!string.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && fullDesctiptionLayout != "hide") 6755 { 6756 Block detailsDescription = new Block() 6757 { 6758 Name = fullDesctiptionLayout != "MainInformation" ? Translate("Description") : "", 6759 Id = "FullDescription", 6760 SortId = 8, 6761 Template = RenderProductDescriptionCustom(fullDesctiptionLayout), 6762 Design = new Design 6763 { 6764 Size = "12", 6765 RenderType = RenderType.Column, 6766 HidePadding = true 6767 } 6768 }; 6769 productFieldsPageCustom.ReplaceBlock(detailsDescription); 6770 } 6771 } 6772 6773 @helper RenderProductDescriptionCustom(string layout) 6774 { 6775 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 6776 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 6777 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("FullDescriptionLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 6778 6779 <div class="product__section @ribbonClasses dw-mod"> 6780 <div class="product__description center-container @ribbonSubClasses dw-mod"> 6781 @if (layout == "Section") 6782 { 6783 @Render(new Heading { Title = Translate("Description"), Level = 2 }) 6784 } 6785 @Render(new Text { Content = GetString("Ecom:Product.LongDescription") }) 6786 </div> 6787 </div> 6788 } 6789 6790 @helper RenderDetailsFieldsCustom(IEnumerable<LoopItem> fields, string viewType) 6791 { 6792 foreach (LoopItem field in fields) 6793 { 6794 string fieldValue = field.GetString("Ecom:FieldDisplayGroup.Field.Value"); 6795 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 6796 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 6797 6798 if (!string.IsNullOrEmpty(field.GetString("Ecom:FieldDisplayGroup.Field.Name")) && !string.IsNullOrEmpty(fieldValue)) 6799 { 6800 string FieldDisplayGroup = field.GetString("Ecom:FieldDisplayGroup.Field.Name"); 6801 FieldDisplayGroup = Translate(FieldDisplayGroup); 6802 if (field.GetString("Ecom:FieldDisplayGroup.Field.TypeId") == "15") 6803 { 6804 6805 @RenderFieldItemCustom(FieldDisplayGroup, field.GetString("Ecom:FieldDisplayGroup.Field.OptionLabel"), viewType); 6806 } 6807 else if (field.GetString("Ecom:FieldDisplayGroup.Field.TypeId") == "8") 6808 { 6809 @RenderFieldItemCustom(field.GetString("Ecom:Product.CategoryField.Label"), fieldValue, viewType, "link"); 6810 } 6811 else if (field.GetString("Ecom:FieldDisplayGroup.Field.TypeId") == "9") 6812 { 6813 @RenderFieldItemCustom(field.GetString("Ecom:FieldDisplayGroup.Field.Name"), fieldValue, viewType, "download"); 6814 } 6815 else 6816 { 6817 @RenderFieldItemCustom(FieldDisplayGroup, fieldValue, viewType); 6818 6819 } 6820 } 6821 } 6822 } 6823 6824 @helper RenderCustomFieldsCustom(List<LoopItem> fieldsLoop, string viewType) 6825 { 6826 bool collectAllDownloads = Pageview.AreaSettings.GetItem("ProductPage").GetString("CollectAllDownloads") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("CollectAllDownloads") : true; 6827 6828 foreach (LoopItem customField in fieldsLoop) 6829 { 6830 string fieldValue = customField.GetString("Product.CustomField.Value.Clean"); 6831 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 6832 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 6833 6834 if (customField.GetLoop("Product.CustomField.Options").Count > 0) 6835 { 6836 List<string> accumulatedValues = new List<string>(); 6837 6838 foreach (var option in customField.GetLoop("Product.CustomField.Options")) 6839 { 6840 if (option.GetBoolean("Product.CustomField.Option.IsSelected")) 6841 { 6842 accumulatedValues.Add(option.GetString("Product.CustomField.Option.Name")); 6843 } 6844 } 6845 fieldValue = string.Join(", ", accumulatedValues); 6846 } 6847 6848 if (!string.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) && !string.IsNullOrEmpty(fieldValue) && customField.GetString("Product.CustomField.Name") != "Custom sticker" && customField.GetString("Product.CustomField.Name") != "RRP") 6849 { 6850 if (string.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 6851 { 6852 @RenderFieldItemCustom(customField.GetString("Product.CustomField.Name"), fieldValue, viewType); 6853 } 6854 else if (collectAllDownloads == false) 6855 { 6856 @RenderFieldItemCustom(customField.GetString("Product.CustomField.Name"), fieldValue, viewType, "download"); 6857 } 6858 } 6859 } 6860 } 6861 6862 @helper RenderProductSectionCustom(string layout, string viewType, string name, RazorEngine.Templating.TemplateWriter writer) 6863 { 6864 string ribbonClasses = layout == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : "u-no-padding"; 6865 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 6866 string ribbonSubClasses = layout == "Ribbon" ? "center-container--ribbon" : ""; 6867 6868 string fieldColumns = viewType == "list" ? "12" : "6"; 6869 6870 <div class="product__section @ribbonClasses dw-mod"> 6871 <div class="center-container @ribbonSubClasses dw-mod"> 6872 @if (layout == "Section") 6873 { 6874 @Render(new Heading { Title = name, Level = 2 }) 6875 } 6876 6877 @if (viewType != "table") 6878 { 6879 // This section is dependent on data from ProductFeedCustom.cshtml, 6880 // and the rendering of it is dependent on "RenderCustomHandlebarsScripts" in Custom_Blocks_Variants.cshmtl 6881 <div class="grid grid--bleed u-margin-bottom--lg" id="CustomFieldDisplayGroups"> 6882 <div class="preloader-overlay-element preloader-overlay-element--clean"></div> 6883 </div> 6884 <script type="text/x-template" id="CustomFieldDisplayGroupsTemplate"> 6885 {{#.}} 6886 {{#CustomFieldDisplayGroups}} 6887 <div class="grid__col-md-12 grid__col-sm-12"><h2 class="u-padding-y-double-top">{{Name}}</h2></div> 6888 {{#CustomFieldValueViewModels}} 6889 <div class="product__field-column--custom grid__col-md-@fieldColumns grid__col-sm-12 u-margin-bottom grid grid--direction-row"> 6890 <div class="u-bold grid__col-md-6"> 6891 {{Name}} 6892 </div> 6893 <div class="grid__col-md-6"> 6894 {{#ifCond FieldTemplate "===" "Link"}} 6895 <a target="_blank" href="{{Value}}">{{Value}}</a> 6896 {{/ifCond}} 6897 {{#ifCond FieldTemplate "===" "Default"}} 6898 {{Value}} 6899 {{/ifCond}} 6900 6901 </div> 6902 </div> 6903 {{/CustomFieldValueViewModels}} 6904 {{/CustomFieldDisplayGroups}} 6905 {{/.}} 6906 </script> 6907 } 6908 else 6909 { 6910 string tableWidth = layout != "MainInformation" ? "grid__col-md-6" : "grid__col-md-12"; 6911 6912 <div class="grid grid--external-bleed-x u-margin-bottom--lg"> 6913 <div class="@tableWidth grid__col-sm-12 grid__col-xs-12"> 6914 <table class="table--no-top-border"> 6915 @writer 6916 </table> 6917 </div> 6918 </div> 6919 } 6920 </div> 6921 </div> 6922 } 6923 6924 @helper RenderFieldItemCustom(string name, string value, string viewType, string fieldType = "clean") 6925 { 6926 if (viewType != "table") 6927 { 6928 string fieldColumns = viewType == "list" ? "12" : "6"; 6929 if (!string.IsNullOrEmpty(value) && value != "0" && value != "0 x 0 x 0" && value != "0x0x0" && value != "0,00") 6930 { 6931 <div class="product__field-column--custom grid__col-md-@fieldColumns grid__col-sm-12 u-margin-bottom grid grid--direction-row"> 6932 <div class="u-bold grid__col-md-6"> 6933 @name 6934 </div> 6935 <div class="grid__col-md-6"> 6936 @RenderFieldItemContent(name, value, fieldType) 6937 </div> 6938 </div> 6939 } 6940 } 6941 else 6942 { 6943 <tr> 6944 <th>@name</th> 6945 <td> 6946 @RenderFieldItemContent(name, value, fieldType) 6947 </td> 6948 </tr> 6949 } 6950 } 6951 6952 6953 6954 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 6955 @using Dynamicweb.Core 6956 @using System 6957 @using System.Web 6958 @using System.Collections.Generic 6959 @using Dynamicweb.Rapido.Services 6960 @using Dynamicweb.Rapido.Blocks 6961 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 6962 @using Dynamicweb.Rapido.Blocks.Components.General 6963 @using Dynamicweb.Logging 6964 @using Variant.VariantConfigurator; 6965 6966 6967 @functions { 6968 BlocksPage productVariantsPageCustom = BlocksPage.GetBlockPage("Product"); 6969 bool mainInfoIsFamilyMember; 6970 bool mainInfoIsFamilyMaster = false; 6971 List<LoopItem> mainInfoVariantGroups; 6972 int mainInfoVariantGroupCount; 6973 bool hidePrice; 6974 VariantConfigurations configurationsItems; 6975 6976 } 6977 6978 @{ 6979 //family members 6980 mainInfoVariantGroupCount = mainInfoVariantGroups.Count; 6981 mainInfoVariantGroups = GetLoop("VariantGroups"); 6982 if (mainInfoVariantGroupCount == 1) 6983 { 6984 var firstVariantGroup = Dynamicweb.Ecommerce.Services.VariantGroups.GetVariantGroup(Dynamicweb.Ecommerce.Common.Context.LanguageID, mainInfoVariantGroups[0]?.GetString("Ecom:VariantGroup.ID")); 6985 if (firstVariantGroup != null) 6986 { 6987 mainInfoIsFamilyMember = firstVariantGroup.Family; 6988 string variantId = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"); 6989 mainInfoIsFamilyMaster = string.IsNullOrEmpty(variantId); 6990 } 6991 } 6992 if (!mainInfoRenderVariantsAsProducts && !mainInfoIsFamilyMember) 6993 { 6994 productVariantsPageCustom.RemoveBlockById("Variants"); 6995 } 6996 6997 hidePrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 6998 configurationsItems = configurationsHelper.GetVariantConfigurationsById(GetString("Ecom:Product.Number")); 6999 7000 7001 Block buyCustom = new Block() 7002 { 7003 Id = "BuyCustom", 7004 SortId = 40, 7005 Template = RenderBuyCustom() 7006 }; 7007 if (!mainInfoRenderVariantsAsProducts && showCartButton) 7008 { 7009 mainInfoPageCustom.Add("MainInformation", buyCustom); 7010 } 7011 7012 if (Dynamicweb.Rapido.Services.User.IsPricesAllowed() && !hidePrice) 7013 { 7014 mainInfoPageCustom.Add("MainInformation", new Block() 7015 { 7016 Id = "PriceInfoCustom", 7017 SortId = 30, 7018 Template = RenderPriceInfoConfiguratorCustom() 7019 }); 7020 } 7021 7022 mainInfoPageCustom.Add("Snippets", new Block() 7023 { 7024 Id = "CustomHandlebarsScripts", 7025 SortId = 10, 7026 Template = RenderCustomHandlebarsScripts() 7027 }); 7028 } 7029 7030 @helper RenderCustomHandlebarsScripts() 7031 { 7032 <script> 7033 document.addEventListener("DOMContentLoaded", function (event) { 7034 var priceInfoTemplate = document.getElementById('PriceInfoTemplate'); 7035 var trailerMeasurementsTemplate = document.getElementById('trailerMeasurementsTemplate'); 7036 var variantSelectorTemplate = document.getElementById('PricesAndActionsTemplate'); 7037 var customFieldDisplayGroupsTemplate = document.getElementById('CustomFieldDisplayGroupsTemplate'); 7038 7039 fetch('/Default.aspx?ID=@feedId').then(response => response.json()) 7040 .then(function (data) { 7041 var priceInfoContainer = document.getElementById('PriceInfo'); 7042 var trailerMeasurementsContainer = document.getElementById('trailerMeasurements'); 7043 var variantSelectorContainer = document.getElementById('PriceAndActionsConfigurator'); 7044 var customFieldDisplayGroupsContainer = document.getElementById('CustomFieldDisplayGroups'); 7045 7046 if (priceInfoTemplate && priceInfoContainer) { 7047 AddHandlebarsHTMLToContainer(priceInfoTemplate, priceInfoContainer, data); 7048 } 7049 if (trailerMeasurementsTemplate && trailerMeasurementsContainer) { 7050 AddHandlebarsHTMLToContainer(trailerMeasurementsTemplate, trailerMeasurementsContainer, data); 7051 } 7052 if (variantSelectorTemplate && variantSelectorContainer) { 7053 AddHandlebarsHTMLToContainer(variantSelectorTemplate, variantSelectorContainer, data); 7054 } 7055 if (customFieldDisplayGroupsTemplate && customFieldDisplayGroupsContainer) { 7056 AddHandlebarsHTMLToContainer(CustomFieldDisplayGroupsTemplate, customFieldDisplayGroupsContainer, data); 7057 } 7058 const customContentLoadedEvent = new Event('contentLoaded', { 7059 bubbles: true, 7060 cancelable: true, 7061 composed: false 7062 }); 7063 document.getElementById("PriceAndActionsConfigurator").dispatchEvent(customContentLoadedEvent); 7064 }); 7065 }); 7066 7067 function AddHandlebarsHTMLToContainer(template, container, data) { 7068 var template = Handlebars.compile(template.innerHTML); 7069 var compiledHTML = template(data); 7070 container.innerHTML = compiledHTML; 7071 } 7072 7073 </script> 7074 } 7075 7076 @helper RenderPriceInfoConfiguratorCustom() 7077 { 7078 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 7079 bool showPrice = !Pageview.AreaSettings.GetItem("ProductList").GetBoolean("HidePrice"); 7080 bool showCartButton = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideAddToCartButton"); 7081 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductList").GetBoolean("ShowBothPricesWithWithoutVAT"); 7082 7083 //Get all ids from configurator products. 7084 var configuratorItemsIds = configurationsItems.Categories.SelectMany(x => x).Select(x => x.RelatedProductID).ToList(); 7085 //Get mainproduct id 7086 var mainProductId = GetString("Ecom:Product.ID"); 7087 //Get product number 7088 var ProductNumber = GetString("Ecom:Product.Number"); 7089 //Get all retailprices in a dictionary with key being the ProductID, containing the prices of the product in all languages 7090 var retailPrices = new VariantRetailPricesHelper().GetVariantRetailPricesById(new List<string> { ProductNumber }); 7091 //A formatter for showing the price with correct priceformatting(decimals, currencyCode etc) 7092 var countryCode = Pageview.Area.EcomCountryCode ?? "DK"; 7093 7094 List<VariantRetailPrice> retailPricesForSingleCountry = new List<VariantRetailPrice>(); 7095 retailPrices?.variantRetailPrices?.TryGetValue(ProductNumber, out retailPricesForSingleCountry); 7096 7097 var retailPrice = retailPricesForSingleCountry?.SingleOrDefault(x => x?.CountryCode == countryCode) ?? new VariantRetailPrice(); 7098 7099 7100 7101 if (showPrice && Dynamicweb.Rapido.Services.User.IsPricesAllowed()) 7102 { 7103 <div class="" id="PriceInfo"></div> 7104 7105 <script id="PriceInfoTemplate" type="text/x-template"> 7106 {{#.}} 7107 @if (pointShopOnly) 7108 { 7109 <text> 7110 {{#if havePointPrice}} 7111 <div class="price price--product-page dw-mod">{{points}} @Translate("points")</div> 7112 @if (showCartButton) 7113 { 7114 <text> 7115 {{#unless canBePurchasedWithPoints}} 7116 <small class="help-text u-no-margin">@Translate("Not enough points to buy this")</small> 7117 {{/unless}} 7118 </text> 7119 } 7120 {{else}} 7121 @Translate("Not available") 7122 {{/if}} 7123 </text> 7124 7125 } 7126 else 7127 { 7128 <div class="price price--product-page dw-mod" style="line-height:23px;" id="priceCustom"> 7129 @if (Pageview.User != null) 7130 {<div class="grid__col-md-12 grid grid--direction-row product__prices-container gray-background"> 7131 7132 <div class="grid grid__col-6 prices_text u-padding-y-sm"> 7133 7134 <div class="grid__col-md-12 u-padding-y-sm">@Translate("Din pris")</div> 7135 {{#if isShowPrice}} 7136 <div class="grid__col-md-12 u-flex--row u-padding-y-sm" id="mainProductPrice"><p class="u-margin-none-custom"><strong class="bold-900 without-vat-price">{{priceWithoutVAT}}</strong><span class="without-vat-text"> @Translate("excl. VAT")</span></p></div> 7137 <div class="grid__col-md-12 u-padding-y-sm"><p class="u-margin-none-custom"><span class="with-vat-price">({{priceWithVAT}}</span><span class="with-vat-text"> @Translate("incl. VAT"))</span></p></div> 7138 {{else}} 7139 <br /> 7140 <div class="grid__col-md-12 u-padding-y-sm" style="color:#2D2D2D;">@Translate("Select variant for price")</div> 7141 {{/if}} 7142 </div> 7143 7144 7145 <div class="grid grid__col-6 retail-prices logged-in u-padding-y-sm"> 7146 <div class="grid__col-md-12 u-padding-y-sm">@Translate("Vejledende udsalgspris")</div> 7147 {{#if isShowPrice}} 7148 <div class="grid__col-md-12 u-padding-y-sm @(isMobileOrTablet ? "" : "u-flex--row")"> 7149 @{ 7150 try 7151 { 7152 <p class="u-margin-none-custom"> 7153 <span class="bold-900 without-vat-price" id="retailPrices" data-retailPriceWithoutVat="@(retailPrice.RetailPriceExVAT)" data-retailPriceWithVat="@(retailPrice.RetailPriceInclVAT)">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture), true)</span> 7154 <span class="without-vat-text"> @Translate("excl. VAT")</span> 7155 </p> 7156 } 7157 catch 7158 { 7159 @Translate("Kunne ikke hente vejl. udsalgspris uden moms") 7160 } 7161 } 7162 7163 </div> 7164 <div class="grid__col-md-12 u-padding-y-sm @(isMobileOrTablet ? "" : "u-flex--row")"> 7165 @{ 7166 try 7167 { 7168 <p class="u-margin-none-custom"> 7169 <span class="with-vat-price">(@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice?.RetailPriceInclVAT ?? "", System.Globalization.CultureInfo.InvariantCulture), true)</span> 7170 <span class="with-vat-text"> @Translate("incl. VAT") </span>) 7171 </p> 7172 7173 7174 } 7175 catch 7176 { 7177 @Translate("Kunne ikke hente vejl. udsalgspris med moms") 7178 7179 } 7180 } 7181 7182 </div> 7183 {{else}} 7184 <br /> 7185 <div class="grid__col-md-12 u-padding-y-sm" style="color:#2D2D2D;">@Translate("Select variant for price")</div> 7186 {{/if}} 7187 </div> 7188 </div> } 7189 else 7190 { 7191 <div class="grid__col-md-6 grid grid--direction-row product__prices-container gray-background"> 7192 <div class="grid grid__col-6 logged-out retail-prices u-padding-y-sm"> 7193 <div class="grid__col-md-12 u-padding-y-sm">@Translate("Vejledende udsalgspris")</div> 7194 {{#if isShowPrice}} 7195 <div class="grid__col-md-12 u-flex--row u-padding-y-sm"> 7196 @{ 7197 try 7198 { 7199 <p class="u-margin-none-custom"> 7200 <span class="bold-900 u-padding-right" id="retailPrices" data-retailPriceWithoutVat="@(retailPrice.RetailPriceExVAT)" data-retailPriceWithVat="@(retailPrice.RetailPriceInclVAT)">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceInclVAT, System.Globalization.CultureInfo.InvariantCulture), true)</span> 7201 @(Translate("incl. VAT")) 7202 </p> 7203 } 7204 catch 7205 { 7206 @Translate("Kunne ikke hente vejl. udsalgspris med moms") 7207 7208 } 7209 } 7210 </div> 7211 <div class="grid__col-md-12 u-flex--row u-padding-y-sm"> 7212 @{ 7213 try 7214 { 7215 <p class="u-margin-none-custom"> 7216 <span class="u-padding-right">(@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture), true)</span> 7217 @Translate("excl. VAT") ) 7218 </p> 7219 } 7220 catch 7221 { 7222 @Translate("Kunne ikke hente vejl. udsalgspris uden moms") 7223 } 7224 } 7225 7226 </div> 7227 {{else}} 7228 <br /> 7229 <div class="grid__col-md-12 u-padding-y-sm" style="color:#2D2D2D;">@Translate("Select variant for price")</div> 7230 {{/if}} 7231 </div> 7232 </div> 7233 } 7234 </div> 7235 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 7236 if (showVATPrice) 7237 { 7238 <div class="vat-price vat-price--product-page u-margin-top dw-mod"> 7239 @if (isPricesWithVATEnabled) 7240 { 7241 <span>@Translate("excl. VAT")</span><span id="priceWithoutVatInfoCustom"> ({{priceWithoutVAT}})</span> 7242 } 7243 else 7244 { 7245 <span>@Translate("incl. VAT")</span><span id="priceWithVatInfoCustom"> ({{priceWithVAT}})</span> 7246 } 7247 </div> 7248 } 7249 <text> 7250 {{#if priceRRP}} 7251 <div><small>@Translate("RRP") {{priceRRP}}</small></div> 7252 {{/if}} 7253 </text> 7254 } 7255 {{/.}} 7256 7257 </script> 7258 7259 7260 7261 } 7262 } 7263 7264 7265 @helper RenderBuyCustom() 7266 { 7267 if (!mainInfoRenderVariantsAsProducts && showCartButton) 7268 { 7269 @RenderMainInfoBuyScriptsCustom(); 7270 } 7271 } 7272 7273 @helper RenderMainInfoBuyScriptsCustom() 7274 { 7275 bool showPrice = !Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HidePrice"); 7276 bool pointShopOnly = Pageview.AreaSettings.GetItem("Ecommerce").GetBoolean("PointShopOnly"); 7277 string cartIcon = Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon") != null ? Pageview.AreaSettings.GetItem("Layout").GetItem("Icons").GetList("CartIcon").SelectedValue : "fas fa-shopping-cart"; 7278 bool showVATPrice = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("ShowBothPricesWithWithoutVAT"); 7279 bool isPricesWithVATEnabled = Converter.ToBoolean(Pageview.Area.EcomPricesWithVat); 7280 int minicartId = GetPageIdByNavigationTag("MiniCartFeed"); 7281 7282 var customerId = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId(); 7283 var shopId = Pageview.Area.EcomShopId; 7284 var orderType = Dynamicweb.Ecommerce.Orders.OrderType.Order; 7285 var cartsList = (List<Dynamicweb.Ecommerce.Orders.Order>)Dynamicweb.Ecommerce.Services.Orders.GetCustomerOrdersByType(customerId, shopId, orderType, 0, false, "", DateTime.MinValue, false, true); 7286 7287 string isloggedin = "false"; 7288 if (Pageview.User != null) 7289 { 7290 isloggedin = "true"; 7291 } 7292 7293 <div class="product__price-actions dw-mod product__price-actions-custom gray-background u-padding-left-md-custom" id="PriceAndActionsConfigurator"></div> 7294 <input type="hidden" value="@GetString("Ecom:Product.VariantID.Extented")" name="Variant" id="Variant_@GetString("Ecom:Product.ID")" /> 7295 @* Handlebars templates *@ 7296 <script id="PricesAndActionsTemplate" type="text/x-template"> 7297 {{#.}} 7298 @if (Pageview.User != null) 7299 { 7300 <div id="bulkpricesContainer" class="u-flex u-flex--column u-padding-top" style="padding-left:6px"></div> 7301 <text>{{#if ShowLargeOrderRequestText}}</text> 7302 <div class="u-padding-top u-padding-left--lg"> 7303 @Translate("Custom:LargeOrderRequestText") 7304 </div> 7305 <text>{{/if}}</text> 7306 } 7307 @if (configurationsItems.Categories.Count() > 0) 7308 { 7309 <div class="grid__col-12 grid grid--direction-row"> 7310 <div class="grid__col-6-auto @(isMobileOrTablet? "stock-container-mobile " : "stock-container ")"> 7311 @RenderStockAndShippingCustom() 7312 </div> 7313 </div> 7314 } 7315 else 7316 { 7317 if (GetLoop("VariantGroups").Count > 0) 7318 { 7319 <div class="@(isMobileOrTablet? "grid__col-12 " : "grid__col-6 ")"> 7320 @RenderMainInfoVariantsCustom() 7321 </div> 7322 7323 <div class="grid__col-6-auto @(isMobileOrTablet? "stock-container-mobile " : "u-padding-left--lg ")"> 7324 @RenderStockAndShippingCustom() 7325 </div> 7326 } 7327 else 7328 { 7329 <div class="grid__col-6-auto u-padding-top--lg @(isMobileOrTablet? "stock-container-mobile " : "u-padding-left--lg")"> 7330 @RenderStockAndShippingCustom() 7331 </div> 7332 } 7333 7334 } 7335 7336 7337 7338 7339 @{var addToCartBtn = new Button 7340 { 7341 Id = "AddToCartCustomBtn", 7342 ButtonLayout = GetEnumSetting(ButtonLayout.Primary), 7343 Title = Translate("Add to cart"), 7344 Icon = new Icon { Prefix = "fal", Name = "fa-shopping-cart", LabelPosition = IconLabelPosition.After }, 7345 CssClass = "u-flex-grow--1", 7346 ExtraAttributes = new Dictionary<string, string> 7347 { 7348 { "{{disabledBuyButton}}", "" } 7349 } 7350 }; } 7351 7352 <div class="product__price-actions-wrap u-padding-top--lg u-align-center dw-mod u-padding-x"> 7353 <input class="cartQuantity u-margin-right-custom" id="cartQuantity" data-productNumber="{{number}}" data-productName="{{name}}" data-productID="{{productId}}" data-variantID="{{variantid}}" data-unitID="{{unitId}}" data-priceWithoutVatUnformatted="{{priceWithoutVATUnformatted}}" data-priceWithoutVat="{{priceWithoutVAT}}" data-priceWithVAT="{{priceWithVAT}}" data-priceWithVatUnformatted="{{priceWithVATUnformatted}}" type="number" value="1" min="0" max="10000"> 7354 7355 7356 @if (showCartButton && Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 7357 { 7358 var currentUsername = GetGlobalValue("Global:Extranet.UserName"); 7359 if (currentUsername != "dw_dk@variant.dk" && currentUsername != "dw_de@variant.dk" && currentUsername != "dw_se@variant.dk" && currentUsername != "dw_no@variant.dk" && currentUsername != "dw_ex@variant.dk") 7360 { 7361 @Render(addToCartBtn) 7362 } 7363 } 7364 else 7365 { 7366 int dealerPageId = GetPageIdByNavigationTag("Find_dealer"); 7367 string dealerPageLink = "/Default.aspx?ID=" + dealerPageId; 7368 <a href="@dealerPageLink"> 7369 @Render(new Button 7370 { 7371 ButtonLayout = GetEnumSetting(ButtonLayout.Primary), 7372 Title = Translate("Find forhandler"), 7373 CssClass = "u-flex-grow--1 u-flex", 7374 Id = "findDealerBuyReplacementBtn" 7375 }) 7376 </a> 7377 7378 } 7379 7380 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")) && User.IsBuyingAllowed() && cartsList.Count > 0 && GetPageIdByNavigationTag("OrderDraft") != 0) 7381 { 7382 var addToDraftCart = new Button 7383 { 7384 Id = "AddToDraftCart", 7385 Title = Translate("Add to draft"), 7386 ButtonLayout = ButtonLayout.Secondary, 7387 OnClick = "document.getElementById('OrderDraftSelectModalTrigger').checked = true", 7388 CssClass = "u-margin-top u-margin-left u-no-margin-top u-padding-x-sm-custom", 7389 Icon = new Icon { Prefix = "fal", Name = "fa-clipboard-list-check u-mr-10px", LabelPosition = IconLabelPosition.After }, 7390 ExtraAttributes = new Dictionary<string, string> 7391 { 7392 { "{{disabledBuyButton}}", "" } 7393 } 7394 }; 7395 var currentUsername = GetGlobalValue("Global:Extranet.UserName"); 7396 if (currentUsername != "dw_dk@variant.dk" && currentUsername != "dw_de@variant.dk" && currentUsername != "dw_se@variant.dk" && currentUsername != "dw_no@variant.dk" && currentUsername != "dw_ex@variant.dk") 7397 { 7398 @Render(addToDraftCart) 7399 } 7400 } 7401 7402 @if (Pageview.User != null && !pointShopOnly && Dynamicweb.Security.Licensing.LicenseManager.LicenseHasFeature("LoyaltyPoints")) 7403 { 7404 <text> 7405 {{#if canBePurchasedWithPoints}} 7406 <form method="post" role="form" class="u-no-margin u-margin-top"> 7407 <input type="hidden" name="ProductID" value="{{id}}" /> 7408 <button type="submit" class="btn btn--loyalty-points product__price-points-buy-button u-no-margin dw-mod pull-right u-no-margin js-cart-btn {{disabledBuyButton}}" name="CartCmd" value="addWithPoints">@Translate("Buy for") {{points}} @Translate("points")</button> 7409 </form> 7410 {{/if}} 7411 </text> 7412 } 7413 7414 </div> 7415 7416 {{#if ExtraAccessories}} 7417 <div class="grid__col-12 grid u-flex--row extra-accessories-container"> 7418 <p class="u-full-width extra-accessories-title">@Translate("Følger med") <span class="u-underline">@Translate("uden") </span>@Translate("beregning")</p> 7419 {{#each ExtraAccessories}} 7420 <div class="grid__col-6 u-flex--row u-flex--align-center u-justify-content--end"> 7421 <img src="/Files/Images/Icons/Checkmark-blue-background.svg" class="u-padding-right extra-accessories-icon" /> 7422 <div class="u-break-word"> 7423 <p class="u-no-margin--bottom extra-accessories-text"> 7424 {{this.Title}} 7425 </p> 7426 <p class="u-no-margin--bottom extra-accessories-price"> 7427 (@Translate("Værdi") {{this.Pricetext}}) 7428 </p> 7429 </div> 7430 7431 </div> 7432 {{/each}} 7433 </div> 7434 {{/if}} 7435 7436 {{/.}} 7437 </script> 7438 7439 <script> 7440 @{ 7441 if(Pageview.User != null) 7442 { 7443 <text> 7444 function useBulkpriceQuantity(input) { 7445 document.getElementById('cartQuantity').value = input.value; 7446 }; 7447 7448 document.getElementById("PriceAndActionsConfigurator").addEventListener("contentLoaded", function () { 7449 var bulkpricesContainer = document.getElementById('bulkpricesContainer'); 7450 var quantityElement = document.getElementById('cartQuantity'); 7451 var customerId = '@Pageview.User.CustomerNumber'; 7452 fetch('/api/variant/bulkprices/' + quantityElement.getAttribute('data-productNumber') + '/' + customerId, { 7453 method: 'GET', 7454 }).then(response => (response.status === 200 ? response.json() : "")).then(data => { 7455 var radioButtonsTemplate = `<p style="padding-left: 6px;" class="u-bold">@Translate("Bulkdiscount ex. VAT")</p>`; 7456 if (data.length > 0) { 7457 var bulkPricesObject = JSON.parse(data); 7458 for (var i = 0; i < bulkPricesObject.Bulkprices.length; i++) { 7459 var currentBulkprice = bulkPricesObject.Bulkprices[i]; 7460 var uniqueIdentifier = `${i}_${currentBulkprice.Price}`; 7461 radioButtonsTemplate += `<div class="radio-item"> 7462 <input type="radio" name="bulkdiscounts" ${i === 0 ? "checked" : ""} id="${uniqueIdentifier}" onchange="useBulkpriceQuantity(this);" value="${currentBulkprice.MinQuantity}"> 7463 <label for="${uniqueIdentifier}"></label><span><b style="padding-right:1px;">${currentBulkprice.MinQuantity} </b> @Translate("for") ${currentBulkprice.Price} ${currentBulkprice.Currency}. @Translate("pr/stk")</span></div>`; 7464 } 7465 7466 bulkpricesContainer.innerHTML = radioButtonsTemplate; 7467 } 7468 }); 7469 }); 7470 </text> 7471 } 7472 } 7473 7474 7475 function hasClass(elem, cls) { 7476 var str = " " + elem.className + " "; 7477 var testCls = " " + cls + " "; 7478 return (str.indexOf(testCls) != -1); 7479 } 7480 7481 function nextByClass(node, cls) { 7482 while (node = node.nextSibling) { 7483 if (hasClass(node, cls)) { 7484 return node; 7485 } 7486 } 7487 return null; 7488 } 7489 7490 function prevByClass(node, cls) { 7491 while (node = node.previousSibling) { 7492 if (hasClass(node, cls)) { 7493 return node; 7494 } 7495 } 7496 return null; 7497 } 7498 7499 function activateConfiguratorItem(event) { 7500 var element = nextByClass(event.target, "configuratorSelectorQuantity"); 7501 var event = new Event('input'); 7502 element.dispatchEvent(event); 7503 } 7504 7505 function uuidv4() { 7506 return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => 7507 (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) 7508 ); 7509 } 7510 7511 function parseNumber(value, locales = '@Dynamicweb.Ecommerce.Common.Context.Currency.CultureInfo') { 7512 if (typeof value == 'number') { 7513 return value; 7514 } 7515 const example = Intl.NumberFormat(locales).format("1.1"); 7516 const cleanPattern = new RegExp(`[^-+0-9${example.charAt(1)}]`, 'g'); 7517 const cleaned = value.toString().replace(cleanPattern, ''); 7518 return parseFloat(cleaned.replace(',', '.')); 7519 } 7520 7521 async function updateTotalPriceAnonymous(isOnPageload = false, updateCookie = false) { 7522 var configuratorSelectors = document.getElementsByClassName('configuratorSelectorQuantity'); 7523 var currencySymbol = '@Dynamicweb.Ecommerce.Common.Context.Currency.Symbol'; 7524 if (typeof document.getElementById('retailPrices')?.getAttribute('data-retailpricewithvat') === undefined) { 7525 return; 7526 } 7527 var priceWithoutVat = document.getElementById('cartQuantity').getAttribute('data-pricewithoutvatUnformatted').toString().replace(currencySymbol, "").trim(); 7528 var retailPriceWithVat = parseFloat(document.getElementById('retailPrices')?.getAttribute('data-retailpricewithvat') ?? "0"); 7529 var retailPriceWithoutVat = parseFloat(document.getElementById('retailPrices')?.getAttribute('data-retailpricewithoutvat') ?? "0"); 7530 var mainProductPrice = await formatPrice(retailPriceWithVat, currencySymbol); 7531 var productsSummaryTemplate = ""; 7532 productsSummaryTemplate += formatProductForSummary("", "", "",mainProductPrice , true); 7533 var configuratorSessionItems = []; 7534 7535 for (i = 0; i < configuratorSelectors.length; i++) { 7536 var quantity = (configuratorSelectors[i].value < 1) ? configuratorSelectors[i].value = 0 : configuratorSelectors[i].value; 7537 if (quantity > 0) { 7538 retailPriceWithVat = parseFloat(retailPriceWithVat) + (parseFloat(configuratorSelectors[i].getAttribute('data-retailpricewithvat')) * quantity); 7539 retailPriceWithoutVat = parseFloat(retailPriceWithoutVat) + (parseFloat(configuratorSelectors[i].getAttribute('data-retailpriceexclvat')) * quantity); 7540 var productPriceWithVat = (parseFloat(configuratorSelectors[i].getAttribute('data-retailpricewithvat')) * quantity); 7541 var productName = configuratorSelectors[i].getAttribute('data-productName'); 7542 var productId = configuratorSelectors[i].getAttribute('data-productid'); 7543 7544 productsSummaryTemplate += formatProductForSummary(productName, quantity, await formatPrice(productPriceWithVat, currencySymbol)); 7545 configuratorSessionItems.push({ ProductId: productId, Quantity: quantity}); 7546 } 7547 } 7548 7549 updateConfiguratorSessionManager(configuratorSessionItems); 7550 7551 refreshSummaryContainer(productsSummaryTemplate); 7552 7553 7554 var mainProductQuantity = document.getElementById('cartQuantity').value; 7555 7556 retailpriceWithoutVat = parseNumber(retailPriceWithoutVat) * mainProductQuantity; 7557 retailPriceWithVat = parseNumber(retailPriceWithVat * mainProductQuantity); 7558 7559 var summaryContainerBottom = document.getElementById('summary-table-bottom'); 7560 //console.trace('updateTotalPriceAnonymous formatPriceForSummary', await formatPrice(retailPriceWithoutVat, currencySymbol), await formatPrice(retailPriceWithoutVat, currencySymbol), await formatPrice(retailPriceWithVat, currencySymbol), retailPriceWithoutVat, retailPriceWithoutVat) 7561 if (summaryContainerBottom) { 7562 summaryContainerBottom.innerHTML = formatPriceForSummary(await formatPrice(retailPriceWithoutVat, currencySymbol), await formatPrice(retailPriceWithoutVat, currencySymbol), await formatPrice(retailPriceWithVat, currencySymbol), retailPriceWithoutVat, retailPriceWithoutVat); 7563 } 7564 @if (isMobileOrTablet) 7565 { 7566 <text> 7567 refreshStickySummary(await formatPrice(retailPriceWithVat, currencySymbol)); 7568 </text> 7569 } 7570 if (!isOnPageload) { 7571 highlightBorderOnProductChange(); 7572 } 7573 }; 7574 7575 function updateConfiguratorSessionManager(configuratorItemsDictionary) { 7576 var sessionManagerFeedId = '@GetPageIdByNavigationTag("ConfiguratorSessionManagerFeed")'; 7577 var formData = new FormData(); 7578 formData.append("ConfiguratorItems", JSON.stringify(configuratorItemsDictionary)); 7579 formData.append("ProductId", "@GetString("Ecom:Product.ID")"); 7580 7581 //console.log('updateConfiguratorSessionManager:' + sessionManagerFeedId); 7582 7583 fetch(`/Default.aspx?ID=${sessionManagerFeedId}`, { 7584 method: 'post', 7585 body: formData, 7586 }).then(response => response.json()).then(function (json) {}); 7587 } 7588 7589 7590 async function updateTotalPrice(isOnPageload = false, updateCookie = false) { 7591 var isLoggedIn = '@(Pageview.User != null ? "true" : "false")'; 7592 if (isLoggedIn === 'false') { 7593 7594 updateTotalPriceAnonymous(isOnPageload, false); 7595 return; 7596 } 7597 7598 var configuratorSelectors = document.getElementsByClassName('configuratorSelectorQuantity'); 7599 var currencySymbol = '@Dynamicweb.Ecommerce.Common.Context.Currency.Symbol'; 7600 7601 var priceWithVat = document.getElementById('cartQuantity').getAttribute('data-pricewithvatUnformatted').toString().replace(currencySymbol, "").trim(); 7602 var priceWithoutVat = document.getElementById('cartQuantity').getAttribute('data-pricewithoutvatUnformatted').toString().replace(currencySymbol, "").trim(); 7603 if (document.getElementById('retailPrices')?.getAttribute('data-retailpricewithvat') === null) { 7604 return; 7605 } 7606 var retailPriceWithVat = parseFloat(document.getElementById('retailPrices')?.getAttribute('data-retailpricewithvat') ?? "0"); 7607 var retailPriceWithoutVat = parseFloat(document.getElementById('retailPrices')?.getAttribute('data-retailpricewithoutvat') ?? "0"); 7608 var mainProductPrice = await formatPrice(parseNumber(priceWithoutVat), currencySymbol); 7609 var productsSummaryTemplate = ""; 7610 productsSummaryTemplate += formatProductForSummary("", "", "",mainProductPrice , true); 7611 7612 for (i = 0; i < configuratorSelectors.length; i++) { 7613 var quantity = (configuratorSelectors[i].value < 1) ? configuratorSelectors[i].value = 0 : configuratorSelectors[i].value; 7614 if (quantity > 0) { 7615 priceWithVat = parseNumber(priceWithVat) + (parseNumber(configuratorSelectors[i].getAttribute('data-priceraw').toString()) * quantity); 7616 priceWithoutVat = parseNumber(priceWithoutVat) + (parseNumber(configuratorSelectors[i].getAttribute('data-pricewithoutvat')) * quantity); 7617 retailPriceWithVat = parseFloat(retailPriceWithVat) + (parseFloat(configuratorSelectors[i].getAttribute('data-retailpricewithvat')) * quantity); 7618 retailPriceWithoutVat = parseFloat(retailPriceWithoutVat) + (parseFloat(configuratorSelectors[i].getAttribute('data-retailpriceexclvat')) * quantity); 7619 var productPriceWithoutVat = (parseNumber(configuratorSelectors[i].getAttribute('data-pricewithoutvat')) * quantity); 7620 var productName = configuratorSelectors[i].getAttribute('data-productName'); 7621 productsSummaryTemplate += formatProductForSummary(productName, quantity, await formatPrice(productPriceWithoutVat, currencySymbol)); 7622 var productId = configuratorSelectors[i].getAttribute('data-productid'); 7623 7624 } 7625 } 7626 refreshSummaryContainer(productsSummaryTemplate); 7627 7628 7629 var mainProductQuantity = document.getElementById('cartQuantity').value; 7630 7631 priceWithVat = parseNumber(priceWithVat) * mainProductQuantity; 7632 priceWithoutVat = parseNumber(priceWithoutVat) * mainProductQuantity; 7633 7634 var summaryContainerBottom = document.getElementById('summary-table-bottom'); 7635 //console.trace('updateTotalPrice formatPriceForSummary', await formatPrice(priceWithoutVat, currencySymbol), await formatPrice(retailPriceWithoutVat, currencySymbol), await formatPrice(retailPriceWithVat, currencySymbol), priceWithoutVat, retailPriceWithoutVat) 7636 if (summaryContainerBottom) { 7637 summaryContainerBottom.innerHTML = await formatPriceForSummary(await formatPrice(priceWithoutVat, currencySymbol), await formatPrice(retailPriceWithoutVat, currencySymbol), await formatPrice(retailPriceWithVat, currencySymbol), priceWithoutVat, retailPriceWithoutVat); 7638 renderSalesPrice(); 7639 } 7640 @if (isMobileOrTablet) 7641 { 7642 <text> 7643 refreshStickySummary(await formatPrice(priceWithoutVat, currencySymbol)); 7644 </text> 7645 } 7646 if (!isOnPageload) { 7647 highlightBorderOnProductChange(); 7648 } 7649 }; 7650 7651 async function formatPrice(price, currencySymbol) { 7652 if (price === undefined || price === null || isNaN(price)) { 7653 return "@Translate("Could not retrieve price")"; 7654 } 7655 var currencyFormattedFeedId = '@GetPageIdByNavigationTag("CurrencyFormattingFeed")'; 7656 var response = await fetch('/Default.aspx?ID=' + currencyFormattedFeedId + '&price=' + price); 7657 var responseDataJson = await response.json(); 7658 return responseDataJson.price; 7659 } 7660 function isNaN(num) { 7661 return num != num; 7662 } 7663 7664 function refreshStickySummary(totalPrice) { 7665 var stickyPriceContainer = document.getElementById('stickySummaryPrice'); 7666 if (stickyPriceContainer) { 7667 stickyPriceContainer.innerHTML = totalPrice; 7668 } 7669 } 7670 7671 function highlightBorderOnProductChange() { 7672 var currentBorder; 7673 var bgopacity = 1.0 7674 var container = document.getElementById("summaryContainer"); 7675 if (container && container.getAttribute('data-fading') !== true) { 7676 container.setAttribute('data-fading', true); 7677 var bgfade = function () { 7678 bgopacity -= 0.02 7679 7680 if (bgopacity === 1.0) { 7681 currentBorder = container.style.border; 7682 } 7683 container.style.border = "2px solid rgba(26, 127, 81, " + bgopacity + ")"; 7684 if (bgopacity >= 0) { 7685 setTimeout(bgfade, 30); 7686 } 7687 else { 7688 container.setAttribute('data-fading', false); 7689 container.style.border = currentBorder; 7690 } 7691 } 7692 bgfade(); 7693 } 7694 } 7695 7696 function formatProductForSummary(productName, productQuantity, productPriceWithoutVat, mainProductPrice = "", isMainProduct = false) { 7697 var productQuant = +productQuantity; 7698 var mainProductName = document.getElementById('cartQuantity').getAttribute('data-productName'); 7699 var mainProductQuantity = document.getElementById('cartQuantity').value; 7700 var mainProductTemplate = `<div class=\"grid__col-12 u-flex u-flex--row summary-table-bold u-no-padding\">` + 7701 `<div class=\"grid__col-7\"><span class="u-flex u-flex--row"><span class="u-padding-right-sm min-width-35">${mainProductQuantity+" @Translate("stk.")"}</span> ${mainProductName}</span></div>` + 7702 `<div class=\"grid__col-5 u-text-align-end\">${mainProductPrice}</div>` + 7703 `</div>`; 7704 var productTemplate = `<div class=\"grid__col-12 u-flex u-flex--row summary-table-text u-no-padding\">` + 7705 `<div class=\"grid__col-8 summary-icon\"><span class="u-flex u-flex--row"><span class="u-padding-right-sm min-width-35">${productQuant + " @Translate("stk.")"}</span> ${productName}</span></div>` + 7706 `<div class=\"grid__col-4 u-text-align-end\">${productPriceWithoutVat}</div>`+ 7707 `</div >`; 7708 7709 if (isMainProduct) { 7710 return mainProductTemplate; 7711 } 7712 else { 7713 return productTemplate; 7714 } 7715 } 7716 7717 function refreshSummaryContainer(productsSummaryTemplate) { 7718 const summaryContainer = document.getElementById('summary-table-top'); 7719 if (summaryContainer !== null) { 7720 summaryContainer.innerHTML = productsSummaryTemplate; 7721 7722 const summaryTableExpandBtn = summaryContainer.closest('.expand-container')?.querySelector('label[for]'); 7723 if (summaryTableExpandBtn) { 7724 const summaryTableExpandInput = document.getElementById(summaryTableExpandBtn.getAttribute('for')); 7725 const hasConfigRows = summaryContainer.querySelector('.summary-table-text') !== null 7726 if (hasConfigRows === true) { 7727 summaryTableExpandBtn.classList.remove('u-hidden'); 7728 summaryTableExpandInput.checked = false; 7729 } else { 7730 summaryTableExpandBtn.classList.add('u-hidden'); 7731 summaryTableExpandInput.checked = true; 7732 } 7733 } 7734 } 7735 } 7736 7737 function formatPriceForSummary(mainProductPrice, retailPriceExVat = "", retailPriceIncVat = "", priceWithoutVat = "", retailPriceWithoutVat = "") { 7738 7739 //console.log('formatPriceForSummary mainProductPrice',mainProductPrice) 7740 //console.log('formatPriceForSummary retailPriceExVat',retailPriceExVat) 7741 //console.log('formatPriceForSummary retailPriceIncVat',retailPriceIncVat) 7742 //console.log('formatPriceForSummary priceWithoutVat',priceWithoutVat) 7743 //console.log('formatPriceForSummary retailPriceWithoutVat',retailPriceWithoutVat) 7744 7745 var mainProductTemplate = `<div class=\"grid__col-12 u-flex u-flex--row summary-table-bold u-no-padding\">` + 7746 `<div class=\"grid__col-8 totalprice-summary\"><span>${"@Translate("Totalpris inkl. tilvalg") <span class=\"totalprice-vattext\">@Translate("(eksl. moms)")</span>"}</span></div>` + 7747 `<div class=\"grid__col-4 u-text-align-end js-totalprice-with-addons\" data-total-price-with-addons=\"${priceWithoutVat}\">${mainProductPrice}</div>` + 7748 `</div>`; 7749 var retailPricesExVatTemplate = `<div class=\"grid__col-12 u-flex u-flex--row summary-table-text u-no-padding\">` + 7750 `<div class=\"grid__col-7\">${"@Translate("Vejl. Udsalgspris (eksl. moms)")"}</div>` + 7751 `<div class=\"grid__col-5 u-text-align-end js-totalretailprice-with-addons\" data-total-retail-price-with-addons=\"${retailPriceWithoutVat}\">${retailPriceExVat}</div>` + 7752 `</div>`; 7753 var retailPricesIncVatTemplate = `<div class=\"grid__col-12 u-flex u-flex--row summary-table-text u-no-padding @(Pageview.User == null ? "summary-price-anonymous" :"")\">` + 7754 `<div class=\"grid__col-7\"><span>@Translate("Vejl. Udsalgspris") <span class=\"retailprice-vattext\">@Translate("(inkl. moms)")</span></span></div>` + 7755 `<div class=\"grid__col-5 u-text-align-end\">${retailPriceIncVat}</div>` + 7756 `</div>`; 7757 7758 var isloggedin = @isloggedin; 7759 if (isloggedin !== false) { 7760 if (retailPriceExVat !== "" && retailPriceIncVat !== "") { 7761 return mainProductTemplate + retailPricesExVatTemplate + retailPricesIncVatTemplate; 7762 } 7763 else if (retailPriceIncVat) { 7764 return retailPricesIncVatTemplate; 7765 } 7766 } 7767 else { 7768 return retailPricesIncVatTemplate + retailPricesExVatTemplate; 7769 } 7770 return mainProductTemplate; 7771 } 7772 7773 function addConfiguratorItemsAndMainProductToCart(isConfiguratorBuyButton,l) { 7774 var clickedButton = l; 7775 var clickedButtonText = clickedButton.innerHTML; 7776 var clickedButtonWidth = clickedButton.offsetWidth; 7777 var clickedButtonStyleWidth = clickedButton.style.width; 7778 7779 clickedButton.classList.add("disabled"); 7780 clickedButton.disabled = true; 7781 clickedButton.innerHTML = "<i class=\"fas fa-circle-notch fa-spin\"></i>"; 7782 clickedButton.style.width = clickedButtonWidth + "px"; 7783 var data = new FormData(); 7784 var guid = uuidv4(); 7785 var mainProductInfo = document.getElementById('cartQuantity'); 7786 var mainProductQuantity = mainProductInfo.value; 7787 var configuratorDropdowns = document.getElementsByClassName('configuratorSelectorQuantity'); 7788 var hasAnyConfiguratorOptionsBeenSelected = false; 7789 for (var i = 0; i < configuratorDropdowns.length; i++) { 7790 //Check if any configurator options have been selected 7791 if (configuratorDropdowns[i].value > 0) { 7792 hasAnyConfiguratorOptionsBeenSelected = true; 7793 break; 7794 } 7795 } 7796 data.append('ProductLoopCounter1', 1); 7797 data.append('Quantity1', mainProductQuantity); 7798 data.append('ProductID1', mainProductInfo.getAttribute('data-productID')); 7799 data.append('VariantID1', mainProductInfo.getAttribute('data-variantID')); 7800 data.append('UnitID1', mainProductInfo.getAttribute('data-unitID')); 7801 if (hasAnyConfiguratorOptionsBeenSelected === true && isConfiguratorBuyButton) { 7802 //It's only a configurator item if there have been chosen 1 or more configurations 7803 data.append('EcomOrderLineFieldInput_IsToplevelProduct1', true); 7804 data.append('EcomOrderLineFieldInput_OrderTransactionID1', guid); 7805 7806 for (i = 2; i < configuratorDropdowns.length + 2; i++) { 7807 var currentConfigurator = configuratorDropdowns[i - 2]; 7808 7809 if (currentConfigurator.value > 0) { 7810 data.append('ProductLoopCounter' + i, i); 7811 data.append('Quantity' + i, currentConfigurator.value * mainProductQuantity); 7812 data.append('ProductID' + i, currentConfigurator.getAttribute('data-productID')); 7813 data.append('VariantID' + i, currentConfigurator.getAttribute('data-variantID')); 7814 data.append('UnitID' + i, currentConfigurator.getAttribute('data-unitID')); 7815 if (currentConfigurator.getAttribute('data-isConfigurator') === 'Yes' || 7816 currentConfigurator.getAttribute('data-isConfigurator') === 'Ja' ) { 7817 data.append('EcomOrderLineFieldInput_OrderTransactionID' + i, guid); 7818 data.append('EcomOrderLineFieldInput_IsToplevelProduct' + i, false); 7819 } 7820 } 7821 } 7822 } 7823 data.append('CartCmd', 'addmulti'); 7824 7825 fetch('/Default.aspx?ID=@minicartId&feedType=Counter&redirect=false', { 7826 method: 'POST', 7827 body: data 7828 }).then(response => response.json()).then(function (json) { 7829 document.getElementById('cartCounter').firstElementChild.innerHTML = json[0].numberofproducts; 7830 document.getElementById('cartCounter').firstElementChild.setAttribute('data-count', json[0].numberofproducts); 7831 7832 Cart.UpdateMiniCart('miniCartTrigger', 'miniCart', 'cartCounter', '/Default.aspx?ID=@minicartId&feedType=MiniCart&redirect=false'); 7833 Cart.HideMiniCart('miniCart', 'miniCartTrigger'); 7834 var event = new CustomEvent('cartUpdated', { 'detail': { "command": 'addmulti', "data": json } }); 7835 document.dispatchEvent(event); 7836 clickedButton.classList.remove("disabled"); 7837 clickedButton.disabled = false; 7838 clickedButton.innerHTML = clickedButtonText; 7839 clickedButton.style.width = clickedButtonStyleWidth; 7840 }); 7841 }; 7842 7843 function sleep(ms) { 7844 return new Promise(resolve => setTimeout(resolve, ms)); 7845 } 7846 7847 document.addEventListener("DOMContentLoaded", function () { 7848 if (document.getElementById("PriceAndActionsConfigurator")) { 7849 7850 document.getElementById("PriceAndActionsConfigurator").addEventListener("contentLoaded", function (event) { 7851 var configuratorSelectorsUpdate = document.getElementsByClassName('configuratorSelectorQuantity'); 7852 7853 if (document.querySelector(".js-variants") != null) { 7854 MatchVariants.Update(document.querySelector(".js-variants"), "DoNothing"); 7855 } 7856 7857 @{ 7858 if(Pageview.User != null) 7859 { 7860 <text>updateTotalPrice(true);</text> 7861 } 7862 } 7863 7864 7865 @if(Pageview.User != null) 7866 { 7867 <text> 7868 document.getElementById('AddToCartCustomBtn').addEventListener("click", function(e) { 7869 e.preventDefault(); 7870 addConfiguratorItemsAndMainProductToCart(false, document.getElementById('AddToCartCustomBtn')); 7871 }); 7872 </text> 7873 7874 if (configurationsItems.Categories.Count() > 0) 7875 { 7876 var currentUsername = GetGlobalValue("Global:Extranet.UserName"); 7877 if (currentUsername != "dw_dk@variant.dk" && currentUsername != "dw_de@variant.dk" && currentUsername != "dw_se@variant.dk" && currentUsername != "dw_no@variant.dk" && currentUsername != "dw_ex@variant.dk") 7878 { 7879 <text> 7880 7881 document.getElementById('AddAllToCartCustomBtn').addEventListener("click", function(e) { 7882 e.preventDefault(); 7883 addConfiguratorItemsAndMainProductToCart(true, document.getElementById('AddAllToCartCustomBtn')); 7884 }); 7885 </text> 7886 } 7887 } 7888 7889 7890 } 7891 document.getElementById('cartQuantity').addEventListener('change', function (e) { 7892 updateTotalPrice(true, true); 7893 }); 7894 7895 }); 7896 } 7897 }); 7898 setTimeout(function() {updateTotalPrice(false,false)}, 2000); 7899 7900 </script> 7901 7902 7903 7904 7905 } 7906 7907 7908 @helper RenderMainInfoVariantsCustom(string title = "") 7909 { 7910 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 7911 string productId = GetString("Ecom:Product.ID"); 7912 string variantSelection = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("variantId")) ? HttpContext.Current.Request.QueryString.Get("variantId").Replace(".", ",") : ""; 7913 string hideHelpText = ""; 7914 string variantsLayout = Pageview.AreaSettings.GetItem("Ecommerce").GetString("VariantsLayout") != null ? Pageview.AreaSettings.GetItem("Ecommerce").GetList("VariantsLayout").SelectedValue : "buttons"; 7915 7916 foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 7917 { 7918 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions")) 7919 { 7920 if (variantoption.GetBoolean("Ecom:VariantOption.Selected")) 7921 { 7922 hideHelpText = "u-hidden"; 7923 } 7924 } 7925 } 7926 7927 if (GetLoop("VariantGroups").Count > 0) 7928 { 7929 var variantCombinationsObject = new List<Array>(); 7930 foreach (LoopItem variantcomb in GetLoop("VariantCombinations")) 7931 { 7932 string[] combinations = variantcomb.GetString("Ecom:VariantCombination.VariantID").Split('.'); 7933 variantCombinationsObject.Add(combinations); 7934 } 7935 7936 string combinationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantCombinationsObject).Replace("\"", "\'"); 7937 7938 var variantGroupsObject = new List<List<String>>(); 7939 foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 7940 { 7941 var variantsObject = new List<String>(); 7942 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 7943 { 7944 variantsObject.Add(variantOption.GetString("Ecom:VariantOption.ID")); 7945 } 7946 variantGroupsObject.Add(variantsObject); 7947 } 7948 7949 string variantsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantGroupsObject).Replace("\"", "\'"); 7950 string productGroupId = HttpContext.Current.Request["GroupId"]; 7951 7952 <div> 7953 <div class="js-variants" data-total-variant-groups="@GetLoop("VariantGroups").Count" data-combinations="@combinationsJson" data-variants="@variantsJson" data-variant-selections="@variantSelection" data-selection-complete="UpdatePage" data-page-id="@pageId" data-product-id="@productId" data-group-id="@productGroupId"> 7954 @foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 7955 { 7956 string groupId = variantGroup.GetString("Ecom:VariantGroup.ID"); 7957 7958 <div> 7959 <div class="product__variant-group-name u-bold dw-mod"> 7960 @if (title == "trailer") 7961 { 7962 <div style="display:inline-block"> 7963 <img src="/Files/Images/Icons/Warning_sign.svg" width="16" /> 7964 </div> 7965 } 7966 @Translate("Vælg") @variantGroup.GetString("Ecom:VariantGroup.Name").ToLower() 7967 </div> 7968 <div class="u-margin-top"> 7969 @if (variantsLayout == "buttons") 7970 { 7971 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 7972 { 7973 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 7974 string color = !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Colorcode")) ? variantOption.GetString("Ecom:VariantOption.Colorcode") : null; 7975 color = color == null && !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Color")) ? variantOption.GetString("Ecom:VariantOption.Color") : color; 7976 7977 if (!String.IsNullOrEmpty(color)) 7978 { 7979 <button type="button" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" onclick="MatchVariants.SelectThis(event)" class="btn btn--colorbox u-margin-right @selected js-variant-option" data-check="@selected" style="background-color: @color"></button> 7980 } 7981 else 7982 { 7983 <button type="button" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" onclick="MatchVariants.SelectThis(event)" class="btn btn--tag @selected js-variant-option" data-check="@selected">@variantOption.GetString("Ecom:VariantOption.Name")</button> 7984 } 7985 } 7986 } 7987 else 7988 { 7989 <select id="VariantSelector_@groupId" class="u-full-width dw-mod" name="VariantSelector_@groupId" onchange="MatchVariants.SelectOnChange(event)" style="width:30% !important;"> 7990 <option>@Translate("Choose")</option> 7991 @foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 7992 { 7993 string check = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 7994 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "selected" : ""; 7995 string color = !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Colorcode")) ? variantOption.GetString("Ecom:VariantOption.Colorcode") : null; 7996 color = color == null && !String.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.Color")) ? variantOption.GetString("Ecom:VariantOption.Color") : color; 7997 7998 <option class="js-variant-option @selected" id="@(groupId)_@variantOption.GetString("Ecom:VariantOption.ID")" value="@(groupId)_@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" @selected data-check="@check">@variantOption.GetString("Ecom:VariantOption.Name")</option> 7999 } 8000 </select> 8001 } 8002 </div> 8003 </div> 8004 } 8005 </div> 8006 <small class="js-help-text help-text @hideHelpText">@Translate("Please select variant!")</small> 8007 </div> 8008 } 8009 } 8010 8011 8012 8013 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 8014 @using Dynamicweb.Core 8015 @using System 8016 @using System.Web 8017 @using System.Collections.Generic 8018 @using System.Globalization 8019 @using Dynamicweb.Ecommerce.Products 8020 @using Dynamicweb.Frontend 8021 @using Dynamicweb.Rapido.Services 8022 @using Dynamicweb.Rapido.Blocks 8023 @using Dynamicweb.Rapido.Blocks.Components.Ecommerce 8024 @using Dynamicweb.Rapido.Blocks.Components.General 8025 @using Dynamicweb.Logging 8026 @using Variant.VariantConfigurator; 8027 @using Variant.Configurator.Shared; 8028 @using Variant.SparePartLookup 8029 8030 8031 @functions{ 8032 8033 int counter; 8034 ConfiguratorSessionManager configuratorItemsFromSession = null; 8035 string retailPriceUsername = Dynamicweb.Frontend.PageView.Current().AreaSettings?.GetItem("Variant")?.GetUsers("Retailprice_Impersonation_User")?.FirstOrDefault()?.Email ?? ""; 8036 8037 private string GetQuantityFromSession(string productId) 8038 { 8039 string quantity = "0"; 8040 if (Pageview.User == null) 8041 { 8042 return quantity; 8043 } 8044 8045 if (configuratorItemsFromSession?.ProductId != null && (configuratorItemsFromSession?.ProductId?.Equals(GetString("Ecom:Product.ID"), StringComparison.OrdinalIgnoreCase) ?? false)) 8046 { 8047 if (configuratorItemsFromSession.ConfiguratorItems != null && configuratorItemsFromSession.ConfiguratorItems.Any(x => x.ProductId.Equals(productId, StringComparison.OrdinalIgnoreCase))) 8048 { 8049 quantity = configuratorItemsFromSession.ConfiguratorItems.First(x => x.ProductId.Equals(productId, StringComparison.OrdinalIgnoreCase)).Quantity; 8050 } 8051 } 8052 8053 return quantity; 8054 } 8055 8056 private List<Bulkprice> GetBulkPrices(string itemNumber) 8057 { 8058 List<Bulkprice> bulkPrices = new List<Bulkprice>(); 8059 8060 try 8061 { 8062 string customerNumber = Pageview.User?.CustomerNumber; 8063 bulkPrices = new BulkpricesService().GetQuantityPrices(itemNumber, customerNumber); 8064 } 8065 catch (Exception _) 8066 { 8067 // ignored 8068 } 8069 8070 return bulkPrices; 8071 } 8072 8073 private Dictionary<string, List<Bulkprice>> GetBulkPrices(List<string> itemNumbers) 8074 { 8075 Dictionary<string, List<Bulkprice>> bulkPrices = new Dictionary<string, List<Bulkprice>>(); 8076 8077 try 8078 { 8079 string customerNumber = Pageview.User?.CustomerNumber; 8080 bulkPrices = new BulkpricesService().GetQuantityPricesMulti(itemNumbers, customerNumber); 8081 } 8082 catch (Exception _) 8083 { 8084 // ignored 8085 } 8086 8087 return bulkPrices; 8088 } 8089 } 8090 8091 @{ 8092 configuratorItemsFromSession = ConfiguratorSessionManagerHelper.Get(); 8093 8094 Block mainInfoConfiguratorCustom = new Block() 8095 { 8096 Id = "MainInfoConfiguratorCustom", 8097 SortId = 20, 8098 Template = RenderMainInfoConfiguratorCustom() 8099 }; 8100 8101 Block orderDraftScriptsCustom = new Block 8102 { 8103 Id = "OrderDraftScripts", 8104 SortId = 110, 8105 Template = RenderOrderDraftScriptsCustom() 8106 }; 8107 8108 Block renderQuoteMessage = new Block 8109 { 8110 Id = "RenderQuoteMessage", 8111 SortId = 30, 8112 Template = RenderQuoteSentMessage() 8113 }; 8114 8115 //From custom_blocks_maininformation 8116 if (!mainInfoRenderVariantsAsProducts && showCartButton && configurationsItems.Categories.Count() > 0) 8117 { 8118 mainInfoPageCustom.Add(mainInfoConfiguratorCustom); 8119 mainInfoPageCustom.Add(renderQuoteMessage); 8120 mainInfoPageCustom.ReplaceBlock(orderDraftScriptsCustom); 8121 8122 counter = 0; 8123 } 8124 } 8125 8126 @helper RenderQuoteSentMessage() 8127 { 8128 <input type="checkbox" id="QuoteSentMessageModalTrigger" class="modal-trigger"> 8129 <div class="modal-container"> 8130 <label for="QuoteSentMessageModalTrigger" id="QuoteSentMessageModalOverlay" class="modal-overlay"></label> 8131 <div class="modal modal--sm modal-height--auto" id="QuoteSentMessageModalTrigger"> 8132 <div class="modal__header"> 8133 <strong>@Translate("Custom:RequestQuote.Modal.Header", "Tak for din forespørgsel")</strong> 8134 </div> 8135 <div class="modal__body js-quote-sent-confirmation"> 8136 </div> 8137 <label class="modal__close-btn" for="QuoteSentMessageModalTrigger"></label> 8138 </div> 8139 </div> 8140 } 8141 8142 @helper RenderMainInfoConfiguratorCustom() 8143 { 8144 var configurationsItems = configurationsHelper.GetVariantConfigurationsById(GetString("Ecom:Product.Number")); 8145 bool editOpenQuote = configuratorItemsFromSession != null ? configuratorItemsFromSession.EditOpenQuote : false; 8146 string discountType = configuratorItemsFromSession != null ? configuratorItemsFromSession.DiscountType : "amount"; 8147 double discountPercent = configuratorItemsFromSession != null ? configuratorItemsFromSession.DiscountPercent : 0; 8148 List<(string discountName, double discountWithoutVAT)> discounts = configuratorItemsFromSession != null ? configuratorItemsFromSession.Discounts : null; 8149 List<(string productName, double priceWithoutVAT)> otherProducts = configuratorItemsFromSession != null ? configuratorItemsFromSession.OtherProducts : null; 8150 string customerName = configuratorItemsFromSession != null ? configuratorItemsFromSession.CustomerName : string.Empty; 8151 string customerEmail = configuratorItemsFromSession != null ? configuratorItemsFromSession.CustomerEmail : string.Empty; 8152 string customerComment = configuratorItemsFromSession != null ? configuratorItemsFromSession.CustomerComment : string.Empty; 8153 bool registration = configuratorItemsFromSession != null ? configuratorItemsFromSession.Registration : false; 8154 double registrationAmountWithoutVAT = registration ? configuratorItemsFromSession.RegistrationAmountWithoutVAT : 0; 8155 var countryCode = Pageview.Area.EcomCountryCode; 8156 string currentUsername = GetGlobalValue("Global:Extranet.UserName"); 8157 8158 Dictionary<string, List<(Dynamicweb.Ecommerce.Products.Product product, string configuration)>> configurations = new Dictionary<string, List<(Dynamicweb.Ecommerce.Products.Product product, string configuration)>>(); 8159 Dictionary<string, List<Bulkprice>> allBulkPrices = new Dictionary<string, List<Bulkprice>>(); 8160 8161 <div id="ContainerConfigurator" class=""> 8162 <div class="grid__col-lg-8 grid__col-md-8 grid__col-sm-12 grid__col-xs-12 dw-mod" id="configuratorCategoryList"> 8163 <div class="grid__col-12 configurator-title-container text-center-custom"> 8164 <h2>@Translate("Tilvalg til din trailer")</h2> 8165 <h3>@Translate("ProduktKonfigurationsOversættelse")</h3> 8166 @if (Pageview.User != null) 8167 { 8168 <h3>@Translate("Alle priser er eksl. moms")</h3> 8169 } 8170 </div> 8171 @if (!mainInfoRenderVariantsAsProducts && !mainInfoIsFamilyMember) 8172 { 8173 <div class="grid__col-12" style="text-align:center;"> 8174 @RenderMainInfoVariantsCustom("trailer") 8175 </div> 8176 } 8177 @{ 8178 if (configurationsItems?.Categories != null) 8179 { 8180 foreach (var category in configurationsItems.Categories) 8181 { 8182 var dwProducts = new List<(Dynamicweb.Ecommerce.Products.Product product, string configuration)>(); 8183 8184 foreach (var configuratorItem in category) 8185 { 8186 Dynamicweb.Ecommerce.Products.Product p = Dynamicweb.Ecommerce.Services.Products.GetProductByNumber(configuratorItem.RelatedProductID, Pageview.Area.EcomLanguageId); 8187 8188 if (p != null) 8189 { 8190 dwProducts.Add((p, configuratorItem.Configuration)); 8191 } 8192 else 8193 { 8194 continue; 8195 } 8196 } 8197 8198 configurations.Add(category.Key, dwProducts); 8199 } 8200 8201 if (configurations.Any()) 8202 { 8203 var products = configurations.SelectMany(kvp => kvp.Value).Select(x => x.product).ToList(); 8204 8205 //Fetch price and stock from NAV for all related configurations 8206 Dynamicweb.Ecommerce.LiveIntegration.Products.ProductManager.FetchProductInfos(products); 8207 8208 //Fetch bulk prices for all related configurations 8209 allBulkPrices = GetBulkPrices(products.Select(p => p.Number).ToList()); 8210 } 8211 8212 foreach (var category in configurations) 8213 { 8214 counter = 0; 8215 <div class="form__field-group u-margin-bottom dw-mod"> 8216 <div onclick="hideElement(this, 'categoryContainer')" class="collapsableCategory category--expanded"> 8217 <span></span><label>@Translate(@category.Key)</label> 8218 </div> 8219 @{ 8220 Categories++; 8221 <div class="categoryContainer grid"> 8222 @foreach (var configuratorItem in category.Value) 8223 { 8224 var p = configuratorItem.product; 8225 8226 try 8227 { 8228 counter++; 8229 var productLanguageId = Pageview.Area.EcomLanguageId.ToString(); 8230 8231 var retailPrices = new VariantRetailPricesHelper().GetVariantRetailPricesById(new List<string> { p.Id }); 8232 List<VariantRetailPrice> retailPricesForSingleCountry = new List<VariantRetailPrice>(); 8233 retailPrices?.variantRetailPrices?.TryGetValue(p.Id, out retailPricesForSingleCountry); 8234 8235 var retailPrice = retailPricesForSingleCountry?.SingleOrDefault(x => x.CountryCode == countryCode) ?? null; 8236 if (p.IsActive) 8237 { 8238 var priceInfo = Dynamicweb.Ecommerce.Prices.PriceManager.GetPrice(configuratorItem.product, Dynamicweb.Ecommerce.Common.Context.Currency.Code, Dynamicweb.Ecommerce.Common.Context.Country.Code2, Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId()); 8239 var priceFormatted = priceInfo.PriceWithoutVATFormatted; 8240 var priceFormattedWithVAT = priceInfo.PriceWithVATFormatted; 8241 8242 var customInfo = p.GetProductFieldValue("MountedDescription"); 8243 var classCustom = "notHasText"; 8244 if (customInfo != "") 8245 { 8246 classCustom = "hasText"; 8247 } 8248 8249 string path = imageService.GetImagePath(p); 8250 <div class="grid grid__col-12 grid--direction-row grid--align-center configurator-item-container u-margin-bottom u-no-padding-y"> 8251 @if (isMobileOrTablet) 8252 { 8253 <div class="grid__col-4 overlay-container"> 8254 <div class="overlay @classCustom close" style="opacity:0;display:none"> 8255 8256 <div class="grid"> 8257 8258 <div class="grid__col-sm-6 inside u-no-padding"> 8259 <img class="img-config" style="width: 100%; height: auto; width: fit-content; object-fit: contain" src='/Admin/Public/GetImage.ashx?Image=@path&Crop=5&Format=webP&Width=600&Height=400&Compression=75' alt=""> 8260 </div> 8261 @if (customInfo != "") 8262 { 8263 <div class="grid__col-sm-6 inside u-no-padding"> 8264 <div class="text u-padding--lg"> 8265 @customInfo 8266 </div> 8267 </div> 8268 } 8269 </div> 8270 <div class="config-close"> 8271 8272 <i class="fas fa-times"></i> 8273 8274 </div> 8275 </div> 8276 8277 <img onclick="mousein(event)" class="img-configurator" style="height: auto; width: fit-content; object-fit: contain;" src='/Admin/Public/GetImage.ashx?Image=@path&Crop=5&Format=webP&Width=600&Height=400&Compression=75' alt="" /> 8278 8279 8280 </div> 8281 <div class="grid__col-8 u-no-padding-y"> 8282 <div class="grid__col-12"> 8283 <p class="configurator-product-name-mobile u-no-margin--bottom"> 8284 @p.Name<br> 8285 @if (Pageview.User != null) 8286 { 8287 <span class="configurator-desc-number u-no-margin--bottom">@Translate("Varenr:") @p.Number</span> 8288 } 8289 </p> 8290 </div> 8291 <div class="grid__col-12"> 8292 8293 @if (Pageview.User != null) 8294 { 8295 if ((GetLoop("DWExtranetSecondaryUsers").Count > 0 || !string.IsNullOrWhiteSpace(GetGlobalValue("Global:Extranet.SecondaryUser.UserID")))) 8296 { 8297 <p class="configurator-product-price-mobile u-no-margin--bottom">@priceFormattedWithVAT</p> 8298 <p class="configurator-desc-text-mobile u-no-margin--bottom"> 8299 (@Translate("Vejl. udsalgspris ekskl. moms") @Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice?.RetailPriceExVAT ?? "0.00", System.Globalization.CultureInfo.InvariantCulture), true)) 8300 </p> 8301 } 8302 else 8303 { 8304 <p class="configurator-product-price-mobile u-no-margin--bottom">@priceFormatted</p> 8305 <p class="configurator-desc-text-mobile u-no-margin--bottom"> 8306 (@Translate("Vejl. udsalgspris ekskl. moms") @Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice?.RetailPriceExVAT ?? "0.00", System.Globalization.CultureInfo.InvariantCulture), true)) 8307 </p> 8308 } 8309 } 8310 else 8311 { 8312 <p class="u-no-margin--bottom"> 8313 @Translate("Vejl. udsalgspris") <span class="configurator-product-price">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice?.RetailPriceInclVAT ?? "0.00", System.Globalization.CultureInfo.InvariantCulture), true)</span> 8314 </p> 8315 } 8316 </div> 8317 @{ 8318 List<Bulkprice> bulkPrices = new List<Bulkprice>(); 8319 8320 bool hasBulkPrices = false; 8321 8322 if (allBulkPrices.TryGetValue(p.Number, out bulkPrices)) 8323 { 8324 if (bulkPrices != null && bulkPrices.Any(x => Converter.ToInt32(x.MinQuantity) > 1)) 8325 { 8326 hasBulkPrices = true; 8327 } 8328 } 8329 8330 string popoverToggleClasses = hasBulkPrices == true ? "popover-target" : "popover-target u-visually-hidden"; 8331 } 8332 <div class="grid__col-12 u-no-padding-y configuratorSelectorQuantity-custom"> 8333 <input class="configuratorSelectorQuantity" oninput="updateTotalPrice(false, true);" oldQuantity="0" value="@GetQuantityFromSession(p.Id)" type="text" inputmode="numeric" pattern="[0-9]*" onfocusin="if(this.value === '0'){this.value='';}else{this.select();}" onfocusout="if(this.value === ''){this.value = this.defaultValue;}" data-isConfigurator="@configuratorItem.configuration" data-productName="@p.Name" data-retailPriceExclVat="@(retailPrice?.RetailPriceExVAT ?? "0.00")" data-retailPriceWithVat="@(retailPrice?.RetailPriceInclVAT ?? "0.00")" data-quantity="1" data-productID="@p.Id" data-variantID="@p.VariantId" id="@(category.Key + counter)" data-unitID="@p.DefaultUnitId" data-priceFormatted="@priceFormatted" 8334 data-priceRaw="@priceInfo.PriceWithVAT.ToString()" data-priceWithoutVat="@priceInfo.PriceWithoutVAT"><br> 8335 <div class="@popoverToggleClasses" data-popover="#popover-@p.Id-mobile"> 8336 <div> 8337 <img src="/Files/Images/Icons/price-tag.svg" style="width: 20px;"> 8338 </div> 8339 </div> 8340 </div> 8341 @if (hasBulkPrices == true) 8342 { 8343 <div id="popover-@p.Id-mobile" class="popover-content" style="display:none;"> 8344 <strong>@Translate("Mængdepriser inkl. moms")</strong><br><br> 8345 <table border="0"> 8346 @foreach (Bulkprice bulkPrice in bulkPrices) 8347 { 8348 <tr> 8349 <td>@Translate("v.") @bulkPrice.MinQuantity @Translate("stk")</td> 8350 <td style="text-align: right">@bulkPrice.Price @bulkPrice.Currency @Translate("pr/stk")</td> 8351 </tr> 8352 } 8353 </table> 8354 </div> 8355 } 8356 8357 </div> 8358 } 8359 else 8360 { 8361 <div class="overlay-container grid__col-lg-1 grid__col-md-2 grid__col-sm-12 grid__col-xs-12 u-align-content-center u-no-padding"> 8362 <div class="overlay @classCustom close" style="opacity:0;display:none" onmouseleave="hideHover(event)"> 8363 <div class="grid"> 8364 <div class="grid__col-sm-6 u-no-padding"> 8365 8366 <img class="img-config" style="width: 100%; height: auto; width: fit-content; object-fit: contain" src='/Admin/Public/GetImage.ashx?Image=@path&Crop=5&Format=webP&Width=600&Height=400&Compression=75' alt=""> 8367 </div> 8368 @if (customInfo != "") 8369 { 8370 <div class="grid__col-sm-6 u-no-padding"> 8371 <div class="text u-padding--lg"> 8372 @customInfo 8373 </div> 8374 </div> 8375 } 8376 </div> 8377 </div> 8378 <img onmouseover="mousein(event)" class="img-configurator" style="height: auto; width:fit-content; object-fit: contain" src='/Admin/Public/GetImage.ashx?Image=@path&Crop=5&Format=webP&Width=60&Height=40&Compression=75' alt=""> 8379 </div> 8380 <div class="grid__col-5 u-align-content-left"> 8381 <p class="configurator-product-name u-no-margin--bottom"> 8382 @p.Name<br> 8383 @if (Pageview.User != null) 8384 { 8385 <span class="configurator-desc-number u-no-margin--bottom">@Translate("Varenr:") @p.Number</span> 8386 } 8387 </p> 8388 </div> 8389 if (Pageview.User != null) 8390 { 8391 <div class="grid__col-4 u-align-content-right configurator-item-price"> 8392 <div id="hiddenvalues" style="display:none;"> 8393 currentUser: @currentUsername . retail price 8394 username from backend: @retailPriceUsername 8395 </div> 8396 @if (currentUsername == retailPriceUsername) 8397 { 8398 <p class="configurator-product-price u-no-margin--bottom">@priceFormattedWithVAT</p> 8399 <p class="configurator-desc-text u-no-margin--bottom"> 8400 (@Translate("Vejl. udsalgspris ekskl. moms") @Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice?.RetailPriceExVAT ?? "0.00", System.Globalization.CultureInfo.InvariantCulture), true)) 8401 </p> 8402 } 8403 else 8404 { 8405 <p class="configurator-product-price u-no-margin--bottom">@priceFormatted</p> 8406 <p class="configurator-desc-text u-no-margin--bottom"> 8407 (@Translate("Vejl. udsalgspris ekskl. moms") @Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice?.RetailPriceExVAT ?? "0.00", System.Globalization.CultureInfo.InvariantCulture), true)) 8408 </p> 8409 } 8410 </div> 8411 } 8412 else 8413 { 8414 <div class="grid__col-4 u-align-content-right configurator-item-price"> 8415 <p class="configurator-desc-text u-no-margin--bottom"> 8416 @Translate("Vejl. udsalgspris") <span class="configurator-product-price">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice?.RetailPriceInclVAT ?? "0.00", System.Globalization.CultureInfo.InvariantCulture), true)</span> 8417 </p> 8418 </div> 8419 } 8420 8421 List<Bulkprice> bulkPrices = new List<Bulkprice>(); 8422 8423 bool hasBulkPrices = false; 8424 8425 if (allBulkPrices.TryGetValue(p.Number, out bulkPrices)) 8426 { 8427 if (bulkPrices != null && bulkPrices.Any(x => Converter.ToInt32(x.MinQuantity) > 1)) 8428 { 8429 hasBulkPrices = true; 8430 } 8431 } 8432 8433 string popoverToggleClasses = hasBulkPrices == true ? "popover-target" : "popover-target u-visually-hidden"; 8434 8435 <div class="grid__col-2 u-align-content-center"> 8436 <input class="configuratorSelectorQuantity" oninput="updateTotalPrice(false,true);" oldQuantity="0" data-isConfigurator="@configuratorItem.configuration" value="@GetQuantityFromSession(p.Id)" type="text" inputmode="numeric" pattern="[0-9]*" onfocusin="if(this.value === '0'){this.value='';}else{this.select();}" onfocusout="if(this.value === ''){this.value = this.defaultValue;}" data-productName="@p.Name" data-retailPriceExclVat="@(retailPrice?.RetailPriceExVAT ?? "0.00")" data-retailPriceWithVat="@(retailPrice?.RetailPriceInclVAT ?? "0.00")" data-quantity="1" data-productID="@p.Id" data-variantID="@p.VariantId" id="@(category.Key + counter)" data-unitID="@p.DefaultUnitId" data-priceFormatted="@priceFormatted" 8437 data-priceRaw="@priceInfo.PriceWithVAT.ToString()" data-priceWithoutVat="@priceInfo.PriceWithoutVAT"><br> 8438 <div class="@popoverToggleClasses" data-popover="#popover-@p.Id"> 8439 <div> 8440 <img src="/Files/Images/Icons/price-tag.svg" style="width: 20px;"> 8441 </div> 8442 </div> 8443 </div> 8444 if (hasBulkPrices == true) 8445 { 8446 <div id="popover-@p.Id" class="popover-content" style="display:none;"> 8447 <strong>@Translate("Mængdepriser inkl. moms")</strong><br><br> 8448 <table border="0"> 8449 @foreach (Bulkprice bulkPrice in bulkPrices) 8450 { 8451 <tr> 8452 <td>@Translate("v.") @bulkPrice.MinQuantity @Translate("stk")</td> 8453 <td style="text-align: right">@bulkPrice.Price @bulkPrice.Currency @Translate("pr/stk")</td> 8454 </tr> 8455 } 8456 </table> 8457 </div> 8458 } 8459 } 8460 8461 </div> 8462 } 8463 else 8464 { 8465 <div class="grid grid__col-12 grid--direction-row grid--align-center"> 8466 <p> 8467 @(Translate(p.Name) + Translate(" er udgået")); 8468 </p> 8469 </div> 8470 } 8471 } 8472 catch (Exception ex) 8473 { 8474 logger?.Error($"Failed to show configuratorProduct - see Exception: {ex.Message} {ex.StackTrace} {ex.Source} {p.Id}", ex); 8475 } 8476 } 8477 </div>} 8478 </div> 8479 } 8480 } 8481 } 8482 </div> 8483 @{ 8484 var addToCartBtn = new Button 8485 { 8486 Id = "AddAllToCartCustomBtn", 8487 ButtonLayout = GetEnumSetting(ButtonLayout.Primary), 8488 Title = Translate("Læg alle produkter i kurv"), 8489 Icon = new Icon { Prefix = "fal", Name = "fa-shopping-cart", LabelPosition = IconLabelPosition.After }, 8490 CssClass = "u-flex-grow--1", 8491 ExtraAttributes = new Dictionary<string, string> 8492 { 8493 { "{{disabledBuyButton}}", "" } 8494 } 8495 }; 8496 8497 8498 if (isMobileOrTablet) 8499 { 8500 <div class="grid__col-12 product-configurator-sticky-summary"> 8501 <div class="grid__col-12 u-flex--row u-hidden"> 8502 <span class="grid__col-7">@(Pageview.User == null ? Translate("Totalpris inkl. dine tilvalg(inkl. moms)") : Translate("Totalpris inkl. dine tilvalg(eksl. moms)"))</span><span class="grid__col-5" id="stickySummaryPrice"></span> 8503 </div> 8504 <script>document.addEventListener("DOMContentLoaded", () => { updateTotalPrice(false, true); });</script> 8505 8506 <input type="checkbox" id="summary-table-expandable-input" class="expand-trigger" checked="checked"> 8507 <div class="expand-container grid__col-12"> 8508 <label class="grid__col-12 text-center-custom u-hidden" for="summary-table-expandable-input">@Translate("Se konfigurations detaljer")</label> 8509 <div class="expand-container__content" data-input="summary-table-expandable-input"> 8510 <div class="" id="summary-table-top"> 8511 </div> 8512 </div> 8513 </div> 8514 8515 <div class="grid__col-12 summary-table-pricesummary" id="summary-table-bottom"> 8516 </div> 8517 @if (showCartButton && Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 8518 { 8519 if (currentUsername != retailPriceUsername) 8520 { 8521 <div class="grid__col-12"> 8522 8523 @Render(addToCartBtn) 8524 8525 </div> 8526 } 8527 } 8528 @if (Pageview.User == null) 8529 { 8530 <div class="grid__col-12"> 8531 <label for="OverlayDealerModalTrigger" class="btn btn--secondary btn--full u-no-margin dw-mod" onclick="resetManualLinesModal(); loadDealers();" onmouseenter="loadDealers();"> 8532 <i class="fal fa-envelope-open-text u-margin-right--lg u-w20px"></i> @Translate("Anmod om tilbud") 8533 </label> 8534 8535 </div> 8536 } 8537 </div> 8538 } 8539 else 8540 { 8541 <div class="u-flex u-flex--row grid__col-lg-4 grid__col-md-4 product-configurator-price-container u-flex--column u-margin-top--lg @(isMobileOrTablet ? "u-hidden" : "")" id="summaryContainer"> 8542 <div class="grid__col-12"><h2>@Translate("Opsummering")</h2></div> 8543 @* Container our JS populate *@ 8544 <div class="grid__col-12" id="summary-table-top"> 8545 @if (Pageview.User == null) 8546 { 8547 <h3>@Translate("Konfigurer din trailer og se samlet pris")</h3> 8548 } 8549 </div> 8550 @* Container our JS populate *@ 8551 <div class="grid__col-12 summary-table-pricesummary" id="summary-table-bottom"> 8552 </div> 8553 <div class="grid__col-12"> 8554 @if (showCartButton && Dynamicweb.Rapido.Services.User.IsBuyingAllowed()) 8555 { 8556 @Render(addToCartBtn) 8557 } 8558 </div> 8559 @if (Pageview.User != null && Pageview.AreaSettings.GetItem("Custom").GetBoolean("ShowManualLinesButton")) 8560 { 8561 <div class="grid__col-12"> 8562 <label for="OverlayDealerModalTrigger" class="btn btn--secondary btn--full u-no-margin dw-mod" onclick="resetManualLinesModal()"> 8563 <i class="fal fa-envelope-open-text u-margin-right--lg u-w20px"></i> @Translate("Add manual lines") 8564 </label> 8565 </div> 8566 } 8567 else if (Pageview.User == null) 8568 { 8569 <div class="grid__col-12"> 8570 <label for="OverlayDealerModalTrigger" class="btn btn--secondary btn--full u-no-margin dw-mod" onclick="resetManualLinesModal(); loadDealers();" onmouseenter="loadDealers();"> 8571 <i class="fal fa-envelope-open-text u-margin-right--lg u-w20px"></i> @Translate("Anmod om tilbud") 8572 </label> 8573 8574 </div> 8575 } 8576 </div> 8577 } 8578 } 8579 <script> 8580 let loadDealersPromise = null; 8581 const loadDealers = function () { 8582 const selectDealer = document.getElementById("js-customer-selected-dealer"); 8583 if (loadDealersPromise !== null) { 8584 return; 8585 } 8586 const preferredCountry = selectDealer.dataset.preferredCountry; 8587 8588 loadDealersPromise = fetch(selectDealer.dataset.dealerPageUrl) 8589 .then(response => { 8590 if (!response.ok) throw new Error('Failed to load dealer data'); 8591 return response.text(); 8592 }) 8593 .then(html => { 8594 const parser = new DOMParser(); 8595 const doc = parser.parseFromString(html, 'text/html'); 8596 8597 const dealers = doc.querySelectorAll('.dynamicweb-map__locations div[data-dealer-can-make-offer="true"][data-dealer-json]'); 8598 if (!dealers.length) return; 8599 8600 const dealerArray = Array.from(dealers).map(dealer => { 8601 const json = JSON.parse(dealer.dataset.dealerJson); 8602 return { 8603 company: json.Company, 8604 address: json.Address, 8605 zip: json.Zip, 8606 city: json.City, 8607 country: json.Country, 8608 value: json.Id, 8609 }; 8610 }); 8611 8612 // Group by country 8613 const grouped = dealerArray.reduce((acc, d) => { 8614 (acc[d.country] ||= []).push(d); 8615 return acc; 8616 }, {}); 8617 8618 // Sort each group by zip, then company 8619 for (const country in grouped) { 8620 grouped[country].sort((a, b) => { 8621 const zipA = parseInt(a.zip, 10) || 0; 8622 const zipB = parseInt(b.zip, 10) || 0; 8623 if (zipA !== zipB) return zipA - zipB; 8624 return a.company.localeCompare(b.company, undefined, { sensitivity: "base" }); 8625 }); 8626 } 8627 8628 // Sort countries, but prefer the one matching data-preferred-country 8629 const countries = Object.keys(grouped).sort((a, b) => a.localeCompare(b)); 8630 if (preferredCountry) { 8631 countries.sort((a, b) => { 8632 const aPref = a.toLowerCase() === preferredCountry; 8633 const bPref = b.toLowerCase() === preferredCountry; 8634 if (aPref && !bPref) return -1; 8635 if (bPref && !aPref) return 1; 8636 return a.localeCompare(b); 8637 }); 8638 } 8639 8640 // Render dropdown 8641 selectDealer.options[0].innerText = selectDealer.options[0].dataset.text; 8642 const selectCountry = document.getElementById("js-customer-selected-country"); 8643 selectCountry.options[0].innerText = ''; 8644 countries.forEach(country => { 8645 const optgroup = document.createElement("optgroup"); 8646 optgroup.label = country; 8647 8648 grouped[country].forEach(d => { 8649 const optionDealer = document.createElement("option"); 8650 optionDealer.value = d.value; 8651 optionDealer.textContent = `${d.zip} ${d.city} — ${d.company}, ${d.address}`; 8652 optgroup.appendChild(optionDealer); 8653 }); 8654 selectDealer.appendChild(optgroup); 8655 8656 if (selectCountry.querySelector('option[value="' + country + '"]') === null) { 8657 const optionCountry = document.createElement("option"); 8658 optionCountry.value = country; 8659 optionCountry.textContent = country; 8660 selectCountry.appendChild(optionCountry); 8661 } 8662 }); 8663 }) 8664 .catch(err => { 8665 console.error('Dealer select failed:', err); 8666 loadDealersPromise = null; 8667 }); 8668 }; 8669 const showDealersByCountry = function (selectCountry) { 8670 const strSelectedCountry = selectCountry?.options[selectCountry.selectedIndex].value ?? ''; 8671 document.querySelectorAll('#js-customer-selected-dealer optgroup').forEach(optgroup => { 8672 optgroup.style.display = strSelectedCountry === '' || optgroup.label === strSelectedCountry ? 'block' : 'none'; 8673 }); 8674 }; 8675 </script> 8676 </div> 8677 if (Pageview.User != null || Pageview.User == null) // Hack to maintain scope for conflicting variable names, sorry. 8678 { 8679 string productNumber = GetString("Ecom:Product.Number"); 8680 VariantRetailPrices retailPrices = new VariantRetailPricesHelper().GetVariantRetailPricesById(new List<string> { productNumber }); 8681 List<VariantRetailPrice> retailPricesForSingleCountry = new List<VariantRetailPrice>(); 8682 retailPrices?.variantRetailPrices?.TryGetValue(productNumber, out retailPricesForSingleCountry); 8683 VariantRetailPrice retailPrice = retailPricesForSingleCountry?.SingleOrDefault(x => x.CountryCode == countryCode); 8684 string variantid = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"); 8685 string httpDomain = Dynamicweb.Context.Current.Request.Url.Scheme + "://" + GetGlobalValue("Global:Request.Host"); 8686 string url = httpDomain + Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetString("Ecom:Product.LinkGroup.Clean") + (!string.IsNullOrWhiteSpace(variantid) ? "&VariantID=" + variantid : "")); 8687 string editOpenQuoteUrl = !string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("Custom").GetString("EditOpenQuoteUrl")) ? httpDomain + "/" + Pageview.AreaSettings.GetItem("Custom").GetString("EditOpenQuoteUrl") : ""; 8688 8689 <script src="/Files/Templates/Designs/Rapido/js/source/flatpickr.js"></script> 8690 <input type="checkbox" id="OverlayDealerModalTrigger" class="modal-trigger"> 8691 <div class="modal-container"> 8692 <label for="OverlayDealerModalTrigger" id="DealerModalOverlay" class="modal-overlay"></label> 8693 <div class="modal modal--md modal-height--auto" id="DealerInModal"> 8694 <div class="modal__header"> 8695 <div class=" dw-mod"> 8696 @if (Pageview.User != null) 8697 { 8698 @Translate("Add lines") 8699 } 8700 else 8701 { 8702 @Translate("Anmod om tilbud") 8703 } 8704 </div> 8705 </div> 8706 <div class="modal__body "> 8707 <form class="save_configuration_form js-save_configuration_form" data-edit-quote="@editOpenQuote"> 8708 @if (Pageview.User != null) 8709 { 8710 @*Before discount price*@ 8711 <div class="form__field-group u-full-width dw-mod"> 8712 <div class="grid"> 8713 <div class="grid__col-8 u-no-margin u-no-padding"> 8714 <label class="summary-table-bold">@Translate("AddLines.SalesPriceIncludingAddOns", "Vejl. Udsalgspris inkl. tilvalg") (@Translate("AddLines.Taxfree", "ekskl. moms"))</label> 8715 </div> 8716 <div class="grid__col-4 u-no-margin u-no-padding"> 8717 <label class="u-text-align-end js-totalprice-with-addons-configurator">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture), true)</label> 8718 </div> 8719 </div> 8720 </div> 8721 8722 @*Discount form*@ 8723 <div class="form__field-group u-full-width dw-mod"> 8724 <div class="grid "> 8725 <div class="grid__col-12 u-no-margin u-no-padding u-padding-bottom"> 8726 <label class="u-pull--left summary-table-bold">@Translate("AddLines.Discount.Titel", "Rabat") (@Translate("AddLines.Taxfree", "ekskl. moms"))</label> 8727 <label class="u-pull--left summary-table-text">@Translate("AddLines.Discount.SubTitel", "Vælg om det skal være i beløb eller i %") (@Translate("AddLines.Taxfree", "ekskl. moms"))</label> 8728 </div> 8729 </div> 8730 <div class="grid "> 8731 <div class=" u-no-margin u-no-padding u-padding-bottom"> 8732 <input type="radio" id="amount" name="discounttype" value="amount" onchange="selectDiscount();" @(discountType == "amount" ? "checked" : "")><label for="amount" style="padding-bottom: 0; vertical-align: top; line-height: 27px; float: left; padding-right:40px;">@Translate("AddLines.Discount.AmountText", "Beløb")</label> 8733 <input class="js-discount-radio-percent" type="radio" id="percent" name="discounttype" value="percent" onchange="selectDiscount();" @(discountType == "percent" ? "checked" : "")><label for="percent" style="padding-bottom: 0; vertical-align: top; line-height: 27px; float: left; ">@Translate("AddLines.Discount.PercentageText", "% Procent")</label> 8734 </div> 8735 </div> 8736 <div class="grid js-discount-line amount discount-line-amount"> 8737 @if (discounts != null && discounts.Any()) 8738 { 8739 int lineCounter = 0; 8740 8741 foreach (var discount in discounts) 8742 { 8743 <div class="grid__col-8 u-no-padding u-padding-right u-padding-bottom @(lineCounter > 0 ? "js-added" : string.Empty) js-discount"> 8744 <input name="discount" type="text" class="u-full-width dw-mod js-dealer-discount-name" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Discount.Name.Placeholder", "Indsæt navn på rabat"))" value="@discount.discountName"> 8745 </div> 8746 <div class="grid__col-4 u-no-padding @(lineCounter > 0 ? "js-added" : string.Empty) js-discount"> 8747 <input name="amountdiscount" type="text" class="u-full-width dw-mod number-input js-discount-input" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Discount.Size.Placeholder", "Rabatstørrelse"))" value="@discount.discountWithoutVAT"> 8748 </div> 8749 8750 lineCounter++; 8751 } 8752 } 8753 else if (discountType == "percent" && discountPercent > 0) 8754 { 8755 <div class="grid__col-8 u-no-padding u-padding-right u-padding-bottom js-discount"> 8756 <input name="discount" type="text" class="u-full-width dw-mod js-dealer-discount-name" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Discount.Name.Placeholder", "Indsæt navn på rabat"))" value="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Discount.Name.Default", "Rabat"))"> 8757 </div> 8758 <div class="grid__col-4 u-no-padding js-discount"> 8759 <input name="amountdiscount" type="text" class="u-full-width dw-mod number-input js-discount-input" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Discount.Size.Placeholder", "Rabatstørrelse"))" value="@discountPercent"> 8760 </div> 8761 } 8762 else 8763 { 8764 <div class="grid__col-8 u-no-padding u-padding-right u-padding-bottom"> 8765 <input name="discount" type="text" class="u-full-width dw-mod js-dealer-discount-name" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Discount.Name.Placeholder", "Indsæt navn på rabat"))"> 8766 </div> 8767 <div class="grid__col-4 u-no-padding"> 8768 <input name="amountdiscount" type="text" class="u-full-width dw-mod number-input js-discount-input" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Discount.Size.Placeholder", "Rabatstørrelse"))"> 8769 </div> 8770 } 8771 </div> 8772 8773 <div class="js-add-more-discount-lines u-full-width u-ta-right amount discount-line"> 8774 <a href="javascript:void(0)" class="u-pull--right u-brand-color-two text u-block summary-table-bold" id="addDiscount">@Translate("AddLines.AddLineText", "Add line+")</a> 8775 </div> 8776 8777 </div> 8778 @*After discount price*@ 8779 <div class="form__field-group u-full-width dw-mod u-border-bottom"> 8780 <div class="grid"> 8781 <div class="grid__col-8 u-no-margin u-no-padding"> 8782 <label class="summary-table-bold">@Translate("AddLines.SalesPriceAfterDiscount", "Salgspris efter rabat") (@Translate("AddLines.Taxfree", "ekskl. moms"))</label> 8783 </div> 8784 <div class="grid__col-4 u-no-margin u-no-padding"> 8785 <label class="u-text-align-end js-sales-price-after-discount">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture), true)</label> 8786 </div> 8787 <div class="grid__col-12 u-no-margin u-no-padding"> 8788 <label class="summary-table-bold accordion-header" onclick="toggleMyPriceAccordion(this)">@Translate("AddLines.SalesPriceAfterDiscount.ShowMyPrice", "+ Vis min pris")</label> 8789 <div class="accordion-content" style="display: none;"> 8790 @if (currentUsername == retailPriceUsername) 8791 { 8792 <label class="u-text-align-end">@Translate("AddLines.SalesPriceAfterDiscount.CantShowMyPrice", "Slå vis listepriser fra for at se min pris")</label> 8793 } 8794 else 8795 { 8796 <label class="u-text-align-end js-my-price-after-discount"></label> 8797 } 8798 </div> 8799 </div> 8800 <div class="grid__col-12 u-no-margin u-no-padding"> 8801 <label class="summary-table-delivery">@Translate("AddLines.SalesPriceAfterDiscount.Delivery", "Uden eventuel fragt")</label> 8802 </div> 8803 </div> 8804 </div> 8805 @*Trailer registration*@ 8806 <div class="form__field-group u-full-width dw-mod"> 8807 <div class="grid"> 8808 <div class="u-no-margin u-padding-bottom licenseplate-checkbox-container"> 8809 <input class="js-licenseplate licenseplate" type="checkbox" id="registration" name="register" value="registration" onchange="selectLicenseplate()" @(registration && registrationAmountWithoutVAT > 0 ? "checked" : string.Empty) )> 8810 <label class="licenseplate-label" for="registration">@Translate("AddLines.Licenseplate.Register", "Indregistrering af trailer")</label> 8811 <div class="grid__col-4 u-no-padding @(!registration ? "u-hidden" : string.Empty) js-licenseplate-line u-align-self-end"> 8812 <input name="licenseplateprice" type="text" class="u-full-width dw-mod number-input js-licenseplate-input" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.Licenseplate.Placeholder","Pris på nummerplade"))" value="@(registration ? Converter.ToString(registrationAmountWithoutVAT) : string.Empty)"> 8813 </div> 8814 </div> 8815 </div> 8816 </div> 8817 @*Other products*@ 8818 <div class="form__field-group u-full-width dw-mod"> 8819 <div class="grid "> 8820 <div class="grid__col-12 u-no-margin u-no-padding "> 8821 <label for="other-product" class="u-pull--left summary-table-bold">@Translate("Other product") </label> 8822 </div> 8823 </div> 8824 <div class="grid otherproduct-line"> 8825 @if (otherProducts != null && otherProducts.Any()) 8826 { 8827 foreach (var product in otherProducts) 8828 { 8829 <div class="grid__col-8 u-no-padding u-padding-right u-padding-bottom js-added"> 8830 <input name="otherproduct" type="text" class="u-full-width dw-mod" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.OtherProduct.Name.Placeholder", "Indsæt navn på produkt"))" value="@product.productName"> 8831 </div> 8832 <div class="grid__col-4 u-no-padding js-added"> 8833 <input name="amountproduct" type="text" class="u-full-width dw-mod number-input js-other-product-input" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.OtherProduct.Price.Placeholder", "Pris på produkt"))" value="@product.priceWithoutVAT"> 8834 </div> 8835 } 8836 } 8837 else 8838 { 8839 <div class="grid__col-8 u-no-padding u-padding-right u-padding-bottom"> 8840 <input name="otherproduct" type="text" class="u-full-width dw-mod" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.OtherProduct.Name.Placeholder", "Indsæt navn på produkt"))"> 8841 </div> 8842 <div class="grid__col-4 u-no-padding"> 8843 <input name="amountproduct" type="text" class="u-full-width dw-mod number-input js-other-product-input" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("AddLines.OtherProduct.Price.Placeholder", "Pris på produkt"))"> 8844 </div> 8845 } 8846 </div> 8847 <div class="add-more-lines u-full-width u-ta-right"> 8848 <a href="javascript:void(0)" class="u-pull--right u-brand-color-two text u-block summary-table-bold" id="addProduct">@Translate("Add line")+</a> 8849 </div> 8850 </div> 8851 @*Final price with and without tax*@ 8852 <div class="form__field-group u-full-width dw-mod u-border-bottom"> 8853 <div class="grid"> 8854 <div class="grid__col-8 u-no-margin u-no-padding"> 8855 <label class="summary-table-bold">@Translate("AddLines.FinalPrice", "Slutpris") (@Translate("AddLines.Tax", "inkl. moms"))</label> 8856 </div> 8857 <div class="grid__col-4 u-no-margin u-no-padding"> 8858 <label class="u-text-align-end js-sales-price-after-everything-with-tax">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture), true)</label> 8859 <input type="hidden" name="totalPriceWithoutTax" class="js-total-price-with-tax" /> 8860 </div> 8861 <div class="grid__col-8 u-no-margin u-no-padding"> 8862 <label class="summary-table-bold">@Translate("AddLines.FinalPrice", "Slutpris") (@Translate("AddLines.Taxfree", "ekskl. moms"))</label> 8863 </div> 8864 <div class="grid__col-4 u-no-margin u-no-padding"> 8865 <label class="u-text-align-end js-sales-price-after-everything-without-tax">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture), true)</label> 8866 <input type="hidden" name="totalPriceWithTax" class="js-total-price-without-tax" /> 8867 </div> 8868 </div> 8869 </div> 8870 @*Customer data*@ 8871 <div class="form__field-group u-full-width dw-mod"> 8872 <div class="grid "> 8873 <div class="grid__col-12 u-no-margin u-no-padding "> 8874 <label for="datepicker" class="u-pull--left summary-table-bold">@Translate("Select date") </label> 8875 </div> 8876 </div> 8877 <div class="grid datapicker-line"> 8878 <div class="grid__col-12 u-no-padding u-no-padding"> 8879 <input type="text" name="datepicker" id="datepicker" value="@DateTime.Today.ToString("dd-MM-yyyy")" /> 8880 </div> 8881 </div> 8882 </div> 8883 <div class="form__field-group u-full-width dw-mod"> 8884 <div class="grid "> 8885 <div class="grid__col-12 u-no-margin u-no-padding "> 8886 <label for="customername" class="u-pull--left summary-table-bold">@Translate("Customer name") </label> 8887 </div> 8888 </div> 8889 <div class="grid customername-line"> 8890 <div class="grid__col-12 u-no-padding u-no-padding"> 8891 <input type="text" name="customername" id="customername" value="@customerName" /> 8892 </div> 8893 </div> 8894 </div> 8895 <div class="form__field-group u-full-width dw-mod"> 8896 <div class="grid "> 8897 <div class="grid__col-12 u-no-margin u-no-padding "> 8898 <label for="email" class="u-pull--left summary-table-bold">@Translate("Overlay Email") </label> 8899 </div> 8900 </div> 8901 <div class="grid email-line"> 8902 <div class="grid__col-12 u-no-padding u-no-padding"> 8903 <input type="text" name="email" id="email" onchange="validateEmail(this)" value="@customerEmail"> 8904 <div class="u-color-danger u-hidden validation-error">@Translate("Invalid email address")</div> 8905 </div> 8906 </div> 8907 </div> 8908 <div class="form__field-group u-full-width dw-mod"> 8909 <div class="grid "> 8910 <div class="grid__col-12 u-no-margin u-no-padding "> 8911 <label for="comment" class="u-pull--left summary-table-bold">@Translate("Comment end customer") </label> 8912 </div> 8913 </div> 8914 <div class="grid otherproduct-line"> 8915 <div class="grid__col-12 u-no-padding u-no-padding"> 8916 <textarea id="comment" name="comment" type="text" class="u-full-width dw-mod">@customerComment</textarea> 8917 </div> 8918 </div> 8919 </div> 8920 8921 <button id="save_configuration_button" class="btn--full btn btn--primary dw-mod" title="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Save configuration"))" type="button">@Translate("Save configuration")</button> 8922 } 8923 else 8924 { 8925 @*Retail price*@ 8926 <div class="form__field-group u-full-width dw-mod"> 8927 <div class="grid "> 8928 <div class="grid__col-8 u-no-margin u-no-padding"> 8929 <label class="summary-table-bold">@Translate("Totalpris inkl. dine tilvalg(inkl. moms)")</label> 8930 </div> 8931 <div class="grid__col-4 u-no-margin u-no-padding"> 8932 <label class="u-text-align-end js-sales-price-after-everything-with-tax">@Dynamicweb.Ecommerce.Services.Currencies.Format(Dynamicweb.Ecommerce.Common.Context.Currency, Convert.ToDouble(retailPrice.RetailPriceInclVAT, System.Globalization.CultureInfo.InvariantCulture), true)</label> 8933 <input type="hidden" name="totalPriceWithoutTax" class="js-total-price-with-tax" /> 8934 </div> 8935 </div> 8936 </div> 8937 8938 @*Trailer registration*@ 8939 <div class="form__field-group u-full-width dw-mod"> 8940 <div class="grid "> 8941 <div class="grid__col-12 u-no-margin u-no-padding "> 8942 <label class="u-pull--left summary-table-bold">@Translate("Indregistrering af trailer") </label> 8943 </div> 8944 </div> 8945 <div class="grid"> 8946 <div class="u-no-margin u-no-padding licenseplate-checkbox-container"> 8947 <input class="js-licenseplate licenseplate" type="checkbox" id="registration" name="register" value="registration" onchange="selectLicenseplate()"> 8948 <label class="licenseplate-label" for="registration">@Translate("Ja tak, jeg ønsker indregistrering")</label> 8949 </div> 8950 </div> 8951 </div> 8952 8953 @*Customer data*@ 8954 <div class="form__field-group u-full-width dw-mod"> 8955 <div class="grid "> 8956 <div class="grid__col-12 u-no-margin u-no-padding "> 8957 <label for="customername" class="u-pull--left summary-table-bold">@Translate("Navn") </label> 8958 </div> 8959 </div> 8960 <div class="grid customername-line"> 8961 <div class="grid__col-12 u-no-padding u-no-padding"> 8962 <input required type="text" name="customername" id="customername" value="" /> 8963 </div> 8964 </div> 8965 </div> 8966 8967 <div class="form__field-group u-full-width dw-mod"> 8968 <div class="grid "> 8969 <div class="grid__col-12 u-no-margin u-no-padding "> 8970 <label for="customeraddress" class="u-pull--left summary-table-bold">@Translate("Adresse") </label> 8971 </div> 8972 </div> 8973 <div class="grid customeraddress-line"> 8974 <div class="grid__col-12 u-no-padding u-no-padding"> 8975 <input required type="text" name="customeraddress" id="customeraddress" value="" /> 8976 </div> 8977 </div> 8978 </div> 8979 8980 <div class="form__field-group u-full-width dw-mod"> 8981 <div class="grid "> 8982 <div class="grid__col-4 u-no-margin u-no-padding "> 8983 8984 <div class="grid u-padding-right"> 8985 <div class="grid__col-12 u-no-margin u-no-padding "> 8986 <label for="customerzip" class="u-pull--left summary-table-bold">@Translate("Postnr.") </label> 8987 </div> 8988 </div> 8989 <div class="grid customerzip-line"> 8990 <div class="grid__col-12 u-no-padding u-no-padding"> 8991 <input required type="text" name="customerzip" id="customerzip" value="" /> 8992 </div> 8993 </div> 8994 8995 </div> 8996 <div class="grid__col-8 u-no-margin u-no-padding "> 8997 8998 <div class="grid "> 8999 <div class="grid__col-12 u-no-margin u-no-padding "> 9000 <label for="customercity" class="u-pull--left summary-table-bold">@Translate("By") </label> 9001 </div> 9002 </div> 9003 <div class="grid customercity-line"> 9004 <div class="grid__col-12 u-no-padding u-no-padding"> 9005 <input required type="text" name="customercity" id="customercity" value="" /> 9006 </div> 9007 </div> 9008 </div> 9009 </div> 9010 </div> 9011 9012 <div class="form__field-group u-full-width dw-mod"> 9013 <div class="grid "> 9014 <div class="grid__col-12 u-no-margin u-no-padding "> 9015 <label for="js-customer-selected-country" class="u-pull--left summary-table-bold">@Translate("Land") </label> 9016 </div> 9017 </div> 9018 <div class="grid customercountry-line"> 9019 <div class="grid__col-12 u-no-padding u-no-padding"> 9020 <select id="js-customer-selected-country" onchange="showDealersByCountry(event.target);"> 9021 <option value="">@Translate("Finder lande...")</option> 9022 </select> 9023 </div> 9024 </div> 9025 </div> 9026 9027 <div class="form__field-group u-full-width dw-mod"> 9028 <div class="grid "> 9029 <div class="grid__col-12 u-no-margin u-no-padding "> 9030 <label for="email" class="u-pull--left summary-table-bold">@Translate("Email") </label> 9031 </div> 9032 </div> 9033 <div class="grid email-line"> 9034 <div class="grid__col-12 u-no-padding u-no-padding"> 9035 <input required type="text" name="email" id="email" onchange="validateEmail(this)"> 9036 <div class="u-color-danger u-hidden validation-error">@Translate("Invalid email address")</div> 9037 </div> 9038 </div> 9039 </div> 9040 9041 <div class="form__field-group u-full-width dw-mod"> 9042 <div class="grid "> 9043 <div class="grid__col-12 u-no-margin u-no-padding "> 9044 <label for="OrderCustomerPhone" class="u-pull--left summary-table-bold">@Translate("Telefon") </label> 9045 </div> 9046 </div> 9047 <div class="grid OrderCustomerPhone-line"> 9048 <div class="grid__col-12 u-no-padding u-no-padding"> 9049 <input required type="text" inputmode="tel" name="OrderCustomerPhone" id="OrderCustomerPhone" value="" /> 9050 </div> 9051 </div> 9052 </div> 9053 9054 @*Dealer*@ 9055 <div class="form__field-group u-full-width dw-mod"> 9056 <div class="grid"> 9057 <div class="grid__col-12 u-no-margin u-no-padding "> 9058 <label class="u-pull--left summary-table-bold">@Translate("Vælg forhandler") </label> 9059 </div> 9060 </div> 9061 <div class=""> 9062 @{ 9063 string dealerPageLink = "/Default.aspx?ID=" + GetPageIdByNavigationTag("Find_dealer"); 9064 RegionInfo languageCountry = new RegionInfo(Pageview.Area.CultureInfo.Name); 9065 } 9066 <select required name="customer-selected-dealer" id="js-customer-selected-dealer" data-dealer-page-url="@dealerPageLink" data-preferred-country="@languageCountry.EnglishName.ToLowerInvariant()"> 9067 <option value="" data-text="@HttpUtility.HtmlAttributeEncode(Translate("Vælg forhandler..."))">@Translate("Finder forhandlere...")</option> 9068 </select> 9069 </div> 9070 </div> 9071 9072 <div class="form__field-group u-full-width dw-mod"> 9073 <div class="grid "> 9074 <div class="grid__col-12 u-no-margin u-no-padding "> 9075 <label for="comment" class="u-pull--left summary-table-bold">@Translate("Kommentarer eller spørgsmål") </label> 9076 </div> 9077 </div> 9078 <div class="grid"> 9079 <div class="grid__col-12 u-no-padding u-no-padding"> 9080 <textarea id="comment" name="comment" type="text" class="u-full-width dw-mod"></textarea> 9081 </div> 9082 </div> 9083 </div> 9084 9085 @*Consent*@ 9086 <div class="form__field-group u-full-width dw-mod"> 9087 <div class="grid"> 9088 <div class="u-no-margin u-no-padding licenseplate-checkbox-container"> 9089 <input class="licenseplate u-align-self-start" required style="margin-top:12px;" type="checkbox" id="customer-consent" name="customer-consent" value="yes"> 9090 <label class="licenseplate-label" for="customer-consent">@Translate("Jeg acceptere at mine oplysninger bliver sendt videre til den valgte forhandler. Oplysningerne bliver gemt i 30 dage hvorefter de slettes.")</label> 9091 </div> 9092 </div> 9093 </div> 9094 9095 <button id="save_configuration_button" class="btn--full btn btn--primary dw-mod" title="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Save configuration"))" type="button">@Translate("Få et tilbud")</button> 9096 9097 } 9098 9099 9100 9101 9102 <script> 9103 eventListenerPriceInput(); 9104 renderSalesPrice(); 9105 9106 function resetManualLinesModal() { 9107 let configurationForm = document.querySelector(".js-save_configuration_form"); 9108 if (configurationForm != null && configurationForm.getAttribute('data-edit-quote') == 'False') { 9109 document.querySelector(".js-save_configuration_form").reset(); 9110 let createdElement = document.querySelectorAll('.js-added'); 9111 createdElement.forEach(el => { 9112 el.remove(); 9113 }); 9114 } 9115 renderSalesPrice(); 9116 selectDiscount(); 9117 } 9118 9119 function eventListenerPriceInput() { 9120 const discountInputs = document.querySelectorAll(".js-discount-input"); 9121 const licensePlateInput = document.querySelector(".js-licenseplate-input"); 9122 const otherProductInputs = document.querySelectorAll(".js-other-product-input") 9123 if (discountInputs.length > 0) { 9124 discountInputs.forEach(input => { 9125 input.addEventListener("keyup", renderSalesPrice) 9126 }); 9127 } 9128 if (licensePlateInput) { 9129 licensePlateInput.addEventListener("keyup", renderSalesPrice); 9130 } 9131 if (otherProductInputs.length > 0) { 9132 otherProductInputs.forEach(input => { 9133 input.addEventListener("keyup", renderSalesPrice); 9134 }); 9135 } 9136 } 9137 9138 function renderSalesPrice() { 9139 let currencyCode = '@Dynamicweb.Ecommerce.Common.Context.Currency.Code'; 9140 const form = document.querySelector(".js-save_configuration_form"); 9141 const params = new FormData(form); 9142 const licenseplateInput = document.querySelector('.js-licenseplate-input'); 9143 let licenseplatePrice = 0; 9144 let discountPercentage = 0; 9145 9146 params.forEach((value, key) => { 9147 if (params.get("discounttype") === "percent") { 9148 if (key === "amountdiscount") { 9149 if (value && !discountPercentage) { 9150 discountPercentage = (parseFloat(value) / 100); 9151 } 9152 } 9153 } 9154 }); 9155 9156 if (licenseplateInput?.value && licenseplateInput.value && !isNaN(parseFloat(licenseplateInput.value))) { 9157 licenseplatePrice = parseFloat(licenseplateInput.value); 9158 } 9159 9160 let totalPriceWithAddonsInput = document.querySelector('.js-totalprice-with-addons'); 9161 let totalRetailPriceWithAddonsInput = document.querySelector('.js-totalretailprice-with-addons'); 9162 9163 let initialPrice = parseFloat('@Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture)'); 9164 let initialRetailPrice = parseFloat('@Convert.ToDouble(retailPrice.RetailPriceExVAT, System.Globalization.CultureInfo.InvariantCulture)'); 9165 9166 if (totalPriceWithAddonsInput) { 9167 initialPrice = parseFloat(totalPriceWithAddonsInput.getAttribute('data-total-price-with-addons')); 9168 } 9169 renderPrice(".js-my-price-after-discount", initialPrice, currencyCode) 9170 9171 if (totalRetailPriceWithAddonsInput) { 9172 //console.log('totalRetailPriceWithAddonsInput',initialRetailPrice, parseFloat(totalRetailPriceWithAddonsInput.getAttribute('data-total-retail-price-with-addons'))); 9173 initialRetailPrice = parseFloat(totalRetailPriceWithAddonsInput.getAttribute('data-total-retail-price-with-addons')); 9174 } 9175 renderPrice(".js-totalprice-with-addons-configurator", initialRetailPrice, currencyCode); 9176 9177 //console.log('calculateProductPriceAfterDiscount',params, discountPercentage, initialRetailPrice) 9178 const productRetailPriceAfterDiscountWithoutTax = calculateProductPriceAfterDiscount(params, discountPercentage, initialRetailPrice); 9179 renderPrice(".js-sales-price-after-discount", productRetailPriceAfterDiscountWithoutTax, currencyCode); 9180 9181 //console.log( 'salesPriceWithoutTax', productRetailPriceAfterDiscountWithoutTax, licenseplatePrice, calculateCostOfOtherProducts(params)); 9182 const salesPriceWithoutTax = productRetailPriceAfterDiscountWithoutTax + licenseplatePrice + calculateCostOfOtherProducts(params); 9183 renderPrice(".js-sales-price-after-everything-without-tax", salesPriceWithoutTax, currencyCode, ".js-total-price-without-tax"); 9184 9185 const salesPriceWithTax = calculateSalesPriceWithTax(salesPriceWithoutTax - licenseplatePrice) + licenseplatePrice; 9186 //console.trace(".js-sales-price-after-everything-with-tax", salesPriceWithTax, currencyCode, ".js-total-price-with-tax"); 9187 renderPrice(".js-sales-price-after-everything-with-tax", salesPriceWithTax, currencyCode, ".js-total-price-with-tax"); 9188 } 9189 9190 function renderPrice(jsElementTag, price, currencyCode, jsInputElementTag) { 9191 const priceLabel = document.querySelector(jsElementTag); 9192 const inputPrice = document.querySelector(jsInputElementTag); 9193 9194 if (priceLabel) { 9195 priceLabel.innerHTML = formatPrice(price) + " " + currencyCode; 9196 } 9197 if (inputPrice) { 9198 inputPrice.value = price.toFixed(2); 9199 } 9200 } 9201 9202 function formatPrice(price) { 9203 const formattedPrice = price.toLocaleString('da-DK', { 9204 minimumFractionDigits: 2, 9205 maximumFractionDigits: 2, 9206 }); 9207 return formattedPrice; 9208 } 9209 9210 function calculateSalesPriceWithTax(salesPriceWithoutTax) { 9211 const tax = parseFloat('@GetDouble("Ecom:Product.VATPercent")'); 9212 let salesPriceWithTax = salesPriceWithoutTax * (1 + tax / 100); 9213 //console.log('calculateSalesPriceWithTax',salesPriceWithoutTax, (1 + tax / 100)) 9214 return salesPriceWithTax; 9215 } 9216 9217 function calculateCostOfOtherProducts(params) { 9218 let costOfOtherProducts = 0; 9219 params.forEach((value, key) => { 9220 if (key === "amountproduct") { 9221 if (value) { 9222 costOfOtherProducts += parseFloat(value); 9223 } 9224 } 9225 }); 9226 return costOfOtherProducts; 9227 } 9228 9229 function calculateProductPriceAfterDiscount(params, discountPercentage, initialPrice) { 9230 let salesPrice = initialPrice; 9231 let discount = 0; 9232 params.forEach((value, key) => { 9233 if (key === "amountdiscount") { 9234 if (params.get("discounttype") === "amount") { 9235 if (value) { 9236 discount += parseFloat(value); 9237 } 9238 } else { 9239 discount = salesPrice * discountPercentage; 9240 } 9241 } 9242 }); 9243 return salesPrice - discount; 9244 } 9245 9246 function toggleMyPriceAccordion(label) { 9247 let accordionContent = label.nextElementSibling; 9248 if (accordionContent.style.display === 'none') { 9249 accordionContent.style.display = 'block'; 9250 label.innerHTML = '@HttpUtility.JavaScriptStringEncode(Translate("AddLines.SalesPriceAfterDiscount.HideMyPrice", "- Skjul min pris"))'; 9251 } else { 9252 accordionContent.style.display = 'none'; 9253 label.innerHTML = '@HttpUtility.JavaScriptStringEncode(Translate("AddLines.SalesPriceAfterDiscount.ShowMyPrice", "+ Vis min pris"))'; 9254 } 9255 } 9256 9257 document.addEventListener("DOMContentLoaded", (event) => { 9258 let httpRequest; 9259 let clickedButton = document.getElementById('save_configuration_button'); 9260 if (clickedButton) { 9261 let clickedButtonWidth = clickedButton.offsetWidth; 9262 9263 clickedButton.addEventListener("click", event => { 9264 const form = document.querySelector(".js-save_configuration_form"); 9265 const isGetOfferForm = form.querySelector('#js-customer-selected-dealer') !== null; 9266 if (form.reportValidity() === true || isGetOfferForm === false) { 9267 clickedButton.classList.add("disabled"); 9268 clickedButton.disabled = true; 9269 clickedButton.innerHTML = "<i class=\"fas fa-circle-notch fa-spin\"></i>"; 9270 clickedButton.style.width = clickedButtonWidth + "px"; 9271 saveConfiguration(event); 9272 } 9273 }); 9274 9275 function alertContents() { 9276 if (httpRequest.readyState === XMLHttpRequest.DONE) { 9277 if (httpRequest.status === 200) { 9278 //console.log("saveConfiguration success. Download pdf"); 9279 if (httpRequest.responseText.length > 2) { 9280 document.getElementById('configuratordownload').src = '/api/variant/configurator/download/' + JSON.parse(httpRequest.responseText); 9281 } 9282 else { 9283 const confirmationPageId = '@GetPageIdByNavigationTag("QuoteSentConfirmationPage")'; 9284 9285 fetch('/Default.aspx?ID=' + confirmationPageId).then(function (response) { 9286 return response.text(); 9287 }).then(function (html) { 9288 const confirmationModalBody = document.querySelector(".js-quote-sent-confirmation"); 9289 if (confirmationModalBody !== null) { 9290 confirmationModalBody.innerHTML = html; 9291 } 9292 9293 document.getElementById('QuoteSentMessageModalTrigger').checked = true; 9294 9295 }).catch(function (err) { 9296 console.warn('Error fetching confirmation text', err); 9297 }); 9298 } 9299 9300 } else { 9301 alert("@(HttpUtility.JavaScriptStringEncode(Translate("There was a problem with the request").Trim())) " + httpRequest.responseText); 9302 } 9303 if (clickedButton) { 9304 clickedButton.classList.remove("disabled"); 9305 clickedButton.disabled = false; 9306 clickedButton.innerHTML = "@HttpUtility.JavaScriptStringEncode(Translate("Save configuration"))"; 9307 clickedButton.style.width = clickedButtonWidth + "px"; 9308 document.getElementById("OverlayDealerModalTrigger").checked = false; 9309 resetManualLinesModal(); 9310 } 9311 } 9312 } 9313 } 9314 9315 //console.log("listening for any saved configuration"); 9316 9317 function saveConfiguration() { 9318 let guid = uuidv4(); 9319 9320 //console.log("saveConfiguration - " + guid); 9321 httpRequest = new XMLHttpRequest(); 9322 9323 const form = document.querySelector(".js-save_configuration_form"); 9324 const params = new FormData(form); 9325 9326 params.append("url", "@url"); 9327 params.append("editOpenQuoteUrl", "@editOpenQuoteUrl"); 9328 collectProductData(params, guid); 9329 9330 if (!httpRequest) { 9331 //console.log("Giving up :( Cannot create an XMLHTTP instance"); 9332 return false; 9333 } 9334 httpRequest.onreadystatechange = alertContents; 9335 @if (Pageview.User != null) 9336 { 9337 <text> 9338 httpRequest.open("POST", "/api/variant/configurator/send/dealer", true); 9339 </text> 9340 } 9341 else 9342 { 9343 <text> 9344 httpRequest.open("POST", "/api/variant/configurator/send/anonymous", true); 9345 </text> 9346 } 9347 9348 httpRequest.send(params); 9349 } 9350 9351 function collectProductData(params, guid) { 9352 const mainProductInfo = document.getElementById('cartQuantity'); 9353 const mainProductQuantity = parseFloat(mainProductInfo.value); 9354 9355 const product = { 9356 Quantity: mainProductQuantity, 9357 ProductId: mainProductInfo.getAttribute('data-productID'), 9358 VariantId: mainProductInfo.getAttribute('data-variantID'), 9359 UnitId: mainProductInfo.getAttribute('data-unitID'), 9360 OrderTransactionId: guid, 9361 IsToplevelProduct: true 9362 } 9363 params.append("product", JSON.stringify(product)) 9364 9365 const configuratorDropdowns = document.getElementsByClassName('configuratorSelectorQuantity'); 9366 for (i = 2; i < configuratorDropdowns.length + 2; i++) { 9367 var currentConfigurator = configuratorDropdowns[i - 2]; 9368 9369 if (currentConfigurator.value > 0) { 9370 9371 const addOnProduct = { 9372 Quantity: currentConfigurator.value * mainProductQuantity, 9373 ProductId: currentConfigurator.getAttribute('data-productID'), 9374 VariantId: currentConfigurator.getAttribute('data-variantID'), 9375 UnitId: currentConfigurator.getAttribute('data-unitID') 9376 } 9377 9378 if (currentConfigurator.getAttribute('data-isConfigurator') === 'Yes' || 9379 currentConfigurator.getAttribute('data-isConfigurator') === 'Ja') { 9380 addOnProduct.OrderTransactionId = guid; 9381 addOnProduct.IsToplevelProduct = false; 9382 } 9383 9384 params.append("addOnProducts", JSON.stringify(addOnProduct)) 9385 } 9386 } 9387 } 9388 9389 9390 }); 9391 </script> 9392 <iframe id="configuratordownload" src="about:blank" width="0" height="0" frameborder="0" scrolling="no"></iframe> 9393 </form> 9394 9395 </div> 9396 <label class="modal__close-btn" for="OverlayDealerModalTrigger"></label> 9397 </div> 9398 </div> 9399 } 9400 9401 if (!isMobileOrTablet) 9402 { 9403 <script> 9404 9405 window.addEventListener("scroll", (event) => { 9406 let headerHeight = document.getElementById('Top').clientHeight; 9407 let heightBox = document.getElementById('ContainerConfigurator').offsetHeight; 9408 let heightSummary = document.getElementById('summaryContainer').offsetHeight; 9409 var y = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; 9410 var bottomElement = document.getElementById('ContainerConfigurator').offsetTop + document.getElementById('ContainerConfigurator').scrollHeight; 9411 if (y >= document.getElementById('ContainerConfigurator').offsetTop) { 9412 document.getElementById('ContainerConfigurator').classList.add('stick'); 9413 document.getElementById('summaryContainer').style.top = headerHeight + 40 + "px"; 9414 if (y > (document.getElementById('ContainerConfigurator').offsetTop + heightBox)) { 9415 document.getElementById('ContainerConfigurator').classList.remove('stick'); 9416 document.getElementById('summaryContainer').style.top = "0px"; 9417 } 9418 } else { 9419 document.getElementById('ContainerConfigurator').classList.remove('stick'); 9420 document.getElementById('summaryContainer').style.top = "0px"; 9421 } 9422 9423 }); 9424 </script> 9425 } 9426 else 9427 { 9428 <script> 9429 document.getElementById('Page').onclick = function (e) { 9430 if (!e.target.classList.contains("img-configurator")) { 9431 if (!e.target.closest(".opened")) { 9432 var cusid_ele = document.getElementsByClassName('opened'); 9433 for (var i = 0; i < cusid_ele.length; ++i) { 9434 var item = cusid_ele[i]; 9435 item.classList.add('close'); 9436 item.classList.remove("opened"); 9437 item.style.display = "none"; 9438 item.style.opacity = "0"; 9439 } 9440 } 9441 } 9442 9443 }; 9444 9445 </script> 9446 } 9447 9448 <script> 9449 // Restricts input for the given textbox to the given inputFilter. 9450 function setInputFilter(textbox, inputFilter) { 9451 ["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout"].forEach(function (event) { 9452 textbox.addEventListener(event, function (e) { 9453 if (inputFilter(this.value)) { 9454 // Accepted value 9455 if (["keydown", "mousedown", "focusout"].indexOf(e.type) >= 0) { 9456 9457 } 9458 this.oldValue = this.value; 9459 this.oldSelectionStart = this.selectionStart; 9460 this.oldSelectionEnd = this.selectionEnd; 9461 } else if (this.hasOwnProperty("oldValue")) { 9462 // Rejected value - restore the previous one 9463 9464 9465 this.reportValidity(); 9466 this.value = this.oldValue; 9467 this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd); 9468 } else { 9469 // Rejected value - nothing to restore 9470 this.value = ""; 9471 } 9472 }); 9473 }); 9474 } 9475 9476 let numbers = document.getElementsByClassName('number-input'); 9477 for (var j = 0; j < numbers.length; ++j) { 9478 var item = numbers[j]; 9479 item.addEventListener("keypress", function (event) { 9480 var element = event.target; 9481 9482 setInputFilter(element, function (value) { 9483 return /^-?\d*[.,]?\d{0,2}$/.test(value) 9484 }); 9485 9486 }); 9487 9488 9489 } 9490 window.addEventListener("load", function () { 9491 let count = 0; 9492 document.getElementById("addProduct")?.addEventListener("click", function () { 9493 // Create a div 9494 var div8 = document.createElement("div"); 9495 div8.setAttribute("class", "grid__col-8 u-no-padding u-padding-right u-padding-bottom js-added"); 9496 9497 var div4 = document.createElement("div"); 9498 div4.setAttribute("class", "grid__col-4 u-no-padding js-added") 9499 9500 // Create a file input 9501 var inputText = document.createElement("input"); 9502 inputText.setAttribute("type", "text"); 9503 inputText.setAttribute("name", "otherproduct"); 9504 inputText.setAttribute("class", "u-full-width dw-mod"); 9505 inputText.setAttribute("placeholder", "@HttpUtility.JavaScriptStringEncode(Translate("AddLines.OtherProduct.Name.Placeholder", "Indsæt navn på produkt"))"); 9506 9507 9508 // Create a text input 9509 var inputNumber = document.createElement("input"); 9510 inputNumber.setAttribute("type", "text"); 9511 inputNumber.setAttribute("name", "amountproduct"); 9512 inputNumber.setAttribute("class", "u-full-width dw-mod number-input js-other-product-input"); 9513 inputNumber.setAttribute("placeholder", "@HttpUtility.JavaScriptStringEncode(Translate("AddLines.OtherProduct.Price.Placeholder", "Pris på produkt"))"); 9514 9515 // add the text and number to the div 9516 div8.appendChild(inputText); 9517 div4.appendChild(inputNumber); 9518 9519 //Append the div to the container div 9520 document.getElementsByClassName("otherproduct-line")[0].appendChild(div8); 9521 document.getElementsByClassName("otherproduct-line")[0].appendChild(div4); 9522 for (var j = 0; j < numbers.length; ++j) { 9523 var item = numbers[j]; 9524 item.addEventListener("keypress", function (event) { 9525 var element = event.target; 9526 9527 setInputFilter(element, function (value) { 9528 return /^-?\d*[.,]?\d{0,2}$/.test(value) 9529 }); 9530 9531 }); 9532 } 9533 eventListenerPriceInput(); 9534 }); 9535 document.getElementById("addDiscount")?.addEventListener("click", function () { 9536 // Create a div 9537 var div8 = document.createElement("div"); 9538 div8.setAttribute("class", "grid__col-8 u-no-padding u-padding-right u-padding-bottom js-added js-discount"); 9539 9540 var div4 = document.createElement("div"); 9541 div4.setAttribute("class", "grid__col-4 u-no-padding js-added js-discount") 9542 9543 // Create a file input 9544 var inputText = document.createElement("input"); 9545 inputText.setAttribute("type", "text"); 9546 inputText.setAttribute("name", "discount"); 9547 inputText.setAttribute("placeholder", "@HttpUtility.JavaScriptStringEncode(Translate("AddLines.Discount.Name.Placeholder", "Indsæt navn på rabat"))"); 9548 inputText.setAttribute("class", "u-full-width dw-mod"); 9549 9550 // Create a text input 9551 var inputNumber = document.createElement("input"); 9552 inputNumber.setAttribute("name", "amountdiscount"); 9553 inputNumber.setAttribute("type", "text"); 9554 inputNumber.setAttribute("placeholder", "@HttpUtility.JavaScriptStringEncode(Translate("AddLines.Discount.Size.Placeholder", "Rabatstørrelse"))"); 9555 inputNumber.setAttribute("class", "u-full-width dw-mod number-input js-discount-input"); 9556 9557 // add the text and number to the div 9558 div8.appendChild(inputText); 9559 div4.appendChild(inputNumber); 9560 9561 //Append the div to the container div 9562 document.getElementsByClassName("discount-line-amount")[0].appendChild(div8); 9563 document.getElementsByClassName("discount-line-amount")[0].appendChild(div4); 9564 for (var j = 0; j < numbers.length; ++j) { 9565 var item = numbers[j]; 9566 item.addEventListener("keypress", function (event) { 9567 var element = event.target; 9568 9569 setInputFilter(element, function (value) { 9570 return /^-?\d*[.,]?\d{0,2}$/.test(value) 9571 }); 9572 9573 }); 9574 9575 9576 } 9577 eventListenerPriceInput() 9578 }); 9579 9580 document.getElementById("OverlayDealerModalTrigger").addEventListener("change", function () { 9581 if (!document.getElementById("OverlayDealerModalTrigger").checked) { 9582 let configurationForm = document.querySelector(".js-save_configuration_form"); 9583 if (configurationForm != null && configurationForm.getAttribute('data-edit-quote') == 'False') { 9584 const createdElement = document.querySelectorAll('.js-added'); 9585 createdElement.forEach(el => { 9586 el.remove(); 9587 }); 9588 } 9589 } 9590 }) 9591 9592 }); 9593 9594 let ele = document.getElementsByClassName('config-close'); 9595 for (var j = 0; j < ele.length; ++j) { 9596 var item = ele[j]; 9597 item.addEventListener("click", function (event) { 9598 var element = event.target; 9599 var parentElement = element.parentNode.parentNode; 9600 9601 parentElement.style.opacity = "0"; 9602 parentElement.classList.add('close'); 9603 parentElement.classList.remove('opened') 9604 parentElement.style.display = "none"; 9605 9606 }); 9607 9608 9609 } 9610 flatpickr('#datepicker', { 9611 minDate: "today", 9612 dateFormat: 'd-m-Y' 9613 9614 }); 9615 9616 function validateEmail(l) { 9617 var emailValue = l.value; 9618 var reg = /^([A-Za-z0-9_\-\.]+)\@('@')([A-Za -z0-9_\-\.]+)\.([A-Za-z]{2,4})$/; 9619 if (emailValue.length > 0) { 9620 9621 //var address = document.getElementById[email].value; 9622 if (reg.test(emailValue) == false) { 9623 document.getElementsByClassName("validation-error")[0].classList.remove("u-hidden"); 9624 document.getElementById("save_configuration_button").classList.add("disabled"); 9625 return (false); 9626 } else { 9627 document.getElementsByClassName("validation-error")[0].classList.add("u-hidden"); 9628 document.getElementById("save_configuration_button").classList.remove("disabled"); 9629 return (true); 9630 } 9631 } else { 9632 document.getElementsByClassName("validation-error")[0].classList.add("u-hidden"); 9633 document.getElementById("save_configuration_button").classList.remove("disabled"); 9634 return (true); 9635 } 9636 9637 } 9638 9639 function selectDiscount() { 9640 let inputs = document.querySelectorAll('.js-discount-line'); 9641 let inputRadio = document.querySelector('.js-discount-radio-percent'); 9642 let addedLine = document.querySelectorAll('.js-added.js-discount'); 9643 let addLinesSection = document.querySelector('.js-add-more-discount-lines'); 9644 let configurationForm = document.querySelector('.js-save_configuration_form'); 9645 let isEditQuote = configurationForm?.getAttribute('data-edit-quote'); 9646 let selectedDiscountType = document.querySelector('input[name="discounttype"]:checked')?.value; 9647 9648 if (isEditQuote.toLowerCase() == 'true') { 9649 addedLine.forEach(el => { 9650 let inputField = el.querySelector('input') 9651 if (inputField != null) { 9652 if (selectedDiscountType === 'percent') { 9653 inputField.disabled = true; 9654 inputField.classList.add('u-hidden'); 9655 } 9656 else { 9657 inputField.disabled = false; 9658 inputField.classList.remove('u-hidden'); 9659 } 9660 } 9661 }); 9662 } 9663 else { 9664 addedLine.forEach(el => { 9665 el.remove(); 9666 }); 9667 } 9668 9669 for (let j = 0; j < inputs.length; ++j) { 9670 let inputitem = inputs[j]; 9671 inputitem.value = ""; 9672 } 9673 9674 if (inputRadio.checked) { 9675 addLinesSection.classList.add('u-hidden'); 9676 } else { 9677 addLinesSection.classList.remove('u-hidden'); 9678 } 9679 9680 renderSalesPrice(); 9681 } 9682 9683 function selectLicenseplate() { 9684 let licenseplateInputWrapper = document.querySelector('.js-licenseplate-line'); 9685 let licenseplateCheckbox = document.querySelector('.js-licenseplate'); 9686 const licenseplateInput = document.querySelector(".js-licenseplate-input"); 9687 9688 if (licenseplateInput && licenseplateInputWrapper && licenseplateCheckbox) { 9689 if (licenseplateCheckbox.checked) { 9690 licenseplateInputWrapper.classList.remove('u-hidden'); 9691 licenseplateInput.value = licenseplateInput.oldValue || 0; 9692 } else { 9693 licenseplateInputWrapper.classList.add('u-hidden'); 9694 licenseplateInput.oldValue = licenseplateInput.value; 9695 licenseplateInput.value = 0.0; 9696 } 9697 renderSalesPrice() 9698 } 9699 } 9700 9701 function hideHover(l) { 9702 9703 var cusid_ele = document.getElementsByClassName('opened'); 9704 for (var i = 0; i < cusid_ele.length; ++i) { 9705 var item = cusid_ele[i]; 9706 item.classList.add('close'); 9707 item.classList.remove("opened"); 9708 item.style.display = "none"; 9709 item.style.opacity = "0"; 9710 } 9711 9712 } 9713 9714 function mousein(e) { 9715 9716 var element = e.currentTarget.parentNode; 9717 9718 var cusid_ele = document.getElementsByClassName('opened'); 9719 for (var i = 0; i < cusid_ele.length; ++i) { 9720 var item = cusid_ele[i]; 9721 item.classList.add('close'); 9722 item.classList.remove("opened"); 9723 item.style.display = "none"; 9724 item.style.opacity = "0"; 9725 } 9726 if (element.children[0].style.opacity === "0") { 9727 element.children[0].classList.remove('close'); 9728 element.children[0].style.display = "block"; 9729 element.children[0].classList.add("opened"); 9730 element.children[0].style.opacity = "1"; 9731 } else { 9732 element.children[0].style.opacity = "0"; 9733 element.children[0].classList.add('close'); 9734 element.children[0].style.display = "none"; 9735 element.children[0].classList.remove("opened"); 9736 } 9737 }; 9738 9739 9740 function hideElement(event, cls) { 9741 var element = nextByClass(event, cls); 9742 if (element.style.display === "none") { 9743 event.classList.remove('category--collapsed'); 9744 9745 event.classList.add("category--expanded"); 9746 element.style.display = "block"; 9747 } else { 9748 element.style.display = "none"; 9749 event.classList.add('category--collapsed'); 9750 event.classList.remove("category--expanded"); 9751 } 9752 }; 9753 </script> 9754 9755 <script id="UnitOption" type="text/x-template"> 9756 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActionsConfigurator', '{{link}}&feed=true&UnitID={{value}}')"> 9757 {{name}} 9758 </div> 9759 </script> 9760 } 9761 9762 @helper RenderOrderDraftScriptsCustom() 9763 { 9764 string productId = GetString("Ecom:Product.ID"); 9765 string variantId = !string.IsNullOrEmpty(GetString("Ecom:Product.VariantID")) ? GetString("Ecom:Product.VariantID") : GetString("Ecom:Product.VariantID.Extented"); 9766 string unitId = GetString("Ecom:Product.DefaultUnitID"); 9767 var cartCmdUrl = "/Default.aspx?ID=" + Pageview.Page.ID; 9768 int orderDraftPageId = GetPageIdByNavigationTag("DraftDetails"); 9769 int orderDraftParagraphId = Dynamicweb.Services.Paragraphs.GetParagraphsByPageId(orderDraftPageId).ToList().First().ID; 9770 int minicartId = GetPageIdByNavigationTag("MiniCartFeed"); 9771 9772 9773 foreach (LoopItem unitOption in GetLoop("Units")) 9774 { 9775 if (unitOption.GetString("Ecom:VariantOption.Selected") == "SELECTED") 9776 { 9777 unitId = unitOption.GetString("Ecom:VariantOption.ID"); 9778 } 9779 } 9780 9781 <script> 9782 9783 function addToSelectedCart() { 9784 document.getElementById('OrderDraftSelectModalTrigger').checked = false; 9785 9786 var overlayElement = document.createElement('div'); 9787 overlayElement.className = "preloader-overlay"; 9788 overlayElement.setAttribute('id', "CartOverlay"); 9789 var overlayElementIcon = document.createElement('div'); 9790 overlayElementIcon.className = "preloader-overlay__icon dw-mod"; 9791 overlayElementIcon.style.top = window.pageYOffset + "px"; 9792 overlayElement.appendChild(overlayElementIcon); 9793 document.getElementById('content').parentNode.insertBefore(overlayElement, document.getElementById('content')); 9794 9795 var data = new FormData(); 9796 var guid = uuidv4(); 9797 var mainProductInfo = document.getElementById('cartQuantity'); 9798 var mainProductQuantity = mainProductInfo.value; 9799 var configuratorDropdowns = document.getElementsByClassName('configuratorSelectorQuantity'); 9800 var hasAnyConfiguratorOptionsBeenSelected = false; 9801 for (var i = 0; i < configuratorDropdowns.length; i++) { 9802 //Check if any configurator options have been selected 9803 if (configuratorDropdowns[i].value != 0) { 9804 hasAnyConfiguratorOptionsBeenSelected = true; 9805 break; 9806 } 9807 } 9808 data.append('ProductLoopCounter1', 1); 9809 data.append('Quantity1', mainProductQuantity); 9810 data.append('ProductID1', mainProductInfo.getAttribute('data-productID')); 9811 data.append('VariantID1', mainProductInfo.getAttribute('data-variantID')); 9812 data.append('UnitID1', mainProductInfo.getAttribute('data-unitID')); 9813 if (hasAnyConfiguratorOptionsBeenSelected === true) { 9814 //It's only a configurator item if there have been chosen 1 or more configurations 9815 data.append('EcomOrderLineFieldInput_IsToplevelProduct1', true); 9816 data.append('EcomOrderLineFieldInput_OrderTransactionID1', guid); 9817 9818 for (i = 2; i < configuratorDropdowns.length + 2; i++) { 9819 var currentConfigurator = configuratorDropdowns[i - 2]; 9820 9821 if (currentConfigurator.value > 0) { 9822 data.append('ProductLoopCounter' + i, i); 9823 data.append('Quantity' + i, nextByClass(currentConfigurator, "configuratorSelectorQuantity").value * mainProductQuantity); 9824 data.append('ProductID' + i, currentConfigurator.getAttribute('data-productID')); 9825 data.append('VariantID' + i, currentConfigurator.getAttribute('data-variantID')); 9826 data.append('UnitID' + i, currentConfigurator.getAttribute('data-unitID')); 9827 if (currentConfigurator.getAttribute('data-isConfigurator') === 'Yes' || 9828 currentConfigurator.getAttribute('data-isConfigurator') === 'Ja') { 9829 data.append('EcomOrderLineFieldInput_OrderTransactionID' + i, guid); 9830 data.append('EcomOrderLineFieldInput_IsToplevelProduct' + i, false); 9831 } 9832 } 9833 } 9834 } 9835 9836 data.append('CartCmd', 'addmulti'); 9837 data.append('CartId', document.getElementById("CartSelector").value) 9838 9839 fetch("@cartCmdUrl" + '&feedType=MiniCart&redirect=false', { 9840 method: 'POST', 9841 body: data 9842 }).then(function () { 9843 var overlayNode = document.getElementById('CartOverlay'); 9844 overlayNode.parentNode.removeChild(overlayNode); 9845 document.getElementById('OrderDraftNotificationModalTrigger').checked = true; 9846 Cart.UpdateMiniCart('miniCartTrigger', 'miniCart', 'cartCounter', '/Default.aspx?ID=@minicartId&feedType=Counter&redirect=false'); 9847 }); 9848 } 9849 9850 function goToSelectedCart() { 9851 window.location = "/Default.aspx?ID=" + "@orderDraftPageId" + "&CartID=" + document.getElementById('CartSelector').value + "&CartCmd=setcart" + "&redirect=false"; 9852 } 9853 9854 </script> 9855 9856 } 9857 9858 <script src="/Files/Templates/Designs/Rapido/js/source/Popover.js"></script> 9859 9860 9861 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 9862 @using Dynamicweb.Core 9863 @using System 9864 @using System.Web 9865 @using System.Collections.Generic 9866 @using Dynamicweb.Rapido.Blocks 9867 @using Dynamicweb.Rapido.Blocks.Components.General 9868 9869 9870 9871 @functions { 9872 BlocksPage mainImagePageCustom = BlocksPage.GetBlockPage("Product"); 9873 bool showThumbsCustom; 9874 bool thumbsOnTheSideCustom; 9875 } 9876 9877 @{ 9878 string blocksPositionCustom = Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition") != null ? Pageview.AreaSettings.GetItem("ProductPage").GetList("ImageSectionPosition").SelectedValue : "thumbs-image-info"; 9879 bool infoOnTheRightCustom = blocksPositionCustom.LastIndexOf("info") == blocksPositionCustom.Length - 4; 9880 showThumbsCustom = blocksPositionCustom.IndexOf("thumbs") != -1; 9881 bool thumbsOnTheLeftCustom = blocksPositionCustom.IndexOf("image") > blocksPositionCustom.IndexOf("thumbs"); 9882 9883 if (showThumbsCustom) 9884 { 9885 mainImagePageCustom.ReplaceBlock(new Block 9886 { 9887 Id = "Image", 9888 SortId = thumbsOnTheLeftCustom ? 20 : 0, 9889 Template = RenderProductImageCustom(), 9890 Design = new Design 9891 { 9892 Size = thumbsOnTheSideCustom ? "auto" : "12", 9893 RenderType = RenderType.Column 9894 } 9895 }); 9896 } 9897 9898 mainImagePageCustom.ReplaceBlock(new Block 9899 { 9900 Id = "Carousel", 9901 SortId = 10, 9902 Template = RenderThumbnailsCustom(), 9903 Design = new Design 9904 { 9905 Size = thumbsOnTheSideCustom ? "2" : "12", 9906 RenderType = RenderType.Column 9907 } 9908 }); 9909 } 9910 9911 @helper RenderThumbnailsCustom() 9912 { 9913 <div class="@(showThumbsCustom ? "product__thumbs" : "") dw-mod"> 9914 @RenderProductImagesCarouselCustom( 9915 "productCarousel", 9916 !showThumbsCustom ? 1 : 7, 9917 thumbsOnTheSideCustom ? "vertical" : "horizontal", 9918 !showThumbsCustom ? 3 : 2 9919 ) 9920 @if (!showThumbsCustom) 9921 { 9922 @RenderProductStickers() 9923 } 9924 </div> 9925 } 9926 9927 @helper RenderProductImagesCarouselCustom(string id, int slidesInView, string direction, int preloaderSize, bool isModal = false) 9928 { 9929 var selectedImageCategories = Pageview.AreaSettings.GetItem("ProductPage").GetList("ProductImagesInTopSection").SelectedValues; 9930 var imagesFromAssets = GetLoop("ImageCategories").Where(x => selectedImageCategories.Contains(x.GetString("Category.Id"))); 9931 9932 HashSet<string> images = new HashSet<string>(); 9933 9934 images.Add(GetProductImage()); 9935 9936 foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 9937 { 9938 string alt_image = alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 9939 9940 if (!string.IsNullOrEmpty(alt_image)) 9941 { 9942 images.Add(alt_image); 9943 } 9944 } 9945 9946 int assetImagesCount = 0; 9947 foreach (LoopItem category in imagesFromAssets) 9948 { 9949 foreach (LoopItem asset in category.GetLoop("Category.Images")) 9950 { 9951 assetImagesCount++; 9952 } 9953 } 9954 9955 if (assetImagesCount > 0) 9956 { 9957 foreach (LoopItem category in imagesFromAssets) 9958 { 9959 foreach (LoopItem asset in category.GetLoop("Category.Images")) 9960 { 9961 images.Add(asset.GetString("Ecom:Product:Detail.Image.Clean")); 9962 } 9963 } 9964 } 9965 else 9966 { 9967 foreach (LoopItem detail in GetLoop("Details")) 9968 { 9969 string detail_image = detail.GetString("Ecom:Product:Detail.Image.Clean"); 9970 9971 if (!string.IsNullOrEmpty(detail_image)) 9972 { 9973 string ext = Path.GetExtension(detail_image).ToLower(); 9974 if (ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".png") 9975 { 9976 images.Add(detail_image); 9977 } 9978 } 9979 } 9980 } 9981 9982 <div class="carousel dw-mod" id="@id"> 9983 <div class="thumb-list carousel__container @(slidesInView != 1 ? "carousel__container--hidden" : "") js-carousel-slides dw-mod"> 9984 @{ var i = 0; } 9985 @foreach (var image in images) 9986 { 9987 @RenderProductImageCustom(image, slidesInView == 1, isModal ? "modal--full__img" : "", i == 0, isModal) 9988 i++; //first is active 9989 } 9990 </div> 9991 9992 <script> 9993 document.addEventListener("DOMContentLoaded", function () { 9994 @id = new CarouselModule('#@id', { 9995 slidesInView: @slidesInView, 9996 direction: "@direction", 9997 preloaderSize: @preloaderSize, 9998 showCounter: @isModal.ToString().ToLower() 9999 }); 10000 }); 10001 </script> 10002 </div> 10003 } 10004 10005 @helper RenderProductImageCustom(string image, bool isBig, string cssClass = "", bool isActive = false, bool isModal = false) 10006 { 10007 string productId = GetString("Ecom:Product.ID"); 10008 string imagePrefix = "/Admin/Public/GetImage.ashx?width=750&height=500&format=webp&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image="; 10009 10010 Image productImage = new Image 10011 { 10012 Path = image, 10013 Title = GetString("Ecom:Product.Name"), 10014 ImageDefault = new ImageSettings 10015 { 10016 Width = 500, 10017 Height = 500, 10018 Crop = 5, 10019 FillCanvas = true 10020 }, 10021 CssClass = "u-middle " + cssClass, 10022 OnClick = "modalCarousel.GoToSlide('modalCarousel', this.closest('.carousel__slide').index());" 10023 }; 10024 productImage.ExtraAttributes.Add("data-image", image); 10025 10026 <div class="carousel__slide dw-mod"> 10027 @if (isModal) 10028 { 10029 @Render(new Image 10030 { 10031 Path = image, 10032 CssClass = cssClass, 10033 Title = GetString("Ecom:Product.Name"), 10034 DisableImageEngine = false, 10035 ImageDefault = new ImageSettings 10036 { 10037 Width = 1920, 10038 Height = 1080, 10039 Crop = 5 10040 } 10041 }); 10042 } 10043 else if (isBig) 10044 { 10045 <label for="GalleryModalTrigger" class="u-middle"> 10046 @Render(productImage) 10047 </label> 10048 } 10049 else 10050 { 10051 Image productThumb = productImage; 10052 productThumb.ImageDefault = new ImageSettings 10053 { 10054 Width = 120, 10055 Height = 120, 10056 Crop = 5, 10057 FillCanvas = true 10058 }; 10059 productImage.CssClass += " thumb-list__image"; 10060 <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)"> 10061 <label for="GalleryModalTrigger" class="thumb-list__image-label"> 10062 @Render(productThumb) 10063 </label> 10064 </div> 10065 } 10066 </div> 10067 } 10068 10069 @helper RenderProductImageCustom() 10070 { 10071 //Add product image to the og meta data 10072 Pageview.Meta.AddTag("og:image", GetProductImage()); 10073 10074 <label for="GalleryModalTrigger" class="product__image-container u-position-relative"> 10075 @{ 10076 Image productImage = new Image 10077 { 10078 Path = GetProductImage(), 10079 Id = "Image_" + GetString("Ecom:Product.ID"), 10080 CssClass = "u-middle product__image-container__image dw-mod", 10081 Title = GetString("Ecom:Product.Name"), 10082 OnClick = "modalCarousel.GoToSlide('modalCarousel', this.getAttribute('data-number'))", 10083 ImageDefault = new ImageSettings 10084 { 10085 Width = 750, 10086 Height = 500, 10087 Crop = 5, 10088 FillCanvas = true 10089 } 10090 }; 10091 productImage.ExtraAttributes.Add("data-number", "0"); 10092 } 10093 @Render(productImage) 10094 @RenderProductStickers() 10095 </label> 10096 } 10097 10098 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 10099 10100 @using Dynamicweb.Extensibility 10101 @using Dynamicweb.Content 10102 @using System 10103 @using System.IO 10104 @using Dynamicweb.Core 10105 @using System.Web 10106 @using System.Globalization 10107 @using System.Web.UI.HtmlControls 10108 @using Dynamicweb.Rapido.Blocks 10109 @using Dynamicweb.Ecommerce 10110 10111 @functions{ 10112 BlocksPage productsPageCustom = BlocksPage.GetBlockPage("Product"); 10113 List<Block> subBlocksCustom; 10114 } 10115 @{ 10116 subBlocksCustom = productsPageCustom.GetBlockListById("Tabs").OrderBy(item => item.SortId).ToList(); 10117 10118 Block productTabsBlockCustom = new Block() 10119 { 10120 Id = "Tabs", 10121 SortId = 28, 10122 Template = RenderProductTabsCustom(), 10123 SkipRenderBlocksList = true 10124 }; 10125 productsPageCustom.ReplaceBlock(productTabsBlockCustom); 10126 10127 } 10128 10129 @helper RenderProductTabsCustom() 10130 { 10131 if (Pageview.Device.ToString() != "Mobile") 10132 { 10133 <div class="grid__col-12 product__info product__info--tabs tabs dw-mod"> 10134 @{ 10135 bool firstTab = true; 10136 foreach (Block item in subBlocksCustom) 10137 { 10138 string isChecked = firstTab ? "checked" : ""; 10139 firstTab = false; 10140 10141 <input type="radio" class="tabs__trigger" name="productTabs" id="@item.Id" onchange="bLazy.revalidate()" @isChecked /> 10142 } 10143 } 10144 10145 <div class="tabs__list dw-mod" id="tabs-list"> 10146 @foreach (Block item in subBlocksCustom) 10147 { 10148 if (item.Design.RenderType != RenderType.Hide) 10149 { 10150 <label for="@item.Id" class="tabs__label dw-mod">@item.Name</label> 10151 } 10152 } 10153 </div> 10154 10155 <div class="tabs__blocks dw-mod"> 10156 @foreach (Block item in subBlocksCustom) 10157 { 10158 if (item.Design.RenderType != RenderType.Hide) 10159 { 10160 <div class="tabs__block dw-mod" id="Block__@item.Id"> 10161 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 10162 <div class="center-container u-padding--lg dw-mod"> 10163 @RenderBlock(item) 10164 </div> 10165 </section> 10166 </div> 10167 } 10168 } 10169 </div> 10170 </div> 10171 } 10172 else 10173 { 10174 <div id="details_blocks__mobile" class="u-margin-left u-padding-right"> 10175 @foreach (Block item in subBlocksCustom) 10176 { 10177 if (item.Design.RenderType != RenderType.Hide) 10178 { 10179 <div class="center-container dw-mod product-tab u-margin-bottom"> 10180 <div class="padding-position-left padding-size-sm product-tab-title u-flex" onclick="ToggleHideShow(this)"> 10181 @Render(new Heading { Title = item.Name, Level = 2 }) 10182 </div> 10183 10184 <div class="tab-collapsed"> 10185 @RenderBlock(item) 10186 </div> 10187 </div> 10188 } 10189 } 10190 </div> 10191 } 10192 10193 <script> 10194 function ToggleHideShow(event) { 10195 if (event) { 10196 var containerToHide = event.nextElementSibling; 10197 if (containerToHide) { 10198 event.classList.toggle("open"); 10199 if (containerToHide.classList.contains("tab-collapsed")) { 10200 containerToHide.classList.remove('tab-collapsed'); 10201 10202 containerToHide.classList.add("tab-expanded"); 10203 } else { 10204 containerToHide.classList.add('tab-collapsed'); 10205 containerToHide.classList.remove("tab-expanded"); 10206 } 10207 } 10208 } 10209 } 10210 </script> 10211 } 10212 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 10213 @using Dynamicweb.Core 10214 @using System 10215 @using System.Web 10216 @using System.Collections.Generic 10217 @using Dynamicweb.Rapido.Blocks.Components.General 10218 @using Dynamicweb.Rapido.Blocks 10219 @using Dynamicweb.Rapido.Services 10220 @using Variant.VariantConfigurator 10221 @using Dynamicweb.Frontend.Devices 10222 10223 10224 @{ 10225 BlocksPage productRelatedPageCustom = BlocksPage.GetBlockPage("Product"); 10226 10227 if (relatedProductsLayout != "hide") 10228 { 10229 var i = 0; 10230 foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups")) 10231 { 10232 string relatedGroupId = ToPascalCase(relatedGroup.GetString("Ecom:Product:RelatedGroup.Name")); 10233 string baseFeedPageUrl = "/Default.aspx?ID=" + GetPageIdByNavigationTag("ProductsPage") + "&PageSize=" + relatedProductsPageSize + "&ProdID=" + GetString("Ecom:Product.ID") + "&feed=true"; 10234 string relatedFeed = baseFeedPageUrl + "&" + relatedGroupId + "=" + GetString("Ecom:Product.ID") + GetString("Ecom:Product.VariantID") + "&GroupName=" + relatedGroupId; 10235 string relatedGroupName = relatedProductsLayout != "maininformation" ? relatedGroup.GetString("Ecom:Product:RelatedGroup.Name") : ""; 10236 10237 i++; 10238 10239 Block detailsRelated = new Block() 10240 { 10241 Name = relatedGroupName, 10242 Id = relatedGroupId, 10243 SortId = 70 + i, 10244 Template = RenderRelatedProductsCustom(relatedGroupName, relatedGroupId, relatedFeed, relatedProductsLayout), 10245 Design = new Design 10246 { 10247 Size = "12", 10248 RenderType = RenderType.Column, 10249 HidePadding = true 10250 } 10251 }; 10252 10253 productRelatedPageCustom.ReplaceBlock(detailsRelated); 10254 } 10255 } 10256 } 10257 10258 @helper RenderRelatedProductsCustom(string name, string groupId, string relatedFeedUrl, string layout) 10259 { 10260 string relatedImageZoomOnHover = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("HoverImageZoom") ? "image-hover--zoom" : ""; 10261 bool relatedShowNumber = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowProductNumber"); 10262 bool showAddToDownloadButton = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowAddToDownloadButton"); 10263 bool relatedShowStock = Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("ShowStockAndShipping"); 10264 bool relatedShowFavoriteButton = !Pageview.AreaSettings.GetItem("ProductList").GetItem("GridView").GetBoolean("HideFavoriteButton") && Pageview.User != null; 10265 bool userLoggedIn = Pageview.User != null; 10266 10267 int relatedProductsPageSize = 4; 10268 10269 if (Pageview.Device.ToString() == "Mobile") 10270 { 10271 relatedProductsPageSize = 1; 10272 } 10273 10274 if (Pageview.Device.ToString() == "Tablet") 10275 { 10276 relatedProductsPageSize = 3; 10277 } 10278 10279 int relatedProductsColumnWidth = 12 / relatedProductsPageSize; 10280 10281 10282 string ribbonClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "product__section--ribbon paragraph-container paragraph-container--full-width" : ""; 10283 ribbonClasses = layout == "Tabs" ? "" : ribbonClasses; 10284 string ribbonSubClasses = Pageview.AreaSettings.GetItem("ProductPage").GetList("RelatedProductsLayout").SelectedValue == "Ribbon" ? "center-container--ribbon" : ""; 10285 10286 <div class="product__section @ribbonClasses dw-mod"> 10287 <div class="center-container @ribbonSubClasses dw-mod"> 10288 @if (layout == "Section") 10289 { 10290 @Render(new Heading { Title = name, Level = 2 }) 10291 } 10292 <div class="js-handlebars-root" id="ProductList_@groupId" data-template="ProductContainerCustom" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedFeedUrl" data-preloader="minimal"></div> 10293 </div> 10294 </div> 10295 10296 <script id="ProductContainerCustom" type="text/x-template"> 10297 {{#.}} 10298 <div class="u-min-h400px u-full-width"> 10299 <div class="grid"> 10300 <div class="grid__col-45px grid__col--bleed-x"> 10301 <div class="grid__cell grid__cell--align-middle-left"> 10302 @{ 10303 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}}')" }; 10304 prevButton.ExtraAttributes.Add("", "{{prevdisabled}}"); 10305 } 10306 @Render(prevButton) 10307 </div> 10308 </div> 10309 <div class="grid__col-auto grid__col--bleed-x"> 10310 <div id="ProductsContainer" data-template="ProductGridItemContainer" class="grid product-list dw-mod" data-save-cookie="true"> 10311 {{#ProductsContainer}} 10312 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__grid-item @relatedImageZoomOnHover dw-mod"> 10313 {{#Product}} 10314 <div class="grid__col--auto product-scroll js-product-scroll-trigger u-no-padding u-full-height" data-params="{{googleImpression}}"> 10315 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}"> 10316 <a href="{{link}}" 10317 onclick="{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" 10318 class="u-block u-position-relative image-hover__wrapper dw-mod"> 10319 @Render(new Image { Path = "{{image}}", ImageDefault = new ImageSettings { Width = 300, Height = 300, Crop = 5, FillCanvas = true, DoNotUpscale = true }, Title = "{{name}}", CssClass = "grid__cell-img grid__cell-img--centered u-min-h180px" }) 10320 {{#StickersContainers}} 10321 {{>StickersContainer}} 10322 {{/StickersContainers}} 10323 </a> 10324 @if (relatedShowFavoriteButton) 10325 { 10326 <div class="favorites favorites--for-grid-view u-pull--right {{hasVariants}} dw-mod" {{hasVariants}}> 10327 {{#Favorite}} 10328 {{>FavoriteTemplate}} 10329 {{/Favorite}} 10330 </div> 10331 } 10332 </div> 10333 10334 <div class="grid__cell product-list__grid-item__price-info dw-mod"> 10335 <a href="{{link}}" onclick="{{#if googleImpression}}googleEnchantImpressionClick({{googleImpression}}, event){{/if}}" title="{{name}}" class="u-color-inherit"> 10336 @Render(new Heading { Title = "{{name}}", Level = 6, CssClass = "u-condensed-text u-bold" }) 10337 </a> 10338 10339 @if (relatedShowNumber) 10340 { 10341 <div class="item-number dw-mod">{{number}}</div> 10342 } 10343 @if (!userLoggedIn) 10344 { 10345 <span> 10346 {{#if retailPriceInclVat}} 10347 <div class="price price--product-list dw-mod">{{retailPriceInclVat}}</div> 10348 {{else}} 10349 @Translate("Vejl. udsalgspris ikke fundet.") 10350 {{/if}} 10351 </span> 10352 } 10353 else 10354 { 10355 @RenderGridViewPriceInfo() 10356 } 10357 </div> 10358 10359 <div class="product-list__grid-item__footer dw-mod"> 10360 @RenderProductGridItemAddToCart() 10361 10362 @if (User.IsStockInfoAllowed() && relatedShowStock) 10363 { 10364 bool hideStockState = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideStockState"); 10365 bool hideDelivery = Pageview.AreaSettings.GetItem("ProductPage").GetBoolean("HideShipping"); 10366 bool isMobileOrTablet = Pageview.Device == DeviceType.Tablet || Pageview.Device == DeviceType.Mobile; 10367 10368 10369 <text>{{#if stockTextCustom}}</text> 10370 <div class="dw-mod @(isMobileOrTablet? "u-no-margin " : "u-margin-top")"> 10371 @if (!hideStockState) 10372 { 10373 <span class="stock-icon stock-{{stockColorCustom}} u-no-margin dw-mod" title="{{stockColorCustom}}"></span> 10374 <span class="u-margin-right--lg"> {{stockTextCustom}}</span> 10375 } 10376 @if (!hideDelivery) 10377 { 10378 <text>{{deliveryText}}</text> 10379 } 10380 </div> 10381 <text>{{/if}}</text> 10382 } 10383 10384 @if (showAddToDownloadButton && Pageview.User != null) 10385 { 10386 Button addButton = new Button { Title = "<span class='js-button-text'>" + Translate("Add") + "</span>", ButtonLayout = ButtonLayout.Primary, CssClass = "u-no-margin u-margin-top btn--condensed dw-mod js-add-to-downloads", Icon = new Icon { Prefix = "fas", Name = "fa-plus", CssClass = "js-button-icon", LabelPosition = IconLabelPosition.After } }; 10387 addButton.ExtraAttributes.Add("data-product-id", "{{productId}}"); //Button addButton = new Button { Title = "<span class='js-button-text'>" + Translate("Add") + "</span>", ButtonLayout = ButtonLayout.Primary, CssClass = "u-no-margin u-margin-top btn--condensed dw-mod js-add-to-downloads", Icon = new Icon { Prefix = "fas", Name = "fa-plus", CssClass = "js-button-icon", LabelPosition = IconLabelPosition.After } }; 10388 addButton.ExtraAttributes.Add("data-product-id", "{{productId}}"); 10389 @Render(addButton) 10390 } 10391 </div> 10392 </div> 10393 {{/Product}} 10394 </div> 10395 {{/ProductsContainer}} 10396 </div> 10397 </div> 10398 <div class="grid__col-45px grid__col--bleed-x"> 10399 <div class="grid__cell grid__cell--align-middle-right"> 10400 @{ 10401 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}}')" }; 10402 nextButton.ExtraAttributes.Add("", "{{nextdisabled}}"); 10403 } 10404 @Render(nextButton) 10405 </div> 10406 </div> 10407 </div> 10408 </div> 10409 {{/.}} 10410 </script> 10411 } 10412 10413 10414 10415 10416 <div class="product__info dw-mod u-margin-bottom--lg js-product"> 10417 <div class="grid grid--align-content-start"> 10418 @* The @RenderBlockList base helper is included in Components/GridBuilder.cshtml *@ 10419 @RenderBlockList(productsPage.BlocksRoot.BlocksList) 10420 </div> 10421 </div> 10422 10423 @helper RenderProductTop() 10424 { 10425 List<Block> subBlocks = productsPage.GetBlockListById("Top").OrderBy(item => item.SortId).ToList(); 10426 10427 <div class="product__top paragraph-container paragraph-container--full-width dw-mod"> 10428 <div class="center-container dw-mod"> 10429 <div class="grid"> 10430 @RenderBlockList(subBlocks) 10431 </div> 10432 </div> 10433 </div> 10434 } 10435 10436 @helper RenderProductMiniTabs() 10437 { 10438 List<Block> subBlocks = productsPage.GetBlockListById("MiniTabs").OrderBy(item => item.SortId).ToList(); 10439 10440 if (subBlocks.Count > 0) 10441 { 10442 <div class="grid__col-12 product__info tabs u-no-padding u-margin-bottom--lg dw-mod"> 10443 @{ 10444 bool firstTab = true; 10445 foreach (Block item in subBlocks) 10446 { 10447 string isChecked = firstTab ? "checked" : ""; 10448 firstTab = false; 10449 10450 <input type="radio" class="tabs__trigger" name="productMiniTabs" id="@item.Id" onchange="bLazy.revalidate()" @isChecked /> 10451 } 10452 } 10453 10454 <div class="tabs__list dw-mod"> 10455 @foreach (Block item in subBlocks) 10456 { 10457 <label for="@item.Id" class="tabs__label dw-mod">@item.Name</label> 10458 } 10459 </div> 10460 10461 <div class="tabs__blocks dw-mod"> 10462 @foreach (Block item in subBlocks) 10463 { 10464 string hidePadding = item.Design.HidePadding ? "u-no-padding" : ""; 10465 10466 if (item.Design.RenderType != RenderType.Hide) 10467 { 10468 <div class="tabs__block u-border dw-mod" id="Block__@item.Id"> 10469 <block class="product__block paragraph-container product__block--bordered dw-mod"> 10470 <div class="center-container dw-mod"> 10471 @RenderBlock(item) 10472 </div> 10473 </block> 10474 </div> 10475 } 10476 } 10477 </div> 10478 </div> 10479 } 10480 } 10481 10482 @helper RenderProductTabs() 10483 { 10484 List<Block> subBlocks = productsPage.GetBlockListById("Tabs").OrderBy(item => item.SortId).ToList(); 10485 10486 if (Pageview.Device.ToString() != "Mobile") { 10487 <div class="grid__col-12 product__info product__info--tabs tabs dw-mod"> 10488 @{ 10489 bool firstTab = true; 10490 foreach (Block item in subBlocks) 10491 { 10492 string isChecked = firstTab ? "checked" : ""; 10493 firstTab = false; 10494 10495 <input type="radio" class="tabs__trigger" name="productTabs" id="@item.Id" onchange="bLazy.revalidate()" @isChecked /> 10496 } 10497 } 10498 10499 <div class="tabs__list dw-mod"> 10500 @foreach (Block item in subBlocks) 10501 { 10502 if (item.Design.RenderType != RenderType.Hide) 10503 { 10504 <label for="@item.Id" class="tabs__label dw-mod">@item.Name</label> 10505 } 10506 } 10507 </div> 10508 10509 <div class="tabs__blocks dw-mod"> 10510 @foreach (Block item in subBlocks) 10511 { 10512 if (item.Design.RenderType != RenderType.Hide) 10513 { 10514 <div class="tabs__block dw-mod" id="Block__@item.Id"> 10515 <section class="product__section paragraph-container paragraph-container--full-width product__section--bordered dw-mod"> 10516 <div class="center-container u-padding--lg dw-mod"> 10517 @RenderBlock(item) 10518 </div> 10519 </section> 10520 </div> 10521 } 10522 } 10523 </div> 10524 </div> 10525 } else { 10526 foreach (Block item in subBlocks) 10527 { 10528 if (item.Design.RenderType != RenderType.Hide) 10529 { 10530 <div class="center-container dw-mod"> 10531 <div class="padding-position-left padding-size-sm"> 10532 @Render(new Heading { Title = item.Name, Level = 2 }) 10533 </div> 10534 10535 @RenderBlock(item) 10536 </div> 10537 } 10538 } 10539 } 10540 }