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