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_1aa1eee2506949ddabc6e9aad38bf16f.Execute() in D:\web\hounisen\Hounisen.Website\Files\Templates\Designs\Dwsimple\eCom\Product\Product.cshtml:line 790
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 bool activateLimitedProducts = false;
178 string limitedProductNumbers = "";
179 var currentUser = User.GetCurrentExtranetUser();
180 if (currentUser != null)
181 {
182 var skiGroup = currentUser.Groups.FirstOrDefault(e => e.Name == "SKI");
183 if (skiGroup != null && !string.IsNullOrEmpty(skiGroup.Name))
184 {
185 hasSkiDeal = true;
186 }
187
188 hasRegionHDeal = Dynamicweb.Core.Converter.ToBoolean(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_RegionH").Value);
189 activateLimitedProducts = Dynamicweb.Core.Converter.ToBoolean(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_ActivateLimitedProducts").Value);
190 limitedProductNumbers = Dynamicweb.Core.Converter.ToString(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_LimitedProductNumbers").Value);
191 }
192
193 List<string> limitedProductNumbersList = new List<string>();
194 if (!String.IsNullOrWhiteSpace(limitedProductNumbers) && activateLimitedProducts)
195 {
196 limitedProductNumbersList = limitedProductNumbers.Split(',').ToList();
197 }
198
199
200 foreach (LoopItem product in Loop)
201 {
202 string GroupLink = "/Default.aspx?ID=" + product.GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + product.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + product.GetString("Ecom:Product.ID");
203 // string GroupLink = product.GetString("Ecom:Product.LinkGroup.Clean");
204 int stock = product.GetInteger("Ecom:Product.Stock");
205 string Name = product.GetString("Ecom:Product.Name");
206 string Description = product.GetString("Ecom:Product.ShortDescription");
207 string prodID = product.GetString("Ecom:Product.ID");
208 string prodVariantID = product.GetString("Ecom:Product.VariantID");
209 string prodLanguageID = product.GetString("Ecom:Product.LanguageID");
210 string Image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + prodID + ".jpg&format=webp&quality=85";
211
212 //prices and units
213 string defaultUnitId = product.GetString("Ecom:Product.DefaultUnitID");
214 var prices = product.GetLoop("Product.Prices");
215 List<string> pricesHtmlList = Hounisen.Website.Helpers.Helpers.PricesListMakeListString(prices);
216 List<Hounisen.Website.Models.Unit> unitsDropdown = Hounisen.Website.Helpers.Helpers.PopulateUnitsDropdown(prices);
217 var unitDefault = unitsDropdown.Where(x => x.Id.Equals(defaultUnitId)).FirstOrDefault();
218 int minOrder = unitDefault != null ? unitDefault.MinOrder : 1;
219
220 if (!string.IsNullOrWhiteSpace(product.GetString("Ecom:Product.SelectedVariantComboID")))
221 {
222 prodID = product.GetString("Ecom:Product.ID") + "&" + product.GetString("Ecom:Product.SelectedVariantComboID");
223 }
224
225
226 GroupHelper gh = new GroupHelper();
227 var masterPage = pageService.GetPage(product.GetInteger("Ecom:Product.PrimaryOrCurrentPageID"));
228 masterPage.GetDisplayName();
229
230 var group = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(product.GetString("Ecom:Product.PrimaryOrFirstGroupID"));
231 var groups = "";
232 if (group != null)
233 {
234 var groupNames = gh.GetParentsRecursively(group, new List<string>());
235 groupNames = gh.Format(groupNames, masterPage.GetDisplayName(), group);
236 groups = gh.ListToString(groupNames);
237 }
238
239 // should the button for adding to cart be disabled and show different text
240 bool showLimitedProduct = false;
241 if (activateLimitedProducts)
242 {
243 showLimitedProduct = true;
244 if (limitedProductNumbersList.Count > 0 && limitedProductNumbersList.Contains(product.GetString("Ecom:Product.Number")))
245 {
246 showLimitedProduct = false;
247 }
248 }
249
250 <div class="product-list__item">
251 <div class="col-xs-12">
252 <div class="product-list__item-inner">
253 <div class="col-xs-12 col-sm-4 col-flex">
254
255 <div class="product-list-item__primary-image">
256 @if (currentUser != null)
257 {
258 <a href="@GroupLink" title="@Name">
259 <img class="product-list-item__image lazy" alt="@Name" data-src="@Image&width=300" class="img-responsive img-center">
260 </a>
261 <a class="fancybox" data-fancybox href="@Image&width=1000" title="@Name">
262 <svg class="product-list-item__image-icon">
263 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#fullscreen"></use>
264 </svg>
265 </a>
266 }
267 else
268 {
269 <a href="@GroupLink" title="@Name">
270 <img class="product-list-item__image lazy" alt="@Name" data-src="@Image&width=300" class="img-responsive img-center">
271 </a>
272 <a class="fancybox" data-fancybox href="@Image&width=1000" title="@Name">
273 <svg class="product-list-item__image-icon">
274 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#fullscreen"></use>
275 </svg>
276 </a>
277 }
278
279
280 </div>
281 @{
282 var productObj = productService.GetProductById(prodID, prodVariantID, prodLanguageID);
283 var overlayNameAndColors = new ProductImageOverlayHelper().GetTextAndColor(productObj);
284
285 <div class="product__primary-image__overlay-container">
286 @foreach (var overlayNameAndColo in overlayNameAndColors)
287 {
288 <div style="background-color: @overlayNameAndColo.Value" class="product__primary-image__overlay-container__item">
289 @overlayNameAndColo.Key
290 </div>
291 }
292 </div>}
293 </div>
294 <div class="col-xs-12 col-sm-8">
295 <div class="product-list-item__info js-product-info">
296 <div class="row">
297 @*Title & Number*@
298 <div class="col-xs-12">
299 <h4 data-name="@Name" data-product_id="@prodID" data-categories="@groups" class="product-list-item__title">
300 <a class="product-list-item__title-link" href="@GroupLink">@Name</a>
301 </h4>
302 </div>
303 </div>
304 <div class="row">
305 <div class="col-xs-12 col-sm-5">
306
307 <div class="product-list-item__attributes">
308 <p>
309 <strong>Varenummer:</strong> @product.GetString("Ecom:Product.Number")
310 </p>
311 <p>
312 <strong>@product.GetString("Ecom:Product:Field.Attribut1A"):</strong><br />@product.GetString("Ecom:Product:Field.Attribut1B")
313 </p>
314 <p>
315 <strong>@product.GetString("Ecom:Product:Field.Attribut2A"):</strong> @product.GetString("Ecom:Product:Field.Attribut2B")
316 </p>
317 </div>
318
319 <div class="hidden-xs">
320 <div class="">
321 @* IKONER *@
322 <div class="product-list-item__icons">
323 @{
324 foreach (var c in product.GetString("Ecom:Product:Field.Certificates").Split(','))
325 {
326 if (!string.IsNullOrEmpty(c))
327 {
328 string src = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Certificates/" + @c + ".jpg&format=webp&quality=85&width=100";
329 <img class="product-list-item__icon lazy" alt="@Translate("Cert_" + c, c)" title="@Translate("Cert_" + c, c)" data-src=@src src=@src>
330 }
331 }
332 }
333 </div>
334 </div>
335 </div>
336 </div>
337
338 <div class="col-xs-12 col-sm-7">
339 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")))
340 {
341 <ul class="product-list-item__prices">
342 @foreach (var priceHtml in pricesHtmlList)
343 {
344 <li>
345 @priceHtml
346 </li>
347 }
348 </ul>
349 }
350 </div>
351 </div>
352
353 <div class="row">
354 <div class="col-xs-12 col-sm-4 col-lg-5">
355 @* LAGERBEHOLDNING *@
356 <div class="product-list-item__stock">
357 @{
358 if (stock > 0)
359 {
360 <p class="product-list-item__stock-text">
361 <span class="product-list-item__stock-circle product-list-item__stock-circle--green"></span> På lager
362 </p>
363 }
364 else
365 {
366 <p class="product-list-item__stock-text">
367 <span class="product-list-item__stock-circle product-list-item__stock-circle--yellow"></span> Kontakt os for leveringstid: 86210800 eller salg@hounisen.com
368 </p>
369 }
370 }
371 </div>
372
373 <div class="product-list-item__see-product">
374 <a class="product-list-item__link" href="@GroupLink" class="">@Translate("See product", "Se produkt")</a>
375 </div>
376 </div>
377 <div class="col-xs-12 col-sm-8 col-lg-7">
378 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")))
379 {
380 <div class="row">
381 @if (showLimitedProduct)
382 {
383 <div class="col-xs-12">
384 <button class="btn btn--ghost product__button disabled">
385 @Translate("Kan bestilles på fritekstordre", "Kan bestilles på fritekstordre")
386 </button>
387 </div>
388 }
389 else
390 {
391 <div class="col-xs-7">
392 <div class="product__addtocart-input js-addtocart-input">
393 <input type="button" value="-" class="product-list-item__quantity-button product-list-item__quantity-button--minus qtyminus" field="quantity" />
394 <input type="number" class="product__quantity-input product-list-item__quantity-input quantity" data-name="quantity" name="quantity" value="@minOrder" field="quantity" />
395 <input type="button" value="+" class="product-list-item__quantity-button product-list-item__quantity-button--plus qtyplus" field="quantity" />
396 </div>
397 <div class="product__unit-selector" style="display: inline-block;">
398 @{
399 int counter = 0;
400 }
401 @foreach (var unitDropdown in unitsDropdown)
402 {
403 var currentUnitPrice = prices[counter].Values["Ecom:Product.Prices.Amount"];
404 <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'" : "")>
405 <label for="@(unitDropdown.Id + prodID)">@unitDropdown.Name</label>
406 counter++;
407 }
408 </div>
409 <p class="product__unit-selector-error-message">
410 @Translate("unit-error-message", "* Du mangler at vælge type")
411 </p>
412 </div>
413 <div class="col-xs-5">
414 <div class="product__addtocart-button">
415 <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">
416 @Translate("Add to cart", "Add to cart")
417 <svg class="product__button-icon hidden-xs">
418 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#basket"></use>
419 </svg>
420 </button>
421
422 <div class="product-list-item__favorite-list popup-wrap favorite">
423
424 @if (hasRegionHDeal == false)
425 {
426 <button class="popup-show" data-popup="favorite-list" type="button" title="@Translate("Add to favorites", "Add to favorites")">
427 <i class="fa fa-star-o"></i> <span>Tilføj til liste</span>
428 </button>
429 <div id="favorite-list" class="popup-form">
430 <div class="close">
431 <i class="fa fa-times"></i>
432 </div>
433 <h3>@Translate("Choose list", "Choose list")</h3>
434 <ul>
435 @{
436 var lists = Dynamicweb.Ecommerce.CustomerCenter.CustomerProductList.GetListsByUserCustomerNumber(currentUser.CustomerNumber);
437 }
438
439 @foreach (var list in lists)
440 {
441 if (list.Products.Where(p => p.ProductId.ToString() == prodID).Count() > 0)
442 {
443 <li>
444 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCRemoveFromMyLists=@prodID&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType=">
445 <i class="fa fa-star"></i> @list.Name
446 </a>
447 </li>
448 }
449 else
450 {
451 <li>
452 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCAddToMyLists=@prodID&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType=">
453 <i class="fa fa-star-o"></i> @list.Name
454 </a>
455 </li>
456 }
457 }
458 <li>
459 <a href="/mine-favoritter/opret-favoritliste?ProdID=@prodID">
460 <i class="fa fa-plus"></i>@Translate("Add new list", "Add new list")
461 </a>
462 </li>
463 </ul>
464 </div>
465 }
466
467 </div>
468 </div>
469 </div>
470 }
471
472 </div>
473 }
474 else
475 {
476 <div class="not-loggedin">
477 <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>
478 <a data-toggle="modal" data-target="#login" href="" class="btn btn-primary not-loggedin-button">
479 <span>Log ind</span>
480 </a>
481 </div>
482 }
483 </div>
484 </div>
485 </div>
486
487
488 </div>
489 </div>
490 </div>
491 </div>
492
493 if (index == embedIndex)
494 {
495 <div class="product-list__item">
496 <div class="col-xs-12">
497 @embeddedScript
498 </div>
499 </div>
500 }
501
502
503 Count++;
504 index++;
505
506 if (Count == ColMD)
507 {
508 <div class="row"></div>
509 Count = 0;
510 }
511 }
512 }
513
514 <script>
515
516 document.addEventListener("DOMContentLoaded", function () {
517
518 var addToCartButtons = document.querySelectorAll('.product__button');
519 var unitTypes = document.getElementsByClassName("unit-type");
520 var product_names = document.getElementsByClassName("product-list-item__title");
521
522 addToCartButtons.forEach(function (item) {
523
524 item.addEventListener('click', function () {
525
526 var product_name = product_names[this.dataset.id - 1].dataset.name;
527 var product_id = product_names[this.dataset.id - 1].dataset.product_id;
528 var initialCategories = product_names[this.dataset.id - 1].dataset.categories;
529 var categories = initialCategories.split("_");
530 var quantity = document.getElementsByClassName("quantity")[this.dataset.id - 1].value;
531 var unitPrice;
532 var variantIsNull = true;
533 var unitTypeName = null;
534
535 //Get unittype price
536 for (const unitType of unitTypes) {
537
538 if (unitType.dataset.id == this.dataset.id) {
539
540 if (unitType.checked == true) {
541
542 var tempPrice = unitType.dataset.price.replace(".", "");
543 tempPrice = tempPrice.replace(",", ".");
544 unitPrice = parseFloat(tempPrice);
545 variantIsNull = false;
546 unitTypeName = unitType.value;
547
548 unitTypeName = unitTypeName.toString().split("_")[1];
549
550 }
551 }
552 }
553
554 if (!variantIsNull) {
555 dataLayer.push({ ecommerce: null });
556 dataLayer.push({
557 'event': 'add_to_cart',
558 "ecommerce": {
559 "currency": "DKK",
560 "value": unitPrice * parseInt(quantity).toFixed(2),
561 "items": [
562 {
563 "item_name": product_name + " - " + unitTypeName,
564 'item_id': product_id,
565 'price': unitPrice,
566 "item_brand": "",
567 "item_category": (categories[0] != null ? categories[0] : ""),
568 "item_category2": (categories[1] != null ? categories[1] : ""),
569 "item_category3": (categories[2] != null ? categories[2] : ""),
570 "item_category4": (categories[3] != null ? categories[3] : ""),
571 "item_category5": (categories[4] != null ? categories[4] : ""),
572 "quantity": parseInt(quantity),
573 }
574 ]
575 },
576
577 });
578 }
579 });
580 })
581 });
582
583 </script>
584 @using Dynamicweb.Security.UserManagement
585 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
586
587 @helper GetProductListRelated(dynamic Loop, int ColMD = 3, int ColSM = 3, int ColXS = 1)
588 {
589 var currentUser = User.GetCurrentExtranetUser();
590
591 <ul class="shop-list__list">
592
593 @foreach (LoopItem product in Loop)
594 {
595
596 string GroupLink = "/Default.aspx?ID=" + product.GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + product.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + product.GetString("Ecom:Product.ID");
597 string Name = product.GetString("Ecom:Product.Name");
598 string Description = product.GetString("Ecom:Product.ShortDescription");
599 string prodID = product.GetString("Ecom:Product.ID");
600 string Image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + prodID + ".jpg&format=webp&quality=85";
601
602 <li class="shop-list__item col-xs-12">
603 <a class="shop-list__link" href="@GroupLink" title="@Name">
604 <figure class="shop-list__figure">
605 <img class="shop-list__image lazy" style="width: 213px;" alt="@Name" data-src="@Image&width=213">
606 </figure>
607 <h4 class="shop-list__title">@Name</h4>
608 <div class="shop-list__text">
609 @if (String.IsNullOrEmpty(product.GetString("Ecom:Product.LongDescription")))
610 {
611 var gr = Dynamicweb.Ecommerce.Products.Group.GetGroupById(product.GetString("Ecom:Product.PrimaryOrFirstGroupID"));
612
613 @gr.Description.Replace("<a ", "<span ").Replace("</a>", "</span>").Replace("<h2>", "<p>").Replace("</h2>", "</p>")
614 }
615 else
616 {
617 @product.GetString("Ecom:Product.LongDescription").Replace("<a ", "<span ").Replace("</a>", "</span>").Replace("<h2>", "<p>").Replace("</h2>", "</p>")
618 }
619
620 </div>
621 <div class="shop-list__price">
622 @if (currentUser != null)
623 {
624 string baseUnitPrice = String.Empty;
625 var price = product.GetLoop("Product.Prices").OrderBy(x => x.GetDouble("Ecom:Product.Prices.BaseUnitPrice")).FirstOrDefault();
626 if (price != null)
627 {
628 baseUnitPrice = price.GetString("Ecom:Product.Prices.BaseUnitPrice");
629 }
630 <span class="shop-list__price-from">Priser fra</span>
631 <span class="shop-list__price-value">@baseUnitPrice</span>
632 <span class="shop-list__price-unit">kr./stk.</span>
633 }
634 </div>
635 </a>
636 </li>
637
638 }
639 </ul>
640 }
641
642
643 @using Dynamicweb.Security.UserManagement
644 @using System.Text.RegularExpressions;
645 @using Hounisen.Website.Helpers
646 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
647
648 @helper GetProductListFullRelated(dynamic Loop, int ColMD = 4, int ColSM = 4, int ColXS = 1)
649 {
650 int Count = 0;
651
652 string ColumnsMD = WrapMethods.ColumnMaker(ColMD, "md");
653 string ColumnsSM = WrapMethods.ColumnMaker(ColSM, "sm");
654 string ColumnsXS = WrapMethods.ColumnMaker(ColXS, "xs");
655 var currentUser = User.GetCurrentExtranetUser();
656
657 foreach (LoopItem product in Loop)
658 {
659 string GroupLink = "/Default.aspx?ID=" + product.GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + product.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + product.GetString("Ecom:Product.ID");
660 string Name = product.GetString("Ecom:Product.Name");
661 string Description = GetFormattedDescription(product.GetString("Ecom:Product.LongDescription"));
662 string prodID = product.GetString("Ecom:Product.ID");
663 string Image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + prodID + ".jpg&format=webp&quality=85";
664 var productObject = Dynamicweb.Ecommerce.Products.Product.GetProductById(product.GetString("Ecom:Product.ID"), product.GetString("Ecom:Product.VariantID"), product.GetString("Ecom:Product.LanguageID"));
665 var textAndColors = new ProductImageOverlayHelper().GetTextAndColor(productObject);
666 <li class="shop-list__item col-xs-12">
667 <a class="shop-list__link" href="@GroupLink" title="@Name">
668 <figure class="shop-list__figure" style="position: relative">
669 <img class="shop-list__image lazy" style="width: 213px;" alt="@Name" data-src="@Image&width=213">
670 <div class="product__primary-image__overlay-container">
671 @foreach (var overlayNameAndColor in textAndColors)
672 {
673 <div style="background-color: @overlayNameAndColor.Value" class="product__primary-image__overlay-container__item">
674 @overlayNameAndColor.Key
675 </div>
676 }
677 </div>
678 </figure>
679 <h4 class="shop-list__title">@Name</h4>
680 <div class="shop-list__text">@Description</div>
681 <div class="shop-list__price">
682 @if (currentUser != null)
683 {
684 string baseUnitPrice = String.Empty;
685 var price = product.GetLoop("Product.Prices").OrderBy(x => x.GetDouble("Ecom:Product.Prices.BaseUnitPrice")).FirstOrDefault();
686 if (price != null)
687 {
688 baseUnitPrice = price.GetString("Ecom:Product.Prices.BaseUnitPrice");
689 }
690
691 <span class="shop-list__price-from">Priser fra</span>
692 <span class="shop-list__price-value">@baseUnitPrice</span>
693 <span class="shop-list__price-unit">kr./stk</span>
694 }
695 </div>
696 </a>
697 </li>
698 }
699 }
700
701 @functions {
702 private static string GetFormattedDescription(string description = "")
703 {
704 string formattedDescription = Regex.Replace(description, @"<.*?>|[\r\n\t]| ", " ");
705 return formattedDescription.Length > 103 ? formattedDescription.Substring(0, 103).TrimEnd() + "..." : formattedDescription;
706 }
707 }
708
709 <script src="/Files/Templates/Designs/DwSimple/js/ProductVariantsAjax.js"></script>
710 <link rel="stylesheet" href="/Files/Templates/Designs/DwSimple/css/product.css"/>
711
712 @{
713 IFormatProvider jsNumberFormat = new NumberFormatInfo() { NumberDecimalSeparator = ".", NumberGroupSeparator = "" };
714 string initialPrice = string.Empty;
715 string metaDescription = string.Empty;
716 if (String.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")))
717 {
718 metaDescription = StripHTML(GetString("Ecom:Group.Description"));
719 }
720 else
721 {
722 metaDescription = StripHTML(GetString("Ecom:Product.LongDescription"));
723 }
724
725 bool isMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile;
726
727 //prices and units
728 string defaultUnitId = GetString("Ecom:Product.DefaultUnitID");
729 var prices = GetLoop("Product.Prices");
730 List<string> pricesHtmlList = Hounisen.Website.Helpers.Helpers.PricesListMakeListString(prices, false);
731 List<Hounisen.Website.Models.Unit> unitsDropdown = Hounisen.Website.Helpers.Helpers.PopulateUnitsDropdown(prices);
732 var unitDefault = unitsDropdown.Where(x => x.Id.Equals(defaultUnitId)).FirstOrDefault();
733 int minOrder = unitDefault != null ? unitDefault.MinOrder : 1;
734
735
736 //other vars
737 var pid = GetString("Ecom:Product.ID");
738 int stock = GetInteger("Ecom:Product.Stock");
739 string image = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + pid + ".jpg";
740 string productname = GetString("Ecom:Product.Name");
741 string productlink = "/Default.aspx?ID=" + GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&groupid=" + GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&productid=" + GetString("Ecom:Product.ID");
742
743
744 // SKI AND Region H
745 bool hasSkiDeal = false;
746 bool hasRegionHDeal = false;
747 bool activateLimitedProducts = false;
748 string limitedProductNumbers = "";
749 var currentUser = User.GetCurrentExtranetUser();
750 if (currentUser != null)
751 {
752 var skiGroup = currentUser.Groups.FirstOrDefault(e => e.Name == "SKI");
753 if (skiGroup != null && !string.IsNullOrEmpty(skiGroup.Name))
754 {
755 hasSkiDeal = true;
756 }
757
758 hasRegionHDeal = Dynamicweb.Core.Converter.ToBoolean(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_RegionH").Value);
759 activateLimitedProducts = Dynamicweb.Core.Converter.ToBoolean(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_ActivateLimitedProducts").Value);
760 limitedProductNumbers = Dynamicweb.Core.Converter.ToString(currentUser.CustomFieldValues.Find(f => f.CustomField.SystemName == "AccessUser_LimitedProductNumbers").Value);
761 }
762
763 List<string> limitedProductNumbersList = new List<string>();
764 if (!String.IsNullOrWhiteSpace(limitedProductNumbers) && activateLimitedProducts)
765 {
766 limitedProductNumbersList = limitedProductNumbers.Split(',').ToList();
767 }
768
769 // should the button for adding to cart be disabled and show different text
770 bool showLimitedProduct = false;
771 if (activateLimitedProducts)
772 {
773 showLimitedProduct = true;
774 if (limitedProductNumbersList.Count > 0 && limitedProductNumbersList.Contains(GetString("Ecom:Product.Number")))
775 {
776 showLimitedProduct = false;
777 }
778 }
779
780 //serialized data
781 var pagedata = new System.Collections.Generic.Dictionary<String, Object>();
782 Pageview.Area.Item.SerializeTo(pagedata);
783
784
785 var pageService = new PageService();
786 GroupHelper gh = new GroupHelper();
787 var group = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(GetString("Ecom:Product.PrimaryOrFirstGroupID"));
788 var masterPage = pageService.GetPage(GetInteger("Ecom:Product.PrimaryOrCurrentPageID"));
789 masterPage.GetDisplayName();
790 var groupNames = gh.GetParentsRecursively(group, new List<string>());
791 groupNames = gh.Format(groupNames, masterPage.GetDisplayName(), group);
792
793 var groups = gh.ListToString(groupNames);
794 }
795
796 <div class="col-md-12 col-sm-12 col-xs-12" style="margin-bottom: 25px">
797
798 <div class="row product" itemscope itemtype="http://schema.org/Product">
799 <section class="page-header" style="margin-top: 15px">
800 <div class="product__help-name-container">
801 <div class="col-xs-12 col-sm-7 p-0">
802 <meta itemprop="description" content="@metaDescription"/>
803 <h1 data-categories="@groups" data-group="@GetString("Ecom:Group.Name")" class="page-header__title" itemprop="name">@GetString("Ecom:Product.Name")</h1>
804 <div class="page-header__short-description">
805 <p class="product__number">@Translate("Productnumber", "Productnumber"): <span property="identifier" itemprop="mpn">@GetString("Ecom:Product.Number")</span></p>
806 @if (hasSkiDeal)
807 {
808 <p class="product__number">@Translate("Skinumber", "SKI nr"): <span property="identifier">@GetString("Ecom:Product:Field.SkiId")</span></p>
809 }
810 @if (hasRegionHDeal && GetBoolean("Ecom:Product:Field.RegionH"))
811 {
812 <p class="product__number">@Translate("RegionHText")</p>
813 }
814
815 </div>
816 </div>
817
818
819 <div class="d-none d-lg-block product__help-name-container__help p-0">
820 <div class="need-help product-view">
821 <img class="need-help__image lazy" width="81" height="81" data-src='@(Pageview.Area.Item["Support_Image"].ToString())?format=webp&width=81&quality=75'/>
822 <div class="need-help__text product-view">
823 @Pageview.Area.Item["Support_Content"].ToString()
824 </div>
825 </div>
826 </div>
827
828
829 </div>
830 </section>
831 <div class="row">
832
833 @* The image area *@
834 <div class="col-md-6 col-sm-4 col-xs-12 product__column">
835 <div class="product__gallery">
836
837 @* Discount sticker *@
838
839 @if (GetString("Ecom:Product.Discount.Price.PriceWithVATFormatted") != GetString("Ecom:Product.Price.PriceWithVATFormatted"))
840 {
841 if (pagedata["EcommerceStickerType"].ToString() == "ribbon")
842 {
843 <span class="ribbon base">@Translate("On sale!", "On sale!")</span>
844 }
845
846 if (pagedata["EcommerceStickerType"].ToString() == "ball")
847 {
848 <span class="ball">@Translate("On sale!", "On sale!")</span>
849 }
850 }
851
852
853 @* Product images *@
854 @{
855 string currenthost = HttpContext.Current.Request.Url.AbsoluteUri;
856 Uri uri = new Uri(currenthost);
857 currenthost = string.Format("{0}://{1}", uri.Scheme, uri.Authority);
858 string ImagePathloop = "";
859 string ImagePathClean = "";
860 string options = "format=webp&quality=85&width=1000";
861 List<string> imagepath = new List<string>();
862
863
864 //i starts at 1 - avoids showing the first image twice
865 for (int i = 1; i <= 5; i++)
866 {
867 ImagePathloop = "/Admin/Public/GetImage.ashx?Image=/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg";
868 //currenthost +
869 ImagePathClean = "/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg";
870
871 try
872 {
873 if (File.Exists(HttpContext.Current.Server.MapPath(ImagePathClean)))
874 {
875 imagepath.Add(ImagePathloop + "&" + options);
876 }
877
878 HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(ImagePathloop);
879 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
880 {
881 if (response.StatusCode == HttpStatusCode.NotFound)
882 {
883 break;
884 }
885 else
886 {
887 imagepath.Add("/Files/Images/Ecom/Products/" + pid + "-0" + i.ToString() + ".jpg" + "" + options);
888 }
889 }
890 }
891 catch (Exception ex)
892 {
893 }
894 }
895 }
896
897 @{
898 var resizedImageLarge = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings()
899 {
900 Image = $"/Files/Images/Ecom/Products/{pid}.jpg",
901 Width = 1000,
902 Quality = 99
903 });
904
905 var resizedImage = VestjyskMarketing.Helpers.ImageHelper.ResizeImage(new ResizeImageSettings()
906 {
907 Image = $"/Files/Images/Ecom/Products/{pid}.jpg",
908 Width = 458,
909 Quality = 85
910 });
911 }
912
913 <div class="product__primary-image">
914 <a href="@resizedImageLarge" data-fancybox="product-gallery" class="fancybox">
915 <img src="@resizedImage" data-src="@resizedImage" width="458" alt="@productname" class="product__image img-responsive lazy" itemprop="image">
916 @{
917 var productObj = new ProductService().GetProductById(GetString("Ecom:Product.ID"), GetString("Ecom:Product.VariantID"), GetString("Ecom:Product.LanguageID"));
918 var overlayNameAndColors = new ProductImageOverlayHelper().GetTextAndColor(productObj);
919 }
920
921 <div class="product__primary-image__overlay-container">
922 @foreach (var overlayNameAndColor in overlayNameAndColors)
923 {
924 <div style="background-color: @overlayNameAndColor.Value" class="product__primary-image__overlay-container__item">
925 @overlayNameAndColor.Key
926 </div>
927 }
928 </div>
929 <svg class="product__image-icon">
930 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#fullscreen"></use>
931 </svg>
932 </a>
933 </div>
934 <div class="row col-xs-12">
935 <div class="product__thumbnail-list">
936 @foreach (var imageThumb in imagepath)
937 {
938 <div class="col-sm-3 col-xs-4">
939 <div class="product__thumbnail-images">
940 <a href="@imageThumb&width=1000" data-fancybox="product-gallery" rel="product" class="fancybox">
941 <img data-src="@imageThumb&width=458" width="458" alt="@productname" class="img-responsive lazy">
942 </a>
943 </div>
944 </div>
945 }
946 @{
947 var youtubeVideos = productObj.Details.Where(x => "YoutubeVideos" == new DetailsGroupService().GetById(x.GroupId).SystemName).ToList();
948 var productVideos = productObj.Details.Where(x => "ProductVideos" == new DetailsGroupService().GetById(x.GroupId).SystemName).ToList();
949
950 if (youtubeVideos.Count > 0)
951 {
952 foreach (var youtubeVideo in youtubeVideos)
953 {
954 string thumbnail = youtubeVideo.Value;
955 string youtubeId = youtubeVideo.Keywords;
956
957 // For Fancybox, we typically include “?autoplay=1” in the iframe URL.
958 var youtubeEmbedUrl = $"https://www.youtube.com/embed/{youtubeId}?autoplay=1&enablejsapi=1";
959
960 <div class="col-sm-3 col-xs-4">
961 <div class="product__thumbnail-images">
962 <a style="" href="@youtubeEmbedUrl"
963 data-fancybox="product-gallery"
964 data-type="iframe"
965 rel="product"
966 class="fancybox">
967
968 <div class="product__play-container">
969 <img alt="Video thumbnail" src="@thumbnail"/>
970 <svg class="product__play-container__play-icon" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
971 <path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9l0-176c0-8.7 4.7-16.7 12.3-20.9z"/>
972 </svg>
973 </div>
974 </a>
975 </div>
976 </div>
977 }
978 }
979 else
980 {
981 var youtubeId = GetString("Ecom:Product:Field.YoutubeId");
982 // For Fancybox, we typically include “?autoplay=1” in the iframe URL.
983 var youtubeEmbedUrl = $"https://www.youtube.com/embed/{youtubeId}?autoplay=1&enablejsapi=1";
984
985 if (!string.IsNullOrEmpty(youtubeId))
986 {
987 <div class="col-sm-3 col-xs-4">
988 <div class="product__thumbnail-images">
989 <a style="height: 63px" href="@youtubeEmbedUrl"
990 data-fancybox="product-gallery"
991 data-type="iframe"
992 rel="product"
993 class="fancybox">
994 <svg class="product__play-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
995 <path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9l0-176c0-8.7 4.7-16.7 12.3-20.9z"/>
996 </svg>
997 </a>
998 </div>
999 </div>
1000 }
1001 }
1002
1003 if (productVideos.Count > 0)
1004 {
1005 foreach (var productVideo in productVideos)
1006 {
1007 string thumbnail = productVideo.Value;
1008 string mp4Path = productVideo.Keywords;
1009
1010
1011 <div class="col-sm-3 col-xs-4">
1012 <div class="product__thumbnail-images">
1013 <!--
1014 Link to a hidden <div> containing our <video>.
1015 We use data-fancybox="product-gallery" to group it with our images.
1016 data-src="#mp4VideoContent" + data-type="inline" to open inline HTML content.
1017 -->
1018 <a style="" data-fancybox="product-gallery"
1019 data-src="#mp4VideoContent"
1020 data-type="inline"
1021 href="javascript:;">
1022 <div class="product__play-container">
1023 <img alt="Video thumbnail" src="@thumbnail"/>
1024 <svg class="product__play-container__play-icon" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
1025 <path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9l0-176c0-8.7 4.7-16.7 12.3-20.9z"/>
1026 </svg>
1027 </div>
1028 </a>
1029 </div>
1030 </div>
1031
1032 <!-- Hidden HTML content that Fancybox will open -->
1033 <div style="display:none;" id="mp4VideoContent">
1034 <video controls style="width:100%; height:auto;">
1035 <source src="@mp4Path" type="video/mp4"/>
1036 <!-- You can add WebM or OGG sources if you like for broader browser support -->
1037 Your browser does not support the video tag.
1038 </video>
1039 </div>
1040 }
1041 }
1042 else
1043 {
1044 string mp4Path = GetString("Ecom:Product:Field.ProductVideo.FullPath");
1045
1046 if (!string.IsNullOrEmpty(mp4Path))
1047 {
1048 <div class="col-sm-3 col-xs-4">
1049 <div class="product__thumbnail-images">
1050 <!--
1051 Link to a hidden <div> containing our <video>.
1052 We use data-fancybox="product-gallery" to group it with our images.
1053 data-src="#mp4VideoContent" + data-type="inline" to open inline HTML content.
1054 -->
1055 <a style="height: 63px" data-fancybox="product-gallery"
1056 data-src="#mp4VideoContent"
1057 data-type="inline"
1058 href="javascript:;">
1059 <svg class="product__play-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
1060 <path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9l0-176c0-8.7 4.7-16.7 12.3-20.9z"/>
1061 </svg>
1062 </a>
1063 </div>
1064 </div>
1065
1066 <!-- Hidden HTML content that Fancybox will open -->
1067 <div style="display:none;" id="mp4VideoContent">
1068 <video controls style="width:100%; height:auto;">
1069 <source src="@mp4Path" type="video/mp4"/>
1070 <!-- You can add WebM or OGG sources if you like for broader browser support -->
1071 Your browser does not support the video tag.
1072 </video>
1073 </div>
1074 }
1075 }
1076 }
1077 </div>
1078 </div>
1079 </div>
1080 <section class="d-block d-lg-none page-header p-0 m-0" style="border: none">
1081 <div class="product__help-name-container" style="width: 100%">
1082 <div class=" product__help-name-container__help second">
1083 <div class="need-help product-view">
1084 <img class="need-help__image lazy" width="81" height="81" data-src='@(Pageview.Area.Item["Support_Image"].ToString())?format=webp&width=81&quality=75'/>
1085 <div class="need-help__text product-view second">
1086 @Pageview.Area.Item["Support_Content"].ToString()
1087 </div>
1088 </div>
1089 </div>
1090 </div>
1091 </section>
1092 </div>
1093
1094
1095 @* The main product information area *@
1096
1097 <div class="col-md-6 col-sm-8 col-xs-12 product__column">
1098 <div class="product-info js-product-info" id="productinfo">
1099 <div class="product__control">
1100 <div class="row">
1101 <div class="col-xs-12 col-sm-6">
1102 @* LAGERBEHOLDNING *@
1103 <div class="product__stock">
1104 @{
1105 if (stock > 0)
1106 {
1107 <p class="product__stock-text">
1108 <span class="product__stock-circle product__stock-circle--green"></span> På lager
1109 </p>
1110 }
1111 else
1112 {
1113 <p class="product__stock-text">
1114 <span class="product__stock-circle product__stock-circle--yellow"></span> Kontakt os for leveringstid: 86210800 eller salg@hounisen.com
1115 </p>
1116 }
1117 }
1118 </div>
1119 </div>
1120 <div class="col-xs-12 col-sm-6">
1121 @* FAVORITTER *@
1122 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")))
1123 {
1124 if (hasRegionHDeal == false)
1125 {
1126 <div class="product__favorite-list popup-wrap favorite">
1127 <button class="popup-show" data-popup="favorite-list" type="button" title="@Translate("Add to favorites", "Add to favorites")">
1128 <i class="fa fa-star-o"></i> <span>@Translate("Add to favorites", "Add to favorites")</span>
1129 </button>
1130 <div id="favorite-list" class="popup-form">
1131 <div class="close">
1132 <i class="fa fa-times"></i>
1133 </div>
1134 <h3>@Translate("Choose list", "Choose list")</h3>
1135 <ul>
1136 @{
1137 var lists = Dynamicweb.Ecommerce.CustomerCenter.CustomerProductList.GetListsByUserCustomerNumber(currentUser.CustomerNumber);
1138 }
1139
1140 @foreach (var list in lists)
1141 {
1142 if (list.Products.Where(p => p.ProductId.ToString() == GetString("Ecom:Product.ID")).Count() > 0)
1143 {
1144 <li>
1145 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCRemoveFromMyLists=@GetString("Ecom:Product.ID")&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType=">
1146 <i class="fa fa-star"></i> @list.Name
1147 </a>
1148 </li>
1149 }
1150 else
1151 {
1152 <li>
1153 <a href="@(System.Web.HttpContext.Current.Request.Url)&CCAddToMyLists=@GetString("Ecom:Product.ID")&CCAddToListVariantID=&CCAddToListLanguageID=LANG1&CCAddToListID=@list.ListId&CCListType=">
1154 <i class="fa fa-star-o"></i> @list.Name
1155 </a>
1156 </li>
1157 }
1158 }
1159 <li>
1160 <a href="/mine-favoritter/opret-favoritliste?ProdID=@GetString("Ecom:Product.ID")">
1161 <i class="fa fa-plus"></i>@Translate("Add new list", "Add new list")
1162 </a>
1163 </li>
1164 </ul>
1165 </div>
1166 </div>
1167 }
1168 }
1169 else
1170 {
1171 <div class="not-loggedin">
1172 <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>
1173 <a data-toggle="modal" data-target="#login" href="" class="btn btn-primary not-loggedin-button">
1174 <span>Log ind</span>
1175 </a>
1176 </div>
1177 }
1178 </div>
1179 </div>
1180
1181
1182 @* Prices and actions *@
1183 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")))
1184 {
1185 var product = GetString("Ecom:Product.ID");
1186 if (!string.IsNullOrWhiteSpace(GetString("Ecom:Product.SelectedVariantComboID")))
1187 {
1188 product = GetString("Ecom:Product.ID") + "&" + GetString("Ecom:Product.SelectedVariantComboID");
1189 }
1190
1191 <div class="row">
1192 <div class="col-xs-12">
1193 <ul class="product__prices">
1194 @foreach (var priceHtml in pricesHtmlList)
1195 {
1196 <li>
1197 @priceHtml
1198 </li>
1199 }
1200 </ul>
1201 </div>
1202 </div>
1203
1204 <div class="row">
1205 @if (showLimitedProduct)
1206 {
1207 <div class="col-xs-12">
1208 <button class="btn btn--ghost product__button disabled">
1209 @Translate("Kan bestilles på fritekstordre", "Kan bestilles på fritekstordre")
1210 </button>
1211 </div>
1212 }
1213 else
1214 {
1215 <div class="col-xs-7">
1216 <div class="product__addtocart-input js-addtocart-input">
1217 <input type="button" value="-" class="product__quantity-button product__quantity-button--minus qtyminus" field="quantity"/>
1218 <input type="number" class="product__quantity-input quantity" data-name="quantity" name="quantity" value="@minOrder" field="quantity"/>
1219 <input type="button" value="+" class="product__quantity-button product__quantity-button--plus qtyplus" field="quantity"/>
1220 </div>
1221 <div class="product__unit-selector" style="display: inline-block;">
1222
1223 @{
1224 var index = 0;
1225 }
1226
1227 @foreach (var unitDropdown in unitsDropdown)
1228 {
1229 index++;
1230 var currentUnitPrice = prices[index - 1].Values["Ecom:Product.Prices.Amount"];
1231 <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'" : "")>
1232 <label for="@unitDropdown.Id">@unitDropdown.Name</label>
1233 }
1234 </div>
1235 <p class="product__unit-selector-error-message">
1236 * Du mangler at vælge type
1237 </p>
1238 </div>
1239 <div class="col-xs-5">
1240 <div class="product__addtocart-button">
1241 <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">
1242 @Translate("Add to cart", "Add to cart")
1243 <svg class="product__button-icon hidden-xs">
1244 <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/icons/icons.svg#basket"></use>
1245 </svg>
1246 </button>
1247 </div>
1248 </div>
1249 }
1250 </div>
1251 }
1252 </div>
1253
1254 @* Product details *@
1255 <div>
1256 @* IKONER *@
1257 <div class="product__icons">
1258 @{
1259 foreach (var c in GetString("Ecom:Product:Field.Certificates").Split(','))
1260 {
1261 if (!string.IsNullOrEmpty(c))
1262 {
1263 <img class="product__icon lazy" data-src="/Files/Images/Ecom/certificates/@(c).jpg" title="@Translate("Cert_" + c, c)"/>
1264 }
1265 }
1266 }
1267
1268
1269 </div>
1270
1271
1272 </div>
1273 </div>
1274 </div>
1275 </div>
1276 </div>
1277 </div>
1278
1279
1280 @helper RenderDocuments()
1281 {
1282 var productObj = new ProductService().GetProductById(GetString("Ecom:Product.ID"), GetString("Ecom:Product.VariantID"), GetString("Ecom:Product.LanguageID"));
1283 var documents = productObj.Details.Where(x => "Documents" == new DetailsGroupService().GetById(x.GroupId).SystemName).ToList();
1284
1285 bool hasAtLeastOneLink =
1286 !string.IsNullOrEmpty(GetString("Ecom:Product:Field.Link1Label")) ||
1287 !string.IsNullOrEmpty(GetString("Ecom:Product:Field.Link2Label")) ||
1288 !string.IsNullOrEmpty(GetString("Ecom:Product:Field.Link3Label")) ||
1289 !string.IsNullOrEmpty(GetString("Ecom:Product:Field.Link4Label")) ||
1290 !string.IsNullOrEmpty(GetString("Ecom:Product:Field.Link5Label"));
1291 bool atleastOneProductDetail = hasAtLeastOneLink ||
1292 !string.IsNullOrEmpty(GetString("Ecom:Product:Field.Guidance.Value.Clean")) ||
1293 !string.IsNullOrEmpty(GetString("Ecom:Product:Field.FAQ.Value.Clean")) || documents.Count > 0;
1294
1295
1296 @* DOWNLOAD *@
1297 if (hasAtLeastOneLink)
1298 {
1299 <div class="row">
1300 <div class="col-xs-12">
1301 <div onclick="updateDetailAccessibility(this)" class="product__section-container">
1302 <h3 class="product__header">@Translate("Dokumenter")</h3>
1303 <div class="product__section-container__icon-wrapper" data-height="0px" data-content-id="documents">
1304 <svg style="display: block" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1305 <path d="M240 64c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 176L32 240c-8.8 0-16 7.2-16 16s7.2 16 16 16l176 0 0 176c0 8.8 7.2 16 16 16s16-7.2 16-16l0-176 176 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-176 0 0-176z"/>
1306 </svg>
1307 <svg style="display: none" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1308 <path d="M424 256c0 4.4-3.6 8-8 8L32 264c-4.4 0-8-3.6-8-8s3.6-8 8-8l384 0c4.4 0 8 3.6 8 8z"/>
1309 </svg>
1310 </div>
1311
1312 </div>
1313 </div>
1314 <div class="col-xs-12">
1315 <div style="display: block;">
1316 <div class="product__details">
1317 <div data-content-id="documents" class="product__details__content" style="max-height: 0px;">
1318
1319
1320 @{
1321 if (documents.Count > 0)
1322 {
1323 foreach (var document in documents)
1324 {
1325 <div>
1326 <a class="product__download-pdf" target="_blank" href="@document.Value" class="">@document.Keywords</a>
1327 </div>
1328 }
1329 }
1330 else
1331 {
1332 if (GetString("Ecom:Product:Field.Link1Label") != "")
1333 {
1334 <div>
1335 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link1File.Clean")" class="">@GetString("Ecom:Product:Field.Link1Label")</a>
1336 </div>
1337 }
1338
1339 if (GetString("Ecom:Product:Field.Link2Label") != "")
1340 {
1341 <div>
1342 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link2File.Clean")" class="">@GetString("Ecom:Product:Field.Link2Label")</a>
1343 </div>
1344 }
1345
1346 if (GetString("Ecom:Product:Field.Link3Label") != "")
1347 {
1348 <div>
1349 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link3File.Clean")" class="">@GetString("Ecom:Product:Field.Link3Label")</a>
1350 </div>
1351 }
1352
1353 if (GetString("Ecom:Product:Field.Link4Label") != "")
1354 {
1355 <div>
1356 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link4File.Clean")" class="">@GetString("Ecom:Product:Field.Link4Label")</a>
1357 </div>
1358 }
1359
1360 if (GetString("Ecom:Product:Field.Link5Label") != "")
1361 {
1362 <div>
1363 <a class="product__download-pdf" target="_blank" href="@GetString("Ecom:Product:Field.Link5File.Clean")" class="">@GetString("Ecom:Product:Field.Link5Label")</a>
1364 </div>
1365 }
1366 }
1367 }
1368
1369 </div>
1370 </div>
1371 </div>
1372 </div>
1373 </div>
1374 <hr class="product__hr"/>
1375 }
1376 }
1377
1378 @helper RenderGuidance()
1379 {
1380 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.Guidance.Value.Clean")))
1381 {
1382 <div class="row">
1383
1384 <div class="col-xs-12">
1385
1386
1387 <div onclick="updateDetailAccessibility(this)" class="product__section-container">
1388 <h3 class="product__header">Vejledning</h3>
1389
1390 <div class="product__section-container__icon-wrapper" data-height="0px" data-content-id="Guidance">
1391 <svg style="display: block" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1392 <path d="M240 64c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 176L32 240c-8.8 0-16 7.2-16 16s7.2 16 16 16l176 0 0 176c0 8.8 7.2 16 16 16s16-7.2 16-16l0-176 176 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-176 0 0-176z"/>
1393 </svg>
1394 <svg style="display: none" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1395 <path d="M424 256c0 4.4-3.6 8-8 8L32 264c-4.4 0-8-3.6-8-8s3.6-8 8-8l384 0c4.4 0 8 3.6 8 8z"/>
1396 </svg>
1397 </div>
1398
1399 </div>
1400 </div>
1401 <div class="col-xs-12 py-4">
1402 <div style="display: block;">
1403 <div class="product__details">
1404 @{
1405 var text = GetString("Ecom:Product:Field.Guidance.Value.Clean");
1406 }
1407
1408 <div data-content-id="Guidance" class="product__details__content" style="max-height: 0px;">
1409 @text
1410 </div>
1411
1412 </div>
1413 </div>
1414 </div>
1415 </div>
1416
1417 <hr class="product__hr"/>
1418 }
1419 }
1420
1421 @helper RenderFAQ()
1422 {
1423 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.FAQ.Value.Clean")))
1424 {
1425 <div class="row">
1426
1427 <div class="col-xs-12">
1428
1429
1430 <div onclick="updateDetailAccessibility(this)" class="product__section-container">
1431 <h3 class="product__header">@Translate("FAQ")</h3>
1432
1433 <div class="product__section-container__icon-wrapper" data-height="0px" data-content-id="FAQ">
1434 <svg style="display: block" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1435 <path d="M240 64c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 176L32 240c-8.8 0-16 7.2-16 16s7.2 16 16 16l176 0 0 176c0 8.8 7.2 16 16 16s16-7.2 16-16l0-176 176 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-176 0 0-176z"/>
1436 </svg>
1437 <svg style="display: none" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1438 <path d="M424 256c0 4.4-3.6 8-8 8L32 264c-4.4 0-8-3.6-8-8s3.6-8 8-8l384 0c4.4 0 8 3.6 8 8z"/>
1439 </svg>
1440 </div>
1441
1442 </div>
1443 </div>
1444 <div class="col-xs-12 py-4">
1445 <div style="display: block;">
1446 <div class="product__details">
1447 @{
1448 var text = GetString("Ecom:Product:Field.FAQ.Value.Clean");
1449 }
1450
1451 <div data-content-id="FAQ" class="product__details__content" style="max-height: 0px;">
1452 @text
1453 </div>
1454
1455 </div>
1456 </div>
1457 </div>
1458 </div>
1459
1460 <hr class="product__hr"/>
1461 }
1462 }
1463
1464 @helper RenderSpecifikationer()
1465 {
1466 <div class="row">
1467 <div class="col-xs-12">
1468 <hr class="product__hr"/>
1469 <div class="product__section-container product__section-container--no-hover">
1470 <h3 class="product__header">Specifikationer</h3>
1471 </div>
1472 </div>
1473 <div class="col-xs-12 py-4">
1474 <div style="display: block;">
1475 <div class="product__details">
1476
1477
1478 <div data-content-id="specifikationer" class="product__details__content" style="max-height: 9999px;">
1479
1480 @* ATTRIBUTTER *@
1481 <div class="product__information">
1482
1483 <dl class="product__information-table">
1484 @{
1485 int attributeLineCount = 0;
1486 for (int i = 1; i < 8; i++)
1487 {
1488 attributeLineCount++;
1489 string attributeName = "Ecom:Product:Field.Attribut" + attributeLineCount + "A";
1490 string attributeValue = "Ecom:Product:Field.Attribut" + attributeLineCount + "B";
1491 string attributeBrand = string.Empty;
1492
1493 if (GetString(attributeName) != "")
1494 {
1495 if (attributeLineCount == 7)
1496 {
1497 attributeBrand = "itemprop=\"brand\"";
1498 }
1499
1500 <dt>@GetString(attributeName) :</dt>
1501 <dd @attributeBrand>@GetString(attributeValue)</dd>
1502 }
1503 }
1504
1505 string manufacturerName = GetString("Ecom:Manufacturer.Name");
1506 string manufacturerUrl = GetString("Ecom:Manufacturer.Web");
1507
1508 if (!manufacturerName.IsNullOrEmpty() && !manufacturerUrl.IsNullOrEmpty())
1509 {
1510 <dt>Brand :</dt>
1511 <dd>
1512 <a target="_blank" class="product__information-table__manufacturer" href="@manufacturerUrl">@manufacturerName</a>
1513 </dd>
1514 }
1515 }
1516
1517 </dl>
1518 </div>
1519
1520
1521 </div>
1522
1523 </div>
1524 </div>
1525 </div>
1526 </div>
1527 }
1528
1529 @helper RenderDescription()
1530 {
1531 if (!String.IsNullOrEmpty(GetString("Ecom:Product.LongDescription")))
1532 {
1533 var description = GetString("Ecom:Product.LongDescription");
1534
1535 // Remove HTML tags
1536 string cleanedText = Regex.Replace(description, "<.*?>", " ");
1537 string[] words = cleanedText.Split(new[] { ' ', '\n', '\r', '\t' }, StringSplitOptions.RemoveEmptyEntries);
1538 bool readMoreButton = words.Length > 80;
1539
1540 <div class="row">
1541
1542 <div class="col-xs-12">
1543 <hr class="product__hr"/>
1544 <div onclick="updateDetailAccessibility(this)" class="product__section-container">
1545 <h3 style="@(!readMoreButton ? "cursor: auto" : "") " id="productLongDescriptionID" class="product__header">@Translate("Description", "Description")</h3>
1546
1547 <div class="product__section-container__icon-wrapper" data-height="95px" data-content-id="description">
1548
1549 @if (readMoreButton)
1550 {
1551 <svg style="display: block" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1552 <path d="M240 64c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 176L32 240c-8.8 0-16 7.2-16 16s7.2 16 16 16l176 0 0 176c0 8.8 7.2 16 16 16s16-7.2 16-16l0-176 176 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-176 0 0-176z"/>
1553 </svg>
1554 <svg style="display: none" class="product__section-container__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
1555 <path d="M424 256c0 4.4-3.6 8-8 8L32 264c-4.4 0-8-3.6-8-8s3.6-8 8-8l384 0c4.4 0 8 3.6 8 8z"/>
1556 </svg>
1557 }
1558 </div>
1559 </div>
1560 </div>
1561 <div class="col-xs-12 py-4">
1562 <div style="display: block;">
1563 <div class="product__details">
1564
1565 @if (readMoreButton)
1566 {
1567 <div data-content-id="description" class="product__details__content" style="min-height: 95px;max-height: 95px;">
1568 @description
1569 </div>
1570 }
1571 else
1572 {
1573 @description
1574 }
1575 </div>
1576 </div>
1577 </div>
1578 </div>
1579 }
1580 }
1581
1582
1583 <div class="row product__column__wrapper">
1584 <div class="col-md-6 col-sm-12 col-xs-12 product__column">
1585 @if (isMobile)
1586 {
1587 @RenderSpecifikationer()
1588 @RenderDescription()
1589 <hr class="product__hr"/>
1590 }
1591 else
1592 {
1593 @RenderDescription()
1594 <hr class="product__hr"/>
1595 @RenderGuidance()
1596 @RenderFAQ()
1597 }
1598
1599 </div>
1600 <div class="col-md-6 col-sm-12 col-xs-12 product__column">
1601 @if (isMobile)
1602 {
1603 @RenderDocuments()
1604 @RenderGuidance()
1605 @RenderFAQ()
1606 }
1607 else
1608 {
1609 @RenderSpecifikationer()
1610 <hr class="product__hr"/>
1611 @RenderDocuments()
1612 }
1613 </div>
1614 </div>
1615
1616
1617 @* Related products *@
1618
1619 @if (GetString("Ecom:Product.RelatedCount") != "0")
1620 {
1621 <div class="row">
1622 <div class="col-xs-12 p-15 p-md-0 @(isMobile ? "related-products-slider" : "")">
1623 <h2 class="product__header product__header--mobile-center">Relaterede varer</h2>
1624 <ul class="shop-list__list p-0-fc @(isMobile ? "owl-carousel" : "") ">
1625 @foreach (LoopItem relatedgroup in GetLoop("ProductRelatedGroups"))
1626 {
1627 var relatedproductloop = relatedgroup.GetLoop("RelatedProducts").OrderByDescending(g => g.GetString("Ecom:Product.LoopCounter")).Take(4).ToList();
1628 @GetProductListFullRelated(relatedproductloop, 3, 3, 1)
1629 }
1630 </ul>
1631 </div>
1632 </div>
1633 }
1634
1635
1636 <!-- Udforsk mere -->
1637
1638 @functions
1639 {
1640 List<int> GetIds(string idsRaw)
1641 {
1642 List<int> ids = new List<int>();
1643 if (idsRaw.IsNotNullOrEmpty())
1644 {
1645 foreach (var articleId in idsRaw.Split(','))
1646 {
1647 if (int.TryParse(articleId, out int id))
1648 {
1649 ids.Add(id);
1650 }
1651 }
1652 }
1653
1654 return ids;
1655 }
1656 }
1657
1658 @{
1659 var articlesPageId = GetPageIdByNavigationTag("ProductviewUniverseArticles");
1660 bool hasActiveArticles = false;
1661
1662 var productId = Dynamicweb.Context.Current.Request.QueryString["productid"];
1663 var defaultGroup = new ProductService().GetProductById(productId, "", true).DefaultGroup;
1664
1665 if (defaultGroup != null)
1666 {
1667 string articlesIdsRaw = defaultGroup.ProductGroupFieldValues.GetProductGroupFieldValue("Articles").Value.ToString();
1668 string articleSubGroupIdsRaw = defaultGroup.ProductGroupFieldValues.GetProductGroupFieldValue("ArticleSubCategories").Value.ToString();
1669
1670 List<int> articlesIds = new List<int>();
1671 if (!string.IsNullOrEmpty(articlesIdsRaw))
1672 {
1673 articlesIds = GetIds(articlesIdsRaw);
1674
1675 if (articlesIds.Count > 0)
1676 {
1677 hasActiveArticles = articlesIds.Any(x => new PageService().GetPage(x).Active);
1678 }
1679 }
1680
1681 if (!string.IsNullOrEmpty(articleSubGroupIdsRaw))
1682 {
1683 var subCategoryIds = GetIds(articleSubGroupIdsRaw);
1684
1685 List<string> subCategoryNames = new List<string>();
1686
1687 foreach (int subCategoryId in subCategoryIds)
1688 {
1689 var subCategory = new PageService().GetPage(subCategoryId);
1690 if (subCategory != null)
1691 {
1692 subCategoryNames.Add(subCategory.GetDisplayName());
1693 }
1694 }
1695
1696 foreach (string subCategoryName in subCategoryNames)
1697 {
1698 try
1699 {
1700 var subCategoryArticles = new PageService().GetPagesForItems(new List<string> { "UniverseArticlePage" }).Where(x => x.Item["SubCategories"].ToString().Contains(subCategoryName));
1701 if (subCategoryArticles.Any(x => x.Active))
1702 {
1703 hasActiveArticles = true;
1704 }
1705 }
1706 catch
1707 {
1708 }
1709 }
1710 }
1711 }
1712
1713 if (hasActiveArticles)
1714 {
1715 string articlesHeader = "";
1716 articlesHeader = defaultGroup.ProductGroupFieldValues.GetProductGroupFieldValue("ArticlesHeader").Value.ToString();
1717
1718 if (string.IsNullOrEmpty(articlesHeader))
1719 {
1720 articlesHeader = Translate("ProductViewArticleHeader");
1721 }
1722
1723 var paragraph = new ParagraphService().GetParagraphsByPageId(articlesPageId).FirstOrDefault();
1724
1725 if (paragraph != null)
1726 {
1727 <div class="row" style="margin-top: 15px">
1728 <div class="col-xs-12 p-15 p-md-0">
1729 <h2 class="product__header product__header--mobile-center articles">@articlesHeader</h2>
1730 </div>
1731
1732 </div>
1733
1734 <div class="row-25">
1735 @RenderParagraphContent(paragraph.ID)
1736 </div>
1737 }
1738 }
1739 }
1740
1741
1742 <div class="row p-15 p-md-0" style="margin-top: 15px">
1743 <!-- display block in clerk.js if at least one product -->
1744 <h2 class="product__header product__header--mobile-center" id="product-header-clerk" style="display: block;">Ofte købt sammen med</h2>
1745 <span class="clerk"
1746 data-template="@@product-page-others-also-bought"
1747 data-products='["@GetString("Ecom:Product.ID")"]'>
1748 </span>
1749 </div>
1750
1751
1752 <div class="row">
1753 <div class="col-md-12 col-sm-12 col-xs-12"> </div>
1754 </div>
1755
1756 @{
1757 var priceInitial = prices.Where(x => x.GetString("Ecom:Product.Prices.UnitID").Equals(unitDefault.Id)).OrderBy(x => x.GetDouble("Ecom:Product.Prices.Quantity")).FirstOrDefault();
1758
1759 CultureInfo us = new CultureInfo("en-US");
1760 string datalayerPriceInitial = string.Empty;
1761 if (priceInitial != null && Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName")))
1762 {
1763 datalayerPriceInitial = priceInitial.GetDouble("Ecom:Product.Prices.Amount").ToString("n", us).Replace(",", "");
1764 }
1765
1766 var pricesJs = new List<Dynamicweb.Ecommerce.LiveIntegration.Products.ProductPrice>();
1767 foreach (var priceJs in prices)
1768 {
1769 var productPrice = new Dynamicweb.Ecommerce.LiveIntegration.Products.ProductPrice();
1770 productPrice.BaseUnitPrice = priceJs.GetDouble("Ecom:Product.Prices.BaseUnitPrice");
1771 productPrice.PriceQuantityPerUnit = priceJs.GetDouble("Ecom:Product.Prices.PriceQuantityPerUnit");
1772 productPrice.Quantity = priceJs.GetDouble("Ecom:Product.Prices.Quantity");
1773 productPrice.UnitId = priceJs.GetString("Ecom:Product.Prices.UnitID");
1774 pricesJs.Add(productPrice);
1775 }
1776 }
1777
1778 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ScriptsBottom")))
1779 {
1780 @SnippetStart("JavaScriptBottom")
1781 @GetString("Ecom:Product:Field.ScriptsBottom")
1782 @SnippetEnd("JavaScriptBottom")
1783 }
1784
1785 <script>
1786 var pricesJs = JSON.parse('@Newtonsoft.Json.JsonConvert.SerializeObject(pricesJs)');
1787
1788 // Create our number formatter.
1789 var formatterUs = new Intl.NumberFormat('en-US', {
1790 minimumFractionDigits: 2,
1791 });
1792
1793
1794
1795
1796 $('.product__addtocart-button').on('click', function () {
1797
1798 var quantityAdded = parseInt($(this).parent().prev().find('input.quantity').val());
1799 var unitAdded = $(this).parent().prev().find('select.unit').val();
1800 var priceFound = null;
1801 for (const key in pricesJs) {
1802 if (pricesJs[key].UnitId == unitAdded && quantityAdded >= parseInt(pricesJs[key].Quantity)){
1803 priceFound = pricesJs[key];
1804 }
1805 }
1806
1807 var priceAdded = 0;
1808 if (priceFound != null) {
1809 priceAdded = (priceFound.BaseUnitPrice * priceFound.PriceQuantityPerUnit) * quantityAdded; }
1810
1811 var quantity = document.getElementsByClassName("product__quantity-input")[0].value;
1812 var unitTypes = document.getElementsByClassName("unit-type");
1813 var isVariantNull = true;
1814
1815 var index = 0;
1816 var unitPrice;
1817 var currentUnitName;
1818 for (const button of unitTypes){
1819
1820 if (button.checked != false)
1821 {
1822 isVariantNull = false;
1823 var tempPrice = button.dataset.price.replace(".","");
1824 tempPrice = tempPrice.replace(",",".");
1825 unitPrice = parseFloat(tempPrice);
1826 currentUnitName = button.value.split("_")[1];
1827 index++;
1828 }
1829 }
1830
1831 if (!isVariantNull)
1832 {
1833 dataLayer.push({ecommerce:null});
1834 dataLayer.push({
1835 'event': 'add_to_cart',
1836 "ecommerce":{
1837 "currency" : "@GetString("Ecom:Product.CurrencyCode")",
1838 "value" : unitPrice * (parseInt(quantity)).toFixed(2),
1839 "items":[
1840 {
1841 "item_name": "@GetString("Ecom:Product.Name")" + " - " + currentUnitName,
1842 'item_id': '@GetString("Ecom:Product.ID")',
1843 'price': unitPrice,
1844 "item_brand" : "",
1845 "item_category": (categories[0] != null ? categories[0] : ""),
1846 "item_category2": (categories[1] != null ? categories[1] : ""),
1847 "item_category3": (categories[2] != null ? categories[2] : ""),
1848 "item_category4": (categories[3] != null ? categories[3] : ""),
1849 "item_category5": (categories[4] != null ? categories[4] : ""),
1850 "quantity": parseInt(quantity),
1851 }
1852 ]
1853 },
1854
1855 });
1856 }
1857
1858 });
1859
1860 //Sets the unittype if only one unittype for the product exists
1861 var types = document.getElementsByClassName("unit-type");
1862 var currentUnitName;
1863
1864 if (types.length === 1){
1865 currentUnitName = " - " + (types[0].value.split("_")[1]);
1866
1867 }
1868 else{
1869 currentUnitName = "";
1870 }
1871
1872
1873 var initialCategories = document.getElementsByClassName("page-header__title")[0].dataset.categories;
1874 var categories = initialCategories.split("_");
1875
1876
1877 if (types.length === 1){
1878
1879 var currentUnitPrice = 0;
1880 var tempPrice = types[0].dataset.price.replace(".","");
1881 tempPrice = tempPrice.replace(",",".");
1882 currentUnitPrice = parseFloat(tempPrice);
1883
1884 // View_item initial, if only one unit type exists
1885 dataLayer.push({ecommerce:null});
1886 dataLayer.push({
1887 'event': 'view_item',
1888 "ecommerce":{
1889 "currency" : "@GetString("Ecom:Product.CurrencyCode")",
1890 "value" : currentUnitPrice,
1891 "items":[
1892 {
1893 "item_name": "@GetString("Ecom:Product.Name")" + currentUnitName,
1894 'item_id': '@GetString("Ecom:Product.ID")',
1895 'price': currentUnitPrice,
1896 "item_brand" : "",
1897 "item_category": (categories[0] != null ? categories[0] : ""),
1898 "item_category2": (categories[1] != null ? categories[1] : ""),
1899 "item_category3": (categories[2] != null ? categories[2] : ""),
1900 "item_category4": (categories[3] != null ? categories[3] : ""),
1901 "item_category5": (categories[4] != null ? categories[4] : ""),
1902 "quantity": 1,
1903
1904 }
1905 ]
1906 },
1907
1908 });
1909 }
1910
1911
1912 var unitTypes = document.getElementsByClassName("unit-type");
1913
1914 var price;
1915 var oldPrice;
1916
1917 for (const btn of unitTypes)
1918 {
1919 btn.addEventListener("click", function () {
1920
1921
1922 tempPrice = this.dataset.price.replace(".","");
1923 tempPrice = tempPrice.replace(",",".");
1924 price = parseFloat(tempPrice);
1925
1926 currentUnitName = btn.value.split("_")[1];
1927
1928 //checks to see if the new variant is the same as the old one
1929 if (price != oldPrice){
1930
1931 dataLayer.push({ecommerce:null});
1932 dataLayer.push({
1933 'event': 'view_item',
1934 "ecommerce":{
1935 "currency" : "@GetString("Ecom:Product.CurrencyCode")",
1936 "value" : price,
1937 "items":[
1938 {
1939 "item_name": "@GetString("Ecom:Product.Name")" + " - " + currentUnitName,
1940 'item_id': '@GetString("Ecom:Product.ID")',
1941 'price': price,
1942 "item_brand" : "",
1943 "item_category": (categories[0] != null ? categories[0] : ""),
1944 "item_category2": (categories[1] != null ? categories[1] : ""),
1945 "item_category3": (categories[2] != null ? categories[2] : ""),
1946 "item_category4": (categories[3] != null ? categories[3] : ""),
1947 "item_category5": (categories[4] != null ? categories[4] : ""),
1948 "quantity": 1,
1949
1950 }
1951 ]
1952 },
1953
1954 });
1955
1956 }
1957 oldPrice = price;
1958 })
1959 }
1960
1961 </script>
1962
1963 @SnippetStart("JavaScriptBottom")
1964 <script type="text/javascript" src="~/Files/Templates/Designs/Dwsimple/js/video-api.js"></script>
1965
1966 @if (currentUser != null)
1967 {
1968 <script type="text/javascript" src="~/Files/Templates/Designs/Dwsimple/js/clerk.js"></script>
1969 }
1970
1971 <script>
1972 function on() {
1973 document.getElementById("overlay").style.display = "block";
1974 callPlayer('product-video', 'playVideo');
1975 }
1976 function off() {
1977 document.getElementById("overlay").style.display = "none";
1978 callPlayer('product-video', 'pauseVideo');
1979 }
1980 function updateDetailAccessibility(button) {
1981
1982 //set wrapper equal to first child of button with class product__section-container__icon-wrapper
1983 wrapper = button.parentElement.parentElement.querySelector('.product__section-container__icon-wrapper');
1984
1985
1986 var content = document.querySelector('.product__details__content[data-content-id="' + wrapper.getAttribute('data-content-id') + '"]');
1987 var defaultHeight = wrapper.getAttribute("data-height");
1988
1989 if (content.style.maxHeight == defaultHeight) {
1990 content.style.maxHeight = content.scrollHeight + "px";
1991 } else {
1992 content.style.maxHeight = defaultHeight;
1993 }
1994
1995 var icons = wrapper.querySelectorAll('.product__section-container__icon');
1996 icons.forEach(function(icon) {
1997 icon.style.display = icon.style.display === 'none' ? 'block' : 'none';
1998 });
1999
2000 }
2001
2002 </script>
2003
2004 @SnippetEnd("JavaScriptBottom")
2005
2006 @functions {
2007
2008 public static string StripHTML(string input)
2009 {
2010 var doc = new HtmlDocument();
2011 doc.LoadHtml(input);
2012 return doc.DocumentNode.InnerText;
2013 }
2014
2015 }
2016
2017
2018 <style>
2019
2020 .product__details {
2021 position: relative;
2022 margin-top: 10px;
2023 margin-bottom: 10px;
2024 p {
2025 margin: 0;
2026 width: fit-content;
2027 }
2028 a:hover{
2029 cursor: pointer;
2030 }
2031
2032 .product__details__content {
2033
2034
2035 overflow: hidden;
2036 transition: max-height 0.3s ease;
2037 }
2038
2039 }
2040
2041
2042 </style>