Solución de alto rendimiento para profesionales de carrocerías. Diseñados con tecnologías avanzadas, como capas de encolado doble y abrasivo de óxido de aluminio tratado térmicamente y enriquecido con polvo de diamante, garantizan un lijado rápido y cortante durante mucho tiempo. Versátiles para pinturas antiguas y recientes, aparejos de alto contenido en sólidos, barnices y masillas de poliéster, estos discos ofrecen unos resultados tan eficientes que son imprescindibles para los profesionales del sector.
Ventajas
- Disco portador de papel.
- Granos autoafilables, óxido de aluminio tratado con fuego azul.
- Lijado más rápido gracias a la tecnología autoafilable.
- Mayor durabilidad gracias a la tecnología autoafilable.
- Recubierto con estearato para evitar obstrucciones.
- Se puede usar en masillas de poliéster, imprimaciones high solid, lacas transparentes, así como en pinturas antiguas y nuevas.
Detalles del producto
- Adecuado para
- matizado preparación de superficies
- Superficies de aplicación
- acero recubrimiento electroforético acero galvanizado aluminio aluminio RMS fibra de vidrio plástico rígido plástico flexible cromo goma pintura nueva pintura en buen estado pintura descuidada pintura sin brillo gelcoat masilla imprimación/aparejo pintura original pintura de reparación madera zinc esmalte cerámico cobre plomo acero inoxidable laminado a presión piedra hormigón placas de yeso paneles de fibrocemento polietileno polipropileno policarbonato polimetilmetacrilato politetrafluoroetileno clorados materiales compuestos termoestables fibra de carbono termoplásticos metales recubiertos
- Tipo de fijación
- gancho y bucle
- Soporte
- papel
- Grano
- abierto
- Diámetro
- 150 mm
- Tamaño de grano
- 600
- Tipo de abrasivo
- óxido de aluminio
- Longitud
- 150 mm
- Número de orificios
- 15
- Perforaciones
- si
- Espesor
- 1 mm
- Tipo
- caja
- Uso
- seco
- Uso manual
- no
- Uso con máquina
- excéntrica rotativa
- Anchura
- 150 mm
- Color
- rojo
- Almacenamiento en seco
- Si
- Resistente a la congelación
- si
- Material
- papel
- Número
- SPDA 0600
- Condiciones de almacenamiento
- oscuro
- Unidad de venta
- 1
- Unidades por caja exterior
- 8
- Unidades por palet
- 336
Uso
-
Utilización SPDA-SPDD-SPDE-SPDS
Indicaciones de uso:
Estos discos están pensados para lijadoras roto-orbitales.
Estos discos solo se pueden utilizar para lijar en seco. Para pinturas, madera, masillas de poliéster y aparejos.
- Encienda la lijadora SOBRE la superficie y deténgala SEPARADA de la superficie. Así se reducen considerablemente las marcas de remolinos.
- Presione ligeramente con la mano sobre la lijadora para que el plato se mueva libremente. Deje que la herramienta haga el trabajo.
- Trabaje con la lijadora plana sobre la superficie para evitar marcas.
- Lije con un patrón sistemático. Esto permite ir eliminando las rayas para obtener un acabado uniforme. Respete siempre las etapas de lijado indicadas por el proveedor de pintura.
DETAIL29024
https://www.youtube.com/embed/7WQtu7IKXXs?origin=https://plyr.io&iv_load_policy=3&modestbranding=1&playsinline=1&showinfo=0&rel=0&enablejsapi=1
https://www.youtube.com/embed/7WQtu7IKXXs?origin=https://plyr.io&iv_load_policy=3&modestbranding=1&playsinline=1&showinfo=0&rel=0&enablejsapi=1
DETAIL29024
https://www.youtube.com/embed/7WQtu7IKXXs?origin=https://plyr.io&iv_load_policy=3&modestbranding=1&playsinline=1&showinfo=0&rel=0&enablejsapi=1
https://www.youtube.com/embed/7WQtu7IKXXs?origin=https://plyr.io&iv_load_policy=3&modestbranding=1&playsinline=1&showinfo=0&rel=0&enablejsapi=1
Error compiling template "Designs/Swift/Paragraph/Finixa_ProductDetailsMediaTable.cshtml" Line 567: } expected Line 567: } expected Line 567: } expected Line 567: } expected Line 567: } expected Line 353: The name 'RenderAsset' does not exist in the current context Line 357: The name 'languageId' does not exist in the current context Line 507: A local or parameter named 'asset' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter Line 509: A local or parameter named 'assetName' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter Line 170: The variable 'videoNumber' is assigned but its value is never used Line 178: The variable 'iconPath' is assigned but its value is never used
1 // <auto-generated/> 2 #pragma warning disable 1591 3 namespace CompiledRazorTemplates.Dynamic 4 { 5 #line hidden 6 using System.Threading.Tasks; 7 using System; 8 using System.Collections.Generic; 9 using System.Linq; 10 using Dynamicweb.Ecommerce.ProductCatalog; 11 using System.Text.RegularExpressions; 12 using System.IO; 13 internal class RazorEngine_e6bfa15323f84153b1e02977caec6d23 : Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 14 { 15 #pragma warning disable 1998 16 public async override global::System.Threading.Tasks.Task ExecuteAsync() 17 { 18 19 ProductViewModel product = null; 20 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 21 { 22 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 23 } 24 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 25 { 26 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 27 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 28 if (productList?.Products is object) 29 { 30 product = productList.Products[0]; 31 } 32 } 33 string siteLanguage = Pageview.Area.CultureInfo.Name; 34 35 36 int pageId = Dynamicweb.Context.Current.Request["CurrentPageID"] != null ? Convert.ToInt32(Dynamicweb.Context.Current.Request["CurrentPageID"]) : Pageview.ID; 37 var currentPage = Dynamicweb.Content.Services.Pages.GetPage(pageId); 38 List<Dynamicweb.Content.Page> websiteLanguages = new List<Dynamicweb.Content.Page>(); 39 if (currentPage.Area.IsMaster) 40 { 41 websiteLanguages.Add(currentPage); // Add master language 42 if (currentPage.Languages != null) 43 { 44 foreach (var lang in currentPage.Languages) 45 { 46 if (lang.Area.Active == true) // Filter active languages 47 { 48 websiteLanguages.Add(lang); 49 } 50 } 51 } 52 } 53 else 54 { 55 websiteLanguages.Add(currentPage.MasterPage); // Add master page 56 if (currentPage.MasterPage != null && currentPage.MasterPage.Languages != null) 57 { 58 foreach (var lang in currentPage.MasterPage.Languages) 59 { 60 if (lang.Area.Active == true) 61 { 62 websiteLanguages.Add(lang); 63 } 64 } 65 } 66 } 67 68 69 var ecomLanguages = Dynamicweb.Ecommerce.Services.Languages.GetLanguages(); 70 List<Dynamicweb.Ecommerce.International.Language> activeLanguages = new List<Dynamicweb.Ecommerce.International.Language>(); 71 72 73 foreach (var websiteLanguage in websiteLanguages) 74 { 75 var matchingEcomLanguage = ecomLanguages.FirstOrDefault(ecomLang => 76 string.Equals(ecomLang.Culture, websiteLanguage.Area.CultureInfo.Name, StringComparison.OrdinalIgnoreCase) || 77 string.Equals(ecomLang.Code, websiteLanguage.Area.CultureInfo.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase)); 78 79 if (matchingEcomLanguage != null && !activeLanguages.Contains(matchingEcomLanguage)) 80 { 81 activeLanguages.Add(matchingEcomLanguage); 82 } 83 } 84 85 if (activeLanguages.Count == 0) 86 { 87 activeLanguages = ecomLanguages.ToList(); 88 } 89 if (product is object) 90 { 91 92 supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff" }; 93 supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; 94 supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", ".pptx", ".igs", ".ipt", ".sat", ".stp", ".dwg", ".dxf", ".dwf" }; 95 allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); 96 97 98 var selectedAssetCategories = Model.Item.GetList("ImageAssets")?.GetRawValue().OfType<string>(); 99 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 100 101 102 Dynamicweb.Ecommerce.Products.ProductService ps = new Dynamicweb.Ecommerce.Products.ProductService(); 103 Dynamicweb.Ecommerce.Products.DetailsGroupService dgs = new Dynamicweb.Ecommerce.Products.DetailsGroupService(); 104 105 List<ewiMediaViewModel> productAssets = new List<ewiMediaViewModel>(); 106 List<Dynamicweb.Ecommerce.Products.Product> products = new List<Dynamicweb.Ecommerce.Products.Product>(); 107 foreach (var language in ecomLanguages) 108 { 109 var productitem = ps.GetProductById(product.Id, product.VariantId, language.LanguageId); 110 if (productitem is object) 111 { 112 Dynamicweb.Ecommerce.Products.DetailService detailService = new Dynamicweb.Ecommerce.Products.DetailService(); 113 114 foreach (var detail in detailService.GetDetails(productitem)) 115 { 116 if (detail.LanguageId == language.LanguageId) 117 { 118 Dynamicweb.Ecommerce.Products.DetailsGroup detailsGroup = dgs.GetById(detail.GroupId); 119 120 if (selectedAssetCategories.Contains(detailsGroup.SystemName)) 121 { 122 // Check if this language is already in activeLanguages before adding 123 if (!activeLanguages.Any(al => al.LanguageId == language.LanguageId)) 124 { 125 activeLanguages.Add(language); 126 } 127 128 ewiMediaViewModel productAsset = new ewiMediaViewModel(); 129 productAsset.Value = detail.Value; 130 productAsset.AssetSystemName = detailsGroup.SystemName; 131 productAsset.LanguageId = detail.LanguageId; 132 productAsset.LanguageName = language.NativeName; 133 productAsset.DisplayName = detail.Name; 134 productAssets.Add(productAsset); 135 } 136 } 137 } 138 } 139 } 140 141 142 143 string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; 144 IEnumerable<MediaViewModel> assetsImages = selectedAssetCategories != null ? 145 product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets) : 146 product.AssetCategories.SelectMany(x => x.Assets); 147 assetsImages = assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); 148 IEnumerable<MediaViewModel> assetsList = new MediaViewModel[] { }; 149 assetsList = productAssets.Cast<MediaViewModel>(); 150 assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; 151 assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; 152 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 153 bool showOnlyPrimaryImage = Model.Item.GetBoolean("ShowOnlyPrimaryImage"); 154 int totalAssets = 0; 155 if (showOnlyPrimaryImage == false) { 156 foreach (MediaViewModel asset in assetsList) { 157 var assetValue = asset.Value; 158 foreach (string format in allSupportedFormats) { 159 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { 160 totalAssets++; 161 } 162 } 163 } 164 } 165 if ((totalAssets == 0 && product.DefaultImage != null && selectedAssetCategories?.Count() == 0) || (showOnlyPrimaryImage == true && product.DefaultImage != null)) 166 { 167 assetsList = new List<MediaViewModel>(){ product.DefaultImage }; 168 totalAssets = 1; 169 } 170 int videoNumber = 0; 171 172 string spacing = Model.Item.GetRawValueString("Spacing", "p-0"); 173 spacing = spacing == "none" ? "p-0" : spacing; 174 spacing = spacing == "small" ? "p-3" : spacing; 175 spacing = spacing == "large" ? "p-5" : spacing; 176 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 177 bool hideThumbnails = Model.Item.GetBoolean("HideThumbnails"); 178 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 179 int modalVideoNumber = 0; 180 181 if (totalAssets != 0 && assetsList.Any()) 182 { 183 WriteLiteral(" <div"); 184 BeginWriteAttribute("class", " class=\"", 11709, "\"", 11771, 4); 185 WriteAttributeValue("", 11717, spacing, 11717, 8, false); 186 WriteAttributeValue("", 11725, theme, 11725, 8, false); 187 WriteAttributeValue(" ", 11733, "item_", 11734, 6, true); 188 WriteAttributeValue("", 11739, Model.Item.SystemName.ToLower(), 11739, 32, false); 189 EndWriteAttribute(); 190 WriteLiteral(">\r\n"); 191 if (!string.IsNullOrEmpty(Model.Item.GetString("Title")) && !Model.Item.GetBoolean("HideTitle")) 192 { 193 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3"); 194 WriteLiteral(" <h3"); 195 BeginWriteAttribute("class", " class=\"", 12013, "\"", 12040, 2); 196 WriteAttributeValue("", 12021, titleFontSize, 12021, 14, false); 197 WriteAttributeValue(" ", 12035, "mb-3", 12036, 5, true); 198 EndWriteAttribute(); 199 WriteLiteral(">\r\n "); 200 Write(Model.Item.GetString("Title")); 201 WriteLiteral("\r\n </h3>\r\n"); 202 } 203 if (activeLanguages.Count > 1) 204 { 205 206 // Filter activeLanguages als deze taal assets bevat 207 var languagesWithAssets = new List<Dynamicweb.Ecommerce.International.Language>(); 208 209 foreach (var lang in activeLanguages) 210 { 211 bool hasAssets = false; 212 foreach (MediaViewModel asset in assetsList) 213 { 214 try { 215 if (asset.GetType().GetProperty("LanguageId") != null) 216 { 217 var assetLangId = asset.GetType().GetProperty("LanguageId").GetValue(asset)?.ToString() ?? ""; 218 if (assetLangId == lang.LanguageId) 219 { 220 hasAssets = true; 221 break; 222 } 223 } 224 } catch { } 225 } 226 227 if (hasAssets) 228 { 229 languagesWithAssets.Add(lang); 230 } 231 } 232 233 Dynamicweb.Ecommerce.International.Language currentLanguage = null; 234 string currentLanguageValue = "ALL"; 235 236 // Toon enkel de taal dropdown als er meer dan 1 taal is met assets 237 if (languagesWithAssets.Count > 1) 238 { 239 240 currentLanguage = languagesWithAssets.FirstOrDefault(lang => 241 string.Equals(lang.Culture, siteLanguage, StringComparison.OrdinalIgnoreCase)) ?? 242 languagesWithAssets.FirstOrDefault(lang => 243 string.Equals(lang.NativeName, "English", StringComparison.OrdinalIgnoreCase)) ?? 244 languagesWithAssets.FirstOrDefault(); 245 246 // Map English naar LANG1 247 currentLanguageValue = currentLanguage != null && 248 string.Equals(currentLanguage.NativeName, "English", StringComparison.OrdinalIgnoreCase) 249 ? "LANG1" : currentLanguage?.LanguageId ?? "ALL"; 250 } 251 if (languagesWithAssets.Count > 1) 252 { 253 WriteLiteral(" <div class=\"mb-3\">\r\n <div class=\"mb-1\">"); 254 Write(Translate("Language")); 255 WriteLiteral(@"</div> 256 <div class=""dropdown js-dropdown""> 257 <button class=""form-select text-start w-100 js-dropdown-btn"" type=""button"" data-bs-toggle=""dropdown"" data-bs-auto-close=""outside"" aria-expanded=""false""> 258 "); 259 Write(currentLanguage?.NativeName ?? "All"); 260 WriteLiteral(@" 261 </button> 262 <div class=""dropdown-menu w-100 p-3""> 263 <div class=""form-check""> 264 <input class=""form-check-input"" type=""checkbox"" name=""LanguageId"" value=""ALL"" id=""LanguageCheckAll"" onchange=""filterResults('ALL', event);""> 265 <label class=""form-check-label"" for=""LanguageCheckAll""> 266 "); 267 Write(Translate("All")); 268 WriteLiteral("\r\n </label>\r\n </div>\r\n"); 269 foreach (var language in languagesWithAssets.GroupBy(l => l.NativeName).Select(g => g.First())) 270 { 271 string languageValue = string.Equals(language.NativeName, "English", StringComparison.OrdinalIgnoreCase) 272 ? "LANG1" : language.LanguageId; 273 bool isCurrentLanguage = language == currentLanguage; 274 WriteLiteral(" <div class=\"form-check\">\r\n <input class=\"form-check-input\" type=\"checkbox\" name=\"LanguageId\" data-short-name=\""); 275 Write(language.NativeName); 276 WriteLiteral("\""); 277 BeginWriteAttribute("value", " value=\"", 16500, "\"", 16522, 1); 278 WriteAttributeValue("", 16508, languageValue, 16508, 14, false); 279 EndWriteAttribute(); 280 BeginWriteAttribute("id", " id=\"", 16523, "\"", 16548, 2); 281 WriteAttributeValue("", 16528, "Check_", 16528, 6, true); 282 WriteAttributeValue("", 16534, languageValue, 16534, 14, false); 283 EndWriteAttribute(); 284 WriteLiteral(" "); 285 Write(isCurrentLanguage ? "checked" : ""); 286 WriteLiteral(" onchange=\"filterResults(\'"); 287 Write(languageValue); 288 WriteLiteral("\', event);\">\r\n <label class=\"form-check-label\""); 289 BeginWriteAttribute("for", " for=\"", 16712, "\"", 16738, 2); 290 WriteAttributeValue("", 16718, "Check_", 16718, 6, true); 291 WriteAttributeValue("", 16724, languageValue, 16724, 14, false); 292 EndWriteAttribute(); 293 WriteLiteral(">\r\n "); 294 Write(language.NativeName); 295 WriteLiteral("\r\n </label>\r\n </div>\r\n"); 296 } 297 WriteLiteral(" </div>\r\n </div>\r\n </div>\r\n"); 298 } 299 } 300 WriteLiteral(" <div class=\"table-responsive\">\r\n <table class=\"table table-hover align-middle mb-0\" style=\"table-layout: fixed;\" id=\"assets-table\">\r\n <thead>\r\n <tr>\r\n"); 301 if (!hideThumbnails) 302 { 303 WriteLiteral(" <th style=\"width:60px\"> </th>\r\n"); 304 } 305 WriteLiteral(" <th>"); 306 Write(Translate("Name")); 307 WriteLiteral("</th>\r\n <th>"); 308 Write(Translate("Asset type")); 309 WriteLiteral("</th>\r\n <th>"); 310 Write(Translate("Language")); 311 WriteLiteral("</th>\r\n <th class=\"text-end\" style=\"width:100px\">"); 312 Write(Translate("File type")); 313 WriteLiteral("</th>\r\n <th class=\"text-end d-none d-lg-table-cell\">"); 314 Write(Translate("Download")); 315 WriteLiteral("</th>\r\n </tr>\r\n </thead>\r\n <tbody class=\"border-top-0\">\r\n"); 316 foreach (ewiMediaViewModel asset in productAssets) 317 { 318 var assetValue = asset.Value; 319 string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Value.Substring(asset.Value.LastIndexOf('/') + 1); 320 321 bool isVideo = false; 322 323 foreach (string format in supportedVideoFormats) 324 { //Videos 325 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) 326 { 327 isVideo = true; 328 } 329 } 330 // Check if it's a supported format 331 if (!isVideo) 332 { 333 // Get file extension for file type display 334 string filePath = Dynamicweb.Context.Current.Server.MapPath(assetValue); 335 long fileSize = 0; 336 if (File.Exists(filePath)) 337 { 338 fileSize = new System.IO.FileInfo(filePath) != null ? new System.IO.FileInfo(filePath).Length / 1024 : 0; 339 340 foreach (string format in allSupportedFormats) 341 { 342 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) 343 { 344 string show = "hide-row"; 345 WriteLiteral("\t\t\t\t\t\t\t\t\t\t\t<tr"); 346 BeginWriteAttribute("class", " class=\"", 19370, "\"", 19401, 2); 347 WriteAttributeValue("", 19378, asset.LanguageId, 19378, 17, false); 348 WriteAttributeValue(" ", 19395, show, 19396, 5, false); 349 EndWriteAttribute(); 350 WriteLiteral(">\r\n"); 351 if (!hideThumbnails) 352 { 353 Write(RenderAsset(asset)); 354 355 } 356 WriteLiteral(" string languageId = string.Equals(asset.LanguageName, \"English\", StringComparison.OrdinalIgnoreCase) ? \"LANG1\" : asset.LanguageId;\r\n \r\n <tr data-language-ids=\""); 357 Write(languageId); 358 WriteLiteral("\" data-language-name=\""); 359 Write(asset.LanguageName); 360 WriteLiteral("\">\r\n"); 361 if (!hideThumbnails) 362 { 363 WriteLiteral(" <td class=\"px-0\">\r\n"); 364 365 string productName = product.Name; 366 string imagePath = asset.Value; 367 string imageLinkPath = imagePath; 368 imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; 369 RatioSettings ratioSettings = GetRatioSettings(); 370 WriteLiteral(" <a"); 371 BeginWriteAttribute("href", " href=\"", 20590, "\"", 20611, 1); 372 WriteAttributeValue("", 20597, imageLinkPath, 20597, 14, false); 373 EndWriteAttribute(); 374 BeginWriteAttribute("class", " class=\"", 20612, "\"", 20674, 3); 375 WriteAttributeValue("", 20620, "d-block", 20620, 7, true); 376 WriteAttributeValue(" ", 20627, ratioSettings.CssClass, 20628, 25, false); 377 WriteAttributeValue("", 20653, ratioSettings.Fill, 20653, 21, false); 378 EndWriteAttribute(); 379 BeginWriteAttribute("style", " style=\"", 20675, "\"", 20711, 1); 380 WriteAttributeValue("", 20683, ratioSettings.CssVariable, 20683, 28, false); 381 EndWriteAttribute(); 382 WriteLiteral(" download"); 383 BeginWriteAttribute("alt", " alt=\"", 20721, "\"", 20739, 1); 384 WriteAttributeValue("", 20727, productName, 20727, 12, false); 385 EndWriteAttribute(); 386 WriteLiteral(">\r\n <div class=\"d-flex align-items-center justify-content-center overflow-hidden h-100\">\r\n <img loading=\"lazy\""); 387 BeginWriteAttribute("src", " src=\"", 20948, "\"", 20964, 1); 388 WriteAttributeValue("", 20954, imagePath, 20954, 10, false); 389 EndWriteAttribute(); 390 WriteLiteral(" class=\"mw-100 mh-100\""); 391 BeginWriteAttribute("alt", " alt=\"", 20987, "\"", 21005, 1); 392 WriteAttributeValue("", 20993, productName, 20993, 12, false); 393 EndWriteAttribute(); 394 WriteLiteral(" />\r\n </div>\r\n </a>\r\n </td>\r\n"); 395 } 396 WriteLiteral(" <td><span class=\"hide-on-desktop\">"); 397 Write(Translate("Name")); 398 WriteLiteral("</span> <span>"); 399 Write(assetName); 400 WriteLiteral("</span></td>\r\n\t\t\t\t\t\t\t\t\t<td><span class=\"hide-on-desktop\">"); 401 Write(Translate("Asset type")); 402 WriteLiteral("</span> <span>"); 403 Write(asset.AssetSystemName); 404 WriteLiteral("</span></td>\r\n <td><span class=\"hide-on-desktop\">"); 405 Write(Translate("Language")); 406 WriteLiteral("</span> <span>"); 407 Write(asset.LanguageName); 408 WriteLiteral("</span></td>\r\n\t\t\t\t\t\t\t\t\t<td class=\"no-border-bottom\"><span class=\"hide-on-desktop\">"); 409 Write(Translate("File type")); 410 WriteLiteral("</span> <span>.pdf</span></td>\r\n <td class=\"text-end\">\r\n\t\t\t\t\t\t\t\t\t\t<a"); 411 BeginWriteAttribute("href", " href=\"", 21779, "\"", 21797, 1); 412 WriteAttributeValue("", 21786, assetValue, 21786, 11, false); 413 EndWriteAttribute(); 414 WriteLiteral(" class=\"download-button\" target=\"_blank\">"); 415 Write(Translate("Download")); 416 WriteLiteral(@"</a> 417 </td> 418 </tr> 419 } 420 } 421 </tbody> 422 </table> 423 </div> 424 <script> 425 function filterResults(selectedLang, event) { 426 console.log('Filtering by language:', selectedLang); 427 428 // Prevent event bubbling 429 if (event) { 430 event.stopPropagation(); 431 } 432 433 const table = document.getElementById('assets-table'); 434 const rows = table.querySelectorAll('tbody tr'); 435 const button = document.querySelector('.js-dropdown-btn'); 436 437 const checkedBoxes = document.querySelectorAll('input[name=""LanguageId""]:checked'); 438 const checkedLanguages = Array.from(checkedBoxes).map(cb => cb.value); 439 440 "); 441 WriteLiteral(@" // Handle ""All"" checkbox behavior - if ""All"" is checked, uncheck others 442 if (selectedLang === 'ALL') { 443 const allCheckbox = document.querySelector('input[value=""ALL""]'); 444 if (allCheckbox && allCheckbox.checked) { 445 // Uncheck all other checkboxes 446 document.querySelectorAll('input[name=""LanguageId""]:not([value=""ALL""])').forEach(cb => { 447 cb.checked = false; 448 }); 449 } 450 } else { 451 // If any specific language is checked, uncheck ""All"" 452 const allCheckbox = document.querySelector('input[value=""ALL""]'); 453 if (allCheckbox) { 454 allCheckbox.checked = false; 455 } 456 } 457 458 // Re-get checked languages after potenti"); 459 WriteLiteral(@"al changes 460 const finalCheckedBoxes = document.querySelectorAll('input[name=""LanguageId""]:checked'); 461 const finalCheckedLanguages = Array.from(finalCheckedBoxes).map(cb => cb.value); 462 463 // Update button text based on selected languages 464 if (finalCheckedLanguages.length === 0) { 465 button.textContent = '"); 466 Write(Translate("All")); 467 WriteLiteral("\';\r\n } else if (finalCheckedLanguages.includes(\'ALL\')) {\r\n button.textContent = \'"); 468 Write(Translate("All")); 469 WriteLiteral(@"'; 470 } else if (finalCheckedLanguages.length === 1) { 471 const selectedCheckbox = document.querySelector(`input[value=""${finalCheckedLanguages[0]}""]`); 472 button.textContent = selectedCheckbox ? selectedCheckbox.getAttribute('data-short-name') : 'All'; 473 } else { 474 button.textContent = `${finalCheckedLanguages.length} languages selected`; 475 } 476 477 // Filter table rows 478 rows.forEach(row => { 479 const rowLanguageIds = row.getAttribute('data-language-ids'); 480 const rowLanguageName = row.getAttribute('data-language-name'); 481 482 if (finalCheckedLanguages.length === 0 || finalCheckedLanguages.includes('ALL')) { 483 row.style.display = ''; 484 } else { 485 const shouldShow = ro"); 486 WriteLiteral(@"wLanguageIds && finalCheckedLanguages.some(lang => 487 rowLanguageIds === lang || 488 rowLanguageIds === 'ALL' 489 ); 490 491 row.style.display = shouldShow ? '' : 'none'; 492 } 493 }); 494 495 } 496 document.addEventListener('DOMContentLoaded', function() { 497 // Set initial state - apply filter for pre-checked language 498 const currentLangCheckbox = document.querySelector('input[name=""LanguageId""]:checked'); 499 if (currentLangCheckbox) { 500 filterResults(currentLangCheckbox.value); 501 } else { 502 // Default to show all if nothing is checked 503 const table = document.getElementById('assets-table'); 504 const rows = table.querySelectorAll('tbody tr'); "); 505 WriteLiteral("\n rows.forEach(row => {\r\n row.style.display = \'\';\r\n });\r\n }\r\n });\r\n </script>\r\n"); 506 foreach (MediaViewModel asset in assetsList) 507 { 508 var assetName = asset.Value.ToLower(); 509 foreach (string videoFormat in supportedVideoFormats) 510 { //Videos 511 if (assetName.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) 512 { 513 WriteLiteral(" <div class=\"modal fade js-video-modal\""); 514 BeginWriteAttribute("id", " id=\"", 27149, "\"", 27189, 4); 515 WriteAttributeValue("", 27154, "modal_", 27154, 6, true); 516 WriteAttributeValue("", 27160, Model.ID, 27160, 11, false); 517 WriteAttributeValue("", 27171, "_", 27171, 1, true); 518 WriteAttributeValue("", 27172, modalVideoNumber, 27172, 17, false); 519 EndWriteAttribute(); 520 WriteLiteral(" tabindex=\"-1\""); 521 BeginWriteAttribute("aria-labelledby", " aria-labelledby=\"", 27204, "\"", 27281, 4); 522 WriteAttributeValue("", 27222, "productDetailsTableModalTitle_", 27222, 30, true); 523 WriteAttributeValue("", 27252, Model.ID, 27252, 11, false); 524 WriteAttributeValue("", 27263, "_", 27263, 1, true); 525 WriteAttributeValue("", 27264, modalVideoNumber, 27264, 17, false); 526 EndWriteAttribute(); 527 WriteLiteral(@" aria-hidden=""true""> 528 <div class=""modal-dialog modal-dialog-centered modal-xl""> 529 <div class=""modal-content""> 530 <div class=""modal-header visually-hidden""> 531 <h5 class=""modal-title"""); 532 BeginWriteAttribute("id", " id=\"", 27595, "\"", 27659, 4); 533 WriteAttributeValue("", 27600, "productDetailsTableModalTitle_", 27600, 30, true); 534 WriteAttributeValue("", 27630, Model.ID, 27630, 11, false); 535 WriteAttributeValue("", 27641, "_", 27641, 1, true); 536 WriteAttributeValue("", 27642, modalVideoNumber, 27642, 17, false); 537 EndWriteAttribute(); 538 WriteLiteral(">"); 539 Write(product.Title); 540 WriteLiteral(@"</h5> 541 <button type=""button"" class=""btn-close"" data-bs-dismiss=""modal"" aria-label=""Close""></button> 542 </div> 543 <div class=""modal-body p-2 p-lg-3 h-100""> 544 "); 545 546 var videoParams = GetVideoParams(asset, "modal"); 547 Write(RenderPartial("Components/VideoPlayer.cshtml", new Dynamicweb.Frontend.FileViewModel { Path = asset.Value }, videoParams)); 548 WriteLiteral(" </div>\r\n </div>\r\n </div>\r\n </div>\r\n"); 549 modalVideoNumber++; 550 } 551 } 552 }WriteLiteral(" </div>\r\n"); 553 } 554 else if (Pageview.IsVisualEditorMode) 555 { 556 WriteLiteral(" <div"); 557 BeginWriteAttribute("class", " class=\"", 28629, "\"", 28649, 2); 558 WriteAttributeValue("", 28637, "h-100", 28637, 5, true); 559 WriteAttributeValue(" ", 28642, theme, 28643, 6, false); 560 EndWriteAttribute(); 561 WriteLiteral(">\r\n <div class=\"alert alert-dark m-0\">\r\n "); 562 Write(Translate("No assets are available")); 563 WriteLiteral("\r\n </div>\r\n </div>\r\n"); 564 } 565 } 566 } 567 #pragma warning restore 1998 568 569 public ProductViewModel product { get; set; } = new ProductViewModel(); 570 public string[] supportedImageFormats { get; set; } 571 public string[] supportedVideoFormats { get; set; } 572 public string[] supportedDocumentFormats { get; set; } 573 public string[] allSupportedFormats { get; set; } 574 public class RatioSettings 575 { 576 public string Ratio { get; set; } 577 public string CssClass { get; set; } 578 public string CssVariable { get; set; } 579 public string Fill { get; set; } 580 } 581 public RatioSettings GetRatioSettings() 582 { 583 var ratioSettings = new RatioSettings(); 584 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 585 ratio = ratio != "0" ? ratio : ""; 586 string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 587 string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 588 ratioSettings.Ratio = ratio; 589 ratioSettings.CssClass = cssClass; 590 ratioSettings.CssVariable = cssVariable; 591 ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; 592 return ratioSettings; 593 } 594 // PDB: eWings MediaViewModel extender 595 public class ewiMediaViewModel : MediaViewModel 596 { 597 public string LanguageId { get; set; } 598 public string LanguageName { get; set; } 599 public string AssetSystemName { get; set; } 600 } 601 public Dictionary<string, object> GetVideoParams(MediaViewModel asset, string size) 602 { 603 string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Name; 604 string type = GetVideoType(asset.Value); 605 bool openInModal = Model.Item.GetString("OpenVideoInModal") == "true" ? true : false; 606 bool autoPlay = Model.Item.GetBoolean("VideoAutoPlay"); 607 var videoParams = new Dictionary<string, object>(); 608 videoParams.Add("AssetName", asset.Name); 609 videoParams.Add("AssetVideoType", type); 610 videoParams.Add("AssetDisplayName", asset.DisplayName); 611 videoParams.Add("OpenVideoInModal", openInModal); 612 videoParams.Add("VideoAutoPlay", autoPlay); 613 videoParams.Add("Size", size); 614 videoParams.Add("Id", Model.ID); 615 return videoParams; 616 } 617 public string GetVideoType(string assetValue) 618 { 619 string type = assetValue.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) >= 0 || assetValue.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) >= 0 ? "youtube" : string.Empty; 620 type = assetValue.IndexOf("vimeo", StringComparison.OrdinalIgnoreCase) >= 0 ? "vimeo" : type; 621 type = string.IsNullOrEmpty(type) ? "selfhosted" : type; 622 return type; 623 } 624 public string GetYoutubeScreenDump(string assetValue) 625 { 626 var regex = new Regex(@"(?:youtube\.com\/.*[\?&]v=|youtu\.be\/|youtube\.com\/embed\/)([\w-]+)(?:\?.*)?"); 627 Match match = regex.Match(assetValue); 628 string videoId = match.Success ? match.Groups[1].Value : string.Empty; 629 string youtubeThumbnail = $"https://img.youtube.com/vi/{videoId}/mqdefault.jpg"; 630 return youtubeThumbnail; 631 } 632 } 633 } 634 #pragma warning restore 1591 635
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using System.Text.RegularExpressions; 4 @using System.IO 5 @functions { 6 public ProductViewModel product { get; set; } = new ProductViewModel(); 7 public string[] supportedImageFormats { get; set; } 8 public string[] supportedVideoFormats { get; set; } 9 public string[] supportedDocumentFormats { get; set; } 10 public string[] allSupportedFormats { get; set; } 11 public class RatioSettings 12 { 13 public string Ratio { get; set; } 14 public string CssClass { get; set; } 15 public string CssVariable { get; set; } 16 public string Fill { get; set; } 17 } 18 public RatioSettings GetRatioSettings() 19 { 20 var ratioSettings = new RatioSettings(); 21 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 22 ratio = ratio != "0" ? ratio : ""; 23 string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 24 string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 25 ratioSettings.Ratio = ratio; 26 ratioSettings.CssClass = cssClass; 27 ratioSettings.CssVariable = cssVariable; 28 ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; 29 return ratioSettings; 30 } 31 // PDB: eWings MediaViewModel extender 32 public class ewiMediaViewModel : MediaViewModel 33 { 34 public string LanguageId { get; set; } 35 public string LanguageName { get; set; } 36 public string AssetSystemName { get; set; } 37 } 38 public Dictionary<string, object> GetVideoParams(MediaViewModel asset, string size) 39 { 40 string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Name; 41 string type = GetVideoType(asset.Value); 42 bool openInModal = Model.Item.GetString("OpenVideoInModal") == "true" ? true : false; 43 bool autoPlay = Model.Item.GetBoolean("VideoAutoPlay"); 44 var videoParams = new Dictionary<string, object>(); 45 videoParams.Add("AssetName", asset.Name); 46 videoParams.Add("AssetVideoType", type); 47 videoParams.Add("AssetDisplayName", asset.DisplayName); 48 videoParams.Add("OpenVideoInModal", openInModal); 49 videoParams.Add("VideoAutoPlay", autoPlay); 50 videoParams.Add("Size", size); 51 videoParams.Add("Id", Model.ID); 52 return videoParams; 53 } 54 public string GetVideoType(string assetValue) 55 { 56 string type = assetValue.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) >= 0 || assetValue.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) >= 0 ? "youtube" : string.Empty; 57 type = assetValue.IndexOf("vimeo", StringComparison.OrdinalIgnoreCase) >= 0 ? "vimeo" : type; 58 type = string.IsNullOrEmpty(type) ? "selfhosted" : type; 59 return type; 60 } 61 public string GetYoutubeScreenDump(string assetValue) 62 { 63 var regex = new Regex(@"(?:youtube\.com\/.*[\?&]v=|youtu\.be\/|youtube\.com\/embed\/)([\w-]+)(?:\?.*)?"); 64 Match match = regex.Match(assetValue); 65 string videoId = match.Success ? match.Groups[1].Value : string.Empty; 66 string youtubeThumbnail = $"https://img.youtube.com/vi/{videoId}/mqdefault.jpg"; 67 return youtubeThumbnail; 68 } 69 } 70 @{ 71 @* Get the product data *@ 72 ProductViewModel product = null; 73 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 74 { 75 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 76 } 77 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 78 { 79 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 80 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 81 if (productList?.Products is object) 82 { 83 product = productList.Products[0]; 84 } 85 } 86 string siteLanguage = Pageview.Area.CultureInfo.Name; 87 88 @* Get active website languages first *@ 89 int pageId = Dynamicweb.Context.Current.Request["CurrentPageID"] != null ? Convert.ToInt32(Dynamicweb.Context.Current.Request["CurrentPageID"]) : Pageview.ID; 90 var currentPage = Dynamicweb.Content.Services.Pages.GetPage(pageId); 91 List<Dynamicweb.Content.Page> websiteLanguages = new List<Dynamicweb.Content.Page>(); 92 if (currentPage.Area.IsMaster) 93 { 94 websiteLanguages.Add(currentPage); // Add master language 95 if (currentPage.Languages != null) 96 { 97 foreach (var lang in currentPage.Languages) 98 { 99 if (lang.Area.Active == true) // Filter active languages 100 { 101 websiteLanguages.Add(lang); 102 } 103 } 104 } 105 } 106 else 107 { 108 websiteLanguages.Add(currentPage.MasterPage); // Add master page 109 if (currentPage.MasterPage != null && currentPage.MasterPage.Languages != null) 110 { 111 foreach (var lang in currentPage.MasterPage.Languages) 112 { 113 if (lang.Area.Active == true) 114 { 115 websiteLanguages.Add(lang); 116 } 117 } 118 } 119 } 120 121 @* Get ecommerce languages and filter by active website languages *@ 122 var ecomLanguages = Dynamicweb.Ecommerce.Services.Languages.GetLanguages(); 123 List<Dynamicweb.Ecommerce.International.Language> activeLanguages = new List<Dynamicweb.Ecommerce.International.Language>(); 124 125 @* Filter ecommerce languages to only include those corresponding to active website languages *@ 126 foreach (var websiteLanguage in websiteLanguages) 127 { 128 var matchingEcomLanguage = ecomLanguages.FirstOrDefault(ecomLang => 129 string.Equals(ecomLang.Culture, websiteLanguage.Area.CultureInfo.Name, StringComparison.OrdinalIgnoreCase) || 130 string.Equals(ecomLang.Code, websiteLanguage.Area.CultureInfo.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase)); 131 132 if (matchingEcomLanguage != null && !activeLanguages.Contains(matchingEcomLanguage)) 133 { 134 activeLanguages.Add(matchingEcomLanguage); 135 } 136 } 137 @* Fallback: if no matches found, use all ecommerce languages *@ 138 if (activeLanguages.Count == 0) 139 { 140 activeLanguages = ecomLanguages.ToList(); 141 } 142 } 143 @if (product is object) 144 { 145 @* Supported formats *@ 146 supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff" }; 147 supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; 148 supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", ".pptx", ".igs", ".ipt", ".sat", ".stp", ".dwg", ".dxf", ".dwf" }; 149 allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); 150 151 @* Collect the assets *@ 152 var selectedAssetCategories = Model.Item.GetList("ImageAssets")?.GetRawValue().OfType<string>(); 153 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 154 155 @* PDB: Collect the valid assets and languages *@ 156 Dynamicweb.Ecommerce.Products.ProductService ps = new Dynamicweb.Ecommerce.Products.ProductService(); 157 Dynamicweb.Ecommerce.Products.DetailsGroupService dgs = new Dynamicweb.Ecommerce.Products.DetailsGroupService(); 158 159 List<ewiMediaViewModel> productAssets = new List<ewiMediaViewModel>(); 160 List<Dynamicweb.Ecommerce.Products.Product> products = new List<Dynamicweb.Ecommerce.Products.Product>(); 161 foreach (var language in ecomLanguages) 162 { 163 var productitem = ps.GetProductById(product.Id, product.VariantId, language.LanguageId); 164 if (productitem is object) 165 { 166 Dynamicweb.Ecommerce.Products.DetailService detailService = new Dynamicweb.Ecommerce.Products.DetailService(); 167 168 foreach (var detail in detailService.GetDetails(productitem)) 169 { 170 if (detail.LanguageId == language.LanguageId) 171 { 172 Dynamicweb.Ecommerce.Products.DetailsGroup detailsGroup = dgs.GetById(detail.GroupId); 173 174 if (selectedAssetCategories.Contains(detailsGroup.SystemName)) 175 { 176 // Check if this language is already in activeLanguages before adding 177 if (!activeLanguages.Any(al => al.LanguageId == language.LanguageId)) 178 { 179 activeLanguages.Add(language); 180 } 181 182 ewiMediaViewModel productAsset = new ewiMediaViewModel(); 183 productAsset.Value = detail.Value; 184 productAsset.AssetSystemName = detailsGroup.SystemName; 185 productAsset.LanguageId = detail.LanguageId; 186 productAsset.LanguageName = language.NativeName; 187 productAsset.DisplayName = detail.Name; 188 productAssets.Add(productAsset); 189 } 190 } 191 } 192 } 193 } 194 195 196 @* Standard asset collection (existing logic) *@ 197 string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; 198 IEnumerable<MediaViewModel> assetsImages = selectedAssetCategories != null ? 199 product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets) : 200 product.AssetCategories.SelectMany(x => x.Assets); 201 assetsImages = assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); 202 IEnumerable<MediaViewModel> assetsList = new MediaViewModel[] { }; 203 assetsList = productAssets.Cast<MediaViewModel>(); 204 assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; 205 assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; 206 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 207 bool showOnlyPrimaryImage = Model.Item.GetBoolean("ShowOnlyPrimaryImage"); 208 int totalAssets = 0; 209 if (showOnlyPrimaryImage == false) { 210 foreach (MediaViewModel asset in assetsList) { 211 var assetValue = asset.Value; 212 foreach (string format in allSupportedFormats) { 213 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { 214 totalAssets++; 215 } 216 } 217 } 218 } 219 if ((totalAssets == 0 && product.DefaultImage != null && selectedAssetCategories?.Count() == 0) || (showOnlyPrimaryImage == true && product.DefaultImage != null)) 220 { 221 assetsList = new List<MediaViewModel>(){ product.DefaultImage }; 222 totalAssets = 1; 223 } 224 int videoNumber = 0; 225 @* Layout settings *@ 226 string spacing = Model.Item.GetRawValueString("Spacing", "p-0"); 227 spacing = spacing == "none" ? "p-0" : spacing; 228 spacing = spacing == "small" ? "p-3" : spacing; 229 spacing = spacing == "large" ? "p-5" : spacing; 230 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 231 bool hideThumbnails = Model.Item.GetBoolean("HideThumbnails"); 232 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 233 int modalVideoNumber = 0; 234 @* Get assets from selected categories or get all assets *@ 235 if (totalAssets != 0 && assetsList.Any()) 236 { 237 <div class="@spacing@(theme) item_@Model.Item.SystemName.ToLower()"> 238 @if (!string.IsNullOrEmpty(Model.Item.GetString("Title")) && !Model.Item.GetBoolean("HideTitle")) 239 { 240 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3"); 241 <h3 class="@titleFontSize mb-3"> 242 @Model.Item.GetString("Title") 243 </h3> 244 } 245 @if (activeLanguages.Count > 1) 246 { 247 @{ 248 // Filter activeLanguages als deze taal assets bevat 249 var languagesWithAssets = new List<Dynamicweb.Ecommerce.International.Language>(); 250 251 foreach (var lang in activeLanguages) 252 { 253 bool hasAssets = false; 254 foreach (MediaViewModel asset in assetsList) 255 { 256 try { 257 if (asset.GetType().GetProperty("LanguageId") != null) 258 { 259 var assetLangId = asset.GetType().GetProperty("LanguageId").GetValue(asset)?.ToString() ?? ""; 260 if (assetLangId == lang.LanguageId) 261 { 262 hasAssets = true; 263 break; 264 } 265 } 266 } catch { } 267 } 268 269 if (hasAssets) 270 { 271 languagesWithAssets.Add(lang); 272 } 273 } 274 275 Dynamicweb.Ecommerce.International.Language currentLanguage = null; 276 string currentLanguageValue = "ALL"; 277 278 // Toon enkel de taal dropdown als er meer dan 1 taal is met assets 279 if (languagesWithAssets.Count > 1) 280 { 281 282 currentLanguage = languagesWithAssets.FirstOrDefault(lang => 283 string.Equals(lang.Culture, siteLanguage, StringComparison.OrdinalIgnoreCase)) ?? 284 languagesWithAssets.FirstOrDefault(lang => 285 string.Equals(lang.NativeName, "English", StringComparison.OrdinalIgnoreCase)) ?? 286 languagesWithAssets.FirstOrDefault(); 287 288 // Map English naar LANG1 289 currentLanguageValue = currentLanguage != null && 290 string.Equals(currentLanguage.NativeName, "English", StringComparison.OrdinalIgnoreCase) 291 ? "LANG1" : currentLanguage?.LanguageId ?? "ALL"; 292 } 293 } 294 295 @if (languagesWithAssets.Count > 1) 296 { 297 <div class="mb-3"> 298 <div class="mb-1">@Translate("Language")</div> 299 <div class="dropdown js-dropdown"> 300 <button class="form-select text-start w-100 js-dropdown-btn" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false"> 301 @(currentLanguage?.NativeName ?? "All") 302 </button> 303 <div class="dropdown-menu w-100 p-3"> 304 <div class="form-check"> 305 <input class="form-check-input" type="checkbox" name="LanguageId" value="ALL" id="LanguageCheckAll" onchange="filterResults('ALL', event);"> 306 <label class="form-check-label" for="LanguageCheckAll"> 307 @Translate("All") 308 </label> 309 </div> 310 @foreach (var language in languagesWithAssets.GroupBy(l => l.NativeName).Select(g => g.First())) 311 { 312 string languageValue = string.Equals(language.NativeName, "English", StringComparison.OrdinalIgnoreCase) 313 ? "LANG1" : language.LanguageId; 314 bool isCurrentLanguage = language == currentLanguage; 315 <div class="form-check"> 316 <input class="form-check-input" type="checkbox" name="LanguageId" data-short-name="@language.NativeName" value="@languageValue" id="Check_@languageValue" @(isCurrentLanguage ? "checked" : "") onchange="filterResults('@languageValue', event);"> 317 <label class="form-check-label" for="Check_@languageValue"> 318 @language.NativeName 319 </label> 320 </div> 321 } 322 </div> 323 </div> 324 </div> 325 } 326 } 327 <div class="table-responsive"> 328 <table class="table table-hover align-middle mb-0" style="table-layout: fixed;" id="assets-table"> 329 <thead> 330 <tr> 331 @if (!hideThumbnails) 332 { 333 <th style="width:60px"> </th> 334 } 335 <th>@Translate("Name")</th> 336 <th>@Translate("Asset type")</th> 337 <th>@Translate("Language")</th> 338 <th class="text-end" style="width:100px">@Translate("File type")</th> 339 <th class="text-end d-none d-lg-table-cell">@Translate("Download")</th> 340 </tr> 341 </thead> 342 <tbody class="border-top-0"> 343 @foreach (ewiMediaViewModel asset in productAssets) 344 { 345 var assetValue = asset.Value; 346 string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Value.Substring(asset.Value.LastIndexOf('/') + 1); 347 348 bool isVideo = false; 349 350 foreach (string format in supportedVideoFormats) 351 { //Videos 352 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) 353 { 354 isVideo = true; 355 } 356 } 357 // Check if it's a supported format 358 if (!isVideo) 359 { 360 // Get file extension for file type display 361 string filePath = Dynamicweb.Context.Current.Server.MapPath(assetValue); 362 long fileSize = 0; 363 if (File.Exists(filePath)) 364 { 365 fileSize = new System.IO.FileInfo(filePath) != null ? new System.IO.FileInfo(filePath).Length / 1024 : 0; 366 367 foreach (string format in allSupportedFormats) 368 { 369 if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) 370 { 371 string show = "hide-row"; 372 <tr class="@asset.LanguageId @show"> 373 @if (!hideThumbnails) 374 { 375 @RenderAsset(asset) 376 } 377 string languageId = string.Equals(asset.LanguageName, "English", StringComparison.OrdinalIgnoreCase) ? "LANG1" : asset.LanguageId; 378 379 <tr data-language-ids="@languageId" data-language-name="@asset.LanguageName"> 380 @if (!hideThumbnails) 381 { 382 <td class="px-0"> 383 @{ 384 string productName = product.Name; 385 string imagePath = asset.Value; 386 string imageLinkPath = imagePath; 387 imagePath = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=60&format=webp"; 388 RatioSettings ratioSettings = GetRatioSettings(); 389 } 390 <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download alt="@productName"> 391 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 392 <img loading="lazy" src="@imagePath" class="mw-100 mh-100" alt="@productName" /> 393 </div> 394 </a> 395 </td> 396 } 397 <td><span class="hide-on-desktop">@Translate("Name")</span> <span>@assetName</span></td> 398 <td><span class="hide-on-desktop">@Translate("Asset type")</span> <span>@asset.AssetSystemName</span></td> 399 <td><span class="hide-on-desktop">@Translate("Language")</span> <span>@asset.LanguageName</span></td> 400 <td class="no-border-bottom"><span class="hide-on-desktop">@Translate("File type")</span> <span>.pdf</span></td> 401 <td class="text-end"> 402 <a href="@assetValue" class="download-button" target="_blank">@Translate("Download")</a> 403 </td> 404 </tr> 405 } 406 } 407 </tbody> 408 </table> 409 </div> 410 <script> 411 function filterResults(selectedLang, event) { 412 console.log('Filtering by language:', selectedLang); 413 414 // Prevent event bubbling 415 if (event) { 416 event.stopPropagation(); 417 } 418 419 const table = document.getElementById('assets-table'); 420 const rows = table.querySelectorAll('tbody tr'); 421 const button = document.querySelector('.js-dropdown-btn'); 422 423 const checkedBoxes = document.querySelectorAll('input[name="LanguageId"]:checked'); 424 const checkedLanguages = Array.from(checkedBoxes).map(cb => cb.value); 425 426 // Handle "All" checkbox behavior - if "All" is checked, uncheck others 427 if (selectedLang === 'ALL') { 428 const allCheckbox = document.querySelector('input[value="ALL"]'); 429 if (allCheckbox && allCheckbox.checked) { 430 // Uncheck all other checkboxes 431 document.querySelectorAll('input[name="LanguageId"]:not([value="ALL"])').forEach(cb => { 432 cb.checked = false; 433 }); 434 } 435 } else { 436 // If any specific language is checked, uncheck "All" 437 const allCheckbox = document.querySelector('input[value="ALL"]'); 438 if (allCheckbox) { 439 allCheckbox.checked = false; 440 } 441 } 442 443 // Re-get checked languages after potential changes 444 const finalCheckedBoxes = document.querySelectorAll('input[name="LanguageId"]:checked'); 445 const finalCheckedLanguages = Array.from(finalCheckedBoxes).map(cb => cb.value); 446 447 // Update button text based on selected languages 448 if (finalCheckedLanguages.length === 0) { 449 button.textContent = '@Translate("All")'; 450 } else if (finalCheckedLanguages.includes('ALL')) { 451 button.textContent = '@Translate("All")'; 452 } else if (finalCheckedLanguages.length === 1) { 453 const selectedCheckbox = document.querySelector(`input[value="${finalCheckedLanguages[0]}"]`); 454 button.textContent = selectedCheckbox ? selectedCheckbox.getAttribute('data-short-name') : 'All'; 455 } else { 456 button.textContent = `${finalCheckedLanguages.length} languages selected`; 457 } 458 459 // Filter table rows 460 rows.forEach(row => { 461 const rowLanguageIds = row.getAttribute('data-language-ids'); 462 const rowLanguageName = row.getAttribute('data-language-name'); 463 464 if (finalCheckedLanguages.length === 0 || finalCheckedLanguages.includes('ALL')) { 465 row.style.display = ''; 466 } else { 467 const shouldShow = rowLanguageIds && finalCheckedLanguages.some(lang => 468 rowLanguageIds === lang || 469 rowLanguageIds === 'ALL' 470 ); 471 472 row.style.display = shouldShow ? '' : 'none'; 473 } 474 }); 475 476 } 477 document.addEventListener('DOMContentLoaded', function() { 478 // Set initial state - apply filter for pre-checked language 479 const currentLangCheckbox = document.querySelector('input[name="LanguageId"]:checked'); 480 if (currentLangCheckbox) { 481 filterResults(currentLangCheckbox.value); 482 } else { 483 // Default to show all if nothing is checked 484 const table = document.getElementById('assets-table'); 485 const rows = table.querySelectorAll('tbody tr'); 486 rows.forEach(row => { 487 row.style.display = ''; 488 }); 489 } 490 }); 491 </script> 492 @foreach (MediaViewModel asset in assetsList) 493 { 494 var assetName = asset.Value.ToLower(); 495 foreach (string videoFormat in supportedVideoFormats) 496 { //Videos 497 if (assetName.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) 498 { 499 <div class="modal fade js-video-modal" id="modal_@(Model.ID)_@modalVideoNumber" tabindex="-1" aria-labelledby="productDetailsTableModalTitle_@(Model.ID)_@modalVideoNumber" aria-hidden="true"> 500 <div class="modal-dialog modal-dialog-centered modal-xl"> 501 <div class="modal-content"> 502 <div class="modal-header visually-hidden"> 503 <h5 class="modal-title" id="productDetailsTableModalTitle_@(Model.ID)_@modalVideoNumber">@product.Title</h5> 504 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 505 </div> 506 <div class="modal-body p-2 p-lg-3 h-100"> 507 @{ 508 var videoParams = GetVideoParams(asset, "modal"); 509 @RenderPartial("Components/VideoPlayer.cshtml", new Dynamicweb.Frontend.FileViewModel { Path = asset.Value }, videoParams) 510 } 511 </div> 512 </div> 513 </div> 514 </div> 515 modalVideoNumber++; 516 } 517 } 518 } 519 </div> 520 } 521 else if (Pageview.IsVisualEditorMode) 522 { 523 <div class="h-100 @theme"> 524 <div class="alert alert-dark m-0"> 525 @Translate("No assets are available") 526 </div> 527 </div> 528 } 529 } 530