Error executing template "Designs/Rapido/eCom/Product/NZProductView.cshtml" System.IO.PathTooLongException: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters. at System.IO.PathHelper.GetFullPathName() at System.IO.Path.LegacyNormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths) at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths) at System.IO.Path.GetFullPathInternal(String path) at System.IO.FileInfo.Init(String fileName, Boolean checkHost) at System.IO.FileInfo..ctor(String fileName) at S_DW_Lauridsen.CustomCode.DocumentInfo.FileInformation(String docCol) at CompiledRazorTemplates.Dynamic.RazorEngine_3da4bf5a350247bdbde3ca7be13b3aaa.Execute() in E:\Solutions\S_DW_Lauridsen\lauridsen-live\Files\Templates\Designs\Rapido\eCom\Product\NZProductView.cshtml:line 37 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.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 RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 @using Dynamicweb.Extensibility 3 @using Dynamicweb.Content 4 @using System; 5 @using System.Globalization; 6 @using System.Linq 7 @using System.IO 8 @using Dynamicweb.Core 9 @using System.Web 10 @using Dynamicweb.Ecommerce 11 @using Dynamicweb.Ecommerce.Discounts 12 @using Dynamicweb.Ecommerce.Orders.Discounts 13 @using Dynamicweb.Ecommerce.Products 14 @using Dynamicweb.Ecommerce.Prices 15 @using NLog; 16 @using S_DW_Lauridsen.CustomCode 17 @using Dynamicweb.Security.UserManagement 18 @using NuGet.Versioning 19 @{ 20 21 string favoritPage = String.Format("/Default.aspx?ID={0}&CC20=CreateFormList", GetPageIdByNavigationTag("CustomerFavorites").ToString()); 22 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 23 string productId = GetString("Ecom:Product.ID"); 24 string uniqueId = GetString("Ecom:Product.ID") + GetString("Ecom:Product.VariantID"); 25 // Stock status 26 int stockAmount = GetInteger("Ecom:Product.AvailableAmount"); 27 string currentPrice = GetString("Ecom:Product.Discount.Price.PriceFormatted") == GetString("Ecom:Product.Price.PriceFormatted") ? GetString("Ecom:Product.Price.PriceFormatted") : GetString("Ecom:Product.Discount.Price.PriceFormatted"); 28 string hideHelpText = ""; 29 string requestQuery = GetGlobalValue("Global:Request.Query"); 30 string variantId = HttpContext.Current.Request.QueryString.Get("variantId"); 31 string feedId = pageId + "&ProductID=" + productId + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 32 //CFP bool 33 bool cfp = GetBoolean("Ecom:Product:Field.CFP"); 34 35 // Documents 36 string documentValue = GetString("Ecom:Product:Field.PDF_Path"); 37 var results = DocumentInfo.FileInformation(documentValue); 38 39 40 string externalLink = GetValue("Ecom:Product:Field.ExternalLinks.Value").ToString(); 41 var testList = externalLink.Split(new string[] { "</p>" }, StringSplitOptions.RemoveEmptyEntries).ToList(); 42 43 44 45 int featuresCount = 0; 46 string brand = GetString("Ecom:Product:Field.brand"); 47 bool onlyPreviewForAnonymousUsers = Pageview.AreaSettings.GetBoolean("OnlyPreviewForAnonymous"); 48 bool onlyPreview = onlyPreviewForAnonymousUsers ? Pageview.User == null : false; 49 50 foreach (LoopItem customField in GetLoop("CustomFieldValues")) 51 { 52 if (!String.IsNullOrEmpty(customField.GetString("Product.CustomField.Value.Clean")) && customField.GetString("Product.CustomField.Name") != "CustomSticker") 53 { 54 featuresCount++; 55 } 56 } 57 58 foreach (LoopItem customField in GetLoop("ProductCategories")) 59 { 60 foreach (LoopItem field in customField.GetLoop("ProductCategoryFields")) 61 { 62 if (!String.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Value"))) 63 { 64 featuresCount++; 65 } 66 } 67 } 68 69 foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 70 { 71 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions")) 72 { 73 if (variantoption.GetBoolean("Ecom:VariantOption.Selected")) 74 { 75 hideHelpText = "u-hidden"; 76 } 77 } 78 } 79 80 int relatedProductsPageSize = 4; 81 int relatedProductsColumnWidth = 3; 82 83 if (Pageview.Device.ToString() == "Mobile") 84 { 85 relatedProductsPageSize = 1; 86 relatedProductsColumnWidth = 12; 87 } 88 89 if (Pageview.Device.ToString() == "Tablet") 90 { 91 relatedProductsPageSize = 3; 92 relatedProductsColumnWidth = 4; 93 } 94 95 string pageNavTag = GetPageIdByNavigationTag("ProductsPage").ToString(); 96 string feedFullUrl = String.Format("/Default.aspx?ID={0}&PageSize={1}&ProdID={2}&feed=true", pageNavTag, relatedProductsPageSize, productId); 97 string relatedProductsFeed = String.Format("/Default.aspx?ID={0}&PageSize={1}&ProdID={2}&feed=true&RelateredeProdukter=", pageNavTag, relatedProductsPageSize, productId); 98 string productContainerId = "Product" + productId; 99 string video = GetString("Ecom:Product:Field.video"); 100 string siteURL = Dynamicweb.Context.Current.Request.Url.Scheme + "://" + Dynamicweb.Context.Current.Request.Url.Host; 101 Dynamicweb.Ecommerce.Products.Product currentProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(GetString("Ecom:Product.ID"), GetString("Ecom:Product.VariantID"), GetString("Ecom:Product.LanguageID")); 102 var imagePathValue = Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(currentProduct, "ImagePath"); 103 string imagePath = !string.IsNullOrWhiteSpace(imagePathValue.ToString()) ? "/Files/Images/Ecom/LHI_Products/Images/" + imagePathValue + ".jpg" : ""; 104 string productImage = !string.IsNullOrWhiteSpace(imagePath) ? imagePath : GetString("Ecom:Product.ImageLarge.Default.Clean"); 105 string canonicalURL = GetString("Ecom:Product.Canonical"); 106 string vismaUnitName = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.Enhed")) ? GetString("Ecom:Product:Field.Enhed")?.ToLower() : Translate("UnitPriceTextStk"); 107 108 //gallery 109 int imagesCount = 1; 110 List<string> galleryImages = new List<string>(); 111 112 galleryImages.Add(productImage); 113 if (!string.IsNullOrWhiteSpace(video)) 114 { 115 foreach (var image in video.Split('|')) 116 { 117 string videoThumb = String.Format("https://img.youtube.com/vi/{0}/0.jpg", image); 118 galleryImages.Add(videoThumb); 119 imagesCount++; 120 } 121 } 122 123 foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 124 { 125 if (!String.IsNullOrEmpty(alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"))) 126 { 127 string fullImage = "/Admin/Public/GetImage.ashx?width=550&height=550&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=" + alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 128 galleryImages.Add(fullImage); 129 imagesCount++; 130 } 131 } 132 133 foreach (LoopItem detail in GetLoop("Details")) 134 { 135 string fullImage = "/Admin/Public/GetImage.ashx?width=550&height=550&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=" + detail.GetString("Ecom:Product:Detail.Image.Clean"); 136 137 if (!String.IsNullOrEmpty(fullImage)) 138 { 139 galleryImages.Add(fullImage); 140 imagesCount++; 141 } 142 } 143 144 string firstImage = galleryImages.FirstOrDefault(); 145 string galleryImagesArray = string.Join(", ", galleryImages); 146 } 147 148 @* Set product canonical URL *@ 149 @SnippetStart("canonical") 150 @{ 151 string host = GetGlobalValue("Global:Request.Host"); 152 string url = GetGlobalValue("Global:Pageview.Url"); 153 int queryIndex = url.IndexOf("?", StringComparison.Ordinal); 154 if (queryIndex > -1) 155 { 156 url = url.Substring(0, queryIndex); 157 } 158 } 159 <link rel="canonical" href="https://@host@url"> 160 @SnippetEnd("canonical") 161 <!-- Trigger for the gallery modal --> 162 <input type="checkbox" id="GalleryModalTrigger" class="modal-trigger" /> 163 164 <!-- Gallery modal --> 165 <div class="modal-container"> 166 <label for="GalleryModalTrigger" id="GalleryModalOverlay" class="modal-overlay"></label> 167 <div class="modal modal--lg modal--full modal-no-bg" id="GalleryModal"> 168 <div class="modal__body"> 169 <div class="gallery-slider js-gallery-slider" data-total-images="@imagesCount" data-images="@galleryImagesArray"> 170 <div class="gallery-slider__image" data-icon-nz="play"> 171 <img id="FullImage" src="@firstImage" class="w-100 js-video-button js-gallery-image" /> 172 </div> 173 <div class="gallery-slider__image-counter" id="FullImage_counter"> 174 </div> 175 <label class="gallery-slider__close-btn" for="GalleryModalTrigger"></label> 176 177 @if (imagesCount > 1) 178 { 179 <button class="gallery-slider__previous-btn" id="FullImage_prev" onclick="Gallery.prevImage('FullImage')"></button> 180 <button class="gallery-slider__next-btn" id="FullImage_next" onclick="Gallery.nextImage('FullImage')"></button> 181 } 182 183 </div> 184 </div> 185 </div> 186 </div> 187 188 <div class="paragraph-container__grid--bleed-x paragraph-container__grid--bleed-y product-view"> 189 <div class="grid product js-product" id="productGrid"> 190 @* Image block with optional thumbs *@ 191 @if (!String.IsNullOrEmpty(productImage)) 192 { 193 <div class="grid__col-md-6 grid__col-sm-6"> 194 <div class="grid grid--bleed product-slider"> 195 @{ 196 int thumbCounter = 0; 197 } 198 <div class="grid__col-2 product-slider__thumbnails dw-mod "> 199 <div class="carousel js-carousel-container u-max-h500px dw-mod"> 200 <div class="thumb-list carousel__container dw-mod m-0"> 201 <div class="carousel__container__slide carousel__container__slide--vertical product-slider__inner dw-mod"> 202 203 @*Main image thumb*@ 204 <div class="carousel__container__slide product-slider__slide dw-mod"> 205 <div class="thumb-list__item thumb-list__item--active dw-mod js-thumb js-thumb-btn js-gallery" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="/Admin/Public/GetImage.ashx?width=550&height=550&crop=5&DoNotUpscale=true&Compression=75&image=@productImage"> 206 <label for="GalleryModalTrigger"> 207 <img src="/Admin/Public/GetImage.ashx?width=100&height=100&crop=5&DoNotUpscale=true&Compression=75&image=@productImage" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="/Admin/Public/GetImage.ashx?width=550&height=550&crop=5&DoNotUpscale=true&Compression=75&image=@productImage"> 208 </label> 209 </div> 210 </div> 211 212 @{ thumbCounter++; } 213 214 @foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 215 { 216 if (!String.IsNullOrEmpty(alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"))) 217 { 218 string image = "/Admin/Public/GetImage.ashx?width=550&height=550&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=" + alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 219 string thumb = "/Admin/Public/GetImage.ashx?width=100&height=100&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=" + alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 220 221 <div class="carousel__container__slide product-slider__slide dw-mod"> 222 <div class="thumb-list__item dw-mod js-thumb-btn js-thumb js-gallery" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="@image"> 223 <label for="GalleryModalTrigger"> 224 <img src="@thumb" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="@image" data-src="@image"> 225 </label> 226 </div> 227 </div> 228 thumbCounter++; 229 } 230 } 231 232 @foreach (var youtubeLink in video.Split('|')) 233 { 234 if (!String.IsNullOrEmpty(youtubeLink)) 235 { 236 string image = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink.Split('?')); 237 string thumb = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink.Split('?')); 238 239 <div class="carousel__container__slide product-slider__slide dw-mod"> 240 <a class="d-block thumb-list__item has-video dw-mod js-thumb js-thumb-btn js-video-button js-gallery" data-icon-nz="play" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="@image" href="@youtubeLink" data-type="youtube" data-toggle="modal"> 241 <label for="GalleryModalTrigger"> 242 <img src="@thumb" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="@image" data-src="@image" data-cookieconsent="ignore"> 243 </label> 244 </a> 245 </div> 246 thumbCounter++; 247 } 248 } 249 250 @foreach (LoopItem detail in GetLoop("Details")) 251 { 252 if (!String.IsNullOrEmpty(detail.GetString("Ecom:Product:Detail.Image.Clean"))) 253 { 254 string image = "/Admin/Public/GetImage.ashx?width=550&height=550&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=" + detail.GetString("Ecom:Product:Detail.Image.Clean"); 255 string thumb = "/Admin/Public/GetImage.ashx?width=100&height=100&crop=5&FillCanvas=True&DoNotUpscale=true&Compression=75&image=" + detail.GetString("Ecom:Product:Detail.Image.Clean"); 256 257 <div class="carousel__container__slide product-slider__slide dw-mod"> 258 <div class="thumb-list__item dw-mod js-thumb-btn js-thumb js-gallery" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="@image"> 259 <label for="GalleryModalTrigger"> 260 <img src="@thumb" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="@image" data-src="@image"> 261 </label> 262 </div> 263 </div> 264 thumbCounter++; 265 } 266 } 267 </div> 268 </div> 269 270 <div class="js-carousel-data" data-total-slides="@(imagesCount + 1)" data-carousel-slide-time="0" data-current-slide="0" data-direction="vertical" data-sliding-type="items" slides-in-view="6"> 271 <div class="carousel-prev-btn carousel-prev-btn--vertical dw-mod" onclick="Carousel.GetPreviousSlide(this)"></div> 272 <div class="carousel-next-btn carousel-next-btn--vertical dw-mod" onclick="Carousel.GetNextSlide(this)"></div> 273 </div> 274 275 </div> 276 </div> 277 278 <div class="grid__col-10 product-slider__large-image"> 279 <div class="stickers-container dw-mod"> 280 @{ 281 if (Converter.ToBoolean(Pageview.Area.Item["EnableSaleTags"])) 282 { 283 string contentType = Pageview.Area.Item["EcommerceSaleTagContentType"].ToString(); 284 string text = ""; 285 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 286 287 switch (contentType) 288 { 289 case "Name": 290 foreach (LoopItem discount in GetLoop("ProductDiscounts")) 291 { 292 text = discount.GetString("Ecom:Product.Discount.Name"); 293 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 294 } 295 break; 296 case "Amount": 297 if (GetLoop("ProductDiscounts").Count > 0) 298 { 299 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.Price") - GetDouble("Ecom:Product.Price.Price")); 300 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 301 } 302 break; 303 case "Percents": 304 double percents = 0; 305 foreach (LoopItem discount in GetLoop("ProductDiscounts")) 306 { 307 if (discount.GetDouble("Ecom:Product.Discount.ProductQuantity").Equals(1)) 308 { 309 percents = discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 310 } 311 } 312 if (percents > 0) 313 { 314 text = Math.Round(percents, 0) + "%"; 315 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 316 } 317 break; 318 case "Amount and percents": 319 double amount = 0; 320 double percent = 0; 321 foreach (LoopItem discount in GetLoop("ProductDiscounts")) 322 { 323 if (discount.GetString("Ecom:Product.Discount.Type") == "PERCENT") 324 { 325 percent += discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 326 } 327 else if (discount.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 328 { 329 amount += discount.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 330 } 331 } 332 if (percent > 0) 333 { 334 text = percent + "%"; 335 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 336 } 337 if (amount > 0) 338 { 339 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 340 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 341 } 342 break; 343 default: 344 if (GetLoop("ProductDiscounts").Count > 0) 345 { 346 text = Translate("Sale!"); 347 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 348 } 349 break; 350 } 351 } 352 353 if (Converter.ToBoolean(Pageview.Area.Item["NewStickersEnable"]) && GetDate("Ecom:Product.Created").AddDays(Converter.ToDouble(Pageview.Area.Item["NewStickersExpiration"])) > DateTime.Now) 354 { 355 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div> 356 } 357 358 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value"))) 359 { 360 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div> 361 } 362 } 363 </div> 364 365 <label for="GalleryModalTrigger" class="product__image-container"> 366 <img class="thumb-image-view product__image-container__image js-gallery-slider js-video-button dw-mod" src="/Admin/Public/GetImage.ashx?crop=5&width=550&height=550&Compression=75&image=@productImage" data-current-image="0" data-total-images="@imagesCount" data-images="@galleryImagesArray" data-src="/Admin/Public/GetImage.ashx?crop=5&width=550&height=550&Compression=75&image=@productImage" alt="@GetString("Ecom:Product.Name")" id="Image_@productId" data-for="FullImage" data-number="0" onclick="Gallery.openImageByNum(this)" /> 367 </label> 368 369 </div> 370 </div> 371 </div> 372 } 373 374 @* Primary product informations *@ 375 <div class="grid__col-12 grid__col-md-6 product__info dw-mod"> 376 <div> 377 <h1 class="product__title u-no-margin">@GetString("Ecom:Product.Name") @GetString("Ecom:Product.SelectedVariantComboName")</h1> 378 <small class="x-small text-gray-light font-weight-light">@(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.Brand")) ? String.Format("{0}: {1}", Translate("Manufacturer"), GetString("Ecom:Product:Field.Brand")) : "") @Translate("product number"): @GetString("Ecom:Product.Number") @(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.VVSNumber")) ? String.Format("{0}: {1}", Translate("VVS nr."), GetString("Ecom:Product:Field.VVSNumber")) : "") @(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.DBN")) ? String.Format("{0}: {1}", Translate("DB nr."), GetString("Ecom:Product:Field.DBN")) : "") </small> 379 <div> 380 @* Delivery + stock information *@ 381 @if (onlyPreview) 382 { 383 <div> 384 <h5 class="mb-2">@Translate("LoginText", "Login")</h5> 385 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod" onclick="setTimeout(function() { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 386 </div> 387 } 388 389 @* Variants *@ 390 @*@if (GetLoop("VariantGroups").Count > 0) 391 { 392 string containerId = "Variants" + productId; 393 394 <div> 395 <div id="@containerId" data-product-id="@productId"> 396 @foreach (LoopItem variantGoup in GetLoop("VariantGroups")) 397 { 398 <div> 399 <div class="u-bold">@variantGoup.GetString("Ecom:VariantGroup.Name")</div> 400 <div> 401 @foreach (LoopItem variantOption in variantGoup.GetLoop("VariantAvailableOptions")) 402 { 403 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 404 405 if (!string.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.ImgSmall.Clean"))) 406 { 407 <img src="/Admin/Public/GetImage.ashx?width=100&height=50&crop=5&Compression=75&image=/Images/@variantOption.GetString("Ecom:VariantOption.ImgSmall.Clean")" title="@variantOption.GetString("Ecom:VariantOption.Name")" id="@productId@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-product-id="@productId" onclick="Variants.UpdateVariants(this, false, true)" class="btn btn--tag @selected" data-check="@selected" /> 408 } 409 else 410 { 411 <button type="button" data-id="@GetString("Ecom:Product.ID")" id="@productId@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-product-id="@productId" onclick="Variants.UpdateVariants(this, false, true)" class="btn btn--tag @selected" data-check="@selected">@variantOption.GetString("Ecom:VariantOption.Name")</button> 412 } 413 } 414 </div> 415 </div> 416 } 417 </div> 418 <small id="helpText_@productId" class="help-text @hideHelpText">@Translate("Please select variant!")</small> 419 </div> 420 }*@ 421 @if (GetLoop("VariantGroups").Count > 0) 422 { 423 var variantCombinationsObject = new List<Array>(); 424 foreach (LoopItem variantcomb in GetLoop("VariantStockCombinations")) 425 { 426 string[] combinations = variantcomb.GetString("Ecom:VariantStockCombination.VariantID").Split('.'); 427 variantCombinationsObject.Add(combinations); 428 } 429 430 string combinationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantCombinationsObject).Replace("\"", "\'"); 431 432 var variantGroupsObject = new List<List<String>>(); 433 var selectedItem = new Dictionary<string, string>(); 434 string variantSelection = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("variantId")) ? HttpContext.Current.Request.QueryString.Get("variantId").Replace(".", ",") : ""; 435 436 var selectedText = Translate("Select variant"); 437 438 foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 439 { 440 var variantsObject = new List<String>(); 441 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 442 { 443 variantsObject.Add(variantOption.GetString("Ecom:VariantOption.ID")); 444 445 446 if (variantOption.GetBoolean("Ecom:VariantOption.Selected")) 447 { 448 selectedItem.Add(variantGroup.GetString("Ecom:VariantGroup.ID"), variantOption.GetString("Ecom:VariantOption.Name")); 449 } 450 } 451 variantGroupsObject.Add(variantsObject); 452 } 453 string variantsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantGroupsObject).Replace("\"", "\'"); 454 string productGroupId = HttpContext.Current.Request["GroupId"]; 455 int variantCounter = 0; 456 457 <div class="variants-container"> 458 <div class="js-variants" data-total-variant-groups="@GetLoop("VariantGroups").Count" data-combinations="@combinationsJson" data-variants="@variantsJson" data-selection-complete="UpdatePage" data-page-id="@pageId" data-product-id="@productId" data-group-id="@productGroupId"> 459 @foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 460 { 461 string groupId = variantGroup.GetString("Ecom:VariantGroup.ID"); 462 variantCounter++; 463 <div class="dropdown-container u-margin-bottom--lg"> 464 <div class="product__variant-group-name u-margin-bottom-5px dw-mod">@variantGroup.GetString("Ecom:VariantGroup.Name")</div> 465 <div class="display-value" id="displayValue-@variantCounter" onclick="toggleOptions('selectContainer-@variantCounter')"> 466 <span class="value-text" id="valueText-@variantCounter">@(selectedItem.ContainsKey(variantGroup.GetString("Ecom:VariantGroup.ID")) ? selectedItem[variantGroup.GetString("Ecom:VariantGroup.ID")] : selectedText)</span> 467 <span class="arrow arrow-down" id="arrowControl"></span> 468 </div> 469 <ul tabindex="0" class="select-container" id="selectContainer-@variantCounter" onblur="toggleOptions('selectContainer-@variantCounter')"> 470 @foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 471 { 472 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 473 474 475 476 <li value="@variantOption.GetString("Ecom:VariantOption.ID")" 477 type="button" 478 data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" 479 onclick="MatchVariants.SelectThis(event), selected('@variantOption.GetString("Ecom:VariantOption.Name")','valueText-@variantCounter', 'selectContainer-@variantCounter')" 480 data-variant-group="@groupId" 481 class="btn btn--tag @selected js-variant-option select-option" 482 data-check="@selected">@variantOption.GetString("Ecom:VariantOption.Name")</li> 483 } 484 </ul> 485 </div> 486 } 487 </div> 488 </div> 489 } 490 491 @* BOMProducts *@ 492 @if (GetLoop("BOMProducts").Count > 0) 493 { 494 <h2 class="section-title">@Translate("Including products")</h2> 495 foreach (LoopItem BOMProductItem in GetLoop("BOMProducts")) 496 { 497 string link = "/" + BOMProductItem.GetString("Ecom:Product.LinkGroup.Clean") + (!String.IsNullOrEmpty(BOMProductItem.GetString("Ecom:Product.VariantID")) ? "&VariantID=" + BOMProductItem.GetString("Ecom:Product.VariantID") : ""); 498 <div class="grid__col--border grid"> 499 <div class="grid__cell grid__cell--align-middle-left"> 500 <a href="@link" class="u-pull--left u-margin-right"> 501 <img src="/Admin/Public/GetImage.ashx?width=50&image=@BOMProductItem.GetString("Ecom:Product.ImageSmall.Default.Clean")&Compression=99" /> 502 </a> 503 <a href="@link">@BOMProductItem.GetString("Ecom:Product.Name")</a> 504 </div> 505 </div> 506 } 507 } 508 </div> 509 </div> 510 511 @* Buy block *@ 512 <div class="w-100 mt-5"> 513 <div class="js-handlebars-root dw-mod" id="PriceAndActions" data-template="PricesAndActionsTemplate" data-json-feed="/Default.aspx?ID=@feedId"></div> 514 <input type="hidden" value="@GetString("Ecom:Product.VariantID.Extented")" name="Variant" id="Variant_@GetString("Ecom:Product.ID")" /> 515 </div> 516 <div class="mt-4">@GetString("Ecom:Product:Field.LongDescription")</div> 517 <div class="product-page__specs">@ProductPropertiesMainArea()</div> 518 </div> 519 </div> 520 521 <section class="product-page__product-info"> 522 <div class="grid__col-12 grid__col-lg-9 m-auto"> 523 <div class="nav nav-pills nav-justified"> 524 <a class="nav-item nav-link js-toggle-class js-toggle-retrigger is-active" data-target-retrigger="target-retrigger" data-target=".product-page__content--description">@Translate("Product information")</a> 525 <a class="nav-item nav-link js-toggle-class js-toggle-retrigger" data-target-retrigger="target-retrigger" data-target=".product-page__content--video">@Translate("Documents/Video")</a> 526 <a class="nav-item nav-link js-toggle-class js-toggle-retrigger" data-target-retrigger="target-retrigger" data-target=".product-page__content--accessories">@Translate("Accessories")</a> 527 </div> 528 </div> 529 530 <div class="grid__col-12 grid__col-lg-10 m-auto grid__col--bleed-x"> 531 <div class="grid product-page__content product-page__content--description js-toggle-retrigger is-active"> 532 @* Features lists *@ 533 <div class="grid__col-12 grid__col-md-6 product__features dw-mod"> 534 <h1 class="h3 section-title">@Translate("Product information")</h1> 535 @GetString("Ecom:Product.LongDescription") 536 @GetString("Ecom:Product:Field.description") 537 </div> 538 <div class="grid__col-12 grid__col-md-6 product__features dw-mod"> 539 <h1 class="h3 section-title">@Translate("Product specs")</h1> 540 <div class="product-page__specs">@ProductProperties()</div> 541 </div> 542 </div> 543 <div class="grid product-page__content product-page__content--video js-toggle-retrigger justify-content-center"> 544 <div class="grid__col-12 grid__col-md-8 p-0 p-md-4"> 545 <h1 class="h3 section-title">@Translate("Documents/Video")</h1> 546 <div class="table-responsive small order-list"> 547 <table class="table table-striped product-page-table"> 548 <thead> 549 <tr> 550 <th class="font-weight-bold border-bottom-0" scope="col">@Translate("Name")</th> 551 <th class="font-weight-bold border-bottom-0" scope="col">@Translate("Type")</th> 552 <th class="font-weight-bold border-bottom-0" scope="col">@Translate("Size")</th> 553 </tr> 554 </thead> 555 <tbody> 556 557 @foreach (var documentPath in results) 558 { 559 <tr> 560 <td scope="row"> 561 <a href="@documentPath.FilePath" target="_blank"> 562 <img src="/Files/Images/Lauridsen/icons/icon-pdf.svg" class="product-page-table__icon d-inline-block align-middle mr-3" alt="@documentPath.FileName" /> 563 <span class="d-inline-block align-middle u-underline">@documentPath.FileName</span> 564 </a> 565 </td> 566 <td>@documentPath.FileType.Replace(".pdf", "PDF")</td> 567 <td>@documentPath.FileSize.ToSize(ByteExtension.SizeUnits.KB) KB</td> 568 </tr> 569 } 570 571 572 573 @foreach (var youtubeLink in video.Split('|')) 574 { 575 if (!String.IsNullOrEmpty(youtubeLink)) 576 { 577 int thumbCounter = 0; 578 string image = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink); 579 string thumb = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink); 580 <tr> 581 <td> 582 <div class="carousel__container__slide dw-mod"> 583 <a class="d-block dw-mod js-thumb-btn js-video-button" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" href="@youtubeLink" data-type="youtube" data-toggle="modal"> 584 <label for="GalleryModalTrigger"> 585 <img src="/Files/Images/Lauridsen/icons/icon-video.svg" class="product-page-table__icon d-inline-block align-middle mr-4" alt="@GetString("Ecom:Product:Field.video")" /> 586 <span class="d-inline-block align-middle u-underline">@GetString("Ecom:Product:Field.video")</span> 587 </label> 588 </a> 589 </div> 590 </td> 591 <td>@GetString("Ecom:Product:Field.video.Name")</td> 592 <td>-</td> 593 </tr> 594 thumbCounter++; 595 } 596 } 597 598 599 600 @foreach (var value in testList) 601 { 602 603 if (externalLink.IsNotNullOrEmpty() && !string.IsNullOrWhiteSpace(value)) 604 { 605 <tr> 606 <td scope="row"> 607 <i class="product-page-table__icon d-inline-block align-middle mr-3 fa fa-link fa-2x"></i> 608 <span class="d-inline-block align-middle u-underline product-external-link">@value</span> 609 </td> 610 <td>@Translate("Link")</td> 611 <td>-</td> 612 </tr> 613 } 614 } 615 </tbody> 616 </table> 617 </div> 618 </div> 619 </div> 620 <div class="grid product-page__content product-page__content--accessories js-toggle-retrigger"> 621 <h1 class="h3 section-title">@Translate("Accessories")</h1> 622 <div class="grid accessories-list dw-mod"> 623 <form name="multiForm" id="multiForm" class="accessories-list__form js-load-more-container" data-initial-load="5" method="post"> 624 <input type="hidden" name="CartCmd" id="CartCmd" value="addMulti" /> 625 @foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups").Where(group => group.GetString("Ecom:Product:RelatedGroup.Name") == "Tilbehør" || group.GetString("Ecom:Product:RelatedGroup.Name") == "Reservedele")) 626 { 627 foreach (LoopItem relatedProduct in relatedGroup.GetLoop("RelatedProducts")) 628 { 629 Dynamicweb.Ecommerce.Products.Product currentRelatedProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(relatedProduct.GetString("Ecom:Product.ID"), relatedProduct.GetString("Ecom:Product.VariantID"), relatedProduct.GetString("Ecom:Product.LanguageID")); 630 var relatedProductImagePathValue = Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(currentRelatedProduct, "ImagePath"); 631 string imgUrl = "/Files/Images/missing_image.jpg"; 632 string relatedProductImagePath = !string.IsNullOrWhiteSpace(relatedProductImagePathValue.ToString()) ? "/Files/Images/Ecom/LHI_Products/Images/" + relatedProductImagePathValue + ".jpg" : ""; 633 string relatedProductImage = !string.IsNullOrWhiteSpace(relatedProductImagePath) ? relatedProductImagePath : relatedProduct.GetString("Ecom:Product.ImageLarge.Default.Clean"); 634 635 if (!string.IsNullOrWhiteSpace(relatedProductImage)) 636 { 637 imgUrl = relatedProductImage; 638 } 639 640 string name = relatedProduct.GetString("Ecom:Product.Name"); 641 string number = relatedProduct.GetString("Ecom:Product.Number"); 642 string price = relatedProduct.GetString("Ecom:Product.Price"); 643 string groupId = relatedProduct.GetString("Ecom:Product.PrimaryGroupID"); 644 string id = relatedProduct.GetString("Ecom:Product.ID"); 645 var stock = relatedProduct.GetInteger("Ecom:Product.Stock"); 646 string stockText = relatedProduct.GetString("Ecom:Product:Stock.Text"); 647 string shortDescription = relatedProduct.GetString("Ecom:Product.ShortDescription"); 648 649 650 string link = "Default.aspx?" + "ID=" + GetInteger("Ecom:Product.PrimaryOrCurrentPageID") + "&GroupID=" + relatedProduct.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&ProductID=" + id; 651 List<Dynamicweb.Security.UserManagement.Group> userGroups = new List<Dynamicweb.Security.UserManagement.Group>(); 652 bool userisLoggedIn = Dynamicweb.Security.UserManagement.User.IsExtranetUserLoggedIn(); 653 bool isEmpty = !userGroups.Any(); 654 655 if (isEmpty && Dynamicweb.Security.UserManagement.User.IsExtranetUserLoggedIn()) 656 { 657 userGroups = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser().Groups.ToList(); 658 } 659 660 <div class="accessories-list__item accessorie grid__col-12 grid__col--bleed-x js-load-more-item is-hidden"> 661 <div class="grid"> 662 <figure class="grid__col-sm-2 grid__col-12 accessorie__figure"> 663 <div class="stickers-container dw-mod"> 664 665 666 667 @if (Converter.ToBoolean(Pageview.Area.Item["EnableSaleTags"])) 668 { 669 string contentType = Pageview.Area.Item["EcommerceSaleTagContentType"].ToString(); 670 string text = ""; 671 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 672 673 674 switch (contentType) 675 { 676 case "Name": 677 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 678 { 679 text = relatedDiscounts.GetString("Ecom:Product.Discount.Name"); 680 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 681 } 682 break; 683 case "Amount": 684 if (GetLoop("ProductDiscounts").Count > 0) 685 { 686 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.Price") - GetDouble("Ecom:Product.Price.Price")); 687 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 688 } 689 break; 690 case "Percents": 691 double percents = 0; 692 if (relatedProduct.GetLoop("ProductDiscounts").Count > 0) 693 { 694 foreach (LoopItem discount in relatedProduct.GetLoop("ProductDiscounts")) 695 { 696 if (discount.GetDouble("Ecom:Product.Discount.ProductQuantity") == 1) 697 { 698 percents = discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 699 } 700 } 701 if (percents > 0) 702 { 703 text = Math.Round(percents, 0) + "%"; 704 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 705 } 706 707 708 } 709 break; 710 case "Amount and percents": 711 double amount = 0; 712 double percent = 0; 713 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 714 { 715 if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "PERCENT") 716 { 717 percent += relatedDiscounts.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 718 } 719 else if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 720 { 721 amount += relatedDiscounts.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 722 } 723 } 724 if (percent > 0) 725 { 726 text = percent + "%"; 727 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 728 } 729 if (amount > 0) 730 { 731 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 732 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 733 } 734 break; 735 default: 736 if (GetLoop("ProductDiscounts").Count > 0) 737 { 738 text = Translate("Sale!"); 739 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 740 } 741 break; 742 } 743 744 745 if (Converter.ToBoolean(Pageview.Area.Item["NewStickersEnable"]) && GetDate("Ecom:Product.Created").AddDays(Converter.ToDouble(Pageview.Area.Item["NewStickersExpiration"])) > DateTime.Now) 746 { 747 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div> 748 } 749 750 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value"))) 751 { 752 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div> 753 } 754 755 } 756 </div> 757 <div class="grid__cell"> 758 <a href="@link" onclick="Scroll.SavePosition(event)" title="@name"> 759 <img class="grid__cell-img accessorie__image" 760 src="/Admin/Public/GetImage.ashx?width=350&height=350&crop=5&Compression=75&DoNotUpscale=true&image=@imgUrl" 761 alt="@name" /> 762 </a> 763 </div> 764 </figure> 765 <div class="grid__col-12 grid__col-sm-4 accessorie__description"> 766 <a class="" href="@link" onclick="Scroll.SavePosition(event)" title="@name"> 767 <div class="accessorie__number"><b>Vare nr.</b> @number</div> 768 <h3 class="accessorie__name">@name</h3> 769 <div class="accessorie__text">@shortDescription</div> 770 <div class="product-list-item__stock"> 771 <div class="stock-icon ml-0 @(stock > 0 ? "stock-icon--in" : "stock-icon--not")"></div> 772 <span>@stockText</span> 773 </div> 774 <span class="product-card__quantity-alert js-product-quantity-error-@id ">@Translate("Max stock level is reached")</span> 775 </a> 776 </div> 777 778 @if (!onlyPreview) 779 { 780 List<Price> priceCollectionList = new List<Price>(); 781 List<Price> getLowestPriceList = new List<Price>(); 782 List<Price> orderedPriceList = new List<Price>(); 783 List<Price> getPriceCollection = new List<Price>(); 784 785 if (userisLoggedIn) 786 { 787 if (currentProduct.Prices.ToList().Any()) 788 { 789 priceCollectionList = currentProduct.Prices.ToList(); 790 } 791 792 string userPriceGroups = string.Empty; 793 if (userGroups.Any()) 794 { 795 <div class=" grid__col-12 grid__col-sm-3 accessorie__details" style="text-align: center"> 796 @foreach (Price priceItem in priceCollectionList.Where(priceItem => priceItem.ProductId.Equals(uniqueId))) 797 { 798 if (Int32.TryParse(priceItem.UserGroupId, out int priceUserGroupId)) 799 { 800 foreach (Dynamicweb.Security.UserManagement.Group userGroupItem in userGroups.Where(userGroup => userGroup.ID.Equals(priceUserGroupId))) 801 { 802 userPriceGroups = userGroupItem.ID.ToString(); 803 if (userPriceGroups != null && priceCollectionList != null) 804 { 805 Price getLowest = priceCollectionList.Where(priceGroup => priceGroup.UserGroupId.Contains(userPriceGroups)).OrderBy(sortQuantity => sortQuantity.Quantity).ThenBy(sortOrder => sortOrder.Amount).ToList().FirstOrDefault(); 806 getLowestPriceList.Add(getLowest); 807 getPriceCollection = priceCollectionList.Where(priceGroup => priceGroup.UserGroupId.Contains(userPriceGroups)).ToList(); 808 if (getPriceCollection.Exists(check => check.Quantity > 2) && getPriceCollection != null) 809 { 810 orderedPriceList.Add(getPriceCollection.FirstOrDefault()); 811 } 812 } 813 } 814 } 815 } 816 @if (userPriceGroups != null && getLowestPriceList.Any()) 817 { 818 string priceWithDiscount = relatedProduct.GetString("Ecom:Product.Discount.Price.PriceFormatted"); 819 820 Price getLowestPrice = getLowestPriceList.OrderBy(lowerPrice => lowerPrice.Amount).ToList().FirstOrDefault(); 821 if (getLowestPrice.Quantity < 2) 822 { 823 <div class="accessorie__price price">@priceWithDiscount</div> 824 <div class=""> 825 @Translate("UnitPriceText") @getLowestPrice.Quantity @vismaUnitName 826 </div> 827 } 828 829 List<LoopItem> priceLoop = relatedProduct.GetLoop("Product.Prices"); 830 if (priceLoop.Any(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 831 { 832 <div class="js-popup"> 833 834 <a class="js-popup-trigger">@Translate("DiscountText")</a> 835 <div class="js-popup-modal popup_productrelatedview"> 836 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 837 <ul class="grid__col-12 pt-5 p-0 d-flex flex-row flex-wrap"> 838 839 @foreach (LoopItem priceItem in priceLoop.Where(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 840 { 841 string relatedVismaUnitName = !string.IsNullOrWhiteSpace(priceItem.GetString("Ecom:Product:Field.Enhed")) ? priceItem.GetString("Ecom:Product:Field.Enhed")?.ToLower() : Translate("UnitPriceTextStk"); 842 <li class="grid__col-lg-6 p-0 mb-0 grid__col-12 align-items-center align-items-xl-start">@Translate("UnitPriceText") @priceItem.GetDouble("Ecom:Product.Prices.Quantity") @relatedVismaUnitName</li> 843 <li class="grid__col-lg-6 p-0 pb-3 grid__col-12 align-items-center align-items-xl-end">@priceItem.GetString("Ecom:Product.Prices.AmountFormatted")</li> 844 } 845 </ul> 846 </div> 847 </div> 848 } 849 } 850 851 </div> 852 if (getLowestPriceList.Any()) 853 { 854 855 if (relatedProduct.GetLoop("VariantGroups").Count > 0) 856 { 857 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 858 <div class="accessorie__controls-inner"> 859 860 <a href="@link" class="btn btn-secondary dw-mod js-scroll-btn d-inline-block px-5">@Translate("Select variant")</a> 861 </div> 862 </div> 863 864 } 865 else 866 { 867 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 868 <div class="accessorie__controls-inner"> 869 <div class="accessorie__button-container d-inline-block"> 870 <button type="button" id="CartButton_@id" class="btn btn--primary accessorie__cart" name="submit" onclick="Cart.AddToCart(event, '@id', document.getElementById('Quantity_@id').value, 'Unit_@id', 'Variant_@id');"> 871 <i class="fa fa-shopping-cart"></i> 872 <span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span> 873 </button> 874 </div> 875 876 <div class="product-card__quantity--condenced product-card__quantity accessorie__quantity"> 877 <input id="Quantity_@id" class="product-card__quantity-input pointer-events js-quantity-input" name="Quantity@accessoriesProduct.Id" data-id="@id" type="number" min="1" max="@stock" value="1"> 878 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 879 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 880 </div> 881 882 </div> 883 </div> 884 } 885 } 886 else 887 { 888 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 889 <div class="accessorie__controls-inner"> 890 <div class="accessorie__button-container d-inline-block"> 891 <button type="button" id="CartButton_@id" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target"> 892 <span class="u-hidden-xs u-hidden-xxs"> @Translate("CallForPrice")</span> 893 </button> 894 </div> 895 </div> 896 </div> 897 } 898 } 899 else 900 { 901 <div class=" grid__col-12 grid__col-sm-3 accessorie__details" style="text-align: center"> 902 <div class="accessorie__price price"></div> 903 <div class="accessorie__before-price before-price "></div> 904 <div class=""> 905 </div> 906 <div class="js-popup"> 907 <div class="js-popup-modal popup_productrelatedview"> 908 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 909 </div> 910 </div> 911 </div> 912 if (getLowestPriceList.Any()) 913 { 914 915 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 916 <div class="accessorie__controls-inner"> 917 918 <div class="accessorie__button-container d-inline-block"> 919 <button type="button" id="CartButton_@id" class="btn btn--primary accessorie__cart" name="submit" onclick="Cart.AddToCart(event, '@id', document.getElementById('Quantity_@id').value, 'Unit_@id', 'Variant_@id');"> 920 <i class="fa fa-shopping-cart"></i> 921 <span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span> 922 </button> 923 </div> 924 925 <div class="product-card__quantity--condenced product-card__quantity accessorie__quantity"> 926 <input id="Quantity_@id" class="product-card__quantity-input pointer-events js-quantity-input" name="Quantity@accessoriesProduct.Id" data-id="@id" type="number" min="1" max="@stock" value="1"> 927 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 928 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 929 </div> 930 931 </div> 932 </div> 933 } 934 else 935 { 936 937 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 938 <div class="accessorie__controls-inner"> 939 <div class="accessorie__button-container d-inline-block"> 940 <button type="button" id="CartButton_@id" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target"> 941 <span class="u-hidden-xs u-hidden-xxs"> @Translate("CallForPrice")</span> 942 </button> 943 </div> 944 </div> 945 </div> 946 } 947 } 948 } 949 } 950 else 951 { 952 <div class="grid__col-12 grid__col-sm-6 align-items-center align-items-lg-end"> 953 <div class="grid__cell"> 954 <div class="grid__col-12 pb-0"> 955 <h5>@Translate("LoginText")</h5> 956 </div> 957 <div class="grid__col-12 pb-0"> 958 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod" onclick="setTimeout(function() { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 959 </div> 960 </div> 961 </div> 962 } 963 </div> 964 </div> 965 } 966 } 967 <div class="grid__col--bleed-y mb-6"> 968 <a class="btn btn-teritary btn--load-more js-load-more-trigger dw-mod">@Translate("Load more")</a> 969 </div> 970 </form> 971 </div> 972 </div> 973 </div> 974 </section> 975 @if (GetLoop("ProductRelatedGroups").Any()) 976 { 977 <section class="related-products"> 978 <div class="grid related-products__inner-container"> 979 980 <div class="grid__col-xs-12 related-products__headline-container"> 981 <h2 class="related-products__headline h2 section-title section-title--condensed">@Translate("Related products")</h2> 982 </div> 983 984 <div class="grid__col-12 grid__col-md-10 grid__col--bleed m-auto"> 985 <div class="grid"> 986 987 @foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups").Where(group => group.GetString("Ecom:Product:RelatedGroup.Name") == "Relaterede produkter")) 988 { 989 foreach (LoopItem related in relatedGroup.GetLoop("RelatedProducts")) 990 { 991 Dynamicweb.Ecommerce.Products.Product currentRelatedProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(related.GetString("Ecom:Product.ID"), related.GetString("Ecom:Product.VariantID"), related.GetString("Ecom:Product.LanguageID")); 992 var relatedProductImagePathValue = Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(currentRelatedProduct, "ImagePath"); 993 string imgUrl = "/Files/Images/missing_image.jpg"; 994 string relatedProductImagePath = !string.IsNullOrWhiteSpace(relatedProductImagePathValue.ToString()) ? "/Files/Images/Ecom/LHI_Products/Images/" + relatedProductImagePathValue + ".jpg" : ""; 995 string relatedProductImage = !string.IsNullOrWhiteSpace(relatedProductImagePath) ? relatedProductImagePath : related.GetString("Ecom:Product.ImageLarge.Default.Clean"); 996 997 if (!string.IsNullOrWhiteSpace(relatedProductImage)) 998 { 999 imgUrl = relatedProductImage; 1000 } 1001 1002 string name = related.GetString("Ecom:Product.Name"); 1003 string number = related.GetString("Ecom:Product.Number"); 1004 string price = related.GetString("Ecom:Product.Price"); 1005 string groupId = related.GetString("Ecom:Product.PrimaryGroupID"); 1006 string id = related.GetString("Ecom:Product.ID"); 1007 var stock = related.GetInteger("Ecom:Product.Stock"); 1008 string stockText = related.GetString("Ecom:Product:Stock.Text"); 1009 1010 <div class="grid__col-12 grid__col-sm-6 grid__col-lg-3"> 1011 <div class="related-products__product related-product"> 1012 <a href="@related.GetString("Ecom:Product.Link.Clean")"> 1013 <div class="stickers-container dw-mod"> 1014 1015 @if (Converter.ToBoolean(Pageview.Area.Item["EnableSaleTags"])) 1016 { 1017 string contentType = Pageview.Area.Item["EcommerceSaleTagContentType"].ToString(); 1018 string text = ""; 1019 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 1020 1021 1022 switch (contentType) 1023 { 1024 case "Name": 1025 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 1026 { 1027 text = relatedDiscounts.GetString("Ecom:Product.Discount.Name"); 1028 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1029 } 1030 break; 1031 case "Amount": 1032 if (GetLoop("ProductDiscounts").Count > 0) 1033 { 1034 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.Price") - GetDouble("Ecom:Product.Price.Price")); 1035 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1036 } 1037 break; 1038 case "Percents": 1039 double percents = 0; 1040 if (related.GetLoop("ProductDiscounts").Count > 0) 1041 { 1042 foreach (LoopItem discount in related.GetLoop("ProductDiscounts")) 1043 { 1044 if (discount.GetDouble("Ecom:Product.Discount.ProductQuantity") == 1) 1045 { 1046 percents = discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 1047 } 1048 } 1049 if (percents > 0) 1050 { 1051 text = Math.Round(percents, 0) + "%"; 1052 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1053 } 1054 1055 1056 } 1057 break; 1058 case "Amount and percents": 1059 double amount = 0; 1060 double percent = 0; 1061 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 1062 { 1063 if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "PERCENT") 1064 { 1065 percent += relatedDiscounts.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 1066 } 1067 else if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 1068 { 1069 amount += relatedDiscounts.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 1070 } 1071 } 1072 if (percent > 0) 1073 { 1074 text = percent + "%"; 1075 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1076 } 1077 if (amount > 0) 1078 { 1079 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 1080 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1081 } 1082 break; 1083 default: 1084 if (GetLoop("ProductDiscounts").Count > 0) 1085 { 1086 text = Translate("Sale!"); 1087 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1088 } 1089 break; 1090 } 1091 1092 1093 if (Converter.ToBoolean(Pageview.Area.Item["NewStickersEnable"]) && GetDate("Ecom:Product.Created").AddDays(Converter.ToDouble(Pageview.Area.Item["NewStickersExpiration"])) > DateTime.Now) 1094 { 1095 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div> 1096 } 1097 1098 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value"))) 1099 { 1100 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div> 1101 } 1102 1103 } 1104 1105 1106 </div> 1107 <img class="related-product__image b-lazy" src="/Files/Images/placeholder.gif" data-src="/Admin/Public/GetImage.ashx?width=350&height=350&crop=5&Compression=75&DoNotUpscale=true&image=@imgUrl" alt="@name" /> 1108 <h4 class="related-product__name">@name</h4> 1109 <div class="related-product__number">@Translate("product number") @number</div> 1110 1111 <div class="product-list-item__stock"> 1112 <div class="stock-icon ml-0 @(stock > 0 ? "stock-icon--in" : "stock-icon--not")"></div> 1113 <span>@stockText</span> 1114 </div> 1115 1116 <span class="product-card__quantity-alert js-product-quantity-error-@id ">@Translate("Max stock level is reached")</span> 1117 </a> 1118 1119 @if (!onlyPreview) 1120 { 1121 string priceWithDiscount = related.GetString("Ecom:Product.Discount.Price.Price"); 1122 string currencySymbol = related.GetString("Ecom:Product.Currency.Symbol"); 1123 string priceWithOutDiscount = related.GetString("Ecom:Product.Price.Price"); 1124 bool productHasDiscount = GetBoolean("Ecom:Product.HaveDiscount"); 1125 1126 <div class="related-product__button-container d-inline-block"> 1127 @if (priceWithDiscount != "0,00" || priceWithOutDiscount != "0,00") 1128 { 1129 if (GetString("Ecom:Product.Discount.TotalAmount") != "DKK 0,00") 1130 { 1131 <div class="related-product__price withdiscount">@currencySymbol @priceWithDiscount</div> 1132 } 1133 1134 else 1135 { 1136 <div class="related-product__price withoutdiscount">@currencySymbol @priceWithOutDiscount</div> 1137 } 1138 1139 List<LoopItem> priceLoop = related.GetLoop("Product.Prices"); 1140 if (priceLoop.Any(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 1141 { 1142 <div class="js-popup"> 1143 <a class="js-popup-trigger">@Translate("DiscountText")</a> 1144 <div class="js-popup-modal popup_productrelatedview"> 1145 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 1146 <ul class="grid__col-12 pt-5 p-0 d-flex flex-row flex-wrap"> 1147 1148 @foreach (LoopItem priceItem in priceLoop.Where(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 1149 { 1150 <li class="grid__col-lg-6 p-0 mb-0 grid__col-12 align-items-center align-items-xl-start">@Translate("UnitPriceText") @priceItem.GetDouble("Ecom:Product.Prices.Quantity") @Translate("UnitPriceTextStk")</li> 1151 <li class="grid__col-lg-6 p-0 pb-3 grid__col-12 align-items-center align-items-xl-end">@priceItem.GetString("Ecom:Product.Prices.AmountFormatted")</li> 1152 } 1153 </ul> 1154 </div> 1155 </div> 1156 } 1157 1158 if (related.GetLoop("VariantGroups").Count > 0) 1159 { 1160 <div class="related-product__controls"> 1161 1162 1163 <a href="@related.GetString("Ecom:Product.Link.Clean")" class="btn btn-secondary dw-mod js-scroll-btn d-inline-block px-5">@Translate("Select variant")</a> 1164 1165 </div> 1166 1167 } 1168 else 1169 { 1170 <div class="related-product__controls"> 1171 <div class="product-card__quantity--condenced product-card__quantity related-product__quantity"> 1172 <input id="Quantity_@id" class="product-card__quantity-input pointer-events js-quantity-input" name="Quantity@id" data-id="@id" type="number" min="1" max="@stock" value="1"> 1173 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 1174 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 1175 </div> 1176 <button type="button" id="CartButton_@id" class="btn btn--primary related-product__cart" name="submit" onclick="Cart.AddToCart(event, '@id', document.getElementById('Quantity_@id').value, 'Unit_@id', 'Variant_@id');"> 1177 <i class="fa fa-shopping-cart"></i> 1178 <span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span> 1179 </button> 1180 </div> 1181 } 1182 1183 1184 } 1185 else 1186 { 1187 <button type="button" id="CartButton_@id" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target"> 1188 <span class="u-hidden-xs u-hidden-xxs"> @Translate("CallForPrice")</span> 1189 </button> 1190 } 1191 </div> 1192 1193 1194 } 1195 else 1196 { 1197 <div class="related-product__login-label">@Translate("LoginText")</div> 1198 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod related-product__login" onclick="setTimeout(function () { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 1199 } 1200 1201 1202 </div> 1203 </div> 1204 1205 1206 1207 1208 } 1209 1210 } 1211 1212 </div> 1213 </div> 1214 </div> 1215 </section> 1216 1217 1218 1219 } 1220 </div> 1221 1222 @* 1223 @if(GetLoop("eCom:Related.CustomersWhoSawThisAlsoSaw").Any()) 1224 { 1225 foreach (LoopItem item in GetLoop("eCom:Related.CustomersWhoSawThisAlsoSaw")) 1226 { 1227 relatedProductsFeed += item.GetString("Ecom:Product.ID"); 1228 relatedProductsFeed += ""; 1229 } 1230 1231 <div class="grid"> 1232 <div class="grid__col-12"> 1233 <div class="bg-gray bg-gray-full-width"> 1234 <h2 class="h1 section-title section-title--condensed">@Translate("ecom-related-products-3", "Related products")</h2> 1235 <div class="js-handlebars-root" id="ProductList_@productId" data-template="ProductContainer" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedProductsFeed" data-preloader="overlay"></div> 1236 </div> 1237 </div> 1238 </div> 1239 } 1240 *@ 1241 1242 @helper ProductPropertiesMainArea() 1243 { 1244 if (GetLoop("CustomFieldValues").Count > 0) 1245 { 1246 var visibleCount = 0; 1247 1248 <div class="specs-list specs-list--5"> 1249 <dl class="table table--clean table--compact product-page__specs-list"> 1250 @foreach (LoopItem customField in GetLoop("CustomFieldValues").Where(customField => customField.GetString("Product.CustomField.System") != "description").Where(customField => customField.GetString("Product.CustomField.System") != "LongDescription").Where(customField => customField.GetString("Product.CustomField.System") != "ShortDescription")) 1251 { 1252 string fieldValue = customField.GetString("Product.CustomField.Value.Clean"); 1253 1254 if (customField.GetLoop("Product.CustomField.Options").Count > 0) 1255 { 1256 fieldValue = ""; 1257 int count = 0; 1258 1259 foreach (LoopItem customFieldOptions in customField.GetLoop("Product.CustomField.Options").Where(customFieldOptions => !string.IsNullOrWhiteSpace(customFieldOptions.GetString("Product.CustomField.Option.Name")))) 1260 { 1261 if (customFieldOptions.GetBoolean("Product.CustomField.Option.IsSelected")) 1262 { 1263 if (count != 0) 1264 { 1265 fieldValue += ", "; 1266 } 1267 1268 fieldValue += customFieldOptions.GetString("Product.CustomField.Option.Name"); 1269 count++; 1270 } 1271 } 1272 } 1273 1274 if (fieldValue == "False") 1275 { 1276 fieldValue = Translate("No"); 1277 } 1278 1279 if (fieldValue == "True") 1280 { 1281 fieldValue = Translate("Yes"); 1282 } 1283 1284 1285 if (!String.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) 1286 && !String.IsNullOrWhiteSpace(fieldValue) 1287 && customField.GetString("Product.CustomField.Name") != "Custom sticker" 1288 && customField.GetString("Product.CustomField.Name").Contains("Produkt tekst") == true) 1289 { 1290 if (!String.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 1291 { 1292 visibleCount++; 1293 <dd class="product-page__specs-value"><a href="@customField.GetString("Document.FullPath")" download title="@Translate("Download")" class="product__document"><span property="identifier">@getIconForFile(fieldValue) @Path.GetFileName(fieldValue)</span></a></dd> 1294 } 1295 else 1296 { 1297 visibleCount++; 1298 <dd class="product-page__specs-value"><span property="identifier">@fieldValue</span></dd> 1299 } 1300 } 1301 } 1302 </dl> 1303 1304 @if (visibleCount > 5) 1305 { 1306 <div class="js-load-more-specs specs-list__trigger"> 1307 <span class="specs-list__load-more">@Translate("Show more")</span> 1308 <span class="specs-list__load-less">@Translate("Show less")</span> 1309 </div> 1310 } 1311 1312 </div> 1313 } 1314 } 1315 @helper ProductProperties() 1316 { 1317 if (GetLoop("CustomFieldValues").Count > 0) 1318 { 1319 var visibleCount = 0; 1320 1321 <div class="specs-list specs-list--10"> 1322 <dl class="table table--clean table--compact product-page__specs-list"> 1323 @foreach (LoopItem customField in GetLoop("CustomFieldValues").Where(customField => customField.GetString("Product.CustomField.System") != "description").Where(customField => customField.GetString("Product.CustomField.System") != "LongDescription").Where(customField => customField.GetString("Product.CustomField.System") != "ShortDescription")) 1324 { 1325 string fieldValue = customField.GetString("Product.CustomField.Value.Clean"); 1326 1327 if (customField.GetLoop("Product.CustomField.Options").Count > 0) 1328 { 1329 fieldValue = ""; 1330 int count = 0; 1331 1332 foreach (LoopItem customFieldOptions in customField.GetLoop("Product.CustomField.Options").Where(customFieldOptions => !string.IsNullOrWhiteSpace(customFieldOptions.GetString("Product.CustomField.Option.Name")))) 1333 { 1334 if (customFieldOptions.GetBoolean("Product.CustomField.Option.IsSelected")) 1335 { 1336 if (count != 0) 1337 { 1338 fieldValue += ", "; 1339 } 1340 1341 fieldValue += customFieldOptions.GetString("Product.CustomField.Option.Name"); 1342 count++; 1343 } 1344 } 1345 } 1346 if (fieldValue == "False") 1347 { 1348 fieldValue = Translate("No"); 1349 } 1350 1351 if (fieldValue == "True") 1352 { 1353 fieldValue = Translate("Yes"); 1354 } 1355 1356 if (!String.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) 1357 && !String.IsNullOrWhiteSpace(fieldValue) 1358 && customField.GetString("Product.CustomField.Name") != "Custom sticker" 1359 && !customField.GetString("Product.CustomField.Name").Contains("Produktions ansvarlig") 1360 && !customField.GetString("Product.CustomField.Name").Contains("Video") 1361 && !customField.GetString("Product.CustomField.Name").Contains("PDF") 1362 && !customField.GetString("Product.CustomField.Name").Contains("Lokation") 1363 && !customField.GetString("Product.CustomField.Name").Contains("Status") 1364 && !customField.GetString("Product.CustomField.Name").Contains("Produktgr. (CO)") 1365 && !customField.GetString("Product.CustomField.Name").Contains("Produktprisgr. 1 (rabatgruppe)") 1366 && !customField.GetString("Product.CustomField.Name").Contains("Prisliste") 1367 && !customField.GetString("Product.CustomField.Name").Contains("Godkendelse") 1368 && !customField.GetString("Product.CustomField.Name").Contains("Salgsstatistik") 1369 && !customField.GetString("Product.CustomField.Name").Contains("ABC") 1370 && !customField.GetString("Product.CustomField.Name").Contains("Billedefilnr (LFR)") 1371 && !customField.GetString("Product.CustomField.Name").Contains("Rabat gruppe 2") 1372 && !customField.GetString("Product.CustomField.Name").Contains("Visma changed by user") 1373 && !customField.GetString("Product.CustomField.Name").Contains("Visma changed date") 1374 && customField.GetString("Product.CustomField.Value") != "0" 1375 && customField.GetString("Product.CustomField.Value") != "" 1376 && customField.GetString("Product.CustomField.Name").Contains("Produkt tekst") != true) 1377 { 1378 <dt class="product-page__specs-display" width="160">@Translate(customField.GetString("Product.CustomField.Name")): </dt> 1379 if (!String.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 1380 { 1381 visibleCount++; 1382 <dd class="text-right product-page__specs-value"><a href="@customField.GetString("Document.FullPath")" download title="@Translate("Download")" class="product__document"><span property="identifier">@getIconForFile(fieldValue) @Path.GetFileName(fieldValue)</span></a></dd> 1383 } 1384 else 1385 { 1386 visibleCount++; 1387 <dd class="text-right product-page__specs-value"><span property="identifier">@fieldValue</span></dd> 1388 } 1389 } 1390 } 1391 </dl> 1392 1393 @if (visibleCount > 10) 1394 { 1395 <div class="js-load-more-specs specs-list__trigger"> 1396 <span class="specs-list__load-more">@Translate("Show more")</span> 1397 <span class="specs-list__load-less">@Translate("Show less")</span> 1398 </div> 1399 } 1400 </div> 1401 } 1402 1403 if (GetLoop("ProductCategories").Count > 0) 1404 { 1405 <dl class="product-page__specs-list"> 1406 @foreach (LoopItem categoryGroup in GetLoop("ProductCategories")) 1407 { 1408 int fieldsCount = 0; 1409 foreach (LoopItem categoryField in categoryGroup.GetLoop("ProductCategoryFields")) 1410 { 1411 if (!String.IsNullOrEmpty(categoryField.GetString("Ecom:Product.CategoryField.Value"))) 1412 { 1413 fieldsCount++; 1414 } 1415 } 1416 if (fieldsCount > 0) 1417 { 1418 <dd class="product-page__specs-display">@categoryGroup.GetString("Ecom:Product.Category.Name")</dd> 1419 1420 foreach (LoopItem categoryField in categoryGroup.GetLoop("ProductCategoryFields")) 1421 { 1422 string fieldValue = categoryField.GetString("Ecom:Product.CategoryField.Value"); 1423 1424 if (fieldValue == "False") 1425 { 1426 fieldValue = Translate("No"); 1427 } 1428 1429 if (fieldValue == "True") 1430 { 1431 fieldValue = Translate("Yes"); 1432 } 1433 1434 if (!String.IsNullOrEmpty(categoryField.GetString("Ecom:Product.CategoryField.Label")) && !String.IsNullOrEmpty(fieldValue)) 1435 { 1436 <dt class="product-page__specs-display">@categoryField.GetString("Ecom:Product.CategoryField.Label"):</dt> 1437 <dd class="text-right product-page__specs-value"><span property="identifier">@fieldValue</span></dd> 1438 } 1439 } 1440 } 1441 } 1442 </dl> 1443 } 1444 } 1445 1446 <script id="PricesAndActionsTemplate" type="text/x-template"> 1447 {{#.}} 1448 1449 @if (!onlyPreview) 1450 { 1451 if (cfp == false) 1452 { 1453 <text> 1454 {{#ifCond hasVariants "!==" "disabled"}} 1455 1456 @if (GetInteger("Ecom:Product.Discount.TotalAmount") > 0) 1457 { 1458 <small class="text-gray font-weight-light">@Translate("NettoPrice")</small> 1459 <div class="text-gray font-weight-light product__price--discount {{onSale}}">{{#Discount}}{{#if @@first}}{{this.discountCurrency}} {{this.discount}}{{/if}}{{/Discount}}</div> 1460 <br /> 1461 <small class="text-gray font-weight-light">@Translate("ProductDiscount")</small> 1462 <div class="text-gray font-weight-light product__price--discount {{onSale}}">{{#Discount}}{{#if @@first}}{{this.discountCurrency}} {{this.subtractPriceWithoutDecimals}}{{/if}}{{/Discount}}</div> 1463 <br /> 1464 <small class="text-gray font-weight-light">@Translate("PriceWithDiscount")</small> 1465 } 1466 else 1467 { 1468 <small class="text-gray font-weight-light">@Translate("PriceWithoutDiscount")</small> 1469 } 1470 1471 @if (GetLoop("ProductDiscounts").Any()) 1472 { 1473 <div class="h1 my-3 text-gray font-weight-light">{{price}}</div> 1474 } 1475 else 1476 { 1477 <div class="h1 my-3 text-gray font-weight-light">{{price}}</div> 1478 } 1479 1480 {{/ifCond}} 1481 </text> 1482 1483 1484 } 1485 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.Text")) || !String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText"))) 1486 { 1487 if (GetLoop("Product.Prices").Count >= 1) 1488 { 1489 1490 var priceLoop = GetLoop("Product.Prices"); 1491 var excludedIds = "1"; 1492 var priceQuantity = priceLoop.Where(i => !excludedIds.Contains(i.GetString("Ecom:Product.Prices.Quantity"))); 1493 1494 if (GetLoop("Product.Prices").Count > 1 && priceQuantity.Any()) 1495 { 1496 1497 1498 <div class="js-popup"> 1499 <a class="js-popup-trigger">@Translate("DiscountText")</a> 1500 <div class="js-popup-modal popup_productview"> 1501 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 1502 <ul class="grid__col-12 pt-5 p-0 d-flex flex-row flex-wrap"> 1503 @* FOREACH DISCOUNT LOOP FROM JSON FEED *@ 1504 {{#each Discount}} 1505 {{#unless @@first}} 1506 <li class="grid__col-lg-6 p-0 mb-0 grid__col-12 align-items-center align-items-xl-start">@Translate("UnitPriceText") {{this.discountQuantity}} {{this.vismaUnitName}}</li> 1507 <li class="grid__col-lg-6 p-0 pb-3 grid__col-12 align-items-center align-items-xl-end">{{this.discountCurrency}} {{this.discount}}</li> 1508 {{/unless}} 1509 {{/each}} 1510 1511 </ul> 1512 </div> 1513 </div> 1514 } 1515 } 1516 <br> 1517 1518 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.Text")) || !String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText"))) 1519 { 1520 string stockIcon = GetInteger("Ecom:Product.Stock") > 0 ? "product__stock-icon--in" : "product__stock-icon--not"; 1521 1522 if (cfp == false) 1523 { 1524 <table class="table table--clean delivery-and-stock-info dw-mod"> 1525 <tr> 1526 <td class="u-no-padding"> 1527 <div class="stock-icon ml-0 @stockIcon"></div> 1528 <span class="font-weight-bold">@GetString("Ecom:Product:Stock.Text")</span> 1529 </td> 1530 </tr> 1531 <tr> 1532 @* 1533 @if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText"))) 1534 { 1535 <td class="u-no-padding">@Translate("Shipping") @GetString("Ecom:Product:Stock.DeliveryText") @GetString("Ecom:Product:Stock.DeliveryUnit")</td> 1536 } 1537 *@ 1538 </tr> 1539 </table> 1540 } 1541 } 1542 1543 <div class="buttons-collection product__price-actions__actions dw-mod d-inline-block d-lg-flex mt-5 w-100"> 1544 1545 @if (GetBoolean("Ecom:Product:Field.CFP")) 1546 { 1547 <div class="cfp-btn-container pt-4 pt-lg-0"> 1548 <button type="button" id="CartButton_{{id}}" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target">@Translate("CallForPrice")</button> 1549 </div> 1550 } 1551 1552 else 1553 { 1554 var disabledClass = String.IsNullOrWhiteSpace(variantId) && GetLoop("VariantGroups").Count > 0 ? "disabled" : ""; 1555 @* Product quantity *@ 1556 <div class="product-card__quantity product-card__quantity--condenced"> 1557 <input id="Quantity_{{id}}" class="product-card__quantity-input pointer-events js-quantity-input" data-id="{{id}}" name="Quantity" type="number" min="1" max="@stockAmount" value="1"> 1558 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 1559 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 1560 </div> 1561 <div class="product-btn-buy-container pt-4 pt-lg-0 pl-lg-3"> 1562 {{#ifCond hasVariants "==" "disabled"}} 1563 <a href="{{link}}" class="btn btn-secondary dw-mod js-scroll-btn d-inline-block px-5 @disabledClass">@Translate("Select variant")</a> 1564 {{else}} 1565 <button type="button" id="CartButton_{{id}}" class="btn btn-primary dw-mod d-inline-block px-5 @disabledClass" name="submit" onclick="Cart.AddToCart(event, '{{productId}}', document.getElementById('Quantity_{{id}}').value, 'Unit_{{id}}', 'Variant_{{productId}}');">@Translate("Add to cart")</button> 1566 {{/ifCond}} 1567 </div> 1568 } 1569 1570 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 1571 { 1572 string favoriteId = "Favorite" + GetString("Ecom:Product.ID"); 1573 1574 <div id="@favoriteId" class="favorites fav-product-container favorites--md d-inline-block dw-mod p-0 pl-lg-3"> 1575 <label for="FavoriteTrigger" class="btn mb-0 btn-secondary"><span class="pr-2 product__add-to-favorites"></span><small class="x-small">@Translate("Add to list")</small></label> 1576 <input type="checkbox" id="FavoriteTrigger" class="dropdown-trigger"> 1577 <div class="dropdown"> 1578 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 1579 @if (GetLoop("CustomerCenter.ListTypes").Any()) 1580 { 1581 <ul class="list list--clean dw-mod"> 1582 @foreach (LoopItem listType in GetLoop("CustomerCenter.ListTypes")) 1583 { 1584 foreach (LoopItem list in listType.GetLoop("CustomerCenter.ProductLists")) 1585 { 1586 <li> 1587 @{string favLinkType = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? list.GetString("Ecom:Product.RemoveFromThisList") : list.GetString("Ecom:Product.AddToThisListAction");} 1588 @{string isInListIcon = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? "fa fa-star" : "fa fa-star-o";} 1589 <a href="@favLinkType" class="list__link dw-mod"><i class="@isInListIcon"></i> @list.GetValue("Ecom:CustomerCenter.List.Name")</a> 1590 </li> 1591 } 1592 } 1593 </ul> 1594 } 1595 1596 else 1597 { 1598 <p>@Translate("CreateFavoritList")</p><a class="btn-sm btn-primary d-block text-center" href="@favoritPage">@Translate("CreateFavoritListButton")</a> 1599 } 1600 1601 </div> 1602 <label class="dropdown-trigger-off" for="FavoriteTrigger"></label> 1603 </div> 1604 </div> 1605 } 1606 1607 1608 </div> 1609 1610 <span class="product-card__quantity-alert js-product-quantity-error-{{id}}">@Translate("Max stock level is reached")</span> 1611 } 1612 } 1613 1614 else 1615 { 1616 <button type="button" id="CartButton_{{id}}" class="u-hidden"></button> 1617 } 1618 {{/.}} 1619 </script> 1620 1621 <script id="Units" type="text/x-template"> 1622 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '/Default.aspx?ID=@feedId&UnitID={{value}}')">{{name}}</div> 1623 </script> 1624 1625 1626 @* Script templates for related products *@ 1627 <script id="ProductPreRenderContainer" type="text/x-template"> 1628 <div class="u-h600px u-full-width"> 1629 <div class="grid"> 1630 <div class="grid__col-12"> 1631 <div class="pre-render-element pre-render-element--md"></div> 1632 </div> 1633 </div> 1634 </div> 1635 </script> 1636 1637 <script id="ProductContainer" type="text/x-template"> 1638 {{#.}} 1639 <div class="u-min-h400px u-full-width"> 1640 <div class="grid"> 1641 <div class="grid__col-45px grid__col--bleed-x"> 1642 <div class="grid__cell grid__cell--align-middle-left"> 1643 <button class="btn btn--condensed btn--clean {{prevdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{prevPage}}')" {{prevdisabled}}><i class="fa fa-chevron-left fa-2x"></i></button> 1644 </div> 1645 </div> 1646 <div class="grid__col-auto grid__col--bleed-x"> 1647 <div id="ProductsContainer" class="grid product-list dw-mod"> 1648 {{#ProductsContainer}} 1649 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__list-item dw-mod"> 1650 <div class="product-list__inner"> 1651 {{#Product}} 1652 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}"> 1653 <div class="stickers-container dw-mod"> 1654 {{#Stickers}} 1655 {{>Sticker}} 1656 {{/Stickers}} 1657 </div> 1658 <a href="{{link}}" onclick="Scroll.SavePosition(event)"><img class="grid__cell-img grid__cell-img--centered b-lazy" src="/Files/Images/placeholder.gif" data-src="/Admin/Public/GetImage.ashx?width=300&height=300&crop=5&Compression=75&image={{image}}" alt="{{name}}" /></a> 1659 </div> 1660 1661 <div class="grid__cell product-list__grid-item__price-info {{shortGridInfo}} dw-mod"> 1662 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6 class="u-condensed-text">{{name}}</h6></a> 1663 <div class="item-number dw-mod">{{number}}</div> 1664 1665 @if (!onlyPreview && cfp == true) 1666 { 1667 <div class="price dw-mod">{{price}}</div> 1668 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 1669 } 1670 </div> 1671 1672 <div class="product-list__grid-item__footer dw-mod"> 1673 <div class="u-ta-center"> 1674 1675 @if (!onlyPreview && cfp == true) 1676 { 1677 <a href="{{link}}" id="CartButton_{{id}}" class="btn btn--secondary text-uppercase u-no-margin dw-mod">@Translate("View")</a> 1678 } 1679 else 1680 { 1681 <h5 class="mb-2">@Translate("LoginText", "Login")</h5> 1682 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod" onclick="setTimeout(function () { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 1683 } 1684 </div> 1685 </div> 1686 {{/Product}} 1687 </div> 1688 </div> 1689 {{/ProductsContainer}} 1690 </div> 1691 </div> 1692 1693 <div class="grid__col-45px grid__col--bleed-x"> 1694 <div class="grid__cell grid__cell--align-middle-right"> 1695 <button class="btn btn--condensed btn--clean {{nextdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{nextPage}}')" {{nextdisabled}}><i class="fa fa-chevron-right fa-2x"></i></button> 1696 </div> 1697 </div> 1698 1699 </div> 1700 </div> 1701 {{/.}} 1702 </script> 1703 1704 <script id="Sticker" type="text/x-template"> 1705 <div class="stickers-container__tag {{className}} dw-mod">{{text}}</div> 1706 </script> 1707 1708 @* Units templates *@ 1709 1710 <script id="UnitOption" type="text/x-template"> 1711 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '{{link}}&feed=true&UnitID={{value}}&rid={{id}}')">{{name}}</div> 1712 </script> 1713 1714 1715 @*Variants data generation*@ 1716 1717 <script> 1718 document.addEventListener("DOMContentLoaded", function (event) { 1719 var variants = []; 1720 1721 document.getElementById("productGrid").addEventListener('contentLoaded', function (e) { 1722 if (e.srcElement.classList.contains("js-variants-wrap")) { 1723 Variants.SetVariantOptionStatesForProductList(e.srcElement); 1724 } 1725 }, false); 1726 1727 @foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 1728 { 1729 <text>var optionsArray = [];</text> 1730 1731 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions")) 1732 { 1733 string variantSelection = variantoption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 1734 1735 <text> 1736 var option = new Variants.VariantOption("@uniqueId", "@GetString("Ecom:Product.ID")", "@variantoption.GetValue("Ecom:VariantOption.ID")", "@variantoption.GetString("Ecom:VariantOption.Name")", "@variantSelection", "", "@variantoption.GetString("Ecom:VariantOption.Color")", "@variantoption.GetString("Ecom:VariantOption.ImgSmall.Clean")"); 1737 optionsArray.push(option); 1738 </text> 1739 } 1740 1741 <text> 1742 var group = new Variants.VariantGroup("@GetString("Ecom:Product.ID")_@variantgroup.GetValue("Ecom:VariantGroup.ID")", "@variantgroup.GetValue("Ecom:VariantGroup.Name")", optionsArray); 1743 variants.push(group); 1744 </text> 1745 } 1746 1747 var combinations = []; 1748 @foreach (LoopItem variantcomb in GetLoop("VariantStockCombinations")) 1749 { 1750 <text> 1751 combinations.push(new Variants.CombinationItem("@variantcomb.GetValue("Ecom:VariantStockCombination.VariantID")")); 1752 </text> 1753 } 1754 1755 variants = variants.sort(function (a, b) { 1756 var firstVariantId = a.VariantOptions[0].variantId; 1757 for (var i = 0; i < combinations.length; i++) { 1758 var combinationIndex = combinations[i].id.indexOf(firstVariantId); 1759 if (combinationIndex != -1) { 1760 return combinationIndex; 1761 } 1762 } 1763 //should never happen 1764 return 0; 1765 }); 1766 1767 Variants.SetProductFeedId('@feedId'); 1768 Variants.SetProductUrl('/@GetString("Ecom:Product.VariantLinkGroup.Clean")'); 1769 1770 HandlebarsBolt.SetDataInCache(("Variants" + "@productId"), variants); 1771 HandlebarsBolt.SetDataInCache(("Combinations" + "@productId"), combinations); 1772 1773 document.getElementById("PriceAndActions").addEventListener('contentLoaded', function (e) { 1774 Variants.InitVariants(variants, combinations, "@productId", "@uniqueId"); 1775 }, false); 1776 1777 1778 Handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) { 1779 1780 var operators, result; 1781 1782 if (arguments.length < 3) { 1783 throw new Error("Handlerbars Helper 'compare' needs 2 parameters"); 1784 } 1785 1786 if (options === undefined) { 1787 options = rvalue; 1788 rvalue = operator; 1789 operator = "==="; 1790 } 1791 1792 operators = { 1793 '==': function (l, r) { return l == r; }, 1794 '===': function (l, r) { return l === r; }, 1795 '!=': function (l, r) { return l != r; }, 1796 '!==': function (l, r) { return l !== r; }, 1797 '<': function (l, r) { return l < r; }, 1798 '>': function (l, r) { return l > r; }, 1799 '<=': function (l, r) { return l <= r; }, 1800 '>=': function (l, r) { return l >= r; }, 1801 'typeof': function (l, r) { return typeof l == r; } 1802 }; 1803 1804 if (!operators[operator]) { 1805 throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator); 1806 } 1807 1808 result = operators[operator](lvalue, rvalue); 1809 1810 if (result) { 1811 return options.fn(this); 1812 } else { 1813 return options.inverse(this); 1814 } 1815 1816 }); 1817 1818 1819 }); 1820 </script> 1821 1822 @functions { 1823 string getIconForFile(string fileName) 1824 { 1825 string ext = Path.GetExtension(fileName); 1826 string icon = ""; 1827 switch (ext.ToLower()) 1828 { 1829 case ".xls": 1830 case ".xlsx": 1831 icon = "fa-file-excel-o"; 1832 break; 1833 case ".ppt": 1834 case ".pptx": 1835 icon = "fa-file-powerpoint-o"; 1836 break; 1837 case ".doc": 1838 case ".docx": 1839 icon = "fa-file-word-o"; 1840 break; 1841 case ".jpg": 1842 case ".jpeg": 1843 case ".png": 1844 case ".gif": 1845 case ".pdf": 1846 return "<img class='product__document-icon b-lazy' src='/Files/Images/placeholder.gif' data-src='/Admin/Public/GetImage.ashx?crop=5&height=70&width=120&Compression=75&DoNotUpscale=true&image=" + fileName + "' />"; 1847 default: 1848 icon = "fa-file-o"; 1849 break; 1850 } 1851 return "<i class='fa " + icon + "'></i> "; 1852 } 1853 1854 public static string ToPascalCase(string str) 1855 { 1856 return CultureInfo.InvariantCulture.TextInfo 1857 .ToTitleCase(str.ToLowerInvariant()) 1858 .Replace("-", "") 1859 .Replace("_", "") 1860 .Replace(" ", ""); 1861 } 1862 } 1863 1864 <script type="application/ld+json"> 1865 { 1866 "@@context": "http://schema.org/", 1867 "@@type": "Product", 1868 "name": "@GetString("Ecom:Product.Name")", 1869 @if (!string.IsNullOrEmpty(GetString("Ecom:Product.ImageLarge.Default.Clean"))) 1870 { 1871 <text>"image": [ 1872 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=400&crop=0&Compression=75&DoNotUpscale=true&image=@productImage", 1873 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=300&crop=0&Compression=75&DoNotUpscale=true&image=@productImage", 1874 "@siteURL/Admin/Public/GetImage.ashx?width=448&height=225&crop=0&Compression=75&DoNotUpscale=true&image=@productImage" 1875 ],</text> 1876 } 1877 "description": "@GetString("Ecom: Product.ShortDescription")", 1878 "mpn": "925872", 1879 @if (!string.IsNullOrEmpty(brand)) 1880 { 1881 <text>"brand": { 1882 "@@type": "Thing", 1883 "name": "@brand" 1884 },</text> 1885 } 1886 "offers": { 1887 "@@type": "Offer", 1888 "priceCurrency": "@GetString("Ecom:Product.Price.Currency.Code")", 1889 "price": "@GetString("Ecom:Product.Price.Price")", 1890 "availability": "@(GetInteger("Ecom:Product.Stock") > 0 ? "InStock" : "OutOfStock")" 1891 } 1892 } 1893 </script> 1894 <script> 1895 document.addEventListener("DOMContentLoaded", function () { 1896 if (document.getElementById("PriceAndActions")) { 1897 document.getElementById("PriceAndActions").addEventListener("contentLoaded", function (event) { 1898 if (document.querySelector(".js-variants") != null) { 1899 MatchVariants.Update(document.querySelector(".js-variants"), "DoNothing"); 1900 } 1901 }); 1902 } 1903 }); 1904 1905 //Custom dropdown 1906 var isOpen = false; 1907 1908 function toggleOptions(id) { 1909 1910 isOpen = !isOpen; 1911 if (isOpen) { 1912 document.getElementById(id).style.visibility = 'visible'; 1913 document.getElementById(id).classList.add("active"); 1914 document.getElementById(id).focus(); 1915 } else { 1916 document.getElementById(id).blur(); 1917 document.getElementById(id).classList.remove("active"); 1918 document.getElementById(id).style.visibility = 'hidden'; 1919 } 1920 1921 } 1922 1923 function selected(val, id, blurId) { 1924 document.getElementById(id).innerHTML = val; 1925 toggleOptions(blurId); 1926 var variantContainer = $(".js-variants"); 1927 variantContainer.find('.dropdown-container').each(function () { 1928 1929 var $this = $(this); 1930 var disabledItem = $this.find('.disabled'); 1931 if (disabledItem) { 1932 var displayValueItem = $this.find('.value-text'); 1933 1934 if (displayValueItem.html() == disabledItem.html()) { 1935 displayValueItem.html("@Translate("Select variant")"); 1936 } 1937 } 1938 1939 }); 1940 } 1941 </script>
![](/Files/Images/Lauridsen/img/new-contact-img.jpg?width=360&quality=75&mode=crop)
Kontakt os
Har du spørgsmål til vores produkter, løsninger eller services? Eller søger du hjælp til beregninger og dimensioneringer? Vi står klar til at hjælpe. Udfyld formularen herunder, og vi kontakter dig hurtigst muligt.