Error executing template "Designs/Tapas/eCom/Product/product.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_f123c1e93158489e9308128248149cf1.<>c__DisplayClass8_0.<renderTechSpecs2>b__0(TextWriter __razor_helper_writer) in E:\Websites\elma.LIVE\Files\Templates\Designs\Tapas\eCom\Product\product.cshtml:line 1280
   at CompiledRazorTemplates.Dynamic.RazorEngine_f123c1e93158489e9308128248149cf1.Execute() in E:\Websites\elma.LIVE\Files\Templates\Designs\Tapas\eCom\Product\product.cshtml:line 893
   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 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 3 @using Dynamicweb.Rendering; 4 @using System.Web; 5 @using Dynamicweb.Frontend; 6 @using Dynamicweb.Environment 7 @using System.Text.RegularExpressions; 8 @using NLog; 9 @using System.Net; 10 @using System.Drawing 11 @using System.IO; 12 13 @inherits RazorTemplateBase<RazorTemplateModel<Template>> 14 @using System.Web; 15 @using Dynamicweb.Rendering; 16 17 @helper renderProduct(LoopItem item, bool fourColsPerRow = false) 18 { 19 string productName = item.GetString("Ecom:Product.Name"); 20 string productNameEncoded = HttpUtility.UrlEncode(item.GetString("Ecom:Product.Name")); 21 string productNumber = item.GetString("Ecom:Product.Number"); 22 string productID = item.GetString("Ecom:Product.ID"); 23 string productCurrency = item.GetString("Ecom:Product.Currency"); 24 string productLink = item.GetString("Ecom:Product.Link.Clean"); 25 string productElNo = item.GetString("Ecom:Product:Field.FirstwebElNo.Value.Clean"); 26 bool productAskForPrice = item.GetBoolean("Ecom:Product:Field.FirstwebAskForPrice.Value.Clean"); 27 bool testDiscount = item.GetBoolean("Ecom:Product:Field.FirstwebIsDiscountPrice.Value.Clean"); 28 string productDescription = item.GetString("Ecom:Product.LongDescription"); 29 30 string nettoPriceWithoutVAT = item.GetString("Ecom:Product.Price.PriceWithoutVATFormatted");//item.GetString("Firstweb:ErpPriceInfo.NettoPriceFormattedNoSymbol"); 31 string nettoPriceWithVAT = item.GetString("Ecom:Product.Price.PriceWithVATFormatted"); 32 33 bool discountIsDiscountPrice = item.GetBoolean("Firstweb:Product.Discount.IsDiscountPrice"); 34 string discountDefaultPrice = item.GetString("Firstweb:Product.Discount.DefaultPriceFormatted"); 35 string discountEndDate = item.GetString("Firstweb:Product.Discount.EndDate"); 36 string discountPrice = item.GetString("Firstweb:Product.Discount.DefaultPriceWithVatFormatted"); 37 string StockColor = item.GetString("Firstweb:ErpStockInfo.StockColor"); 38 39 string orderLineId = item.GetString("Firstweb:OrderTemplate:Line.ID"); 40 string orderTemplateId = item.GetString("Firstweb:OrderTemplate:Line.OrderTemplateID"); 41 string orderLineQuantity = item.GetString("Firstweb:OrderTemplate:Line.Quantity"); 42 string orderLineComment = item.GetString("Firstweb:OrderTemplate:Line.Comment"); 43 bool inFavourite = item.GetInteger("Firstweb:Ecom:Product:OrderTemplate.InTemplates.Count") > 0 ? true : false; 44 string inFavouriteBoolJS = inFavourite.ToString().ToLower(); 45 int productInFavoritLists = item.GetInteger("Firstweb:Ecom:Product:OrderTemplate.InTemplates.Count"); 46 string missingImagePath = Dynamicweb.Core.Converter.ToString(Pageview.Area.Item["MissingImageLink"]); 47 bool orderTemplate = !string.IsNullOrEmpty(orderLineId); 48 bool askForPrice = item.GetBoolean("Ecom:Product:Field.FirstwebAskForPrice.Value.Clean"); 49 string imageDefaultPath = item.GetString("Ecom:Product.ImageDefault.Default.Clean"); 50 string imageUrl = String.Format("/admin/public/getimage.ashx?image={0}&altFmImage_path={1}&height=300&crop=5", imageDefaultPath, missingImagePath); 51 int stock = item.GetInteger("Firstweb:ErpStockInfo.StockQuantity"); 52 string stockStatus = "in-stock"; 53 if (stock <= 0) 54 { 55 stockStatus = "out-of-stock"; 56 } 57 else if (stock == 1) 58 { 59 stockStatus = "low-stock"; 60 } 61 bool noPrice = item.GetString("Ecom:Product.Price.PriceWithoutVAT") == "0,00" || item.GetString("Ecom:Product.Price.PriceWithoutVAT") == "0.00"; 62 int savingPct = item.GetInteger("Firstweb:Product.Discount.SavingPct"); 63 double saving = item.GetDouble("Firstweb:Product.Discount.Saving"); 64 string colClass = fourColsPerRow ? "col-lg-3" : "col-lg-4"; 65 string CustomerType = Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.CustomerType.GetCustomerType(); 66 string languageId = item.GetString("Ecom:Product.LanguageID"); 67 string country = ""; 68 if (languageId == "LANG1") 69 { 70 country = "Denmark"; 71 } 72 if (languageId == "LANG2") 73 { 74 country = "Sweden"; 75 } 76 if (languageId == "LANG3") 77 { 78 country = "Norway"; 79 } 80 if (languageId == "LANG4") 81 { 82 country = "England"; 83 } 84 string primaryGroupId = item.GetString("Ecom:Product.PrimaryGroupID"); 85 string primaryGroupName = ""; 86 87 if (!string.IsNullOrEmpty(primaryGroupId)) 88 { 89 var primaryGroup = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(primaryGroupId); 90 if (primaryGroup != null) 91 { 92 primaryGroupName = HttpUtility.HtmlEncode(primaryGroup.Name); 93 } 94 } 95 96 <!-- ko viewModel: Elma.ViewModels.ProductViewModel--> 97 <!-- ko initValue: {observable: ProductId, value:'@productID'}--><!-- /ko--> 98 <div class="col-xs-12 col-sm-6 @colClass product-list-col"> 99 100 <div class="elma-card elma-card--white product-list-card"> 101 <div class="product-list-card_img-ratio"> 102 @if (discountIsDiscountPrice && savingPct > 0) 103 { 104 <span class="product-list-card_saving-indicator">@savingPct %</span> 105 } 106 <a href="@productLink" class="product-list-card_img-container"> 107 <img src="@imageUrl" alt="@productName" class="product-list-card_img" /> 108 </a> 109 @if (!String.IsNullOrEmpty(productDescription)) 110 { 111 <a href="@productLink" class="product-list-card_hover-description" style="cursor:pointer;" data-bind="click: productLink.bind($data, '@productLink', '@productNameEncoded', '@productID', '@country', @saving, '@nettoPriceWithVAT', '@item.GetString("Ecom:Manufacturer.Name")', '@primaryGroupName', event)"> 112 @productDescription 113 <div class="product-list-card_description-read-more">@Translate("readmore", "Læs mere")</div> 114 </a> 115 } 116 </div> 117 <a href="@productLink" class="product-list-card_information-area" data-bind="click: productLink.bind($data, '@productLink', '@productNameEncoded', '@productID', '@country', @saving, '@nettoPriceWithVAT', '@item.GetString("Ecom:Manufacturer.Name")', '@primaryGroupName', event)"> 118 <p class="product-list-card_name">@productName</p> 119 <p class="product-list-card_id"> 120 @Translate("Firstweb:Product.ProductInfo.Eannumber", "EAN:") @productNumber 121 </p> 122 @if (!String.IsNullOrEmpty(productElNo)) 123 { 124 <p class="product-list-card_id"> 125 @Translate("Firstweb:Product.ProductInfo.Elnumber", "EL-NR.:") @productElNo 126 </p> 127 } 128 </a> 129 130 <div class="product-list-card_price-area"> 131 @if (!askForPrice) 132 { 133 <p class="stock-indicator stock-indicator--@stockStatus"> 134 <span class="stock-text stock-text--in-stock">@Translate("Firstweb:Product.ProductInfo.Stock.instock", "P&aring; lager")</span> 135 <span class="stock-text stock-text--low-stock">@Translate("Firstweb:Product.ProductInfo.Stock.lowstock", "Lav lagerbeholdning")</span> 136 <span class="stock-text stock-text--out-of-stock">@Translate("Firstweb:Product.ProductInfo.Stock.notinstock", "Ikke p&aring; lager")</span> 137 </p> 138 } 139 @if (askForPrice) 140 { 141 <div>@RenderParagraphContent(Dynamicweb.Core.Converter.ToInt32(Pageview.Area.Item["AskForPriceParagraph"]))</div> 142 } 143 else 144 { 145 if (discountIsDiscountPrice) 146 { 147 if (CustomerType == "Privat") 148 { 149 <p class="product-list-card_price--previous">@item.GetString("Firstweb:Product.Discount.DefaultPriceWithVatFormatted")</p> 150 } 151 else 152 { 153 <p class="product-list-card_price--previous">@item.GetString("Firstweb:Product.Discount.DefaultPriceFormatted")</p> 154 } 155 } 156 <p class="product-list-card_price"> 157 @if (CustomerType == "Privat") 158 { 159 <span class="product-list-card_price--current">@nettoPriceWithVAT</span> <span class="product-list-card_price--vat">@Translate("Firstweb:Product.ProductInfo.InclVat", "Incl. moms")</span> 160 } 161 else 162 { 163 <span class="product-list-card_price--current">@nettoPriceWithoutVAT</span> <span class="product-list-card_price--vat">@Translate("Firstweb:Product.ProductInfo.ExVat", "Excl. moms")</span> 164 } 165 </p> 166 } 167 </div> 168 <div class="product-list-card_button-area"> 169 <a class="btn btn-secondary" href="@productLink" data-bind="click: productLink.bind($data, '@productLink', '@productNameEncoded', '@productID', '@country', @saving, '@nettoPriceWithVAT', '@item.GetString("Ecom:Manufacturer.Name")', '@primaryGroupName', event)">@Translate("readmore", "Læs mere")</a> 170 @if (!noPrice && !askForPrice) 171 { 172 <button class="btn btn-primary add-to-cart-list" data-bind="click: $parent.AddProductFromProductViewModel" data-productid="@productID" data-product-info='["@productNameEncoded", "@productID", "@country", @saving, "@nettoPriceWithVAT", "@item.GetString("Ecom:Manufacturer.Name")", "@primaryGroupName"]'>@Translate("Productlist.AddToCart", "Læg i kurv")</button> 173 } 174 </div> 175 </div> 176 177 </div> 178 <!-- /ko--> 179 } 180 181 @* Variables for the producttemplate *@ 182 @{ 183 string productUrl = GetString("Ecom:Product.Link.Clean"); 184 productUrl = SearchEngineFriendlyURLs.GetFriendlyUrl(productUrl); 185 string eComProductCanonical = string.Empty; 186 187 if (string.IsNullOrEmpty(GetString("Ecom:Product.Canonical")) == false) 188 { 189 eComProductCanonical = String.Format("{0}://{1}{2}", GetGlobalValue("Global:Request.Scheme"), GetGlobalValue("Global:Request.Host"), "" + GetString("Ecom:Product.Canonical")); 190 } 191 else 192 { 193 eComProductCanonical = String.Format("{0}://{1}{2}", GetGlobalValue("Global:Request.Scheme"), GetGlobalValue("Global:Request.Host"), "" + productUrl); 194 } 195 196 string currentProductId = GetString("Ecom:Product.ID"); 197 198 //Get main webshop group breadcrumb 199 List<Dynamicweb.Ecommerce.Products.Group> breadCrumbGroupList = new List<Dynamicweb.Ecommerce.Products.Group>(); 200 Dynamicweb.Ecommerce.Products.Product currentProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(currentProductId, "", Firstweb.Custom.CustomCode.DWHelper.GetLanguageId()); 201 if (currentProduct != null && !String.IsNullOrEmpty(currentProduct.Id)) 202 { 203 var shopGroups = currentProduct.Groups.Where(g => g.ShopId == "SHOP2"); 204 205 Dynamicweb.Ecommerce.Products.Group mainShopGroup = null; 206 207 if (!String.IsNullOrEmpty(currentProduct.PrimaryGroupId)) 208 { 209 mainShopGroup = shopGroups.FirstOrDefault(g => g.Id == currentProduct.PrimaryGroupId); 210 } 211 212 if (mainShopGroup == null) 213 { 214 mainShopGroup = shopGroups.FirstOrDefault(); 215 } 216 217 if (mainShopGroup != null) 218 { 219 breadCrumbGroupList = Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.EcomGroups.getBreadCrumbGroupList(mainShopGroup, true); 220 } 221 } 222 223 int favouriteCount = GetInteger("Firstweb:Ecom:Product:OrderTemplate.InTemplates.Count"); 224 string productName = !String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.FirstwebHeadline.Value.Clean")) ? GetString("Ecom:Product:Field.FirstwebHeadline.Value.Clean") : GetString("Ecom:Product.Name"); 225 string productNameEncoded = HttpUtility.UrlEncode(GetString("Ecom:Product.Name")); 226 string subHeading = GetString("Ecom:Product:Field.FirstwebSubheadline.Value.Clean"); 227 228 string productNumber = GetString("Ecom:Product.Number"); 229 string productId = GetString("Ecom:Product.ID"); 230 string productCurrency = GetString("Ecom:Product.Currency"); 231 string productLink = GetString("Ecom:Product.Link.Clean"); 232 233 bool nobuy = true; 234 235 if (Dynamicweb.Frontend.PageView.Current() != null && Dynamicweb.Frontend.PageView.Current().Page != null && 236 Dynamicweb.Frontend.PageView.Current().Page.NavigationTag != null) 237 { 238 nobuy = Dynamicweb.Frontend.PageView.Current().Page.NavigationTag.ToLower().Equals("ecom_nobuy"); 239 } 240 241 var productDocuments = Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.ProductDocuments.getProductPimDocuments(productId); 242 243 244 bool askForPrice = GetBoolean("Ecom:Product:Field.FirstwebAskForPrice.Value.Clean"); 245 246 string ForceStock = GetString("Firstweb:ErpStockInfo.Configuration(ForceStock)"); //Used to make the product template provider fetch stock status from visma 247 248 string iFrameWidth = Dynamicweb.Core.Converter.ToString(Pageview.Area.Item["GlobalProductVideoIframeWidth"]); 249 string videoTitle = GetString("Ecom:Product:Field.FirstwebVideoText.Value.Clean"); 250 int productInFavoritLists = GetInteger("Firstweb:Ecom:Product:OrderTemplate.InTemplates.Count"); 251 string userDefinedLink = GetString("Ecom:Product:Field.FirstwebVideoLink.Value"); 252 bool inFavourite = productInFavoritLists > 0; 253 string inFavouriteBoolJS = inFavourite.ToString().ToLower(); 254 255 string productPageID = Dynamicweb.Core.Converter.ToInt32(Pageview.Area.Item["ProductCatalogId"]).ToString(); 256 string productPageHref = "/Default.aspx?ID=" + productPageID; 257 var productImages = Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.ProductImages.getProductImages(productId); 258 259 // Decide which sections to show on the page 260 bool showVideoSection = !string.IsNullOrWhiteSpace(userDefinedLink); 261 bool showDocumentSection = (productDocuments.Count > 0); 262 bool isReadMoreVisible = false; 263 264 bool printActivated = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.GetString("activatePrint")); 265 266 if (GetString("Ecom:Product.LongDescription").Length > 350) 267 { 268 isReadMoreVisible = true; 269 } 270 int stock = GetInteger("Firstweb:ErpStockInfo.StockQuantity"); 271 string stockStatus = "in-stock"; 272 if (stock <= 0) 273 { 274 stockStatus = "out-of-stock"; 275 } 276 else if (stock == 1) 277 { 278 stockStatus = "low-stock"; 279 } 280 string CustomerType = Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.CustomerType.GetCustomerType(); 281 bool onDiscount = GetBoolean("Firstweb:Product.Discount.IsDiscountPrice"); 282 string discountPrice = GetString("Firstweb:Product.Discount.DefaultPriceWithVatFormatted"); 283 int savingPct = GetInteger("Firstweb:Product.Discount.SavingPct"); 284 double saving = GetDouble("Firstweb:Product.Discount.Saving"); 285 286 bool showNewSpecs = GetBoolean("Ecom:Product:Field.ShowNewSpecs.Value.Clean"); 287 bool debugSpecs = Dynamicweb.Context.Current.Request.GetBoolean("debugspecs"); 288 string debugSpecsOldDebugLabel = debugSpecs ? " [#OLD]" : ""; 289 string debugSpecsNewDebugLabel = debugSpecs ? " [#NEW]" : ""; 290 291 string languageId = GetString("Ecom:Product.LanguageID"); 292 string country = ""; 293 if (languageId == "LANG1") 294 { 295 country = "Denmark"; 296 } 297 if (languageId == "LANG2") 298 { 299 country = "Sweden"; 300 } 301 if (languageId == "LANG3") 302 { 303 country = "Norway"; 304 } 305 if (languageId == "LANG4") 306 { 307 country = "England"; 308 } 309 string primaryGroupId = GetString("Ecom:Product.PrimaryGroupID"); 310 string primaryGroupName = ""; 311 312 if (!string.IsNullOrEmpty(primaryGroupId)) 313 { 314 var primaryGroup = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(primaryGroupId); 315 if (primaryGroup != null) 316 { 317 primaryGroupName = HttpUtility.HtmlEncode(primaryGroup.Name); 318 } 319 } 320 321 var HiddenProductSpecificationDisplayGroup = GetLoop("FieldDisplayGroups").FirstOrDefault(fdg => fdg.GetString("Ecom:FieldDisplayGroup.SystemName") == "Frontend_HIddenSpecificationsProductPage"); 322 List<string> HiddenProductSpecificationFieldIds = new List<string>(); 323 324 if (HiddenProductSpecificationDisplayGroup != null) 325 { 326 HiddenProductSpecificationFieldIds = HiddenProductSpecificationDisplayGroup.GetLoop("Fields").Select(f => f.GetString("Ecom:FieldDisplayGroup.Field.Id")).ToList(); 327 } 328 329 330 } 331 332 @SnippetStart("eComCanonical")@eComProductCanonical.TrimEnd(new[] { '/' })@SnippetEnd("eComCanonical") 333 334 @inherits RazorTemplateBase<RazorTemplateModel<Template>> 335 @using Dynamicweb.Rendering; 336 @using System.Text.RegularExpressions; 337 @using System.Text; 338 @using System.Web; 339 340 @* Checkout stuff - START *@ 341 342 @{ 343 @functions { 344 string GetCurrentActiveStepClass(int currentStep, int activeStep) 345 { 346 return currentStep >= activeStep ? "active" : ""; 347 } 348 } 349 } 350 351 @helper GetOrderLines(IEnumerable<LoopItem> Loop, string type = "checkout") 352 { 353 string CustomerType = Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.CustomerType.GetCustomerType(); 354 foreach (LoopItem item in Loop) 355 { 356 string productId = item.GetString("Ecom:Product.ID"); 357 string productName = item.GetString("Ecom:Product.Name"); 358 string productNameEncoded = HttpUtility.UrlEncode(productName); 359 string productNumber = item.GetString("Ecom:Product.Number"); 360 string orderLineUnitPrice = item.GetString("Ecom:Order:OrderLine.UnitPrice.PriceWithoutVAT"); 361 string orderLineUnitPriceVat = item.GetString("Ecom:Order:OrderLine.UnitPrice.PriceWithVAT"); 362 string orderLinePriceVat = item.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.PriceWithVAT"); 363 string productCurrency = item.GetString("Ecom:Product.Currency.Code"); 364 int orderLineQuantity = item.GetInteger("Ecom:Order:OrderLine.Quantity"); 365 double saving = item.GetDouble( "Firstweb:Order.Discount.Saving"); 366 367 string languageId = item.GetString("Ecom:Product.LanguageID"); 368 string country = ""; 369 if (languageId == "LANG1") 370 { 371 country = "Denmark"; 372 } 373 if (languageId == "LANG2") 374 { 375 country = "Sweden"; 376 } 377 if (languageId == "LANG3") 378 { 379 country = "Norway"; 380 } 381 if (languageId == "LANG4") 382 { 383 country = "England"; 384 } 385 string primaryGroupId = item.GetString("Ecom:Product.PrimaryGroupID"); 386 string primaryGroupName = ""; 387 388 if (!string.IsNullOrEmpty(primaryGroupId)) 389 { 390 var primaryGroup = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(primaryGroupId); 391 if (primaryGroup != null) 392 { 393 primaryGroupName = HttpUtility.HtmlEncode(primaryGroup.Name); 394 } 395 } 396 397 <div class="row margin-top-half summary-orderline" data-product-info='["@productNameEncoded", "@productId", "@country", @saving, "@orderLinePriceVat", "@productCurrency", "@item.GetString("Ecom:Manufacturer.Name")", "@primaryGroupName", "@orderLineQuantity"]'> 398 <div class="col-md-7 col-sm-7 col-xs-7"> 399 <strong>@productName</strong> 400 </div> 401 @if (CustomerType == "Privat") 402 { 403 <div class="col-md-5 col-sm-5 col-xs-5 text-right xs-regular-padding"> 404 @orderLineQuantity @Translate("Checkout.Quantity.One", "stk.") @Translate("Checkout.Quantity.OnePrefix", "á") @orderLineUnitPriceVat <span>@productCurrency</span> 405 </div> 406 } 407 else 408 { 409 <div class="col-md-5 col-sm-5 col-xs-5 text-right xs-regular-padding"> 410 @orderLineQuantity @Translate("Checkout.Quantity.One", "stk.") @Translate("Checkout.Quantity.OnePrefix", "á") @orderLineUnitPrice <span>@productCurrency</span> 411 </div> 412 } 413 </div> 414 } 415 } 416 417 @helper renderCartSteps(int currentActiveStep) { 418 <div class="row"> 419 420 <div class="col-xs-3"> 421 <div class="cart-step cart-step--@GetCurrentActiveStepClass(currentActiveStep, 1)"> 422 <div class="cart-step_icon"> 423 <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="shopping-cart" class="svg-inline--fa fa-shopping-cart fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M528.12 301.319l47.273-208C578.806 78.301 567.391 64 551.99 64H159.208l-9.166-44.81C147.758 8.021 137.93 0 126.529 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24h69.883l70.248 343.435C147.325 417.1 136 435.222 136 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-15.674-6.447-29.835-16.824-40h209.647C430.447 426.165 424 440.326 424 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-22.172-12.888-41.332-31.579-50.405l5.517-24.276c3.413-15.018-8.002-29.319-23.403-29.319H218.117l-6.545-32h293.145c11.206 0 20.92-7.754 23.403-18.681z"></path></svg> 424 </div> 425 <p class="cart-step_name">@Translate("CartStep.Cart", "Kurv")</p> 426 <div class="cart-step_completion-indicator"></div> 427 </div> 428 </div> 429 430 <div class="col-xs-3"> 431 <div class="cart-step cart-step--@GetCurrentActiveStepClass(currentActiveStep, 2)"> 432 <div class="cart-step_icon"> 433 <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="home" class="svg-inline--fa fa-home fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z"></path></svg> 434 </div> 435 <p class="cart-step_name">@Translate("CartStep.Address", "Adresse")</p> 436 <div class="cart-step_completion-indicator"></div> 437 </div> 438 </div> 439 440 <div class="col-xs-3"> 441 <div class="cart-step cart-step--@GetCurrentActiveStepClass(currentActiveStep, 3)"> 442 <div class="cart-step_icon"> 443 <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="coins" class="svg-inline--fa fa-coins fa-w-16 img-responsive" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M0 405.3V448c0 35.3 86 64 192 64s192-28.7 192-64v-42.7C342.7 434.4 267.2 448 192 448S41.3 434.4 0 405.3zM320 128c106 0 192-28.7 192-64S426 0 320 0 128 28.7 128 64s86 64 192 64zM0 300.4V352c0 35.3 86 64 192 64s192-28.7 192-64v-51.6c-41.3 34-116.9 51.6-192 51.6S41.3 334.4 0 300.4zm416 11c57.3-11.1 96-31.7 96-55.4v-42.7c-23.2 16.4-57.3 27.6-96 34.5v63.6zM192 160C86 160 0 195.8 0 240s86 80 192 80 192-35.8 192-80-86-80-192-80zm219.3 56.3c60-10.8 100.7-32 100.7-56.3v-42.7c-35.5 25.1-96.5 38.6-160.7 41.8 29.5 14.3 51.2 33.5 60 57.2z"></path></svg> 444 </div> 445 <p class="cart-step_name">@Translate("CartStep.Payment", "Betaling")</p> 446 <div class="cart-step_completion-indicator"></div> 447 </div> 448 </div> 449 450 <div class="col-xs-3"> 451 <div class="cart-step cart-step--@GetCurrentActiveStepClass(currentActiveStep, 4)"> 452 <div class="cart-step_icon"> 453 <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="check" class="svg-inline--fa fa-check fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z"></path></svg> 454 </div> 455 <p class="cart-step_name">@Translate("CartStep.Receipt", "Kvittering")</p> 456 </div> 457 </div> 458 459 </div> 460 } 461 462 @* Checkout stuff - END *@ 463 464 465 @* Regular functions *@ 466 467 @** 468 * StringDelimiter() 469 * Takes the description texts and shortens them so 470 * they can be displayed in a "cropped" version, 471 ***@ 472 473 @helper StringDelimiter(string textString, int maxLength = 20, string delimiterType = "d", string regex = " ") 474 { 475 476 var delimiterPattern = regex == " " ? new Regex(@"\s+").ToString() : new Regex(@"-").ToString(); 477 478 string returnString = String.Empty; 479 string fullText = String.Empty; 480 /** 481 * Helper to delimit a long string to a custom amount of words - if used default. 482 * If delimiterType is set to custom, the regex will decide the delimier and insert a linebreak instead 483 **/ 484 StringBuilder sb = new StringBuilder(); 485 486 switch (delimiterType) 487 { 488 case "textLength": 489 490 // find all spaces between words 491 MatchCollection matches = Regex.Matches(textString, delimiterPattern); 492 493 int wordLimit = maxLength; 494 int wordCharLength = wordLimit * 6; 495 496 string firstFourWords = (matches.Count >= wordLimit) ? (textString.Substring(0, matches[wordLimit - 1].Index)) : (textString); 497 498 string firstFortyCharacters = textString.Substring(0, Math.Min(textString.Length, wordCharLength)); 499 string restOfText = textString.Substring(Math.Min(textString.Length, wordCharLength)); 500 string result = (firstFourWords.Length > wordCharLength) ? (firstFortyCharacters) : (firstFourWords); 501 502 fullText = "<p id='fullDescription' class='invisible'>" + restOfText.Trim() + "</p>"; 503 504 sb.Append(result.Trim()); 505 sb.Append("..."); 506 507 break; 508 509 default: 510 511 MatchCollection matchesDash = Regex.Matches(textString, delimiterPattern); 512 513 if (matchesDash.Count > 0) 514 { 515 // Console.WriteLine(matchesDash[0].Index); 516 sb.Append(textString.Substring(0, matchesDash[0].Index + 1)); 517 sb.Append("<br />"); 518 sb.Append(textString.Substring(matchesDash[0].Index + 1)); 519 } 520 else 521 { 522 // Failsafe for showing atleast some text if anything goes wrong. 523 sb.Append(textString); 524 } 525 526 break; 527 } 528 529 @sb.ToString(); 530 if (fullText != String.Empty) 531 { 532 @fullText 533 } 534 } 535 536 537 @** 538 * generateVideoLink() 539 * Creates the video link from the userdefined link on the specific product. 540 * The helper supports both the full embed link, 541 * but also if the user inserts the normal youtube link. 542 **@ 543 544 @helper generateVideoLink(string link, string product, string videoTitle, string iFrameWidth) 545 { 546 string youtubeEmbedUrl = "https://www.youtube.com/embed/", 547 result = string.Empty, 548 element = string.Empty; 549 string videoId = string.Empty; 550 string embedHeight = string.Empty; 551 552 if (link.Contains(youtubeEmbedUrl)) 553 { 554 result = link; 555 var embedLength = youtubeEmbedUrl.Length; 556 var linkLength = link.Length; 557 var differenceInLength = linkLength - embedLength; 558 videoId = link.Substring(embedLength, differenceInLength); // get video id with substring 559 } 560 else 561 { 562 var uri = new Uri(link); 563 var query = HttpUtility.ParseQueryString(uri.Query); 564 videoId = query["v"]; 565 result = youtubeEmbedUrl + videoId; 566 } 567 string videoImagePath = String.Format("https://i1.ytimg.com/vi/{0}/maxresdefault.jpg", videoId); 568 569 <figure class="product-video-container product-video-container--link" id="cover-image-container" data-bind="click: toggleCoverImage, css: {visible:isVisible}"> 570 <img src="@videoImagePath" alt='@Translate("Firstweb.Ecom.Product.Details.ProductVideo", "Se ")@videoTitle' class="img-responsive center-block" /> 571 <a class="big-play-button" id="play"><i class="fa fa-youtube-play big-play-icon color-primary gradient-background" aria-hidden="true"></i></a> 572 </figure> 573 <figure class="product-video-container text-center embed-responsive embed-responsive-16by9" data-bind="visible: isVisible"> 574 <iframe src='@result' class='product-video-element embed-responsive-item' allowfullscreen></iframe> 575 </figure> 576 } 577 578 @if (printActivated == false) 579 { 580 <article class="product-view" data-bind="viewModel: Elma.ViewModels.ProductPageViewModel"> 581 582 <section class="product-view__main"> 583 <div> 584 <div class="container"> 585 <div> 586 <ul class="row breadcrumb"> 587 <li> 588 <a href="@productPageHref" title="@Translate("Firstweb.Content.Breadcrumbs.ProductPage", "Produkter")">@Translate("Firstweb.Content.Breadcrumbs.ProductPage", "Produkter")</a> 589 </li> 590 @foreach (var g in breadCrumbGroupList) 591 { 592 <li> 593 <a href='/Default.aspx?ID=@GetString("Ecom:Product:Page.ID")&amp;GroupID=@g.Id' title="@g.Name">@g.Name</a> 594 </li> 595 } 596 </ul> 597 </div> 598 </div> 599 </div> 600 601 <div> 602 <section class="container"> 603 <div id="product-view-details" class="product-view__details" data-bind="event: { DOMContentLoaded: gtmDataLayer() }" data-product-info='["@productNameEncoded", "@productId", "@country", @saving, "@GetString("Ecom:Product.Price.PriceWithVATFormatted")", "@GetString("Ecom:Manufacturer.Name")", "@primaryGroupName"]'> 604 <div class="row"> 605 <div class="col-md-6 col-sm-12 col-xs-12 detailsBox"> 606 <div class="product-view__meta"> 607 <span>@Translate("Firstweb:Product.ProductInfo.Eannumber", "EAN")</span> 608 <span>@GetString("Ecom:Product.Number")</span> / <span>@Translate("Firstweb:Product.ProductInfo.Elnumber", "EL-NR")</span> 609 <span>@GetString("Ecom:Product:Field.FirstwebElNo.Value.Clean")</span> 610 </div> 611 612 <div class="product-view__headings"> 613 <h1 class="product-view__heading">@productName</h1> 614 <h2 class="product-view__subheading">@subHeading</h2> 615 </div> 616 617 <div class="row" data-bind="viewModel: Tapas.ViewModels.ProductViewModel"> 618 619 <div class="col-xs-12 product-view__pricing" data-bind="initValue: {observable : ProductId, value: '@GetString("Ecom:Product.ID")'}"> 620 @if (!nobuy) 621 { 622 if (askForPrice) 623 { 624 <div class="row"> 625 @RenderParagraphContent(Dynamicweb.Core.Converter.ToInt32(Pageview.Area.Item["AskForPriceParagraph"])) 626 </div> 627 } 628 else 629 { 630 <div class="row"> 631 <div class="col-md-10 col-sm-10 col-xs-12 price"> 632 633 @{ 634 if (onDiscount) 635 { 636 <div class="row product-sale"> 637 <div class="col-xs-12"> 638 @if (CustomerType == "Privat") 639 { 640 <div class="product-old-price text-left">@GetString("Firstweb:Product.Discount.DefaultPriceWithVatFormatted")</div> 641 } 642 else 643 { 644 <div class="product-old-price text-left">@GetString("Firstweb:Product.Discount.DefaultPriceFormatted")</div> 645 } 646 647 </div> 648 </div> 649 } 650 } 651 @if (CustomerType == "Privat") 652 { 653 <div class="actual-price text-left">@GetString("Ecom:Product.Price.PriceWithVATFormatted")</div> 654 <div class="small-price-vat text-left">@Translate("Firstweb.Ecom.Product.Details.Price.No.VAT", "Pris eksl. moms ") @GetString("Ecom:Product.Price.PriceWithoutVATFormatted")</div> 655 } 656 else 657 { 658 <div class="actual-price text-left">@GetString("Ecom:Product.Price.PriceWithoutVATFormatted")</div> 659 <div class="small-price-vat text-left">@Translate("Firstweb.Ecom.Product.Details.Price.Excl.VAT", "Pris incl. moms ") @GetString("Ecom:Product.Price.PriceWithVATFormatted")</div> 660 } 661 @if (onDiscount) 662 { 663 <div class="small-price-vat text-left">@Translate("Firstweb.Ecom.Product.Details.Price.Discount.Until", "Tilbud t.o.m. ") @GetString("Firstweb:Product.Discount.EndDate")</div> 664 } 665 </div> 666 </div> 667 } 668 } 669 </div> 670 @if (!askForPrice) 671 { 672 <div class="col-xs-12"> 673 <p class="stock-indicator stock-indicator--@stockStatus product-view__stock"> 674 <span class="stock-text stock-text--in-stock">@Translate("Firstweb:Product.ProductInfo.Stock.instock", "P&aring; lager")</span> 675 <span class="stock-text stock-text--low-stock">@Translate("Firstweb:Product.ProductInfo.Stock.lowstock", "Lav lagerbeholdning")</span> 676 <span class="stock-text stock-text--out-of-stock">@Translate("Firstweb:Product.ProductInfo.Stock.notinstock", "Ikke p&aring; lager")</span> 677 </p> 678 </div> 679 } 680 <div class="col-xs-12 product-buttons hidden-print"> 681 @if (!nobuy) 682 { 683 <div class="product-buttons__item"> 684 @if (askForPrice == false) 685 { 686 <input type="hidden" value="1" class="hide" data-bind="textInput: Quantity"> 687 688 if (GetString("Ecom:Product.Price.PriceWithoutVAT") == "0,00" || GetString("Ecom:Product.Price.PriceWithoutVAT") == "0.00") 689 { 690 <div class="btn btn-primary add-to-cart product-button not-active" data-bind="loadOnBool: { observableBool: $parent.CartLoading, text: '@Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.Base.JSTrimTranslation(Translate(" addproduct", "Tilf&oslash;jer produkt"))' }"> 691 @Translate("Firstweb.Ecom.Product.Details.Addtocart", "K&oslash;b nu") 692 </div> 693 } 694 else 695 { 696 <div class="btn btn-primary add-to-cart product-button" data-bind="click: $parent.AddProductFromProductViewModel, loadOnBool: { observableBool: $parent.CartLoading, text: '@Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.Base.JSTrimTranslation(Translate(" addproduct", "Tilf&oslash;jer produkt"))' }"> 697 @Translate("Firstweb.Ecom.Product.Details.Addtocart", "K&oslash;b nu") 698 </div> 699 } 700 } 701 </div> 702 } 703 704 <div class="product-buttons__item" data-bind="with: OrderTemplateViewModel"> 705 <!-- ko initValue: {observable: OrderTemplateRelationCount, value:'@favouriteCount'}--><!-- /ko--> 706 <!-- ko initValue: {observable: ShowInFavourite, value: @inFavouriteBoolJS}--><!-- /ko--> 707 708 <div class="add-to-wish product-view__add-to-wish product-button" 709 data-bind="css : { showFavorite : ShowOrderTemplateDialog}, 710 visible: $root.User().IsLoggedIn(), 711 click: ToggleOrderTemplateDialog"> 712 <?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 25.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 40 40" style="enable-background:new 0 0 40 40;" xml:space="preserve"> <style type="text/css"> .st0{fill:#97C93D;} .st1{fill:#FFFFFF;} </style> <path id="Rectangle_380" class="st0" d="M6,0h28c3.3,0,6,2.7,6,6v28c0,3.3-2.7,6-6,6H6c-3.3,0-6-2.7-6-6V6C0,2.7,2.7,0,6,0z"/> <path id="Path_581" class="st1" d="M20,30.3L18.5,29c-5.1-4.7-8.5-7.8-8.5-11.5c0-3,2.4-5.5,5.4-5.5c0,0,0.1,0,0.1,0 c1.7,0,3.4,0.8,4.5,2.1c1.1-1.3,2.8-2.1,4.5-2.1c3,0,5.5,2.4,5.5,5.4c0,0,0,0.1,0,0.1c0,3.8-3.4,6.9-8.5,11.5L20,30.3z"/> </svg> 713 </div> 714 </div> 715 716 <div class="product-buttons__item"> 717 @{ 718 string httpProtocole = HttpContext.Current.Request.IsSecureConnection ? "https" : "http"; 719 string printPageUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetPageIdByNavigationTag("ProductPrintPage")) + $"?ProductId={productId}"; 720 string pageLink = String.Format("{0}://{1}{2}&activatePrint=true", httpProtocole, HttpContext.Current.Request.Url.Host, printPageUrl); 721 string pdfServiceParameter = String.Format("{0}&filename={1}.pdf", HttpUtility.UrlEncode(pageLink), HttpUtility.UrlEncode(productName)); 722 string pdfLink = String.Format("https://pdfservice.1stweb.dk/?printurl={0}", pdfServiceParameter); 723 } 724 <a href="@pdfLink" target="_blank" class="print-as-pdf color-info flex-center" title="@Translate("Firstweb.Ecom.Product.Details.PrintAsPDF", "PDF")"> 725 <span class="btn__icon"> 726 <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-pdf" class="svg-inline--fa fa-file-pdf fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M181.9 256.1c-5-16-4.9-46.9-2-46.9 8.4 0 7.6 36.9 2 46.9zm-1.7 47.2c-7.7 20.2-17.3 43.3-28.4 62.7 18.3-7 39-17.2 62.9-21.9-12.7-9.6-24.9-23.4-34.5-40.8zM86.1 428.1c0 .8 13.2-5.4 34.9-40.2-6.7 6.3-29.1 24.5-34.9 40.2zM248 160h136v328c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V24C0 10.7 10.7 0 24 0h200v136c0 13.2 10.8 24 24 24zm-8 171.8c-20-12.2-33.3-29-42.7-53.8 4.5-18.5 11.6-46.6 6.2-64.2-4.7-29.4-42.4-26.5-47.8-6.8-5 18.3-.4 44.1 8.1 77-11.6 27.6-28.7 64.6-40.8 85.8-.1 0-.1.1-.2.1-27.1 13.9-73.6 44.5-54.5 68 5.6 6.9 16 10 21.5 10 17.9 0 35.7-18 61.1-61.8 25.8-8.5 54.1-19.1 79-23.2 21.7 11.8 47.1 19.5 64 19.5 29.2 0 31.2-32 19.7-43.4-13.9-13.6-54.3-9.7-73.6-7.2zM377 105L279 7c-4.5-4.5-10.6-7-17-7h-6v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-74.1 255.3c4.1-2.7-2.5-11.9-42.8-9 37.1 15.8 42.8 9 42.8 9z"></path></svg> 727 </span> 728 <span>@Translate("Firstweb.Ecom.Product.Details.PrintAsPDF", "PDF")</span> 729 </a> 730 </div> 731 </div> 732 733 <div class="col-xs-12 list" data-bind="visible: $root.User().IsLoggedIn(), with: OrderTemplateViewModel"> 734 <div class="add-to-wish" data-bind="css : { showFavorite : ShowOrderTemplateDialog }, 735 visible: $root.User().IsLoggedIn()"> 736 </div> 737 <div class="favoriteDropdown product-list-favourite product-details elma-card"> 738 <div> 739 <div class="toggleNewList" data-bind="css: {showNewList : OrderTemplateShowNewList}, toggleClick: OrderTemplateShowNewList">@Translate("makenewlist", "Opret ny liste")</div> 740 <select class="favField" data-bind="options: OrderTemplateList, optionsCaption:'@Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.Base.JSTrimTranslation(Translate("chooseFromList", "Vælg en liste"))', optionsText: function(item) { return item.Value.Name() + ' (' + item.Value.Count() + ') Varer' }, value: OrderTemplateSelectedList"></select> 741 <input type="text" placeholder="@Translate("favoritlistname", "Favoritliste navn")" class="bs form-control newList favField" data-bind="textInput: OrderTemplateNewListName" /> 742 <input type="hidden" class="bs quantity" data-bind="textInput: OrderTemplateQuantity" value="1" /> 743 <div class="save-button btn btn-primary" data-bind="click: function() { OrderTemplateShowNewList() ? CreateNewOrderTemplateList('@currentProductId') : AddProductToOrderTemplate('@currentProductId') } "> 744 @Translate("addtofavoritlist", "Gem") 745 </div> 746 </div> 747 </div> 748 </div> 749 </div> 750 751 <div class="row tableRow"> 752 <div class="col-xs-12"> 753 <div class="main-product-description-full">@GetString("Ecom:Product.LongDescription")</div> 754 <!-- ko initValue: {observable: readMoreBeforeText, value:'@Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.Base.JSTrimTranslation(Translate("Firstweb:Product.ProductInfo.readMore", "Læs yderligere produktinformation"))'}--><!-- /ko--> 755 <!-- ko initValue: {observable: readMoreAfterText, value: '@Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.Base.JSTrimTranslation(Translate("Firstweb:Product.ProductInfo.CloseReadMore", "Luk"))'}--><!-- /ko--> 756 <!-- ko initValue: {observable: readMoreElementName, value: '.main-product-description-full'}--><!-- /ko--> 757 <a href="#" title='@Translate("Firstweb:Product.ProductInfo.readMore", "Læs yderligere produktinformation")' class="product-view__read-more-link" role="button" data-bind="visible: isReadMoreRelevant, click: toggleReadMore"> 758 <span class="elma-link js-text" data-bind="text: readMoreButtonText"></span> 759 </a> 760 </div> 761 </div> 762 </div> 763 764 <!-- Product image --> 765 <div class="col-xs-12 col-md-6" style="overflow: hidden;padding-bottom: 10px;min-height:100px;"> 766 <div class="product-view__image-zoom" data-bind="click: zoomClickHandler"> 767 <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 768 viewBox="0 0 43 43" style="enable-background:new 0 0 43 43;" xml:space="preserve"> 769 <style type="text/css"> 770 771 .st69 { 772 fill: #E8E8E8; 773 } 774 775 .st420 { 776 fill: #595959; 777 } 778 </style> 779 <circle id="Ellipse_14" class="st69" cx="21.5" cy="21.5" r="21.5" /> 780 781 <g> 782 <path class="st420" d="M31.8401,11.5135c-0.0008-0.0019-0.001-0.0039-0.0018-0.0058c-0.152-0.3724-0.4484-0.6692-0.8207-0.8215 783 c-0.0056-0.0023-0.0113-0.003-0.0168-0.0052c-0.1707-0.0675-0.3555-0.1074-0.5502-0.1074h-8.1475c-0.8286,0-1.5,0.6714-1.5,1.5 784 s0.6714,1.5,1.5,1.5h4.5251l-4.5007,4.501c-0.5859,0.5859-0.5859,1.5352,0,2.1211c0.293,0.293,0.6768,0.4395,1.0605,0.4395 785 s0.7676-0.1465,1.0605-0.4395l4.502-4.5023v4.5276c0,0.8281,0.6714,1.5,1.5,1.5s1.5-0.6719,1.5-1.5v-8.1475 786 C31.9506,11.8752,31.9101,11.6869,31.8401,11.5135z" /> 787 788 <path class="st420" d="M20.2206,28.9496H15.696l4.5007-4.501c0.5859-0.5859,0.5859-1.5352,0-2.1211s-1.5352-0.5859-2.1211,0 789 l-4.502,4.5023v-4.5276c0-0.8281-0.6714-1.5-1.5-1.5s-1.5,0.6719-1.5,1.5v8.1475c0,0.1983,0.0405,0.3867,0.1105,0.5599 790 c0.0008,0.002,0.001,0.0038,0.0018,0.0058c0.152,0.3723,0.4484,0.6692,0.8206,0.8215c0.0058,0.0024,0.0116,0.0032,0.0174,0.0054 791 c0.1706,0.0674,0.3552,0.1073,0.5497,0.1073h8.147c0.8286,0,1.5-0.6719,1.5-1.5S21.0492,28.9496,20.2206,28.9496z" /> 792 793 </g> 794 </svg> 795 796 </div> 797 @if (onDiscount) 798 { 799 <div class="product-view__saving-pct">@savingPct %</div> 800 } 801 <div id="slider" class="product-gallery" data-bind="css: { 'loaded' : loadedGallery }, lightSlider: lightSliderGalleryConfig"> 802 @foreach (string imagePath in productImages) 803 { 804 string encodedImage = HttpUtility.UrlEncode(imagePath); 805 806 <div data-thumb="/admin/public/getimage.ashx?image=@encodedImage&altFmImage_path=/Files/Images/ecom/no-image.png&amp;width=840" data-src="/admin/public/getimage.ashx?image=@encodedImage&altFmImage_path=/Files/Images/ecom/no-image.png&amp;width=840" alt="@GetString("Ecom:Product.Name")"> 807 <img src="x.gif" style="width:580px;height:440px;background-image:url(/admin/public/getimage.ashx?image=@encodedImage&altFmImage_path=/Files/Images/ecom/no-image.png&width=580&height=440&crop=5);background-size:contain;background-position:50% 50%;background-repeat:no-repeat;" alt="@GetString("Ecom:Product.Name")" /> 808 </div> 809 } 810 </div> 811 </div> 812 </div> 813 </div> 814 </section> 815 </div> 816 </section> 817 818 <section class="product-info"> 819 <div> 820 @{ 821 LoopItem kitRelationGroup = GetLoop("ProductRelatedGroups").FirstOrDefault(g => g.GetString("Ecom:Product:RelatedGroup.Name").ToLower().Equals("kit")); 822 823 if (kitRelationGroup != null) 824 { 825 List<LoopItem> kitRelationGroupProducts = kitRelationGroup.GetLoop("Products"); 826 if (kitRelationGroupProducts.Any()) 827 { 828 @RenderKitRow(kitRelationGroupProducts) 829 } 830 } 831 } 832 <div class="container spacing-vert spacing-vert--padded"> 833 <div class="row"> 834 @if (!showNewSpecs) 835 { 836 <div class="col-xs-12 col-md-6 mobile-m-b-20"> 837 <div class="elma-card elma-card--white elma-card--padded"> 838 <h3 class="product-info__heading"> 839 @Translate("Firstweb.Ecom.Product.Details.TechnicalData", "Tekniske Data") @debugSpecsOldDebugLabel 840 </h3> 841 842 @if (GetLoop("Firstweb.ProductSpecs").Count() > 4) 843 { 844 <div class="product-info__read-more-container" data-bind="productSpecsReadMore"> 845 @renderTechSpecs() 846 <div class="product-info__read-more-toggler elma-link elma-link--grey js-toggle-read-more"> 847 <span class="product-info__read-more-closed-text">@Translate("ProductDetails.ReadMore", "Vis mere")</span> 848 <span class="product-info__read-more-open-text">@Translate("ProductDetails.ReadLess", "Skjul")</span> 849 </div> 850 </div> 851 } 852 else 853 { 854 @renderTechSpecs() 855 } 856 </div> 857 </div> 858 } 859 860 @if ((showNewSpecs || debugSpecs) && GetLoop("ProductCategories").Any()) 861 { 862 int totalSpecs = 0; 863 foreach (var item in GetLoop("ProductCategories")) 864 { 865 string productCategoryID = item.GetString("Ecom:Product.Category.ID"); 866 totalSpecs += item.GetLoop("ProductCategoryFields") 867 .Where(pcf => !String.IsNullOrEmpty(pcf.GetString("Ecom:Product.CategoryField.Value")) 868 && !HiddenProductSpecificationFieldIds.Contains("ProductCategory|" + productCategoryID + "|" + pcf.GetString("Ecom:Product.CategoryField.ID"))) 869 .Count(); 870 } 871 if (totalSpecs > 0) 872 { 873 <div class="col-xs-12 col-md-6 mobile-m-b-20"> 874 <div class="elma-card elma-card--white elma-card--padded"> 875 <h3 class="product-info__heading"> 876 @Translate("Firstweb.Ecom.Product.Details.Technicialdata", "Tekniske Data") @debugSpecsNewDebugLabel 877 </h3> 878 @if (totalSpecs > 4) 879 { 880 <div class="product-info__read-more-container" data-bind="productSpecsReadMore"> 881 @renderTechSpecs2(HiddenProductSpecificationFieldIds, currentProduct) 882 <div class="product-info__read-more-toggler elma-link elma-link--grey js-toggle-read-more"> 883 <span class="product-info__read-more-closed-text">@Translate("ProductDetails.ReadMore", "Vis mere")</span> 884 <span class="product-info__read-more-open-text">@Translate("ProductDetails.ReadLess", "Skjul")</span> 885 </div> 886 </div> 887 } 888 else 889 { 890 @renderTechSpecs2(HiddenProductSpecificationFieldIds, currentProduct) 891 } 892 </div> 893 </div> 894 } 895 } 896 897 @if (productDocuments.Any()) 898 { 899 bool readMoreCondition = productDocuments.Count > 4; 900 string documentCountClassModifier = readMoreCondition ? "product-info__read-more-container" : ""; 901 string documentCountDataBindModifier = readMoreCondition ? "productSpecsReadMore" : ""; 902 <div class="col-xs-12 col-md-6"> 903 <div class="elma-card elma-card--white elma-card--padded"> 904 <h3 class="product-info__heading"> 905 @Translate("Firstweb.Ecom.Product.Details.Download", "Download") 906 </h3> 907 908 <div class="@documentCountClassModifier" data-bind="@documentCountDataBindModifier"> 909 <ul class="product-info__list js-read-more-content"> 910 @foreach (var productDocument in productDocuments.OrderBy(pd => pd.DocumentPath)) 911 { 912 string extensionIconSrc = "PDF"; 913 if (productDocument.DocumentPath.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) 914 { 915 extensionIconSrc = "ZIP"; 916 } 917 string docTypeLabel = Translate("productDocumentType_" + productDocument.DocumentType); 918 <li class="row"> 919 <div class="col-sm-3 col-xs-12 desc-item-label"> 920 <span style="display: flex;align-items: center;"> 921 @if (extensionIconSrc == "PDF") 922 { 923 <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-pdf" class="svg-inline--fa fa-file-pdf fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M181.9 256.1c-5-16-4.9-46.9-2-46.9 8.4 0 7.6 36.9 2 46.9zm-1.7 47.2c-7.7 20.2-17.3 43.3-28.4 62.7 18.3-7 39-17.2 62.9-21.9-12.7-9.6-24.9-23.4-34.5-40.8zM86.1 428.1c0 .8 13.2-5.4 34.9-40.2-6.7 6.3-29.1 24.5-34.9 40.2zM248 160h136v328c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V24C0 10.7 10.7 0 24 0h200v136c0 13.2 10.8 24 24 24zm-8 171.8c-20-12.2-33.3-29-42.7-53.8 4.5-18.5 11.6-46.6 6.2-64.2-4.7-29.4-42.4-26.5-47.8-6.8-5 18.3-.4 44.1 8.1 77-11.6 27.6-28.7 64.6-40.8 85.8-.1 0-.1.1-.2.1-27.1 13.9-73.6 44.5-54.5 68 5.6 6.9 16 10 21.5 10 17.9 0 35.7-18 61.1-61.8 25.8-8.5 54.1-19.1 79-23.2 21.7 11.8 47.1 19.5 64 19.5 29.2 0 31.2-32 19.7-43.4-13.9-13.6-54.3-9.7-73.6-7.2zM377 105L279 7c-4.5-4.5-10.6-7-17-7h-6v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-74.1 255.3c4.1-2.7-2.5-11.9-42.8-9 37.1 15.8 42.8 9 42.8 9z"></path></svg> 924 } 925 else if (extensionIconSrc == "ZIP") 926 { 927 <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-download" class="svg-inline--fa fa-file-download fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm76.45 211.36l-96.42 95.7c-6.65 6.61-17.39 6.61-24.04 0l-96.42-95.7C73.42 337.29 80.54 320 94.82 320H160v-80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v80h65.18c14.28 0 21.4 17.29 11.27 27.36zM377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z"></path></svg> 928 } 929 <span>@docTypeLabel</span> 930 </span> 931 </div> 932 <div class="col-sm-9 col-xs-12 desc-item-value"> 933 <a target="_blank" class="file-download-link" href="@productDocument.DocumentPath"> 934 @productDocument.FileName 935 </a> 936 </div> 937 </li> 938 } 939 </ul> 940 @if (readMoreCondition) 941 { 942 <div class="product-info__read-more-toggler elma-link elma-link--grey js-toggle-read-more"> 943 <span class="product-info__read-more-closed-text">@Translate("ProductDetails.ReadMore", "Vis mere")</span> 944 <span class="product-info__read-more-open-text">@Translate("ProductDetails.ReadLess", "Skjul")</span> 945 </div> 946 } 947 </div> 948 949 </div> 950 </div> 951 } 952 </div> 953 </div> 954 </div> 955 </section> 956 957 @if (showVideoSection) 958 { 959 <section class="product-video spacing-vert spacing-vert--padded" data-bind="viewModel:Elma.ViewModels.Html5VideoViewModel"> 960 <!-- ko initValue: {observable: elementSelector, value:'cover-image-container'}--><!-- /ko--> 961 <div class="container product-video__inner"> 962 <div class="row"> 963 <div class="col-xs-12 col-md-8 center-block"> 964 @generateVideoLink(userDefinedLink, productName, videoTitle, iFrameWidth) 965 </div> 966 </div> 967 </div> 968 </section> 969 } 970 971 @{ 972 int feedPageId = GetPageIdByNavigationTag("RelatedProductsService"); 973 <div class="js-ribbons-async" data-feed-id="@feedPageId" data-product-id="@productId" data-print-active="@printActivated"></div> 974 } 975 </article> 976 977 } 978 else 979 { 980 @* print section: only active is activatePrint=True exists *@ 981 string printHeaderImage = Dynamicweb.Core.Converter.ToString(Pageview.Area.Item["PrintHeaderImage"]); 982 983 984 <div id="pdfcontent" class="container"> 985 986 <img src="@printHeaderImage"> 987 988 <div class="product-view__details"> 989 <div class="row"> 990 <div class="col-xs-10"> 991 <div class="product-view__meta"> 992 <span>@Translate("Firstweb:Product.ProductInfo.Eannumber", "EAN")</span> 993 <span>@GetString("Ecom:Product.Number")</span> / <span>@Translate("Firstweb:Product.ProductInfo.Elnumber", "EL-NR")</span> 994 <span>@GetString("Ecom:Product:Field.FirstwebElNo.Value.Clean")</span> 995 </div> 996 997 <div class="product-view__headings"> 998 <h1 class="product-view__heading">@productName</h1> 999 <h2 class="product-view__subheading">@subHeading</h2> 1000 </div> 1001 </div> 1002 </div> 1003 1004 <!-- Product image --> 1005 <div class="row"> 1006 <div class="col-xs-12"> 1007 <div id="slider" class="product-gallery" data-bind="css: { 'loaded' : loadedGallery }, lightSlider: lightSliderGalleryConfig"> 1008 @foreach (string imagePath in productImages.Take(1)) 1009 { 1010 string encodedImage = HttpUtility.UrlEncode(imagePath); 1011 1012 <div data-thumb="/admin/public/getimage.ashx?image=@encodedImage&altFmImage_path=/Files/Images/ecom/no-image.png&amp;width=740" data-src="/admin/public/getimage.ashx?image=@encodedImage&altFmImage_path=/Files/Images/ecom/no-image.png&amp;width=840" alt="@GetString("Ecom:Product.Name")"> 1013 <img src="x.gif" style="width:480px;height:440px;background-image:url(/admin/public/getimage.ashx?image=@encodedImage&altFmImage_path=/Files/Images/ecom/no-image.png&width=580&height=440&crop=5);background-size:contain;background-position:50% 50%;background-repeat:no-repeat;" alt="@GetString("Ecom:Product.Name")" /> 1014 </div> 1015 } 1016 </div> 1017 </div> 1018 </div> 1019 1020 <div class="row"> 1021 <div class="col-xs-10"> 1022 <div class="main-product-description-full">@GetString("Ecom:Product.LongDescription")</div> 1023 </div> 1024 </div> 1025 </div> 1026 1027 @if (!showNewSpecs) 1028 { 1029 <div class="full-width margin-top-desktop margin-bottom-desktop"> 1030 <!-- Tab panes --> 1031 <div class="tab-content"> 1032 <div role="tabpanel" class="tab-pane active" id="techspecs"> 1033 <div class="col-sm-12 col-xs-12"> 1034 <h4>@Translate("Firstweb.Ecom.Product.Details.Technicialdata", "Tekniske Data")</h4> 1035 @renderTechSpecs("print") 1036 </div> 1037 </div> 1038 </div> 1039 </div> 1040 } 1041 @if (showNewSpecs && GetLoop("ProductCategories").Any()) 1042 { 1043 1044 <div class="full-width margin-top-desktop margin-bottom-desktop"> 1045 <!-- Tab panes --> 1046 <div class="tab-content"> 1047 <div role="tabpanel" class="tab-pane active" id="techspecs"> 1048 <div class="col-sm-12 col-xs-12"> 1049 <h4>@Translate("Firstweb.Ecom.Product.Details.Technicialdata", "Tekniske Data")</h4> 1050 @renderTechSpecs2(HiddenProductSpecificationFieldIds, currentProduct, "print") 1051 </div> 1052 </div> 1053 </div> 1054 </div> 1055 } 1056 1057 @{ 1058 int feedPageId = GetPageIdByNavigationTag("RelatedProductsService"); 1059 <div class="js-ribbons-async" data-feed-id="@feedPageId" data-product-id="@productId" data-print-active="@printActivated"></div> 1060 } 1061 </div> 1062 1063 } 1064 1065 @helper RenderKitRow(List<LoopItem> kitProductList) 1066 { 1067 int amountOfItemsShown = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile ? 1 : 3; 1068 <div class="container spacing-vert spacing-vert--padded"> 1069 <h3 class="product-related__heading">@Translate("Contents")</h3> 1070 <div class="row kit-container"> 1071 <div class="col-xs-12 col-md-9 mobile-m-b-20 tablet-m-b-20 kit-carousel-container" style="padding: 0;"> 1072 <div id="productCarousel" class="carousel" style="overflow: hidden; width: 100%; margin: 0 auto;"> 1073 <div class="carousel-inner custom-carousel-inner" itemsShown="@amountOfItemsShown"> 1074 @{ 1075 foreach (LoopItem relationGroupProduct in kitProductList) 1076 { 1077 <div class="carousel-item custom-carousel-item"> 1078 @{ 1079 string productName = relationGroupProduct.GetString("Ecom:Product.Name"); 1080 string productLink = relationGroupProduct.GetString("Ecom:Product.Link.Clean"); 1081 string productID = relationGroupProduct.GetString("Ecom:Product.ID"); 1082 string imageUrl = Firstweb.Custom.CustomCode.Webshop.Frontend.Helpers.ProductImages.getProductPrimaryImage(productID); 1083 string encodedImage = HttpUtility.UrlEncode(imageUrl); 1084 } 1085 <div class="col-xs-12 col-md-12 mobile-m-b-20"> 1086 <div class="elma-card elma-card--white elma-card--padded elma-card--carousel"> 1087 <div class="product-list-card_img-ratio"> 1088 <a href="@productLink" class="product-list-card_img-container"> 1089 <img src="/admin/public/getimage.ashx?image=@encodedImage&altFmImage_path=/Files/Images/ecom/no-image.png&amp;width=840" alt="@productName" class="product-list-card_img" /> 1090 </a> 1091 </div> 1092 <a href="@productLink" class="product-list-card_information-area"> 1093 <p class="product-list-card_name" style="margin:0">@productName</p> 1094 </a> 1095 </div> 1096 </div> 1097 </div> 1098 } 1099 } 1100 </div> 1101 1102 <a class="left carousel-control custom-left-control" role="button"> 1103 <span class="glyphicon glyphicon-chevron-left left-arrow" aria-hidden="true"></span> 1104 <span class="sr-only">@Translate("KitRelatedProduct.Carousel.LeftButton", "Previous")</span> 1105 </a> 1106 <a class="right carousel-control custom-right-control" role="button"> 1107 <span class="glyphicon glyphicon-chevron-right right-arrow" aria-hidden="true"></span> 1108 <span class="sr-only">@Translate("KitRelatedProduct.Carousel.LeftButton", "Next")</span> 1109 </a> 1110 </div> 1111 </div> 1112 <div class="col-xs-12 col-md-3 kit-contents-container"> 1113 <div class="elma-card elma-card--white elma-card--padded js-elma-card last-elma-card elma-card--carousel"> 1114 <div class="vertical-line"></div> 1115 <div class="elma-card-text-container js-accordion-container"> 1116 <h3 class="product-info__heading" style="border-bottom: 1px solid #cecece; padding-bottom: 24px;">@Translate("KitRelatedProduct.Contains", "Indeholder")</h3> 1117 <div class="full-width"> 1118 <div class="tab-content"> 1119 <div role="tabpanel" class="tab-pane active" id="techspecs"> 1120 <ul class="col-sm-12 col-xs-12 kit-bulletpoint-container"> 1121 @foreach (LoopItem relationGroupProduct in kitProductList) 1122 { 1123 <li class="" style="list-style:none; padding-bottom: 10px; font-weight: 600"> 1124 @relationGroupProduct.GetString("Ecom:Product.Name") 1125 </li> 1126 } 1127 </ul> 1128 </div> 1129 </div> 1130 </div> 1131 </div> 1132 <button type="button" class="elma-card-expand-btn js-accordion-btn elma-link"> 1133 <span class="js-card-button-text">@Translate("ProductDetails.KitContents.ReadMore", "Læs mere")</span> 1134 </button> 1135 </div> 1136 </div> 1137 1138 <script> 1139 document.addEventListener("DOMContentLoaded", function () { 1140 const carouselInner = document.querySelector("#productCarousel .carousel-inner"); 1141 const items = document.querySelectorAll("#productCarousel .carousel-inner > div"); 1142 const visibleItems = carouselInner.getAttribute("itemsShown"); 1143 const itemWidth = 100 / visibleItems; 1144 const maxIndex = items.length - visibleItems; 1145 let currentIndex = 0; 1146 1147 const leftControl = document.querySelector(".left.carousel-control"); 1148 const rightControl = document.querySelector(".right.carousel-control"); 1149 1150 function updateCarousel() { 1151 const offset = -(currentIndex * itemWidth); 1152 carouselInner.style.transform = `translateX(${offset}%)`; 1153 1154 leftControl.style.display = currentIndex > 0 ? 'block' : 'none'; 1155 rightControl.style.display = currentIndex < maxIndex ? 'block' : 'none'; 1156 } 1157 1158 document.querySelector(".left.carousel-control").addEventListener("click", function () { 1159 if (currentIndex > 0) { 1160 currentIndex--; 1161 updateCarousel(); 1162 } 1163 }); 1164 1165 document.querySelector(".right.carousel-control").addEventListener("click", function () { 1166 if (currentIndex < maxIndex) { 1167 currentIndex++; 1168 updateCarousel(); 1169 } 1170 }); 1171 1172 updateCarousel(); 1173 1174 window.addEventListener("resize", () => { 1175 updateCarousel(); 1176 }); 1177 1178 1179 function expandElmaCard() { 1180 const card = document.querySelector('.js-elma-card'); 1181 const textContainer = document.querySelector('.js-accordion-container'); 1182 const readMoreElement = document.querySelector('.js-accordion-btn'); 1183 const buttonText = document.querySelector('.js-card-button-text'); 1184 1185 if (!card) return; 1186 if (!textContainer) return; 1187 if (!readMoreElement) return; 1188 if (!buttonText) return; 1189 1190 // Detect overflow in the text container 1191 // Make sure padding is included in calculation for conditional rendering of button 1192 const parentStyle = getComputedStyle(card); 1193 const parentPadding = parseFloat(parentStyle.paddingTop); 1194 const overflowAmount = (textContainer.scrollHeight - parentPadding) - textContainer.clientHeight; 1195 1196 if (overflowAmount <= 0) return; 1197 1198 card.classList.add('text-overflow'); 1199 1200 const cardHeight = card.clientHeight; 1201 1202 readMoreElement.addEventListener('click', () => { 1203 if (card.classList.contains('accordion-open')) { 1204 card.style.height = cardHeight + 'px'; 1205 card.classList.remove('accordion-open'); 1206 1207 buttonText.textContent = "@Translate("ProductDetails.KitContents.ReadMore", "Læs mere")"; 1208 return; 1209 } 1210 1211 card.style.height = (cardHeight + overflowAmount + parentPadding) + 'px'; 1212 card.classList.add('accordion-open'); 1213 buttonText.textContent = "@Translate("ProductDetails.KitContents.ReadLess", "Luk")"; 1214 }); 1215 } 1216 1217 expandElmaCard(); 1218 }); 1219 </script> 1220 </div> 1221 </div> 1222 1223 } 1224 1225 @helper renderTechSpecs(string type = "regular") 1226 { 1227 if (GetLoop("Firstweb.ProductSpecs").Any()) 1228 { 1229 if (type == "print") 1230 { 1231 <div class="product-info__list js-read-more-content"> 1232 @foreach (LoopItem i in GetLoop("Firstweb.ProductSpecs")) 1233 { 1234 <div style="width:100%;float:left;"> 1235 <p style="width:50%;float:left;"><b>@i.GetValue("SpecLabel"):</b></p> 1236 <p style="width:50%;float:left;">@i.GetValue("SpecValue")</p> 1237 </div> 1238 } 1239 </div> 1240 } 1241 else 1242 { 1243 <ul class="product-info__list js-read-more-content"> 1244 @foreach (LoopItem i in GetLoop("Firstweb.ProductSpecs")) 1245 { 1246 <li class="row"> 1247 <div class="col-sm-4 col-xs-12 desc-item-label">@i.GetValue("SpecLabel")</div> 1248 <div class="col-sm-8 col-xs-12 desc-item-value">@i.GetValue("SpecValue")</div> 1249 </li> 1250 } 1251 </ul> 1252 } 1253 } 1254 } 1255 1256 @helper renderTechSpecs2(List<string> hiddenProductSpecificationFieldIds, Dynamicweb.Ecommerce.Products.Product currentProduct, string type = "regular") 1257 { 1258 1259 Dictionary<string, Dictionary<string, string>> productCategoryValues = new Dictionary<string, Dictionary<string, string>>(); 1260 1261 var productCategorySortOrder = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItems("CustomProductCategorySort")? 1262 .Select(x => x.GetList("Category")?.SelectedValue)? 1263 .Where(x => !string.IsNullOrEmpty(x))? 1264 .ToList(); 1265 1266 LoopItem generalSpecifications = GetLoop("FieldDisplayGroups").FirstOrDefault(fdg => fdg.GetString("Ecom:FieldDisplayGroup.SystemName") == "GeneralSpecifications"); 1267 1268 List<LoopItem> generalSpecificationFields = generalSpecifications.GetLoop("Fields"); 1269 List<LoopItem> productCategories = GetLoop("ProductCategories"); 1270 1271 @:<ul class="product-info__list js-read-more-content"> 1272 1273 1274 if (generalSpecificationFields.Any(x => !string.IsNullOrEmpty(x.GetString("Ecom:FieldDisplayGroup.Field.Value")))) 1275 { 1276 <li class="row technical-group-header"> 1277 <div class="col-sm-12 col-xs-12 desc-item-label" style="font-weight:bold;">@generalSpecifications.GetString("Ecom:FieldDisplayGroup.Name")</div> 1278 </li> 1279 1280 foreach (LoopItem field in generalSpecificationFields) 1281 { 1282 string value = field.GetString("Ecom:FieldDisplayGroup.Field.Value"); 1283 1284 if (!String.IsNullOrEmpty(field.GetString("Ecom:FieldDisplayGroup.Field.OptionLabel"))) 1285 { 1286 value = field.GetString("Ecom:FieldDisplayGroup.Field.OptionLabel"); 1287 } 1288 1289 if (value.ToLower() == "false") 1290 { 1291 value = ""; 1292 } 1293 else if (value.ToLower() == "true") 1294 { 1295 value = Translate("SpecificationValue:Yes", "Ja"); 1296 } 1297 1298 if (!String.IsNullOrEmpty(value)) 1299 { 1300 <li class="row"> 1301 <div class="col-sm-4 col-xs-12 desc-item-label">@field.GetString("Ecom:FieldDisplayGroup.Field.Name"):</div> 1302 <div class="col-sm-8 col-xs-12 desc-item-value">@value</div> 1303 </li> 1304 } 1305 } 1306 } 1307 1308 if (productCategorySortOrder != null && productCategorySortOrder.Any()) 1309 { 1310 productCategories = productCategories.OrderBy(x => { 1311 int index = productCategorySortOrder.IndexOf(x.GetString("Ecom:Product.Category.ID")); 1312 return index < 0 ? int.MaxValue : index; 1313 }).ToList(); 1314 } 1315 1316 foreach (LoopItem productCategory in productCategories) 1317 { 1318 string productCategoryID = productCategory.GetString("Ecom:Product.Category.ID"); 1319 Dictionary<string, string> categoryValues = new Dictionary<string, string>(); 1320 1321 var activeCategoryFields = productCategory.GetLoop("ProductCategoryFields").Where(f => !hiddenProductSpecificationFieldIds.Contains("ProductCategory|" + productCategoryID + "|" + f.GetString("Ecom:Product.CategoryField.ID"))).ToList(); 1322 1323 if (!activeCategoryFields.Any()) 1324 { 1325 continue; 1326 } 1327 1328 string categoryName = productCategory.GetString("Ecom:Product.Category.Name"); 1329 1330 categoryName = categoryName.Substring(categoryName.IndexOf(" ") + 1).TrimStart(); 1331 1332 <li class="row technical-group-header"> 1333 <div class="col-sm-12 col-xs-12 desc-item-label" style="font-weight:bold;">@categoryName</div> 1334 </li> 1335 1336 foreach (LoopItem productCategoryField in activeCategoryFields) 1337 { 1338 string value = productCategoryField.GetString("Ecom:Product.CategoryField.Value"); 1339 1340 if (!String.IsNullOrEmpty(productCategoryField.GetString("Ecom:Product.CategoryField.OptionLabel"))) 1341 { 1342 value = productCategoryField.GetString("Ecom:Product.CategoryField.OptionLabel"); 1343 } 1344 1345 if (value.ToLower() == "false") 1346 { 1347 value = ""; 1348 } 1349 else if (value.ToLower() == "true") 1350 { 1351 value = Translate("SpecificationValue:Yes", "Ja"); 1352 } 1353 1354 if (!String.IsNullOrEmpty(value)) 1355 { 1356 1357 string productCategoryValueKey = productCategoryField.GetString("Ecom:Product.CategoryField.Label"); 1358 if (productCategoryValueKey.Contains("|")) 1359 { 1360 productCategoryValueKey = productCategoryValueKey.Substring(productCategoryValueKey.IndexOf("|") + 1).TrimStart(); 1361 } 1362 1363 <li class="row"> 1364 <div class="col-sm-4 col-xs-12 desc-item-label">@productCategoryValueKey:</div> 1365 <div class="col-sm-8 col-xs-12 desc-item-value">@value</div> 1366 </li> 1367 1368 } 1369 } 1370 } 1371 1372 @:</ul> 1373 1374 1375 } 1376 1377 1378 <script> 1379 function loadRibbons() { 1380 const asyncRibbonSection = document.querySelector('.js-ribbons-async'); 1381 if (asyncRibbonSection != null) { 1382 const feedPageId = asyncRibbonSection.getAttribute('data-feed-id'); 1383 const productId = asyncRibbonSection.getAttribute('data-product-id'); 1384 const print = asyncRibbonSection.getAttribute('data-print-active') == 'True' ? "&activatePrint=true" : ""; 1385 console.log(asyncRibbonSection.getAttribute('data-print-active')); 1386 if (feedPageId && productId) { 1387 fetch(`/Default.aspx?ID=${feedPageId}&ProductId=${productId}${print}&redirect=false`) 1388 .then(function (response) { 1389 return response.text(); 1390 }).then(function (html) { 1391 const res = new DOMParser().parseFromString(html, "text/html"); 1392 var asyncRibbonSectionFeed = res.querySelector('.js-ribbons-async-feed'); 1393 asyncRibbonSection.innerHTML = asyncRibbonSectionFeed.innerHTML; 1394 }).catch(err => console.log(err)); 1395 } 1396 } 1397 } 1398 loadRibbons(); 1399 </script>