Error executing template "Designs/Dwsimple/eCom/Product/Product.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at Hounisen.Website.Helpers.GroupHelper.GetParentsRecursively(Group group, List`1 groupNames)
   at CompiledRazorTemplates.Dynamic.RazorEngine_297be6f7d85e49b5865c1436054a099f.Execute() in D:\web\hounisen\Hounisen.Website\Files\Templates\Designs\Dwsimple\eCom\Product\Product.cshtml:line 735
   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 @using System.Web; 2 @using System.Net; 3 @using System.Globalization; 4 @using System.Text.RegularExpressions; 5 @using Dynamicweb; 6 @using Dynamicweb.Rendering; 7 @using Dynamicweb.Security.UserManagement; 8 @using System.IO; 9 @using Dynamicweb.Content 10 @using Dynamicweb.Core; 11 @using Dynamicweb.Ecommerce.Products 12 @using Hounisen.Website.Helpers 13 @using VestjyskMarketing.Models; 14 @using HtmlAgilityPack 15 16 17 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 18 19 @using System.Globalization 20 @using Dynamicweb.Content 21 @using Dynamicweb.Ecommerce 22 @using Dynamicweb.Ecommerce.Products 23 @using Dynamicweb.Security.UserManagement 24 @using Hounisen.Website.Helpers 25 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 26 27 @using System.Text.RegularExpressions 28 @using System.Web 29 30 31 @functions{ 32 public class WrapMethods 33 { 34 //Gets the contrasting color 35 public static string getContrastYIQ(string hexcolor) 36 { 37 if (hexcolor != "") 38 { 39 hexcolor = Regex.Replace(hexcolor, "[^0-9a-zA-Z]+", ""); 40 41 int r = Convert.ToByte(hexcolor.Substring(0, 2), 16); 42 int g = Convert.ToByte(hexcolor.Substring(2, 2), 16); 43 int b = Convert.ToByte(hexcolor.Substring(4, 2), 16); 44 int yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; 45 46 if (yiq >= 128) 47 { 48 return "black"; 49 } 50 else 51 { 52 return "white"; 53 } 54 } 55 else 56 { 57 return "black"; 58 } 59 } 60 61 62 //Truncate text 63 public static string Truncate (string value, int count, bool strip=true) 64 { 65 if (strip == true){ 66 value = StripHtmlTagByCharArray(value); 67 } 68 69 if (value.Length > count) 70 { 71 value = value.Substring(0, count - 1) + "..."; 72 } 73 74 return value; 75 } 76 77 78 //Strip text from HTML 79 public static string StripHtmlTagByCharArray(string htmlString) 80 { 81 char[] array = new char[htmlString.Length]; 82 int arrayIndex = 0; 83 bool inside = false; 84 85 for (int i = 0; i < htmlString.Length; i++) 86 { 87 char let = htmlString[i]; 88 if (let == '<') 89 { 90 inside = true; 91 continue; 92 } 93 if (let == '>') 94 { 95 inside = false; 96 continue; 97 } 98 if (!inside) 99 { 100 array[arrayIndex] = let; 101 arrayIndex++; 102 } 103 } 104 return new string(array, 0, arrayIndex); 105 } 106 107 //Make the correct count of columns 108 public static string ColumnMaker(int Col, string ScreenSize) 109 { 110 string Columns = ""; 111 112 switch (Col) 113 { 114 case 1: 115 Columns = "col-"+ScreenSize+"-12"; 116 break; 117 118 case 2: 119 Columns = "col-"+ScreenSize+"-6"; 120 break; 121 122 case 3: 123 Columns = "col-"+ScreenSize+"-4"; 124 break; 125 126 case 4: 127 Columns = "col-"+ScreenSize+"-3"; 128 break; 129 130 default: 131 Columns = "col-"+ScreenSize+"-3"; 132 break; 133 } 134 135 return Columns; 136 } 137 138 139 private string Custom(string firstoption, string secondoption) 140 { 141 if (firstoption == "custom") 142 { 143 return secondoption; 144 } 145 else 146 { 147 return firstoption; 148 } 149 } 150 } 151 } 152 153 154 155 156 157 158 @helper GetProductList(dynamic Loop, int ColMD = 3, int ColSM = 3, int ColXS = 1) 159 { 160 int Count = 0; 161 162 int index = 1; 163 164 var embeddedScript = GetString("Ecom:Group:Field.ProductEmbeddedScript"); 165 var embedIndex = GetInteger("Ecom:Group:Field.EmbedScriptStartingIndex"); 166 167 IFormatProvider jsNumberFormat = new NumberFormatInfo() { NumberDecimalSeparator = ".", NumberGroupSeparator = "" }; 168 169 170 var groupService = new GroupService(); 171 var productService = new ProductService(); 172 var pageService = new PageService(); 173 174 // SKI AND Region H 175 bool hasSkiDeal = false; 176 bool hasRegionHDeal = false; 177 var currentUser = User.GetCurrentExtranetUser(); 178 if (currentUser != null) 179 { 180 var skiGroup = currentUser.Groups.FirstOrDefault(e => e.Name == "SKI"); 181 if (skiGroup != null && !string.IsNullOrEmpty(skiGroup.Name)) 182 { 183 hasSkiDeal = true; 184 } 185 186 hasRegionHDeal = Dynamicweb.Core.Converter.ToBoolean(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_RegionH").Value); 187 } 188 189 190 foreach (LoopItem product in Loop) 191 { 192 string GroupLink = "/Default.aspx?ID=" + product.GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + product.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + product.GetString("Ecom:Product.ID"); 193 // string GroupLink = product.GetString("Ecom:Product.LinkGroup.Clean"); 194 int stock = product.GetInteger("Ecom:Product.Stock"); 195 string Name = product.GetString("Ecom:Product.Name"); 196 string Description = product.GetString("Ecom:Product.ShortDescription"); 197 string prodID = product.GetString("Ecom:Product.ID"); 198 string prodVariantID = product.GetString("Ecom:Product.VariantID"); 199 string prodLanguageID = product.GetString("Ecom:Product.LanguageID"); 200 string Image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + prodID + ".jpg&format=webp&quality=85"; 201 202 //prices and units 203 string defaultUnitId = product.GetString("Ecom:Product.DefaultUnitID"); 204 var prices = product.GetLoop("Product.Prices"); 205 List<string> pricesHtmlList = Hounisen.Website.Helpers.Helpers.PricesListMakeListString(prices); 206 List<Hounisen.Website.Models.Unit> unitsDropdown = Hounisen.Website.Helpers.Helpers.PopulateUnitsDropdown(prices); 207 var unitDefault = unitsDropdown.Where(x => x.Id.Equals(defaultUnitId)).FirstOrDefault(); 208 int minOrder = unitDefault != null ? unitDefault.MinOrder : 1; 209 210 if (!string.IsNullOrWhiteSpace(product.GetString("Ecom:Product.SelectedVariantComboID"))) 211 { 212 prodID = product.GetString("Ecom:Product.ID") + "&" + product.GetString("Ecom:Product.SelectedVariantComboID"); 213 } 214 215 216 GroupHelper gh = new GroupHelper(); 217 var masterPage = pageService.GetPage(product.GetInteger("Ecom:Product.PrimaryOrCurrentPageID")); 218 masterPage.GetDisplayName(); 219 220 var group = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(product.GetString("Ecom:Product.PrimaryOrFirstGroupID")); 221 var groups = ""; 222 if (group != null) 223 { 224 var groupNames = gh.GetParentsRecursively(group, new List<string>()); 225 groupNames = gh.Format(groupNames, masterPage.GetDisplayName(), group); 226 groups = gh.ListToString(groupNames); 227 } 228 229 <div class="product-list__item"> 230 <div class="col-xs-12"> 231 <div class="product-list__item-inner"> 232 <div class="col-xs-12 col-sm-4 col-flex"> 233 234 <div class="product-list-item__primary-image"> 235 @if (currentUser != null) 236 { 237 <a href="@GroupLink" title="@Name"> 238 <img class="product-list-item__image lazy" alt="@Name" data-src="@Image&width=300" class="img-responsive img-center"> 239 </a> 240 <a class="fancybox" data-fancybox href="@Image&width=1000" title="@Name"> 241 <svg class="product-list-item__image-icon"> 242 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#fullscreen"></use> 243 </svg> 244 </a> 245 } 246 else 247 { 248 <a href="@GroupLink" title="@Name"> 249 <img class="product-list-item__image lazy" alt="@Name" data-src="@Image&width=300" class="img-responsive img-center"> 250 </a> 251 <a class="fancybox" data-fancybox href="@Image&width=1000" title="@Name"> 252 <svg class="product-list-item__image-icon"> 253 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#fullscreen"></use> 254 </svg> 255 </a> 256 } 257 258 259 </div> 260 @{ 261 var productObj = productService.GetProductById(prodID, prodVariantID, prodLanguageID); 262 var overlayNameAndColors = new ProductImageOverlayHelper().GetTextAndColor(productObj); 263 264 <div class="product__primary-image__overlay-container"> 265 @foreach (var overlayNameAndColo in overlayNameAndColors) 266 { 267 <div style="background-color: @overlayNameAndColo.Value" class="product__primary-image__overlay-container__item"> 268 @overlayNameAndColo.Key 269 </div> 270 } 271 </div>} 272 </div> 273 <div class="col-xs-12 col-sm-8"> 274 <div class="product-list-item__info js-product-info"> 275 <div class="row"> 276 @*Title & Number*@ 277 <div class="col-xs-12"> 278 <h4 data-name="@Name" data-product_id="@prodID" data-categories="@groups" class="product-list-item__title"> 279 <a class="product-list-item__title-link" href="@GroupLink">@Name</a> 280 </h4> 281 </div> 282 </div> 283 <div class="row"> 284 <div class="col-xs-12 col-sm-5"> 285 286 <div class="product-list-item__attributes"> 287 <p> 288 <strong>Varenummer:</strong> @product.GetString("Ecom:Product.Number") 289 </p> 290 <p> 291 <strong>@product.GetString("Ecom:Product:Field.Attribut1A"):</strong><br/>@product.GetString("Ecom:Product:Field.Attribut1B") 292 </p> 293 <p> 294 <strong>@product.GetString("Ecom:Product:Field.Attribut2A"):</strong> @product.GetString("Ecom:Product:Field.Attribut2B") 295 </p> 296 </div> 297 298 <div class="hidden-xs"> 299 <div class=""> 300 @* IKONER *@ 301 <div class="product-list-item__icons"> 302 @{ 303 foreach (var c in product.GetString("Ecom:Product:Field.Certificates").Split(',')) 304 { 305 if (!string.IsNullOrEmpty(c)) 306 { 307 string src = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Certificates/" + @c + ".jpg&format=webp&quality=85&width=100"; 308 <img class="product-list-item__icon lazy" alt="@Translate("Cert_" + c, c)" title="@Translate("Cert_" + c, c)" data-src=@src src=@src> 309 } 310 } 311 } 312 </div> 313 </div> 314 </div> 315 </div> 316 317 <div class="col-xs-12 col-sm-7"> 318 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 319 { 320 <ul class="product-list-item__prices"> 321 @foreach (var priceHtml in pricesHtmlList) 322 { 323 <li> 324 @priceHtml 325 </li> 326 } 327 </ul> 328 } 329 </div> 330 </div> 331 332 <div class="row"> 333 <div class="col-xs-12 col-sm-4 col-lg-5"> 334 @* LAGERBEHOLDNING *@ 335 <div class="product-list-item__stock"> 336 @{ 337 if (stock > 0) 338 { 339 <p class="product-list-item__stock-text"> 340 <span class="product-list-item__stock-circle product-list-item__stock-circle--green"></span> På lager 341 </p> 342 } 343 else 344 { 345 <p class="product-list-item__stock-text"> 346 <span class="product-list-item__stock-circle product-list-item__stock-circle--yellow"></span> Kontakt os for leveringstid: 86210800 eller salg@hounisen.com 347 </p> 348 } 349 } 350 </div> 351 352 <div class="product-list-item__see-product"> 353 <a class="product-list-item__link" href="@GroupLink" class="">@Translate("See product", "Se produkt")</a> 354 </div> 355 </div> 356 <div class="col-xs-12 col-sm-8 col-lg-7"> 357 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 358 { 359 <div class="row"> 360 <div class="col-xs-7"> 361 <div class="product__addtocart-input js-addtocart-input"> 362 <input type="button" value="-" class="product-list-item__quantity-button product-list-item__quantity-button--minus qtyminus" field="quantity"/> 363 <input type="number" class="product__quantity-input product-list-item__quantity-input quantity" data-name="quantity" name="quantity" value="@minOrder" field="quantity"/> 364 <input type="button" value="+" class="product-list-item__quantity-button product-list-item__quantity-button--plus qtyplus" field="quantity"/> 365 </div> 366 <div class="product__unit-selector" style="display: inline-block;"> 367 @{ 368 int counter = 0; 369 } 370 @foreach (var unitDropdown in unitsDropdown) 371 { 372 var currentUnitPrice = prices[counter].Values["Ecom:Product.Prices.Amount"]; 373 <input type="radio" data-id="@index" data-price="@currentUnitPrice" class="unit-type" id="@(unitDropdown.Id + prodID)" name="UnitID@(product.GetString("Ecom:Product.Number"))" value="@unitDropdown.Id" required data-lot-size="@unitDropdown.LotSize" data-min-order="@unitDropdown.MinOrder" @(unitsDropdown.Count == 1 ? "checked='checked'" : "")> 374 <label for="@(unitDropdown.Id + prodID)">@unitDropdown.Name</label> 375 counter++; 376 } 377 </div> 378 <p class="product__unit-selector-error-message"> 379 @Translate("unit-error-message", "* Du mangler at vælge type") 380 </p> 381 </div> 382 <div class="col-xs-5"> 383 <div class="product__addtocart-button"> 384 <button data-id="@index" type="submit" name="submit" onclick="AddToCart(event, '@prodID', $(this).parent().parent().prev().find('input.quantity').val(), $(this).parent().parent().prev().find('input[name=\'UnitID@(product.GetString("Ecom:Product.Number"))\']:checked').val());" class="btn btn-primary product__button"> 385 @Translate("Add to cart", "Add to cart") 386 <svg class="product__button-icon hidden-xs"> 387 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#basket"></use> 388 </svg> 389 </button> 390 <div class="product-list-item__favorite-list popup-wrap favorite"> 391 392 @if (hasRegionHDeal == false) 393 { 394 <button class="popup-show" data-popup="favorite-list" type="button" title="@Translate("Add to favorites", "Add to favorites")"> 395 <i class="fa fa-star-o"></i> <span>Tilføj til liste</span> 396 </button> 397 <div id="favorite-list" class="popup-form"> 398 <div class="close"> 399 <i class="fa fa-times"></i> 400 </div> 401 <h3>@Translate("Choose list", "Choose list")</h3> 402 <ul> 403 @{ 404 var lists = Dynamicweb.Ecommerce.CustomerCenter.CustomerProductList.GetListsByUserCustomerNumber(currentUser.CustomerNumber); 405 } 406 407 @foreach (var list in lists) 408 { 409 if (list.Products.Where(p => p.ProductId.ToString() == prodID).Count() > 0) 410 { 411 <li> 412 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCRemoveFromMyLists=@prodID&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType="> 413 <i class="fa fa-star"></i> @list.Name 414 </a> 415 </li> 416 } 417 else 418 { 419 <li> 420 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCAddToMyLists=@prodID&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType="> 421 <i class="fa fa-star-o"></i> @list.Name 422 </a> 423 </li> 424 } 425 } 426 <li> 427 <a href="/favoritter/opret-favoritliste?ProdID=@prodID"> 428 <i class="fa fa-plus"></i>@Translate("Add new list", "Add new list") 429 </a> 430 </li> 431 </ul> 432 </div> 433 } 434 435 </div> 436 </div> 437 </div> 438 </div> 439 } 440 else 441 { 442 <div class="not-loggedin"> 443 <p class="not-loggedin-text"><a data-toggle="modal" data-target="#login" href="">@Translate("Login", "Login")</a> eller <a href="/kontakt/opret-brugerprofil">Bliv kunde</a> for at se priser og købe på Hounisen.com</p> 444 <a data-toggle="modal" data-target="#login" href="" class="btn btn-primary not-loggedin-button"> 445 <span>Log ind</span> 446 </a> 447 </div> 448 } 449 </div> 450 </div> 451 </div> 452 453 454 </div> 455 </div> 456 </div> 457 </div> 458 459 if (index == embedIndex) 460 { 461 <div class="product-list__item"> 462 <div class="col-xs-12"> 463 @embeddedScript 464 </div> 465 </div> 466 } 467 468 469 Count++; 470 index++; 471 472 if (Count == ColMD) 473 { 474 <div class="row"></div> 475 Count = 0; 476 } 477 } 478 } 479 480 <script> 481 482 document.addEventListener("DOMContentLoaded", function () { 483 484 var addToCartButtons = document.querySelectorAll('.product__button'); 485 var unitTypes = document.getElementsByClassName("unit-type"); 486 var product_names = document.getElementsByClassName("product-list-item__title"); 487 488 addToCartButtons.forEach(function (item) { 489 490 item.addEventListener('click', function () { 491 492 var product_name = product_names[this.dataset.id - 1].dataset.name; 493 var product_id = product_names[this.dataset.id - 1].dataset.product_id; 494 var initialCategories = product_names[this.dataset.id - 1].dataset.categories; 495 var categories = initialCategories.split("_"); 496 var quantity = document.getElementsByClassName("quantity")[this.dataset.id - 1].value; 497 var unitPrice; 498 var variantIsNull = true; 499 var unitTypeName = null; 500 501 //Get unittype price 502 for (const unitType of unitTypes) { 503 504 if (unitType.dataset.id == this.dataset.id) { 505 506 if (unitType.checked == true) { 507 508 var tempPrice = unitType.dataset.price.replace(".", ""); 509 tempPrice = tempPrice.replace(",", "."); 510 unitPrice = parseFloat(tempPrice); 511 variantIsNull = false; 512 unitTypeName = unitType.value; 513 514 unitTypeName = unitTypeName.toString().split("_")[1]; 515 516 } 517 } 518 } 519 520 if (!variantIsNull) { 521 dataLayer.push({ ecommerce: null }); 522 dataLayer.push({ 523 'event': 'add_to_cart', 524 "ecommerce": { 525 "currency": "DKK", 526 "value": unitPrice * parseInt(quantity).toFixed(2), 527 "items": [ 528 { 529 "item_name": product_name + " - " + unitTypeName, 530 'item_id': product_id, 531 'price': unitPrice, 532 "item_brand": "", 533 "item_category": (categories[0] != null ? categories[0] : ""), 534 "item_category2": (categories[1] != null ? categories[1] : ""), 535 "item_category3": (categories[2] != null ? categories[2] : ""), 536 "item_category4": (categories[3] != null ? categories[3] : ""), 537 "item_category5": (categories[4] != null ? categories[4] : ""), 538 "quantity": parseInt(quantity), 539 } 540 ] 541 }, 542 543 }); 544 } 545 }); 546 }) 547 }); 548 549 </script> 550 @using Dynamicweb.Security.UserManagement 551 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 552 553 @helper GetProductListRelated(dynamic Loop, int ColMD = 3, int ColSM = 3, int ColXS = 1) 554 { 555 var currentUser = User.GetCurrentExtranetUser(); 556 557 <ul class="shop-list__list"> 558 559 @foreach (LoopItem product in Loop) 560 { 561 562 string GroupLink = "/Default.aspx?ID=" + product.GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + product.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + product.GetString("Ecom:Product.ID"); 563 string Name = product.GetString("Ecom:Product.Name"); 564 string Description = product.GetString("Ecom:Product.ShortDescription"); 565 string prodID = product.GetString("Ecom:Product.ID"); 566 string Image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + prodID + ".jpg&format=webp&quality=85"; 567 568 <li class="shop-list__item col-xs-12"> 569 <a class="shop-list__link" href="@GroupLink" title="@Name"> 570 <figure class="shop-list__figure"> 571 <img class="shop-list__image lazy" style="width: 213px;" alt="@Name" data-src="@Image&width=213"> 572 </figure> 573 <h4 class="shop-list__title">@Name</h4> 574 <div class="shop-list__text"> 575 @if (String.IsNullOrEmpty(product.GetString("Ecom:Product.LongDescription"))) 576 { 577 var gr = Dynamicweb.Ecommerce.Products.Group.GetGroupById(product.GetString("Ecom:Product.PrimaryOrFirstGroupID")); 578 579 @gr.Description.Replace("<a ", "<span ").Replace("</a>", "</span>").Replace("<h2>", "<p>").Replace("</h2>", "</p>") 580 } 581 else 582 { 583 @product.GetString("Ecom:Product.LongDescription").Replace("<a ", "<span ").Replace("</a>", "</span>").Replace("<h2>", "<p>").Replace("</h2>", "</p>") 584 } 585 586 </div> 587 <div class="shop-list__price"> 588 @if (currentUser != null) 589 { 590 string baseUnitPrice = String.Empty; 591 var price = product.GetLoop("Product.Prices").OrderBy(x => x.GetDouble("Ecom:Product.Prices.BaseUnitPrice")).FirstOrDefault(); 592 if (price != null) 593 { 594 baseUnitPrice = price.GetString("Ecom:Product.Prices.BaseUnitPrice"); 595 } 596 <span class="shop-list__price-from">Priser fra</span> 597 <span class="shop-list__price-value">@baseUnitPrice</span> 598 <span class="shop-list__price-unit">kr./stk.</span> 599 } 600 </div> 601 </a> 602 </li> 603 604 } 605 </ul> 606 } 607 608 609 @using Dynamicweb.Security.UserManagement 610 @using System.Text.RegularExpressions; 611 @using Hounisen.Website.Helpers 612 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 613 614 @helper GetProductListFullRelated(dynamic Loop, int ColMD = 4, int ColSM = 4, int ColXS = 1) 615 { 616 int Count = 0; 617 618 string ColumnsMD = WrapMethods.ColumnMaker(ColMD, "md"); 619 string ColumnsSM = WrapMethods.ColumnMaker(ColSM, "sm"); 620 string ColumnsXS = WrapMethods.ColumnMaker(ColXS, "xs"); 621 var currentUser = User.GetCurrentExtranetUser(); 622 623 foreach (LoopItem product in Loop) 624 { 625 string GroupLink = "/Default.aspx?ID=" + product.GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + product.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + product.GetString("Ecom:Product.ID"); 626 string Name = product.GetString("Ecom:Product.Name"); 627 string Description = GetFormattedDescription(product.GetString("Ecom:Product.LongDescription")); 628 string prodID = product.GetString("Ecom:Product.ID"); 629 string Image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + prodID + ".jpg&format=webp&quality=85"; 630 var productObject = Dynamicweb.Ecommerce.Products.Product.GetProductById(product.GetString("Ecom:Product.ID"), product.GetString("Ecom:Product.VariantID"), product.GetString("Ecom:Product.LanguageID")); 631 var textAndColors = new ProductImageOverlayHelper().GetTextAndColor(productObject); 632 <li class="shop-list__item col-xs-12"> 633 <a class="shop-list__link" href="@GroupLink" title="@Name"> 634 <figure class="shop-list__figure" style="position: relative"> 635 <img class="shop-list__image lazy" style="width: 213px;" alt="@Name" data-src="@Image&width=213"> 636 <div class="product__primary-image__overlay-container"> 637 @foreach (var overlayNameAndColor in textAndColors) 638 { 639 <div style="background-color: @overlayNameAndColor.Value" class="product__primary-image__overlay-container__item"> 640 @overlayNameAndColor.Key 641 </div> 642 } 643 </div> 644 </figure> 645 <h4 class="shop-list__title">@Name</h4> 646 <div class="shop-list__text">@Description</div> 647 <div class="shop-list__price"> 648 @if (currentUser != null) 649 { 650 string baseUnitPrice = String.Empty; 651 var price = product.GetLoop("Product.Prices").OrderBy(x => x.GetDouble("Ecom:Product.Prices.BaseUnitPrice")).FirstOrDefault(); 652 if (price != null) 653 { 654 baseUnitPrice = price.GetString("Ecom:Product.Prices.BaseUnitPrice"); 655 } 656 657 <span class="shop-list__price-from">Priser fra</span> 658 <span class="shop-list__price-value">@baseUnitPrice</span> 659 <span class="shop-list__price-unit">kr./stk</span> 660 } 661 </div> 662 </a> 663 </li> 664 } 665 } 666 667 @functions { 668 private static string GetFormattedDescription(string description = "") 669 { 670 string formattedDescription = Regex.Replace(description, @"<.*?>|[\r\n\t]|&nbsp;", " "); 671 return formattedDescription.Length > 103 ? formattedDescription.Substring(0, 103).TrimEnd() + "..." : formattedDescription; 672 } 673 } 674 675 <script src="/Files/Templates/Designs/DwSimple/js/ProductVariantsAjax.js"></script> 676 <link rel="stylesheet" href="/Files/Templates/Designs/DwSimple/css/product.css"/> 677 678 @{ 679 IFormatProvider jsNumberFormat = new NumberFormatInfo() { NumberDecimalSeparator = ".", NumberGroupSeparator = "" }; 680 string initialPrice = string.Empty; 681 string metaDescription = string.Empty; 682 if (String.IsNullOrEmpty(GetString("Ecom:Product.LongDescription"))) 683 { 684 metaDescription = StripHTML(GetString("Ecom:Group.Description")); 685 686 } 687 else 688 { 689 metaDescription = StripHTML(GetString("Ecom:Product.LongDescription")); 690 691 } 692 693 //prices and units 694 string defaultUnitId = GetString("Ecom:Product.DefaultUnitID"); 695 var prices = GetLoop("Product.Prices"); 696 List<string> pricesHtmlList = Hounisen.Website.Helpers.Helpers.PricesListMakeListString(prices, false); 697 List<Hounisen.Website.Models.Unit> unitsDropdown = Hounisen.Website.Helpers.Helpers.PopulateUnitsDropdown(prices); 698 var unitDefault = unitsDropdown.Where(x => x.Id.Equals(defaultUnitId)).FirstOrDefault(); 699 int minOrder = unitDefault != null ? unitDefault.MinOrder : 1; 700 701 702 //other vars 703 var pid = GetString("Ecom:Product.ID"); 704 int stock = GetInteger("Ecom:Product.Stock"); 705 string image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + pid + ".jpg"; 706 string productname = GetString("Ecom:Product.Name"); 707 string productlink = "/Default.aspx?ID=" + GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + GetString("Ecom:Product.ID"); 708 709 710 // SKI AND Region H 711 bool hasSkiDeal = false; 712 bool hasRegionHDeal = false; 713 var currentUser = User.GetCurrentExtranetUser(); 714 if (currentUser != null) 715 { 716 var skiGroup = currentUser.Groups.FirstOrDefault(e => e.Name == "SKI"); 717 if (skiGroup != null && !string.IsNullOrEmpty(skiGroup.Name)) 718 { 719 hasSkiDeal = true; 720 } 721 722 hasRegionHDeal = Dynamicweb.Core.Converter.ToBoolean(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_RegionH").Value); 723 } 724 725 //serialized data 726 var pagedata = new System.Collections.Generic.Dictionary<String, Object>(); 727 Pageview.Area.Item.SerializeTo(pagedata); 728 729 730 var pageService = new PageService(); 731 GroupHelper gh = new GroupHelper(); 732 var group = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(GetString("Ecom:Product.PrimaryOrFirstGroupID")); 733 var masterPage = pageService.GetPage(GetInteger("Ecom:Product.PrimaryOrCurrentPageID")); 734 masterPage.GetDisplayName(); 735 var groupNames = gh.GetParentsRecursively(group, new List<string>()); 736 groupNames = gh.Format(groupNames, masterPage.GetDisplayName(), group); 737 738 var groups = gh.ListToString(groupNames); 739 } 740 741 <div class="col-md-12 col-sm-12 col-xs-12 aaa"> 742 743 <div class="row product" itemscope itemtype="http://schema.org/Product"> 744 <section class="page-header"> 745 <div class="row product__help-name-container"> 746 <div class="col-xs-12 col-sm-7"> 747 <meta itemprop="description" content="@metaDescription"/> 748 <h1 data-categories="@groups" data-group="@GetString("Ecom:Group.Name")" class="page-header__title" itemprop="name">@GetString("Ecom:Product.Name")</h1> 749 <div class="page-header__short-description"> 750 <p class="product__number">@Translate("Productnumber", "Productnumber"): <span property="identifier" itemprop="mpn">@GetString("Ecom:Product.Number")</span></p> 751 @if (hasSkiDeal) 752 { 753 <p class="product__number">@Translate("Skinumber", "SKI nr"): <span property="identifier">@GetString("Ecom:Product:Field.SkiId")</span></p> 754 } 755 @if (hasRegionHDeal && GetBoolean("Ecom:Product:Field.RegionH")) 756 { 757 <p class="product__number">@Translate("RegionHText")</p> 758 } 759 760 </div> 761 </div> 762 <div class="col-xs-12 col-sm-offset-1 col-sm-4 product__help-name-container__help"> 763 <div class="need-help"> 764 <img class="need-help__image lazy" width="81" height="81" data-src='@(Pageview.Area.Item["Support_Image"].ToString())?format=webp&width=81&quality=75'/> 765 <div class="need-help__text"> 766 @Pageview.Area.Item["Support_Content"].ToString() 767 </div> 768 </div> 769 </div> 770 </div> 771 </section> 772 <div class="row"> 773 774 @* The image area *@ 775 <div class="col-md-5 col-sm-4 col-xs-12"> 776 <div class="product__gallery"> 777 778 @* Discount sticker *@ 779 780 @if (GetString("Ecom:Product.Discount.Price.PriceWithVATFormatted") != GetString("Ecom:Product.Price.PriceWithVATFormatted")) 781 { 782 if (pagedata["EcommerceStickerType"].ToString() == "ribbon") 783 { 784 <span class="ribbon base">@Translate("On sale!", "On sale!")</span> 785 } 786 787 if (pagedata["EcommerceStickerType"].ToString() == "ball") 788 { 789 <span class="ball">@Translate("On sale!", "On sale!")</span> 790 } 791 } 792 793 794 @* Product images *@ 795 @{ 796 string currenthost = HttpContext.Current.Request.Url.AbsoluteUri; 797 Uri uri = new Uri(currenthost); 798 currenthost = string.Format("{0}://{1}", uri.Scheme, uri.Authority); 799 string ImagePathloop = ""; 800 string ImagePathClean = ""; 801 string options = "format=webp&quality=85&width=1000"; 802 List<string> imagepath = new List<string>(); 803 for (int i = 0; i <= 4; i++) 804 { 805 if (i == 0) 806 { 807 ImagePathloop = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings() 808 { 809 Image = $"/Files/Images/Ecom/Products/{pid}.jpg", 810 Width = 1000, 811 Quality = 85 812 }); 813 imagepath.Add(ImagePathloop); 814 } 815 else 816 { 817 ImagePathloop = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg"; 818 //currenthost + 819 ImagePathClean = "/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg"; 820 821 try 822 { 823 if (File.Exists(HttpContext.Current.Server.MapPath(ImagePathClean))) 824 { 825 imagepath.Add(ImagePathloop + "&" + options); 826 } 827 828 829 HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(ImagePathloop); 830 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 831 { 832 if (response.StatusCode == HttpStatusCode.NotFound) 833 { 834 break; 835 } 836 else 837 { 838 imagepath.Add("/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg" + "" + options); 839 } 840 } 841 } 842 catch (Exception ex) 843 { 844 } 845 } 846 } 847 } 848 849 @{ 850 var resizedImageLarge = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings() 851 { 852 Image = $"/Files/Images/Ecom/Products/{pid}.jpg", 853 Width = 1000, 854 Quality = 99 855 }); 856 857 var resizedImage = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings() 858 { 859 Image = $"/Files/Images/Ecom/Products/{pid}.jpg", 860 Width = 458, 861 Quality = 85 862 }); 863 } 864 865 <div class="product__primary-image"> 866 <a href="@resizedImageLarge" data-fancybox class="fancybox"> 867 <img src="@resizedImage" data-src="@resizedImage" width="458" alt="@productname" class="product__image img-responsive lazy" itemprop="image"> 868 @{ 869 var productObj = new ProductService().GetProductById(GetString("Ecom:Product.ID"),GetString("Ecom:Product.VariantID"),GetString("Ecom:Product.LanguageID")); 870 var overlayNameAndColors = new ProductImageOverlayHelper().GetTextAndColor(productObj); 871 } 872 873 <div class="product__primary-image__overlay-container"> 874 @foreach (var overlayNameAndColor in overlayNameAndColors) 875 { 876 <div style="background-color: @overlayNameAndColor.Value" class="product__primary-image__overlay-container__item"> 877 @overlayNameAndColor.Key 878 </div> 879 } 880 </div> 881 <svg class="product__image-icon"> 882 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#fullscreen"></use> 883 </svg> 884 </a> 885 </div> 886 <div class="row"> 887 <div class="product__thumbnail-list"> 888 @foreach (var imageThumb in imagepath) 889 { 890 <div class="col-sm-3 col-xs-4"> 891 <div class="product__thumbnail-images"> 892 <a href="@imageThumb&width=1000" rel="product" class="fancybox"> 893 <img data-src="@imageThumb&width=458" width="458" alt="@productname" class="img-responsive lazy"> 894 </a> 895 </div> 896 </div> 897 } 898 @{ 899 var youtubeId = GetString("Ecom:Product:Field.YoutubeId"); 900 var youtubeUrl = $"//www.youtube.com/embed/{youtubeId}?autoplay=0"; 901 if (!string.IsNullOrEmpty(youtubeId)) 902 { 903 <div class="col-sm-3 col-xs-4"> 904 <div id="video-container" class="product__thumbnail-list__video-thumbnail" onclick="on(); return false;"> 905 <iframe width="100%" height="70" src="@youtubeUrl" frameborder="0"></iframe> 906 <div class="product__thumbnail-list__video-thumbnail__video"></div> 907 </div> 908 <div id="overlay" class="product__thumbnail-list__overlay" onclick="off()"> 909 <iframe class="product__thumbnail-list__overlay__video" id="product-video" width="100%" height="80%" src="@youtubeUrl?autoplay=1&enablejsapi=1" frameborder="0"></iframe> 910 </div> 911 </div> 912 } 913 } 914 </div> 915 </div> 916 </div> 917 </div> 918 919 @* The main product information area *@ 920 921 <div class="col-md-7 col-sm-8 col-xs-12 "> 922 <div class="product-info js-product-info" id="productinfo"> 923 <div class="product__control"> 924 <div class="row"> 925 <div class="col-xs-12 col-sm-6"> 926 @* LAGERBEHOLDNING *@ 927 <div class="product__stock"> 928 @{ 929 if (stock > 0) 930 { 931 <p class="product__stock-text"> 932 <span class="product__stock-circle product__stock-circle--green"></span> På lager 933 </p> 934 } 935 else 936 { 937 <p class="product__stock-text"> 938 <span class="product__stock-circle product__stock-circle--yellow"></span> Kontakt os for leveringstid: 86210800 eller salg@hounisen.com 939 </p> 940 } 941 } 942 </div> 943 </div> 944 <div class="col-xs-12 col-sm-6"> 945 @* FAVORITTER *@ 946 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 947 { 948 if (hasRegionHDeal == false) 949 { 950 <div class="product__favorite-list popup-wrap favorite"> 951 <button class="popup-show" data-popup="favorite-list" type="button" title="@Translate("Add to favorites", "Add to favorites")"> 952 <i class="fa fa-star-o"></i> <span>@Translate("Add to favorites", "Add to favorites")</span> 953 </button> 954 <div id="favorite-list" class="popup-form"> 955 <div class="close"> 956 <i class="fa fa-times"></i> 957 </div> 958 <h3>@Translate("Choose list", "Choose list")</h3> 959 <ul> 960 @{ 961 var lists = Dynamicweb.Ecommerce.CustomerCenter.CustomerProductList.GetListsByUserCustomerNumber(currentUser.CustomerNumber); 962 } 963 964 @foreach (var list in lists) 965 { 966 if (list.Products.Where(p => p.ProductId.ToString() == GetString("Ecom:Product.ID")).Count() > 0) 967 { 968 <li> 969 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCRemoveFromMyLists=@GetString("Ecom:Product.ID")&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType="> 970 <i class="fa fa-star"></i> @list.Name 971 </a> 972 </li> 973 } 974 else 975 { 976 <li> 977 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCAddToMyLists=@GetString("Ecom:Product.ID")&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType="> 978 <i class="fa fa-star-o"></i> @list.Name 979 </a> 980 </li> 981 } 982 } 983 <li> 984 <a href="/favoritter/opret-favoritliste?ProdID=@GetString("Ecom:Product.ID")"> 985 <i class="fa fa-plus"></i>@Translate("Add new list", "Add new list") 986 </a> 987 </li> 988 </ul> 989 </div> 990 </div> 991 } 992 } 993 else 994 { 995 <div class="not-loggedin"> 996 <p class="not-loggedin-text"><a data-toggle="modal" data-target="#login" href="">@Translate("Login", "Login")</a> eller <a href="/kontakt/opret-brugerprofil">Bliv kunde</a> for at se priser og købe på Hounisen.com</p> 997 <a data-toggle="modal" data-target="#login" href="" class="btn btn-primary not-loggedin-button"> 998 <span>Log ind</span> 999 </a> 1000 </div> 1001 } 1002 </div> 1003 </div> 1004 1005 1006 @* Prices and actions *@ 1007 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 1008 { 1009 var product = GetString("Ecom:Product.ID"); 1010 if (!string.IsNullOrWhiteSpace(GetString("Ecom:Product.SelectedVariantComboID"))) 1011 { 1012 product = GetString("Ecom:Product.ID") + "&" + GetString("Ecom:Product.SelectedVariantComboID"); 1013 } 1014 1015 <div class="row"> 1016 <div class="col-xs-12"> 1017 <ul class="product__prices"> 1018 @foreach (var priceHtml in pricesHtmlList) 1019 { 1020 <li> 1021 @priceHtml 1022 </li> 1023 } 1024 </ul> 1025 </div> 1026 </div> 1027 1028 <div class="row"> 1029 <div class="col-xs-7"> 1030 <div class="product__addtocart-input js-addtocart-input"> 1031 <input type="button" value="-" class="product__quantity-button product__quantity-button--minus qtyminus" field="quantity"/> 1032 <input type="number" class="product__quantity-input quantity" data-name="quantity" name="quantity" value="@minOrder" field="quantity"/> 1033 <input type="button" value="+" class="product__quantity-button product__quantity-button--plus qtyplus" field="quantity"/> 1034 </div> 1035 <div class="product__unit-selector" style="display: inline-block;"> 1036 1037 @{ 1038 var index = 0; 1039 } 1040 1041 @foreach (var unitDropdown in unitsDropdown) 1042 { 1043 index++; 1044 var currentUnitPrice = prices[index - 1].Values["Ecom:Product.Prices.Amount"]; 1045 <input data-price="@currentUnitPrice" class="unit-type" type="radio" id="@unitDropdown.Id" name="UnitID" value="@unitDropdown.Id" required data-lot-size="@unitDropdown.LotSize" data-min-order="@unitDropdown.MinOrder" @(unitsDropdown.Count == 1 ? "checked='checked'" : "")> 1046 <label for="@unitDropdown.Id">@unitDropdown.Name</label> 1047 } 1048 </div> 1049 <p class="product__unit-selector-error-message"> 1050 * Du mangler at vælge type 1051 </p> 1052 </div> 1053 <div class="col-xs-5"> 1054 <div class="product__addtocart-button"> 1055 <button type="submit" name="submit" onclick="AddToCart(event, '@product', $(this).parent().parent().prev().find('input.quantity').val(), $(this).parent().parent().prev().find('input[name=\'UnitID\']:checked').val());" class="btn btn-primary product__button"> 1056 @Translate("Add to cart", "Add to cart") 1057 <svg class="product__button-icon hidden-xs"> 1058 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#basket"></use> 1059 </svg> 1060 </button> 1061 </div> 1062 </div> 1063 </div> 1064 } 1065 </div> 1066 1067 @* Product details *@ 1068 <div> 1069 1070 @* BESKRIVELSE *@ 1071 @*PRODUCT Long*@ 1072 <div class="product__description"> 1073 <p> 1074 @{ 1075 string productDescrption = null; 1076 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.Teaser"))) 1077 { 1078 productDescrption = GetString("Ecom:Product:Field.Teaser"); 1079 <div> 1080 @if (GetString("Ecom:Product.LongDescription").Length > 150) 1081 { 1082 productDescrption = productDescrption + "..."; 1083 <p class="product__description__long"> 1084 @productDescrption 1085 </p> 1086 <p> 1087 <a href="#productLongDescriptionID" id="js-smooth-scroll" class="js-smooth-scroll">@Translate("ReadMore", "Læs mere")</a> 1088 </p> 1089 } 1090 else 1091 { 1092 <p class="product__description__long"> 1093 @productDescrption 1094 </p> 1095 } 1096 </div> 1097 } 1098 else if (String.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && String.IsNullOrEmpty(GetString("Ecom:Product:Field.Teaser"))) 1099 { 1100 productDescrption = GetString("Ecom:Group.Description"); 1101 @productDescrption 1102 } 1103 else 1104 { 1105 productDescrption = StripHTML(GetString("Ecom:Product.LongDescription").ToString()); 1106 if (productDescrption.Length > 150) 1107 { 1108 productDescrption = productDescrption.Substring(0, 150) + "..."; 1109 1110 <p class="product__description__long"> 1111 @productDescrption 1112 1113 </p> 1114 <p> 1115 <a href="#productLongDescriptionID" id="js-smooth-scroll" class="js-smooth-scroll">@Translate("ReadMore", "Læs mere")</a> 1116 </p> 1117 } 1118 else 1119 { 1120 productDescrption = GetString("Ecom:Product.LongDescription"); 1121 <p class="product__description__long"> 1122 @productDescrption 1123 </p> 1124 } 1125 } 1126 } 1127 1128 </p> 1129 1130 </div> 1131 1132 @* ATTRIBUTTER *@ 1133 <div class="product__information"> 1134 <h3>Specifikationer</h3> 1135 <dl class="product__information-table"> 1136 @{ 1137 int attributeLineCount = 0; 1138 for (int i = 1; i < 8; i++) 1139 { 1140 attributeLineCount++; 1141 string attributeName = "Ecom:Product:Field.Attribut" + attributeLineCount + "A"; 1142 string attributeValue = "Ecom:Product:Field.Attribut" + attributeLineCount + "B"; 1143 string attributeBrand = string.Empty; 1144 1145 if (GetString(attributeName) != "") 1146 { 1147 if (attributeLineCount == 7) 1148 { 1149 attributeBrand = "itemprop=\"brand\""; 1150 } 1151 1152 <dt>@GetString(attributeName) :</dt> 1153 <dd @attributeBrand>@GetString(attributeValue)</dd> 1154 } 1155 } 1156 } 1157 </dl> 1158 </div> 1159 1160 @* IKONER *@ 1161 <div class="product__icons"> 1162 @{ 1163 foreach (var c in GetString("Ecom:Product:Field.Certificates").Split(',')) 1164 { 1165 if (!string.IsNullOrEmpty(c)) 1166 { 1167 <img class="product__icon lazy" data-src="/Files/Images/Ecom/certificates/@(c).jpg" title="@Translate("Cert_" + c, c)"/> 1168 } 1169 } 1170 } 1171 </div> 1172 1173 1174 @* DOWNLOAD *@ 1175 1176 @if (GetString("Ecom:Product:Field.Link1Label") != "") 1177 { 1178 <div> 1179 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link1File.Clean")" class="">@GetString("Ecom:Product:Field.Link1Label")</a> 1180 </div> 1181 } 1182 @if (GetString("Ecom:Product:Field.Link2Label") != "") 1183 { 1184 <div> 1185 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link2File.Clean")" class="">@GetString("Ecom:Product:Field.Link2Label")</a> 1186 </div> 1187 } 1188 @if (GetString("Ecom:Product:Field.Link3Label") != "") 1189 { 1190 <div> 1191 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link3File.Clean")" class="">@GetString("Ecom:Product:Field.Link3Label")</a> 1192 </div> 1193 } 1194 @if (GetString("Ecom:Product:Field.Link4Label") != "") 1195 { 1196 <div> 1197 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link4File.Clean")" class="">@GetString("Ecom:Product:Field.Link4Label")</a> 1198 </div> 1199 } 1200 @if (GetString("Ecom:Product:Field.Link5Label") != "") 1201 { 1202 <div> 1203 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link5File.Clean")" class="">@GetString("Ecom:Product:Field.Link5Label")</a> 1204 </div> 1205 } 1206 1207 1208 </div> 1209 </div> 1210 </div> 1211 </div> 1212 </div> 1213 </div> 1214 1215 @* Related products *@ 1216 1217 @if (GetString("Ecom:Product.RelatedCount") != "0") 1218 { 1219 <div class="row"> 1220 <div class="col-xs-12"> 1221 <h3 class="section-header shop-list__header">Relaterede varer</h3> 1222 <ul class="shop-list__list"> 1223 @foreach (LoopItem relatedgroup in GetLoop("ProductRelatedGroups")) 1224 { 1225 var relatedproductloop = relatedgroup.GetLoop("RelatedProducts").OrderByDescending(g => g.GetString("Ecom:Product.LoopCounter")).Take(4).ToList(); 1226 @GetProductListFullRelated(relatedproductloop, 3, 3, 1) 1227 } 1228 </ul> 1229 </div> 1230 </div> 1231 } 1232 1233 @if (!String.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && StripHTML(GetString("Ecom:Product.LongDescription").ToString()).Length > 150) 1234 { 1235 <div class="row"> 1236 <div class="col-xs-12"> 1237 <h3 id="productLongDescriptionID" class="product__description-title">@Translate("Description", "Description")</h3> 1238 </div> 1239 <div class="col-xs-12 py-4"> 1240 <div style="display: block; margin-bottom: 15px;"> 1241 <div class="product__details"> 1242 @{ 1243 var description = GetString("Ecom:Product.LongDescription"); 1244 1245 // Remove HTML tags 1246 string cleanedText = Regex.Replace(description, "<.*?>", " "); 1247 string[] words = cleanedText.Split(new[] { ' ', '\n', '\r', '\t' }, StringSplitOptions.RemoveEmptyEntries); 1248 bool readMoreButton = words.Length > 80; 1249 } 1250 @if (readMoreButton) 1251 { 1252 <div class="product__details__content" style="max-height: 75px;"> 1253 @description 1254 </div> 1255 <a onclick="updateDetailAccessibility(this)">@Translate("Læs mere")</a> 1256 } 1257 else 1258 { 1259 @description 1260 } 1261 </div> 1262 </div> 1263 </div> 1264 </div> 1265 } 1266 1267 <span class="clerk" 1268 data-template="@@product-page-others-also-bought" 1269 data-products='["@GetString("Ecom:Product.ID")"]'> 1270 </span> 1271 1272 1273 <div class="row"> 1274 <div class="col-md-12 col-sm-12 col-xs-12">&nbsp;</div> 1275 </div> 1276 1277 @{ 1278 var priceInitial = prices.Where(x => x.GetString("Ecom:Product.Prices.UnitID").Equals(unitDefault.Id)).OrderBy(x => x.GetDouble("Ecom:Product.Prices.Quantity")).FirstOrDefault(); 1279 1280 CultureInfo us = new CultureInfo("en-US"); 1281 string datalayerPriceInitial = string.Empty; 1282 if (priceInitial != null && Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 1283 { 1284 datalayerPriceInitial = priceInitial.GetDouble("Ecom:Product.Prices.Amount").ToString("n", us).Replace(",", ""); 1285 } 1286 1287 var pricesJs = new List<Dynamicweb.Ecommerce.LiveIntegration.Products.ProductPrice>(); 1288 foreach (var priceJs in prices) 1289 { 1290 var productPrice = new Dynamicweb.Ecommerce.LiveIntegration.Products.ProductPrice(); 1291 productPrice.BaseUnitPrice = priceJs.GetDouble("Ecom:Product.Prices.BaseUnitPrice"); 1292 productPrice.PriceQuantityPerUnit = priceJs.GetDouble("Ecom:Product.Prices.PriceQuantityPerUnit"); 1293 productPrice.Quantity = priceJs.GetDouble("Ecom:Product.Prices.Quantity"); 1294 productPrice.UnitId = priceJs.GetString("Ecom:Product.Prices.UnitID"); 1295 pricesJs.Add(productPrice); 1296 } 1297 } 1298 1299 @if (!String.IsNullOrWhiteSpace(GetString("Item.Page.ScriptsBottom"))) 1300 { 1301 @SnippetStart("JavaScriptBottom") 1302 @GetString("Item.Page.ScriptsBottom") 1303 @SnippetEnd("JavaScriptBottom") 1304 } 1305 1306 <script> 1307 var pricesJs = JSON.parse('@Newtonsoft.Json.JsonConvert.SerializeObject(pricesJs)'); 1308 1309 // Create our number formatter. 1310 var formatterUs = new Intl.NumberFormat('en-US', { 1311 minimumFractionDigits: 2, 1312 }); 1313 1314 1315 1316 1317 $('.product__addtocart-button').on('click', function () { 1318 1319 var quantityAdded = parseInt($(this).parent().prev().find('input.quantity').val()); 1320 var unitAdded = $(this).parent().prev().find('select.unit').val(); 1321 var priceFound = null; 1322 for (const key in pricesJs) { 1323 if (pricesJs[key].UnitId == unitAdded && quantityAdded >= parseInt(pricesJs[key].Quantity)){ 1324 priceFound = pricesJs[key]; 1325 } 1326 } 1327 1328 var priceAdded = 0; 1329 if (priceFound != null) { 1330 priceAdded = (priceFound.BaseUnitPrice * priceFound.PriceQuantityPerUnit) * quantityAdded; } 1331 1332 var quantity = document.getElementsByClassName("product__quantity-input")[0].value; 1333 var unitTypes = document.getElementsByClassName("unit-type"); 1334 var isVariantNull = true; 1335 1336 var index = 0; 1337 var unitPrice; 1338 var currentUnitName; 1339 for (const button of unitTypes){ 1340 1341 if (button.checked != false) 1342 { 1343 isVariantNull = false; 1344 var tempPrice = button.dataset.price.replace(".",""); 1345 tempPrice = tempPrice.replace(",","."); 1346 unitPrice = parseFloat(tempPrice); 1347 currentUnitName = button.value.split("_")[1]; 1348 index++; 1349 } 1350 } 1351 1352 if (!isVariantNull) 1353 { 1354 dataLayer.push({ecommerce:null}); 1355 dataLayer.push({ 1356 'event': 'add_to_cart', 1357 "ecommerce":{ 1358 "currency" : "@GetString("Ecom:Product.CurrencyCode")", 1359 "value" : unitPrice * (parseInt(quantity)).toFixed(2), 1360 "items":[ 1361 { 1362 "item_name": "@GetString("Ecom:Product.Name")" + " - " + currentUnitName, 1363 'item_id': '@GetString("Ecom:Product.ID")', 1364 'price': unitPrice, 1365 "item_brand" : "", 1366 "item_category": (categories[0] != null ? categories[0] : ""), 1367 "item_category2": (categories[1] != null ? categories[1] : ""), 1368 "item_category3": (categories[2] != null ? categories[2] : ""), 1369 "item_category4": (categories[3] != null ? categories[3] : ""), 1370 "item_category5": (categories[4] != null ? categories[4] : ""), 1371 "quantity": parseInt(quantity), 1372 } 1373 ] 1374 }, 1375 1376 }); 1377 } 1378 1379 }); 1380 1381 //Sets the unittype if only one unittype for the product exists 1382 var types = document.getElementsByClassName("unit-type"); 1383 var currentUnitName; 1384 var currentUnitPrice = 0; 1385 1386 if (types.length === 1){ 1387 currentUnitName = " - " + (types[0].value.split("_")[1]); 1388 var tempPrice = types[0].dataset.price; 1389 1390 tempPrice = tempPrice.replace(".",""); 1391 tempPrice = tempPrice.replace(",","."); 1392 currentUnitPrice = parseFloat(tempPrice); 1393 1394 } 1395 else{ 1396 currentUnitName = ""; 1397 } 1398 1399 1400 1401 var initialCategories = document.getElementsByClassName("page-header__title")[0].dataset.categories; 1402 var categories = initialCategories.split("_"); 1403 1404 1405 // View_item initial 1406 dataLayer.push({ecommerce:null}); 1407 dataLayer.push({ 1408 'event': 'view_item', 1409 "ecommerce":{ 1410 "currency" : "@GetString("Ecom:Product.CurrencyCode")", 1411 "value" : currentUnitPrice, 1412 "items":[ 1413 { 1414 "item_name": "@GetString("Ecom:Product.Name")" + currentUnitName, 1415 'item_id': '@GetString("Ecom:Product.ID")', 1416 'price': currentUnitPrice, 1417 "item_brand" : "", 1418 "item_category": (categories[0] != null ? categories[0] : ""), 1419 "item_category2": (categories[1] != null ? categories[1] : ""), 1420 "item_category3": (categories[2] != null ? categories[2] : ""), 1421 "item_category4": (categories[3] != null ? categories[3] : ""), 1422 "item_category5": (categories[4] != null ? categories[4] : ""), 1423 "quantity": 1, 1424 1425 } 1426 ] 1427 }, 1428 1429 }); 1430 1431 var unitTypes = document.getElementsByClassName("unit-type"); 1432 1433 var price; 1434 var oldPrice; 1435 1436 for (const btn of unitTypes) 1437 { 1438 btn.addEventListener("click", function () { 1439 1440 1441 tempPrice = this.dataset.price.replace(".",""); 1442 tempPrice = tempPrice.replace(",","."); 1443 price = parseFloat(tempPrice); 1444 1445 currentUnitName = btn.value.split("_")[1]; 1446 1447 //checks to see if the new variant is the same as the old one 1448 if (price != oldPrice){ 1449 1450 dataLayer.push({ecommerce:null}); 1451 dataLayer.push({ 1452 'event': 'view_item', 1453 "ecommerce":{ 1454 "currency" : "@GetString("Ecom:Product.CurrencyCode")", 1455 "value" : currentUnitPrice, 1456 "items":[ 1457 { 1458 "item_name": "@GetString("Ecom:Product.Name")" + currentUnitName, 1459 'item_id': '@GetString("Ecom:Product.ID")', 1460 'price': currentUnitPrice, 1461 "item_brand" : "", 1462 "item_category": (categories[0] != null ? categories[0] : ""), 1463 "item_category2": (categories[1] != null ? categories[1] : ""), 1464 "item_category3": (categories[2] != null ? categories[2] : ""), 1465 "item_category4": (categories[3] != null ? categories[3] : ""), 1466 "item_category5": (categories[4] != null ? categories[4] : ""), 1467 "quantity": 1, 1468 1469 } 1470 ] 1471 }, 1472 1473 }); 1474 1475 } 1476 oldPrice = price; 1477 }) 1478 } 1479 1480 </script> 1481 1482 @SnippetStart("JavaScriptBottom") 1483 <script type="text/javascript" src="~/Files/Templates/Designs/Dwsimple/js/video-api.js"></script> 1484 1485 @if (currentUser != null) 1486 { 1487 <script type="text/javascript" src="~/Files/Templates/Designs/Dwsimple/js/clerk.js"></script> 1488 } 1489 1490 <script> 1491 function on() { 1492 document.getElementById("overlay").style.display = "block"; 1493 callPlayer('product-video', 'playVideo'); 1494 } 1495 function off() { 1496 document.getElementById("overlay").style.display = "none"; 1497 callPlayer('product-video', 'pauseVideo'); 1498 } 1499 function updateDetailAccessibility(button) 1500 { 1501 1502 var content = document.getElementsByClassName("product__details__content")[0]; 1503 1504 var defaultHeight = "75px"; 1505 1506 if (content.style.maxHeight == defaultHeight) 1507 { 1508 content.style.maxHeight = content.scrollHeight + "px"; 1509 button.innerText = '@Translate("ReadLess")' 1510 } 1511 else { 1512 content.style.maxHeight = defaultHeight; 1513 button.innerText = '@Translate("ReadMore")' 1514 } 1515 1516 1517 } 1518 </script> 1519 1520 @SnippetEnd("JavaScriptBottom") 1521 1522 @functions { 1523 1524 public static string StripHTML(string input) 1525 { 1526 var doc = new HtmlDocument(); 1527 doc.LoadHtml(input); 1528 return doc.DocumentNode.InnerText; 1529 } 1530 1531 } 1532 1533 1534 <style> 1535 1536 .product__details { 1537 position: relative; 1538 p { 1539 margin: 0; 1540 width: fit-content; 1541 } 1542 a:hover{ 1543 cursor: pointer; 1544 } 1545 1546 .product__details__content { 1547 1548 1549 overflow: hidden; 1550 transition: max-height 0.3s ease; 1551 } 1552 1553 } 1554 1555 1556 </style>