Error executing template "Designs/SermanTipsmark/_parsed/Basic_Page.parsed.cshtml"
System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Dynamicweb.Ecommerce.Products.GroupRelation.get_GroupRelationsByChildId(String childId)
   at Dynamicweb.Ecommerce.Products.Group.get_IsTopGroup()
   at Dynamicweb.Ecommerce.Shops.Shop.get_TopLevelGroups(String languageId)
   at Dynamicweb.Ecommerce.Frontend.NavigationProviders.GroupNavigationProvider.MakeGroupTree(Page page, NavigationItem parentNode)
   at Dynamicweb.Ecommerce.Frontend.NavigationProviders.GroupNavigationProvider.Process(NavigationItem node)
   at Dynamicweb.Ecommerce.Frontend.NavigationProviders.GroupNavigationProvider.ProcessTree(RootNavigationItem rootNode, NavigationType navigationType)
   at Dynamicweb.Frontend.XmlNavigation.MakeXml(Int32 parentId, Int32 levelStart, Int32 levelStop, Expand expand, Int32 selectedAreaId)
   at Dynamicweb.Frontend.XmlNavigation.GetNavigationHtml(Int32 parentId, Int32 levelStart, Int32 levelStop, Expand expand, String name, String xsltPath, Int32 selectedAreaId, Boolean sitemapMode, NameValueCollection settings, NameValueCollection attributes, IncludeMode mode)
   at Dynamicweb.Frontend.XmlNavigation.GetNavigationHtml(NameValueCollection settings, NameValueCollection attributes)
   at CompiledRazorTemplates.Dynamic.RazorEngine_52e0aa70f9a8452c8de6c9e69d9023b6.Execute() in C:\Solutions\SermanTipsmark\Live\Web\Files\Templates\Designs\SermanTipsmark\_parsed\Basic_Page.parsed.cshtml:line 240
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @using System.Globalization 2 @using Dynamicweb.Content 3 @using Dynamicweb.Content.Items 4 @using Dynamicweb.Frontend; 5 @using Newtonsoft.Json 6 @using Newtonsoft.Json.Serialization 7 @using NLWI.Core.Factory 8 @using SermanTipsmark.Web.CustomCode.Items.Settings 9 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 10 <!DOCTYPE html> 11 <html lang="@Pageview.Area.Culture"> 12 <head> 13 14 <meta charset='utf-8' /> 15 <meta name="description" content="@Model.Description" /> 16 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, user-scalable=yes, shrink-to-fit=no" /> 17 <meta http-equiv="x-ua-compatible" content="ie=edge"> 18 <meta name="theme-color" content="#0067a8" /> 19 @Model.MetaTags 20 @if (Model.Area.Item.GetBoolean("NoIndex")) 21 { 22 <!-- TODO: remove on launch--> 23 <meta name="robots" content="noindex, nofollow" /> 24 } 25 @{ 26 var websiteSettings = Item.GetItemById(Model.Area.ItemType, Model.Area.ItemId).ToCodeFirstItem<Websites>(); 27 28 } 29 <title>@Model.Title</title> 30 <link rel="preload" href="@NORRIQ.Common8.Razor.TimestampSource.GetSourceWithTimestamp("/Files/dist/css/SermanTipsmark-min.css")" as="style" /> 31 <link href="@NORRIQ.Common8.Razor.TimestampSource.GetSourceWithTimestamp("/Files/dist/css/SermanTipsmark-min.css")" rel="stylesheet" /> 32 <style type="text/css"> 33 @@media print { 34 .table .thead-dark th, 35 .border-bottom, 36 .table td, 37 .summary > li { 38 color: black; 39 border-color: gray; 40 } 41 a { 42 color: black; 43 text-decoration: none; 44 } 45 .basic_header, 46 .basic_footer, 47 .checkout .btn, 48 .step-list { 49 display: none; 50 } 51 } 52 </style> 53 <!-- <script id="CookieConsent" src="https://policy.app.cookieinformation.com/uc.js" data-culture="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName.ToUpper()" type="text/javascript"></script> --> 54 55 <script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" data-cbid="6728b80b-1637-43f6-beb9-4dbe9b0f742f" data-blockingmode="auto" type="text/javascript"></script> 56 57 58 59 @if (websiteSettings.TrackGoogleTrackManager) 60 { 61 <!-- Google Tag Manager --> 62 <script> 63 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 64 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 65 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 66 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 67 })(window,document,'script','dataLayer','@websiteSettings.GoogleTrackManager');</script> 68 <!-- End Google Tag Manager --> 69 } 70 @if (websiteSettings.TrackGa) 71 { 72 73 <!-- Google Analytics --> 74 <script async src="https://www.googletagmanager.com/gtag/js?id=@websiteSettings.GoogleGATracking"></script> 75 <script> 76 window.dataLayer = window.dataLayer || []; 77 function gtag(){dataLayer.push(arguments);} 78 gtag('js', new Date()); 79 80 gtag('config', '@websiteSettings.GoogleGATracking'); 81 @if (websiteSettings.TrackAdWords) 82 { 83 <text> 84 gtag('config', '@websiteSettings.GoogleAdWords'); 85 </text> 86 } 87 </script> 88 <!-- End Google Analytics --> 89 90 } 91 <meta name="google-site-verification" content="SaJjE7mf1ymiZ-SUHzOUHxp5EW1q1vNTHFODGrYIwDg" /> 92 93 94 @if (websiteSettings.EnableHeaderScript) 95 { 96 @websiteSettings.HeaderScript 97 } 98 99 <!-- Facebook Pixel Code --> 100 <script> 101 !function(f,b,e,v,n,t,s) 102 {if(f.fbq)return;n=f.fbq=function(){n.callMethod? 103 n.callMethod.apply(n,arguments):n.queue.push(arguments)}; 104 if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; 105 n.queue=[];t=b.createElement(e);t.async=!0; 106 t.src=v;s=b.getElementsByTagName(e)[0]; 107 s.parentNode.insertBefore(t,s)}(window,document,'script', 108 'https://connect.facebook.net/en_US/fbevents.js'); 109 fbq('init', '259009103521898'); 110 fbq('track', 'PageView'); 111 </script> 112 <noscript> 113 <img height="1" width="1" 114 src="https://www.facebook.com/tr?id=259009103521898&ev=PageView 115 &noscript=1"/> 116 </noscript> 117 <!-- End Facebook Pixel Code --> 118 119 </head> 120 <body> 121 <div id="app"> 122 <header class="basic_header bg-primary w-100 position-relative elevation-3"> 123 @{ 124 string basicHeaderPrefix = "Header "; 125 } 126 @if (Pageview.User != null) 127 { 128 <div class="basic_header-top bg-primary text-white py-1"> 129 <div class="container d-flex justify-content-end align-items-center"> 130 <p class="font-size-xs nowrap"> 131 <b-icon-person-fill class="mr-1"></b-icon-person-fill> 132 <span class="mr-1 nowrap ellipsis">@Pageview.User.Name</span> 133 <span class="mr-1">-</span> 134 <a href="/admin/public/extranetlogoff.aspx?ID=@(NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("home"))" class="text-light" v-clear-cache:click.user.cart>@Translate(basicHeaderPrefix + "Sign out", "Sign out")</a> 135 </p> 136 </div> 137 </div> 138 } 139 <div class="basic_header-main position-relative"> 140 <div class="container d-flex justify-content-between align-items-center"> 141 <a href="@Translate(basicHeaderPrefix + "logo url", "/")" class="basic_header-logo d-flex align-items-center py-3" title="@Translate(basicHeaderPrefix + "Go to frontpage", "Go to frontpage")"> 142 @if (Model.Area.Item.GetFile("Logo") != null) 143 { 144 <img class="img-fluid" src="@Model.Area.Item.GetFile("Logo")" alt="@Translate(basicHeaderPrefix + "Website Logo Alttext", "Website Logo Alttext")" /> 145 } 146 else 147 { 148 <i>@Translate(basicHeaderPrefix + "No logo found", "No logo found, please configure it in the Dynamicweb Administration")</i> 149 } 150 </a> 151 <form class="basic_header-search position-relative d-flex justify-content-end flex-grow-1" action="/Default.aspx"> 152 <input name="Id" type="hidden" value="@NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("searchresult")"> 153 <label for="productsearch" class="sr-only">@Translate(basicHeaderPrefix + "Search", "Search")</label> 154 <input type="search" class="form-control position-relative border-0" placeholder="@Translate(basicHeaderPrefix + "Search", "Search")" id="productsearch" name="productsearch"> 155 <button type="submit" class="btn btn-square position-absolute position-top-right" aria-label="@Translate(basicHeaderPrefix + "Search", "Search")"> 156 <b-icon-search font-scale="1.25"></b-icon-search> 157 </button> 158 </form> 159 <div class="basic_header-functions d-flex align-items-center"> 160 <button type="button" 161 class="btn btn-square btn-burger" 162 aria-label="@Translate(basicHeaderPrefix + "Open main navigation", "Open main navigation")" 163 v-b-toggle.basic_navigation> 164 <b-icon-list font-scale="2" style="margin-top:4px;"></b-icon-list> 165 </button> 166 <b-dropdown variant="square" right no-caret id="langSelector"> 167 <template v-slot:button-content> 168 <img src="@Pageview.Area.Flag32X32" alt="@Pageview.Area.CultureInfo.EnglishName" /> 169 <span class="sr-only">@Pageview.Area.CultureInfo.EnglishName</span> 170 </template> 171 <template> 172 @{ 173 var groupId = System.Web.HttpContext.Current.Request["GroupId"]; 174 var productId = System.Web.HttpContext.Current.Request["ProductId"]; 175 var variantId = System.Web.HttpContext.Current.Request["VariantId"]; 176 } 177 @foreach (var lang in Model.Languages) 178 { 179 var langCode = lang.Culture.Split('-').Last(); 180 var cultureInfo = CultureInfo.GetCultureInfo(lang.Culture); 181 var language = cultureInfo.NativeName.Split('(')[0]; 182 language = cultureInfo.TextInfo.ToTitleCase(language); 183 var url = $"/Default.aspx?Id={lang.Page.ID}"; 184 var query = System.Web.HttpUtility.ParseQueryString(System.Web.HttpContext.Current.Request.QueryString.ToString()); 185 query.Remove("Id"); 186 query.Remove("GroupId"); 187 query.Remove("ProductId"); 188 query.Remove("VariantId"); 189 if (!string.IsNullOrWhiteSpace(groupId)) 190 { 191 url += $"&GroupId={groupId}"; 192 } 193 if (!string.IsNullOrWhiteSpace(productId)) 194 { 195 url += $"&ProductId={productId}"; 196 } 197 if (!string.IsNullOrWhiteSpace(variantId)) 198 { 199 url += $"&VariantId={variantId}"; 200 } 201 var urlencodedQuery = url; 202 if (query.HasKeys()) 203 { 204 urlencodedQuery += "&" + query.ToString(); 205 206 } 207 <b-dropdown-item href="@urlencodedQuery" link-class="d-flex align-items-center"><img src="@($"/Admin/Images/Flags/flag_{langCode}.png")" alt="@Translate(basicHeaderPrefix + language, language)" /><span class="font-size-sm ml-2">@Translate(basicHeaderPrefix + language, language)</span></b-dropdown-item> 208 } 209 @*<b-dropdown-item href="/admin/public/extranetlogoff.aspx?ID=@(NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("home"))" v-clear-cache:click.user.cart class="border-top bg-light">@Translate(basicHeaderPrefix + "Sign out", "Sign out")</b-dropdown-item>*@ 210 </template> 211 </b-dropdown> 212 @if (Pageview.User == null) 213 { 214 <a href="@NORRIQ.Common8.Razor.Navigation.GetUrlByNavigationTag("selfservice")" class="btn btn-square" aria-label="@Translate(basicHeaderPrefix + "Login", "Login")"> 215 <b-icon-person font-scale="2"></b-icon-person> 216 </a> 217 } 218 else 219 { 220 <b-dropdown variant="square" right no-caret> 221 <template v-slot:button-content> 222 <b-icon-person font-scale="2"></b-icon-person> 223 <span class="sr-only">User</span> 224 </template> 225 <template> 226 @RenderNavigation(new { Template = "dropdown.xslt", Expandmode = "all", StartLevel = 1, EndLevel = 4, NavigationTag = "selfservice" }) 227 @*<b-dropdown-item href="/admin/public/extranetlogoff.aspx?ID=@(NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("home"))" v-clear-cache:click.user.cart class="border-top bg-light">@Translate(basicHeaderPrefix + "Sign out", "Sign out")</b-dropdown-item>*@ 228 </template> 229 </b-dropdown> 230 } 231 @if (Pageview.User != null) 232 { 233 <cart-icon cartlink="@NORRIQ.Common8.Razor.Navigation.GetUrlByNavigationTag("checkout")"></cart-icon> 234 } 235 </div> 236 </div> 237 </div> 238 <template> 239 <b-sidebar id="basic_navigation" tag="nav" bg-variant="nav" text-variant="nav" backdrop body-class="container"> 240 @RenderNavigation(new { Template = "basic_Header.xslt", Expandmode = "all", StartLevel = 1, EndLevel = 4 }) 241 </b-sidebar> 242 </template> 243 </header> 244 @using Dynamicweb.Content.Items 245 @using Dynamicweb.Frontend; 246 @using SermanTipsmark.Web.CustomCode.Items.Pages 247 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 248 249 @Title("Page") 250 @Description("Default page template") 251 @if (Pageview.IsCurrentUserAllowed) 252 { 253 string pageLayout = !string.IsNullOrEmpty(Model.Item.GetValue<ListViewModel>("Layout").SelectedValue) ? Model.Item.GetValue<ListViewModel>("Layout").SelectedValue : "page-menu"; 254 string cssClass = !string.IsNullOrEmpty(Model.Item.GetString("CssClass")) ? " " + Model.Item.GetString("CssClass") : ""; 255 string columns = !string.IsNullOrEmpty(Model.Item.GetValue<ListViewModel>("Columns").SelectedValue) ? Model.Item.GetValue<ListViewModel>("Columns").SelectedValue : "d-grid-12"; 256 string width = Model.Item.GetBoolean("FullWidth") ? "container-0" : "container"; 257 string background = !string.IsNullOrEmpty(Model.Item.GetValue<ListViewModel>("BgColor").SelectedValue) ? " " + Model.Item.GetValue<ListViewModel>("BgColor").SelectedValue : ""; 258 string color = !string.IsNullOrEmpty(Model.Item.GetValue<ListViewModel>("TextColor").SelectedValue) ? " " + Model.Item.GetValue<ListViewModel>("TextColor").SelectedValue : ""; 259 string padding = !string.IsNullOrEmpty(Model.Item.GetValue<ListViewModel>("Padding").SelectedValue) ? " " + Model.Item.GetValue<ListViewModel>("Padding").SelectedValue : " py-4"; 260 string gap = Model.Item.GetBoolean("NoGaps") ? "gap-0" : ""; 261 <main class="d-block"> 262 @if (!Model.Item.GetBoolean("HideBreadcrumb") || pageLayout == "page-menu") 263 { 264 <nav class="page-nav"> 265 <div class="container d-flex justify-content-start align-items-center"> 266 @if (pageLayout == "page-menu") 267 { 268 <button type="button" 269 class="btn btn-sidebar btn-square border p-0 btn-sm mr-3" 270 v-b-toggle.sidebar 271 aria-label="@Translate("Toggle sidebar", "Toogle Sidebar")"> 272 <span class="arrow-left"></span> 273 </button> 274 } 275 @if (!Model.Item.GetBoolean("HideBreadcrumb")) 276 { 277 @RenderNavigation(new { Template = "basic_Breadcrumb.xslt", Expandmode = "all", StartLevel = 1, EndLevel = 5 }) 278 } 279 </div> 280 </nav> 281 } 282 283 @if (pageLayout == "page-menu") 284 { 285 @*<main class="d-block">*@ 286 <div class="@pageLayout @width @padding"> 287 <aside class="sidebar"> 288 <b-sidebar id="sidebar" backdrop shadow bg-variant="white" text-variant="dark" tag="nav"> 289 @RenderNavigation(new { Template = "basic_ListView.xslt", Expandmode = "all", StartLevel = 1, EndLevel = 3 }) 290 </b-sidebar> 291 </aside> 292 <div class="content"> 293 @RenderBanner() 294 <section class="layout@(cssClass)@(background)@(color)"> 295 @RenderHeader() 296 <div class="@columns @width @gap"> 297 @RenderPlaceholder() 298 </div> 299 </section> 300 </div> 301 </div> 302 @*</main>*@ 303 } 304 else if (pageLayout == "page-content") 305 { 306 <div class="@pageLayout @width @padding"> 307 @RenderBanner() 308 <section class="layout@(cssClass)@(background)@(color)"> 309 @RenderHeader() 310 <div class="@columns @width @gap"> 311 @RenderPlaceholder() 312 </div> 313 </section> 314 </div> 315 } 316 else 317 { 318 319 @RenderPlaceholder() 320 321 } 322 </main> 323 } 324 else 325 { 326 <main class="d-flex justify-content-center align-items-center w-100 h-100"> 327 @RenderPlaceholder() 328 </main> 329 } 330 @helper RenderPlaceholder() 331 { 332 @Model.Placeholder("Content", "Content", "unwrap:true;default:true") 333 } 334 335 @helper RenderHeader() 336 { 337 if (!string.IsNullOrEmpty(Model.Item.GetString("Title"))) 338 { 339 string display = Model.Item.GetBoolean("Display") ? "display " : ""; 340 string align = !string.IsNullOrEmpty(Model.Item.GetValue<ListViewModel>("Align").SelectedValue) ? Model.Item.GetValue<ListViewModel>("Align").SelectedValue + " " : ""; 341 string headingClass = align + display; 342 <header class="pb-4"> 343 <h1 class="@headingClass">@Model.Item.GetString("Title")</h1> 344 </header> 345 } 346 } 347 348 @helper RenderBanner() 349 { 350 var item = Item.GetItemById(Model.ItemType, Model.ItemId).ToCodeFirstItem<Basic_Page>(); 351 if (Model.Item.GetFile("TopImage") != null) 352 { 353 <figure class="page-banner layout"> 354 <img src="@Model.Item.GetFile("TopImage").Path" 355 alt="@Model.Item.GetString("Title")" 356 class="img-fluid @(item.ImageFullWith ? "full-with": "")" 357 loading="lazy" /> 358 </figure> 359 } 360 } 361 362 <footer class="basic_footer py-4"> 363 @{ 364 var imageLinks = Model.Area.Item.GetItems("ImageLinks").Where(s => s.GetFile("Image") != null); 365 } 366 <div class="container d-grid-3-3-3-3"> 367 @if (!string.IsNullOrEmpty(Model.Area.Item.GetString("FooterOneTitle")) && !string.IsNullOrEmpty(Model.Area.Item.GetString("FooterOneText"))) 368 { 369 <div class="basic_footer-box mt-0"> 370 <b-button variant="footer" v-b-toggle.footer-one> 371 @Model.Area.Item.GetString("FooterOneTitle") 372 <span class="plus-minus"></span> 373 </b-button> 374 <b-collapse id="footer-one"> 375 <div class="flow-2 font-size-sm"> 376 @Model.Area.Item.GetString("FooterOneText") 377 </div> 378 </b-collapse> 379 </div> 380 } 381 @if (!string.IsNullOrEmpty(Model.Area.Item.GetString("FooterTwoTitle")) && !string.IsNullOrEmpty(Model.Area.Item.GetString("FooterTwoText"))) 382 { 383 <div class="basic_footer-box mt-0"> 384 <b-button variant="footer" v-b-toggle.footer-two> 385 @Model.Area.Item.GetString("FooterTwoTitle") 386 <span class="plus-minus"></span> 387 </b-button> 388 <b-collapse id="footer-two"> 389 <div class="flow-2 font-size-sm"> 390 @Model.Area.Item.GetString("FooterTwoText") 391 </div> 392 </b-collapse> 393 </div> 394 } 395 @if (!string.IsNullOrEmpty(Model.Area.Item.GetString("FooterThreeTitle")) && !string.IsNullOrEmpty(Model.Area.Item.GetString("FooterThreeText"))) 396 { 397 <div class="basic_footer-box mt-0"> 398 <b-button variant="footer" v-b-toggle.footer-three> 399 @Model.Area.Item.GetString("FooterThreeTitle") 400 <span class="plus-minus"></span> 401 </b-button> 402 <b-collapse id="footer-three"> 403 <div class="flow-2 font-size-sm"> 404 @Model.Area.Item.GetString("FooterThreeText") 405 </div> 406 </b-collapse> 407 </div> 408 } 409 @if (!string.IsNullOrEmpty(Model.Area.Item.GetString("FooterFourTitle")) && !string.IsNullOrEmpty(Model.Area.Item.GetString("FooterFourText"))) 410 { 411 <div class="basic_footer-box mt-0"> 412 <b-button variant="footer" v-b-toggle.footer-four> 413 @Model.Area.Item.GetString("FooterFourTitle") 414 <span class="plus-minus"></span> 415 </b-button> 416 <b-collapse id="footer-four"> 417 <div class="flow-2 font-size-sm"> 418 @Model.Area.Item.GetString("FooterFourText") 419 </div> 420 </b-collapse> 421 </div> 422 } 423 </div> 424 425 @if (!string.IsNullOrEmpty(Model.Area.Item.GetString("FooterCopyright")) || imageLinks != null && imageLinks.Any()) 426 { 427 428 <div class="basic_footer-sub container pt-4 d-flex align-items-center"> 429 @if (!string.IsNullOrEmpty(Model.Area.Item.GetString("FooterCopyright"))) 430 { 431 <p class="font-size-xs"> 432 &copy; @DateTime.Now.Year @Model.Area.Item.GetString("FooterCopyright") 433 </p> 434 } 435 @if (imageLinks != null && imageLinks.Any()) 436 { 437 <div class="basic_footer-imagelinks d-flex align-items-center"> 438 @foreach (var item in imageLinks) 439 { 440 string target = item.GetString("Url").Contains("http") ? "_blank" : "_self"; 441 string rel = item.GetString("Url").Contains("http") ? "noreferrer noopener" : ""; 442 <a href="@item.GetString("Url")" class="d-inline-flex align-items-center p-1" rel="@rel" target="@target" title="@item.GetString("Title")"> 443 <img src="@item.GetFile("Image").Path" class="img-fluid" width="32" alt="@item.GetString("Title")" /> 444 </a> 445 } 446 </div> 447 } 448 </div> 449 } 450 </footer> 451 </div> 452 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 453 454 <script type="text/x-template" id="cart-icon-template"> 455 @{ 456 string cartIconPrefix = "Minicart "; 457 } 458 <a :href="cartlink" class="btn btn-square"> 459 <b-icon-cart3 font-scale="1.65"></b-icon-cart3> 460 <span class="sr-only">@Translate(cartIconPrefix + "Checkout", "Checkout")</span> 461 <span v-if="!cartEmpty" class="cart-quantity d-flex align-items-center justify-content-center">{{quantity}}</span> 462 </a> 463 </script> 464 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 465 466 <script type="text/x-template" id="basic-facet-filter-template"> 467 @{ 468 string basicFacetPrefix = "Filter "; 469 } 470 <div v-if="!queryLoading && !error && facetFilters" class="facets" id="sidebar-filter"> 471 472 473 474 <div class="facet-collapse" v-if="HasActiveFilter()"> 475 <p id="selected-filter-label" class="btn btn-collapse"> 476 @Translate(basicFacetPrefix + "Active", "Active") 477 </p> 478 <div class="pb-3 flow-2" aria-labelledby="selected-filter-label"> 479 <template v-for="facetFilter in facetFilters"> 480 <div v-for="option in SelectedOptions(facetFilter)" class="custom-control"> 481 <input type="checkbox" 482 :id="'Selected-' + facetFilter.name + '-' + option.name" 483 :name="facetFilter.name" 484 :value="option.value" 485 :v-model="option.selected" 486 :checked="option.selected" 487 v-on:click="ToggleFilter(facetFilter.queryParameter,option)" 488 class="custom-control-input" /> 489 <label :for="'Selected-' + facetFilter.name + '-' + option.name" class="custom-facet-label"> 490 <b-icon-x-circle-fill></b-icon-x-circle-fill> 491 <span> 492 {{facetFilter.name}}: {{option.label}} 493 </span> 494 </label> 495 </div> 496 </template> 497 </div> 498 </div> 499 <div class="facet-collapse" v-for="(facetFilter, index) in facetFilters"> 500 <b-button variant="collapse" v-b-toggle="'filter-group-' + facetFilter.name.replace(/\s/g, '').toLowerCase()"> 501 <span>{{facetFilter.name}}</span> 502 <span class="arrow-down"></span> 503 </b-button> 504 <b-collapse :id="'filter-group-' + facetFilter.name.replace(/\s/g, '').toLowerCase()" :visible="ShowGroupIfSelected(facetFilter.options, index)"> 505 <div class="py-3 flow-2"> 506 <template v-if="facetFilter.options.length > 5"> 507 <div v-for="option in facetFilter.options.slice(0, 5)" class="custom-control custom-checkbox"> 508 <input type="checkbox" class="custom-control-input" 509 :id="'UnSelected-' + facetFilter.name + '-' + option.name" 510 :name="facetFilter.name" 511 :value="option.value" 512 :v-model="option.selected" 513 :checked="option.selected" 514 v-on:click="ToggleFilter(facetFilter.queryParameter,option)" /> 515 <label :for="'UnSelected-' + facetFilter.name + '-' + option.name" class="custom-control-label"> 516 {{option.label}}<span class="count">({{option.count}})</span> 517 </label> 518 </div> 519 <b-collapse class="basic_filter-expand flow-2" :id="'filter-expand-' + facetFilter.name.replace(/\s/g, '').toLowerCase()" :visible="ShowMoreIfSelected(facetFilter.options, index)"> 520 <div v-for="option in facetFilter.options.slice(5)" class="custom-control custom-checkbox facet-option"> 521 <input type="checkbox" class="custom-control-input" 522 :id="'UnSelected-' + facetFilter.name + '-' + option.name" 523 :name="facetFilter.name" 524 :value="option.value" 525 :v-model="option.selected" 526 :checked="option.selected" 527 v-on:click="ToggleFilter(facetFilter.queryParameter,option)" /> 528 <label :for="'UnSelected-' + facetFilter.name + '-' + option.name" class="custom-control-label"> 529 {{option.label}} <span class="count">({{option.count}})</span> 530 </label> 531 </div> 532 </b-collapse> 533 <a v-b-toggle="'filter-expand-' + facetFilter.name.replace(/\s/g, '').toLowerCase()" class="btn btn-inline" v-if="facetFilter.options.length > 5"> 534 <span class="plus-minus"></span> 535 <span class="show-more">@Translate(basicFacetPrefix + "show more", "show more")</span> 536 <span class="show-less">@Translate(basicFacetPrefix + "show less", "show less")</span> 537 </a> 538 </template> 539 <template v-else> 540 <div v-for="option in facetFilter.options" class="custom-control custom-checkbox"> 541 <input type="checkbox" class="custom-control-input" 542 :id="'UnSelected-' + facetFilter.name + '-' + option.name" 543 :name="facetFilter.name" 544 :value="option.value" 545 :v-model="option.selected" 546 :checked="option.selected" 547 v-on:click="ToggleFilter(facetFilter.queryParameter,option)" /> 548 <label :for="'UnSelected-' + facetFilter.name + '-' + option.name" class="custom-control-label"> 549 {{option.label}} 550 </label> 551 </div> 552 </template> 553 </div> 554 </b-collapse> 555 </div> 556 557 </div> 558 </script> 559 560 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 561 <script type="text/x-template" id="add-to-basket-simple-template"> 562 @{ 563 string addToBasketSimplePrifix = "BuyButton "; 564 } 565 <div v-if="!isB2C"> 566 <label :for="'quantity-' + productId" class="sr-only">@Translate(addToBasketSimplePrifix + "Quantity", "Quantity")</label> 567 <input @@focus="$event.target.select()" :class="['form-control form-quantity', inputClass]" type="tel" name="quantity" :id="'quantity-' + productId" v-model="quantity" autocomplete="off" onclick="this.setSelectionRange(0, this.value.length)"> 568 <button :disabled="quantity < 1" :class="['btn', buttonClass, {added: IsAdded}, {adding: IsAdding}]" v-on:click="addToBasketAndResetQuantity()" aria-label="@Translate(addToBasketSimplePrifix + "Add to Basket", "Add to Basket")"> 569 <slot> 570 <b-icon-cart3></b-icon-cart3> 571 <span v-if="buttonLabel">{{buttonLabel}}</span> 572 </slot> 573 </button> 574 </div> 575 </script> 576 577 <script type="text/x-template" id="quick-add-template"> 578 @{ 579 string quickAddPrifix = "BuyButton "; 580 } 581 <div v-if="!isB2C" v-bind:class="[{added: IsAdded}, {adding: IsAdding}]"> 582 <label for="quantity">@Translate(quickAddPrifix + "Quantity", "Quantity")</label> 583 <input class="form-control" type="number" id="quantity" name="quantity" v-model="quantity" autocomplete="off"> 584 </div> 585 </script> 586 587 <script type="text/x-template" id="add-to-basket-button-only-template"> 588 @{ 589 string addToBasketPrefix = "BuyButton "; 590 } 591 <div v-if="!isB2C"> 592 <button :class="['btn', buttonClass, {added: IsAdded}, {adding: IsAdding}]" v-on:click="addToBasket()"> 593 <slot> 594 <b-icon-cart3></b-icon-cart3> 595 <span>@Translate(addToBasketPrefix + "Add to basket", "Add to basket")</span> 596 </slot> 597 </button> 598 </div> 599 </script> 600 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 601 <script type="text/x-template" id="async-price-template"> 602 @{ 603 string asyncPrefix = "Async "; 604 } 605 <div :class="'async' + (loading && !onlyStock ? ' loading text-center' : '')"> 606 <template v-if="error"> 607 <p class="text-danger font-weight-bold">{{error}}</p> 608 </template> 609 <template v-if="!onlyPrice && !error"> 610 @*<div class="d-flex align-items-center flex-wrap font-size-xs" >*@ 611 <template v-if="!loading && price && !hasStock"> 612 <p class="stock out-of-stock"> 613 <link itemprop="availability" href="http://schema.org/SoldOut" /> 614 @Translate(asyncPrefix + "Out Of Stock", "Out Of Stock") 615 </p> 616 <p class="text-muted font-size-xs"> 617 <template v-if="outOfStockText && outOfStockText !=''"> 618 {{outOfStockText}} 619 </template> 620 <template v-else> 621 <a href="@NORRIQ.Common8.Razor.Navigation.GetUrlByNavigationTag("service-contact")" style="z-index:10;">@Translate(asyncPrefix + "Contact Service", "Contact Service")</a> 622 </template> 623 </p> 624 </template> 625 @*</div>*@ 626 <p class="stock in-stock" v-if="!loading && price && hasStock && !isB2C"> 627 <link itemprop="availability" href="http://schema.org/InStock" /> 628 @Translate(asyncPrefix + "In Stock", "In Stock") ({{ productStockAmount }}) 629 </p> 630 <p class="stock in-stock" v-if="!loading && price && hasStock && isB2C"> 631 <link itemprop="availability" href="http://schema.org/InStock" /> 632 @Translate(asyncPrefix + "In Stock", "In Stock") 633 </p> 634 </template> 635 <template v-if="!onlyStock && !isB2C"> 636 <div v-if="!loading && price" class="price-settings"> 637 <div class="price"> 638 <p :class="'unit-price ' + classType" itemprop="priceCurrency" :content="price.unitPrice?.currencyKey"> 639 <span itemprop="price" :content="unitPrice">{{ netUnitPriceString | currency }}</span> 640 </p> 641 @if (Pageview.User != null) 642 { 643 <template v-if="savingsPercentage != 0"> 644 <p class="list-price">{{ defaultUnitPriceString | currency }}</p> 645 </template> 646 647 } 648 </div> 649 @if (Pageview.User != null) 650 { 651 <template v-if="savingsPercentage != 0"> 652 <div class="ml-4"> 653 <span class="badge size-2 bg-success text-white">{{savingsPercentage}}%</span> 654 </div> 655 </template> 656 } 657 </div> 658 </template> 659 </div> 660 </script> 661 662 663 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 664 665 @{ 666 string relatedProductsPrefix = "Related Products "; 667 } 668 669 670 <script type="text/x-template" id="related-products-template"> 671 672 <section class="related plp grid-view"> 673 <header> 674 <h2 class="text-center"> 675 {{header}} 676 </h2> 677 </header> 678 <div class="related-products products"> 679 <article v-for="product in relatedProducts"> 680 <a :href="product.url" class="position-relative"> 681 <figure class="d-flex justify-content-center align-items-center border p-2" style="min-height:1px;"> 682 <img :src="imageUrl(product)" 683 :alt="product.name" 684 itemprop="image" 685 class="img-fluid" /> 686 </figure> 687 <header class="flow-1"> 688 <h1 class="font-size-lg text-dark">{{product.name}}</h1> 689 <p class="font-size-xs text-800">@Translate(relatedProductsPrefix + "Product Number", "Product Number") {{product.number}}</p> 690 <async-price class-type="asyncprice-plp" 691 :default-price-without-vat="product.price?.priceWithoutVat" 692 :default-price-with-vat="product.price?.priceWithVat" 693 :product-id="product.number" 694 :variant-id="product.variantId" 695 unit-of-measure="" 696 only-stock="true" 697 :dw-stock-amount="product.stockAmount" 698 :out-of-stock-text="product.outOfStockText"> 699 </async-price> 700 </header> 701 </a> 702 <footer class="flow-3"> 703 <async-price class-type="asyncprice-plp" 704 :default-price-without-vat="product.price?.priceWithoutVat" 705 :default-price-with-vat="product.price?.priceWithVat" 706 :product-id="product.number" 707 :variant-id="product.variantId" 708 unit-of-measure="" 709 only-price="true" 710 :dw-stock-amount="product.stockAmount" 711 :out-of-stock-text="product.outOfStockText"> 712 </async-price> 713 <div class="buy-settings position-relative"> 714 @if (Pageview.User != null) 715 { 716 <favorite-lists :is-favorite-mode="@NORRIQ.Common8.Razor.Navigation.GetPageIdByNavigationTag("favorites") == @Pageview.ID" 717 :product="product" 718 button-class="border btn-square mr-2"></favorite-lists> 719 } 720 <add-to-basket-simple class="d-flex align-items-center" 721 :product-id="product.id" 722 :variant-id="product.variantId" 723 :unit-of-measure="product.defaultUnitId" 724 :language-id="product.languageId" 725 button-class="btn-primary px-3 ml-2" 726 input-class="text-center" 727 :product-name="product.name" 728 :product-number="product.number" 729 :price="product.price" 730 button-label=""> 731 </add-to-basket-simple> 732 </div> 733 @*<add-to-basket-button-only product-id="product.id" 734 variant-id="product.variantId" 735 unit-of-measure="STK" 736 button-class="btn-primary" 737 input-class="form-control-lg text-center px-1" 738 button-label="@Translate(relatedProductsPrefix + "Add to basket", "Add to basket")"> 739 </add-to-basket-button-only>*@ 740 </footer> 741 </article> 742 </div> 743 </section> 744 </script> 745 746 747 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 748 749 <script type="text/x-template" id="pagination-template"> 750 @{ 751 string paginationPrefix = "Pagination "; 752 } 753 <footer class="d-flex justify-content-center align-items-center pt-4"> 754 <nav aria-label="@Translate(paginationPrefix + "Produktliste pagination", "Produktliste pagination")"> 755 <ul class="pagination"> 756 <li :class="['page-item', currentPage == 1 ? 'disabled' : '' ]"> 757 <a class="btn btn-square btn-sm" v-on:click="togglePrevPage()" aria-label="@Translate(paginationPrefix + "Previous Page", "Previous Page")" v-bind:aria-disabled="currentPage > 1 ? 'true' : null"> 758 <b-icon-chevron-left></b-icon-chevron-left> 759 </a> 760 </li> 761 <template v-if="hasGroupId"> 762 <li class="btn btn-sm " v-for="n in totalPages" :key="n" :class="(n == currentPage ? ' is-active' : '')"> 763 <a v-on:click="togglePage(n)" v-bind:aria-current="(n == currentPage ? 'aria-page' : '')" class="page-link"> 764 {{n}} 765 </a> 766 </li> 767 </template> 768 <template v-else> 769 <li class="btn btn-square btn-sm "> 770 <span class="page-label"> 771 {{currentPage}} 772 </span> 773 </li> 774 <li class="btn btn-sm btn-square"> 775 <span class="page-label"> 776 @Translate("of") 777 </span> 778 </li> 779 <li class="btn btn-square btn-sm "> 780 <span class="page-label"> 781 {{totalPages}} 782 </span> 783 </li> 784 </template> 785 <li :class="'page-item' + (currentPage >= totalPages ? ' disabled' : '')"> 786 <a v-on:click="toggleNextPage()" aria-label="@Translate(paginationPrefix + "Next Page", "Next Page")" class="btn btn-square btn-sm" v-bind:aria-disabled="totalPages > currentPage ? 'true' : null"> 787 <b-icon-chevron-right></b-icon-chevron-right> 788 </a> 789 </li> 790 </ul> 791 </nav> 792 </footer> 793 </script> 794 795 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 796 @{ 797 //This template contains everything for the favoritelist items. 798 string favoriteListPrefix = "FavoriteList "; 799 } 800 <span id="favoritelistitem_confirm_delete_on_all" style="display: none; visibility: hidden">@Translate(favoriteListPrefix + "_confirm_delete_all", "Er du sikker på at du vil fjerne produktet {0} fra alle lister ?")</span> 801 802 <script type="text/x-template" id="favorite-item-template"> 803 @*<div class="basic_favoriteitem">*@ 804 <div class="custom-control custom-checkbox"> 805 <input type="checkbox" :checked="isActive" v-on:change="toggleItem()" :id="'fav-' +favoriteList.id" class="custom-control-input"/> 806 <label :for="'fav-' + favoriteList.id" class="custom-control-label"> 807 {{favoriteList.name}} 808 </label> 809 810 @*<input type="checkbox" :value="favoriteList.id" :checked="isItemAddedToThisList(favoriteList)" v-on:change="toggleItem($event, favoriteList.id)" class="form-check-input" /> 811 <label :for="'fav-' + favoriteList.id" class="form-check-label"> 812 {{favoriteList.name}} 813 </label>*@ 814 </div> 815 @*</div>*@ 816 </script> 817 818 <script type="text/x-template" id="favorite-list-template"> 819 <div class="fav"> 820 <button :aria-controls="'favorite' + product.id" :class="['btn', buttonClass]" aria-label="@Translate(" Favorite", "Favorite" )" v-on:click="toggleItem()"> 821 <template v-if="isActive"> 822 <b-icon-star-fill class="font-size-lg"></b-icon-star-fill> 823 </template> 824 <template v-else> 825 <b-icon-star></b-icon-star> 826 </template> 827 </button> 828 <div class="fav-overlay" v-autoClose.nonPath="closeToggle" :id="'favorite' + product.id"> 829 <div class="fav-inwrap" v-if="showingMenu"> 830 <template v-if="loading"> 831 <div class="text-center"> 832 <span class="spinner-md-default"></span> 833 </div> 834 </template> 835 <div class="flow-3" v-if="!loading"> 836 <h5 class="m-0">@Translate(favoriteListPrefix + "Favoritliste", "Favoritliste")</h5> 837 <template v-if="favoriteLists.length > '0'"> 838 <p class="font-size-sm text-600"> 839 @Translate(favoriteListPrefix + "Tilføj eller fjern markering.", "Tilføj eller fjern markering.") 840 </p> 841 <div class="flow-2 pb-3 border-bottom"> 842 <favorite-item v-for="favoriteList in favoriteLists" :favorite-list="favoriteList" :product="product" :key="favoriteList.id" /> 843 </div> 844 <div class="custom-control custom-checkbox"> 845 <input type="checkbox" v-model="addNewList" id="addNewListCheckbox" class="custom-control-input" /> 846 <label for="addNewListCheckbox" class="custom-control-label"> 847 @Translate(favoriteListPrefix + "Ny favoritliste", "Ny favoritliste") 848 </label> 849 </div> 850 <div v-if="addNewList" class="d-flex align-items-center"> 851 <label for="addNewListNameInput" class="sr-only">@Translate(favoriteListPrefix + "Navn", "Navn")</label> 852 <input type="text" id="addNewListNameInput" v-model="addNewListNameInput" class="form-control new-list-name-input" placeholder="@Translate(favoriteListPrefix + "Navn", "Navn")" v-on:keyup.enter="saveAsNewList" /> 853 <button v-on:click="saveAsNewList" class="btn btn-dark ml-2 px-3">@Translate(favoriteListPrefix + "Gem", "Gem")</button> 854 </div> 855 </template> 856 <template v-else> 857 <p>@Translate(favoriteListPrefix + "NoFavoritliste", "Du har endnu ingen favoritlister, angiv navn for at oprette en.")</p> 858 <div class="d-flex align-items-center"> 859 <label for="addNewListNameInput" class="sr-only">@Translate(favoriteListPrefix + "Navn", "Navn")</label> 860 <input type="text" id="addNewListNameInput" v-model="addNewListNameInput" class="form-control new-list-name-input" placeholder="@Translate(favoriteListPrefix + "Navn", "Navn")" v-on:keyup.enter="saveAsNewList" /> 861 <button v-on:click="saveAsNewList" class="btn btn-dark ml-2 px-3">@Translate(favoriteListPrefix + "Gem", "Gem")</button> 862 </div> 863 </template> 864 865 </div> 866 </div> 867 </div> 868 </div> 869 </script> 870 871 <script src="@NORRIQ.Common8.Razor.TimestampSource.GetSourceWithTimestamp("/Files/dist/scripts/bundle.min.js")"></script> 872 @{ 873 var user = NORRIQ.Universal.Identity.Dw.UserViewModel.GetCurrentUser<NORRIQ.Universal.Identity.Dw.UserViewModel>(); 874 var userJson = JsonConvert.SerializeObject(user); 875 var currency = Pageview.User?.Currency ?? Pageview.Area.EcomCurrencyId; 876 } 877 <script> 878 AppStart.VueProvider.init({ 879 webApiUrl: '@System.Web.Configuration.WebConfigurationManager.AppSettings["WebApiUrl"]', 880 currencyCode: '@currency', 881 locale: '@Pageview.Area.Culture', 882 currencyLeft: true, 883 currencySpacing: true, 884 currencySymbol: '@currency', 885 currencyDecimalSeparator: ',', 886 currencyGroupSeparator: '.', 887 currencyDecimalDigits: 2, 888 dateFormatShort: '@Pageview.Area.Dateformat', 889 user: @userJson 890 }); 891 </script> 892 <script append="replace"></script> 893 <script type="text/javascript"> 894 _linkedin_partner_id = "5568962"; 895 window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || []; 896 window._linkedin_data_partner_ids.push(_linkedin_partner_id); 897 </script><script type="text/javascript"> 898 (function(l) { 899 if (!l){window.lintrk = function(a,b){window.lintrk.q.push([a,b])}; 900 window.lintrk.q=[]} 901 var s = document.getElementsByTagName("script")[0]; 902 var b = document.createElement("script"); 903 b.type = "text/javascript";b.async = true; 904 b.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js"; 905 s.parentNode.insertBefore(b, s);})(window.lintrk); 906 </script> 907 <noscript> 908 <img height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=5568962&fmt=gif" /> 909 </noscript> 910 911 </body> 912 </html> 913