Error executing template "Designs/Swift/_parsed/Swift_Page.parsed.cshtml"
System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server) ---> System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at Dynamicweb.Data.DatabaseConnectionProvider.CreateConnection(Boolean open)
   at Dynamicweb.Data.Database.CreateConnection()
   at Dynamicweb.Data.Database.CreateDataReader(CommandBuilder commandBuilder, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout)
   at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductById(String productId, String productVariantId, String productLanguageId)
   at Dynamicweb.Ecommerce.Products.ProductService.FetchMissingProductsInternal(IProductRepository repo, IEnumerable`1 keys)
   at Dynamicweb.Caching.ServiceCache`2.GetCache(IEnumerable`1 keys)
   at Dynamicweb.Caching.ServiceCache`2.GetCache(TKey key)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, User user, Boolean showUntranslated)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, Boolean useAssortments)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId)
   at CompiledRazorTemplates.Dynamic.RazorEngine_6802776a3350483c8856934a66b58a35.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\T3L.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\_parsed\Swift_Page.parsed.cshtml:line 430
   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:00000000-0000-0000-0000-000000000000
Error Number:2,State:0,Class:20

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 2 @using System 3 @using Dynamicweb 4 @using Dynamicweb.Environment 5 @using Dynamicweb.Frontend 6 7 @functions { 8 string GetCookieOptInPermission(string category) 9 { 10 bool categoryOrAllGranted = false; 11 12 if (CookieManager.IsCookieManagementActive) 13 { 14 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 15 var cookieOptInCategories = CookieManager.GetCookieOptInCategories(); 16 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All; 17 } 18 19 return categoryOrAllGranted ? "granted" : "denied"; 20 } 21 22 bool AllowTracking() 23 { 24 bool allowTracking = true; 25 if (CookieManager.IsCookieManagementActive) 26 { 27 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 28 var cookieOptInCategories = CookieManager.GetCookieOptInCategories(); 29 30 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing")); 31 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional; 32 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither); 33 34 allowTracking = consentAtLeastOne; 35 } 36 return allowTracking; 37 } 38 } 39 40 @{ 41 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID; 42 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false; 43 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3"; 44 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart; 45 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0; 46 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0; 47 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0; 48 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null; 49 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null; 50 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null; 51 } 52 53 @if (themesParagraphs != null || brandingPage != null) 54 { 55 string swiftVersion = ReadFile("/Files/Templates/Designs/Swift/swift_version.txt"); 56 bool renderAsResponsive = Model.Area.Item.GetString("DeviceRendering", "responsive").Equals("responsive", StringComparison.OrdinalIgnoreCase); 57 bool renderMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet; 58 string responsiveClassDesktop = string.Empty; 59 string responsiveClassMobile = string.Empty; 60 if (renderAsResponsive) 61 { 62 responsiveClassDesktop = " d-none d-xl-block"; 63 responsiveClassMobile = " d-block d-xl-none"; 64 } 65 66 var headerDesktopLink = Model.Area.Item?.GetLink("HeaderDesktop") ?? null; 67 var headerMobileLink = Model.Area.Item?.GetLink("HeaderMobile") ?? null; 68 69 var footerDesktopLink = Model.Area.Item?.GetLink("FooterDesktop") ?? null; 70 var footerMobileLink = Model.Area.Item?.GetLink("FooterMobile") ?? null; 71 72 var disableWideBreakpoints = Model.Area?.Item?.GetRawValueString("DisableWideBreakpoints", "default"); 73 74 string customHeaderInclude = Model.Area.Item.GetRawValueString("CustomHeaderInclude").Replace("/Files/Templates/Designs/Swift/", ""); 75 if (Model.Area.Item.GetFile("CustomHeaderInclude") != null) 76 { 77 customHeaderInclude = Model.Area.Item.GetFile("CustomHeaderInclude").Path.Replace("/Files/Templates/Designs/Swift/", ""); 78 } 79 80 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 81 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt; 82 83 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css")); 84 85 86 if (cssPageId != 0) 87 { 88 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css")); 89 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 90 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt) 91 { 92 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId); 93 cssPageview.Redirect = false; 94 cssPageview.Output(); 95 } 96 } 97 98 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt) 99 { 100 //Branding page has been saved or the file is missing. Rewrite the file to disc. 101 if (brandingPageId > 0) 102 { 103 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId); 104 brandingPageview.Redirect = false; 105 brandingPageview.Output(); 106 } 107 } 108 109 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt) 110 { 111 //Branding page has been saved or the file is missing. Rewrite the file to disc. 112 if (themePageId > 0) 113 { 114 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId); 115 themePageview.Redirect = false; 116 themePageview.Output(); 117 } 118 } 119 120 // Schema.org details for PDP 121 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID"); 122 bool isArticlePage = Model.ItemType == "Swift_Article"; 123 string schemaOrgType = string.Empty; 124 125 if (isProductDetailsPage) 126 { 127 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\""; 128 } 129 130 if (isArticlePage) 131 { 132 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\""; 133 } 134 135 136 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css")); 137 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js")); 138 139 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 140 141 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png"); 142 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png"); 143 144 string headerCssClass = "sticky-top"; 145 bool movePageBehind = false; 146 147 if (Model.PropertyItem != null) 148 { 149 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top"); 150 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false; 151 } 152 153 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass; 154 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass; 155 156 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim(); 157 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim(); 158 159 bool allowTracking = AllowTracking(); 160 161 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;"); 162 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css?{cssLastModified.Ticks}>; rel=preload; as=style;"); 163 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;"); 164 165 166 SetMetaTags(); 167 168 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>(); 169 170 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage; 171 languages.Add(masterPage); 172 if (masterPage?.Languages != null) 173 { 174 foreach (var language in masterPage.Languages) 175 { 176 languages.Add(language); 177 } 178 } 179 180 Uri url = Dynamicweb.Context.Current.Request.Url; 181 string hostName = url.Host; 182 183 <!doctype html> 184 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName"> 185 <head> 186 <!-- @swiftVersion --> 187 @* Required meta tags *@ 188 <meta charset="utf-8"> 189 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0"> 190 <link rel="shortcut icon" href="@favicon"> 191 <link rel="apple-touch-icon" href="@appleTouchIcon"> 192 193 @Model.MetaTags 194 195 @{ 196 var alreadyWrittenTwoletterIsos = new List<string>(); 197 @* Languages meta data *@ 198 foreach (var language in languages) 199 { 200 hostName = url.Host; 201 if (language?.Area != null) 202 { 203 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock)) 204 { 205 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk 206 } 207 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published) 208 { 209 if (!string.IsNullOrEmpty(language.Area.DomainLock)) 210 { 211 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk 212 } 213 string querystring = $"Default.aspx?ID={language.ID}"; 214 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"])) 215 { 216 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}"; 217 } 218 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 219 { 220 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}"; 221 } 222 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"])) 223 { 224 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}"; 225 } 226 227 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring); 228 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1) 229 { 230 friendlyUrl = "/"; 231 } 232 string href = $"{url.Scheme}://{hostName}{friendlyUrl}"; 233 234 235 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href"> 236 if (!alreadyWrittenTwoletterIsos.Contains(language.Area.CultureInfo.TwoLetterISOLanguageName)) 237 { 238 alreadyWrittenTwoletterIsos.Add(language.Area.CultureInfo.TwoLetterISOLanguageName); 239 <link rel="alternate" hreflang="@language.Area.CultureInfo.TwoLetterISOLanguageName.ToLower()" href="@href"> 240 } 241 } 242 } 243 } 244 } 245 246 <title>@Model.Title</title> 247 @* Bootstrap + Swift stylesheet *@ 248 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css"> 249 250 @if (disableWideBreakpoints != "disableBoth") 251 { 252 <style> 253 @@media ( min-width: 1600px ) { 254 .container-xxl, 255 .container-xl, 256 .container-lg, 257 .container-md, 258 .container-sm, 259 .container { 260 max-width: 1520px; 261 } 262 } 263 </style> 264 265 266 267 if (disableWideBreakpoints != "disableUltraWideOnly") 268 { 269 <style> 270 @@media ( min-width: 1920px ) { 271 .container-xxl, 272 .container-xl, 273 .container-lg, 274 .container-md, 275 .container-sm, 276 .container { 277 max-width: 1820px; 278 } 279 } 280 </style> 281 } 282 } 283 284 @* Branding and Themes min stylesheet *@ 285 <link href="/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_@(Model.Area.ID).min.css?@cssLastModified.Ticks" rel="stylesheet" media="all" type="text/css" data-last-modified-content="@cssLastModified"> 286 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script> 287 <script type="module"> 288 swift.Scroll.hideHeadersOnScroll(); 289 swift.Scroll.handleAlternativeTheme(); 290 291 //Only load if AOS 292 const aosColumns = document.querySelectorAll('[data-aos]'); 293 if (aosColumns.length > 0) { 294 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js'); 295 document.addEventListener('load.swift.assetloader', function () { 296 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') }); 297 }); 298 } 299 </script> 300 301 @* Google gtag method - always include even if it is not used for anything *@ 302 <script> 303 window.dataLayer = window.dataLayer || []; 304 function gtag() { dataLayer.push(arguments); } 305 </script> 306 @* Google tag manager *@ 307 @if (!string.IsNullOrWhiteSpace(googleTagManagerID)) 308 { 309 <script> 310 gtag('consent', 'default', { 311 'ad_storage': 'denied', 312 'ad_user_data': 'denied', 313 'ad_personalization': 'denied', 314 'analytics_storage': 'denied' 315 }); 316 </script> 317 <script> 318 (function (w, d, s, l, i) { 319 w[l] = w[l] || []; w[l].push({ 320 'gtm.start': 321 new Date().getTime(), event: 'gtm.js' 322 }); var f = d.getElementsByTagName(s)[0], 323 j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src = 324 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f); 325 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)'); 326 </script> 327 if (allowTracking) 328 { 329 string adConsent = GetCookieOptInPermission("Marketing"); 330 string analyticsConsent = GetCookieOptInPermission("Statistical"); 331 <script> 332 gtag('consent', 'update', { 333 'ad_storage': '@adConsent', 334 'ad_user_data': '@adConsent', 335 'ad_personalization': '@adConsent', 336 'analytics_storage': '@analyticsConsent' 337 }); 338 </script> 339 } 340 } 341 342 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking) 343 { 344 var GoogleAnalyticsDebugMode = ""; 345 346 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode")) 347 { 348 GoogleAnalyticsDebugMode = ", {'debug_mode': true}"; 349 } 350 351 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script> 352 <script> 353 gtag('js', new Date()); 354 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode); 355 </script> 356 } 357 358 @if (!string.IsNullOrWhiteSpace(customHeaderInclude)) 359 { 360 @RenderPartial(customHeaderInclude) 361 } 362 </head> 363 <body class="brand @(masterTheme)" id="page@(Model.ID)"> 364 365 @* Google tag manager *@ 366 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking) 367 { 368 <noscript> 369 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)" 370 height="0" width="0" style="display:none;visibility:hidden"></iframe> 371 </noscript> 372 } 373 374 @if (renderAsResponsive || !renderMobile) 375 { 376 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop"> 377 @if (headerDesktopLink != null) 378 { 379 @RenderGrid(headerDesktopLink.PageId) 380 } 381 </header> 382 } 383 384 @if ((renderAsResponsive || renderMobile)) 385 { 386 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile"> 387 @if (headerMobileLink != null) 388 { 389 @RenderGrid(headerMobileLink.PageId) 390 } 391 </header> 392 } 393 394 <div data-intersect></div> 395 396 <main id="content" @(schemaOrgType)> 397 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 398 @using System 399 @using Dynamicweb.Ecommerce.ProductCatalog 400 401 402 @{ 403 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty; 404 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop"; 405 406 bool isArticlePagePage = Model.ItemType == "Swift_Article"; 407 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage"; 408 string schemaOrgProp = string.Empty; 409 if (isArticlePagePage) 410 { 411 schemaOrgProp = "itemprop=\"articleBody\""; 412 } 413 414 string theme = ""; 415 string gridContent = ""; 416 417 if (Model.PropertyItem != null) 418 { 419 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 420 } 421 422 if (Model.Item != null || Pageview.IsVisualEditorMode) 423 { 424 if (!isProductDetail) 425 { 426 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page"); 427 } 428 else 429 { 430 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId); 431 if (productObject != null) 432 { 433 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject?.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty; 434 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage"); 435 436 @RenderGrid(detailPageId) 437 } 438 } 439 } 440 441 bool doNotRenderPage = false; 442 443 //Check if we are on the poduct detail page, and if there is data to render 444 ProductViewModel product = new ProductViewModel(); 445 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 446 { 447 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 448 if (string.IsNullOrEmpty(product.Id)) 449 { 450 doNotRenderPage = true; 451 } 452 } 453 454 //Render the page 455 if (!doNotRenderPage) 456 { 457 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page"; 458 459 if (Pageview.IsVisualEditorMode) 460 { 461 @Model.Placeholder("dwcontent", "content", "default:true;sort:1") 462 } 463 464 <div class="@theme @itemIdentifier" @schemaOrgProp> 465 @if (isArticleListPage) 466 { 467 var hx = $"hx-get=\"{Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(Model.ID)}\" hx-select=\"#content\" hx-target=\"#content\" hx-swap=\"outerHTML\" hx-trigger=\"change\" hx-headers='{{\"feed\": \"true\"}}' hx-push-url=\"true\" hx-indicator=\"#ArticleFacetForm\""; 468 469 <form @hx id="ArticleFacetForm"> 470 @gridContent 471 </form> 472 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/htmx.js"></script> 473 <script type="module"> 474 document.addEventListener('htmx:confirm', (event) => { 475 let filters = event.detail.elt.querySelectorAll('select'); 476 for (var i = 0; i < filters.length; i++) { 477 let input = filters[i]; 478 if (input.name && !input.value) { 479 input.name = ''; 480 } 481 } 482 }); 483 484 document.addEventListener('htmx:beforeOnLoad', (event) => { 485 swift.Scroll.stopIntersectionObserver(); 486 }); 487 488 document.addEventListener('htmx:afterOnLoad', () => { 489 swift.Scroll.hideHeadersOnScroll(); 490 swift.Scroll.handleAlternativeTheme(); 491 }); 492 </script> 493 } 494 else 495 { 496 @gridContent 497 } 498 </div> 499 500 } 501 else 502 { 503 <div class="container"> 504 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div> 505 </div> 506 } 507 508 if (!Model.IsCurrentUserAllowed) 509 { 510 int signInPage = GetPageIdByNavigationTag("SignInPage"); 511 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage"); 512 513 if (!Pageview.IsVisualEditorMode) 514 { 515 if (signInPage != 0) 516 { 517 if (signInPage != Model.ID) 518 { 519 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage); 520 } 521 else 522 { 523 if (dashboardPage != 0) 524 { 525 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage); 526 } 527 else 528 { 529 Dynamicweb.Context.Current.Response.Redirect("/"); 530 } 531 } 532 } 533 else 534 { 535 <div class="alert alert-dark m-0" role="alert"> 536 <span>@Translate("You do not have access to this page")</span> 537 </div> 538 } 539 } 540 else 541 { 542 <div class="alert alert-dark m-0" role="alert"> 543 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span> 544 </div> 545 } 546 } 547 } 548 549 </main> 550 551 @if (renderAsResponsive || !renderMobile) 552 { 553 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop"> 554 @if (footerDesktopLink != null) 555 { 556 @RenderGrid(footerDesktopLink.PageId) 557 } 558 </footer> 559 } 560 561 @if (renderAsResponsive || renderMobile) 562 { 563 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile"> 564 @if (footerMobileLink != null) 565 { 566 @RenderGrid(footerMobileLink.PageId) 567 } 568 </footer> 569 } 570 571 @* Render any offcanvas menu here *@ 572 @RenderSnippet("offcanvas") 573 574 @{ 575 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]); 576 } 577 578 @* Language selector modal *@ 579 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true"> 580 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent"> 581 @* The content here comes from an external request *@ 582 </div> 583 </div> 584 585 @* Favorite toast *@ 586 <div aria-live="polite" aria-atomic="true"> 587 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11"> 588 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true"> 589 <div class="toast-header"> 590 <strong class="me-auto">@Translate("Favorite list updated")</strong> 591 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 592 </div> 593 <div class="toast-body d-flex gap-3"> 594 <div id="favoriteNotificationToast_Image"></div> 595 <div id="favoriteNotificationToast_Text"></div> 596 </div> 597 </div> 598 </div> 599 </div> 600 601 @* Modal for dynamic content *@ 602 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true"> 603 <div class="modal-dialog modal-dialog-centered modal-md"> 604 <div class="modal-content theme light" id="DynamicModalContent"> 605 @* The content here comes from an external request *@ 606 </div> 607 </div> 608 </div> 609 610 @* Offcanvas for dynamic content *@ 611 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas"> 612 @* The content here comes from an external request *@ 613 </div> 614 615 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"])) 616 { 617 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light"; 618 619 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040"> 620 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true"> 621 <div class="toast-header"> 622 <strong class="me-auto">@Translate("Connection down")</strong> 623 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 624 </div> 625 <div class="toast-body"> 626 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.") 627 </div> 628 </div> 629 </div> 630 } 631 632 @if (miniCartEnabled) 633 { 634 @* Open MiniCart when the cart is updated *@ 635 <script type="module"> 636 document.addEventListener('updated.swift.cart', (event) => { 637 let orderContext = event?.detail?.formData?.get("OrderContext"); 638 updateCartSummary(orderContext); 639 640 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") { 641 <text>openMiniCartOffcanvas();</text> 642 } 643 }); 644 </script> 645 646 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3") 647 { 648 @* Open MiniCart when toggle is clicked *@ 649 <script type="module"> 650 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity'); 651 miniCartToggles?.forEach((toggle) => { 652 toggle.parentElement.addEventListener('click', (event) => { 653 event.preventDefault(); 654 let orderContext = toggle.dataset?.orderContext; 655 updateCartSummary(orderContext); 656 657 openMiniCartOffcanvas(); 658 }); 659 }); 660 </script> 661 } 662 663 <script> 664 665 const updateCartSummary = (orderContext) => { 666 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 667 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas); 668 }; 669 670 const openMiniCartOffcanvas = () => { 671 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 672 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas); 673 dynamicOffcanvas.classList.add('overflow-y-auto'); 674 675 if (!miniCartOffcanvas._isShown) { 676 miniCartOffcanvas.show(); 677 hideActiveOffcanvases(miniCartOffcanvas); 678 } 679 }; 680 681 const hideActiveOffcanvases = (miniCartOffcanvas) => { 682 let activeOffcanvases = document.querySelectorAll('.offcanvas.show'); 683 activeOffcanvases?.forEach((offCanvas) => { 684 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas); 685 if (offCanvas !== miniCartOffcanvas) { 686 offCanvas.hide(); 687 } 688 }); 689 }; 690 691 </script> 692 } 693 694 </body> 695 696 </html> 697 698 } 699 else if (Pageview.IsVisualEditorMode) 700 { 701 <head> 702 <title>@Model.Title</title> 703 @* Bootstrap + Swift stylesheet *@ 704 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css"> 705 </head> 706 <body class="p-3"> 707 <div class="alert alert-danger" role="alert"> 708 @Translate("Basic Swift setup is needed!") 709 </div> 710 711 @if (brandingPage == null) 712 { 713 <div class="alert alert-warning" role="alert"> 714 @Translate("Please add a Branding page and reference it in website settings") 715 </div> 716 } 717 718 @if (themesParagraphs == null) 719 { 720 <div class="alert alert-warning" role="alert"> 721 @Translate("Please add a Themes collection page and reference it in website settings") 722 </div> 723 } 724 </body> 725 } 726 727 728 @functions { 729 void SetMetaTags() 730 { 731 //Verification Tokens 732 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : ""; 733 734 //Generic Site Values 735 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : ""; 736 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : ""; 737 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : ""; 738 739 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : ""; 740 741 //Page specific values 742 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : ""; 743 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image"); 744 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : ""; 745 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : ""; 746 747 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : ""; 748 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : ""; 749 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : ""; 750 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image"); 751 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : ""; 752 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}"; 753 754 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 755 { 756 if (!string.IsNullOrEmpty(Model.Description)) 757 { 758 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">"); 759 } 760 else 761 { 762 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">"); 763 } 764 765 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 766 { 767 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 768 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 769 } 770 else if (openGraphImage != null) 771 { 772 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 773 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 774 } 775 776 if (!string.IsNullOrEmpty(openGraphImageALT)) 777 { 778 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">"); 779 } 780 if (!string.IsNullOrEmpty(twitterCardDescription)) 781 { 782 Pageview.Meta.AddTag("twitter:description", twitterCardDescription); 783 } 784 785 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 786 { 787 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}"); 788 } 789 else if (twitterCardImage != null) 790 { 791 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}"); 792 } 793 794 if (!string.IsNullOrEmpty(twitterCardImageALT)) 795 { 796 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT); 797 } 798 } 799 800 if (!string.IsNullOrEmpty(siteVerificationGoogle)) 801 { 802 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle); 803 } 804 805 if (!string.IsNullOrEmpty(openGraphFacebookAppID)) 806 { 807 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">"); 808 } 809 810 if (!string.IsNullOrEmpty(openGraphType)) 811 { 812 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">"); 813 } 814 815 if (!string.IsNullOrEmpty(openGraphSiteName)) 816 { 817 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">"); 818 } 819 820 if (!string.IsNullOrEmpty(openGraphSiteName)) 821 { 822 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">"); 823 } 824 825 if (!string.IsNullOrEmpty(Model.Title)) 826 { 827 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">"); 828 } 829 else 830 { 831 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">"); 832 } 833 834 if (!string.IsNullOrEmpty(twitterCardSite)) 835 { 836 Pageview.Meta.AddTag("twitter:site", twitterCardSite); 837 } 838 839 if (!string.IsNullOrEmpty(twitterCardURL)) 840 { 841 Pageview.Meta.AddTag("twitter:url", twitterCardURL); 842 } 843 844 if (!string.IsNullOrEmpty(twitterCardTitle)) 845 { 846 Pageview.Meta.AddTag("twitter:title", twitterCardTitle); 847 } 848 } 849 } 850