Kladdkaka

Swedish sticky chocolate cake

Kladdkaka

By: Frederikke Legaard | Serves 8

Kladdkaka is a Swedish chocolate cake and probably my all-time favourite chocolate cake. I’d always choose a kladdkaka over a brownie or a Gateau Marcel. It’s sticky, tough, sweet and bitter. Every time I went to the Swedish supermarket ICA with my mum as a child I would beg her to please buy the readymade frozen version, which you can get at any Swedish supermarket – and I loved it. My love for the frozen kladdkaka lives on, and I like to freeze any leftovers and eat them frozen, which allows you to bite into it in a different way. Try it if you like chocolate cake.

Ingredients

  • 100g dark chocolate, 50-70%
  • 100g butter
  • 1 ½dl whipping cream
  • 300g sugar
  • 140g muscovado sugar
  • ¼ tsp salt
  • 3 large eggs
  • 2 tsp vanilla sugar
  • 60g wheat flour

Procedure

Preheat the oven to 175 degrees Celsius with top and bottom heat. Grease a springform (approximately 22cm dia.) with butter and sprinkle with sugar before setting aside.
 
Melt the butter and cream in medium sized pot at low heat. Once the butter has melted, add the chocolate and turn off the heat.
 
Pour the mixture into a large bowl. Add the sugar and muscovado sugar and stir until dissolved. Next, add the salt and eggs while briskly whipping so the eggs don’t start to cook in the warm mixture. Finally turn the wheat flour and vanilla sugar in the dough. Add the dough mixture to the greased springform and bake in the hot oven for approximately 20 minutes.
 
