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]| ", " ");
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"> </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>