Error executing template "Designs/Swift/_parsed/Swift_Page.parsed.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_22755aa3cd6d49a0a6dd35de8af560f8.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.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, 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 RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String templateSource, 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()

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