Error executing template "Designs/Swift/Paragraph/Swift_ProductDetailsImage_Custom.cshtml" System.Net.WebException: The remote server returned an error: (404) Not Found. at System.Net.WebClient.DownloadFile(Uri address, String fileName) at CompiledRazorTemplates.Dynamic.RazorEngine_14b751bacbeb4aaab49e5c037d8f0955.Execute() in C:\DynamicWeb\Solution\Development\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsImage_Custom.cshtml:line 91 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.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Frontend 4 @using System.IO 5 6 @functions { 7 public ProductViewModel product { get; set; } = new ProductViewModel(); 8 public string galleryLayout { get; set; } 9 public string[] supportedImageFormats { get; set; } 10 public string[] supportedVideoFormats { get; set; } 11 public string[] supportedDocumentFormats { get; set; } 12 public string[] allSupportedFormats { get; set; } 13 14 public class RatioSettings { 15 public string Ratio { get; set; } 16 public string CssClass { get; set; } 17 public string CssVariable { get; set; } 18 public string Fill { get; set; } 19 } 20 21 public RatioSettings GetRatioSettings(string size = "desktop") { 22 var ratioSettings = new RatioSettings(); 23 24 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 25 ratio = ratio != "0" ? ratio : ""; 26 string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 27 string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 28 cssClass = ratio == "fill" && size == "mobile" ? " ratio" : cssClass; 29 cssVariable = ratio == "fill" && size == "mobile" ? "--bs-aspect-ratio: 66%" : cssVariable; 30 31 ratioSettings.Ratio = ratio; 32 ratioSettings.CssClass = cssClass; 33 ratioSettings.CssVariable = cssVariable; 34 ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; 35 36 return ratioSettings; 37 } 38 } 39 40 @{ 41 @* Get the product data *@ 42 ProductViewModelSettings productSetting = new ProductViewModelSettings 43 { 44 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 45 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 46 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 47 ShopId = Pageview.Area.EcomShopId 48 }; 49 50 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 51 { 52 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 53 } 54 else if (Pageview.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 55 { 56 string dummyProductId = ""; 57 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 58 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 59 if (productList.Products != null) 60 { 61 foreach (var p in productList.Products) { dummyProductId = p.Id; } 62 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel(); 63 product = dummyProduct; 64 } else { 65 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetAllProducts(Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 66 } 67 } else if (Pageview.Item["DummyProduct"] == null) { 68 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetAllProducts(Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 69 } 70 71 @* Supported formats *@ 72 supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff" }; 73 supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; 74 supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", "pptx" }; 75 allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); 76 77 @* Collect the assets *@ 78 var selectedAssetCategories = Model.Item.GetRawValueString("ImageAssets").Split(',').ToList(); 79 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 80 81 } 82 83 @if (product.Id != null) { 84 @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ 85 string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; 86 if( product.DefaultImage.Value.Contains("missing_image.jpg") && !string.IsNullOrEmpty(product.ProductFields["ProductImageUrl"].Value.ToString()) ) { 87 using (var client = new System.Net.WebClient()) 88 { 89 //product.DefaultImage.Value.Contains("missing_image.jpg"); 90 //client.DownloadFile(product.ProductFields["ProductImageUrl"].Value.ToString()); 91 client.DownloadFile(product.ProductFields["ProductImageUrl"].Value.ToString(), AppDomain.CurrentDomain.BaseDirectory+"Files/Images/Products/Downloaded/"+product.Id+".jpg"); 92 } 93 defaultImage = "/Files/Images/Products/Downloaded/"+product.Id+".jpg"; 94 product.DefaultImage.Value = "/Files/Images/Products/Downloaded/"+product.Id+".jpg"; 95 } 96 97 IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); 98 assetsImages = assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); 99 IEnumerable<MediaViewModel> assetsList = new MediaViewModel[]{}; 100 101 assetsList = assetsList.Union(assetsImages); 102 assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; 103 assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; 104 105 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 106 bool showOnlyPrimaryImage = Model.Item.GetBoolean("ShowOnlyPrimaryImage"); 107 108 int totalAssets = 0; 109 if (showOnlyPrimaryImage == false) { 110 foreach (MediaViewModel asset in assetsList) { 111 var assetValue = asset.Value.ToLower(); 112 foreach (string format in allSupportedFormats) { 113 if (assetValue.Contains(format) ) { 114 totalAssets++; 115 } 116 } 117 } 118 } 119 120 121 if((totalAssets == 0 && product.DefaultImage != null && selectedAssetCategories.Count() == 0) || (showOnlyPrimaryImage == true && product.DefaultImage != null)) 122 { 123 assetsList = new List<MediaViewModel>(){ product.DefaultImage }; 124 totalAssets = 1; 125 } 126 127 @* Theme settings *@ 128 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 129 130 var badgeParms = new Dictionary<string, object>(); 131 badgeParms.Add("size", "h5"); 132 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 133 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 134 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 135 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 136 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 137 138 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 139 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 140 DateTime createdDate = product.Created.Value; 141 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 142 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 143 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 144 145 @* Get assets from selected categories or get all assets *@ 146 if (totalAssets != 0) { 147 int assetNumber = 0; 148 int thumbnailNumber = 0; 149 int modalAssetNumber = 0; 150 151 <div class="h-100@(theme) position-relative item_@Model.Item.SystemName.ToLower()"> 152 <div id="SmallScreenImages_@Model.ID" class="carousel" data-bs-ride="carousel"> 153 <div class="carousel-inner h-100"> 154 @foreach (MediaViewModel asset in assetsList) { 155 var assetValue = asset.Value.ToLower(); 156 foreach (string format in allSupportedFormats) { 157 if (assetValue.Contains(format) ) { 158 string activeSlide = assetNumber == 0 ? "active" : ""; 159 160 <div class="carousel-item @activeSlide" data-bs-interval="99999"> 161 @RenderAsset(asset, assetNumber, "mobile") 162 </div> 163 assetNumber++; 164 } 165 } 166 } 167 </div> 168 </div> 169 170 @if (totalAssets > 1) { 171 <div id="SmallScreenImagesThumbnails_@Model.ID" class="grid grid-10 gap-2 overflow-x-auto my-3"> 172 @foreach (MediaViewModel asset in assetsList) { 173 var assetValue = asset.Value; 174 foreach (string format in allSupportedFormats) { 175 if (assetValue.Contains(format)) { 176 string imagePath = Dynamicweb.Context.Current.Server.UrlEncode(assetValue); 177 imagePath = assetValue.Contains("youtu.be") || assetValue.Contains("youtube") ? "https://img.youtube.com/vi/" + assetValue.Substring(assetValue.LastIndexOf('/') + 1) + "/default.jpg" : imagePath; 178 string imagePathThumb = !imagePath.Contains("youtube") ? $"/Admin/Public/GetImage.ashx?image={imagePath}&width=180&format=webp" : imagePath; 179 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 180 181 string videoId = assetValue.Substring(assetValue.LastIndexOf('/') + 1); 182 string vimeoJsClass = assetValue.Contains("vimeo") ? "js-vimeo-video-thumbnail" : ""; 183 184 bool isDocument = false; 185 foreach (string documentFormat in supportedDocumentFormats) { 186 if (assetValue.Contains(documentFormat)) { 187 isDocument = true; 188 } 189 } 190 191 string assetName = asset.Name; 192 assetName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 193 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; 194 195 if (!isDocument) { 196 RatioSettings ratioSettings = GetRatioSettings("desktop"); 197 198 <div class="border outline-none @(ratioSettings.CssClass)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to="@thumbnailNumber"> 199 <div class="d-flex align-items-center justify-content-center overflow-hidden position-absolute h-100"> 200 @foreach (string videoFormat in supportedVideoFormats) { //Videos 201 if (assetValue.Contains(videoFormat)) { 202 <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 203 } 204 } 205 </div> 206 <img src="@imagePathThumb" alt="@assetName" @assetTitle class="p-0 p-lg-1 @vimeoJsClass w-100 h-100" style="object-fit: contain" data-video-id="@videoId"> 207 </div> 208 } else { 209 <a href="@assetValue" class="ratio ratio-4x3 border outline-none" style="cursor: pointer" download title="@asset.Value"> 210 @if (asset.Value.Contains(".pdf")) { 211 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 212 <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> 213 </div> 214 <img src="@imagePathThumb" alt="@assetName" @assetTitle class="p-0 p-lg-1 mw-100 mh-100" style="object-fit: cover;"> 215 } else { 216 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 217 <div class="icon-3 position-absolute" style="z-index: 1">@ReadFile(iconPath + "file-text.svg")</div> 218 </div> 219 } 220 </a> 221 } 222 223 thumbnailNumber++; 224 } 225 } 226 } 227 </div> 228 } 229 230 @if (showBadges) { 231 <div class="position-absolute top-0 left-0 p-2 p-lg-3"> 232 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 233 </div> 234 } 235 </div> 236 237 @* Modal with slides *@ 238 <div class="modal fade swift_products-details-images-modal" id="modal_@Model.ID" tabindex="-1" aria-labelledby="productDetailsGalleryModalTitle_@Model.ID" aria-hidden="true"> 239 <div class="modal-dialog modal-dialog-centered modal-xl"> 240 <div class="modal-content"> 241 <div class="modal-header visually-hidden"> 242 <h5 class="modal-title" id="productDetailsGalleryModalTitle_@Model.ID">@product.Title</h5> 243 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 244 </div> 245 <div class="modal-body p-2 p-lg-3 h-100"> 246 <div id="ModalCarousel_@Model.ID" class="carousel h-100" data-bs-ride="carousel"> 247 <div class="carousel-inner h-100"> 248 @foreach (MediaViewModel asset in assetsList) { 249 var assetValue = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 250 foreach (string format in allSupportedFormats) { 251 if (assetValue.Contains(format) ) { 252 string imagePath = assetValue; 253 string activeSlide = modalAssetNumber == 0 ? "active" : ""; 254 255 var parms = new Dictionary<string, object>(); 256 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 257 parms.Add("fullwidth", true); 258 parms.Add("columns", Model.GridRowColumnCount); 259 260 <div class="carousel-item @activeSlide h-100" data-bs-interval="99999"> 261 @foreach (string imageFormat in supportedImageFormats) { //Images 262 if (assetValue.Contains(imageFormat)) { 263 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 264 } 265 } 266 267 @foreach (string videoFormat in supportedVideoFormats) { //Videos 268 if (assetValue.Contains(videoFormat)) { 269 @RenderVideoPlayer(asset, "modal") 270 } 271 } 272 </div> 273 274 modalAssetNumber++; 275 } 276 } 277 } 278 <button class="carousel-control-prev" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="prev"> 279 <span class="carousel-control-prev-icon" aria-hidden="true"></span> 280 <span class="visually-hidden">@Translate("Previous")</span> 281 </button> 282 <button class="carousel-control-next" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="next"> 283 <span class="carousel-control-next-icon" aria-hidden="true"></span> 284 <span class="visually-hidden">@Translate("Next")</span> 285 </button> 286 </div> 287 </div> 288 </div> 289 </div> 290 </div> 291 </div> 292 } else if (Pageview.IsVisualEditorMode) { 293 RatioSettings ratioSettings = GetRatioSettings("desktop"); 294 295 <div class="h-100 @theme"> 296 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> 297 <img src="~/Files/Images/missing_image.jpg" loading="lazy" decoding="async" class="mh-100 mw-100" style="object-fit: cover;" /> 298 </div> 299 </div> 300 } 301 } else if (Pageview.IsVisualEditorMode) { 302 <div class="alert alert-dark m-0">@Translate("No products available")</div> 303 } 304 305 @helper RenderAsset(MediaViewModel asset, int assetNumber, string size = "desktop") { 306 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 307 string assetValue = asset.Value.ToLower(); 308 309 <div class="h-100 @(theme)"> 310 @foreach (string format in supportedImageFormats) { //Images 311 if (assetValue.Contains(format)) { 312 @RenderImage(asset, assetNumber, size) 313 } 314 } 315 @foreach (string format in supportedVideoFormats) { //Videos 316 if (assetValue.Contains(format)) { 317 if (Model.Item.GetString("OpenVideoInModal") == "true") { 318 @RenderVideoScreendump(asset, assetNumber, size) 319 } else { 320 @RenderVideoPlayer(asset, size) 321 } 322 } 323 } 324 @foreach (string format in supportedDocumentFormats) { //Documents 325 if (assetValue.Contains(format)) { 326 @RenderDocument(asset, assetNumber, size) 327 } 328 } 329 </div> 330 } 331 332 @helper RenderImage(MediaViewModel asset, int number, string size = "desktop") { 333 string productName = product.Name; 334 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value.ToLower() : product.DefaultImage.Value; 335 string imageLinkPath = Dynamicweb.Context.Current.Server.UrlEncode(imagePath); 336 337 RatioSettings ratioSettings = GetRatioSettings(size); 338 339 var parms = new Dictionary<string, object>(); 340 parms.Add("alt", productName + asset.Keywords); 341 parms.Add("itemprop", "image"); 342 parms.Add("fullwidth", true); 343 parms.Add("columns", Model.GridRowColumnCount); 344 if (!string.IsNullOrEmpty(asset.DisplayName)) { 345 parms.Add("title", asset.DisplayName); 346 } 347 348 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") { 349 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 350 } else { 351 parms.Add("cssClass", "mw-100 mh-100"); 352 } 353 354 <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 355 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@number"> 356 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 357 </div> 358 </a> 359 } 360 361 @helper RenderVideoScreendump(MediaViewModel asset, int number, string size = "desktop") { 362 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 363 364 string videoScreendumpPath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : ""; 365 string videoId = videoScreendumpPath.Substring(videoScreendumpPath.LastIndexOf('/') + 1); 366 videoScreendumpPath = videoScreendumpPath.Contains("youtu.be") || videoScreendumpPath.Contains("youtube") ? "https://img.youtube.com/vi/" + videoId + "/maxresdefault.jpg" : videoScreendumpPath; 367 368 string vimeoJsClass = videoScreendumpPath.Contains("vimeo") ? "js-vimeo-video-thumbnail" : ""; 369 videoScreendumpPath = videoScreendumpPath.Contains("vimeo") ? "" : videoScreendumpPath; 370 371 string productName = product.Name; 372 productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 373 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; 374 375 RatioSettings ratioSettings = GetRatioSettings(size); 376 377 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 378 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@number"> 379 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 380 <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@productName" @assetTitle class="@vimeoJsClass mw-100 mh-100 test" data-video-id="@videoId" style="object-fit: cover;" /> 381 </div> 382 </div> 383 } 384 385 @helper RenderVideoPlayer(MediaViewModel asset, string size = "desktop") { 386 string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Name; 387 string assetValue = asset.Value; 388 string videoId = asset.Value.Substring(asset.Value.LastIndexOf('/') + 1); 389 string type = assetValue.Contains("youtu.be") || assetValue.Contains("youtube") ? "youtube" : ""; 390 type = assetValue.Contains("vimeo") ? "vimeo" : type; 391 type = assetValue.Contains(".mp4") || assetValue.Contains(".webm") ? "selfhosted" : type; 392 393 string openInModal = Model.Item.GetString("OpenVideoInModal"); 394 bool autoPlay = Model.Item.GetBoolean("VideoAutoPlay"); 395 396 <div class="h-100" itemscope itemtype="https://schema.org/VideoObject"> 397 <span class="visually-hidden" itemprop="name">@assetName</span> 398 <span class="visually-hidden" itemprop="contentUrl">@asset.Value</span> 399 <span class="visually-hidden" itemprop="thumbnailUrl">@asset.Value</span> 400 401 @if (type != "selfhosted") { 402 <div 403 id="player_@(Pageview.CurrentParagraph.ID)_@(videoId)_@size" 404 class="plyr__video-embed" 405 data-plyr-provider="@(type)" 406 data-plyr-embed-id="@videoId" 407 style="--plyr-color-main: var(--swift-foreground-color); height: 100%"> 408 </div> 409 410 <script type="module" src="~/Files/Templates/Designs/Swift/Assets/js/plyr.js"></script> 411 412 <script type="module"> 413 var player = new Plyr('#player_@(Pageview.CurrentParagraph.ID)_@(videoId)_@size', { 414 type: 'video', 415 youtube: { 416 noCookie: true, 417 showinfo: 0 418 }, 419 fullscreen: { 420 enabled: true, 421 iosNative: true, 422 } 423 }); 424 425 @if (autoPlay && openInModal == "false") { 426 <text> 427 player.config.autoplay = true; 428 player.config.muted = true; 429 player.config.volume = 0; 430 player.media.loop = true; 431 432 player.on('ready', function() { 433 if (player.config.autoplay === true) { 434 player.media.play(); 435 } 436 }); 437 </text> 438 } 439 440 @if (openInModal == "true") { 441 <text> 442 var productDetailsGalleryModal = document.querySelector('#modal_@Model.ID') 443 productDetailsGalleryModal.addEventListener('hidden.bs.modal', function (event) { 444 player.media.pause(); 445 }) 446 </text> 447 } 448 </script> 449 } else { 450 string autoPlayAttributes = (autoPlay && openInModal == "false") ? "loop autoplay muted playsinline" : ""; 451 string videoType = Path.GetExtension(assetValue).ToLower(); 452 453 <video preload="auto" @autoPlayAttributes class="h-100 w-100" style="object-fit: cover;"> 454 <source src="@assetValue" type="video/@videoType.Replace(".", "")"> 455 </video> 456 } 457 </div> 458 } 459 460 @helper RenderDocument(MediaViewModel asset, int number, string size = "desktop") { 461 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 462 463 string productName = product.Name; 464 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 465 string imageLinkPath = imagePath; 466 467 RatioSettings ratioSettings = GetRatioSettings(size); 468 469 var parms = new Dictionary<string, object>(); 470 parms.Add("alt", productName + asset.Keywords); 471 parms.Add("itemprop", "image"); 472 parms.Add("fullwidth", true); 473 parms.Add("columns", Model.GridRowColumnCount); 474 if (!string.IsNullOrEmpty(asset.DisplayName)) { 475 parms.Add("title", asset.DisplayName); 476 } 477 478 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") { 479 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 480 } else { 481 parms.Add("cssClass", "mw-100 mh-100"); 482 } 483 484 <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download alt="@Translate("Download")"> 485 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 486 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> 487 @if (asset.Value.Contains(".pdf")) { 488 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 489 } 490 </div> 491 </a> 492 } 493
Novus Mouse Transthyretin/Prealbumin ELISA Kit (Colorimetric)1 kit
NOVNBP308188
This is a regulated item, so additional permits may be required which may lead to an extended ETA. Please Contact us at lifescience@invitro.com.au for more information.