Error executing template "Designs/Swift/_parsed/Swift_CustomerCenter.parsed.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_8a41c281c0324dd78b359c9592dd24e7.Execute() in C:\inetpub\wwwroot\directions2023_dev\Files\Templates\Designs\Swift\_parsed\Swift_CustomerCenter.parsed.cshtml:line 669
   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()

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 2 @using System 3 @using Dynamicweb 4 @using Dynamicweb.Environment 5 @using Dynamicweb.Frontend 6 @using DirectionsEMEA.Domain.Models.DW.OTP 7 @using DirectionsEMEA.Infrastructure.Facade 8 @using DirectionsEMEA.Infrastructure.Config 9 10 @functions { 11 string GetCookieOptInPermission(string category) 12 { 13 bool categoryOrAllGranted = false; 14 15 if (CookieManager.IsCookieManagementActive) 16 { 17 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 18 var cookieOptInCategories = CookieManager.GetCookieOptInCategories(); 19 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All; 20 21 } 22 23 return categoryOrAllGranted ? "granted" : "denied"; 24 } 25 26 bool AllowTracking() 27 { 28 bool allowTracking = true; 29 if (CookieManager.IsCookieManagementActive) 30 { 31 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 32 var cookieOptInCategories = CookieManager.GetCookieOptInCategories(); 33 34 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing")); 35 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional; 36 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither); 37 38 allowTracking = consentAtLeastOne; 39 } 40 return allowTracking; 41 } 42 } 43 44 @{ 45 46 //CUSTOM CODE 47 //handle Maintenance mode 48 var maintenancePage = Model.Area.Item?.GetLink("MaintenancePage") ?? null; 49 bool maintenanceMode = Model.Area.Item.GetBoolean("MaintenanceMode"); 50 DateTime maintenanceStartDate = Model.Area.Item.GetDateTime("MaintenanceStartDate"); 51 DateTime maintenanceEndDate = Model.Area.Item.GetDateTime("MaintenanceEndDate"); 52 DateTime currentDate = System.DateTime.Now; 53 maintenanceMode = maintenanceMode && maintenanceStartDate <= currentDate && maintenanceEndDate >= currentDate; 54 var adminUser = Dynamicweb.Security.UserManagement.User.GetCurrentBackendUser(); 55 int currentPage = Dynamicweb.Frontend.PageView.Current().Page.ID; 56 57 if(maintenanceMode && maintenancePage != null && adminUser == null && maintenancePage.PageId != currentPage) 58 { 59 string redirectLink = "/" + maintenancePage; 60 Dynamicweb.Context.Current.Response.Redirect(redirectLink); 61 } 62 63 //CUSTOM CODE 64 65 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID; 66 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false; 67 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3"; 68 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart; 69 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0; 70 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0; 71 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0; 72 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null; 73 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null; 74 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null; 75 76 //CUSTOM CODE 77 var backgroundPageId = Model.Area.Item?.GetInt32("BackgroundsPage") ?? 0; 78 var backgroundParagraphs = backgroundPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(backgroundPageId) ?? null : null; 79 //CUSTOM CODE 80 81 // OTP 82 var request = Context.Current.Request; 83 bool isPostBack = request.HttpMethod == "POST"; 84 85 string email = request.Form["Email"] ?? ""; 86 string code = request.Form["Code"] ?? ""; 87 string action = request.Form["Action"] ?? ""; 88 89 string message = ""; 90 bool showCodeInput = false; 91 92 if (Context.Current.Session["OTP_Email"] != null) 93 { 94 email = Context.Current.Session["OTP_Email"].ToString(); 95 showCodeInput = true; 96 } 97 98 if (isPostBack) 99 { 100 if (action == "Send") 101 { 102 var result = AuthenticationFacade.RequestOTP(email); 103 if (result.Success) 104 { 105 Context.Current.Session["OTP_Email"] = email; 106 showCodeInput = true; 107 message = "✅ Code sent to your email!"; 108 } 109 else 110 { 111 message = "❌ " + result.Message; 112 } 113 } 114 else if (action == "Verify") 115 { 116 var result = AuthenticationFacade.VerifyOTP(email, code); 117 if (result.IsValid && result.User != null) 118 { 119 bool isUserAuth = AuthenticationFacade.LoginUser(result.User , LoginType.OTP); 120 Context.Current.Session.Remove("OTP_Email"); 121 Context.Current.Response.Redirect("/"); 122 return; 123 } 124 else 125 { 126 message = "❌ " + result.Message; 127 } 128 } 129 else if (action == "Reset") 130 { 131 Context.Current.Session.Remove("OTP_Email"); 132 showCodeInput = false; 133 email = ""; 134 message = ""; 135 } 136 } 137 138 var otpEmailFromSession = Context.Current?.Session["OTP_Email"]?.ToString() ?? ""; 139 var config = DirectionsConfig.GetFromDynamicweb(); 140 int otpCodeMaxAttempts = config.OTP.CodeMaxAttempts; 141 var otpCodeExpiryMins = config.OTP.CodeExpiryMinutes; 142 var codeExpiresMessage = Translate("Code expires in") + " " + otpCodeExpiryMins + " " + Translate("minutes"); 143 bool disableVerifyButton = message.Contains("attempts") && message.Contains("0"); 144 var otpRedirectPage = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetPageIdByNavigationTag("MyAccountDashboardPageInactive")); 145 } 146 147 @if (themesParagraphs != null || brandingPage != null) 148 { 149 string swiftVersion = ReadFile("/Files/Templates/Designs/Swift/swift_version.txt"); 150 bool renderAsResponsive = Model.Area.Item.GetString("DeviceRendering", "responsive").Equals("responsive", StringComparison.OrdinalIgnoreCase); 151 bool renderMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet; 152 string responsiveClassDesktop = string.Empty; 153 string responsiveClassMobile = string.Empty; 154 if (renderAsResponsive) 155 { 156 responsiveClassDesktop = " d-none d-xl-block"; 157 responsiveClassMobile = " d-block d-xl-none"; 158 } 159 160 var headerDesktopLink = Model.Area.Item?.GetLink("HeaderDesktop") ?? null; 161 var headerMobileLink = Model.Area.Item?.GetLink("HeaderMobile") ?? null; 162 163 var footerDesktopLink = Model.Area.Item?.GetLink("FooterDesktop") ?? null; 164 var footerMobileLink = Model.Area.Item?.GetLink("FooterMobile") ?? null; 165 166 var disableWideBreakpoints = Model.Area?.Item?.GetRawValueString("DisableWideBreakpoints", "default"); 167 168 string customHeaderInclude = !string.IsNullOrEmpty(Model.Area.Item.GetRawValueString("CustomHeaderInclude")) ? Model.Area.Item.GetFile("CustomHeaderInclude").Name : string.Empty; 169 170 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 171 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt; 172 173 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css")); 174 175 //CUSTOM CODE 176 //Create a collection with all last modified dates 177 List<DateTime> filesAudit = new List<DateTime>(); 178 if(brandingPage != null) 179 { 180 filesAudit.Add(brandingPage.Audit.LastModifiedAt); 181 } 182 if(backgroundParagraphs != null) 183 { 184 var backgroundParagraphLastChanged = backgroundParagraphs.OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 185 filesAudit.Add(backgroundParagraphLastChanged.Audit.LastModifiedAt); 186 } 187 188 cssLastModified = filesAudit.Max(); 189 190 if (backgroundPageId != 0) 191 { 192 var backgroundFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_backgrounds_styles_{Model.Area.ID}.css")); 193 194 if(backgroundParagraphs.Any() && !backgroundFileInfo.Exists) 195 { 196 197 var backgroundParagraphLastChanged = backgroundParagraphs.OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 198 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < backgroundParagraphLastChanged.Audit.LastModifiedAt) 199 { 200 201 var backgroundPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(backgroundPageId); 202 backgroundPageview.Redirect = false; 203 backgroundPageview.Output(); 204 } 205 } 206 } 207 208 //CUSTOM CODE 209 210 if (cssPageId != 0) 211 { 212 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css")); 213 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault(); 214 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt) 215 { 216 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId); 217 cssPageview.Redirect = false; 218 cssPageview.Output(); 219 220 var backgroundPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(backgroundPageId); 221 backgroundPageview.Redirect = false; 222 backgroundPageview.Output(); 223 } 224 } 225 226 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt) 227 { 228 //Branding page has been saved or the file is missing. Rewrite the file to disc. 229 if (brandingPageId > 0) 230 { 231 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId); 232 brandingPageview.Redirect = false; 233 brandingPageview.Output(); 234 } 235 } 236 237 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt) 238 { 239 //Branding page has been saved or the file is missing. Rewrite the file to disc. 240 if (themePageId > 0) 241 { 242 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId); 243 themePageview.Redirect = false; 244 themePageview.Output(); 245 } 246 } 247 248 // Schema.org details for PDP 249 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID"); 250 bool isArticlePage = Model.ItemType == "Swift_Article"; 251 string schemaOrgType = string.Empty; 252 253 if (isProductDetailsPage) 254 { 255 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\""; 256 } 257 258 if (isArticlePage) 259 { 260 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\""; 261 } 262 263 264 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css")); 265 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js")); 266 //CUSTOM CODE// 267 var customJsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("Files/Templates/Designs/Swift/Assets/js/custom-scripts.js")); 268 //CUSTOM CODE// 269 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 270 271 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png"); 272 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png"); 273 274 string headerCssClass = "sticky-top"; 275 bool movePageBehind = false; 276 277 if (Model.PropertyItem != null) 278 { 279 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top"); 280 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false; 281 } 282 283 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass; 284 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass; 285 286 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim(); 287 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim(); 288 289 bool allowTracking = AllowTracking(); 290 291 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;"); 292 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;"); 293 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;"); 294 //CUSTOM CODE 295 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/custom-scripts.js?{customJsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;"); 296 //CUSTOM CODE 297 298 SetMetaTags(); 299 300 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>(); 301 302 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage; 303 languages.Add(masterPage); 304 if (masterPage?.Languages != null) 305 { 306 foreach (var language in masterPage.Languages) 307 { 308 languages.Add(language); 309 } 310 } 311 312 Uri url = Dynamicweb.Context.Current.Request.Url; 313 string hostName = url.Host; 314 315 <!doctype html> 316 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName"> 317 <head> 318 <!-- @swiftVersion --> 319 @* Required meta tags *@ 320 <meta charset="utf-8"> 321 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0"> 322 <link rel="shortcut icon" href="@favicon"> 323 <link rel="apple-touch-icon" href="@appleTouchIcon"> 324 325 @Model.MetaTags 326 327 @{ 328 var alreadyWrittenTwoletterIsos = new List<string>(); 329 @* Languages meta data *@ 330 foreach (var language in languages) 331 { 332 hostName = url.Host; 333 if (language?.Area != null) 334 { 335 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock)) 336 { 337 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk 338 } 339 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published) 340 { 341 if (!string.IsNullOrEmpty(language.Area.DomainLock)) 342 { 343 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk 344 } 345 string querystring = $"Default.aspx?ID={language.ID}"; 346 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"])) 347 { 348 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}"; 349 } 350 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 351 { 352 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}"; 353 } 354 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"])) 355 { 356 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}"; 357 } 358 359 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring); 360 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1) 361 { 362 friendlyUrl = "/"; 363 } 364 string href = $"{url.Scheme}://{hostName}{friendlyUrl}"; 365 366 367 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href"> 368 if (!alreadyWrittenTwoletterIsos.Contains(language.Area.CultureInfo.TwoLetterISOLanguageName)) 369 { 370 alreadyWrittenTwoletterIsos.Add(language.Area.CultureInfo.TwoLetterISOLanguageName); 371 <link rel="alternate" hreflang="@language.Area.CultureInfo.TwoLetterISOLanguageName.ToLower()" href="@href"> 372 } 373 } 374 } 375 } 376 } 377 378 <title>@Model.Title</title> 379 @* Bootstrap + Swift stylesheet *@ 380 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css"> 381 382 @if (disableWideBreakpoints != "disableBoth") 383 { 384 <style> 385 @@media ( min-width: 1600px ) { 386 .container-xxl, 387 .container-xl, 388 .container-lg, 389 .container-md, 390 .container-sm, 391 .container { 392 max-width: 1520px; 393 } 394 } 395 </style> 396 397 398 399 if (disableWideBreakpoints != "disableUltraWideOnly") 400 { 401 <style> 402 @@media ( min-width: 1920px ) { 403 .container-xxl, 404 .container-xl, 405 .container-lg, 406 .container-md, 407 .container-sm, 408 .container { 409 max-width: 1820px; 410 } 411 } 412 </style> 413 } 414 } 415 416 @* Branding and Themes min stylesheet *@ 417 <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"> 418 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script> 419 @*CUSTOM CODE*@ 420 <script src="/Files/Templates/Designs/Swift/Assets/js/custom-scripts.js?@customJsFileInfo.LastWriteTime.Ticks" defer></script> 421 @*CUSTOM CODE*@ 422 <script type="module"> 423 swift.Scroll.hideHeadersOnScroll(); 424 swift.Scroll.handleAlternativeTheme(); 425 426 //Only load if AOS 427 const aosColumns = document.querySelectorAll('[data-aos]'); 428 if (aosColumns.length > 0) { 429 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js'); 430 document.addEventListener('load.swift.assetloader', function () { 431 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') }); 432 }); 433 } 434 </script> 435 436 @* Google gtag method - always include even if it is not used for anything *@ 437 <script> 438 window.dataLayer = window.dataLayer || []; 439 function gtag() { dataLayer.push(arguments); } 440 </script> 441 442 @* Google tag manager *@ 443 @if (!string.IsNullOrWhiteSpace(googleTagManagerID)) 444 { 445 <script> 446 gtag('consent', 'default', { 447 'ad_storage': 'denied', 448 'ad_user_data': 'denied', 449 'ad_personalization': 'denied', 450 'analytics_storage': 'denied' 451 }); 452 453 window.dataLayer.push({ 454 'event': 'cookie_cat_functional', 455 'cookie_cat_functional': 'true' 456 457 }); 458 </script> 459 <script> 460 (function (w, d, s, l, i) { 461 w[l] = w[l] || []; w[l].push({ 462 'gtm.start': 463 new Date().getTime(), event: 'gtm.js' 464 }); var f = d.getElementsByTagName(s)[0], 465 j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src = 466 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f); 467 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)'); 468 </script> 469 470 if (allowTracking) 471 { 472 string adConsent = GetCookieOptInPermission("Marketing"); 473 string analyticsConsent = GetCookieOptInPermission("Statistical"); 474 475 string dataLayerMarketing = adConsent == "granted" ? "'event': 'cookie_cat_marketing','cookie_cat_marketing': 'true'" : "'event': 'cookie_cat_marketing','cookie_cat_marketing': 'false'"; 476 string dataLayerStatistical = analyticsConsent == "granted" ? "'event': 'cookie_cat_statistic','cookie_cat_statistic': 'true'" : "'event': 'cookie_cat_statistic','cookie_cat_statistic': 'false'"; 477 478 <script> 479 gtag('consent', 'update', { 480 'ad_storage': '@adConsent', 481 'ad_user_data': '@adConsent', 482 'ad_personalization': '@adConsent', 483 'analytics_storage': '@analyticsConsent' 484 }); 485 486 487 dataLayer.push({@dataLayerMarketing}); 488 dataLayer.push({@dataLayerStatistical}); 489 490 </script> 491 } else { 492 <script> 493 window.dataLayer.push({ 494 'event': 'cookie_cat_marketing', 495 'cookie_cat_marketing' : 'false' 496 497 }); 498 window.dataLayer.push({ 499 'event': 'cookie_cat_statistic', 500 'cookie_cat_statistic' : 'false' 501 }); 502 </script> 503 } 504 } 505 506 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking) 507 { 508 var GoogleAnalyticsDebugMode = ""; 509 510 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode")) 511 { 512 GoogleAnalyticsDebugMode = ", {'debug_mode': true}"; 513 } 514 515 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script> 516 <script> 517 gtag('js', new Date()); 518 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode); 519 </script> 520 } 521 522 @if (!string.IsNullOrWhiteSpace(customHeaderInclude)) 523 { 524 @RenderPartial($"Components/Custom/{customHeaderInclude}") 525 } 526 </head> 527 <body class="brand @(masterTheme)" id="page@(Model.ID)" data-otp-redirect-page="@otpRedirectPage"> 528 529 @* Google tag manager *@ 530 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking) 531 { 532 <noscript> 533 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)" 534 height="0" width="0" style="display:none;visibility:hidden"></iframe> 535 </noscript> 536 } 537 538 @if (renderAsResponsive || !renderMobile) 539 { 540 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop"> 541 @if (headerDesktopLink != null) 542 { 543 @RenderGrid(headerDesktopLink.PageId) 544 } 545 </header> 546 } 547 548 @if ((renderAsResponsive || renderMobile)) 549 { 550 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile"> 551 @if (headerMobileLink != null) 552 { 553 @RenderGrid(headerMobileLink.PageId) 554 } 555 </header> 556 } 557 558 <div data-intersect></div> 559 560 <main id="content" @(schemaOrgType)> 561 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 562 @using System 563 @using Dynamicweb.Ecommerce.ProductCatalog 564 @using Dynamicweb.Frontend.Navigation 565 566 567 @{ 568 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty; 569 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop"; 570 571 bool isArticlePagePage = Model.ItemType == "Swift_Article"; 572 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage"; 573 string schemaOrgProp = string.Empty; 574 if(isArticlePagePage) 575 { 576 schemaOrgProp = "itemprop=\"articleBody\""; 577 } 578 579 string theme = ""; 580 string gridContent = ""; 581 582 if (Model.PropertyItem != null) 583 { 584 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 585 } 586 587 if (Model.Item != null || Pageview.IsVisualEditorMode) 588 { 589 if (!isProductDetail) 590 { 591 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page"); 592 } 593 else 594 { 595 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId); 596 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty; 597 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage"); 598 599 @RenderGrid(detailPageId) 600 } 601 } 602 603 //Navigation settings 604 string navAlignment = "justify-content-start text-start"; 605 string navOrientation = "flex-column"; 606 string layout = "lines"; 607 string linkFontWeight = "fw-normal"; 608 string navTitleFontWeight = "fw-bold"; 609 string NavTitleCasing = "text-capitalize"; 610 string linkCasing = ""; 611 string linkFontSize = "fs-6"; 612 string navTitleFontSize = "h6"; 613 string navigationRoot = "112"; 614 bool showOnlyFirstLevel = true; 615 string contentPadding = " px-3 py-3"; 616 617 var navigationSettings = new NavigationSettings(); 618 navigationSettings.StartLevel = 1; 619 navigationSettings.StopLevel = 10; 620 navigationSettings.ExpandMode = ExpandMode.All; 621 622 navigationSettings.Parameters.Add("Layout", layout); 623 navigationSettings.Parameters.Add("LinkFontSize", linkFontSize); 624 navigationSettings.Parameters.Add("NavOrientation", navOrientation); 625 navigationSettings.Parameters.Add("LinkFontWeight", linkFontWeight); 626 navigationSettings.Parameters.Add("NavAlignment", navAlignment); 627 navigationSettings.Parameters.Add("LinkCasing", linkCasing); 628 navigationSettings.Parameters.Add("Theme", theme); 629 navigationSettings.Parameters.Add("ShowOnlyFirstNavLevel", showOnlyFirstLevel); 630 631 if (!string.IsNullOrEmpty(navigationRoot)) 632 { 633 int rootPageId = Convert.ToInt32(navigationRoot); 634 navigationSettings.RootPageId = rootPageId; 635 636 var page = Dynamicweb.Content.Services.Pages.GetPage(rootPageId); 637 if (page != null && !string.IsNullOrEmpty(page.NavigationTag)) 638 { 639 navigationSettings.Parameters.Add("menu-id", page.NavigationTag.ToLower()); 640 } 641 642 } 643 else 644 { 645 navigationSettings.Parameters.Add("menu-id", "root"); 646 } 647 648 649 bool doNotRenderPage = false; 650 651 //Check if we are on the poduct detail page, and if there is data to render 652 ProductViewModel product = new ProductViewModel(); 653 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 654 { 655 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 656 if (string.IsNullOrEmpty(product.Id)) { 657 doNotRenderPage = true; 658 } 659 } 660 661 //Render the page 662 if (!doNotRenderPage) { 663 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page"; 664 string sectionClass = "py-3 py-lg-3"; 665 string containerClass = "container-xl"; 666 string mobileColumnSize = "1"; 667 string rowClass = ""; 668 669 <div class="@theme @itemIdentifier" @schemaOrgProp> 670 <div class="@(sectionClass)@(theme)"> 671 <div class="@containerClass"> 672 <div class="grid grid-@(mobileColumnSize) grid-lg-4@(rowClass)"> 673 <div class="g-col order-first order-lg-0" data-col-size="3" style="--bs-columns:12"> 674 <div class="h-100@(theme) item_@Model.Item.SystemName.ToLower()"> 675 @if (!string.IsNullOrEmpty(Model.Item.GetString("Title")) && !Model.Item.GetBoolean("HideTitle")) 676 { 677 <h3 class="@contentPadding">@Model.Item.GetString("Title")</h3> 678 } 679 680 @Navigation.RenderNavigation("Navigation/Vertical.cshtml", navigationSettings) 681 </div> 682 </div> 683 <div class="g-col g-col-lg-3" data-col-size="9" style="--bs-columns:12"> 684 @gridContent 685 </div> 686 </div> 687 </div> 688 </div> 689 690 </div> 691 692 } else { 693 <div class="container"> 694 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div> 695 </div> 696 } 697 698 if (!Model.IsCurrentUserAllowed) 699 { 700 int signInPage = GetPageIdByNavigationTag("SignInPage"); 701 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage"); 702 703 if (!Pageview.IsVisualEditorMode) 704 { 705 if (signInPage != 0) 706 { 707 if (signInPage != Model.ID) { 708 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage); 709 } else { 710 if (dashboardPage != 0) { 711 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage); 712 } else { 713 Dynamicweb.Context.Current.Response.Redirect("/"); 714 } 715 } 716 } 717 else 718 { 719 <div class="alert alert-dark m-0" role="alert"> 720 <span>@Translate("You do not have access to this page") @Pageview.Page.ID</span> 721 </div> 722 } 723 } 724 else 725 { 726 <div class="alert alert-dark m-0" role="alert"> 727 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span> 728 </div> 729 } 730 } 731 } 732 733 </main> 734 735 @if (renderAsResponsive || !renderMobile) 736 { 737 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop"> 738 @if (footerDesktopLink != null) 739 { 740 @RenderGrid(footerDesktopLink.PageId) 741 } 742 </footer> 743 } 744 745 @if (renderAsResponsive || renderMobile) 746 { 747 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile"> 748 @if (footerMobileLink != null) 749 { 750 @RenderGrid(footerMobileLink.PageId) 751 } 752 </footer> 753 } 754 755 @* Render any offcanvas menu here *@ 756 @RenderSnippet("offcanvas") 757 758 @{ 759 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]); 760 } 761 762 @* Language selector modal *@ 763 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true"> 764 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent"> 765 @* The content here comes from an external request *@ 766 </div> 767 </div> 768 769 @* Favorite toast *@ 770 <div aria-live="polite" aria-atomic="true"> 771 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11"> 772 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true"> 773 <div class="toast-header"> 774 <strong class="me-auto">@Translate("Favorite list updated")</strong> 775 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 776 </div> 777 <div class="toast-body d-flex gap-3"> 778 <div id="favoriteNotificationToast_Image"></div> 779 <div id="favoriteNotificationToast_Text"></div> 780 </div> 781 </div> 782 </div> 783 </div> 784 785 @* Modal for dynamic content *@ 786 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true"> 787 <div class="modal-dialog modal-dialog-centered modal-md"> 788 <div class="modal-content theme light" id="DynamicModalContent"> 789 @* The content here comes from an external request *@ 790 </div> 791 </div> 792 </div> 793 794 @* Offcanvas for dynamic content *@ 795 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas"> 796 @* The content here comes from an external request *@ 797 </div> 798 799 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"])) 800 { 801 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light"; 802 803 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040"> 804 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true"> 805 <div class="toast-header"> 806 <strong class="me-auto">@Translate("Connection down")</strong> 807 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 808 </div> 809 <div class="toast-body"> 810 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.") 811 </div> 812 </div> 813 </div> 814 } 815 816 @if (miniCartEnabled) 817 { 818 @* Open MiniCart when the cart is updated *@ 819 <script type="module"> 820 document.addEventListener('updated.swift.cart', (event) => { 821 let orderContext = event?.detail?.formData?.get("OrderContext"); 822 updateCartSummary(orderContext); 823 824 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") { 825 <text>openMiniCartOffcanvas();</text> 826 } 827 }); 828 </script> 829 830 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3") 831 { 832 @* Open MiniCart when toggle is clicked *@ 833 <script type="module"> 834 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity'); 835 miniCartToggles?.forEach((toggle) => { 836 toggle.parentElement.addEventListener('click', (event) => { 837 event.preventDefault(); 838 let orderContext = toggle.dataset?.orderContext; 839 updateCartSummary(orderContext); 840 841 openMiniCartOffcanvas(); 842 }); 843 }); 844 </script> 845 } 846 847 <script> 848 849 const updateCartSummary = (orderContext) => { 850 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 851 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas); 852 }; 853 854 const openMiniCartOffcanvas = () => { 855 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 856 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas); 857 dynamicOffcanvas.classList.add('overflow-y-auto'); 858 859 if (!miniCartOffcanvas._isShown) { 860 miniCartOffcanvas.show(); 861 hideActiveOffcanvases(miniCartOffcanvas); 862 } 863 }; 864 865 const hideActiveOffcanvases = (miniCartOffcanvas) => { 866 let activeOffcanvases = document.querySelectorAll('.offcanvas.show'); 867 activeOffcanvases?.forEach((offCanvas) => { 868 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas); 869 if (offCanvas !== miniCartOffcanvas) { 870 offCanvas.hide(); 871 } 872 }); 873 }; 874 875 </script> 876 } 877 878 @* START CUSTOM CODE *@ 879 @RenderFaqModal() 880 @RenderCustomFontStyleTag() 881 @* END CUSTOM CODE *@ 882 883 884 885 @{ 886 var cookieBannerParameter = Dynamicweb.Context.Current.Request.QueryString["showcookiebanner"]; 887 string showCookieBanner = cookieBannerParameter != null ? cookieBannerParameter.ToString() : ""; 888 889 //if(showCookieBanner.Equals("true", StringComparison.OrdinalIgnoreCase)) 890 if(CookieManager.GetCookieOptInCategories().Any() && CookieManager.IsCookieManagementActive) 891 { 892 @RenderPartial($"CookieWarning/{Pageview.Area.CookieWarningTemplate}") 893 } 894 } 895 896 <button class="btn btn-secondary position-fixed bottom-0 mb-2 ms-2 bg-white" id="launchCookieModal" onclick="renderCookieModal()"> 897 @RenderIcon("/Files/Icons/cookies.svg") 898 </button> 899 900 <div class="modal fade modal-md @(showCodeInput ? "show-modal" : "")" id="SignInOTPModal"> 901 <div class="modal-dialog @(Pageview.User != null ? "reload" : "")"> 902 <div class="modal-content rounded-7"> 903 <div class="modal-header"> 904 <h3 class="modal-title">@Translate("OTP Login")</h3> 905 <button type="button" class="btn-close me-1" data-bs-dismiss="modal" aria-label="@Translate("Close")"></button> 906 </div> 907 908 <div class="modal-body" id="SignInOTPModalBody" data-opt-wizard> 909 <div class="d-grid gap-3 @(showCodeInput ? "d-none" : "active")" data-step="1"> 910 <h5 class="mb-0">@Translate("Enter your email")</h5> 911 <div class="form-floating"> 912 <input type="email" class="form-control" required placeholder="@Translate("your.email@example.com")" name="Email" id="OTPEmail"> 913 <label for="Email">@Translate("Email")</label> 914 </div> 915 <button type="submit" class="btn btn-primary action-button" data-action="Send">@Translate("Send verification code")</button> 916 <p class="small mb-0 text-center color-gray">@Translate("We'll send a 6-digit code to your email")</p> 917 </div> 918 919 <div class="d-grid gap-3 @(showCodeInput ? "active" : "d-none")" data-step="2"> 920 <div class="d-grid gap-1"> 921 <h5 class="mb-0">@Translate("Enter verification code")</h5> 922 @if (!string.IsNullOrEmpty(otpEmailFromSession)) 923 { 924 <p class="mb-0 small text-muted">@Translate("Code sent to :") <b>@otpEmailFromSession</b></p> 925 } 926 </div> 927 <input type="hidden" name="Action" value="Verify"> 928 <input type="hidden" name="Email" value="@otpEmailFromSession"> 929 <div class="form-floating"> 930 <input type="text" maxlength="6" minlength="6" class="form-control text-center fw-bold" style="letter-spacing: 8px" placeholder="000000" name="Code" required> 931 <label for="Code">@codeExpiresMessage</label> 932 </div> 933 <button class="btn btn-primary action-button" data-action="Verify" data-current-attempt="1" data-max-attempts="@otpCodeMaxAttempts" @(disableVerifyButton ? "disabled" : "")>@Translate("Verify & Sign In")</button> 934 <div class="d-flex flex-wrap justify-content-center"> 935 <button class="btn btn-link action-button" data-action="Send" skip @(!disableVerifyButton ? "disabled enable-after" : "")>@Translate("Resend code")</button> 936 <button class="btn btn-link action-button" data-action="Reset" skip>@Translate("Use different email")</button> 937 </div> 938 </div> 939 </div> 940 941 @if (!string.IsNullOrEmpty(message)) 942 { 943 <div class="modal-footer justify-content-center"> 944 <div class="d-grid"> 945 @message 946 </div> 947 </div> 948 } 949 950 </div> 951 </div> 952 </div> 953 954 955 </body> 956 957 </html> 958 959 } 960 else if (Pageview.IsVisualEditorMode) 961 { 962 <head> 963 <title>@Model.Title</title> 964 @* Bootstrap + Swift stylesheet *@ 965 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css"> 966 </head> 967 <body class="p-3"> 968 <div class="alert alert-danger" role="alert"> 969 @Translate("Basic Swift setup is needed!") 970 </div> 971 972 @if (brandingPage == null) 973 { 974 <div class="alert alert-warning" role="alert"> 975 @Translate("Please add a Branding page and reference it in website settings") 976 </div> 977 } 978 979 @if (themesParagraphs == null) 980 { 981 <div class="alert alert-warning" role="alert"> 982 @Translate("Please add a Themes collection page and reference it in website settings") 983 </div> 984 } 985 986 987 </body> 988 } 989 990 991 @functions { 992 void SetMetaTags() 993 { 994 //Verification Tokens 995 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : ""; 996 997 //Generic Site Values 998 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : ""; 999 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : ""; 1000 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : ""; 1001 1002 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : ""; 1003 1004 //Page specific values 1005 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : ""; 1006 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image"); 1007 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : ""; 1008 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : ""; 1009 1010 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : ""; 1011 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : ""; 1012 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : ""; 1013 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image"); 1014 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : ""; 1015 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}"; 1016 1017 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 1018 { 1019 if (!string.IsNullOrEmpty(Model.Description)) 1020 { 1021 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">"); 1022 } 1023 else 1024 { 1025 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">"); 1026 } 1027 1028 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 1029 { 1030 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 1031 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 1032 } 1033 else if (openGraphImage != null) 1034 { 1035 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 1036 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 1037 } 1038 1039 if (!string.IsNullOrEmpty(openGraphImageALT)) 1040 { 1041 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">"); 1042 } 1043 if (!string.IsNullOrEmpty(twitterCardDescription)) 1044 { 1045 Pageview.Meta.AddTag("twitter:description", twitterCardDescription); 1046 } 1047 1048 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 1049 { 1050 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}"); 1051 } 1052 else if (twitterCardImage != null) 1053 { 1054 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}"); 1055 } 1056 1057 if (!string.IsNullOrEmpty(twitterCardImageALT)) 1058 { 1059 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT); 1060 } 1061 } 1062 1063 if (!string.IsNullOrEmpty(siteVerificationGoogle)) 1064 { 1065 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle); 1066 } 1067 1068 if (!string.IsNullOrEmpty(openGraphFacebookAppID)) 1069 { 1070 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">"); 1071 } 1072 1073 if (!string.IsNullOrEmpty(openGraphType)) 1074 { 1075 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">"); 1076 } 1077 1078 if (!string.IsNullOrEmpty(openGraphSiteName)) 1079 { 1080 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">"); 1081 } 1082 1083 if (!string.IsNullOrEmpty(openGraphSiteName)) 1084 { 1085 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">"); 1086 } 1087 1088 if (!string.IsNullOrEmpty(Model.Title)) 1089 { 1090 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">"); 1091 } 1092 else 1093 { 1094 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">"); 1095 } 1096 1097 if (!string.IsNullOrEmpty(twitterCardSite)) 1098 { 1099 Pageview.Meta.AddTag("twitter:site", twitterCardSite); 1100 } 1101 1102 if (!string.IsNullOrEmpty(twitterCardURL)) 1103 { 1104 Pageview.Meta.AddTag("twitter:url", twitterCardURL); 1105 } 1106 1107 if (!string.IsNullOrEmpty(twitterCardTitle)) 1108 { 1109 Pageview.Meta.AddTag("twitter:title", twitterCardTitle); 1110 } 1111 } 1112 } 1113 @* START CUSTOM CODE *@ 1114 @helper RenderFaqModal() 1115 { 1116 var faqPage = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetPageIdByNavigationTag("FAQ")); 1117 <div class="modal modal-xl faq-modal" aria-hidden="true" data-url="@faqPage"> 1118 <div class="modal-dialog"> 1119 <div class="modal-content"> 1120 <div class="modal-header"> 1121 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 1122 </div> 1123 <div class="modal-body p-0"></div> 1124 </div> 1125 </div> 1126 </div> 1127 } 1128 @helper RenderCustomFontStyleTag() 1129 { 1130 <style> 1131 @@font-face { 1132 font-family: 'Arsilon'; 1133 font-style: normal; 1134 font-weight: 400; 1135 font-display: swap; 1136 src: url(/Files/Templates/Designs/Swift/Assets/fonts/Arsilon.woff2) format('woff2'); 1137 } 1138 1139 1140 span.special { 1141 font-family:'Arsilon'; 1142 font-weight:400; 1143 font-style:normal; 1144 line-height:1.5; 1145 font-size:72px; 1146 } 1147 </style> 1148 } 1149 @helper RenderIcon(string icon) 1150 { 1151 if (System.IO.Path.GetExtension(icon).ToLower() == ".svg") 1152 { 1153 if (!icon.ToLower().Contains("none") && icon != string.Empty) 1154 { 1155 <span class="icon-auto"> 1156 @ReadFile(icon) 1157 </span> 1158 } 1159 } 1160 } 1161 @* END CUSTOM CODE *@