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