Error executing template "Designs/Swift/Paragraph/Swift_ProductCatalogDetailsApp.cshtml"
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
at RazorEngine.Roslyn.CSharp.RoslynCompilerServiceBase.CompileType(TypeContext context)
at RazorEngine.Templating.RazorEngineCore.CreateTemplateType(ITemplateSource razorTemplate, Type modelType)
at RazorEngine.Templating.RazorEngineCore.Compile(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.GetCompiledTemplate(ITemplateKey key, Type modelType, Boolean compileOnCacheMiss)
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 4 @{
5 //Set default product data for use in Visual Editor
6 if (Pageview.IsVisualEditorMode)
7 {
8 ProductViewModelSettings productSetting = new ProductViewModelSettings
9 {
10 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID,
11 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code,
12 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2,
13 ShopId = Pageview.Area.EcomShopId
14 };
15 16 string selectedDummyProduct = "PROD1";
17 var list = new ProductListViewModel();
18 if (Model.Item.GetValue("DummyProduct") != null)
19 {
20 list = Model.Item.GetValue("DummyProduct") as ProductListViewModel;
21 22 foreach (var product in list.Products)
23 {
24 selectedDummyProduct = product.Id;
25 }
26 27 ProductViewModel dummyProduct = ViewModelFactory.CreateView(productSetting, selectedDummyProduct);
28 29 if (!Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
30 {
31 Dynamicweb.Context.Current.Items.Add("ProductDetails", dummyProduct);
32 }
33 }
34 else
35 {
36 <div class="alert alert-danger" role="alert">
37 <span>@Translate("Please select a Dummy product on this paragraph")</span>
38 </div>
39 }
40 }
41 else if (!Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
42 {
43 ProductViewModel dummyProduct = new ProductViewModel();
44 Dynamicweb.Context.Current.Items.Add("ProductDetails", dummyProduct);
45 }
46 }
47 48 @if (Pageview.IsVisualEditorMode)
49 {
50 <div class="alert alert-info" role="alert">
51 <span>@Translate("Product catalog App: Edit this column to configure. (Product catalog app must be attached this paragraph)")</span>
52 </div>
53 }
54 55 <div class="item_@Model.Item.SystemName.ToLower()">
56 @Model.GetModuleOutput()
57 </div>
58
Error executing template "/Designs/Swift/Grid/Page/RowTemplates/2Columns.cshtml"
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
at RazorEngine.Roslyn.CSharp.RoslynCompilerServiceBase.CompileType(TypeContext context)
at RazorEngine.Templating.RazorEngineCore.CreateTemplateType(ITemplateSource razorTemplate, Type modelType)
at RazorEngine.Templating.RazorEngineCore.Compile(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.GetCompiledTemplate(ITemplateKey key, Type modelType, Boolean compileOnCacheMiss)
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.GridRowViewModel>
2 3 @{
4 string sectionClass = "py-3";
5 string spaceBetweenRows = Model.Item.GetRawValueString("SpaceBetweenRows", "spacing");
6 string spaceBetweenRowsMobile = Model.Item.GetRawValueString("SpaceBetweenRowsMobile", "auto");
7 8 //Row spacing mobile auto
9 if (spaceBetweenRowsMobile == "auto") {
10 spaceBetweenRowsMobile = spaceBetweenRows;
11 }
12 13 //Row spacing mobile
14 switch (spaceBetweenRowsMobile) {
15 case "none": //No spacing
16 sectionClass = "py-0";
17 break;
18 case "spacing": //Small spacing top and bottom
19 sectionClass = "py-3";
20 break;
21 case "spacing-small-top": //Small spacing top
22 sectionClass = "pt-3";
23 break;
24 case "spacing-small-bottom": //Small spacing bottom
25 sectionClass = "pb-3";
26 break;
27 case "spacing-medium": //Medium spacing top and bottom
28 sectionClass = "py-4";
29 break;
30 case "spacing-medium-top": //Medium spacing top
31 sectionClass = "pt-4";
32 break;
33 case "spacing-medium-bottom": //Medium spacing bottom
34 sectionClass = "pb-4";
35 break;
36 case "spacing-large": //Large spacing top and bottom
37 sectionClass = "py-5";
38 break;
39 case "spacing-top": //Large spacing top
40 sectionClass = "pt-5";
41 break;
42 case "spacing-bottom": //Large spacing bottom
43 sectionClass = "pb-5";
44 break;
45 }
46 47 //Row spacing dekstop
48 switch (spaceBetweenRows) {
49 case "none": //No spacing
50 sectionClass += " py-lg-0";
51 break;
52 case "spacing": //Small spacing top and bottom
53 sectionClass += " py-lg-3";
54 break;
55 case "spacing-small-top": //Small spacing top
56 sectionClass += " pt-lg-3 pb-lg-0";
57 break;
58 case "spacing-small-bottom": //Small spacing bottom
59 sectionClass += " pb-lg-3 pt-lg-0";
60 break;
61 case "spacing-medium": //Medium spacing top and bottom
62 sectionClass += " py-lg-5";
63 break;
64 case "spacing-medium-top": //Medium spacing top
65 sectionClass += " pt-lg-5 pb-lg-0";
66 break;
67 case "spacing-medium-bottom": //Medium spacing bottom
68 sectionClass += " pb-lg-5 pt-lg-0";
69 break;
70 case "spacing-large": //Large spacing top and bottom
71 sectionClass += " py-lg-6";
72 break;
73 case "spacing-top": //Large spacing top
74 sectionClass += " pt-lg-6 pb-lg-0";
75 break;
76 case "spacing-bottom": //Large spacing bottom
77 sectionClass += " pb-lg-6 pt-lg-0";
78 break;
79 }
80 81 string containerClass = "container-xl";
82 string width = Model.Item.GetRawValueString("Width", "container-xl");
83 if (width == "none")
84 {
85 containerClass = "container-fluid px-0";
86 }
87 if (width == "stretch") {
88 containerClass = "container-fluid";
89 }
90 if (width == "compressed") {
91 containerClass = " container-compressed";
92 }
93 94 string rowClass = string.Empty;
95 string spaceBetweenColumns = Model.Item.GetRawValueString("SpaceBetweenColumns", string.Empty).ToLower();
96 string spaceBetweenColumnsMobile = Model.Item.GetRawValueString("SpaceBetweenColumnsMobile", string.Empty).ToLower();
97 //Mobile
98 if (spaceBetweenColumnsMobile == "auto")
99 {
100 spaceBetweenColumnsMobile = spaceBetweenColumns;
101 }
102 if (spaceBetweenColumnsMobile == "stick") {
103 rowClass = " gap-0";
104 }
105 if (spaceBetweenColumnsMobile == "spacing-medium")
106 {
107 rowClass = " gap-4";
108 }
109 if (spaceBetweenColumnsMobile == "spacing-large") {
110 rowClass = " gap-5";
111 }
112 //Desktop
113 if (spaceBetweenColumns == "stick") {
114 rowClass += " gap-lg-0";
115 }
116 if (spaceBetweenColumns == "spacing-medium")
117 {
118 rowClass += " gap-lg-4";
119 }
120 if (spaceBetweenColumns == "spacing-large") {
121 rowClass += " gap-lg-5";
122 }
123124 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
125126 string animationOnScrollCol1 = Model.Item.GetRawValueString("AnimationOnScrollCol1", "no-animation");
127 animationOnScrollCol1 = animationOnScrollCol1 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol1 + "'" : "";
128 string animationOnScrollCol2 = Model.Item.GetRawValueString("AnimationOnScrollCol2", "no-animation");
129 animationOnScrollCol2 = animationOnScrollCol2 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol2 + "'" : "";
130131 string hideOverflow = " overflow-hidden";
132 hideOverflow =
133 animationOnScrollCol1 != "" ||
134 animationOnScrollCol2 != ""
135 ? hideOverflow : "";
136137 Dynamicweb.Frontend.FileViewModel backgroundImage = Model.Item.GetFile("BackgroundImage");
138 string backgroundImagePath = backgroundImage?.Path ?? string.Empty;
139 backgroundImagePath = !string.IsNullOrEmpty(backgroundImagePath) ? $"/Admin/Public/GetImage.ashx?image={backgroundImagePath}&width=2600&format=webp&compression=75&quality=90" : string.Empty;
140 backgroundImagePath = Dynamicweb.Core.Encoders.HtmlEncoder.UrlPathEncode(backgroundImagePath);
141 string backgroundRepeat = Model.Item.GetRawValueString("BackgroundImageRepeat", "no-repeat");
142 string backgroundImageSize = Model.Item.GetRawValueString("BackgroundImageSize", "initial");
143 int xPos = backgroundImage?.FocalPositionFromLeft ?? 50;
144 int yPos = backgroundImage?.FocalPositionFromTop ?? 50;
145 string cssPosition = $"{xPos}% {yPos}%";
146 string gradient = Model.Item.GetRawValueString("Gradient", string.Empty);
147 string gradientOpacity = Model.Item.GetRawValueString("GradientOpacity", "0.00");
148 string gradientString = "linear-gradient(" + gradient + "deg," + "rgba(var(--swift-foreground-color-rgb)," + gradientOpacity + "), rgba(var(--swift-background-color-rgb)," + gradientOpacity + "))";
149 string backgroundImageString = "url(" + backgroundImagePath + ")";
150 string backgroundImagePositionString = "background-position:" + cssPosition + ";";
151 string backgroundRepeatString = "background-repeat:" + backgroundRepeat + ";";
152 string backgroundImageSizeString = "background-size:" + backgroundImageSize + ";";
153 string styleString = string.Empty;
154155 var decorations = Model.Item?.GetList("CssDecorations")?.GetRawValue().OfType<string>() ?? Enumerable.Empty<string>();
156 var css = string.Empty;
157 var cssClasses = new List<string> { };
158159 foreach (var itemId in decorations)
160 {
161 var item = Dynamicweb.Content.Services.Items.GetItem("Swift_Css", itemId);
162 item.TryGetValue("Class", out object classes);
163 if (classes is null)
164 {
165 continue;
166 }
167168 var cssString = (string)classes;
169 if (cssString.StartsWith("["))
170 {
171 var cssArray = Dynamicweb.Core.Converter.Deserialize<string[]>(cssString);
172 cssClasses.AddRange(cssArray);
173 }
174 else
175 {
176 cssClasses.Add(cssString.Replace(",", " "));
177 }
178 }
179 css = string.Join(" ", cssClasses).Trim();
180181 @* Only gradient *@
182183 if (!string.IsNullOrEmpty(gradient) && string.IsNullOrEmpty(backgroundImagePath) && gradientOpacity != ("0.00"))
184 {
185 styleString += "style=\"background-image:" + gradientString + ";\"";
186 }
187188 @* Only background image *@
189190 else if (string.IsNullOrEmpty(gradient) && !string.IsNullOrEmpty(backgroundImagePath))
191 {
192 styleString += "style=\"background-image:" + backgroundImageString + "; " + backgroundImagePositionString + backgroundRepeatString + backgroundImageSizeString + "\"";
193 }
194195 @* Gradient and background image *@
196197 else if (!string.IsNullOrEmpty(gradient) && !string.IsNullOrEmpty(backgroundImagePath))
198 {
199 styleString += "style=\"background-image:" + gradientString + "," + backgroundImageString + ";" + backgroundImagePositionString + backgroundRepeatString + backgroundImageSizeString + "\"";
200 }
201202 int mobileColumnSize = Dynamicweb.Core.Converter.ToInt32(Model.Item.GetRawValueString("MobileColumnBehaviour", "1"));
203 int mobileOrderFirst = Dynamicweb.Core.Converter.ToInt32(Model.Item.GetRawValueString("MobileOrderFirst", "1"));
204205 if (Pageview.IsVisualEditorMode || !string.IsNullOrWhiteSpace(Model.Column(1).Output()) || !string.IsNullOrWhiteSpace(Model.Column(2).Output()))
206 {
207 <div class="@(sectionClass)@(theme) @(css) item_@Model.Item.SystemName.ToLower()" @styleString data-swift-gridrow>
208 <div class="@containerClass@(hideOverflow)">
209 <div class="grid grid-@(mobileColumnSize) grid-lg-@Model.Columns.Count()@(rowClass)">
210 <div class="g-col @(Model.Column(1).ColumnNumber == mobileOrderFirst ? "order-first order-lg-0" : string.Empty)" data-col-size="6" @animationOnScrollCol1 style="--bs-columns:12">
211 @Model.Column(1).Output()
212 </div>
213 <div class="g-col @(Model.Column(2).ColumnNumber == mobileOrderFirst ? "order-first order-lg-0" : string.Empty)" data-col-size="6" @animationOnScrollCol2 style="--bs-columns:12">
214 @Model.Column(2).Output()
215 </div>
216 </div>
217 </div>
218 </div>
219 }
220 }
221
Error executing template "/Designs/Swift/Paragraph/Related_ProductList_Custom.cshtml"
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
at RazorEngine.Roslyn.CSharp.RoslynCompilerServiceBase.CompileType(TypeContext context)
at RazorEngine.Templating.RazorEngineCore.CreateTemplateType(ITemplateSource razorTemplate, Type modelType)
at RazorEngine.Templating.RazorEngineCore.Compile(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.GetCompiledTemplate(ITemplateKey key, Type modelType, Boolean compileOnCacheMiss)
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.Core.Encoders
3 @using Dynamicweb.Ecommerce.ProductCatalog
4 @using Dynamicweb.Environment
5 @using Dynamicweb.Frontend
6 7 @{
8 ProductViewModel dwProduct = new ProductViewModel();
9 10 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
11 {
12 dwProduct = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
13 }
14 List<RelatedGroupViewModel> dwProductRelGroups = dwProduct.RelatedGroups;
15 16 if (!dwProductRelGroups.Any())
17 {
18 return;
19 }
20 21 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", "");
22 bool anonymousUser = Pageview.User == null;
23 bool isErpConnectionDown = !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable();
24 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown;
25 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown;
26 27 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService"));
28 if (!url.Contains("LayoutTemplate"))
29 {
30 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml";
31 }
32 33 string iconPath = "/Files/icons/";
34 35 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower();
36 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat);
37 38 IEnumerable<string> selectedDisplayGroupsList = Model.Item.GetRawValueString("Fields").Split(',').ToList();
39 //Collect the titles for all available fields
40 List<string> fieldsHeaders = new List<string>();
41 Dictionary<string, List<ProductViewModel>> productLists = new Dictionary<string, List<ProductViewModel>>();
42 List<string> selectedRelGroups = Model.Item.GetRawValueString("VisibleRelatedGroups").Split(',').ToList();
43 44 45 foreach (RelatedGroupViewModel dwProductGroup in dwProductRelGroups)
46 {
47 if (!selectedRelGroups.Contains(dwProductGroup.Id))
48 {
49 continue;
50 }
51 52 productLists[dwProductGroup.Name] = new List<ProductViewModel>();
53 foreach (ProductInfoViewModel dwProductViewModelInfo in dwProductGroup.Products)
54 {
55 ProductViewModelSettings productSetting = new ProductViewModelSettings
56 {
57 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID,
58 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code,
59 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2,
60 ShopId = Pageview.Area.EcomShopId
61 };
62 63 ProductViewModel productViewModel = dwProductViewModelInfo.ProductId != "" ? ViewModelFactory.CreateView(productSetting, dwProductViewModelInfo.ProductId) : new ProductViewModel();
64 productLists[dwProductGroup.Name].Add(productViewModel);
65 }
66 }
67 68 foreach (var product in productLists.SelectMany(v => v.Value))
69 {
70 foreach (var selection in selectedDisplayGroupsList)
71 {
72 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values)
73 {
74 if (selection.ToString() == group.Id)
75 {
76 foreach (var field in group.Fields)
77 {
78 if (!fieldsHeaders.Contains(field.Value.Name))
79 {
80 bool noValues = false;
81 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) {
82 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
83 noValues = values.Count > 0 ? false : true;
84 } else if (string.IsNullOrEmpty(field.Value.Value.ToString())) {
85 noValues = true;
86 }
87 88 if (!noValues)
89 {
90 fieldsHeaders.Add(field.Value.Name);
91 }
92 }
93 }
94 }
95 }
96 }
97 }
98 99100101 int pageSizeSetting = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"]) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"].ToString()) : 10;
102 string sourceType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["SourceType"]) ? Dynamicweb.Context.Current.Request.Form["SourceType"].ToString() : "variants";
103 string requestType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["RequestType"]) ? Dynamicweb.Context.Current.Request.Form["RequestType"].ToString() : "";
104 string title = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["Title"]) ? Dynamicweb.Context.Current.Request.Form["Title"].ToString() : "";
105 string mainProductId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["MainProductID"]) ? Dynamicweb.Context.Current.Request.Form["MainProductID"].ToString() : "";
106 string paragraphID = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ParagraphID"]) ? Dynamicweb.Context.Current.Request.Form["ParagraphID"].ToString() : "";
107 string servicePageId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ID"]) ? Dynamicweb.Context.Current.Request.Form["ID"].ToString() : "";
108 bool hideTitle = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideTitle"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideTitle"].ToString()) : false;
109 bool hideImage = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideImage"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideImage"].ToString()) : false;
110 bool hideProductNumber = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideProductNumber"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideProductNumber"].ToString()) : false;
111 bool hideProductName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideProductName"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideProductName"].ToString()) : false;
112 bool hideStock = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideStock"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideStock"].ToString()) : false;
113 bool quantitySelector = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["QuantitySelector"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["QuantitySelector"].ToString()) : false;
114 string addToCartColWidth = quantitySelector ? "160" : "60";
115 bool hideFilters = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideFilters"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideFilters"].ToString()) : false;
116117 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : "";
118 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : "";
119 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : "";
120 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0;
121 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : "";
122123 var badgeParms = new Dictionary<string, object>();
124 badgeParms.Add("saleBadgeType", saleBadgeType);
125 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName);
126 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName);
127 badgeParms.Add("campaignBadgesValues", campaignBadgesValues);
128 badgeParms.Add("newPublicationDays", newPublicationDays);
129130 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false;
131 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false;
132133 string theme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["Theme"]) ? Dynamicweb.Context.Current.Request.Form["Theme"].ToString() : "";
134 string modalTheme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ModalTheme"]) ? Dynamicweb.Context.Current.Request.Form["ModalTheme"].ToString() : "theme light";
135 string titleFontSize = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["TitleFontSize"]) ? Dynamicweb.Context.Current.Request.Form["TitleFontSize"].ToString() : "";
136 string contentPadding = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ContentPadding"]) ? Dynamicweb.Context.Current.Request.Form["ContentPadding"].ToString() : "";
137138 //Create group id collection and products id collection strings
139 string groupId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["GroupId"]) ? Dynamicweb.Context.Current.Request.Form["GroupId"].ToString() : "";
140 string productIds = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["MainProductID"]) ? Dynamicweb.Context.Current.Request.Form["MainProductID"].ToString() : "";
141 string contextCart = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["OrderContext"]) ? Dynamicweb.Context.Current.Request.Form["OrderContext"].ToString() : "";
142143 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsLazyLoadingForProductInfoEnabled;
144145 string googleAnalyticsTrackingID = Pageview.AreaSettings.GetString("GoogleAnalyticsTrackingID");
146 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID");
147 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
148 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical"));
149150 if (Model.Item != null)
151 {
152 theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
153 contentPadding = Model.Item.GetRawValueString("ContentPadding", "");
154 contentPadding = contentPadding == "none" ? "p-0" : contentPadding;
155 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding;
156 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding;
157 contentPadding = contentPadding == "small-x" ? "px-2 px-md-3" : contentPadding;
158 contentPadding = contentPadding == "large-x" ? "px-4 px-md-5" : contentPadding;
159 }
160 }
161162 @if (productLists.Any()) {
163164 //The form that defines what should be rendered
165 <form action="/Default.aspx?ID=@servicePageId" id="RelatedProductsListForm_@paragraphID" data-response-target-element="RelatedProductsListFacets_@paragraphID">
166 <input type="hidden" name="SortOrder" value="DESC" />
167 <input type="hidden" name="ID" value="@servicePageId" />
168 <input type="hidden" name="SourceType" value="@sourceType" />
169 <input type="hidden" name="ParagraphID" value="@paragraphID" />
170 <input type="hidden" name="RequestType" value="UpdateFacets" id="RelatedProductsListRequestType_@paragraphID" />
171 <input type="hidden" name="PageSize" value="@pageSizeSetting" id="RelatedProductsListPageSize_@paragraphID" />
172 <input type="hidden" name="PageSizeSetting" value="@pageSizeSetting" />
173 <input type="hidden" name="Title" value="@title" />
174 <input type="hidden" name="HideTitle" value="@hideTitle.ToString()" />
175 <input type="hidden" name="SelectedDisplayGroups" value="@(string.Join(",", selectedDisplayGroupsList))" />
176 <input type="hidden" name="HideImage" value="@hideImage.ToString()" />
177 <input type="hidden" name="HideProductNumber" value="@hideProductNumber.ToString()" />
178 <input type="hidden" name="HideProductName" value="@hideProductName.ToString()" />
179 <input type="hidden" name="HideStock" value="@hideStock.ToString()" />
180 <input type="hidden" name="HideFilters" value="@hideFilters.ToString()" />
181 <input type="hidden" name="QuantitySelector" value="@quantitySelector.ToString()" />
182 <input type="hidden" name="Theme" value="@theme" />
183 <input type="hidden" name="TitleFontSize" value="@titleFontSize" />
184 <input type="hidden" name="ContentPadding" value="@contentPadding" />
185186 @if (!string.IsNullOrEmpty(contextCart))
187 {
188 <input type="hidden" name="OrderContext" value="@contextCart" />
189 <input type="hidden" name="minicartid" value="@contextCart" />
190 }
191192 @if (isLazyLoadingForProductInfoEnabled)
193 {
194 <input type="hidden" name="getproductinfo" value="true" />
195 }
196197 @*--- VARIANTS ---*@
198 @if (sourceType == "variants")
199 {
200 <input type="hidden" name="MainProductID" value="@productIds" />
201 }
202203 @*--- MOST SOLD ---*@
204 @if (sourceType == "most-sold")
205 {
206 <input type="hidden" name="SortBy" value="OrderCount" />
207 <input type="hidden" name="GroupId" value="@groupId" />
208 }
209210 @*--- TRENDING ---*@
211 @if (sourceType == "trending")
212 {
213 <input type="hidden" name="SortBy" value="OrderCountGrowth" />
214 <input type="hidden" name="GroupId" value="@groupId" />
215 }
216217 @*--- LATEST ---*@
218 @if (sourceType == "latest")
219 {
220 <input type="hidden" name="SortBy" value="Created" />
221 <input type="hidden" name="GroupId" value="@groupId" />
222 }
223224 @*--- FREQUENTLY BOUGHT ---*@
225 @if (sourceType == "frequently")
226 {
227 <input type="hidden" name="BoughtWithProductIds" value="[@productIds]" />
228 }
229230 @*--- RELATED PRODUCTS ---*@
231 @if (sourceType == "related-products")
232 {
233 <input type="hidden" name="MainProductID" value="@productIds" />
234 }
235236 @if (sourceType != "variants")
237 {
238 <input type="hidden" name="isVariant" value="false" />
239 }
240 else
241 {
242 <input type="hidden" name="isVariant" value="true" />
243 }
244245 <input type="hidden" name="SaleBadgeType" value="@saleBadgeType" />
246 <input type="hidden" name="SaleBadgeCssClassName" value="@saleBadgeCssClassName" />
247 <input type="hidden" name="NewBadgeCssClassName" value="@newBadgeCssClassName" />
248 <input type="hidden" name="NewPublicationDays" value="@newPublicationDays" />
249250 @if (campaignBadgesValues != "")
251 {
252 <input type="hidden" name="CampaignBadgesValues" value="@campaignBadgesValues" />
253 }
254 </form>
255256 if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID))
257 {
258 string itemVariant = string.Empty;
259260 <script>
261 gtag("event", "view_item_list", {
262 item_list_id: "related_product_list",
263 item_list_name: "Related products list",
264 items: [
265 @foreach (ProductViewModel product in productLists.SelectMany(v => v.Value))
266 {
267 if (!string.IsNullOrEmpty(product.VariantName))
268 {
269 itemVariant = $"item_variant:'{product.VariantName}',";
270 }
271 <text>{
272 item_id: '@product.Number',
273 item_name: '@product.Name',
274 @itemVariant
275 currency: '@product.Price.CurrencyCode',
276 price: @product.Price.Price
277 },</text>
278 }
279 ]
280 });
281 </script>
282 }
283 //The products list table
284 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "list")
285 {
286287 <div class="table-responsive w-100">
288289290291 @foreach (KeyValuePair<string, List<ProductViewModel>> productListDict in productLists)
292 {
293 <div class="h-100 mb-4 @(contentPadding) @theme">
294 <h3>@productListDict.Key</h3>
295296 <table class="table table-sm table-striped align-middle text-nowrap mobile-responsive-table">
297 <thead>
298 <tr class="fw-bold">
299 @if (!hideImage)
300 {
301 <td scope="col"> </td>
302 }
303 @if (!hideProductNumber)
304 {
305 <td scope="col" title="#">#</td>
306 }
307 @if (!hideProductName)
308 {
309 <td scope="col" title="@Translate("Product")">@Translate("Product")</td>
310 }
311 @foreach (var header in fieldsHeaders)
312 {
313 <td scope="col" title="@header">@header</td>
314 }
315 @if (!hideStock)
316 {
317 <td scope="col" title="@Translate("Stock")">@Translate("Stock")</td>
318 }
319 @if (!hidePrice)
320 {
321 <td scope="col" align="right" class="pe-2" title="@Translate("Price")">@Translate("Price")</td>
322 }
323 @if (!hideAddToCart)
324 {
325 <td scope="col" title="@Translate("Qty")">@Translate("Qty")</td>
326 }
327 </tr>
328 </thead>
329330 <tbody>
331 @foreach (var product in productListDict.Value)
332 {
333 string image = product.DefaultImage.Value;
334 string popoverImage = product.DefaultImage.Value;
335 image = $"/Admin/Public/GetImage.ashx?image={image}&width=30&format=webp";
336 popoverImage = $"/Admin/Public/GetImage.ashx?image={popoverImage}&width=350&Format=WebP&Quality=70";
337338 DateTime createdDate = product.Created.Value;
339 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false;
340 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges;
341 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges;
342343 List<CategoryFieldViewModel> categories = new List<CategoryFieldViewModel>();
344 foreach (var selection in selectedDisplayGroupsList)
345 {
346 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values)
347 {
348 if (selection.ToString() == group.Id)
349 {
350 categories.Add(group);
351 }
352 }
353 }
354355 string salesType = product?.ProductFields != null && product.ProductFields.ContainsKey("ProductERPSalesType") ? product.ProductFields["ProductERPSalesType"]?.ToString().ToLower() : null;
356357 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : "";
358 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink;
359360 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop");
361 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}";
362 link += $"&ProductID={product.Id}";
363 link += variantIdForLink;
364 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link);
365366 <tr>
367 @if (!hideImage)
368 {
369 <td width="30" scope="row" data-bs-toggle="popover" data-bs-placement="right" data-bs-content="<img src='@popoverImage' style='max-width:100%;' />" data-bs-html="true" data-bs-trigger="hover focus">
370 <img src="@image"/>
371 </td>
372 }
373 @if (!hideProductNumber)
374 {
375 <td scope="row" title="#">
376 <a href="@link">
377 @product.Number
378 </a>
379 </td>
380 }
381 @if (!hideProductName)
382 {
383 <td scope="row" title="@Translate("Product")">
384 @if (!string.IsNullOrEmpty(product.VariantName))
385 {
386 <div>@product.Name - @product.VariantName</div>
387 }
388 else
389 {
390 @product.Name
391 }
392393 @if (showBadges)
394 {
395 <div class="fs-7">
396 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms)
397 </div>
398 }
399 </td>
400 }
401 @foreach (string fieldCell in fieldsHeaders)
402 {
403 FieldValueViewModel fieldValue = new FieldValueViewModel();
404 bool fieldFound = false;
405 string fieldTitle = default(string);
406407 foreach (CategoryFieldViewModel category in categories)
408 {
409 foreach (var field in category.Fields)
410 {
411 bool noValues = false;
412 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>))
413 {
414 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
415 noValues = values.Count > 0 ? false : true;
416 }
417 else if (string.IsNullOrEmpty(field.Value.Value.ToString()))
418 {
419 noValues = true;
420 }
421422 if (!noValues)
423 {
424 string fieldName = field.Value.Name;
425 if (fieldName == fieldCell)
426 {
427 fieldValue = field.Value;
428 fieldTitle = fieldName;
429 fieldFound = true;
430 }
431 }
432 }
433 }
434435 if (fieldFound)
436 {
437 <td title="@fieldTitle">@RenderFieldValue(fieldValue)</td>
438 }
439 else
440 {
441 <td> </td>
442 }
443 }
444445 @if (!hideStock)
446 {
447 <td title="@Translate("Stock")">
448 @if (product.StockLevel > 0)
449 {
450 <span class="text-success">@Translate("In stock")</span>
451 }
452 else
453 {
454 <span class="text-danger">@Translate("Out of stock")</span>
455 }
456 </td>
457 }
458 @if (!hidePrice)
459 {
460 <td align="right" class="pe-2" title="@Translate("Price")">
461 <div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
462 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span>
463464 @if (showPricesWithVat == "false" && !neverShowVat)
465 {
466 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span>
467 if (product.Price.Price != product.PriceBeforeDiscount.Price)
468 {
469 <span class="text-decoration-line-through opacity-75 me-3">
470 @product.PriceBeforeDiscount.PriceWithoutVatFormatted
471 </span>
472 }
473 }
474 else
475 {
476 <span itemprop="price" content="@product.Price.Price" class="d-none"></span>
477 if (product.Price.Price != product.PriceBeforeDiscount.Price)
478 {
479 <span class="text-decoration-line-through opacity-75 me-3">
480 @product.PriceBeforeDiscount.PriceFormatted
481 </span>
482 }
483 }
484485 @if (showPricesWithVat == "false" && !neverShowVat)
486 {
487 <span class="text-price">@product.Price.PriceWithoutVatFormatted</span>
488 }
489 else
490 {
491 <span class="text-price">@product.Price.PriceFormatted</span>
492 }
493 </div>
494 @if (showPricesWithVat == "false" && !neverShowVat)
495 {
496 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small>
497 }
498 </td>
499 }
500 @if (!hideAddToCart)
501 {
502 bool isDiscontinued = product.Discontinued;
503 bool IsNeverOutOfStock = product.NeverOutOfstock;
504 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : "";
505 disableAddToCart = isDiscontinued ? "disabled" : disableAddToCart;
506 disableAddToCart = IsNeverOutOfStock ? "" : disableAddToCart;
507508 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\"";
509 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1";
510 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty;
511 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : "";
512513 <td width="@addToCartColWidth" style="min-width: @(addToCartColWidth)px" align="right" title="@Translate("Qty")">
514 @if (salesType =="standard") {
515 <form method="post" action="@url">
516 @if (!string.IsNullOrEmpty(contextCart))
517 {
518 <input type="hidden" name="OrderContext" value="@contextCart"/>
519 <input type="hidden" name="minicartid" value="@contextCart"/>
520 }
521 <input type="hidden" name="redirect" value="false"/>
522 <input type="hidden" name="ProductId" value="@product.Id"/>
523 <input type="hidden" name="ProductName" value="@product.Name"/>
524 <input type="hidden" name="ProductVariantName" value="@product.VariantName"/>
525 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code"/>
526 <input type="hidden" name="ProductPrice" value="@product.Price"/>
527 <input type="hidden" name="ProductReferer" value="product_list_related">
528 <input type="hidden" name="cartcmd" value="add"/>
529530 @if (!string.IsNullOrEmpty(product.VariantId))
531 {
532 <input type="hidden" name="VariantId" value="@product.VariantId"/>
533 }
534535 @if (quantitySelector)
536 {
537 <div class="flex-fill input-group input-primary-button-group d-flex flex-row">
538 <label for="Quantity_@(product.Id)_@product.VariantId" class="visually-hidden">@Translate("Quantity")</label>
539 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="0" step="@stepQty" @minQty class="form-control" style="max-width: 100px" type="number" onkeydown="swift.Cart.UpdateOnEnterKey(event)">
540 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button icon-2 @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)" style="max-width: 3rem;">@ReadFile(iconPath + "shopping-cart.svg")</button>
541 @if (stepQty != "1")
542 {
543 <div class="invalid-feedback d-none">
544 @Translate("Please select a quantity that is dividable by") @stepQty
545 </div>
546 }
547 </div>
548 }
549 else
550 {
551 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" type="hidden">
552 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart icon-2" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)" style="max-width: 3rem;">@ReadFile(iconPath + "shopping-cart.svg")</button>
553 }
554 </form>
555 }
556 else
557 {
558 <p class="small my-2"><span class="fw-bold">@Translate("Bestillingsvare")</span></p>
559 }
560 </td>
561 }
562 </tr>
563 }
564 </tbody>
565 </table>
566 </div>
567 }
568569570 </div>
571 }
572573 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "slider")
574 {
575 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script>
576 <script type="module">
577 swift.AssetLoader.Load('Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css');
578 </script>
579 <div class="h-100 grid gap-0">
580 @foreach (var productDict in productLists)
581 {
582 Guid guid = Guid.NewGuid();
583584585 <div class="g-col-12 mt-4 item_@(Model.Item.SystemName.ToLower())">
586 <h3 class="mb-4">@productDict.Key</h3>
587 <div id="Slider_@guid" class="swiffy-slider slider-item-show5 slider-nav-chevron-default slider-item-reveal slider-nav-on-slides slider-indicators-dash" style="--swiffy-slider-nav-light:var(--swift-foreground-color);--swiffy-slider-nav-dark:var(--swift-background-color);">
588 <ul class="slider-container">
589 @foreach (var product in productDict.Value)
590 {
591 @RenderProduct(product)
592 }
593 </ul>
594 <button type="button" title="@Translate("Previous slide")" class="slider-nav" style="z-index:2;">
595 <span class="visually-hidden">@Translate("Previous slide")</span>
596 </button>
597 <button type="button" title="@Translate("Next slide")" class="slider-nav slider-nav-next" style="z-index:2;">
598 <span class="visually-hidden">@Translate("Next slide")</span>
599 </button>
600601 <div class="slider-indicators" style="z-index:2;">
602 @{
603 bool isActive = true;
604 int slideCount = 1;
605 }
606607 @foreach (var item in productDict.Value)
608 {
609 <button @(isActive ? "class=\"active\"" : string.Empty) type="button" title='@Translate("Go to slide") @slideCount'>
610 <span class="visually-hidden">@Translate("Go to slide") @slideCount</span>
611 </button>
612 {
613 slideCount++;
614 }
615 isActive = false;
616 }
617 </div>
618 </div>
619620621622 <script type="module">
623 document.addEventListener('load.swift.assetloader', () => {
624 swiffyslider.initSlider(document.querySelector('#Slider_@guid'));
625 document.querySelector('#Slider_@guid').style.opacity = 1;
626 document.querySelector('#Slider_@guid').style.visibility = "visible";
627 });
628 </script>
629 </div>
630631632633 }
634 </div>
635 }
636637638 }
639640 @helper RenderProduct(ProductViewModel product) {
641 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", "");
642 bool anonymousUser = Pageview.User == null;
643 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable();
644 bool showFavoritesSelectorMasterProduct = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) : false;
645646 string ratio = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio") : "";
647 string ratioCssClass = ratio != "" ? "ratio" : "";
648 string ratioVariable = ratio != "" ? "--bs-aspect-ratio: " + ratio : "";
649650 string theme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("Theme")) ? Dynamicweb.Context.Current.Request.Form.Get("Theme") : "";
651 string themePadding = theme != string.Empty ? "p-3" : string.Empty;
652 string imageTheme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageTheme")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageTheme") : "";
653 string imageOutlineStyle = imageTheme == string.Empty ? "border: 1px solid transparent;" : string.Empty;
654 string imageThemePadding = imageTheme != string.Empty ? "p-3" : string.Empty;
655 string ContentPadding = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ContentPadding")) ? Dynamicweb.Context.Current.Request.Form.Get("ContentPadding") : "";
656657 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower();
658 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat);
659660 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : "";
661 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink;
662663 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop");
664 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}";
665 link += $"&ProductID={product.Id}";
666 link += variantIdForLink;
667 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link);
668669 string imagePath = product?.DefaultImage.Value.ToString() ?? "";
670 imagePath = "/Admin/Public/GetImage.ashx?image=" + imagePath + "&width=" + 350 + "&Format=WebP&Quality=70";
671672 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : "";
673 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : "";
674 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : "";
675 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0;
676 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : "";
677678 var badgeParms = new Dictionary<string, object>();
679 badgeParms.Add("saleBadgeType", saleBadgeType);
680 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName);
681 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName);
682 badgeParms.Add("campaignBadgesValues", campaignBadgesValues);
683 badgeParms.Add("newPublicationDays", newPublicationDays);
684685 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false;
686 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false;
687 DateTime createdDate = product.Created.Value;
688 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false;
689 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges;
690 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges;
691 <li>
692 <a href="@link" class="text-decoration-none d-block h-100">
693 <div class="h-100 d-flex flex-column justify-content-between theme theme-gray-border">
694 <div style="border: 1px solid transparent;">
695 <div class="ratio position-relative" style="--bs-aspect-ratio: 75%">
696 @if (showBadges) {
697 <div class="position-absolute top-0 left-0 p-1 p-lg-2" style="z-index: 2">
698 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms)
699 </div>
700 }
701 <img loading="lazy" decoding="async" src="@imagePath" class="h-100 w-100 " style="object-fit: contain;" alt="@product.Name">
702 </div>
703 </div>
704 <div class="flex-fill d-flex flex-column justify-content-between p-3">
705 <h3 class="h6 opacity-85">@product.Name @product.VariantName</h3>
706707 @if (!hidePrice) {
708 <div>
709710 @if( !anonymousUser) {
711 <p class="mb-0 small">@Translate("Listepris")</p>
712 }
713 <p class="h6 m-0">
714 @if (showPricesWithVat == "false" && !neverShowVat)
715 {
716 if (product.Price.Price != product.PriceBeforeDiscount.Price)
717 {
718 <span class="text-decoration-line-through opacity-75 me-1">
719 @product.PriceBeforeDiscount.PriceWithoutVatFormatted
720 </span>
721 }
722 }
723 else
724 {
725 if (product.Price.Price != product.PriceBeforeDiscount.Price)
726 {
727 <span class="text-decoration-line-through opacity-75 me-1">
728 @product.PriceBeforeDiscount.PriceFormatted
729 </span>
730 }
731 }
732733 @if (showPricesWithVat == "false" && !neverShowVat)
734 {
735 <span class="text-price fw-bold">@product.Price.PriceWithoutVatFormatted</span>
736 }
737 else
738 {
739 <span class="text-price fw-bold">@product.Price.PriceFormatted</span>
740 }
741 </p>
742 @if (showPricesWithVat == "false" && !neverShowVat)
743 {
744 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small>
745 }
746 @if( !anonymousUser) {
747 <p class="mb-0 small opacity-75">@Translate("Fragt tilføjes")</p>
748 }
749 </div>
750 }
751 </div>
752 </div>
753 </a>
754 </li>
755 }
756757758 @helper RenderFieldValue(FieldValueViewModel field) {
759 string fieldValue = field?.Value != null ? field.Value.ToString() : "";
760761 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue;
762 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue;
763764 bool isColor = false;
765766 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>))
767 {
768 int valueCount = 0;
769 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
770 int totalValues = values.Count;
771772 foreach (FieldOptionValueViewModel option in values)
773 {
774 if (option.Value.Substring(0,1) == "#") {
775 isColor = true;
776 }
777778 if (!isColor) {
779 @option.Name
780 } else {
781 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span>
782 }
783784 if (valueCount != totalValues && valueCount < (totalValues - 1)) {
785 if (isColor) {
786 <text> </text>
787 } else {
788 <text>, </text>
789 }
790 }
791 valueCount++;
792 }
793 }
794 else if (fieldValue != "")
795 {
796 if (fieldValue.Substring(0,1) == "#") {
797 isColor = true;
798 }
799800 if (!isColor) {
801 @fieldValue
802 } else {
803 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span>
804 }
805 }
806 }
807808809810 @helper RenderCheckboxOption(FacetViewModel facet, FacetOptionViewModel facetOption)
811 {
812 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label);
813 string disabled = facetOption.Count <= 0 ? "disabled" : "";
814 string selected = facetOption.Selected ? "checked" : "";
815816 if (facetLabel.ToLower() == "true")
817 {
818 facetLabel = Translate("Yes");
819 }
820821 if (facetLabel.ToLower() == "false")
822 {
823 facetLabel = Translate("No");
824 }
825826 <label class="form-check mb-1" @disabled>
827 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="form-check-input" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected>
828 <span class="form-check-label d-flex align-items-center">
829 <span class="flex-fill">@facetLabel </span>
830 <small class="opacity-85">@facetOption.Count</small>
831 </span>
832 </label>
833 }
834835 @helper RenderColorOption(FacetViewModel facet, FacetOptionViewModel facetOption)
836 {
837 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label);
838 string disabled = facetOption.Count <= 0 ? "disabled" : "";
839 string selected = facetOption.Selected ? "checked" : "";
840841 string image = facetOption.Value;
842 string colorCode = facetOption.Value;
843844 var variantOption = Dynamicweb.Ecommerce.Services.VariantOptions.GetVariantOption(facetOption.Value.ToString(), Dynamicweb.Ecommerce.Common.Context.LanguageID);
845 if (variantOption != null)
846 {
847 image = variantOption.LargeImage;
848 colorCode = variantOption.Color;
849 }
850851 <div class="colorbox">
852 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="@disabled @selected" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected title="@facetOption.Label">
853 @if (colorCode.Contains("#"))
854 {
855 <span class="colorbox-background" style="background-color: @colorCode"></span>
856 }
857 else
858 {
859 <img class="colorbox-background" src="/Admin/Public/GetImage.ashx?width=25&height=25&image=@image" />
860 }
861 </div>
862 }
863
Error executing template "/Designs/Swift/Paragraph/Related_ProductList_Custom.cshtml"
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
at RazorEngine.Roslyn.CSharp.RoslynCompilerServiceBase.CompileType(TypeContext context)
at RazorEngine.Templating.RazorEngineCore.CreateTemplateType(ITemplateSource razorTemplate, Type modelType)
at RazorEngine.Templating.RazorEngineCore.Compile(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.GetCompiledTemplate(ITemplateKey key, Type modelType, Boolean compileOnCacheMiss)
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.Core.Encoders
3 @using Dynamicweb.Ecommerce.ProductCatalog
4 @using Dynamicweb.Environment
5 @using Dynamicweb.Frontend
6 7 @{
8 ProductViewModel dwProduct = new ProductViewModel();
9 10 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
11 {
12 dwProduct = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
13 }
14 List<RelatedGroupViewModel> dwProductRelGroups = dwProduct.RelatedGroups;
15 16 if (!dwProductRelGroups.Any())
17 {
18 return;
19 }
20 21 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", "");
22 bool anonymousUser = Pageview.User == null;
23 bool isErpConnectionDown = !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable();
24 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown;
25 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown;
26 27 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService"));
28 if (!url.Contains("LayoutTemplate"))
29 {
30 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml";
31 }
32 33 string iconPath = "/Files/icons/";
34 35 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower();
36 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat);
37 38 IEnumerable<string> selectedDisplayGroupsList = Model.Item.GetRawValueString("Fields").Split(',').ToList();
39 //Collect the titles for all available fields
40 List<string> fieldsHeaders = new List<string>();
41 Dictionary<string, List<ProductViewModel>> productLists = new Dictionary<string, List<ProductViewModel>>();
42 List<string> selectedRelGroups = Model.Item.GetRawValueString("VisibleRelatedGroups").Split(',').ToList();
43 44 45 foreach (RelatedGroupViewModel dwProductGroup in dwProductRelGroups)
46 {
47 if (!selectedRelGroups.Contains(dwProductGroup.Id))
48 {
49 continue;
50 }
51 52 productLists[dwProductGroup.Name] = new List<ProductViewModel>();
53 foreach (ProductInfoViewModel dwProductViewModelInfo in dwProductGroup.Products)
54 {
55 ProductViewModelSettings productSetting = new ProductViewModelSettings
56 {
57 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID,
58 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code,
59 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2,
60 ShopId = Pageview.Area.EcomShopId
61 };
62 63 ProductViewModel productViewModel = dwProductViewModelInfo.ProductId != "" ? ViewModelFactory.CreateView(productSetting, dwProductViewModelInfo.ProductId) : new ProductViewModel();
64 productLists[dwProductGroup.Name].Add(productViewModel);
65 }
66 }
67 68 foreach (var product in productLists.SelectMany(v => v.Value))
69 {
70 foreach (var selection in selectedDisplayGroupsList)
71 {
72 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values)
73 {
74 if (selection.ToString() == group.Id)
75 {
76 foreach (var field in group.Fields)
77 {
78 if (!fieldsHeaders.Contains(field.Value.Name))
79 {
80 bool noValues = false;
81 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) {
82 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
83 noValues = values.Count > 0 ? false : true;
84 } else if (string.IsNullOrEmpty(field.Value.Value.ToString())) {
85 noValues = true;
86 }
87 88 if (!noValues)
89 {
90 fieldsHeaders.Add(field.Value.Name);
91 }
92 }
93 }
94 }
95 }
96 }
97 }
98 99100101 int pageSizeSetting = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"]) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"].ToString()) : 10;
102 string sourceType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["SourceType"]) ? Dynamicweb.Context.Current.Request.Form["SourceType"].ToString() : "variants";
103 string requestType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["RequestType"]) ? Dynamicweb.Context.Current.Request.Form["RequestType"].ToString() : "";
104 string title = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["Title"]) ? Dynamicweb.Context.Current.Request.Form["Title"].ToString() : "";
105 string mainProductId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["MainProductID"]) ? Dynamicweb.Context.Current.Request.Form["MainProductID"].ToString() : "";
106 string paragraphID = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ParagraphID"]) ? Dynamicweb.Context.Current.Request.Form["ParagraphID"].ToString() : "";
107 string servicePageId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ID"]) ? Dynamicweb.Context.Current.Request.Form["ID"].ToString() : "";
108 bool hideTitle = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideTitle"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideTitle"].ToString()) : false;
109 bool hideImage = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideImage"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideImage"].ToString()) : false;
110 bool hideProductNumber = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideProductNumber"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideProductNumber"].ToString()) : false;
111 bool hideProductName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideProductName"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideProductName"].ToString()) : false;
112 bool hideStock = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideStock"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideStock"].ToString()) : false;
113 bool quantitySelector = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["QuantitySelector"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["QuantitySelector"].ToString()) : false;
114 string addToCartColWidth = quantitySelector ? "160" : "60";
115 bool hideFilters = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideFilters"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideFilters"].ToString()) : false;
116117 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : "";
118 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : "";
119 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : "";
120 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0;
121 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : "";
122123 var badgeParms = new Dictionary<string, object>();
124 badgeParms.Add("saleBadgeType", saleBadgeType);
125 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName);
126 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName);
127 badgeParms.Add("campaignBadgesValues", campaignBadgesValues);
128 badgeParms.Add("newPublicationDays", newPublicationDays);
129130 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false;
131 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false;
132133 string theme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["Theme"]) ? Dynamicweb.Context.Current.Request.Form["Theme"].ToString() : "";
134 string modalTheme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ModalTheme"]) ? Dynamicweb.Context.Current.Request.Form["ModalTheme"].ToString() : "theme light";
135 string titleFontSize = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["TitleFontSize"]) ? Dynamicweb.Context.Current.Request.Form["TitleFontSize"].ToString() : "";
136 string contentPadding = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ContentPadding"]) ? Dynamicweb.Context.Current.Request.Form["ContentPadding"].ToString() : "";
137138 //Create group id collection and products id collection strings
139 string groupId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["GroupId"]) ? Dynamicweb.Context.Current.Request.Form["GroupId"].ToString() : "";
140 string productIds = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["MainProductID"]) ? Dynamicweb.Context.Current.Request.Form["MainProductID"].ToString() : "";
141 string contextCart = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["OrderContext"]) ? Dynamicweb.Context.Current.Request.Form["OrderContext"].ToString() : "";
142143 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsLazyLoadingForProductInfoEnabled;
144145 string googleAnalyticsTrackingID = Pageview.AreaSettings.GetString("GoogleAnalyticsTrackingID");
146 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID");
147 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
148 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical"));
149150 if (Model.Item != null)
151 {
152 theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
153 contentPadding = Model.Item.GetRawValueString("ContentPadding", "");
154 contentPadding = contentPadding == "none" ? "p-0" : contentPadding;
155 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding;
156 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding;
157 contentPadding = contentPadding == "small-x" ? "px-2 px-md-3" : contentPadding;
158 contentPadding = contentPadding == "large-x" ? "px-4 px-md-5" : contentPadding;
159 }
160 }
161162 @if (productLists.Any()) {
163164 //The form that defines what should be rendered
165 <form action="/Default.aspx?ID=@servicePageId" id="RelatedProductsListForm_@paragraphID" data-response-target-element="RelatedProductsListFacets_@paragraphID">
166 <input type="hidden" name="SortOrder" value="DESC" />
167 <input type="hidden" name="ID" value="@servicePageId" />
168 <input type="hidden" name="SourceType" value="@sourceType" />
169 <input type="hidden" name="ParagraphID" value="@paragraphID" />
170 <input type="hidden" name="RequestType" value="UpdateFacets" id="RelatedProductsListRequestType_@paragraphID" />
171 <input type="hidden" name="PageSize" value="@pageSizeSetting" id="RelatedProductsListPageSize_@paragraphID" />
172 <input type="hidden" name="PageSizeSetting" value="@pageSizeSetting" />
173 <input type="hidden" name="Title" value="@title" />
174 <input type="hidden" name="HideTitle" value="@hideTitle.ToString()" />
175 <input type="hidden" name="SelectedDisplayGroups" value="@(string.Join(",", selectedDisplayGroupsList))" />
176 <input type="hidden" name="HideImage" value="@hideImage.ToString()" />
177 <input type="hidden" name="HideProductNumber" value="@hideProductNumber.ToString()" />
178 <input type="hidden" name="HideProductName" value="@hideProductName.ToString()" />
179 <input type="hidden" name="HideStock" value="@hideStock.ToString()" />
180 <input type="hidden" name="HideFilters" value="@hideFilters.ToString()" />
181 <input type="hidden" name="QuantitySelector" value="@quantitySelector.ToString()" />
182 <input type="hidden" name="Theme" value="@theme" />
183 <input type="hidden" name="TitleFontSize" value="@titleFontSize" />
184 <input type="hidden" name="ContentPadding" value="@contentPadding" />
185186 @if (!string.IsNullOrEmpty(contextCart))
187 {
188 <input type="hidden" name="OrderContext" value="@contextCart" />
189 <input type="hidden" name="minicartid" value="@contextCart" />
190 }
191192 @if (isLazyLoadingForProductInfoEnabled)
193 {
194 <input type="hidden" name="getproductinfo" value="true" />
195 }
196197 @*--- VARIANTS ---*@
198 @if (sourceType == "variants")
199 {
200 <input type="hidden" name="MainProductID" value="@productIds" />
201 }
202203 @*--- MOST SOLD ---*@
204 @if (sourceType == "most-sold")
205 {
206 <input type="hidden" name="SortBy" value="OrderCount" />
207 <input type="hidden" name="GroupId" value="@groupId" />
208 }
209210 @*--- TRENDING ---*@
211 @if (sourceType == "trending")
212 {
213 <input type="hidden" name="SortBy" value="OrderCountGrowth" />
214 <input type="hidden" name="GroupId" value="@groupId" />
215 }
216217 @*--- LATEST ---*@
218 @if (sourceType == "latest")
219 {
220 <input type="hidden" name="SortBy" value="Created" />
221 <input type="hidden" name="GroupId" value="@groupId" />
222 }
223224 @*--- FREQUENTLY BOUGHT ---*@
225 @if (sourceType == "frequently")
226 {
227 <input type="hidden" name="BoughtWithProductIds" value="[@productIds]" />
228 }
229230 @*--- RELATED PRODUCTS ---*@
231 @if (sourceType == "related-products")
232 {
233 <input type="hidden" name="MainProductID" value="@productIds" />
234 }
235236 @if (sourceType != "variants")
237 {
238 <input type="hidden" name="isVariant" value="false" />
239 }
240 else
241 {
242 <input type="hidden" name="isVariant" value="true" />
243 }
244245 <input type="hidden" name="SaleBadgeType" value="@saleBadgeType" />
246 <input type="hidden" name="SaleBadgeCssClassName" value="@saleBadgeCssClassName" />
247 <input type="hidden" name="NewBadgeCssClassName" value="@newBadgeCssClassName" />
248 <input type="hidden" name="NewPublicationDays" value="@newPublicationDays" />
249250 @if (campaignBadgesValues != "")
251 {
252 <input type="hidden" name="CampaignBadgesValues" value="@campaignBadgesValues" />
253 }
254 </form>
255256 if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID))
257 {
258 string itemVariant = string.Empty;
259260 <script>
261 gtag("event", "view_item_list", {
262 item_list_id: "related_product_list",
263 item_list_name: "Related products list",
264 items: [
265 @foreach (ProductViewModel product in productLists.SelectMany(v => v.Value))
266 {
267 if (!string.IsNullOrEmpty(product.VariantName))
268 {
269 itemVariant = $"item_variant:'{product.VariantName}',";
270 }
271 <text>{
272 item_id: '@product.Number',
273 item_name: '@product.Name',
274 @itemVariant
275 currency: '@product.Price.CurrencyCode',
276 price: @product.Price.Price
277 },</text>
278 }
279 ]
280 });
281 </script>
282 }
283 //The products list table
284 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "list")
285 {
286287 <div class="table-responsive w-100">
288289290291 @foreach (KeyValuePair<string, List<ProductViewModel>> productListDict in productLists)
292 {
293 <div class="h-100 mb-4 @(contentPadding) @theme">
294 <h3>@productListDict.Key</h3>
295296 <table class="table table-sm table-striped align-middle text-nowrap mobile-responsive-table">
297 <thead>
298 <tr class="fw-bold">
299 @if (!hideImage)
300 {
301 <td scope="col"> </td>
302 }
303 @if (!hideProductNumber)
304 {
305 <td scope="col" title="#">#</td>
306 }
307 @if (!hideProductName)
308 {
309 <td scope="col" title="@Translate("Product")">@Translate("Product")</td>
310 }
311 @foreach (var header in fieldsHeaders)
312 {
313 <td scope="col" title="@header">@header</td>
314 }
315 @if (!hideStock)
316 {
317 <td scope="col" title="@Translate("Stock")">@Translate("Stock")</td>
318 }
319 @if (!hidePrice)
320 {
321 <td scope="col" align="right" class="pe-2" title="@Translate("Price")">@Translate("Price")</td>
322 }
323 @if (!hideAddToCart)
324 {
325 <td scope="col" title="@Translate("Qty")">@Translate("Qty")</td>
326 }
327 </tr>
328 </thead>
329330 <tbody>
331 @foreach (var product in productListDict.Value)
332 {
333 string image = product.DefaultImage.Value;
334 string popoverImage = product.DefaultImage.Value;
335 image = $"/Admin/Public/GetImage.ashx?image={image}&width=30&format=webp";
336 popoverImage = $"/Admin/Public/GetImage.ashx?image={popoverImage}&width=350&Format=WebP&Quality=70";
337338 DateTime createdDate = product.Created.Value;
339 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false;
340 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges;
341 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges;
342343 List<CategoryFieldViewModel> categories = new List<CategoryFieldViewModel>();
344 foreach (var selection in selectedDisplayGroupsList)
345 {
346 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values)
347 {
348 if (selection.ToString() == group.Id)
349 {
350 categories.Add(group);
351 }
352 }
353 }
354355 string salesType = product?.ProductFields != null && product.ProductFields.ContainsKey("ProductERPSalesType") ? product.ProductFields["ProductERPSalesType"]?.ToString().ToLower() : null;
356357 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : "";
358 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink;
359360 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop");
361 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}";
362 link += $"&ProductID={product.Id}";
363 link += variantIdForLink;
364 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link);
365366 <tr>
367 @if (!hideImage)
368 {
369 <td width="30" scope="row" data-bs-toggle="popover" data-bs-placement="right" data-bs-content="<img src='@popoverImage' style='max-width:100%;' />" data-bs-html="true" data-bs-trigger="hover focus">
370 <img src="@image"/>
371 </td>
372 }
373 @if (!hideProductNumber)
374 {
375 <td scope="row" title="#">
376 <a href="@link">
377 @product.Number
378 </a>
379 </td>
380 }
381 @if (!hideProductName)
382 {
383 <td scope="row" title="@Translate("Product")">
384 @if (!string.IsNullOrEmpty(product.VariantName))
385 {
386 <div>@product.Name - @product.VariantName</div>
387 }
388 else
389 {
390 @product.Name
391 }
392393 @if (showBadges)
394 {
395 <div class="fs-7">
396 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms)
397 </div>
398 }
399 </td>
400 }
401 @foreach (string fieldCell in fieldsHeaders)
402 {
403 FieldValueViewModel fieldValue = new FieldValueViewModel();
404 bool fieldFound = false;
405 string fieldTitle = default(string);
406407 foreach (CategoryFieldViewModel category in categories)
408 {
409 foreach (var field in category.Fields)
410 {
411 bool noValues = false;
412 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>))
413 {
414 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
415 noValues = values.Count > 0 ? false : true;
416 }
417 else if (string.IsNullOrEmpty(field.Value.Value.ToString()))
418 {
419 noValues = true;
420 }
421422 if (!noValues)
423 {
424 string fieldName = field.Value.Name;
425 if (fieldName == fieldCell)
426 {
427 fieldValue = field.Value;
428 fieldTitle = fieldName;
429 fieldFound = true;
430 }
431 }
432 }
433 }
434435 if (fieldFound)
436 {
437 <td title="@fieldTitle">@RenderFieldValue(fieldValue)</td>
438 }
439 else
440 {
441 <td> </td>
442 }
443 }
444445 @if (!hideStock)
446 {
447 <td title="@Translate("Stock")">
448 @if (product.StockLevel > 0)
449 {
450 <span class="text-success">@Translate("In stock")</span>
451 }
452 else
453 {
454 <span class="text-danger">@Translate("Out of stock")</span>
455 }
456 </td>
457 }
458 @if (!hidePrice)
459 {
460 <td align="right" class="pe-2" title="@Translate("Price")">
461 <div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
462 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span>
463464 @if (showPricesWithVat == "false" && !neverShowVat)
465 {
466 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span>
467 if (product.Price.Price != product.PriceBeforeDiscount.Price)
468 {
469 <span class="text-decoration-line-through opacity-75 me-3">
470 @product.PriceBeforeDiscount.PriceWithoutVatFormatted
471 </span>
472 }
473 }
474 else
475 {
476 <span itemprop="price" content="@product.Price.Price" class="d-none"></span>
477 if (product.Price.Price != product.PriceBeforeDiscount.Price)
478 {
479 <span class="text-decoration-line-through opacity-75 me-3">
480 @product.PriceBeforeDiscount.PriceFormatted
481 </span>
482 }
483 }
484485 @if (showPricesWithVat == "false" && !neverShowVat)
486 {
487 <span class="text-price">@product.Price.PriceWithoutVatFormatted</span>
488 }
489 else
490 {
491 <span class="text-price">@product.Price.PriceFormatted</span>
492 }
493 </div>
494 @if (showPricesWithVat == "false" && !neverShowVat)
495 {
496 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small>
497 }
498 </td>
499 }
500 @if (!hideAddToCart)
501 {
502 bool isDiscontinued = product.Discontinued;
503 bool IsNeverOutOfStock = product.NeverOutOfstock;
504 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : "";
505 disableAddToCart = isDiscontinued ? "disabled" : disableAddToCart;
506 disableAddToCart = IsNeverOutOfStock ? "" : disableAddToCart;
507508 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\"";
509 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1";
510 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty;
511 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : "";
512513 <td width="@addToCartColWidth" style="min-width: @(addToCartColWidth)px" align="right" title="@Translate("Qty")">
514 @if (salesType =="standard") {
515 <form method="post" action="@url">
516 @if (!string.IsNullOrEmpty(contextCart))
517 {
518 <input type="hidden" name="OrderContext" value="@contextCart"/>
519 <input type="hidden" name="minicartid" value="@contextCart"/>
520 }
521 <input type="hidden" name="redirect" value="false"/>
522 <input type="hidden" name="ProductId" value="@product.Id"/>
523 <input type="hidden" name="ProductName" value="@product.Name"/>
524 <input type="hidden" name="ProductVariantName" value="@product.VariantName"/>
525 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code"/>
526 <input type="hidden" name="ProductPrice" value="@product.Price"/>
527 <input type="hidden" name="ProductReferer" value="product_list_related">
528 <input type="hidden" name="cartcmd" value="add"/>
529530 @if (!string.IsNullOrEmpty(product.VariantId))
531 {
532 <input type="hidden" name="VariantId" value="@product.VariantId"/>
533 }
534535 @if (quantitySelector)
536 {
537 <div class="flex-fill input-group input-primary-button-group d-flex flex-row">
538 <label for="Quantity_@(product.Id)_@product.VariantId" class="visually-hidden">@Translate("Quantity")</label>
539 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="0" step="@stepQty" @minQty class="form-control" style="max-width: 100px" type="number" onkeydown="swift.Cart.UpdateOnEnterKey(event)">
540 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button icon-2 @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)" style="max-width: 3rem;">@ReadFile(iconPath + "shopping-cart.svg")</button>
541 @if (stepQty != "1")
542 {
543 <div class="invalid-feedback d-none">
544 @Translate("Please select a quantity that is dividable by") @stepQty
545 </div>
546 }
547 </div>
548 }
549 else
550 {
551 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" type="hidden">
552 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart icon-2" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)" style="max-width: 3rem;">@ReadFile(iconPath + "shopping-cart.svg")</button>
553 }
554 </form>
555 }
556 else
557 {
558 <p class="small my-2"><span class="fw-bold">@Translate("Bestillingsvare")</span></p>
559 }
560 </td>
561 }
562 </tr>
563 }
564 </tbody>
565 </table>
566 </div>
567 }
568569570 </div>
571 }
572573 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "slider")
574 {
575 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script>
576 <script type="module">
577 swift.AssetLoader.Load('Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css');
578 </script>
579 <div class="h-100 grid gap-0">
580 @foreach (var productDict in productLists)
581 {
582 Guid guid = Guid.NewGuid();
583584585 <div class="g-col-12 mt-4 item_@(Model.Item.SystemName.ToLower())">
586 <h3 class="mb-4">@productDict.Key</h3>
587 <div id="Slider_@guid" class="swiffy-slider slider-item-show5 slider-nav-chevron-default slider-item-reveal slider-nav-on-slides slider-indicators-dash" style="--swiffy-slider-nav-light:var(--swift-foreground-color);--swiffy-slider-nav-dark:var(--swift-background-color);">
588 <ul class="slider-container">
589 @foreach (var product in productDict.Value)
590 {
591 @RenderProduct(product)
592 }
593 </ul>
594 <button type="button" title="@Translate("Previous slide")" class="slider-nav" style="z-index:2;">
595 <span class="visually-hidden">@Translate("Previous slide")</span>
596 </button>
597 <button type="button" title="@Translate("Next slide")" class="slider-nav slider-nav-next" style="z-index:2;">
598 <span class="visually-hidden">@Translate("Next slide")</span>
599 </button>
600601 <div class="slider-indicators" style="z-index:2;">
602 @{
603 bool isActive = true;
604 int slideCount = 1;
605 }
606607 @foreach (var item in productDict.Value)
608 {
609 <button @(isActive ? "class=\"active\"" : string.Empty) type="button" title='@Translate("Go to slide") @slideCount'>
610 <span class="visually-hidden">@Translate("Go to slide") @slideCount</span>
611 </button>
612 {
613 slideCount++;
614 }
615 isActive = false;
616 }
617 </div>
618 </div>
619620621622 <script type="module">
623 document.addEventListener('load.swift.assetloader', () => {
624 swiffyslider.initSlider(document.querySelector('#Slider_@guid'));
625 document.querySelector('#Slider_@guid').style.opacity = 1;
626 document.querySelector('#Slider_@guid').style.visibility = "visible";
627 });
628 </script>
629 </div>
630631632633 }
634 </div>
635 }
636637638 }
639640 @helper RenderProduct(ProductViewModel product) {
641 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", "");
642 bool anonymousUser = Pageview.User == null;
643 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable();
644 bool showFavoritesSelectorMasterProduct = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) : false;
645646 string ratio = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio") : "";
647 string ratioCssClass = ratio != "" ? "ratio" : "";
648 string ratioVariable = ratio != "" ? "--bs-aspect-ratio: " + ratio : "";
649650 string theme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("Theme")) ? Dynamicweb.Context.Current.Request.Form.Get("Theme") : "";
651 string themePadding = theme != string.Empty ? "p-3" : string.Empty;
652 string imageTheme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageTheme")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageTheme") : "";
653 string imageOutlineStyle = imageTheme == string.Empty ? "border: 1px solid transparent;" : string.Empty;
654 string imageThemePadding = imageTheme != string.Empty ? "p-3" : string.Empty;
655 string ContentPadding = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ContentPadding")) ? Dynamicweb.Context.Current.Request.Form.Get("ContentPadding") : "";
656657 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower();
658 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat);
659660 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : "";
661 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink;
662663 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop");
664 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}";
665 link += $"&ProductID={product.Id}";
666 link += variantIdForLink;
667 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link);
668669 string imagePath = product?.DefaultImage.Value.ToString() ?? "";
670 imagePath = "/Admin/Public/GetImage.ashx?image=" + imagePath + "&width=" + 350 + "&Format=WebP&Quality=70";
671672 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : "";
673 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : "";
674 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : "";
675 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0;
676 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : "";
677678 var badgeParms = new Dictionary<string, object>();
679 badgeParms.Add("saleBadgeType", saleBadgeType);
680 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName);
681 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName);
682 badgeParms.Add("campaignBadgesValues", campaignBadgesValues);
683 badgeParms.Add("newPublicationDays", newPublicationDays);
684685 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false;
686 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false;
687 DateTime createdDate = product.Created.Value;
688 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false;
689 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges;
690 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges;
691 <li>
692 <a href="@link" class="text-decoration-none d-block h-100">
693 <div class="h-100 d-flex flex-column justify-content-between theme theme-gray-border">
694 <div style="border: 1px solid transparent;">
695 <div class="ratio position-relative" style="--bs-aspect-ratio: 75%">
696 @if (showBadges) {
697 <div class="position-absolute top-0 left-0 p-1 p-lg-2" style="z-index: 2">
698 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms)
699 </div>
700 }
701 <img loading="lazy" decoding="async" src="@imagePath" class="h-100 w-100 " style="object-fit: contain;" alt="@product.Name">
702 </div>
703 </div>
704 <div class="flex-fill d-flex flex-column justify-content-between p-3">
705 <h3 class="h6 opacity-85">@product.Name @product.VariantName</h3>
706707 @if (!hidePrice) {
708 <div>
709710 @if( !anonymousUser) {
711 <p class="mb-0 small">@Translate("Listepris")</p>
712 }
713 <p class="h6 m-0">
714 @if (showPricesWithVat == "false" && !neverShowVat)
715 {
716 if (product.Price.Price != product.PriceBeforeDiscount.Price)
717 {
718 <span class="text-decoration-line-through opacity-75 me-1">
719 @product.PriceBeforeDiscount.PriceWithoutVatFormatted
720 </span>
721 }
722 }
723 else
724 {
725 if (product.Price.Price != product.PriceBeforeDiscount.Price)
726 {
727 <span class="text-decoration-line-through opacity-75 me-1">
728 @product.PriceBeforeDiscount.PriceFormatted
729 </span>
730 }
731 }
732733 @if (showPricesWithVat == "false" && !neverShowVat)
734 {
735 <span class="text-price fw-bold">@product.Price.PriceWithoutVatFormatted</span>
736 }
737 else
738 {
739 <span class="text-price fw-bold">@product.Price.PriceFormatted</span>
740 }
741 </p>
742 @if (showPricesWithVat == "false" && !neverShowVat)
743 {
744 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small>
745 }
746 @if( !anonymousUser) {
747 <p class="mb-0 small opacity-75">@Translate("Fragt tilføjes")</p>
748 }
749 </div>
750 }
751 </div>
752 </div>
753 </a>
754 </li>
755 }
756757758 @helper RenderFieldValue(FieldValueViewModel field) {
759 string fieldValue = field?.Value != null ? field.Value.ToString() : "";
760761 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue;
762 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue;
763764 bool isColor = false;
765766 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>))
767 {
768 int valueCount = 0;
769 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
770 int totalValues = values.Count;
771772 foreach (FieldOptionValueViewModel option in values)
773 {
774 if (option.Value.Substring(0,1) == "#") {
775 isColor = true;
776 }
777778 if (!isColor) {
779 @option.Name
780 } else {
781 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span>
782 }
783784 if (valueCount != totalValues && valueCount < (totalValues - 1)) {
785 if (isColor) {
786 <text> </text>
787 } else {
788 <text>, </text>
789 }
790 }
791 valueCount++;
792 }
793 }
794 else if (fieldValue != "")
795 {
796 if (fieldValue.Substring(0,1) == "#") {
797 isColor = true;
798 }
799800 if (!isColor) {
801 @fieldValue
802 } else {
803 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span>
804 }
805 }
806 }
807808809810 @helper RenderCheckboxOption(FacetViewModel facet, FacetOptionViewModel facetOption)
811 {
812 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label);
813 string disabled = facetOption.Count <= 0 ? "disabled" : "";
814 string selected = facetOption.Selected ? "checked" : "";
815816 if (facetLabel.ToLower() == "true")
817 {
818 facetLabel = Translate("Yes");
819 }
820821 if (facetLabel.ToLower() == "false")
822 {
823 facetLabel = Translate("No");
824 }
825826 <label class="form-check mb-1" @disabled>
827 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="form-check-input" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected>
828 <span class="form-check-label d-flex align-items-center">
829 <span class="flex-fill">@facetLabel </span>
830 <small class="opacity-85">@facetOption.Count</small>
831 </span>
832 </label>
833 }
834835 @helper RenderColorOption(FacetViewModel facet, FacetOptionViewModel facetOption)
836 {
837 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label);
838 string disabled = facetOption.Count <= 0 ? "disabled" : "";
839 string selected = facetOption.Selected ? "checked" : "";
840841 string image = facetOption.Value;
842 string colorCode = facetOption.Value;
843844 var variantOption = Dynamicweb.Ecommerce.Services.VariantOptions.GetVariantOption(facetOption.Value.ToString(), Dynamicweb.Ecommerce.Common.Context.LanguageID);
845 if (variantOption != null)
846 {
847 image = variantOption.LargeImage;
848 colorCode = variantOption.Color;
849 }
850851 <div class="colorbox">
852 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="@disabled @selected" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected title="@facetOption.Label">
853 @if (colorCode.Contains("#"))
854 {
855 <span class="colorbox-background" style="background-color: @colorCode"></span>
856 }
857 else
858 {
859 <img class="colorbox-background" src="/Admin/Public/GetImage.ashx?width=25&height=25&image=@image" />
860 }
861 </div>
862 }
863
Error executing template "/Designs/Swift/Grid/Page/RowTemplates/3Columns.cshtml"
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
at RazorEngine.Roslyn.CSharp.RoslynCompilerServiceBase.CompileType(TypeContext context)
at RazorEngine.Templating.RazorEngineCore.CreateTemplateType(ITemplateSource razorTemplate, Type modelType)
at RazorEngine.Templating.RazorEngineCore.Compile(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.GetCompiledTemplate(ITemplateKey key, Type modelType, Boolean compileOnCacheMiss)
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.GridRowViewModel>
2 @using Dynamicweb.Content.Items
3 4 @{
5 string sectionClass = "py-3";
6 string spaceBetweenRows = Model.Item.GetRawValueString("SpaceBetweenRows", "spacing");
7 string spaceBetweenRowsMobile = Model.Item.GetRawValueString("SpaceBetweenRowsMobile", "auto");
8 9 //Row spacing mobile auto
10 if (spaceBetweenRowsMobile == "auto") {
11 spaceBetweenRowsMobile = spaceBetweenRows;
12 }
13 14 //Row spacing mobile
15 switch (spaceBetweenRowsMobile) {
16 case "none": //No spacing
17 sectionClass = "py-0";
18 break;
19 case "spacing": //Small spacing top and bottom
20 sectionClass = "py-3";
21 break;
22 case "spacing-small-top": //Small spacing top
23 sectionClass = "pt-3";
24 break;
25 case "spacing-small-bottom": //Small spacing bottom
26 sectionClass = "pb-3";
27 break;
28 case "spacing-medium": //Medium spacing top and bottom
29 sectionClass = "py-4";
30 break;
31 case "spacing-medium-top": //Medium spacing top
32 sectionClass = "pt-4";
33 break;
34 case "spacing-medium-bottom": //Medium spacing bottom
35 sectionClass = "pb-4";
36 break;
37 case "spacing-large": //Large spacing top and bottom
38 sectionClass = "py-5";
39 break;
40 case "spacing-top": //Large spacing top
41 sectionClass = "pt-5";
42 break;
43 case "spacing-bottom": //Large spacing bottom
44 sectionClass = "pb-5";
45 break;
46 }
47 48 //Row spacing dekstop
49 switch (spaceBetweenRows) {
50 case "none": //No spacing
51 sectionClass += " py-lg-0";
52 break;
53 case "spacing": //Small spacing top and bottom
54 sectionClass += " py-lg-3";
55 break;
56 case "spacing-small-top": //Small spacing top
57 sectionClass += " pt-lg-3 pb-lg-0";
58 break;
59 case "spacing-small-bottom": //Small spacing bottom
60 sectionClass += " pb-lg-3 pt-lg-0";
61 break;
62 case "spacing-medium": //Medium spacing top and bottom
63 sectionClass += " py-lg-5";
64 break;
65 case "spacing-medium-top": //Medium spacing top
66 sectionClass += " pt-lg-5 pb-lg-0";
67 break;
68 case "spacing-medium-bottom": //Medium spacing bottom
69 sectionClass += " pb-lg-5 pt-lg-0";
70 break;
71 case "spacing-large": //Large spacing top and bottom
72 sectionClass += " py-lg-6";
73 break;
74 case "spacing-top": //Large spacing top
75 sectionClass += " pt-lg-6 pb-lg-0";
76 break;
77 case "spacing-bottom": //Large spacing bottom
78 sectionClass += " pb-lg-6 pt-lg-0";
79 break;
80 }
81 82 string width = Model.Item.GetRawValueString("Width", "").ToLower();
83 string containerClass = "container-xl";
84 if (width == "stretch")
85 {
86 containerClass = "container-fluid";
87 }
88 if (width == "none")
89 {
90 containerClass = "container-fluid px-0";
91 }
92 if (width == "compressed")
93 {
94 containerClass = " container-compressed";
95 }
96 97 string rowClass = string.Empty;
98 string spaceBetweenColumns = Model.Item.GetRawValueString("SpaceBetweenColumns", string.Empty).ToLower();
99 string spaceBetweenColumnsMobile = Model.Item.GetRawValueString("SpaceBetweenColumnsMobile", string.Empty).ToLower();
100 //Mobile
101 if (spaceBetweenColumnsMobile == "auto")
102 {
103 spaceBetweenColumnsMobile = spaceBetweenColumns;
104 }
105 if (spaceBetweenColumnsMobile == "stick") {
106 rowClass = " gap-0";
107 }
108 if (spaceBetweenColumnsMobile == "spacing-medium")
109 {
110 rowClass = " gap-4";
111 }
112 if (spaceBetweenColumnsMobile == "spacing-large") {
113 rowClass = " gap-5";
114 }
115 //Desktop
116 if (spaceBetweenColumns == "stick") {
117 rowClass += " gap-lg-0";
118 }
119 if (spaceBetweenColumns == "spacing-medium")
120 {
121 rowClass += " gap-lg-4";
122 }
123 if (spaceBetweenColumns == "spacing-large") {
124 rowClass += " gap-lg-5";
125 }
126127 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
128129 string animationOnScrollCol1 = Model.Item.GetRawValueString("AnimationOnScrollCol1", "no-animation");
130 animationOnScrollCol1 = animationOnScrollCol1 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol1 + "'" : "";
131 string animationOnScrollCol2 = Model.Item.GetRawValueString("AnimationOnScrollCol2", "no-animation");
132 animationOnScrollCol2 = animationOnScrollCol2 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol2 + "'" : "";
133 string animationOnScrollCol3 = Model.Item.GetRawValueString("AnimationOnScrollCol3", "no-animation");
134 animationOnScrollCol3 = animationOnScrollCol3 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol3 + "'" : "";
135136 string hideOverflow = " overflow-hidden";
137 hideOverflow =
138 animationOnScrollCol1 != "" ||
139 animationOnScrollCol2 != "" ||
140 animationOnScrollCol3 != ""
141 ? hideOverflow : "";
142143 Dynamicweb.Frontend.FileViewModel backgroundImage = Model.Item.GetFile("BackgroundImage");
144 string backgroundImagePath = backgroundImage?.Path ?? string.Empty;
145 backgroundImagePath = !string.IsNullOrEmpty(backgroundImagePath) ? $"/Admin/Public/GetImage.ashx?image={backgroundImagePath}&width=2600&format=webp&compression=75&quality=90" : string.Empty;
146 backgroundImagePath = Dynamicweb.Core.Encoders.HtmlEncoder.UrlPathEncode(backgroundImagePath);
147 string backgroundRepeat = Model.Item.GetRawValueString("BackgroundImageRepeat", "no-repeat");
148 string backgroundImageSize = Model.Item.GetRawValueString("BackgroundImageSize", "initial");
149 int xPos = backgroundImage?.FocalPositionFromLeft ?? 50;
150 int yPos = backgroundImage?.FocalPositionFromTop ?? 50;
151 string cssPosition = $"{xPos}% {yPos}%";
152 string gradient = Model.Item.GetRawValueString("Gradient", string.Empty);
153 string gradientOpacity = Model.Item.GetRawValueString("GradientOpacity", "0.00");
154 string gradientString = "linear-gradient(" + gradient + "deg," + "rgba(var(--swift-foreground-color-rgb)," + gradientOpacity + "), rgba(var(--swift-background-color-rgb)," + gradientOpacity + "))";
155 string backgroundImageString = "url(" + backgroundImagePath + ")";
156 string backgroundImagePositionString = "background-position:" + cssPosition + ";";
157 string backgroundRepeatString = "background-repeat:" + backgroundRepeat + ";";
158 string backgroundImageSizeString = "background-size:" + backgroundImageSize + ";";
159 string styleString = string.Empty;
160161 var decorations = Model.Item?.GetList("CssDecorations")?.GetRawValue().OfType<string>() ?? Enumerable.Empty<string>();
162 var css = string.Empty;
163 var cssClasses = new List<string> { };
164165 foreach (var itemId in decorations)
166 {
167 var item = Dynamicweb.Content.Services.Items.GetItem("Swift_Css", itemId);
168 item.TryGetValue("Class", out object classes);
169 if (classes is null)
170 {
171 continue;
172 }
173174 var cssString = (string)classes;
175 if (cssString.StartsWith("["))
176 {
177 var cssArray = Dynamicweb.Core.Converter.Deserialize<string[]>(cssString);
178 cssClasses.AddRange(cssArray);
179 }
180 else
181 {
182 cssClasses.Add(cssString.Replace(",", " "));
183 }
184 }
185 css = string.Join(" ", cssClasses).Trim();
186187 @* Only gradient *@
188189 if (!string.IsNullOrEmpty(gradient) && string.IsNullOrEmpty(backgroundImagePath) && gradientOpacity != ("0.00"))
190 {
191 styleString += "style=\"background-image:" + gradientString + ";\"";
192 }
193194 @* Only background image *@
195196 else if (string.IsNullOrEmpty(gradient) && !string.IsNullOrEmpty(backgroundImagePath))
197 {
198 styleString += "style=\"background-image:" + backgroundImageString + "; " + backgroundImagePositionString + backgroundRepeatString + backgroundImageSizeString + "\"";
199 }
200201 @* Gradient and background image *@
202203 else if (!string.IsNullOrEmpty(gradient) && !string.IsNullOrEmpty(backgroundImagePath))
204 {
205 styleString += "style=\"background-image:" + gradientString + "," + backgroundImageString + ";" + backgroundImagePositionString + backgroundRepeatString + backgroundImageSizeString + "\"";
206 }
207208 int mobileColumnSize = Dynamicweb.Core.Converter.ToInt32(Model.Item.GetRawValueString("MobileColumnBehaviour", "1"));
209 int mobileOrderFirst = Dynamicweb.Core.Converter.ToInt32(Model.Item.GetRawValueString("MobileOrderFirst", "1"));
210211 if (Pageview.IsVisualEditorMode || !string.IsNullOrWhiteSpace(Model.Column(1).Output()) || !string.IsNullOrWhiteSpace(Model.Column(2).Output()) || !string.IsNullOrWhiteSpace(Model.Column(3).Output()))
212 {
213 <div class="@(sectionClass)@(theme) @(css) item_@Model.Item.SystemName.ToLower()" @styleString data-swift-gridrow>
214 <div class="@containerClass@(hideOverflow)">
215 <div class="grid grid-@(mobileColumnSize) grid-lg-@Model.Columns.Count()@(rowClass)">
216 <div class="g-col @(Model.Column(1).ColumnNumber == mobileOrderFirst ? "order-first order-lg-0" : string.Empty)" data-col-size="4" @animationOnScrollCol1 style="--bs-columns:12">
217 @Model.Column(1).Output()
218 </div>
219 <div class="g-col @(Model.Column(2).ColumnNumber == mobileOrderFirst ? "order-first order-lg-0" : string.Empty)" data-col-size="4" @animationOnScrollCol2 style="--bs-columns:12">
220 @Model.Column(2).Output()
221 </div>
222 <div class="g-col @(Model.Column(3).ColumnNumber == mobileOrderFirst ? "order-first order-lg-0" : string.Empty)" data-col-size="4" @animationOnScrollCol3 style="--bs-columns:12">
223 @Model.Column(3).Output()
224 </div>
225 </div>
226 </div>
227 </div>
228 }
229 }
230
Error executing template "/Designs/Swift/Grid/Page/RowTemplates/ProductDetailsAccordion.cshtml"
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
at RazorEngine.Roslyn.CSharp.RoslynCompilerServiceBase.CompileType(TypeContext context)
at RazorEngine.Templating.RazorEngineCore.CreateTemplateType(ITemplateSource razorTemplate, Type modelType)
at RazorEngine.Templating.RazorEngineCore.Compile(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.GetCompiledTemplate(ITemplateKey key, Type modelType, Boolean compileOnCacheMiss)
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.GridRowViewModel>
2 @functions {
3 public bool IsUnstyledMode()
4 {
5 return Dynamicweb.Context.Current.Items.Contains("ProductDetailsAccordionUnstyled") &&
6 Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["ProductDetailsAccordionUnstyled"]);
7 }
8 9 public int GetCurrentUnstyledColumnIndex()
10 {
11 if (!Dynamicweb.Context.Current.Items.Contains("ProductDetailsAccordionUnstyledColumnIndex"))
12 {
13 return 0;
14 }
15 16 return Dynamicweb.Core.Converter.ToInt32(Dynamicweb.Context.Current.Items["ProductDetailsAccordionUnstyledColumnIndex"]);
17 }
18 19 public string GetTitleKeyForColumn(int columnIndex)
20 {
21 return $"ProductDetailsAccordionUnstyledTitle_{columnIndex}";
22 }
23 24 public void BeginUnstyledColumnScope(int columnIndex)
25 {
26 string titleKey = GetTitleKeyForColumn(columnIndex);
27 Dynamicweb.Context.Current.Items["ProductDetailsAccordionUnstyled"] = true;
28 Dynamicweb.Context.Current.Items["ProductDetailsAccordionUnstyledColumnIndex"] = columnIndex;
29 Dynamicweb.Context.Current.Items.Remove(titleKey);
30 }
31 32 public void EndUnstyledColumnScope(int columnIndex)
33 {
34 string titleKey = GetTitleKeyForColumn(columnIndex);
35 Dynamicweb.Context.Current.Items.Remove("ProductDetailsAccordionUnstyled");
36 Dynamicweb.Context.Current.Items.Remove("ProductDetailsAccordionUnstyledColumnIndex");
37 Dynamicweb.Context.Current.Items.Remove(titleKey);
38 }
39 40 public void SetTitleForCurrentColumn(string title)
41 {
42 if (!IsUnstyledMode() || string.IsNullOrWhiteSpace(title))
43 {
44 return;
45 }
46 47 int columnIndex = GetCurrentUnstyledColumnIndex();
48 if (columnIndex <= 0)
49 {
50 return;
51 }
52 53 string titleKey = GetTitleKeyForColumn(columnIndex);
54 if (!Dynamicweb.Context.Current.Items.Contains(titleKey) || string.IsNullOrWhiteSpace(Dynamicweb.Core.Converter.ToString(Dynamicweb.Context.Current.Items[titleKey])))
55 {
56 Dynamicweb.Context.Current.Items[titleKey] = title;
57 }
58 }
59 60 public string GetTitleForColumn(int columnIndex)
61 {
62 string titleKey = GetTitleKeyForColumn(columnIndex);
63 return Dynamicweb.Context.Current.Items.Contains(titleKey)
64 ? Dynamicweb.Core.Converter.ToString(Dynamicweb.Context.Current.Items[titleKey])
65 : string.Empty;
66 }
67 }
68 69 70 @{
71 string sectionClass = "py-3";
72 string spaceBetweenRows = Model.Item.GetRawValueString("SpaceBetweenRows", "spacing");
73 string spaceBetweenRowsMobile = Model.Item.GetRawValueString("SpaceBetweenRowsMobile", "auto");
74 75 //Row spacing mobile auto
76 if (spaceBetweenRowsMobile == "auto") {
77 spaceBetweenRowsMobile = spaceBetweenRows;
78 }
79 80 //Row spacing mobile
81 switch (spaceBetweenRowsMobile) {
82 case "none": //No spacing
83 sectionClass = "py-0";
84 break;
85 case "spacing": //Small spacing top and bottom
86 sectionClass = "py-3";
87 break;
88 case "spacing-small-top": //Small spacing top
89 sectionClass = "pt-3";
90 break;
91 case "spacing-small-bottom": //Small spacing bottom
92 sectionClass = "pb-3";
93 break;
94 case "spacing-medium": //Medium spacing top and bottom
95 sectionClass = "py-4";
96 break;
97 case "spacing-medium-top": //Medium spacing top
98 sectionClass = "pt-4";
99 break;
100 case "spacing-medium-bottom": //Medium spacing bottom
101 sectionClass = "pb-4";
102 break;
103 case "spacing-large": //Large spacing top and bottom
104 sectionClass = "py-5";
105 break;
106 case "spacing-top": //Large spacing top
107 sectionClass = "pt-5";
108 break;
109 case "spacing-bottom": //Large spacing bottom
110 sectionClass = "pb-5";
111 break;
112 }
113114 //Row spacing dekstop
115 switch (spaceBetweenRows) {
116 case "none": //No spacing
117 sectionClass += " py-lg-0";
118 break;
119 case "spacing": //Small spacing top and bottom
120 sectionClass += " py-lg-3";
121 break;
122 case "spacing-small-top": //Small spacing top
123 sectionClass += " pt-lg-3 pb-lg-0";
124 break;
125 case "spacing-small-bottom": //Small spacing bottom
126 sectionClass += " pb-lg-3 pt-lg-0";
127 break;
128 case "spacing-medium": //Medium spacing top and bottom
129 sectionClass += " py-lg-5";
130 break;
131 case "spacing-medium-top": //Medium spacing top
132 sectionClass += " pt-lg-5 pb-lg-0";
133 break;
134 case "spacing-medium-bottom": //Medium spacing bottom
135 sectionClass += " pb-lg-5 pt-lg-0";
136 break;
137 case "spacing-large": //Large spacing top and bottom
138 sectionClass += " py-lg-6";
139 break;
140 case "spacing-top": //Large spacing top
141 sectionClass += " pt-lg-6 pb-lg-0";
142 break;
143 case "spacing-bottom": //Large spacing bottom
144 sectionClass += " pb-lg-6 pt-lg-0";
145 break;
146 }
147148 string width = Model.Item.GetRawValueString("Width");
149 string containerClass = "container-xl";
150 if (width == "stretch")
151 {
152 containerClass = "container-fluid";
153 }
154 if (width == "none")
155 {
156 containerClass = "container-fluid px-0";
157 }
158 if (width == "compressed")
159 {
160 containerClass = " container-compressed";
161 }
162163 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
164165 string animationOnScrollCol1 = Model.Item.GetRawValueString("AnimationOnScrollCol1", Model.Item.GetRawValueString("AnimationOnScroll", "no-animation"));
166 animationOnScrollCol1 = animationOnScrollCol1 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol1 + "'" : "";
167 string animationOnScrollCol2 = Model.Item.GetRawValueString("AnimationOnScrollCol2", "no-animation");
168 animationOnScrollCol2 = animationOnScrollCol2 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol2 + "'" : "";
169 string animationOnScrollCol3 = Model.Item.GetRawValueString("AnimationOnScrollCol3", "no-animation");
170 animationOnScrollCol3 = animationOnScrollCol3 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol3 + "'" : "";
171 string animationOnScrollCol4 = Model.Item.GetRawValueString("AnimationOnScrollCol4", "no-animation");
172 animationOnScrollCol4 = animationOnScrollCol4 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol4 + "'" : "";
173 string animationOnScrollCol5 = Model.Item.GetRawValueString("AnimationOnScrollCol5", "no-animation");
174 animationOnScrollCol5 = animationOnScrollCol5 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol5 + "'" : "";
175 string animationOnScrollCol6 = Model.Item.GetRawValueString("AnimationOnScrollCol6", "no-animation");
176 animationOnScrollCol6 = animationOnScrollCol6 != "no-animation" ? "data-aos=" + "'" + animationOnScrollCol6 + "'" : "";
177178 string hideOverflow = " overflow-hidden";
179 hideOverflow =
180 animationOnScrollCol1 != "" ||
181 animationOnScrollCol2 != "" ||
182 animationOnScrollCol3 != "" ||
183 animationOnScrollCol4 != "" ||
184 animationOnScrollCol5 != "" ||
185 animationOnScrollCol6 != ""
186 ? hideOverflow : "";
187188 Dynamicweb.Frontend.FileViewModel backgroundImage = Model.Item.GetFile("BackgroundImage");
189 string backgroundImagePath = backgroundImage?.Path ?? string.Empty;
190 backgroundImagePath = !string.IsNullOrEmpty(backgroundImagePath) ? $"/Admin/Public/GetImage.ashx?image={backgroundImagePath}&width=2600&format=webp&compression=75&quality=90" : string.Empty;
191 backgroundImagePath = Dynamicweb.Core.Encoders.HtmlEncoder.UrlPathEncode(backgroundImagePath);
192 string backgroundRepeat = Model.Item.GetRawValueString("BackgroundImageRepeat", "no-repeat");
193 string backgroundImageSize = Model.Item.GetRawValueString("BackgroundImageSize", "initial");
194 int xPos = backgroundImage?.FocalPositionFromLeft ?? 50;
195 int yPos = backgroundImage?.FocalPositionFromTop ?? 50;
196 string cssPosition = $"{xPos}% {yPos}%";
197 string gradient = Model.Item.GetRawValueString("Gradient", string.Empty);
198 string gradientOpacity = Model.Item.GetRawValueString("GradientOpacity", "0.00");
199 string gradientString = "linear-gradient(" + gradient + "deg," + "rgba(var(--swift-foreground-color-rgb)," + gradientOpacity + "), rgba(var(--swift-background-color-rgb)," + gradientOpacity + "))";
200 string backgroundImageString = "url(" + backgroundImagePath + ")";
201 string backgroundImagePositionString = "background-position:" + cssPosition + ";";
202 string backgroundRepeatString = "background-repeat:" + backgroundRepeat + ";";
203 string backgroundImageSizeString = "background-size:" + backgroundImageSize + ";";
204 string styleString = string.Empty;
205206 var decorations = Model.Item?.GetList("CssDecorations")?.GetRawValue().OfType<string>() ?? Enumerable.Empty<string>();
207 var css = string.Empty;
208 var cssClasses = new List<string> { };
209210 foreach (var itemId in decorations)
211 {
212 var item = Dynamicweb.Content.Services.Items.GetItem("Swift_Css", itemId);
213 item.TryGetValue("Class", out object classes);
214 if (classes is null)
215 {
216 continue;
217 }
218219 var cssString = (string)classes;
220 if (cssString.StartsWith("["))
221 {
222 var cssArray = Dynamicweb.Core.Converter.Deserialize<string[]>(cssString);
223 cssClasses.AddRange(cssArray);
224 }
225 else
226 {
227 cssClasses.Add(cssString.Replace(",", " "));
228 }
229 }
230 css = string.Join(" ", cssClasses).Trim();
231232 @* Only gradient *@
233234 if (!string.IsNullOrEmpty(gradient) && string.IsNullOrEmpty(backgroundImagePath) && gradientOpacity != ("0.00"))
235 {
236 styleString += "style=\"background-image:" + gradientString + ";\"";
237 }
238239 @* Only background image *@
240241 else if (string.IsNullOrEmpty(gradient) && !string.IsNullOrEmpty(backgroundImagePath))
242 {
243 styleString += "style=\"background-image:" + backgroundImageString + "; " + backgroundImagePositionString + backgroundRepeatString + backgroundImageSizeString + "\"";
244 }
245246 @* Gradient and background image *@
247248 else if (!string.IsNullOrEmpty(gradient) && !string.IsNullOrEmpty(backgroundImagePath))
249 {
250 styleString += "style=\"background-image:" + gradientString + "," + backgroundImageString + ";" + backgroundImagePositionString + backgroundRepeatString + backgroundImageSizeString + "\"";
251 }
252253 Func<int, Tuple<object, string>> getUnstyledColumnOutput = columnIndex =>
254 {
255 BeginUnstyledColumnScope(columnIndex);
256 try
257 {
258 var output = Model.Column(columnIndex).Output();
259 string title = GetTitleForColumn(columnIndex);
260 return Tuple.Create((object)output, title);
261 }
262 finally
263 {
264 EndUnstyledColumnScope(columnIndex);
265 }
266 };
267268 Func<object, bool> hasMeaningfulContent = output =>
269 {
270 string outputHtml = Dynamicweb.Core.Converter.ToString(output);
271 if (string.IsNullOrWhiteSpace(outputHtml))
272 {
273 return false;
274 }
275276 string withoutComments = System.Text.RegularExpressions.Regex.Replace(outputHtml, "<!--.*?-->", string.Empty, System.Text.RegularExpressions.RegexOptions.Singleline);
277 bool containsMedia = System.Text.RegularExpressions.Regex.IsMatch(withoutComments, "<(img|video|iframe|svg|object|embed|canvas)\\b", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
278 if (containsMedia)
279 {
280 return true;
281 }
282283 string withoutTags = System.Text.RegularExpressions.Regex.Replace(withoutComments, "<[^>]+>", " ");
284 string decodedText = System.Net.WebUtility.HtmlDecode(withoutTags ?? string.Empty);
285 string normalizedText = System.Text.RegularExpressions.Regex.Replace(decodedText, "\\s+", " ").Trim();
286 return !string.IsNullOrWhiteSpace(normalizedText);
287 };
288289 var column1 = getUnstyledColumnOutput(1);
290 var column2 = getUnstyledColumnOutput(2);
291 var column3 = getUnstyledColumnOutput(3);
292 var column4 = getUnstyledColumnOutput(4);
293 var column5 = getUnstyledColumnOutput(5);
294 var column6 = getUnstyledColumnOutput(6);
295296 var columns = new[]
297 {
298 new { Index = 1, Output = column1.Item1, Title = column1.Item2, HasContent = hasMeaningfulContent(column1.Item1), AnimationOnScroll = animationOnScrollCol1 },
299 new { Index = 2, Output = column2.Item1, Title = column2.Item2, HasContent = hasMeaningfulContent(column2.Item1), AnimationOnScroll = animationOnScrollCol2 },
300 new { Index = 3, Output = column3.Item1, Title = column3.Item2, HasContent = hasMeaningfulContent(column3.Item1), AnimationOnScroll = animationOnScrollCol3 },
301 new { Index = 4, Output = column4.Item1, Title = column4.Item2, HasContent = hasMeaningfulContent(column4.Item1), AnimationOnScroll = animationOnScrollCol4 },
302 new { Index = 5, Output = column5.Item1, Title = column5.Item2, HasContent = hasMeaningfulContent(column5.Item1), AnimationOnScroll = animationOnScrollCol5 },
303 new { Index = 6, Output = column6.Item1, Title = column6.Item2, HasContent = hasMeaningfulContent(column6.Item1), AnimationOnScroll = animationOnScrollCol6 }
304 };
305 var hasAnyColumnContent = columns.Any(column => column.HasContent);
306 var accordionId = $"product-details-accordion-{Guid.NewGuid():N}";
307308 if (Pageview.IsVisualEditorMode || hasAnyColumnContent)
309 {
310 <div class="@(sectionClass)@(theme) @(css) item_@Model.Item.SystemName.ToLower()" @styleString data-swift-gridrow>
311 <div class="@containerClass@(hideOverflow)">
312 <div class="accordion" id="@accordionId">
313 @foreach (var column in columns)
314 {
315 var hasColumnContent = column.HasContent;
316 if (Pageview.IsVisualEditorMode || hasColumnContent)
317 {
318 var isExpanded = Pageview.IsVisualEditorMode;
319 var headingId = $"{accordionId}-heading-{column.Index}";
320 var collapseId = $"{accordionId}-collapse-{column.Index}";
321 string manualTitle = Model.Item.GetString($"AccordionTitleCol{column.Index}");
322 var accordionTitle = !string.IsNullOrWhiteSpace(manualTitle) ? manualTitle
323 : !string.IsNullOrWhiteSpace(column.Title) ? column.Title
324 : $"Section {column.Index}";
325 <div class="accordion-item">
326 <h3 class="accordion-header" id="@headingId">
327 <button class="accordion-button@(isExpanded ? "" : " collapsed")" type="button" data-bs-toggle="collapse" data-bs-target="#@collapseId" aria-expanded="@(isExpanded ? "true" : "false")" aria-controls="@collapseId">
328 <span class="py-2 fs-5">@accordionTitle</span>
329 </button>
330 </h3>
331 <div id="@collapseId" class="accordion-collapse collapse@(isExpanded ? " show" : "")" aria-labelledby="@headingId">
332 <div class="accordion-body">
333 <div class="g-col" data-col-size="12" @column.AnimationOnScroll style="--bs-columns:12">
334 @column.Output
335 </div>
336 </div>
337 </div>
338 </div>
339 }
340 }
341 </div>
342 </div>
343 </div>
344 }
345 }
346
Error executing template "/Designs/Swift/Paragraph/Related_ProductList_Custom.cshtml"
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
at System.IO.FileStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)
at RazorEngine.Roslyn.CSharp.RoslynCompilerServiceBase.CompileType(TypeContext context)
at RazorEngine.Templating.RazorEngineCore.CreateTemplateType(ITemplateSource razorTemplate, Type modelType)
at RazorEngine.Templating.RazorEngineCore.Compile(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.CompileAndCacheInternal(ITemplateKey key, Type modelType)
at RazorEngine.Templating.RazorEngineService.GetCompiledTemplate(ITemplateKey key, Type modelType, Boolean compileOnCacheMiss)
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.Core.Encoders
3 @using Dynamicweb.Ecommerce.ProductCatalog
4 @using Dynamicweb.Environment
5 @using Dynamicweb.Frontend
6 7 @{
8 ProductViewModel dwProduct = new ProductViewModel();
9 10 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
11 {
12 dwProduct = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
13 }
14 List<RelatedGroupViewModel> dwProductRelGroups = dwProduct.RelatedGroups;
15 16 if (!dwProductRelGroups.Any())
17 {
18 return;
19 }
20 21 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", "");
22 bool anonymousUser = Pageview.User == null;
23 bool isErpConnectionDown = !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable();
24 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown;
25 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown;
26 27 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService"));
28 if (!url.Contains("LayoutTemplate"))
29 {
30 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml";
31 }
32 33 string iconPath = "/Files/icons/";
34 35 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower();
36 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat);
37 38 IEnumerable<string> selectedDisplayGroupsList = Model.Item.GetRawValueString("Fields").Split(',').ToList();
39 //Collect the titles for all available fields
40 List<string> fieldsHeaders = new List<string>();
41 Dictionary<string, List<ProductViewModel>> productLists = new Dictionary<string, List<ProductViewModel>>();
42 List<string> selectedRelGroups = Model.Item.GetRawValueString("VisibleRelatedGroups").Split(',').ToList();
43 44 45 foreach (RelatedGroupViewModel dwProductGroup in dwProductRelGroups)
46 {
47 if (!selectedRelGroups.Contains(dwProductGroup.Id))
48 {
49 continue;
50 }
51 52 productLists[dwProductGroup.Name] = new List<ProductViewModel>();
53 foreach (ProductInfoViewModel dwProductViewModelInfo in dwProductGroup.Products)
54 {
55 ProductViewModelSettings productSetting = new ProductViewModelSettings
56 {
57 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID,
58 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code,
59 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2,
60 ShopId = Pageview.Area.EcomShopId
61 };
62 63 ProductViewModel productViewModel = dwProductViewModelInfo.ProductId != "" ? ViewModelFactory.CreateView(productSetting, dwProductViewModelInfo.ProductId) : new ProductViewModel();
64 productLists[dwProductGroup.Name].Add(productViewModel);
65 }
66 }
67 68 foreach (var product in productLists.SelectMany(v => v.Value))
69 {
70 foreach (var selection in selectedDisplayGroupsList)
71 {
72 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values)
73 {
74 if (selection.ToString() == group.Id)
75 {
76 foreach (var field in group.Fields)
77 {
78 if (!fieldsHeaders.Contains(field.Value.Name))
79 {
80 bool noValues = false;
81 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) {
82 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
83 noValues = values.Count > 0 ? false : true;
84 } else if (string.IsNullOrEmpty(field.Value.Value.ToString())) {
85 noValues = true;
86 }
87 88 if (!noValues)
89 {
90 fieldsHeaders.Add(field.Value.Name);
91 }
92 }
93 }
94 }
95 }
96 }
97 }
98 99100101 int pageSizeSetting = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"]) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"].ToString()) : 10;
102 string sourceType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["SourceType"]) ? Dynamicweb.Context.Current.Request.Form["SourceType"].ToString() : "variants";
103 string requestType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["RequestType"]) ? Dynamicweb.Context.Current.Request.Form["RequestType"].ToString() : "";
104 string title = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["Title"]) ? Dynamicweb.Context.Current.Request.Form["Title"].ToString() : "";
105 string mainProductId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["MainProductID"]) ? Dynamicweb.Context.Current.Request.Form["MainProductID"].ToString() : "";
106 string paragraphID = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ParagraphID"]) ? Dynamicweb.Context.Current.Request.Form["ParagraphID"].ToString() : "";
107 string servicePageId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ID"]) ? Dynamicweb.Context.Current.Request.Form["ID"].ToString() : "";
108 bool hideTitle = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideTitle"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideTitle"].ToString()) : false;
109 bool hideImage = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideImage"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideImage"].ToString()) : false;
110 bool hideProductNumber = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideProductNumber"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideProductNumber"].ToString()) : false;
111 bool hideProductName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideProductName"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideProductName"].ToString()) : false;
112 bool hideStock = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideStock"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideStock"].ToString()) : false;
113 bool quantitySelector = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["QuantitySelector"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["QuantitySelector"].ToString()) : false;
114 string addToCartColWidth = quantitySelector ? "160" : "60";
115 bool hideFilters = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["HideFilters"]) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form["HideFilters"].ToString()) : false;
116117 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : "";
118 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : "";
119 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : "";
120 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0;
121 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : "";
122123 var badgeParms = new Dictionary<string, object>();
124 badgeParms.Add("saleBadgeType", saleBadgeType);
125 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName);
126 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName);
127 badgeParms.Add("campaignBadgesValues", campaignBadgesValues);
128 badgeParms.Add("newPublicationDays", newPublicationDays);
129130 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false;
131 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false;
132133 string theme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["Theme"]) ? Dynamicweb.Context.Current.Request.Form["Theme"].ToString() : "";
134 string modalTheme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ModalTheme"]) ? Dynamicweb.Context.Current.Request.Form["ModalTheme"].ToString() : "theme light";
135 string titleFontSize = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["TitleFontSize"]) ? Dynamicweb.Context.Current.Request.Form["TitleFontSize"].ToString() : "";
136 string contentPadding = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ContentPadding"]) ? Dynamicweb.Context.Current.Request.Form["ContentPadding"].ToString() : "";
137138 //Create group id collection and products id collection strings
139 string groupId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["GroupId"]) ? Dynamicweb.Context.Current.Request.Form["GroupId"].ToString() : "";
140 string productIds = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["MainProductID"]) ? Dynamicweb.Context.Current.Request.Form["MainProductID"].ToString() : "";
141 string contextCart = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["OrderContext"]) ? Dynamicweb.Context.Current.Request.Form["OrderContext"].ToString() : "";
142143 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsLazyLoadingForProductInfoEnabled;
144145 string googleAnalyticsTrackingID = Pageview.AreaSettings.GetString("GoogleAnalyticsTrackingID");
146 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID");
147 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
148 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical"));
149150 if (Model.Item != null)
151 {
152 theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
153 contentPadding = Model.Item.GetRawValueString("ContentPadding", "");
154 contentPadding = contentPadding == "none" ? "p-0" : contentPadding;
155 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding;
156 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding;
157 contentPadding = contentPadding == "small-x" ? "px-2 px-md-3" : contentPadding;
158 contentPadding = contentPadding == "large-x" ? "px-4 px-md-5" : contentPadding;
159 }
160 }
161162 @if (productLists.Any()) {
163164 //The form that defines what should be rendered
165 <form action="/Default.aspx?ID=@servicePageId" id="RelatedProductsListForm_@paragraphID" data-response-target-element="RelatedProductsListFacets_@paragraphID">
166 <input type="hidden" name="SortOrder" value="DESC" />
167 <input type="hidden" name="ID" value="@servicePageId" />
168 <input type="hidden" name="SourceType" value="@sourceType" />
169 <input type="hidden" name="ParagraphID" value="@paragraphID" />
170 <input type="hidden" name="RequestType" value="UpdateFacets" id="RelatedProductsListRequestType_@paragraphID" />
171 <input type="hidden" name="PageSize" value="@pageSizeSetting" id="RelatedProductsListPageSize_@paragraphID" />
172 <input type="hidden" name="PageSizeSetting" value="@pageSizeSetting" />
173 <input type="hidden" name="Title" value="@title" />
174 <input type="hidden" name="HideTitle" value="@hideTitle.ToString()" />
175 <input type="hidden" name="SelectedDisplayGroups" value="@(string.Join(",", selectedDisplayGroupsList))" />
176 <input type="hidden" name="HideImage" value="@hideImage.ToString()" />
177 <input type="hidden" name="HideProductNumber" value="@hideProductNumber.ToString()" />
178 <input type="hidden" name="HideProductName" value="@hideProductName.ToString()" />
179 <input type="hidden" name="HideStock" value="@hideStock.ToString()" />
180 <input type="hidden" name="HideFilters" value="@hideFilters.ToString()" />
181 <input type="hidden" name="QuantitySelector" value="@quantitySelector.ToString()" />
182 <input type="hidden" name="Theme" value="@theme" />
183 <input type="hidden" name="TitleFontSize" value="@titleFontSize" />
184 <input type="hidden" name="ContentPadding" value="@contentPadding" />
185186 @if (!string.IsNullOrEmpty(contextCart))
187 {
188 <input type="hidden" name="OrderContext" value="@contextCart" />
189 <input type="hidden" name="minicartid" value="@contextCart" />
190 }
191192 @if (isLazyLoadingForProductInfoEnabled)
193 {
194 <input type="hidden" name="getproductinfo" value="true" />
195 }
196197 @*--- VARIANTS ---*@
198 @if (sourceType == "variants")
199 {
200 <input type="hidden" name="MainProductID" value="@productIds" />
201 }
202203 @*--- MOST SOLD ---*@
204 @if (sourceType == "most-sold")
205 {
206 <input type="hidden" name="SortBy" value="OrderCount" />
207 <input type="hidden" name="GroupId" value="@groupId" />
208 }
209210 @*--- TRENDING ---*@
211 @if (sourceType == "trending")
212 {
213 <input type="hidden" name="SortBy" value="OrderCountGrowth" />
214 <input type="hidden" name="GroupId" value="@groupId" />
215 }
216217 @*--- LATEST ---*@
218 @if (sourceType == "latest")
219 {
220 <input type="hidden" name="SortBy" value="Created" />
221 <input type="hidden" name="GroupId" value="@groupId" />
222 }
223224 @*--- FREQUENTLY BOUGHT ---*@
225 @if (sourceType == "frequently")
226 {
227 <input type="hidden" name="BoughtWithProductIds" value="[@productIds]" />
228 }
229230 @*--- RELATED PRODUCTS ---*@
231 @if (sourceType == "related-products")
232 {
233 <input type="hidden" name="MainProductID" value="@productIds" />
234 }
235236 @if (sourceType != "variants")
237 {
238 <input type="hidden" name="isVariant" value="false" />
239 }
240 else
241 {
242 <input type="hidden" name="isVariant" value="true" />
243 }
244245 <input type="hidden" name="SaleBadgeType" value="@saleBadgeType" />
246 <input type="hidden" name="SaleBadgeCssClassName" value="@saleBadgeCssClassName" />
247 <input type="hidden" name="NewBadgeCssClassName" value="@newBadgeCssClassName" />
248 <input type="hidden" name="NewPublicationDays" value="@newPublicationDays" />
249250 @if (campaignBadgesValues != "")
251 {
252 <input type="hidden" name="CampaignBadgesValues" value="@campaignBadgesValues" />
253 }
254 </form>
255256 if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID))
257 {
258 string itemVariant = string.Empty;
259260 <script>
261 gtag("event", "view_item_list", {
262 item_list_id: "related_product_list",
263 item_list_name: "Related products list",
264 items: [
265 @foreach (ProductViewModel product in productLists.SelectMany(v => v.Value))
266 {
267 if (!string.IsNullOrEmpty(product.VariantName))
268 {
269 itemVariant = $"item_variant:'{product.VariantName}',";
270 }
271 <text>{
272 item_id: '@product.Number',
273 item_name: '@product.Name',
274 @itemVariant
275 currency: '@product.Price.CurrencyCode',
276 price: @product.Price.Price
277 },</text>
278 }
279 ]
280 });
281 </script>
282 }
283 //The products list table
284 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "list")
285 {
286287 <div class="table-responsive w-100">
288289290291 @foreach (KeyValuePair<string, List<ProductViewModel>> productListDict in productLists)
292 {
293 <div class="h-100 mb-4 @(contentPadding) @theme">
294 <h3>@productListDict.Key</h3>
295296 <table class="table table-sm table-striped align-middle text-nowrap mobile-responsive-table">
297 <thead>
298 <tr class="fw-bold">
299 @if (!hideImage)
300 {
301 <td scope="col"> </td>
302 }
303 @if (!hideProductNumber)
304 {
305 <td scope="col" title="#">#</td>
306 }
307 @if (!hideProductName)
308 {
309 <td scope="col" title="@Translate("Product")">@Translate("Product")</td>
310 }
311 @foreach (var header in fieldsHeaders)
312 {
313 <td scope="col" title="@header">@header</td>
314 }
315 @if (!hideStock)
316 {
317 <td scope="col" title="@Translate("Stock")">@Translate("Stock")</td>
318 }
319 @if (!hidePrice)
320 {
321 <td scope="col" align="right" class="pe-2" title="@Translate("Price")">@Translate("Price")</td>
322 }
323 @if (!hideAddToCart)
324 {
325 <td scope="col" title="@Translate("Qty")">@Translate("Qty")</td>
326 }
327 </tr>
328 </thead>
329330 <tbody>
331 @foreach (var product in productListDict.Value)
332 {
333 string image = product.DefaultImage.Value;
334 string popoverImage = product.DefaultImage.Value;
335 image = $"/Admin/Public/GetImage.ashx?image={image}&width=30&format=webp";
336 popoverImage = $"/Admin/Public/GetImage.ashx?image={popoverImage}&width=350&Format=WebP&Quality=70";
337338 DateTime createdDate = product.Created.Value;
339 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false;
340 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges;
341 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges;
342343 List<CategoryFieldViewModel> categories = new List<CategoryFieldViewModel>();
344 foreach (var selection in selectedDisplayGroupsList)
345 {
346 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values)
347 {
348 if (selection.ToString() == group.Id)
349 {
350 categories.Add(group);
351 }
352 }
353 }
354355 string salesType = product?.ProductFields != null && product.ProductFields.ContainsKey("ProductERPSalesType") ? product.ProductFields["ProductERPSalesType"]?.ToString().ToLower() : null;
356357 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : "";
358 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink;
359360 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop");
361 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}";
362 link += $"&ProductID={product.Id}";
363 link += variantIdForLink;
364 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link);
365366 <tr>
367 @if (!hideImage)
368 {
369 <td width="30" scope="row" data-bs-toggle="popover" data-bs-placement="right" data-bs-content="<img src='@popoverImage' style='max-width:100%;' />" data-bs-html="true" data-bs-trigger="hover focus">
370 <img src="@image"/>
371 </td>
372 }
373 @if (!hideProductNumber)
374 {
375 <td scope="row" title="#">
376 <a href="@link">
377 @product.Number
378 </a>
379 </td>
380 }
381 @if (!hideProductName)
382 {
383 <td scope="row" title="@Translate("Product")">
384 @if (!string.IsNullOrEmpty(product.VariantName))
385 {
386 <div>@product.Name - @product.VariantName</div>
387 }
388 else
389 {
390 @product.Name
391 }
392393 @if (showBadges)
394 {
395 <div class="fs-7">
396 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms)
397 </div>
398 }
399 </td>
400 }
401 @foreach (string fieldCell in fieldsHeaders)
402 {
403 FieldValueViewModel fieldValue = new FieldValueViewModel();
404 bool fieldFound = false;
405 string fieldTitle = default(string);
406407 foreach (CategoryFieldViewModel category in categories)
408 {
409 foreach (var field in category.Fields)
410 {
411 bool noValues = false;
412 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>))
413 {
414 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
415 noValues = values.Count > 0 ? false : true;
416 }
417 else if (string.IsNullOrEmpty(field.Value.Value.ToString()))
418 {
419 noValues = true;
420 }
421422 if (!noValues)
423 {
424 string fieldName = field.Value.Name;
425 if (fieldName == fieldCell)
426 {
427 fieldValue = field.Value;
428 fieldTitle = fieldName;
429 fieldFound = true;
430 }
431 }
432 }
433 }
434435 if (fieldFound)
436 {
437 <td title="@fieldTitle">@RenderFieldValue(fieldValue)</td>
438 }
439 else
440 {
441 <td> </td>
442 }
443 }
444445 @if (!hideStock)
446 {
447 <td title="@Translate("Stock")">
448 @if (product.StockLevel > 0)
449 {
450 <span class="text-success">@Translate("In stock")</span>
451 }
452 else
453 {
454 <span class="text-danger">@Translate("Out of stock")</span>
455 }
456 </td>
457 }
458 @if (!hidePrice)
459 {
460 <td align="right" class="pe-2" title="@Translate("Price")">
461 <div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
462 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span>
463464 @if (showPricesWithVat == "false" && !neverShowVat)
465 {
466 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span>
467 if (product.Price.Price != product.PriceBeforeDiscount.Price)
468 {
469 <span class="text-decoration-line-through opacity-75 me-3">
470 @product.PriceBeforeDiscount.PriceWithoutVatFormatted
471 </span>
472 }
473 }
474 else
475 {
476 <span itemprop="price" content="@product.Price.Price" class="d-none"></span>
477 if (product.Price.Price != product.PriceBeforeDiscount.Price)
478 {
479 <span class="text-decoration-line-through opacity-75 me-3">
480 @product.PriceBeforeDiscount.PriceFormatted
481 </span>
482 }
483 }
484485 @if (showPricesWithVat == "false" && !neverShowVat)
486 {
487 <span class="text-price">@product.Price.PriceWithoutVatFormatted</span>
488 }
489 else
490 {
491 <span class="text-price">@product.Price.PriceFormatted</span>
492 }
493 </div>
494 @if (showPricesWithVat == "false" && !neverShowVat)
495 {
496 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small>
497 }
498 </td>
499 }
500 @if (!hideAddToCart)
501 {
502 bool isDiscontinued = product.Discontinued;
503 bool IsNeverOutOfStock = product.NeverOutOfstock;
504 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : "";
505 disableAddToCart = isDiscontinued ? "disabled" : disableAddToCart;
506 disableAddToCart = IsNeverOutOfStock ? "" : disableAddToCart;
507508 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\"";
509 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1";
510 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty;
511 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : "";
512513 <td width="@addToCartColWidth" style="min-width: @(addToCartColWidth)px" align="right" title="@Translate("Qty")">
514 @if (salesType =="standard") {
515 <form method="post" action="@url">
516 @if (!string.IsNullOrEmpty(contextCart))
517 {
518 <input type="hidden" name="OrderContext" value="@contextCart"/>
519 <input type="hidden" name="minicartid" value="@contextCart"/>
520 }
521 <input type="hidden" name="redirect" value="false"/>
522 <input type="hidden" name="ProductId" value="@product.Id"/>
523 <input type="hidden" name="ProductName" value="@product.Name"/>
524 <input type="hidden" name="ProductVariantName" value="@product.VariantName"/>
525 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code"/>
526 <input type="hidden" name="ProductPrice" value="@product.Price"/>
527 <input type="hidden" name="ProductReferer" value="product_list_related">
528 <input type="hidden" name="cartcmd" value="add"/>
529530 @if (!string.IsNullOrEmpty(product.VariantId))
531 {
532 <input type="hidden" name="VariantId" value="@product.VariantId"/>
533 }
534535 @if (quantitySelector)
536 {
537 <div class="flex-fill input-group input-primary-button-group d-flex flex-row">
538 <label for="Quantity_@(product.Id)_@product.VariantId" class="visually-hidden">@Translate("Quantity")</label>
539 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="0" step="@stepQty" @minQty class="form-control" style="max-width: 100px" type="number" onkeydown="swift.Cart.UpdateOnEnterKey(event)">
540 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button icon-2 @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)" style="max-width: 3rem;">@ReadFile(iconPath + "shopping-cart.svg")</button>
541 @if (stepQty != "1")
542 {
543 <div class="invalid-feedback d-none">
544 @Translate("Please select a quantity that is dividable by") @stepQty
545 </div>
546 }
547 </div>
548 }
549 else
550 {
551 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" type="hidden">
552 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart icon-2" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)" style="max-width: 3rem;">@ReadFile(iconPath + "shopping-cart.svg")</button>
553 }
554 </form>
555 }
556 else
557 {
558 <p class="small my-2"><span class="fw-bold">@Translate("Bestillingsvare")</span></p>
559 }
560 </td>
561 }
562 </tr>
563 }
564 </tbody>
565 </table>
566 </div>
567 }
568569570 </div>
571 }
572573 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "slider")
574 {
575 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script>
576 <script type="module">
577 swift.AssetLoader.Load('Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css');
578 </script>
579 <div class="h-100 grid gap-0">
580 @foreach (var productDict in productLists)
581 {
582 Guid guid = Guid.NewGuid();
583584585 <div class="g-col-12 mt-4 item_@(Model.Item.SystemName.ToLower())">
586 <h3 class="mb-4">@productDict.Key</h3>
587 <div id="Slider_@guid" class="swiffy-slider slider-item-show5 slider-nav-chevron-default slider-item-reveal slider-nav-on-slides slider-indicators-dash" style="--swiffy-slider-nav-light:var(--swift-foreground-color);--swiffy-slider-nav-dark:var(--swift-background-color);">
588 <ul class="slider-container">
589 @foreach (var product in productDict.Value)
590 {
591 @RenderProduct(product)
592 }
593 </ul>
594 <button type="button" title="@Translate("Previous slide")" class="slider-nav" style="z-index:2;">
595 <span class="visually-hidden">@Translate("Previous slide")</span>
596 </button>
597 <button type="button" title="@Translate("Next slide")" class="slider-nav slider-nav-next" style="z-index:2;">
598 <span class="visually-hidden">@Translate("Next slide")</span>
599 </button>
600601 <div class="slider-indicators" style="z-index:2;">
602 @{
603 bool isActive = true;
604 int slideCount = 1;
605 }
606607 @foreach (var item in productDict.Value)
608 {
609 <button @(isActive ? "class=\"active\"" : string.Empty) type="button" title='@Translate("Go to slide") @slideCount'>
610 <span class="visually-hidden">@Translate("Go to slide") @slideCount</span>
611 </button>
612 {
613 slideCount++;
614 }
615 isActive = false;
616 }
617 </div>
618 </div>
619620621622 <script type="module">
623 document.addEventListener('load.swift.assetloader', () => {
624 swiffyslider.initSlider(document.querySelector('#Slider_@guid'));
625 document.querySelector('#Slider_@guid').style.opacity = 1;
626 document.querySelector('#Slider_@guid').style.visibility = "visible";
627 });
628 </script>
629 </div>
630631632633 }
634 </div>
635 }
636637638 }
639640 @helper RenderProduct(ProductViewModel product) {
641 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", "");
642 bool anonymousUser = Pageview.User == null;
643 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable();
644 bool showFavoritesSelectorMasterProduct = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) : false;
645646 string ratio = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio") : "";
647 string ratioCssClass = ratio != "" ? "ratio" : "";
648 string ratioVariable = ratio != "" ? "--bs-aspect-ratio: " + ratio : "";
649650 string theme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("Theme")) ? Dynamicweb.Context.Current.Request.Form.Get("Theme") : "";
651 string themePadding = theme != string.Empty ? "p-3" : string.Empty;
652 string imageTheme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageTheme")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageTheme") : "";
653 string imageOutlineStyle = imageTheme == string.Empty ? "border: 1px solid transparent;" : string.Empty;
654 string imageThemePadding = imageTheme != string.Empty ? "p-3" : string.Empty;
655 string ContentPadding = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ContentPadding")) ? Dynamicweb.Context.Current.Request.Form.Get("ContentPadding") : "";
656657 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower();
658 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat);
659660 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : "";
661 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink;
662663 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop");
664 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}";
665 link += $"&ProductID={product.Id}";
666 link += variantIdForLink;
667 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link);
668669 string imagePath = product?.DefaultImage.Value.ToString() ?? "";
670 imagePath = "/Admin/Public/GetImage.ashx?image=" + imagePath + "&width=" + 350 + "&Format=WebP&Quality=70";
671672 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : "";
673 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : "";
674 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : "";
675 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0;
676 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : "";
677678 var badgeParms = new Dictionary<string, object>();
679 badgeParms.Add("saleBadgeType", saleBadgeType);
680 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName);
681 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName);
682 badgeParms.Add("campaignBadgesValues", campaignBadgesValues);
683 badgeParms.Add("newPublicationDays", newPublicationDays);
684685 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false;
686 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false;
687 DateTime createdDate = product.Created.Value;
688 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false;
689 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges;
690 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges;
691 <li>
692 <a href="@link" class="text-decoration-none d-block h-100">
693 <div class="h-100 d-flex flex-column justify-content-between theme theme-gray-border">
694 <div style="border: 1px solid transparent;">
695 <div class="ratio position-relative" style="--bs-aspect-ratio: 75%">
696 @if (showBadges) {
697 <div class="position-absolute top-0 left-0 p-1 p-lg-2" style="z-index: 2">
698 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms)
699 </div>
700 }
701 <img loading="lazy" decoding="async" src="@imagePath" class="h-100 w-100 " style="object-fit: contain;" alt="@product.Name">
702 </div>
703 </div>
704 <div class="flex-fill d-flex flex-column justify-content-between p-3">
705 <h3 class="h6 opacity-85">@product.Name @product.VariantName</h3>
706707 @if (!hidePrice) {
708 <div>
709710 @if( !anonymousUser) {
711 <p class="mb-0 small">@Translate("Listepris")</p>
712 }
713 <p class="h6 m-0">
714 @if (showPricesWithVat == "false" && !neverShowVat)
715 {
716 if (product.Price.Price != product.PriceBeforeDiscount.Price)
717 {
718 <span class="text-decoration-line-through opacity-75 me-1">
719 @product.PriceBeforeDiscount.PriceWithoutVatFormatted
720 </span>
721 }
722 }
723 else
724 {
725 if (product.Price.Price != product.PriceBeforeDiscount.Price)
726 {
727 <span class="text-decoration-line-through opacity-75 me-1">
728 @product.PriceBeforeDiscount.PriceFormatted
729 </span>
730 }
731 }
732733 @if (showPricesWithVat == "false" && !neverShowVat)
734 {
735 <span class="text-price fw-bold">@product.Price.PriceWithoutVatFormatted</span>
736 }
737 else
738 {
739 <span class="text-price fw-bold">@product.Price.PriceFormatted</span>
740 }
741 </p>
742 @if (showPricesWithVat == "false" && !neverShowVat)
743 {
744 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small>
745 }
746 @if( !anonymousUser) {
747 <p class="mb-0 small opacity-75">@Translate("Fragt tilføjes")</p>
748 }
749 </div>
750 }
751 </div>
752 </div>
753 </a>
754 </li>
755 }
756757758 @helper RenderFieldValue(FieldValueViewModel field) {
759 string fieldValue = field?.Value != null ? field.Value.ToString() : "";
760761 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue;
762 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue;
763764 bool isColor = false;
765766 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>))
767 {
768 int valueCount = 0;
769 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
770 int totalValues = values.Count;
771772 foreach (FieldOptionValueViewModel option in values)
773 {
774 if (option.Value.Substring(0,1) == "#") {
775 isColor = true;
776 }
777778 if (!isColor) {
779 @option.Name
780 } else {
781 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span>
782 }
783784 if (valueCount != totalValues && valueCount < (totalValues - 1)) {
785 if (isColor) {
786 <text> </text>
787 } else {
788 <text>, </text>
789 }
790 }
791 valueCount++;
792 }
793 }
794 else if (fieldValue != "")
795 {
796 if (fieldValue.Substring(0,1) == "#") {
797 isColor = true;
798 }
799800 if (!isColor) {
801 @fieldValue
802 } else {
803 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span>
804 }
805 }
806 }
807808809810 @helper RenderCheckboxOption(FacetViewModel facet, FacetOptionViewModel facetOption)
811 {
812 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label);
813 string disabled = facetOption.Count <= 0 ? "disabled" : "";
814 string selected = facetOption.Selected ? "checked" : "";
815816 if (facetLabel.ToLower() == "true")
817 {
818 facetLabel = Translate("Yes");
819 }
820821 if (facetLabel.ToLower() == "false")
822 {
823 facetLabel = Translate("No");
824 }
825826 <label class="form-check mb-1" @disabled>
827 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="form-check-input" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected>
828 <span class="form-check-label d-flex align-items-center">
829 <span class="flex-fill">@facetLabel </span>
830 <small class="opacity-85">@facetOption.Count</small>
831 </span>
832 </label>
833 }
834835 @helper RenderColorOption(FacetViewModel facet, FacetOptionViewModel facetOption)
836 {
837 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label);
838 string disabled = facetOption.Count <= 0 ? "disabled" : "";
839 string selected = facetOption.Selected ? "checked" : "";
840841 string image = facetOption.Value;
842 string colorCode = facetOption.Value;
843844 var variantOption = Dynamicweb.Ecommerce.Services.VariantOptions.GetVariantOption(facetOption.Value.ToString(), Dynamicweb.Ecommerce.Common.Context.LanguageID);
845 if (variantOption != null)
846 {
847 image = variantOption.LargeImage;
848 colorCode = variantOption.Color;
849 }
850851 <div class="colorbox">
852 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="@disabled @selected" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected title="@facetOption.Label">
853 @if (colorCode.Contains("#"))
854 {
855 <span class="colorbox-background" style="background-color: @colorCode"></span>
856 }
857 else
858 {
859 <img class="colorbox-background" src="/Admin/Public/GetImage.ashx?width=25&height=25&image=@image" />
860 }
861 </div>
862 }
863