Allow the cake to cool off on a cooling rack whilst still in the springform and next in the fridge for at least an hour.
Error executing template "Designs/Swift/Paragraph/Swift_RelatedProducts_Custom.cshtml"
System.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at Dynamicweb.Data.Database.CreateDataReader(IDbCommand command, CommandBehavior behavior)
   at Dynamicweb.Data.Database.CreateDataReader(CommandBuilder commandBuilder, IDbConnection connection, IDbTransaction transaction, CommandBehavior behavior, Int32 commandTimeout)
   at Dynamicweb.Data.Database.CreateDataReader(CommandBuilder commandBuilder, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout)
   at Dynamicweb.Ecommerce.Products.ProductRepository.Dynamicweb.Ecommerce.Products.IProductRepository.GetProductKeysByGroupId(String groupId, Boolean useOrderBy, Boolean includeVariants, String productLanguageId, Boolean doRefactoring, Boolean useAssortments)
   at Dynamicweb.Ecommerce.Orders.Discounts.Discount.ProcessProductSelections(HashSet`1& productKeys, HashSet`1& includedQueries, HashSet`1& excludedQueries)
   at Dynamicweb.Ecommerce.Orders.Discounts.Discount.GetRelevantProductKeys()
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountService.StatelessSetLookup(Discount discount, ConcurrentDictionary`2 lookup)
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountService.InitializeLookup()
   at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Lazy`1.get_Value()
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountService.GetDiscounts(DiscountApplyType[] discountTypes, String[] productKeys, User user)
   at Dynamicweb.Ecommerce.Orders.Discounts.DiscountInfoCollection.LoadDiscounts()
   at Smartpage.EvaSolo.CampaignPrices.Helpers.DiscountHelper.GetDiscountInfo(Product product, Currency currency, Country country, Shop shop, User user, String format) in D:\a\1\s\Smartpage.EvaSolo.CampaignPrices\Helpers\DiscountHelper.cs:line 48
   at Custom.EvaSolo.CampaignPrices.FieldTypeProviders.OnSaleProvider.GetProductValue(Product product, Object fieldValue, String languageId, Dictionary`2 settings) in D:\a\1\s\Smartpage.EvaSolo.CampaignPrices\FieldTypeProviders\OnSaleProvider.cs:line 27
   at Dynamicweb.Ecommerce.Products.ProductFieldTypeProvider.GetProductValue(Product product, FieldType fieldType, Object fieldValue)
   at Dynamicweb.Ecommerce.Products.ProductFieldValueCollection.RefreshProviderFields(Product product)
   at Dynamicweb.Ecommerce.Products.ProductRepository.ExtractProduct(IDataReader dataReader, Nullable`1& groupProductRelationSortingExists)
   at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductsBySql(CommandBuilder query, Boolean doRefactoring, Boolean bulkFill, Boolean useAssortments)
   at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductsByGroup(Group group, String productLanguageId, Boolean useAssortments)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewModelFactory.CreateView(ProductListViewModelSettings settings, String groupId)
   at CompiledRazorTemplates.Dynamic.RazorEngine_06e27f9d75ed44db892493be03fbbb3e.Execute() in D:\dynamicweb.net\Solutions\twodayco3\evasolo.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_Group_SEO_Custom.cshtml:line 46
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()
ClientConnectionId:077a6f4a-d841-4c19-b87e-820b384f100a
Error Number:-2,State:0,Class:11

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System 3 @using System.Collections.Generic 4 @using System.Linq 5 @using Dynamicweb 6 @using Dynamicweb.Core 7 @using Dynamicweb.Core.Encoders 8 @using Dynamicweb.Environment 9 @using Dynamicweb.Ecommerce.ProductCatalog 10 @using Dynamicweb.Ecommerce.Products 11 @using Dynamicweb.Frontend 12 @using Smartpage.EvaSolo.Clerk.Helpers 13 14 @* CUSTOMIZED STANDARD SWIFT (v1.25.0) TEMPLATE *@ 15 16 @{ 17 ProductViewModel product = null; 18 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 19 { 20 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 21 } 22 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 23 { 24 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 25 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 26 27 if (productList?.Products is object) 28 { 29 product = productList.Products[0]; 30 } 31 } 32 33 string title = Model?.Item?.GetRawValueString("Title", Translate("Products")); 34 string campaignValues = Model.Item.GetRawValueString("CampaignBadges", string.Empty); 35 36 //Styling 37 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3"); 38 string subtitleFontSize = Model.Item.GetRawValueString("SubtitleFontSize", "fs-5"); 39 string buttonStyle = Model.Item.GetRawValueString("ButtonStyle", ""); 40 buttonStyle = buttonStyle == "primary" ? " btn-primary" : buttonStyle; 41 buttonStyle = buttonStyle == "secondary" ? " btn-secondary" : buttonStyle; 42 buttonStyle = buttonStyle == "link" ? " btn-link" : buttonStyle; 43 string maxWidth = Model.Item.GetRawValueString("TextReadability", ""); 44 maxWidth = maxWidth == "max-width-on" ? " mw-75ch" : maxWidth; 45 maxWidth = maxWidth == "max-width-off" ? "" : maxWidth; 46 47 string generalTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("GeneralTheme")) ? " theme " + Model.Item.GetRawValueString("GeneralTheme").Replace(" ", "").Trim().ToLower() : ""; 48 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 49 string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 50 51 //Link generation 52 string pageId = !string.IsNullOrEmpty(Model.Item.GetRawValueString("ProductSliderServicePage")) ? Model.Item.GetLink("ProductSliderServicePage").PageId.ToString() : ""; 53 if (string.IsNullOrEmpty(pageId)) 54 { 55 pageId = GetPageIdByNavigationTag("ProductSliderService").ToString(); 56 } 57 58 string url = "/Default.aspx?ID=" + pageId; 59 if (!url.Contains("LayoutTemplate", StringComparison.OrdinalIgnoreCase)) 60 { 61 url += url.Contains("?") ? "&LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml" : "?LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml"; 62 } 63 64 if (Pageview.IsVisualEditorMode) 65 { 66 url += "&VisualEdit=True"; 67 } 68 69 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsLazyLoadingForProductInfoEnabled"]); 70 if (isLazyLoadingForProductInfoEnabled) 71 { 72 url += "&getproductinfo=true"; 73 } 74 75 //Source type 76 string sourceType = Model.Item.GetRawValueString("RelationType", "trending"); 77 IList<string> relateFromGroupIds = new List<string> { }; 78 IList<string> relateFromProductVariantIds = new List<string> { }; 79 IList<string> relateFromProductIds = new List<string> { }; 80 bool hasVariants = false; 81 82 //--- VARIANTS --- 83 if (sourceType == "variants" && Model.Item.GetValue<ProductListViewModel>("ProductsToRelateToVariants") is ProductListViewModel productsToRelateToVariants) 84 { 85 foreach (var productSelection in productsToRelateToVariants.Products) 86 { 87 relateFromProductIds.Add(productSelection.Id); 88 } 89 } 90 91 //--- MOST SOLD --- 92 if (sourceType == "most-sold" && Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToMostSold") is IList<ProductGroupViewModel> groupsToRelateToMostSold) 93 { 94 foreach (var fromGroup in groupsToRelateToMostSold) 95 { 96 relateFromGroupIds.Add(fromGroup.Id); 97 } 98 } 99 100 //--- TRENDING --- 101 if (sourceType == "trending" && Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToTrending") is IList<ProductGroupViewModel> groupsToRelateToTrending) 102 { 103 foreach (var fromGroup in groupsToRelateToTrending) 104 { 105 relateFromGroupIds.Add(fromGroup.Id); 106 } 107 } 108 109 //--- LATEST --- 110 if (sourceType == "latest" && Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToLatest") is IList<ProductGroupViewModel> groupsToRelateToLatest) 111 { 112 foreach (var fromGroup in groupsToRelateToLatest) 113 { 114 relateFromGroupIds.Add(fromGroup.Id); 115 } 116 } 117 118 //--- FREQUENTLY BOUGHT --- 119 if (sourceType == "frequently" && Model.Item.GetValue<ProductListViewModel>("ProductsToRelateTo") is ProductListViewModel productsToRelateTo) 120 { 121 foreach (var fromProduct in productsToRelateTo.Products) 122 { 123 relateFromProductIds.Add(fromProduct.Id); 124 } 125 } 126 127 //--- SELECTED PRODUCTS --- 128 if ((sourceType == "selected" || sourceType == "frequently") && Model.Item.GetValue<ProductListViewModel>("Products") is ProductListViewModel products) 129 { 130 hasVariants = products.Products.Any(p => !string.IsNullOrEmpty(p.VariantId)); 131 foreach (var productSelection in products.Products) 132 { 133 if (hasVariants) 134 { 135 if (!string.IsNullOrEmpty(productSelection.VariantId)) 136 { 137 relateFromProductVariantIds.Add($"{productSelection.Id} {productSelection.VariantId}"); 138 } 139 else 140 { 141 relateFromProductVariantIds.Add($"{productSelection.Id}"); 142 } 143 } 144 145 relateFromProductIds.Add($"{productSelection.Id}"); 146 } 147 } 148 149 //--- UPSELL PRODUCTS --- 150 if (sourceType == "upsell-products") 151 { 152 string upSell = product.ProductFields.ContainsKey("Custom_UpSell") ? Converter.ToString(product.ProductFields["Custom_UpSell"].Value) : string.Empty; 153 List<Product> upSellProducts = GetActiveUpSellProducts(upSell); 154 relateFromProductIds = upSellProducts != null ? upSellProducts.Select(p => p.Id).ToList() : new List<string>(); 155 } 156 157 //--- RELATED PRODUCTS --- 158 if (sourceType == "related-products" && Model.Item.GetValue<ProductListViewModel>("ProductsToRelateTo2") is ProductListViewModel selectedRelationProduct) 159 { 160 if (selectedRelationProduct.Products.Any()) 161 { 162 product = selectedRelationProduct.Products.FirstOrDefault(); 163 } 164 165 if (product?.RelatedGroups != null) 166 { 167 foreach (var group in product.RelatedGroups) 168 { 169 foreach (var relatedProduct in group.Products) 170 { 171 if (!string.IsNullOrEmpty(relatedProduct.VariantId)) 172 { 173 relateFromProductVariantIds.Add($"{relatedProduct.ProductId} {relatedProduct.VariantId}"); 174 } 175 else 176 { 177 relateFromProductVariantIds.Add($"{relatedProduct.ProductId}"); 178 } 179 } 180 } 181 } 182 } 183 184 //Create group id collection and products id collection strings 185 string groupIds = product is object ? product.PrimaryOrDefaultGroup.Id : string.Join(",", relateFromGroupIds); 186 string productVariantIds = relateFromProductVariantIds.Count > 0 ? string.Join(",", relateFromProductVariantIds) : ""; 187 string productIds = product is object && relateFromProductIds.Count == 0 ? product.Id : string.Join(",", relateFromProductIds); 188 //Set the parameters to the url 189 string linkParameters = ""; 190 linkParameters += sourceType != "related-products" && sourceType != "frequently" && sourceType != "selected" ? "&GroupId=" + groupIds : ""; 191 linkParameters += !string.IsNullOrEmpty(productIds) && sourceType != "most-sold" && sourceType != "trending" && sourceType != "latest" && sourceType != "frequently" && sourceType != "related-products" ? "&MainProductId=" + productIds : ""; 192 linkParameters += !string.IsNullOrEmpty(productVariantIds) && sourceType == "related-products" ? "&ProductVariantId=" + productVariantIds : ""; 193 linkParameters += sourceType == "variants" ? "&IsVariant=true" : ""; 194 linkParameters += sourceType == "latest" ? "&SortBy=Created" : ""; 195 linkParameters += sourceType == "most-sold" ? "&SortBy=OrderCount" : ""; 196 linkParameters += sourceType == "trending" ? "&SortBy=OrderCountGrowth" : ""; 197 linkParameters += !string.IsNullOrEmpty(productIds) && sourceType == "frequently" ? $"&BoughtWithProductIds=[{productIds}]" : ""; 198 var productListPageId = GetPageIdByNavigationTag("Shop"); 199 string link = "/Default.aspx?ID=" + productListPageId + linkParameters; 200 201 // Slider settings (documentation: swiffyslider.com/configuration) 202 string navigationStyle = $"{Model.Item.GetRawValueString("NavigationStyle", "slider-nav-round")}"; 203 string navigationPlacement = $"{Model.Item.GetRawValueString("NavigationPlacement", "slider-nav-on-slides")}"; 204 string indicatorStyle = $"{Model.Item.GetRawValueString("IndicatorStyle", "slider-indicators-hidden")}"; 205 string revealSlides = Model.Item.GetRawValueString("RevealSlides", "no-reveal") == "reveal" ? "slider-item-reveal" : string.Empty; 206 string navigationAlwaysVisible = (Model.Item.GetBoolean("NavigationAlwaysVisible")) ? "slider-nav-visible" : string.Empty; 207 string navigationVisibleOnTouch = (Model.Item.GetBoolean("NavigationVisibleOnTouch")) ? "slider-nav-touch" : string.Empty; 208 string navigationShowScrollbar = (Model.Item.GetBoolean("NavigationShowScrollbar")) ? "slider-nav-scrollbar" : string.Empty; 209 string navigationSmall = (Model.Item.GetBoolean("NavigationSmall")) ? "slider-nav-sm" : string.Empty; 210 string navigationInvertColors = (Model.Item.GetBoolean("NavigationInvertColors")) ? "slider-nav-dark" : string.Empty; 211 string navigationSlideEntirePage = (Model.Item.GetBoolean("NavigationSlideEntirePage")) ? "slider-nav-page" : string.Empty; 212 string navigationNoLoop = (Model.Item.GetBoolean("NavigationNoLoop")) ? "slider-nav-noloop" : string.Empty; 213 string indicatorsOutsideSlider = (Model.Item.GetBoolean("IndicatorsOutsideSlider") && indicatorStyle != string.Empty) ? "slider-indicators-outside" : string.Empty; 214 string indicatorsHighlightActive = (Model.Item.GetBoolean("IndicatorsHighlightActive")) ? "slider-indicators-highlight" : string.Empty; 215 string indicatorsInvertColors = (Model.Item.GetBoolean("IndicatorsInvertedColors")) ? "slider-indicators-dark" : string.Empty; 216 string indicatorsVisibleOnSmallDevices = (Model.Item.GetBoolean("IndicatorsVisibleOnSmallDevices")) ? "slider-indicators-sm" : string.Empty; 217 218 bool productsFound = true; 219 if (sourceType != "clerk" && string.IsNullOrEmpty(groupIds) && string.IsNullOrEmpty(productIds) && string.IsNullOrEmpty(productVariantIds)) //CUSTOM 220 { 221 if (Pageview.IsVisualEditorMode && product != null) //CUSTOM 222 { 223 productIds = product.Id; 224 sourceType = "selected"; 225 } 226 else 227 { 228 productsFound = false; 229 } 230 } 231 else if (sourceType == "upsell-products") 232 { 233 productsFound = relateFromProductIds.Count > 0; 234 } 235 } 236 237 @*//CUSTOM*@ 238 @if (Pageview.IsVisualEditorMode == true && sourceType == "clerk" && PageView.Current().AreaSettings.GetItem("CustomSettings").GetRawValueString("ClerkPublicKey_Custom").IsNullOrEmpty()) 239 { 240 <div class="alert alert-danger" role="alert"> 241 <span>@Translate("Product slider: The Clerk integration requires a public key in the website settings")</span> 242 </div> 243 } 244 @*//--CUSTOM*@ 245 246 @*Container element for the request*@ 247 @if (productsFound) 248 { 249 <form method="post" action="@url" id="RelatedProductsForm_@Model.ID" data-response-target-element="RelatedProducts_@Model.ID" data-preloader="inline" data-update-url="false" class="item_@Model.Item.SystemName.ToLower()"> 250 <input type="hidden" name="ModelID" value="@Model.ID"> 251 <input type="hidden" name="SourceType" value="@sourceType"> 252 253 @*--- SLIDER SETTINGS ---*@ 254 <input type="hidden" name="NavigationStyle" value="@navigationStyle"> 255 <input type="hidden" name="NavigationPlacement" value="@navigationPlacement"> 256 <input type="hidden" name="IndicatorStyle" value="@indicatorStyle"> 257 <input type="hidden" name="RevealSlides" value="@revealSlides"> 258 <input type="hidden" name="NavigationAlwaysVisible" value="@(navigationAlwaysVisible)"> 259 <input type="hidden" name="NavigationVisibleOnTouch" value="@(navigationVisibleOnTouch)"> 260 <input type="hidden" name="NavigationShowScrollbar" value="@(navigationShowScrollbar)"> 261 <input type="hidden" name="NavigationSmall" value="@(navigationSmall)"> 262 <input type="hidden" name="NavigationInvertColors" value="@(navigationInvertColors)"> 263 <input type="hidden" name="NavigationNoLoop" value="@(navigationNoLoop)"> 264 <input type="hidden" name="NavigationSlideEntirePage" value="@(navigationSlideEntirePage)"> 265 <input type="hidden" name="IndicatorsOutsideSlider" value="@(indicatorsOutsideSlider)"> 266 <input type="hidden" name="IndicatorsHighlightActive" value="@(indicatorsHighlightActive)"> 267 <input type="hidden" name="IndicatorsInvertColors" value="@(indicatorsInvertColors)"> 268 <input type="hidden" name="IndicatorsVisibleOnSmallDevices" value="@(indicatorsVisibleOnSmallDevices)"> 269 270 @*--- VARIANTS ---*@ 271 @if (sourceType == "variants") 272 { 273 <input type="hidden" name="isVariant" value="true"> 274 <input type="hidden" name="MainProductID" id="MainProductID_@Model.ID" value="@productIds"> 275 } 276 277 @*--- MOST SOLD ---*@ 278 @if (sourceType == "most-sold") 279 { 280 <input type="hidden" name="SortBy" value="OrderCount"> 281 if (groupIds != "") 282 { 283 <input type="hidden" name="GroupId" value="@groupIds"> 284 } 285 } 286 287 @*--- TRENDING ---*@ 288 @if (sourceType == "trending") 289 { 290 <input type="hidden" name="SortBy" value="OrderCountGrowth"> 291 if (groupIds != "") 292 { 293 <input type="hidden" name="GroupId" value="@groupIds"> 294 } 295 } 296 297 @*--- FREQUENTLY BOUGHT ---*@ 298 @if (sourceType == "frequently" && !string.IsNullOrEmpty(productIds)) 299 { 300 <input type="hidden" name="BoughtWithProductIds" value="[@productIds]"> 301 } 302 @if (sourceType != "frequently" && hasVariants) 303 { 304 <input type="hidden" name="ProductVariantId" value="@productVariantIds"> 305 } 306 307 @*--- LATEST ---*@ 308 @if (sourceType == "latest") 309 { 310 <input type="hidden" name="SortBy" value="Created"> 311 <input type="hidden" name="GroupId" value="@groupIds"> 312 } 313 314 @*--- SELECTED PRODUCTS ---*@ 315 @if (sourceType == "selected" && !string.IsNullOrEmpty(productIds) && !hasVariants) 316 { 317 <input type="hidden" name="MainProductId" id="MainProductID_@Model.ID" value="@productIds"> 318 } 319 @if (sourceType == "selected" && hasVariants) 320 { 321 <input type="hidden" name="ProductVariantId" value="@productVariantIds"> 322 } 323 324 @*--- UPSELL PRODUCTS ---*@ 325 @if (sourceType == "upsell-products" && !string.IsNullOrEmpty(productIds) && !hasVariants) 326 { 327 <input type="hidden" name="MainProductId" id="MainProductID_@Model.ID" value="@productIds"> 328 } 329 @if (sourceType == "upsell-products" && hasVariants) 330 { 331 <input type="hidden" name="ProductVariantId" value="@productVariantIds"> 332 } 333 334 @*--- RELATED PRODUCTS ---*@ 335 @if (sourceType == "related-products") 336 { 337 <input type="hidden" name="ProductVariantId" id="MainProductID_@Model.ID" value="@productVariantIds"> 338 } 339 340 @*//CUSTOM*@ 341 @*--- CLERK ---*@ 342 @if (sourceType == "clerk") 343 { 344 // Doc.: https://docs.clerk.io/reference/recommendations-popular 345 346 var clerkEndPoint = Model.Item.GetString("ClerkEndpoint"); 347 var clerkKeywords = Model.Item.GetString("ClerkKeywords"); 348 var clerkQuery = new List<string>(); 349 var clerkFilter = new List<string>(); 350 351 if (!string.IsNullOrEmpty(clerkKeywords)) 352 { 353 switch (clerkEndPoint) 354 { 355 case "recommendations/keywords": 356 clerkQuery.Add("keywords=['" + clerkKeywords + "']"); 357 break; 358 } 359 } 360 361 if (product != null && !string.IsNullOrEmpty(product.Id)) 362 { 363 switch (clerkEndPoint) 364 { 365 case "recommendations/bundle": 366 clerkQuery.Add("product=" + product.Id); 367 break; 368 369 case "recommendations/complementary": 370 case "recommendations/substituting": 371 case "recommendations/most_sold_with": 372 clerkQuery.Add("products=[" + product.Id + "]"); // NOTE: Clerk format id as integer (Data Sync product feed is string) 373 break; 374 } 375 } 376 377 IList<ProductGroupViewModel> clerkGroupsToRelateTo = Model.Item.GetValue<IList<ProductGroupViewModel>>("ClerkGroupsToRelateTo"); 378 switch (clerkEndPoint) 379 { 380 case "recommendations/category/popular": 381 case "recommendations/category/trending": 382 case "recommendations/category/new": 383 if (clerkGroupsToRelateTo != null && clerkGroupsToRelateTo.Any()) 384 { 385 clerkQuery.Add("category=" + clerkGroupsToRelateTo.First().Id); 386 } 387 else if (Context.Current.Request.HasRequest("GroupID")) 388 { 389 clerkQuery.Add("category=" + Context.Current.Request.GetString("GroupID")); 390 } 391 392 break; 393 394 default: 395 if (clerkGroupsToRelateTo != null && clerkGroupsToRelateTo.Any()) 396 { 397 clerkFilter.Add("categories in ['" + string.Join("','", clerkGroupsToRelateTo.Select(i => i.Id)) + "']"); 398 } 399 400 break; 401 } 402 403 switch (clerkEndPoint) 404 { 405 case "recommendations/page/substituting": 406 case "recommendations/page/related_products": 407 case "recommendations/page/related_categories": 408 clerkQuery.Add("page=" + Model.PageID); 409 break; 410 } 411 412 IList<ItemViewModel> clerkFilters = Model.Item.GetItems("ClerkFilters"); 413 if (clerkFilters != null) 414 { 415 foreach (var i in clerkFilters) 416 { 417 switch (i.GetString("OperatorType")) 418 { 419 case "=": 420 case "!=": 421 case "contains": 422 case "contains not": 423 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")} '{i.GetString("Value")}'"); 424 break; 425 426 case "in": 427 case "not in": 428 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")} ['{i.GetString("Value").Replace(",", "','")}']"); 429 break; 430 431 case "= true": 432 case "= false": 433 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")}"); 434 break; 435 436 default: 437 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")} {i.GetString("Value")}"); 438 break; 439 } 440 } 441 } 442 443 <input type="hidden" name="ClerkEndpoint" value="@HtmlEncoder.HtmlAttributeEncode(clerkEndPoint)" /> 444 <input type="hidden" name="ClerkQuery" value="@HtmlEncoder.HtmlAttributeEncode(string.Join("&", clerkQuery))" /> 445 <input type="hidden" name="ClerkFilter" value="@HtmlEncoder.HtmlAttributeEncode(string.Join(" and ", clerkFilter))" /> 446 <input type="hidden" name="ClerkLabels" value="@HtmlEncoder.HtmlAttributeEncode(Model.Item.GetString("ClerkLabels"))" /> 447 <input type="hidden" name="ClerkLogArea" value="@HtmlEncoder.HtmlAttributeEncode($"{Pageview.Area.Name} (ID: {Pageview.Area.ID})")" /> 448 <input type="hidden" name="ClerkLogPage" value="@HtmlEncoder.HtmlAttributeEncode($"{Pageview.Page.MenuText} (ID: {Pageview.Page.ID})")" /> 449 <input type="hidden" name="ClerkLogParagraph" value="@HtmlEncoder.HtmlAttributeEncode($"{Pageview.CurrentParagraph.Header} (ID: {Pageview.CurrentParagraph.ID})")" /> 450 } 451 @*//--CUSTOM*@ 452 453 @* General parameters *@ 454 <input type="hidden" name="Link" value="@link"> 455 <input type="hidden" name="HideTitle" value="@Model.Item.GetString("HideTitle")"> 456 <input type="hidden" name="HidePrices" value="@Model.Item.GetString("CustomHidePrices")" /> @*//CUSTOM*@ 457 458 @if (Model.Item.GetInt32("ProductsCount") != 0) 459 { 460 <input type="hidden" name="PageSize" value="@Model.Item.GetInt32("ProductsCount")"> 461 } 462 <input type="hidden" name="HeadingTitle" id="RelatedProductsTitle_@Model.ID" value="@title"> 463 @if (!string.IsNullOrEmpty(Model.Item.GetString("Subtitle"))) 464 { 465 <input type="hidden" name="Subtitle" value="@Model.Item.GetString("Subtitle")"> 466 } 467 @if (!string.IsNullOrEmpty(Model.Item.GetString("LinkText"))) 468 { 469 <input type="hidden" name="LinkText" value="@Model.Item.GetString("LinkText")"> 470 } 471 @if (!string.IsNullOrEmpty(Model.Item.GetString("ImageAspectRatio"))) 472 { 473 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 474 ratio = ratio != "0" ? ratio : ""; 475 <input type="hidden" name="ImageAspectRatio" value="@ratio"> 476 } 477 @if (!string.IsNullOrEmpty(Model.Item.GetString("Layout"))) 478 { 479 <input type="hidden" name="Layout" value="@Model.Item.GetRawValueString("Layout")"> 480 } 481 @if (titleFontSize != "") 482 { 483 <input type="hidden" name="TitleFontSize" value="@titleFontSize"> 484 } 485 @if (subtitleFontSize != "") 486 { 487 <input type="hidden" name="SubtitleFontSize" value="@subtitleFontSize"> 488 } 489 @if (buttonStyle != "") 490 { 491 <input type="hidden" name="ButtonStyle" value="@buttonStyle"> 492 } 493 @if (generalTheme != "") 494 { 495 <input type="hidden" name="GeneralTheme" value="@generalTheme"> 496 } 497 @if (theme != "") 498 { 499 <input type="hidden" name="Theme" value="@theme"> 500 } 501 @if (imageTheme != "") 502 { 503 <input type="hidden" name="ImageTheme" value="@imageTheme"> 504 } 505 @if (!string.IsNullOrEmpty(Model.Item.GetString("ContentPadding"))) 506 { 507 string contentPadding = Model.Item.GetRawValueString("ContentPadding"); 508 <input type="hidden" name="ContentPadding" value="@contentPadding"> 509 } 510 <input type="hidden" name="TextReadability" value="@maxWidth"> 511 <input type="hidden" name="ParentColumnSize" id="ParentColumnSize_@Model.ID" value="12"> 512 513 <input type="hidden" name="SaleBadgeType" value="@Model.Item.GetRawValue("SaleBadgeType")"> 514 <input type="hidden" name="SaleBadgeCssClassName" value="@Model.Item.GetRawValue("SaleBadgeDesign")"> 515 <input type="hidden" name="NewBadgeCssClassName" value="@Model.Item.GetRawValue("NewBadgeDesign")"> 516 <input type="hidden" name="NewPublicationDays" value="@Model.Item.GetInt32("NewPublicationDays")"> 517 518 @if (campaignValues != "") 519 { 520 <input type="hidden" name="CampaignBadgesValues" value="@campaignValues"> 521 } 522 </form> 523 524 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script> 525 <script> 526 window.addEventListener("load", () => { 527 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css'); 528 }); 529 </script> 530 531 if (Pageview.IsVisualEditorMode) 532 { 533 <div class="alert alert-info" role="alert"> 534 <span>@Translate("Product slider: Edit this column to configure")</span> 535 </div> 536 } 537 538 if (sourceType == "upsell-products") 539 { 540 <div class="w-100 h-100"> 541 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div> 542 <div id="RelatedProducts_@Model.ID"></div> 543 </div> 544 } 545 else if (sourceType != "related-products") 546 { 547 <div class="w-100 h-100"> 548 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div> 549 <div id="RelatedProducts_@Model.ID" class="h-100 swift_product_slider_container" data-product-count="@Model.Item.GetInt32("ProductsCount")"></div> @*//CUSTOM*@ 550 </div> 551 } 552 else if (product?.RelatedGroups != null) 553 { 554 @* Create multiple slider containers, if type is Product relation *@ 555 <div class="grid w-100 h-100@(generalTheme)" style="grid-row-gap: 4rem"> 556 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div> 557 @foreach (var group in product.RelatedGroups) 558 { 559 <div id="RelatedProducts_@(Model.ID)_@group.Id" class="g-col-12 h-100 swift_product_slider_container"></div> 560 } 561 </div> 562 } 563 564 @* Initialize *@ 565 if (sourceType != "related-products") 566 { 567 <script type="module"> 568 if (document.querySelector("#RelatedProducts_@Model.ID").closest("[data-col-size]")) { 569 document.querySelector("#ParentColumnSize_@Model.ID").value = document.querySelector("#RelatedProducts_@Model.ID").closest("[data-col-size]").getAttribute("data-col-size"); 570 } 571 swift.PageUpdater.Update(document.querySelector("#RelatedProductsForm_@Model.ID")).then(function () { 572 setTimeout(function () { 573 const isVisualEditor = @(Converter.ToString(Pageview.IsVisualEditorMode).ToLowerInvariant()); 574 const productSliderContainer = document.querySelector(".swift_product_slider_container"); 575 576 if (productSliderContainer && productSliderContainer.innerHTML !== "") { 577 productSliderContainer.classList.remove("d-none"); 578 } else if (!isVisualEditor && productSliderContainer) { 579 productSliderContainer.closest("[class*=column]").classList.add("d-none"); 580 } 581 custom.UpsellProducts.bindEvents(); 582 }, 150); 583 }); 584 </script> 585 } 586 else if (product?.RelatedGroups != null) 587 { 588 @* Create multiple sliders, if type is Product relation *@ 589 foreach (var group in product.RelatedGroups) 590 { 591 IList<string> fromProductIds = new List<string> { }; 592 593 foreach (var relatedProduct in group.Products) 594 { 595 if (!string.IsNullOrEmpty(relatedProduct.VariantId)) 596 { 597 fromProductIds.Add($"{relatedProduct.ProductId} {relatedProduct.VariantId}"); 598 } 599 else 600 { 601 fromProductIds.Add($"{relatedProduct.ProductId}"); 602 } 603 } 604 605 <script type="module"> 606 document.querySelector("#ParentColumnSize_@Model.ID").value = document.querySelector("#RelatedProducts_@(Model.ID)_@group.Id").closest("[data-col-size]").getAttribute("data-col-size"); 607 document.querySelector("#MainProductID_@Model.ID").value = "@string.Join(",", fromProductIds)"; 608 document.querySelector("#RelatedProductsTitle_@Model.ID").value = "@group.Name"; 609 document.querySelector("#RelatedProductsForm_@Model.ID").setAttribute("data-response-target-element", "RelatedProducts_@(Model.ID)_@group.Id"); 610 611 swift.PageUpdater.Update(document.querySelector("#RelatedProductsForm_@Model.ID")); 612 </script> 613 } 614 } 615 } 616 617 @functions { 618 List<Product> GetActiveUpSellProducts(string productNumbers) 619 { 620 if (!string.IsNullOrEmpty(productNumbers)) 621 { 622 List<Product> upSellProducts = Product.GetProductsByProductIDs(productNumbers.Split(',').Select(x => x.Trim()).ToArray(), true).ToList(); 623 624 if (upSellProducts != null && upSellProducts.Any()) 625 { 626 List<Product> activeUpSellProducts = new List<Product>(); 627 628 foreach (Product upSellProduct in upSellProducts) 629 { 630 if (upSellProduct.Active && GetStock(upSellProduct) > 0 && !upSellProduct.IsProductDisabledInClerkSync()) 631 { 632 activeUpSellProducts.Add(upSellProduct); 633 } 634 } 635 636 return activeUpSellProducts; 637 } 638 } 639 640 return null; 641 } 642 643 double GetStock(Product product) 644 { 645 double productStock = product.Stock; 646 647 if (Converter.ToBoolean(Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(product, "Custom_FurnitureWarehouse"))) 648 { 649 productStock = Converter.ToDouble(Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(product, "Custom_AlternativeStock")); 650 } 651 652 return productStock; 653 } 654 } 655

You might also like