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_005b3bf959dc4f18a8c95214568309a6.Execute() in D:\web\hounisen\Hounisen.Website\Files\Templates\Designs\Dwsimple\eCom\Product\Product.cshtml:line 733
   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 HtmlAgilityPack 14 @using VestjyskMarketing.Models; 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 else 687 { 688 metaDescription = StripHTML(GetString("Ecom:Product.LongDescription")); 689 } 690 691 //prices and units 692 string defaultUnitId = GetString("Ecom:Product.DefaultUnitID"); 693 var prices = GetLoop("Product.Prices"); 694 List<string> pricesHtmlList = Hounisen.Website.Helpers.Helpers.PricesListMakeListString(prices, false); 695 List<Hounisen.Website.Models.Unit> unitsDropdown = Hounisen.Website.Helpers.Helpers.PopulateUnitsDropdown(prices); 696 var unitDefault = unitsDropdown.Where(x => x.Id.Equals(defaultUnitId)).FirstOrDefault(); 697 int minOrder = unitDefault != null ? unitDefault.MinOrder : 1; 698 699 700 //other vars 701 var pid = GetString("Ecom:Product.ID"); 702 int stock = GetInteger("Ecom:Product.Stock"); 703 string image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + pid + ".jpg"; 704 string productname = GetString("Ecom:Product.Name"); 705 string productlink = "/Default.aspx?ID=" + GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + GetString("Ecom:Product.ID"); 706 707 708 // SKI AND Region H 709 bool hasSkiDeal = false; 710 bool hasRegionHDeal = false; 711 var currentUser = User.GetCurrentExtranetUser(); 712 if (currentUser != null) 713 { 714 var skiGroup = currentUser.Groups.FirstOrDefault(e => e.Name == "SKI"); 715 if (skiGroup != null && !string.IsNullOrEmpty(skiGroup.Name)) 716 { 717 hasSkiDeal = true; 718 } 719 720 hasRegionHDeal = Dynamicweb.Core.Converter.ToBoolean(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_RegionH").Value); 721 } 722 723 //serialized data 724 var pagedata = new System.Collections.Generic.Dictionary<String, Object>(); 725 Pageview.Area.Item.SerializeTo(pagedata); 726 727 728 var pageService = new PageService(); 729 GroupHelper gh = new GroupHelper(); 730 var group = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(GetString("Ecom:Product.PrimaryOrFirstGroupID")); 731 var masterPage = pageService.GetPage(GetInteger("Ecom:Product.PrimaryOrCurrentPageID")); 732 masterPage.GetDisplayName(); 733 var groupNames = gh.GetParentsRecursively(group, new List<string>()); 734 groupNames = gh.Format(groupNames, masterPage.GetDisplayName(), group); 735 736 var groups = gh.ListToString(groupNames); 737 } 738 739 <div class="col-md-12 col-sm-12 col-xs-12 aaa"> 740 741 <div class="row product" itemscope itemtype="http://schema.org/Product"> 742 <section class="page-header"> 743 <div class="row product__help-name-container"> 744 <div class="col-xs-12 col-sm-7"> 745 <meta itemprop="description" content="@metaDescription"/> 746 <h1 data-categories="@groups" data-group="@GetString("Ecom:Group.Name")" class="page-header__title" itemprop="name">@GetString("Ecom:Product.Name")</h1> 747 <div class="page-header__short-description"> 748 <p class="product__number">@Translate("Productnumber", "Productnumber"): <span property="identifier" itemprop="mpn">@GetString("Ecom:Product.Number")</span></p> 749 @if (hasSkiDeal) 750 { 751 <p class="product__number">@Translate("Skinumber", "SKI nr"): <span property="identifier">@GetString("Ecom:Product:Field.SkiId")</span></p> 752 } 753 @if (hasRegionHDeal && GetBoolean("Ecom:Product:Field.RegionH")) 754 { 755 <p class="product__number">@Translate("RegionHText")</p> 756 } 757 758 </div> 759 </div> 760 <div class="col-xs-12 col-sm-offset-1 col-sm-4 product__help-name-container__help"> 761 <div class="need-help"> 762 <img class="need-help__image lazy" width="81" height="81" data-src='@(Pageview.Area.Item["Support_Image"].ToString())?format=webp&width=81&quality=75'/> 763 <div class="need-help__text"> 764 @Pageview.Area.Item["Support_Content"].ToString() 765 </div> 766 </div> 767 </div> 768 </div> 769 </section> 770 <div class="row"> 771 772 @* The image area *@ 773 <div class="col-md-5 col-sm-4 col-xs-12"> 774 <div class="product__gallery"> 775 776 @* Discount sticker *@ 777 778 @if (GetString("Ecom:Product.Discount.Price.PriceWithVATFormatted") != GetString("Ecom:Product.Price.PriceWithVATFormatted")) 779 { 780 if (pagedata["EcommerceStickerType"].ToString() == "ribbon") 781 { 782 <span class="ribbon base">@Translate("On sale!", "On sale!")</span> 783 } 784 785 if (pagedata["EcommerceStickerType"].ToString() == "ball") 786 { 787 <span class="ball">@Translate("On sale!", "On sale!")</span> 788 } 789 } 790 791 792 @* Product images *@ 793 @{ 794 string currenthost = HttpContext.Current.Request.Url.AbsoluteUri; 795 Uri uri = new Uri(currenthost); 796 currenthost = string.Format("{0}://{1}", uri.Scheme, uri.Authority); 797 string ImagePathloop = ""; 798 string ImagePathClean = ""; 799 string options = "format=webp&quality=85&width=1000"; 800 List<string> imagepath = new List<string>(); 801 for (int i = 0; i <= 4; i++) 802 { 803 if (i == 0) 804 { 805 ImagePathloop = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings() 806 { 807 Image = $"/Files/Images/Ecom/Products/{pid}.jpg", 808 Width = 1000, 809 Quality = 85 810 }); 811 imagepath.Add(ImagePathloop); 812 } 813 else 814 { 815 ImagePathloop = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg"; 816 //currenthost + 817 ImagePathClean = "/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg"; 818 819 try 820 { 821 if (File.Exists(HttpContext.Current.Server.MapPath(ImagePathClean))) 822 { 823 imagepath.Add(ImagePathloop + "&" + options); 824 } 825 826 827 HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(ImagePathloop); 828 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 829 { 830 if (response.StatusCode == HttpStatusCode.NotFound) 831 { 832 break; 833 } 834 else 835 { 836 imagepath.Add("/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg" + "" + options); 837 } 838 } 839 } 840 catch (Exception ex) 841 { 842 } 843 } 844 } 845 } 846 847 @{ 848 var resizedImageLarge = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings() 849 { 850 Image = $"/Files/Images/Ecom/Products/{pid}.jpg", 851 Width = 1000, 852 Quality = 99 853 }); 854 855 var resizedImage = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings() 856 { 857 Image = $"/Files/Images/Ecom/Products/{pid}.jpg", 858 Width = 458, 859 Quality = 85 860 }); 861 } 862 863 <div class="product__primary-image"> 864 <a href="@resizedImageLarge" data-fancybox class="fancybox"> 865 <img src="@resizedImage" data-src="@resizedImage" width="458" alt="@productname" class="product__image img-responsive lazy" itemprop="image"> 866 @{ 867 var productObj = new ProductService().GetProductById(GetString("Ecom:Product.ID"),GetString("Ecom:Product.VariantID"),GetString("Ecom:Product.LanguageID")); 868 var overlayNameAndColors = new ProductImageOverlayHelper().GetTextAndColor(productObj); 869 } 870 871 <div class="product__primary-image__overlay-container"> 872 @foreach (var overlayNameAndColor in overlayNameAndColors) 873 { 874 <div style="background-color: @overlayNameAndColor.Value" class="product__primary-image__overlay-container__item"> 875 @overlayNameAndColor.Key 876 </div> 877 } 878 </div> 879 <svg class="product__image-icon"> 880 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#fullscreen"></use> 881 </svg> 882 </a> 883 </div> 884 <div class="row"> 885 <div class="product__thumbnail-list"> 886 @foreach (var imageThumb in imagepath) 887 { 888 <div class="col-sm-3 col-xs-4"> 889 <div class="product__thumbnail-images"> 890 <a href="@imageThumb&width=1000" rel="product" class="fancybox"> 891 <img data-src="@imageThumb&width=458" width="458" alt="@productname" class="img-responsive lazy"> 892 </a> 893 </div> 894 </div> 895 } 896 @{ 897 var youtubeId = GetString("Ecom:Product:Field.YoutubeId"); 898 var youtubeUrl = $"//www.youtube.com/embed/{youtubeId}?autoplay=0"; 899 if (!string.IsNullOrEmpty(youtubeId)) 900 { 901 <div class="col-sm-3 col-xs-4"> 902 <div id="video-container" class="product__thumbnail-list__video-thumbnail" onclick="on(); return false;"> 903 <iframe width="100%" height="70" src="@youtubeUrl" frameborder="0"></iframe> 904 <div class="product__thumbnail-list__video-thumbnail__video"></div> 905 </div> 906 <div id="overlay" class="product__thumbnail-list__overlay" onclick="off()"> 907 <iframe class="product__thumbnail-list__overlay__video" id="product-video" width="100%" height="80%" src="@youtubeUrl?autoplay=1&enablejsapi=1" frameborder="0"></iframe> 908 </div> 909 </div> 910 } 911 } 912 </div> 913 </div> 914 </div> 915 </div> 916 917 @* The main product information area *@ 918 919 <div class="col-md-7 col-sm-8 col-xs-12 "> 920 <div class="product-info js-product-info" id="productinfo"> 921 <div class="product__control"> 922 <div class="row"> 923 <div class="col-xs-12 col-sm-6"> 924 @* LAGERBEHOLDNING *@ 925 <div class="product__stock"> 926 @{ 927 if (stock > 0) 928 { 929 <p class="product__stock-text"> 930 <span class="product__stock-circle product__stock-circle--green"></span> På lager 931 </p> 932 } 933 else 934 { 935 <p class="product__stock-text"> 936 <span class="product__stock-circle product__stock-circle--yellow"></span> Kontakt os for leveringstid: 86210800 eller salg@hounisen.com 937 </p> 938 } 939 } 940 </div> 941 </div> 942 <div class="col-xs-12 col-sm-6"> 943 @* FAVORITTER *@ 944 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 945 { 946 if (hasRegionHDeal == false) 947 { 948 <div class="product__favorite-list popup-wrap favorite"> 949 <button class="popup-show" data-popup="favorite-list" type="button" title="@Translate("Add to favorites", "Add to favorites")"> 950 <i class="fa fa-star-o"></i> <span>@Translate("Add to favorites", "Add to favorites")</span> 951 </button> 952 <div id="favorite-list" class="popup-form"> 953 <div class="close"> 954 <i class="fa fa-times"></i> 955 </div> 956 <h3>@Translate("Choose list", "Choose list")</h3> 957 <ul> 958 @{ 959 var lists = Dynamicweb.Ecommerce.CustomerCenter.CustomerProductList.GetListsByUserCustomerNumber(currentUser.CustomerNumber); 960 } 961 962 @foreach (var list in lists) 963 { 964 if (list.Products.Where(p => p.ProductId.ToString() == GetString("Ecom:Product.ID")).Count() > 0) 965 { 966 <li> 967 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCRemoveFromMyLists=@GetString("Ecom:Product.ID")&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType="> 968 <i class="fa fa-star"></i> @list.Name 969 </a> 970 </li> 971 } 972 else 973 { 974 <li> 975 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCAddToMyLists=@GetString("Ecom:Product.ID")&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType="> 976 <i class="fa fa-star-o"></i> @list.Name 977 </a> 978 </li> 979 } 980 } 981 <li> 982 <a href="/favoritter/opret-favoritliste?ProdID=@GetString("Ecom:Product.ID")"> 983 <i class="fa fa-plus"></i>@Translate("Add new list", "Add new list") 984 </a> 985 </li> 986 </ul> 987 </div> 988 </div> 989 } 990 } 991 else 992 { 993 <div class="not-loggedin"> 994 <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> 995 <a data-toggle="modal" data-target="#login" href="" class="btn btn-primary not-loggedin-button"> 996 <span>Log ind</span> 997 </a> 998 </div> 999 } 1000 </div> 1001 </div> 1002 1003 1004 @* Prices and actions *@ 1005 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 1006 { 1007 var product = GetString("Ecom:Product.ID"); 1008 if (!string.IsNullOrWhiteSpace(GetString("Ecom:Product.SelectedVariantComboID"))) 1009 { 1010 product = GetString("Ecom:Product.ID") + "&" + GetString("Ecom:Product.SelectedVariantComboID"); 1011 } 1012 1013 <div class="row"> 1014 <div class="col-xs-12"> 1015 <ul class="product__prices"> 1016 @foreach (var priceHtml in pricesHtmlList) 1017 { 1018 <li> 1019 @priceHtml 1020 </li> 1021 } 1022 </ul> 1023 </div> 1024 </div> 1025 1026 <div class="row"> 1027 <div class="col-xs-7"> 1028 <div class="product__addtocart-input js-addtocart-input"> 1029 <input type="button" value="-" class="product__quantity-button product__quantity-button--minus qtyminus" field="quantity"/> 1030 <input type="number" class="product__quantity-input quantity" data-name="quantity" name="quantity" value="@minOrder" field="quantity"/> 1031 <input type="button" value="+" class="product__quantity-button product__quantity-button--plus qtyplus" field="quantity"/> 1032 </div> 1033 <div class="product__unit-selector" style="display: inline-block;"> 1034 1035 @{ 1036 var index = 0; 1037 } 1038 1039 @foreach (var unitDropdown in unitsDropdown) 1040 { 1041 index++; 1042 var currentUnitPrice = prices[index - 1].Values["Ecom:Product.Prices.Amount"]; 1043 <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'" : "")> 1044 <label for="@unitDropdown.Id">@unitDropdown.Name</label> 1045 } 1046 </div> 1047 <p class="product__unit-selector-error-message"> 1048 * Du mangler at vælge type 1049 </p> 1050 </div> 1051 <div class="col-xs-5"> 1052 <div class="product__addtocart-button"> 1053 <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"> 1054 @Translate("Add to cart", "Add to cart") 1055 <svg class="product__button-icon hidden-xs"> 1056 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#basket"></use> 1057 </svg> 1058 </button> 1059 </div> 1060 </div> 1061 </div> 1062 } 1063 </div> 1064 1065 @* Product details *@ 1066 <div> 1067 1068 @* BESKRIVELSE *@ 1069 @*PRODUCT Long*@ 1070 <div class="product__description"> 1071 <p> 1072 @{ 1073 string productDescrption = null; 1074 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.Teaser"))) 1075 { 1076 productDescrption = GetString("Ecom:Product:Field.Teaser"); 1077 <div> 1078 @if (GetString("Ecom:Product.LongDescription").Length > 150) 1079 { 1080 productDescrption = productDescrption + "..."; 1081 <p class="product__description__long"> 1082 @productDescrption 1083 </p> 1084 <p> 1085 <a href="#productLongDescriptionID" id="js-smooth-scroll" class="js-smooth-scroll">@Translate("ReadMore", "Læs mere")</a> 1086 </p> 1087 } 1088 else 1089 { 1090 <p class="product__description__long"> 1091 @productDescrption 1092 </p> 1093 } 1094 </div> 1095 } 1096 else if (String.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && String.IsNullOrEmpty(GetString("Ecom:Product:Field.Teaser"))) 1097 { 1098 productDescrption = GetString("Ecom:Group.Description"); 1099 @productDescrption 1100 } 1101 else 1102 { 1103 productDescrption = StripHTML(GetString("Ecom:Product.LongDescription").ToString()); 1104 if (productDescrption.Length > 150) 1105 { 1106 productDescrption = productDescrption.Substring(0, 150) + "..."; 1107 1108 <p class="product__description__long"> 1109 @productDescrption 1110 1111 </p> 1112 <p> 1113 <a href="#productLongDescriptionID" id="js-smooth-scroll" class="js-smooth-scroll">@Translate("ReadMore", "Læs mere")</a> 1114 </p> 1115 } 1116 else 1117 { 1118 productDescrption = GetString("Ecom:Product.LongDescription"); 1119 <p class="product__description__long"> 1120 @productDescrption 1121 </p> 1122 } 1123 } 1124 } 1125 1126 </p> 1127 1128 </div> 1129 1130 @* ATTRIBUTTER *@ 1131 <div class="product__information"> 1132 <h3>Specifikationer</h3> 1133 <dl class="product__information-table"> 1134 @{ 1135 int attributeLineCount = 0; 1136 for (int i = 1; i < 8; i++) 1137 { 1138 attributeLineCount++; 1139 string attributeName = "Ecom:Product:Field.Attribut" + attributeLineCount + "A"; 1140 string attributeValue = "Ecom:Product:Field.Attribut" + attributeLineCount + "B"; 1141 string attributeBrand = string.Empty; 1142 1143 if (GetString(attributeName) != "") 1144 { 1145 if (attributeLineCount == 7) 1146 { 1147 attributeBrand = "itemprop=\"brand\""; 1148 } 1149 1150 <dt>@GetString(attributeName) :</dt> 1151 <dd @attributeBrand>@GetString(attributeValue)</dd> 1152 } 1153 } 1154 } 1155 </dl> 1156 </div> 1157 1158 @* IKONER *@ 1159 <div class="product__icons"> 1160 @{ 1161 foreach (var c in GetString("Ecom:Product:Field.Certificates").Split(',')) 1162 { 1163 if (!string.IsNullOrEmpty(c)) 1164 { 1165 <img class="product__icon lazy" data-src="/Files/Images/Ecom/certificates/@(c).jpg" title="@Translate("Cert_" + c, c)"/> 1166 } 1167 } 1168 } 1169 </div> 1170 1171 1172 @* DOWNLOAD *@ 1173 1174 @if (GetString("Ecom:Product:Field.Link1Label") != "") 1175 { 1176 <div> 1177 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link1File.Clean")" class="">@GetString("Ecom:Product:Field.Link1Label")</a> 1178 </div> 1179 } 1180 @if (GetString("Ecom:Product:Field.Link2Label") != "") 1181 { 1182 <div> 1183 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link2File.Clean")" class="">@GetString("Ecom:Product:Field.Link2Label")</a> 1184 </div> 1185 } 1186 @if (GetString("Ecom:Product:Field.Link3Label") != "") 1187 { 1188 <div> 1189 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link3File.Clean")" class="">@GetString("Ecom:Product:Field.Link3Label")</a> 1190 </div> 1191 } 1192 @if (GetString("Ecom:Product:Field.Link4Label") != "") 1193 { 1194 <div> 1195 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link4File.Clean")" class="">@GetString("Ecom:Product:Field.Link4Label")</a> 1196 </div> 1197 } 1198 @if (GetString("Ecom:Product:Field.Link5Label") != "") 1199 { 1200 <div> 1201 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link5File.Clean")" class="">@GetString("Ecom:Product:Field.Link5Label")</a> 1202 </div> 1203 } 1204 1205 1206 </div> 1207 </div> 1208 </div> 1209 </div> 1210 </div> 1211 </div> 1212 1213 @* Related products *@ 1214 1215 @if (GetString("Ecom:Product.RelatedCount") != "0") 1216 { 1217 <div class="row"> 1218 <div class="col-xs-12"> 1219 <h3 class="section-header shop-list__header">Relaterede varer</h3> 1220 <ul class="shop-list__list"> 1221 @foreach (LoopItem relatedgroup in GetLoop("ProductRelatedGroups")) 1222 { 1223 var relatedproductloop = relatedgroup.GetLoop("RelatedProducts").OrderByDescending(g => g.GetString("Ecom:Product.LoopCounter")).Take(4).ToList(); 1224 @GetProductListFullRelated(relatedproductloop, 3, 3, 1) 1225 } 1226 </ul> 1227 </div> 1228 </div> 1229 } 1230 1231 @if (!String.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")) && StripHTML(GetString("Ecom:Product.LongDescription").ToString()).Length > 150) 1232 { 1233 <div class="row"> 1234 <div class="col-xs-12"> 1235 <h3 id="productLongDescriptionID" class="product__description-title">@Translate("Description", "Description")</h3> 1236 </div> 1237 <div class="col-xs-12 py-4"> 1238 <div style="display: block; margin-bottom: 15px;"> 1239 <div class="product__details"> 1240 @{ 1241 var description = GetString("Ecom:Product.LongDescription"); 1242 1243 // Remove HTML tags 1244 string cleanedText = Regex.Replace(description, "<.*?>", " "); 1245 string[] words = cleanedText.Split(new[] { ' ', '\n', '\r', '\t' }, StringSplitOptions.RemoveEmptyEntries); 1246 bool readMoreButton = words.Length > 80; 1247 } 1248 @if (readMoreButton) 1249 { 1250 <div class="product__details__content" style="max-height: 75px;"> 1251 @description 1252 </div> 1253 <a onclick="updateDetailAccessibility(this)">@Translate("Læs mere")</a> 1254 } 1255 else 1256 { 1257 @description 1258 } 1259 </div> 1260 </div> 1261 </div> 1262 </div> 1263 } 1264 1265 <span class="clerk" 1266 data-template="@@product-page-others-also-bought" 1267 data-products='["@GetString("Ecom:Product.ID")"]'> 1268 </span> 1269 1270 1271 <div class="row"> 1272 <div class="col-md-12 col-sm-12 col-xs-12">&nbsp;</div> 1273 </div> 1274 1275 @{ 1276 var priceInitial = prices.Where(x => x.GetString("Ecom:Product.Prices.UnitID").Equals(unitDefault.Id)).OrderBy(x => x.GetDouble("Ecom:Product.Prices.Quantity")).FirstOrDefault(); 1277 1278 CultureInfo us = new CultureInfo("en-US"); 1279 string datalayerPriceInitial = string.Empty; 1280 if (priceInitial != null && Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 1281 { 1282 datalayerPriceInitial = priceInitial.GetDouble("Ecom:Product.Prices.Amount").ToString("n", us).Replace(",", ""); 1283 } 1284 1285 var pricesJs = new List<Dynamicweb.Ecommerce.LiveIntegration.Products.ProductPrice>(); 1286 foreach (var priceJs in prices) 1287 { 1288 var productPrice = new Dynamicweb.Ecommerce.LiveIntegration.Products.ProductPrice(); 1289 productPrice.BaseUnitPrice = priceJs.GetDouble("Ecom:Product.Prices.BaseUnitPrice"); 1290 productPrice.PriceQuantityPerUnit = priceJs.GetDouble("Ecom:Product.Prices.PriceQuantityPerUnit"); 1291 productPrice.Quantity = priceJs.GetDouble("Ecom:Product.Prices.Quantity"); 1292 productPrice.UnitId = priceJs.GetString("Ecom:Product.Prices.UnitID"); 1293 pricesJs.Add(productPrice); 1294 } 1295 } 1296 1297 @if (!String.IsNullOrWhiteSpace(GetString("Item.Page.ScriptsBottom"))) 1298 { 1299 @SnippetStart("JavaScriptBottom") 1300 @GetString("Item.Page.ScriptsBottom") 1301 @SnippetEnd("JavaScriptBottom") 1302 } 1303 1304 <script> 1305 var pricesJs = JSON.parse('@Newtonsoft.Json.JsonConvert.SerializeObject(pricesJs)'); 1306 1307 // Create our number formatter. 1308 var formatterUs = new Intl.NumberFormat('en-US', { 1309 minimumFractionDigits: 2, 1310 }); 1311 1312 1313 1314 1315 $('.product__addtocart-button').on('click', function () { 1316 1317 var quantityAdded = parseInt($(this).parent().prev().find('input.quantity').val()); 1318 var unitAdded = $(this).parent().prev().find('select.unit').val(); 1319 var priceFound = null; 1320 for (const key in pricesJs) { 1321 if (pricesJs[key].UnitId == unitAdded && quantityAdded >= parseInt(pricesJs[key].Quantity)){ 1322 priceFound = pricesJs[key]; 1323 } 1324 } 1325 1326 var priceAdded = 0; 1327 if (priceFound != null) { 1328 priceAdded = (priceFound.BaseUnitPrice * priceFound.PriceQuantityPerUnit) * quantityAdded; } 1329 1330 var quantity = document.getElementsByClassName("product__quantity-input")[0].value; 1331 var unitTypes = document.getElementsByClassName("unit-type"); 1332 var isVariantNull = true; 1333 1334 var index = 0; 1335 var unitPrice; 1336 var currentUnitName; 1337 for (const button of unitTypes){ 1338 1339 if (button.checked != false) 1340 { 1341 isVariantNull = false; 1342 var tempPrice = button.dataset.price.replace(".",""); 1343 tempPrice = tempPrice.replace(",","."); 1344 unitPrice = parseFloat(tempPrice); 1345 currentUnitName = button.value.split("_")[1]; 1346 index++; 1347 } 1348 } 1349 1350 if (!isVariantNull) 1351 { 1352 dataLayer.push({ecommerce:null}); 1353 dataLayer.push({ 1354 'event': 'add_to_cart', 1355 "ecommerce":{ 1356 "currency" : "@GetString("Ecom:Product.CurrencyCode")", 1357 "value" : unitPrice * (parseInt(quantity)).toFixed(2), 1358 "items":[ 1359 { 1360 "item_name": "@GetString("Ecom:Product.Name")" + " - " + currentUnitName, 1361 'item_id': '@GetString("Ecom:Product.ID")', 1362 'price': unitPrice, 1363 "item_brand" : "", 1364 "item_category": (categories[0] != null ? categories[0] : ""), 1365 "item_category2": (categories[1] != null ? categories[1] : ""), 1366 "item_category3": (categories[2] != null ? categories[2] : ""), 1367 "item_category4": (categories[3] != null ? categories[3] : ""), 1368 "item_category5": (categories[4] != null ? categories[4] : ""), 1369 "quantity": parseInt(quantity), 1370 } 1371 ] 1372 }, 1373 1374 }); 1375 } 1376 1377 }); 1378 1379 //Sets the unittype if only one unittype for the product exists 1380 var types = document.getElementsByClassName("unit-type"); 1381 var currentUnitName; 1382 var currentUnitPrice = 0; 1383 1384 if (types.length === 1){ 1385 currentUnitName = " - " + (types[0].value.split("_")[1]); 1386 var tempPrice = types[0].dataset.price; 1387 1388 tempPrice = tempPrice.replace(".",""); 1389 tempPrice = tempPrice.replace(",","."); 1390 currentUnitPrice = parseFloat(tempPrice); 1391 1392 } 1393 else{ 1394 currentUnitName = ""; 1395 } 1396 1397 1398 1399 var initialCategories = document.getElementsByClassName("page-header__title")[0].dataset.categories; 1400 var categories = initialCategories.split("_"); 1401 1402 1403 // View_item initial 1404 dataLayer.push({ecommerce:null}); 1405 dataLayer.push({ 1406 'event': 'view_item', 1407 "ecommerce":{ 1408 "currency" : "@GetString("Ecom:Product.CurrencyCode")", 1409 "value" : currentUnitPrice, 1410 "items":[ 1411 { 1412 "item_name": "@GetString("Ecom:Product.Name")" + currentUnitName, 1413 'item_id': '@GetString("Ecom:Product.ID")', 1414 'price': currentUnitPrice, 1415 "item_brand" : "", 1416 "item_category": (categories[0] != null ? categories[0] : ""), 1417 "item_category2": (categories[1] != null ? categories[1] : ""), 1418 "item_category3": (categories[2] != null ? categories[2] : ""), 1419 "item_category4": (categories[3] != null ? categories[3] : ""), 1420 "item_category5": (categories[4] != null ? categories[4] : ""), 1421 "quantity": 1, 1422 1423 } 1424 ] 1425 }, 1426 1427 }); 1428 1429 var unitTypes = document.getElementsByClassName("unit-type"); 1430 1431 var price; 1432 var oldPrice; 1433 1434 for (const btn of unitTypes) 1435 { 1436 btn.addEventListener("click", function () { 1437 1438 1439 tempPrice = this.dataset.price.replace(".",""); 1440 tempPrice = tempPrice.replace(",","."); 1441 price = parseFloat(tempPrice); 1442 1443 currentUnitName = btn.value.split("_")[1]; 1444 1445 //checks to see if the new variant is the same as the old one 1446 if (price != oldPrice){ 1447 1448 dataLayer.push({ecommerce:null}); 1449 dataLayer.push({ 1450 'event': 'view_item', 1451 "ecommerce":{ 1452 "currency" : "@GetString("Ecom:Product.CurrencyCode")", 1453 "value" : currentUnitPrice, 1454 "items":[ 1455 { 1456 "item_name": "@GetString("Ecom:Product.Name")" + currentUnitName, 1457 'item_id': '@GetString("Ecom:Product.ID")', 1458 'price': currentUnitPrice, 1459 "item_brand" : "", 1460 "item_category": (categories[0] != null ? categories[0] : ""), 1461 "item_category2": (categories[1] != null ? categories[1] : ""), 1462 "item_category3": (categories[2] != null ? categories[2] : ""), 1463 "item_category4": (categories[3] != null ? categories[3] : ""), 1464 "item_category5": (categories[4] != null ? categories[4] : ""), 1465 "quantity": 1, 1466 1467 } 1468 ] 1469 }, 1470 1471 }); 1472 1473 } 1474 oldPrice = price; 1475 }) 1476 } 1477 1478 </script> 1479 1480 @SnippetStart("JavaScriptBottom") 1481 <script type="text/javascript" src="~/Files/Templates/Designs/Dwsimple/js/video-api.js"></script> 1482 1483 @if (currentUser != null) 1484 { 1485 <script type="text/javascript" src="~/Files/Templates/Designs/Dwsimple/js/clerk.js"></script> 1486 } 1487 1488 <script> 1489 function on() { 1490 document.getElementById("overlay").style.display = "block"; 1491 callPlayer('product-video', 'playVideo'); 1492 } 1493 function off() { 1494 document.getElementById("overlay").style.display = "none"; 1495 callPlayer('product-video', 'pauseVideo'); 1496 } 1497 function updateDetailAccessibility(button) 1498 { 1499 1500 var content = document.getElementsByClassName("product__details__content")[0]; 1501 1502 var defaultHeight = "75px"; 1503 1504 if (content.style.maxHeight == defaultHeight) 1505 { 1506 content.style.maxHeight = content.scrollHeight + "px"; 1507 button.innerText = '@Translate("ReadLess")' 1508 } 1509 else { 1510 content.style.maxHeight = defaultHeight; 1511 button.innerText = '@Translate("ReadMore")' 1512 } 1513 1514 1515 } 1516 </script> 1517 1518 @SnippetEnd("JavaScriptBottom") 1519 1520 @functions { 1521 1522 public static string StripHTML(string input) 1523 { 1524 var doc = new HtmlDocument(); 1525 doc.LoadHtml(input); 1526 return doc.DocumentNode.InnerText; 1527 } 1528 1529 } 1530 1531 1532 <style> 1533 1534 .product__details { 1535 position: relative; 1536 p { 1537 margin: 0; 1538 width: fit-content; 1539 } 1540 a:hover{ 1541 cursor: pointer; 1542 } 1543 1544 .product__details__content { 1545 1546 1547 overflow: hidden; 1548 transition: max-height 0.3s ease; 1549 } 1550 1551 } 1552 1553 1554 </style>