Error executing template "Designs/Swift/Swift_Page.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 (64): 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.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.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.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)
   at CompiledRazorTemplates.Dynamic.RazorEngine_536b6bef34d340e5b4fd527215c13ace.ExecuteAsync()
   at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   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 @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 = !string.IsNullOrEmpty(Model.Area.Item.GetRawValueString("CustomHeaderInclude")) ? Model.Area.Item.GetFile("CustomHeaderInclude").Name : string.Empty; 75 76 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 77 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt; 78 79 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css")); 80 81 82 if (cssPageId != 0) 83 { 84 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css")); 85 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 86 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt) 87 { 88 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId); 89 cssPageview.Redirect = false; 90 cssPageview.Output(); 91 } 92 } 93 94 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt) 95 { 96 //Branding page has been saved or the file is missing. Rewrite the file to disc. 97 if (brandingPageId > 0) 98 { 99 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId); 100 brandingPageview.Redirect = false; 101 brandingPageview.Output(); 102 } 103 } 104 105 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt) 106 { 107 //Branding page has been saved or the file is missing. Rewrite the file to disc. 108 if (themePageId > 0) 109 { 110 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId); 111 themePageview.Redirect = false; 112 themePageview.Output(); 113 } 114 } 115 116 // Schema.org details for PDP 117 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID"); 118 bool isArticlePage = Model.ItemType == "Swift_Article"; 119 string schemaOrgType = string.Empty; 120 121 if (isProductDetailsPage) 122 { 123 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\""; 124 } 125 126 if (isArticlePage) 127 { 128 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\""; 129 } 130 131 // Has ContactID? - used with ActiveCampaign 132 var ContactId = Dynamicweb.Context.Current.Request.QueryString["ContactId"]; 133 if (!string.IsNullOrWhiteSpace(ContactId)) 134 { 135 Dynamicweb.Environment.CookieManager.SetCookie("ContactId", ContactId, DateTime.Now.AddYears(1)); 136 } 137 138 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css")); 139 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js")); 140 var jsMainFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/main.js")); 141 142 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 143 144 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png"); 145 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png"); 146 147 string headerCssClass = "sticky-top"; 148 bool movePageBehind = false; 149 150 if (Model.PropertyItem != null) 151 { 152 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top"); 153 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false; 154 } 155 156 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass; 157 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass; 158 159 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim(); 160 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim(); 161 162 bool allowTracking = AllowTracking(); 163 164 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;"); 165 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;"); 166 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;"); 167 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/main.js?{jsMainFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;"); 168 169 170 SetMetaTags(); 171 172 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>(); 173 174 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage; 175 languages.Add(masterPage); 176 if (masterPage?.Languages != null) 177 { 178 foreach (var language in masterPage.Languages) 179 { 180 languages.Add(language); 181 } 182 } 183 184 Uri url = Dynamicweb.Context.Current.Request.Url; 185 string hostName = url.Host; 186 187 <!doctype html> 188 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName"> 189 <head> 190 <!-- @swiftVersion --> 191 @* Required meta tags *@ 192 <meta charset="utf-8"> 193 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0"> 194 <link rel="shortcut icon" href="@favicon"> 195 <link rel="apple-touch-icon" href="@appleTouchIcon"> 196 197 @Model.MetaTags 198 199 @{ 200 var alreadyWrittenTwoletterIsos = new List<string>(); 201 @* Languages meta data *@ 202 foreach (var language in languages) 203 { 204 hostName = url.Host; 205 if (language?.Area != null) 206 { 207 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock)) 208 { 209 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk 210 } 211 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published) 212 { 213 if (!string.IsNullOrEmpty(language.Area.DomainLock)) 214 { 215 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk 216 } 217 string querystring = $"Default.aspx?ID={language.ID}"; 218 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"])) 219 { 220 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}"; 221 } 222 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 223 { 224 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}"; 225 } 226 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"])) 227 { 228 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}"; 229 } 230 231 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring); 232 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1) 233 { 234 friendlyUrl = "/"; 235 } 236 string href = $"{url.Scheme}://{hostName}{friendlyUrl}"; 237 238 var hreflang = language.Area.CultureInfo.Name.ToLower(); 239 if(language.Area.EcomLanguageId == "LANG7") 240 { 241 hreflang = "en-150"; 242 } 243 244 if (!alreadyWrittenTwoletterIsos.Contains(hreflang)) 245 { 246 alreadyWrittenTwoletterIsos.Add(hreflang); 247 <link rel="alternate" hreflang="@hreflang" href="@href.TrimEnd('/')"> 248 } 249 } 250 } 251 } 252 } 253 254 <title>@Model.Title</title> 255 @* Bootstrap + Swift stylesheet *@ 256 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css"> 257 @* <style>pre.dw-error { display:none; }</style> *@ 258 @if (disableWideBreakpoints != "disableBoth") 259 { 260 <style> 261 @@media ( min-width: 1600px ) { 262 .container-xxl, 263 .container-xl, 264 .container-lg, 265 .container-md, 266 .container-sm, 267 .container { 268 max-width: 1520px; 269 } 270 } 271 </style> 272 273 274 275 if (disableWideBreakpoints != "disableUltraWideOnly") 276 { 277 <style> 278 @@media ( min-width: 1920px ) { 279 .container-xxl, 280 .container-xl, 281 .container-lg, 282 .container-md, 283 .container-sm, 284 .container { 285 max-width: 1820px; 286 } 287 } 288 </style> 289 } 290 } 291 292 @* Branding and Themes min stylesheet *@ 293 <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"> 294 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script> 295 <script src="/Files/Templates/Designs/Swift/Assets/js/main.js?@jsMainFileInfo.LastWriteTime.Ticks"></script> 296 <script type="module"> 297 swift.Scroll.hideHeadersOnScroll(); 298 swift.Scroll.handleAlternativeTheme(); 299 300 //Only load if AOS 301 const aosColumns = document.querySelectorAll('[data-aos]'); 302 if (aosColumns.length > 0) { 303 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js'); 304 document.addEventListener('load.swift.assetloader', function () { 305 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') }); 306 }); 307 } 308 </script> 309 310 @* Google gtag method - always include even if it is not used for anything *@ 311 <script> 312 window.dataLayer = window.dataLayer || []; 313 function gtag() { 314 //dataLayer.push(arguments); 315 if(arguments[2] && arguments[2]?.items) { 316 // try update items 317 // arguments[2]?.items?.forEach(itm => { 318 // const itm_brand = document.querySelector('[data-gtagbrand="'+itm.item_id+'"]')?.innerText; 319 // if(itm_brand) { 320 // itm['item_brand'] = itm_brand; 321 // } 322 // }); 323 324 dataLayer.push({ ecommerce: null }); 325 dataLayer.push({ 326 event: arguments[1], 327 ecommerce: arguments[2] 328 }); 329 } else { 330 dataLayer.push(arguments); 331 } 332 } 333 </script> 334 335 @if (!string.IsNullOrWhiteSpace(customHeaderInclude)) 336 { 337 @RenderPartial($"Components/Custom/{customHeaderInclude}") 338 } 339 <style> 340 .item_swift_productlistitemrepeater { 341 font-size: 0.85rem; 342 } 343 .grid > * { 344 min-width: 0 !important; 345 } 346 article.product:hover .border-hover-primary { 347 border: 1px solid var(--swift-button-primary-background-color)!important; 348 } 349 .image-overlay { 350 position: relative; 351 } 352 .image-overlay:after { 353 content: ""; 354 position: absolute; 355 top: 0; 356 left: 0; 357 width: 100%; 358 height: 100%; 359 pointer-events: none; 360 background: #0004; 361 } 362 .image-overlay-left:after { 363 background: radial-gradient(ellipse at bottom left, #0009 0%, #0000 60%); 364 } 365 .image-overlay-right:after { 366 background: radial-gradient(ellipse at bottom left, #0009 0%, #0000 60%); 367 } 368 @@media (min-width: 992px) { 369 .component-sticky { 370 position: sticky; 371 top: var(--header-height); 372 height: auto !important; 373 } 374 375 .modal-open .component-sticky { 376 position: static; 377 } 378 } 379 </style> 380 </head> 381 <body class="brand @(masterTheme)" id="page@(Model.ID)"> 382 383 @* Google tag manager *@ 384 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking) 385 { 386 <noscript> 387 <iframe src="@googleTagManagerID" height="0" width="0" style="display:none;visibility:hidden"></iframe> 388 </noscript> 389 } 390 391 @if (renderAsResponsive || !renderMobile) 392 { 393 var IsCatalogPage = Pageview.Page.ItemType == "Swift_CatalogPage"; 394 395 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop"> 396 @if (IsCatalogPage) 397 { 398 // Current page path. Page Id and title 399 var PagePath = Pageview.Page.GetPath() 400 .Select(a => new KeyValuePair<int, string>(a.ID, a.MenuText)) 401 .ToDictionary(x => x.Key, x => x.Value); 402 403 var CatalogHeader = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Pageview.Area.ID, "CatalogHeader"); 404 var RootpathBrandname = PagePath.Skip(3).FirstOrDefault().Value; 405 var BrandName = RootpathBrandname?.ToLower() switch 406 { 407 "outwell" => "Swift_styles_3", 408 "robens" => "Swift_styles_4", 409 "easy camp" => "Swift_styles_2", 410 _ => "" 411 }; 412 <link href="/Files/Templates/Designs/Swift/_parsed/Swift_css/@(BrandName).min.css?@cssLastModified.Ticks" rel="stylesheet" media="all" type="text/css" data-last-modified-content="@cssLastModified"> 413 @RenderGrid(CatalogHeader.ID) 414 } else 415 { 416 if (headerDesktopLink != null) 417 { 418 @RenderGrid(headerDesktopLink.PageId) 419 } 420 } 421 </header> 422 } 423 424 @if ((renderAsResponsive || renderMobile)) 425 { 426 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile"> 427 @if (headerMobileLink != null) 428 { 429 @RenderGrid(headerMobileLink.PageId) 430 } 431 </header> 432 } 433 434 <div data-intersect></div> 435 436 <main id="content" style="@(Pageview.AreaID != 29 ? "user-select:none;" : "")" @(schemaOrgType)> 437 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 438 @using System 439 @using Dynamicweb.Ecommerce.ProductCatalog 440 @using Oase.Backend.Extensions 441 442 443 @{ 444 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty; 445 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop"; 446 447 bool isArticlePagePage = Model.ItemType == "Swift_Article"; 448 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage"; 449 string schemaOrgProp = string.Empty; 450 if(isArticlePagePage) 451 { 452 schemaOrgProp = "itemprop=\"articleBody\""; 453 } 454 455 string theme = ""; 456 string gridContent = ""; 457 458 if (Model.PropertyItem != null) 459 { 460 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 461 } 462 463 if (Model.Item != null || Pageview.IsVisualEditorMode) 464 { 465 if (!isProductDetail) 466 { 467 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page"); 468 } 469 else 470 { 471 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId); 472 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty; 473 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage"); 474 475 @RenderGrid(detailPageId) 476 } 477 } 478 479 bool doNotRenderPage = false; 480 481 //Check if we are on the poduct detail page, and if there is data to render 482 ProductViewModel product = new ProductViewModel(); 483 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 484 { 485 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 486 if (string.IsNullOrEmpty(product.Id)) { 487 doNotRenderPage = true; 488 } 489 if (product!.ProductFields.TryGetValue("PublicationStart", out FieldValueViewModel? PublicationStart)) 490 { 491 DateTime.TryParse(PublicationStart.Value.ToString(), out DateTime PublicationStartDate); 492 if (PublicationStartDate >= DateTime.Now) 493 { 494 var shopPageId = GetPageIdByNavigationTag("Shop"); 495 Dynamicweb.Context.Current.Response.Redirect($"/Default.aspx?ID={shopPageId}&GroupID={product.PrimaryOrDefaultGroup.Id}"); 496 } 497 } 498 } 499 if(!string.IsNullOrWhiteSpace(productIdFromUrl)) 500 { 501 <script> 502 503 gtag("event", "view_item", { 504 currency: "@product.Price.CurrencyCode", 505 value: @PriceViewModelExtensions.ToStringInvariant(product.Price), 506 items: [ 507 { 508 item_id: "@product.Id", 509 item_name: "@Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(product.Name)", 510 item_brand: "@product.ProductFields.GetValueOrDefault("Collection")?.Value", 511 currency: "@product.Price.CurrencyCode", 512 price: @PriceViewModelExtensions.ToStringInvariant(product.Price) 513 } 514 ] 515 }); 516 </script> 517 } 518 519 // Custom authorization 520 var AllowUserWith = Model?.PropertyItem?.GetString("AllowUserWith", ""); 521 if (!string.IsNullOrWhiteSpace(AllowUserWith)) 522 { 523 var currentUserValue = Dynamicweb.Security.UserManagement.UserContext.Current.User?.GetCustomFieldValue($"{AllowUserWith}"); 524 if (currentUserValue == false) 525 { 526 doNotRenderPage = true; 527 } 528 } 529 530 //Render the page 531 if (!doNotRenderPage) 532 { 533 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page"; 534 535 if (Pageview.IsVisualEditorMode) { 536 @Model.Placeholder("dwcontent", "content", "default:true;sort:1") 537 } 538 <div class="@theme @itemIdentifier" @schemaOrgProp> 539 @if (isArticleListPage) 540 { 541 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\""; 542 543 <form @hx id="ArticleFacetForm"> 544 @gridContent 545 </form> 546 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/htmx.js"></script> 547 <script type="module"> 548 document.addEventListener('htmx:confirm', (event) => { 549 let filters = event.detail.elt.querySelectorAll('select'); 550 for (var i = 0; i < filters.length; i++) { 551 let input = filters[i]; 552 if (input.name && !input.value) { 553 input.name = ''; 554 } 555 } 556 }); 557 558 document.addEventListener('htmx:beforeOnLoad', (event) => { 559 swift.Scroll.stopIntersectionObserver(); 560 }); 561 562 document.addEventListener('htmx:afterOnLoad', () => { 563 swift.Scroll.hideHeadersOnScroll(); 564 swift.Scroll.handleAlternativeTheme(); 565 }); 566 </script> 567 } 568 else 569 { 570 @gridContent 571 } 572 </div> 573 <style> 574 @@media (max-width: 991.98px) { 575 .item_custom_swift_productaddtocart.is-sticky { 576 position: fixed; 577 top: var(--header-height); 578 left: 0; 579 right: 0; 580 max-width: 100vw!important; 581 z-index: 1060; 582 padding: 0.5rem 1rem; 583 background: #fff; 584 box-shadow: 0 2px 10px rgba(0,0,0,0.1); 585 } 586 587 .item_custom_swift_productaddtocart-placeholder { 588 display: none; 589 } 590 591 .item_custom_swift_productaddtocart-placeholder.active { 592 display: block; 593 } 594 595 .offcanvas { 596 z-index: 1070!important; 597 } 598 } 599 </style> 600 } else { 601 <div class="container py-5"> 602 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div> 603 </div> 604 } 605 606 if (!Model.IsCurrentUserAllowed) 607 { 608 int signInPage = GetPageIdByNavigationTag("SignInPage"); 609 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage"); 610 611 if (!Pageview.IsVisualEditorMode) 612 { 613 if (signInPage != 0) 614 { 615 if (signInPage != Model.ID) { 616 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage); 617 } else { 618 if (dashboardPage != 0) { 619 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage); 620 } else { 621 Dynamicweb.Context.Current.Response.Redirect("/"); 622 } 623 } 624 } 625 else 626 { 627 <div class="alert alert-dark m-0" role="alert"> 628 <span>@Translate("You do not have access to this page")</span> 629 </div> 630 } 631 } 632 else 633 { 634 <div class="alert alert-dark m-0" role="alert"> 635 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span> 636 </div> 637 } 638 } 639 } 640 641 </main> 642 643 <link rel="stylesheet" href="/Files/Templates/Designs/Swift/Assets/css/glightbox.min.css" /> 644 <script src="/Files/Templates/Designs/Swift/Assets/js/glightbox.min.js"></script> 645 <script> 646 var lightbox = GLightbox({ 647 touchNavigation: true, 648 loop: false, 649 autoplayVideos: true, 650 videosWidth: '80vw', 651 dragAutoSnap: true, 652 plyr: { 653 config: { 654 quality: 720, 655 muted: false, 656 volume: 100, 657 youtube: { noCookie: true, rel: 0, showinfo: 0, iv_load_policy: 3, modestbranding: 1 } 658 } 659 } 660 }); 661 </script> 662 <script> 663 document.addEventListener('DOMContentLoaded', () => { 664 document.querySelectorAll('a').forEach(link => { 665 const href = link.getAttribute('href'); 666 if (href && href.startsWith('https')) { 667 link.setAttribute('target', '_blank'); 668 } else { 669 link.setAttribute('target', '_self'); 670 } 671 }); 672 }); 673 </script> 674 675 @if (renderAsResponsive || !renderMobile) 676 { 677 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop"> 678 @if (footerDesktopLink != null) 679 { 680 @RenderGrid(footerDesktopLink.PageId) 681 } 682 </footer> 683 } 684 685 @if (renderAsResponsive || renderMobile) 686 { 687 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile"> 688 @if (footerMobileLink != null) 689 { 690 @RenderGrid(footerMobileLink.PageId) 691 } 692 </footer> 693 } 694 695 @* Render any offcanvas menu here *@ 696 @RenderSnippet("offcanvas") 697 698 @{ 699 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]); 700 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 701 } 702 703 @* Language selector modal *@ 704 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true"> 705 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent"> 706 @* The content here comes from an external request *@ 707 </div> 708 </div> 709 710 @* Toast *@ 711 <div aria-live="polite" aria-atomic="true"> 712 <div class="toast-container position-fixed end-0 p-3" style="top:50px;z-index:1500;"> 713 <div id="notificationToast" class="toast rounded-6 overflow-hidden" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="1000"> 714 <div class="toast-body d-flex align-items-end gap-3 theme theme-gray bg-dark text-light"> 715 @ReadFile(iconPath + "check.svg") 716 <div id="notificationToast_Text" class=""></div> 717 </div> 718 </div> 719 </div> 720 </div> 721 722 @* Modal for dynamic content *@ 723 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true"> 724 <div class="modal-dialog modal-dialog-centered modal-md"> 725 <div class="modal-content theme light" id="DynamicModalContent"> 726 @* The content here comes from an external request *@ 727 </div> 728 </div> 729 </div> 730 731 @* Offcanvas for dynamic content *@ 732 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas"> 733 @* The content here comes from an external request *@ 734 </div> 735 736 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"])) 737 { 738 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light"; 739 740 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040"> 741 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true"> 742 <div class="toast-header"> 743 <strong class="me-auto">@Translate("Connection down")</strong> 744 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 745 </div> 746 <div class="toast-body"> 747 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.") 748 </div> 749 </div> 750 </div> 751 } 752 753 @if (miniCartEnabled) 754 { 755 @* Open MiniCart when the cart is updated *@ 756 <script type="module"> 757 document.addEventListener('updated.swift.cart', (event) => { 758 let orderContext = event?.detail?.formData?.get("OrderContext"); 759 updateCartSummary(orderContext); 760 761 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") { 762 <text>openMiniCartOffcanvas();</text> 763 } 764 }); 765 </script> 766 767 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3") 768 { 769 @* Open MiniCart when toggle is clicked *@ 770 <script type="module"> 771 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity'); 772 miniCartToggles?.forEach((toggle) => { 773 toggle.parentElement.addEventListener('click', (event) => { 774 event.preventDefault(); 775 let orderContext = toggle.dataset?.orderContext; 776 updateCartSummary(orderContext); 777 778 openMiniCartOffcanvas(); 779 }); 780 }); 781 </script> 782 } 783 784 <script> 785 786 const updateCartSummary = (orderContext) => { 787 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 788 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas); 789 }; 790 791 const openMiniCartOffcanvas = () => { 792 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 793 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas); 794 dynamicOffcanvas.classList.add('overflow-y-auto'); 795 796 if (!miniCartOffcanvas._isShown) { 797 miniCartOffcanvas.show(); 798 hideActiveOffcanvases(miniCartOffcanvas); 799 } 800 }; 801 802 const hideActiveOffcanvases = (miniCartOffcanvas) => { 803 let activeOffcanvases = document.querySelectorAll('.offcanvas.show'); 804 activeOffcanvases?.forEach((offCanvas) => { 805 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas); 806 if (offCanvas !== miniCartOffcanvas) { 807 offCanvas.hide(); 808 } 809 }); 810 }; 811 812 </script> 813 } 814 @if (Pageview.Area.Name?.StartsWith("Xhelter") == false && Pageview.Area.Name?.StartsWith("Oase") == false) 815 { 816 <p class="d-none">@Pageview.Area.Name</p> 817 @RenderPartial("Components/Custom/CustomLanguageModal.cshtml") 818 } 819 </body> 820 821 </html> 822 823 } 824 else if (Pageview.IsVisualEditorMode) 825 { 826 <head> 827 <title>@Model.Title</title> 828 @* Bootstrap + Swift stylesheet *@ 829 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css"> 830 </head> 831 <body class="p-3"> 832 <div class="alert alert-danger" role="alert"> 833 @Translate("Basic Swift setup is needed!") 834 </div> 835 836 @if (brandingPage == null) 837 { 838 <div class="alert alert-warning" role="alert"> 839 @Translate("Please add a Branding page and reference it in website settings") 840 </div> 841 } 842 843 @if (themesParagraphs == null) 844 { 845 <div class="alert alert-warning" role="alert"> 846 @Translate("Please add a Themes collection page and reference it in website settings") 847 </div> 848 } 849 </body> 850 } 851 852 853 @functions { 854 void SetMetaTags() 855 { 856 //Verification Tokens 857 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : ""; 858 string siteVerificationFacebook = Model.Area.Item.GetString("Facebook_Site_Verification") != null ? Model.Area.Item.GetString("Facebook_Site_Verification") : ""; 859 860 //Generic Site Values 861 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : ""; 862 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : ""; 863 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : ""; 864 865 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : ""; 866 867 //Page specific values 868 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : ""; 869 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image"); 870 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : ""; 871 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : ""; 872 873 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : ""; 874 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : ""; 875 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : ""; 876 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image"); 877 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : ""; 878 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}"; 879 880 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 881 { 882 if (!string.IsNullOrEmpty(Model.Description)) 883 { 884 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">"); 885 } 886 else 887 { 888 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">"); 889 } 890 891 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 892 { 893 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 894 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 895 } 896 else if (openGraphImage != null) 897 { 898 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 899 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 900 } 901 902 if (!string.IsNullOrEmpty(openGraphImageALT)) 903 { 904 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">"); 905 } 906 if (!string.IsNullOrEmpty(twitterCardDescription)) 907 { 908 Pageview.Meta.AddTag("twitter:description", twitterCardDescription); 909 } 910 911 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 912 { 913 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}"); 914 } 915 else if (twitterCardImage != null) 916 { 917 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}"); 918 } 919 920 if (!string.IsNullOrEmpty(twitterCardImageALT)) 921 { 922 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT); 923 } 924 } 925 926 if (!string.IsNullOrEmpty(siteVerificationGoogle)) 927 { 928 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle); 929 } 930 931 if (!string.IsNullOrEmpty(siteVerificationFacebook)) 932 { 933 Pageview.Meta.AddTag("facebook-domain-verification", siteVerificationFacebook); 934 } 935 936 if (!string.IsNullOrEmpty(openGraphFacebookAppID)) 937 { 938 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">"); 939 } 940 941 if (!string.IsNullOrEmpty(openGraphType)) 942 { 943 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">"); 944 } 945 946 if (!string.IsNullOrEmpty(openGraphSiteName)) 947 { 948 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">"); 949 } 950 951 if (!string.IsNullOrEmpty(openGraphSiteName)) 952 { 953 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">"); 954 } 955 956 if (!string.IsNullOrEmpty(Model.Title)) 957 { 958 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">"); 959 } 960 else 961 { 962 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">"); 963 } 964 965 if (!string.IsNullOrEmpty(twitterCardSite)) 966 { 967 Pageview.Meta.AddTag("twitter:site", twitterCardSite); 968 } 969 970 if (!string.IsNullOrEmpty(twitterCardURL)) 971 { 972 Pageview.Meta.AddTag("twitter:url", twitterCardURL); 973 } 974 975 if (!string.IsNullOrEmpty(twitterCardTitle)) 976 { 977 Pageview.Meta.AddTag("twitter:title", twitterCardTitle); 978 } 979 } 980 } 981