Error executing template "Designs/Swift-v2/Paragraph/Swift-v2_ProductMedia.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_752edd84fd4a4f3e8b9fa59540b8f999.ExecuteAsync()
   at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(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.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Core.Encoders 3 @using Dynamicweb.Ecommerce.ProductCatalog 4 @using Dynamicweb.Frontend 5 @using System.IO 6 @using System.Text.RegularExpressions; 7 8 @functions { 9 public ProductViewModel product { get; set; } = new ProductViewModel(); 10 public string galleryLayout { get; set; } 11 public string[] supportedImageFormats { get; set; } 12 public string[] supportedVideoFormats { get; set; } 13 public string[] supportedDocumentFormats { get; set; } 14 public string[] allSupportedFormats { get; set; } 15 16 public class RatioSettings 17 { 18 public string Ratio { get; set; } 19 public string CssClass { get; set; } 20 public string CssVariable { get; set; } 21 public string Fill { get; set; } 22 } 23 24 public RatioSettings GetRatioSettings(string size = "desktop") 25 { 26 var ratioSettings = new RatioSettings(); 27 28 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 29 ratio = ratio != "0" ? ratio : ""; 30 string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 31 string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 32 cssClass = ratio == "fill" && size == "mobile" ? " ratio" : cssClass; 33 cssVariable = ratio == "fill" && size == "mobile" ? "--bs-aspect-ratio: 66%" : cssVariable; 34 35 ratioSettings.Ratio = ratio; 36 ratioSettings.CssClass = cssClass; 37 ratioSettings.CssVariable = cssVariable; 38 ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; 39 40 return ratioSettings; 41 } 42 43 public string GetArrowsColor() 44 { 45 var invertColor = Model.Item.GetBoolean("InvertModalArrowsColor"); 46 var arrowsColor = invertColor ? " carousel-dark" : string.Empty; 47 return arrowsColor; 48 } 49 50 public string GetThumbnailPlacement() 51 { 52 return Model.Item.GetRawValueString("ThumbnailPlacement", "bottom"); 53 } 54 55 public string GetThumbnailRowSettingCss() 56 { 57 switch (GetThumbnailPlacement()) 58 { 59 case "bottom": 60 return "d-flex flex-wrap"; 61 case "left": 62 return "d-flex flex-column order-first"; 63 case "right": 64 return "d-flex flex-column order-last"; 65 default: 66 return "d-flex flex-wrap"; 67 } 68 } 69 70 public string GetVideoType(string assetValue) 71 { 72 string type = assetValue.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) >= 0 || assetValue.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) >= 0 ? "youtube" : string.Empty; 73 type = assetValue.IndexOf("vimeo", StringComparison.OrdinalIgnoreCase) >= 0 ? "vimeo" : type; 74 type = string.IsNullOrEmpty(type) ? "selfhosted" : type; 75 76 return type; 77 } 78 79 public string GetYoutubeScreenDump(string assetValue, string quality) 80 { 81 var regex = new Regex(@"(?:youtube\.com\/.*[\?&]v=|youtu\.be\/|youtube\.com\/embed\/)([\w-]+)(?:\?.*)?"); 82 Match match = regex.Match(assetValue); 83 string videoId = match.Success ? match.Groups[1].Value : string.Empty; 84 string youtubeThumbnail = $"https://img.youtube.com/vi/{videoId}/{quality}.jpg"; 85 return youtubeThumbnail; 86 } 87 } 88 89 @{ 90 ProductViewModel product = null; 91 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 92 { 93 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 94 } 95 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 96 { 97 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 98 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 99 100 if (productList?.Products is object) 101 { 102 product = productList.Products[0]; 103 } 104 } 105 } 106 107 @if (product is object) 108 { 109 @* Supported formats *@ 110 supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff"}; 111 supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; 112 supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", "pptx" }; 113 allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); 114 115 @* Collect the assets *@ 116 var selectedAssetCategories = Model.Item.GetList("ImageAssets")?.GetRawValue().OfType<string>(); 117 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 118 119 @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ 120 string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; 121 IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); 122 assetsImages = assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); 123 IEnumerable<MediaViewModel> assetsList = new MediaViewModel[] { }; 124 assetsList = assetsList.Union(assetsImages); 125 assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; 126 assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; 127 128 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 129 bool showOnlyPrimaryImage = Model.Item.GetBoolean("ShowOnlyPrimaryImage"); 130 131 int totalAssets = 0; 132 if (showOnlyPrimaryImage == false) 133 { 134 foreach (MediaViewModel asset in assetsList) 135 { 136 var assetValue = asset.Value; 137 foreach (string format in allSupportedFormats) 138 { 139 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) 140 { 141 totalAssets++; 142 } 143 } 144 } 145 } 146 147 if ((totalAssets == 0 && product.DefaultImage != null && selectedAssetCategories.Count() == 0) || (showOnlyPrimaryImage == true && product.DefaultImage != null) || totalAssets == 0 && defaultImageFallback) 148 { 149 assetsList = new List<MediaViewModel>() { product.DefaultImage }; 150 totalAssets = 1; 151 } 152 153 @* Get assets from selected categories or get all assets *@ 154 if (totalAssets != 0) 155 { 156 int assetNumber = 0; 157 int thumbnailNumber = 0; 158 int modalAssetNumber = 0; 159 string thumbnailAxisCss = GetThumbnailPlacement() == "bottom" ? "flex-column" : string.Empty; 160 161 <div class="d-flex gap-3 h-100 @(thumbnailAxisCss) item_@Model.Item.SystemName.ToLower()" data-dw-colorscheme="@Model.ColorScheme?.Id"> 162 <div id="SmallScreenImages_@Model.ID" class="carousel@(GetArrowsColor()) col position-relative" data-bs-ride="carousel"> 163 <div class="carousel-inner h-100"> 164 @foreach (MediaViewModel asset in assetsList) 165 { 166 var assetValue = asset.Value; 167 foreach (string format in allSupportedFormats) 168 { 169 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) 170 { 171 string activeSlide = assetNumber == 0 ? "active" : ""; 172 173 <div class="carousel-item @activeSlide" data-bs-interval="99999"> 174 @{ 175 string size = "mobile"; 176 177 <div class="h-100"> 178 @foreach (string imageFormat in supportedImageFormats) 179 { //Images 180 if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) 181 { 182 if (product is object) 183 { 184 string productName = product.Name; 185 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 186 187 RatioSettings ratioSettings = GetRatioSettings(size); 188 189 var parms = new Dictionary<string, object>(); 190 parms.Add("alt", productName + asset.Keywords); 191 parms.Add("itemprop", "image"); 192 parms.Add("columns", Model.GridRowColumnCount); 193 parms.Add("eagerLoadNewImages", Model.Item.GetBoolean("DisableLazyLoading")); 194 parms.Add("doNotUseGetimage", Model.Item.GetBoolean("DisableGetImage")); 195 if (!string.IsNullOrEmpty(asset.DisplayName)) 196 { 197 parms.Add("title", asset.DisplayName); 198 } 199 200 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") 201 { 202 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 203 } 204 else 205 { 206 parms.Add("cssClass", "mw-100 mh-100"); 207 } 208 209 <a href="@imagePath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 210 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@assetNumber"> 211 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 212 </div> 213 </a> 214 } 215 } 216 } 217 @foreach (string videoFormat in supportedVideoFormats) 218 { //Videos 219 if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) 220 { 221 if (product is object) { 222 var video = asset.GetVideoViewModel(); 223 224 if (Model.Item.GetString("OpenVideoInModal") == "true") 225 { 226 string iconPath = "/Files/Images/Icons/"; 227 228 string productName = product.Name; 229 productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 230 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; 231 232 RatioSettings ratioSettings = GetRatioSettings(size); 233 234 string type = GetVideoType(asset.Value); 235 236 string videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value, "maxresdefault") : string.Empty; 237 string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : ""; 238 239 240 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 241 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@assetNumber"> 242 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 243 @if (video.IsExternalLink()) 244 { 245 <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@productName" @assetTitle class="@videoJsClass mw-100 mh-100" data-asset-value="@asset.Value" style="object-fit: cover;"> 246 } 247 else 248 { 249 250 <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> 251 <source src="@(asset.Value)#t=0.001" type="@video.GetVideoType()"> 252 </video> 253 } 254 </div> 255 </div> 256 } 257 else 258 { 259 @RenderPartial("Components/VideoPlayer.cshtml", video) 260 } 261 } 262 } 263 } 264 @foreach (string documentFormat in supportedDocumentFormats) 265 { //Documents 266 if (assetValue.IndexOf(documentFormat, StringComparison.OrdinalIgnoreCase) >= 0) 267 { 268 if (product is object) 269 { 270 string iconPath = "/Files/Images/Icons/"; 271 272 string productName = product.Name; 273 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 274 275 RatioSettings ratioSettings = GetRatioSettings(size); 276 277 var parms = new Dictionary<string, object>(); 278 parms.Add("alt", productName + asset.Keywords); 279 parms.Add("itemprop", "image"); 280 parms.Add("fullwidth", true); 281 parms.Add("columns", Model.GridRowColumnCount); 282 if (!string.IsNullOrEmpty(asset.DisplayName)) 283 { 284 parms.Add("title", asset.DisplayName); 285 } 286 287 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") 288 { 289 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 290 } 291 else 292 { 293 parms.Add("cssClass", "mw-100 mh-100"); 294 } 295 296 <a href="@imagePath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download alt="@Translate("Download")"> 297 <div class="d-flex align-items-center justify-content-center text-center overflow-hidden h-100 border"> 298 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> 299 <span>@Translate("Download") @(asset.Name)@Path.GetExtension(asset.Value).ToLower()</span> 300 </div> 301 </a> 302 } 303 304 } 305 } 306 </div> 307 } 308 309 310 </div> 311 assetNumber++; 312 } 313 } 314 } 315 </div> 316 317 </div> 318 319 @if (totalAssets > 1) 320 { 321 //Custom: added support for STL. Moved div to prevent empty thumbnails 322 <div style="width:100%; background-color:#E9EAEB; height:1px; margin:auto;"></div> 323 <div class="@(GetThumbnailRowSettingCss()) gap-3" id="SmallScreenImagesThumbnails_@Model.ID"> 324 @foreach (MediaViewModel asset in assetsList) 325 { 326 var assetValue = asset.Value; 327 string assetName = asset.Name; 328 assetName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 329 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : null; 330 string iconPath = "/Files/Images/Icons/"; 331 332 string imagePath = assetValue; 333 imagePath = assetValue.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) >= 0 || assetValue.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) >= 0 ? "https://img.youtube.com/vi/" + assetValue.Substring(assetValue.LastIndexOf('/') + 1) + "/mqdefault.jpg" : imagePath; 334 string imagePathThumb = assetValue.StartsWith("/Files/", StringComparison.OrdinalIgnoreCase) ? imagePath.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) < 0 && imagePath.IndexOf(".mp4", StringComparison.OrdinalIgnoreCase) < 0 ? $"/Admin/Public/GetImage.ashx?image={imagePath}&width=180&format=webp" : imagePath : assetValue; 335 336 RatioSettings ratioSettings = GetRatioSettings("desktop"); 337 338 @foreach (string imageFormat in supportedImageFormats) 339 { //Images 340 if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) 341 { 342 <div class="border border-round outline-none position-relative @(ratioSettings.CssClass)" style="@(ratioSettings.CssVariable); cursor: pointer; min-width: 50px; max-width: 50px; min-height: 50px; max-height: 50px;" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to="@thumbnailNumber"> 343 <img src="@imagePathThumb" alt="@HtmlEncoder.HtmlAttributeEncode(assetName)" class="border-round p-0 p-lg-1 w-100 h-100" style="object-fit: contain;"> 344 </div> 345 thumbnailNumber++; 346 } 347 } 348 349 @foreach (string videoFormat in supportedVideoFormats) 350 { //Videos 351 if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) 352 { 353 var video = asset.GetVideoViewModel(); 354 string type = GetVideoType(asset.Value); 355 356 string videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value, "mqdefault") : ""; 357 videoScreendumpPath = type == "vimeo" ? string.Empty : videoScreendumpPath; 358 string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : string.Empty; 359 <div class="border border-round outline-none position-relative @(ratioSettings.CssClass)" style="@(ratioSettings.CssVariable); cursor: pointer; min-width: 50px; max-width: 50px; min-height: 50px; max-height: 50px;" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to="@thumbnailNumber"> 360 <div class="icon-5 position-absolute top-50 start-50 translate-middle" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 361 362 @if (video.IsExternalLink()) 363 { 364 <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@assetTitle" @assetTitle class="@videoJsClass mw-100 mh-100" data-asset-value="@asset.Value" style="object-fit: cover;" /> 365 } 366 else 367 { 368 <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> 369 <source src="@(asset.Value)#t=0.001" type="@video.GetVideoType()"> 370 </video> 371 } 372 </div> 373 thumbnailNumber++; 374 } 375 } 376 377 @foreach (string documentFormat in supportedDocumentFormats) 378 { //Documents 379 if (assetValue.IndexOf(documentFormat, StringComparison.OrdinalIgnoreCase) >= 0) 380 { 381 <div class="border border-round outline-none position-relative @(ratioSettings.CssClass)" style="@(ratioSettings.CssVariable); cursor: pointer; min-width: 50px; max-width: 50px; min-height: 50px; max-height: 50px;" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to="@thumbnailNumber"> 382 <a href="@assetValue" class="ratio ratio-4x3 border outline-none" style="cursor: pointer; min-width: 7rem; max-width: 8rem;" download title="@asset.Value"> 383 <div class="d-flex align-items-center justify-content-center text-center overflow-hidden h-100 border"> 384 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> 385 <span>@(asset.Name)@Path.GetExtension(asset.Value).ToLower()</span> 386 </div> 387 </a> 388 </div> 389 390 thumbnailNumber++; 391 } 392 } 393 394 if (assetValue.IndexOf(".stl", StringComparison.OrdinalIgnoreCase) >= 0) 395 { 396 var materialColor = "#009870"; 397 var backgroundColor = "#FFFFFF"; 398 399 product.ProductFields.TryGetValue("CustomSp3DModelColor", out FieldValueViewModel color); 400 401 if (!string.IsNullOrEmpty(Dynamicweb.Core.Converter.ToString(color?.Value))) 402 { 403 materialColor = Dynamicweb.Core.Converter.ToString(color.Value); 404 } 405 406 <div class="@(Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Desktop ? "flex-fill text-end" : "")"> 407 <button class="btn btn-link text-decoration-none" data-dw-button="btn-link" data-bs-toggle="modal" data-bs-target="#STL3DModelModal" onclick="swift.Custom.STLViewer('stl3dmodel');"> 408 <span class="text-decoration-none"> 409 @ReadFile("Files/Images/Icons/Custom/3d-model.svg") 410 <span class="text-decoration-underline ms-1"> 411 @Translate("Custom.MediaGallery.ViewModel", "View 3D model") 412 </span> 413 </span> 414 </button> 415 <div class="modal" id="STL3DModelModal"> 416 <div class="modal-dialog modal-dialog-centered"> 417 <div class="modal-content"> 418 <div class="modal-header text-center border-0"> 419 <div class="modal-title text-md semi-bold flex-fill paragraph-md-semibold">@Translate("Custom.MediaGallery.ViewModel.Modal.Header", "3D model")</div> 420 <button type="button" class="btn-close position-absolute top-1 end-0 me-2" data-bs-dismiss="modal" aria-label="Close" onclick="document.querySelector('body').style = ''"></button> 421 </div> 422 <div class="modal-body"> 423 <div id="stl3dmodel" style="width: 400px; height: 400px; margin: auto;" data-file="@assetValue" data-name="@assetName" data-color="@materialColor" data-background-color="@backgroundColor" data-light-skycolor="#FFFFFF" data-light-groundcolor="#000000"> 424 </div> 425 </div> 426 </div> 427 </div> 428 </div> 429 </div> 430 } 431 } 432 </div> 433 } 434 </div> 435 @* Modal with slides *@ 436 <div class="modal fade" id="modal_@Model.ID" tabindex="-1" aria-labelledby="mediaModalTitle_@Model.ID" aria-hidden="true"> 437 <div class="modal-dialog modal-dialog-centered modal-xl"> 438 <div class="modal-content"> 439 <div class="modal-header visually-hidden"> 440 <h5 class="modal-title" id="mediaModalTitle_@Model.ID">@product.Title</h5> 441 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 442 </div> 443 <div class="modal-body p-2 p-lg-3 h-100"> 444 <div id="ModalCarousel_@Model.ID" class="carousel@(GetArrowsColor()) h-100" data-bs-ride="carousel"> 445 <div class="carousel-inner h-100" data-dw-colorscheme="@Model.ColorScheme?.Id"> 446 @foreach (MediaViewModel asset in assetsList) 447 { 448 var assetValue = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 449 foreach (string supportedFormat in supportedImageFormats.Concat(supportedVideoFormats).ToArray()) 450 { 451 if (assetValue.IndexOf(supportedFormat, StringComparison.OrdinalIgnoreCase) >= 0) 452 { 453 string imagePath = assetValue; 454 string activeSlide = modalAssetNumber == 0 ? "active" : ""; 455 456 var parms = new Dictionary<string, object>(); 457 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 458 parms.Add("fullwidth", true); 459 parms.Add("columns", Model.GridRowColumnCount); 460 461 <div class="carousel-item @activeSlide h-100" data-bs-interval="99999"> 462 @foreach (string imageFormat in supportedImageFormats) 463 { //Images 464 if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) 465 { 466 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 467 } 468 } 469 470 @foreach (string videoFormat in supportedVideoFormats) 471 { //Videos 472 if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) 473 { 474 @RenderPartial("Components/VideoPlayer.cshtml", asset.GetVideoViewModel()) 475 } 476 } 477 </div> 478 modalAssetNumber++; 479 } 480 } 481 } 482 <button class="carousel-control-prev carousel-control-area" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="prev"> 483 <span class="carousel-control-prev-icon" aria-hidden="true"></span> 484 <span class="visually-hidden">@Translate("Previous")</span> 485 </button> 486 <button class="carousel-control-next carousel-control-area" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="next"> 487 <span class="carousel-control-next-icon" aria-hidden="true"></span> 488 <span class="visually-hidden">@Translate("Next")</span> 489 </button> 490 </div> 491 </div> 492 </div> 493 </div> 494 </div> 495 </div> 496 } 497 else if (Pageview.IsVisualEditorMode) 498 { 499 RatioSettings ratioSettings = GetRatioSettings("desktop"); 500 501 <div class="h-100" data-dw-colorscheme="@Model.ColorScheme?.Id"> 502 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> 503 <img src="/Files/Images/nopic.png" loading="lazy" decoding="async" class="mh-100 mw-100" style="object-fit: cover;"> 504 </div> 505 </div> 506 } 507 } 508 else if (Pageview.IsVisualEditorMode) 509 { 510 <div class="alert alert-dark m-0">@Translate("The images will be shown here, if any")</div> 511 } 512 513 514 515
Product no. X0022

Flange Protectors with handle (EF)

Complete protection for flange surfaces and sealing zones. EF Flange Protectors cover circuit outlets/inlets, such as turbo connections, and surrounding flange faces, preventing scratches and cracks that can affect sealing. Perfect for transport, storage, and assembly where flange integrity is critical.

Try before you decide
Request sample
All benefits
Easy fit
quick handling during assembly or transport
Prevents sealing issues
avoids scratches and cracks
Total coverage
protects both port and flange face
Product specifications
Size unit:
EF range_PDS
CO2
A mm
B mm
C mm
H mm
J mm
L mm
Q mm
EF0004A-AA00A Red Recycled LDPE 0 5.15 22.1 0 0 64 6.7 3.3
EF0010B-AA00B Red Recycled LDPE 0 8.7 10.1 0 0 86.4 6.35 6.35
EF0011A-AA00B Red Recycled LDPE 0 7 7.7 0 0 105.9 10 36.15
EF0015A-AA00B Red Recycled LDPE 0 33.1 32 32 8 0 0 0
EF0098A-AA30B Grey Recycled LDPE 0 6.95 10.7 0 0 30 5 11.4
EF0305A-AA20A Yellow Recycled LDPE 0 30.5 0 0 0 76 9.8 0
EF0330A-AA00A Red Recycled LDPE 0 0 0 0 0 0 0 0
EF0362B-AA20B Yellow Recycled LDPE 0 36 34 34 0 0 0 0

Learn how our full service can add value to your business

Your full-service protection solution partner

Matching applications to mobility
We’re application specialists. We are familiar with each segment’s unique challenges, from assembly conditions to ergonomics.
Value added services
We’re application specialists. We are familiar with each segment’s unique challenges, from assembly conditions to ergonomics.