Komponent editor til: Product card - For DETAIL (Media)PAGE
Produkt specifikation vil blive vist her
Produkt specifikation vil blive vist her
Error executing template "Designs/Swift/Paragraph/Swift_ProductDetailsGallery.cshtml" System.ArgumentNullException: Value cannot be null. (Parameter 'source') at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument) at System.Linq.Enumerable.Where[TSource](IEnumerable`1 source, Func`2 predicate) at CompiledRazorTemplates.Dynamic.RazorEngine_a616a895af33476aa9e68616985b8a6a.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) in /_/src/Application/Providers/Dynamicweb.Rendering.Providers.NetCore/Razor/RazorTemplateRenderingProvider.cs:line 99 at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\TemplateRenderingService.cs:line 21 at Dynamicweb.Rendering.Template.RenderRazorTemplate() in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\Template.cs:line 749
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> @using Dynamicweb.Ecommerce.ProductCatalog @using Dynamicweb.Frontend @using System.IO @using System.Text.RegularExpressions; @functions { public ProductViewModel product { get; set; } = new ProductViewModel(); public string galleryLayout { get; set; } public string[] supportedImageFormats { get; set; } public string[] supportedVideoFormats { get; set; } public string[] supportedDocumentFormats { get; set; } public string[] allSupportedFormats { get; set; } public class RatioSettings { public string Ratio { get; set; } public string CssClass { get; set; } public string CssVariable { get; set; } public string Fill { get; set; } } public RatioSettings GetRatioSettings(string size = "desktop") { var ratioSettings = new RatioSettings(); string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); ratio = ratio != "0" ? ratio : ""; string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; cssClass = ratio != "" && ratio == "fill" && size == "mobile" ? " ratio" : cssClass; cssVariable = ratio != "" && ratio == "fill" && size == "mobile" ? "--bs-aspect-ratio: 66%" : cssVariable; ratioSettings.Ratio = ratio; ratioSettings.CssClass = cssClass; ratioSettings.CssVariable = cssVariable; ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; return ratioSettings; } public string GetColumnClass(int total, int assetNumber) { string colClass = total > 1 ? "g-col-lg-6" : "g-col-12"; colClass = galleryLayout == "full-first" && assetNumber == 0 ? "g-col-12" : colClass; colClass = galleryLayout == "full-last" && assetNumber == (total - 1) ? "g-col-12" : colClass; colClass = galleryLayout == "advanced-grid" && assetNumber > 1 ? "g-col-4" : colClass; colClass = galleryLayout == "advanced-grid" && total == 1 ? "g-col-12" : colClass; colClass = galleryLayout == "advanced-grid" && total == 3 && assetNumber == 2 ? "g-col-12" : colClass; colClass = galleryLayout == "advanced-grid" && total == 4 && assetNumber == 2 ? "g-col-6" : colClass; colClass = galleryLayout == "advanced-grid" && total == 4 && assetNumber == 3 ? "g-col-6" : colClass; colClass = galleryLayout == "advanced-grid" && total == 6 && assetNumber == 5 ? "g-col-12" : colClass; colClass = galleryLayout == "advanced-grid" && total == 7 && assetNumber == 5 ? "g-col-6" : colClass; colClass = galleryLayout == "advanced-grid" && total == 7 && assetNumber == 6 ? "g-col-6" : colClass; colClass = galleryLayout == "advanced-grid" && total == 9 && assetNumber == 8 ? "g-col-12" : colClass; return colClass; } public string GetArrowsColor() { var invertColor = Model.Item.GetBoolean("InvertModalArrowsColor"); var arrowsColor = invertColor ? " carousel-dark" : string.Empty; return arrowsColor; } public Dictionary<string, object> GetVideoParams(MediaViewModel asset, string size) { string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Name; string type = GetVideoType(asset.Value); bool openInModal = Model.Item.GetString("OpenVideoInModal") == "true" ? true : false; bool autoPlay = Model.Item.GetBoolean("VideoAutoPlay"); var videoParams = new Dictionary<string, object>(); videoParams.Add("AssetName", asset.Name); videoParams.Add("AssetVideoType", type); videoParams.Add("AssetDisplayName", asset.DisplayName); videoParams.Add("OpenVideoInModal", openInModal); videoParams.Add("VideoAutoPlay", autoPlay); videoParams.Add("Size", size); videoParams.Add("Id", Model.ID); return videoParams; } public string GetVideoType(string assetValue) { string type = assetValue.IndexOf("youtu.be", StringComparison.OrdinalIgnoreCase) >= 0 || assetValue.IndexOf("youtube", StringComparison.OrdinalIgnoreCase) >= 0 ? "youtube" : string.Empty; type = assetValue.IndexOf("vimeo", StringComparison.OrdinalIgnoreCase) >= 0 ? "vimeo" : type; type = string.IsNullOrEmpty(type) ? "selfhosted" : type; return type; } public string GetYoutubeScreenDump(string assetValue, string quality) { var regex = new Regex(@"(?:youtube\.com\/.*[\?&]v=|youtu\.be\/|youtube\.com\/embed\/)([\w-]+)(?:\?.*)?"); Match match = regex.Match(assetValue); string videoId = match.Success ? match.Groups[1].Value : string.Empty; string youtubeThumbnail = $"https://img.youtube.com/vi/{videoId}/{quality}.jpg"; return youtubeThumbnail; } } @{ @* Get the product data *@ if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) { product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; } else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) { var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); if (productList?.Products is object) { product = productList.Products[0]; } } } @if (product is object) { @* Supported formats *@ supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff" }; supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", "pptx" }; allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); @* Collect the assets *@ var selectedAssetCategories = Model.Item.GetList("ImageAssets")?.GetRawValue().OfType<string>(); bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); assetsImages = assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); IEnumerable<MediaViewModel> assetsList = new MediaViewModel[]{}; assetsList = assetsList.Union(assetsImages); assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); int totalAssets = 0; foreach (MediaViewModel asset in assetsList) { var assetValue = asset.Value; foreach (string format in allSupportedFormats) { if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { totalAssets++; } } } if (totalAssets == 0) { if (defaultImageFallback) { assetsList = new List<MediaViewModel>(){ product.DefaultImage }; totalAssets = 1; } else { assetsList = new List<MediaViewModel>(){ }; totalAssets = 0; } } @* Layout settings *@ string spacing = Model.Item.GetRawValueString("Spacing", "4"); spacing = spacing == "none" ? "gap-0" : spacing; spacing = spacing == "small" ? "gap-3" : spacing; spacing = spacing == "large" ? "gap-4" : spacing; galleryLayout = Model.Item.GetRawValueString("Layout", "grid"); string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; var badgeParms = new Dictionary<string, object>(); badgeParms.Add("size", "h5"); badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); badgeParms.Add("campaignBadgesValues", Model.Item.GetList("CampaignBadges")?.GetRawValue().OfType<string>().ToList()); bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; DateTime createdDate = product.Created.Value; bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; @* Get assets from selected categories or get all assets *@ if (totalAssets != 0 && assetsList.Count() != 0) { int desktopAssetNumber = 0; int mobileAssetNumber = 0; int mobileAssetThumbnailNumber = 0; int modalAssetNumber = 0; @* Desktop: Show the gallery on large screens *@ <div class="d-none d-lg-block h-100 position-relative @theme item_@Model.Item.SystemName.ToLower() desktop"> <div class="grid @spacing"> @foreach (MediaViewModel asset in assetsList) { var assetName = asset.Value; foreach (string format in allSupportedFormats) { if (assetName.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string size = "desktop"; string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; string assetValue = asset.Value; <div class="@GetColumnClass(totalAssets, desktopAssetNumber)"> <div class="h-100 @(imageTheme)"> @foreach (string imageFormat in supportedImageFormats) { //Images 2 if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = !string.IsNullOrEmpty(imagePath) ? $"/Admin/Public/GetImage.ashx?image={Uri.EscapeDataString(imagePath)}&width=1920&format=webp" : string.Empty; ; RatioSettings ratioSettings = GetRatioSettings(size); var parms = new Dictionary<string, object>(); parms.Add("alt", productName); parms.Add("itemprop", "image"); if (totalAssets > 1) { parms.Add("columns", 2); } else { parms.Add("columns", 1); } parms.Add("eagerLoadNewImages", Model.Item.GetBoolean("DisableLazyLoading")); parms.Add("doNotUseGetimage", Model.Item.GetBoolean("DisableGetImage")); if (!string.IsNullOrEmpty(asset.DisplayName)) { parms.Add("title", asset.DisplayName); } if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") { parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); } else { parms.Add("cssClass", "mw-100 mh-100"); } <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@desktopAssetNumber"> @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) </div> </a> } } @foreach (string videoFormat in supportedVideoFormats) { //Videos if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) { if (Model.Item.GetString("OpenVideoInModal") == "true") { string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; string type = GetVideoType(asset.Value); string videoScreendumpPath = type == "selfhosted" ? System.Uri.EscapeUriString(asset.Value) : string.Empty; videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value, "maxresdefault") : videoScreendumpPath; string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : string.Empty; string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(size); <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@desktopAssetNumber"> <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> @if (type != "selfhosted") { <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;" /> } else { string videoType = Path.GetExtension(asset.Value).ToLower(); <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> <source src="@(videoScreendumpPath)#t=0.001" type="video/@videoType.Replace(".", "")"> </video> } </div> </div> } else { var videoParams = GetVideoParams(asset, size); @RenderPartial("Components/VideoPlayer.cshtml", new FileViewModel { Path = asset.Value }, videoParams); } } } @foreach (string documentFormat in supportedDocumentFormats) { //Documents 3 if (assetValue.IndexOf(documentFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; string productName = product.Name; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = Uri.EscapeDataString(imagePath); 4 5 RatioSettings ratioSettings = GetRatioSettings(size); var parms = new Dictionary<string, object>(); parms.Add("alt", productName); parms.Add("itemprop", "image"); parms.Add("fullwidth", true); parms.Add("columns", Model.GridRowColumnCount); if (!string.IsNullOrEmpty(asset.DisplayName)) { parms.Add("title", asset.DisplayName); } if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") { parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); } else { parms.Add("cssClass", "mw-100 mh-100"); } <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download title="@Translate("Download")"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> @if (asset.Value.IndexOf(".pdf", StringComparison.OrdinalIgnoreCase) >= 0) { @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) } else { } </div> </a> } } </div> </div> desktopAssetNumber++; } } } </div> @if (showBadges) { <div class="position-absolute top-0 left-0 p-2 p-lg-3 w-100"> @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) </div> } </div> @* Mobile: Show the thumbs on small screens *@ <div class="d-block d-lg-none mx-lg-0 position-relative @theme item_@Model.Item.SystemName.ToLower() mobile"> <div id="SmallScreenImages_@Model.ID" class="carousel@(GetArrowsColor())" data-bs-ride="carousel"> <div class="carousel-inner h-100"> @foreach (MediaViewModel asset in assetsList) { var assetValue = asset.Value; foreach (string format in allSupportedFormats) { if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string activeSlide = mobileAssetNumber == 0 ? "active" : ""; string size = "mobile"; string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; <div class="carousel-item @activeSlide" data-bs-interval="99999"> <div class="h-100 @(imageTheme)"> @foreach (string imageFormat in supportedImageFormats) { //Images 6 if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string productName = product.Name; string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; string imageLinkPath = !string.IsNullOrEmpty(imagePath) ? $"/Admin/Public/GetImage.ashx?image={Uri.EscapeDataString(imagePath)}&width=1920&format=webp" : string.Empty; 7 8 RatioSettings ratioSettings = GetRatioSettings(size); var parms = new Dictionary<string, object>(); parms.Add("alt", productName); parms.Add("itemprop", "image"); if (totalAssets > 1) { parms.Add("columns", 2); } else { parms.Add("columns", 1); } parms.Add("eagerLoadNewImages", Model.Item.GetBoolean("DisableLazyLoading")); parms.Add("doNotUseGetimage", Model.Item.GetBoolean("DisableGetImage")); if (!string.IsNullOrEmpty(asset.DisplayName)) { parms.Add("title", asset.DisplayName); } if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") { parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); } else { parms.Add("cssClass", "mw-100 mh-100"); } <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@mobileAssetNumber"> @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) </div> </a> } } @foreach (string videoFormat in supportedVideoFormats) { //Videos if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) { if (Model.Item.GetString("OpenVideoInModal") == "true") { string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; string type = GetVideoType(asset.Value); string videoScreendumpPath = type == "selfhosted" ? System.Uri.EscapeUriString(asset.Value) : string.Empty; videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value, "maxresdefault") : videoScreendumpPath; string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : ""; string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; RatioSettings ratioSettings = GetRatioSettings(size); <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@desktopAssetNumber"> <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> @if (type != "selfhosted") { <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;" > } else { string videoType = Path.GetExtension(asset.Value).ToLower(); <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> <source src="@(videoScreendumpPath)#t=0.001" type="video/@videoType.Replace(".", "")"> </video> } </div> </div> } else { Dictionary<string, object> videoParams = GetVideoParams(asset, size); @RenderPartial("Components/VideoPlayer.cshtml", new FileViewModel { Path = asset.Value }, videoParams); } } } </div> </div> mobileAssetNumber++; } } } </div> </div> @if (totalAssets > 1) { <div id="SmallScreenImagesThumbnails_@Model.ID" class="d-flex flex-nowrap gap-2 overflow-x-auto my-3"> @foreach (MediaViewModel asset in assetsList) { var assetValue = asset.Value; foreach (string format in allSupportedFormats) { if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; string type = GetVideoType(asset.Value); string videoScreendumpPath = type == "youtube" ? GetYoutubeScreenDump(asset.Value, "maxresdefault") : string.Empty; videoScreendumpPath = type == "selfhosted" ? System.Uri.EscapeUriString(asset.Value) : videoScreendumpPath; string videoJsClass = type == "vimeo" ? "js-vimeo-video-thumbnail" : string.Empty; string productName = product.Name; productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; <div class="ratio ratio-4x3 border outline-none" style="flex:0 0 80px" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to="@mobileAssetThumbnailNumber"> @foreach (string imageFormat in supportedImageFormats) { //Images if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string imagePath = !string.IsNullOrEmpty(asset.Value) ? $"/Admin/Public/GetImage.ashx?image={asset.Value}&width=180&format=webp" : string.Empty; <img src="@imagePath" class="p-1 mw-100 mh-100" style="object-fit: cover;" alt="@productName" @assetTitle > } } @foreach (string videoFormat in supportedVideoFormats) { //Videos if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath+"play-circle.svg")</div> </div> if (type != "selfhosted") { <img src="@(videoScreendumpPath)" class="p-1 @videoJsClass mw-100 mh-100" data-asset-value="@asset.Value" style="object-fit: cover;" alt="@productName" @assetTitle> } else { string videoType = Path.GetExtension(asset.Value).ToLower(); <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> <source src="@(videoScreendumpPath)#t=0.001" type="video/@videoType.Replace(".", "")"> </video> } } } @foreach (string documentFormat in supportedDocumentFormats) { //Documents if (assetValue.IndexOf(documentFormat, StringComparison.OrdinalIgnoreCase) >= 0) { string imagePath = !string.IsNullOrEmpty(asset.Value) ? $"/Admin/Public/GetImage.ashx?image={asset.Value}&width=180&format=webp" : string.Empty; <a href="@Uri.EscapeDataString(assetValue)" style="cursor: pointer; min-width: 7rem; max-width: 8rem;" download title="@asset.Value"> @if (asset.Value.IndexOf(".pdf", StringComparison.OrdinalIgnoreCase) >= 0) { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> </div> <img src="@imagePath" alt="@productName" @assetTitle class="p-0 p-lg-1 mw-100 mh-100" style="object-fit: cover;"> } else { <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> <div class="icon-3 position-absolute" style="z-index: 1">@ReadFile(iconPath + "file-text.svg")</div> </div> } </a> } } </div> mobileAssetThumbnailNumber++; } } } </div> } @if (showBadges) { <div class="position-absolute top-0 left-0 p-2 p-lg-3"> @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) </div> } </div> @* Modal with slides *@ <div class="modal fade swift_products-details-images-modal" id="modal_@Model.ID" tabindex="-1" aria-labelledby="productDetailsGalleryModalTitle_@Model.ID" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered modal-xl"> <div class="modal-content"> <div class="modal-header visually-hidden"> <h5 class="modal-title" id="productDetailsGalleryModalTitle_@Model.ID">@product.Title</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body p-2 p-lg-3 h-100"> <div id="ModalCarousel_@Model.ID" class="carousel@(GetArrowsColor()) h-100" data-bs-ride="carousel"> <div class="carousel-inner h-100 @theme"> @foreach (MediaViewModel asset in assetsList) { var assetValue = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; foreach (string format in allSupportedFormats) { if (assetValue.IndexOf(format, StringComparison.OrdinalIgnoreCase) >= 0) { string imagePath = assetValue; string activeSlide = modalAssetNumber == 0 ? "active" : ""; var parms = new Dictionary<string, object>(); parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); parms.Add("columns", Model.GridRowColumnCount); parms.Add("eagerLoadNewImages", Model.Item.GetBoolean("DisableLazyLoading")); parms.Add("doNotUseGetimage", Model.Item.GetBoolean("DisableGetImage")); <div class="carousel-item @activeSlide h-100" data-bs-interval="99999"> @foreach (string imageFormat in supportedImageFormats) { if (assetValue.IndexOf(imageFormat, StringComparison.OrdinalIgnoreCase) >= 0) { @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) } } @foreach (string videoFormat in supportedVideoFormats) { if (assetValue.IndexOf(videoFormat, StringComparison.OrdinalIgnoreCase) >= 0) { Dictionary<string, object> videoParams = GetVideoParams(asset, "modal"); @RenderPartial("Components/VideoPlayer.cshtml", new FileViewModel { Path = asset.Value }, videoParams); } } </div> modalAssetNumber++; } } } <button class="carousel-control-prev carousel-control-area" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden">@Translate("Previous")</span> </button> <button class="carousel-control-next carousel-control-area" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden">@Translate("Next")</span> </button> </div> </div> </div> </div> </div> </div> } else if (Pageview.IsVisualEditorMode) { RatioSettings ratioSettings = GetRatioSettings("desktop"); <div class="h-100 @theme"> <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> <img src="/Files/Images/missing_image.jpg" loading="lazy" decoding="async" class="mh-100 mw-100" style="object-fit: cover;" alt="@Translate("Missing image")"> </div> </div> } }
100% køreklar
Gratis levering*
Tilfredsheds-garanti