Error executing template "Designs/Swift/_parsed/Swift_Page.parsed.cshtml"
System.FormatException: Input string was not in a correct format.
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Int16.Parse(String s, NumberStyles style, NumberFormatInfo info)
at System.Convert.ToInt16(String value)
at CompiledRazorTemplates.Dynamic.RazorEngine_c348464fff8e4344a592a8046ef03084.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\hctswift.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\_parsed\Swift_Page.parsed.cshtml:line 458
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 7 8 @functions {
9 string GetCookieOptInPermission(string category)
10 {
11 bool categoryOrAllGranted = false;
12 13 if (CookieManager.IsCookieManagementActive)
14 {
15 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
16 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
17 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All;
18 }
19 20 return categoryOrAllGranted ? "granted" : "denied";
21 }
22 23 bool AllowTracking()
24 {
25 bool allowTracking = true;
26 if (CookieManager.IsCookieManagementActive)
27 {
28 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
29 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
30 31 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing"));
32 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional;
33 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither);
34 35 allowTracking = consentAtLeastOne;
36 }
37 return allowTracking;
38 }
39 }
40 41 @{
42 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID;
43 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false;
44 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3";
45 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart;
46 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0;
47 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0;
48 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0;
49 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null;
50 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null;
51 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null;
52 var customFooterScripts = Model.Area.Item?.GetRawValueString("FooterScripts", "") ?? "";
53 var scriptsHeader = Model.Area.Item?.GetRawValueString("ScriptsHeader", "") ?? "";
54 55 }
56 57 @if (themesParagraphs != null || brandingPage != null)
58 {
59 string swiftVersion = ReadFile("/Files/Templates/Designs/Swift/swift_version.txt");
60 bool renderAsResponsive = Model.Area.Item.GetString("DeviceRendering", "responsive").Equals("responsive", StringComparison.OrdinalIgnoreCase);
61 bool renderMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet;
62 string responsiveClassDesktop = string.Empty;
63 string responsiveClassMobile = string.Empty;
64 if (renderAsResponsive)
65 {
66 responsiveClassDesktop = " d-none d-xl-block";
67 responsiveClassMobile = " d-block d-xl-none";
68 }
69 70 var headerDesktopLink = Model.Area.Item?.GetLink("HeaderDesktop") ?? null;
71 var headerMobileLink = Model.Area.Item?.GetLink("HeaderMobile") ?? null;
72 73 var footerDesktopLink = Model.Area.Item?.GetLink("FooterDesktop") ?? null;
74 var footerMobileLink = Model.Area.Item?.GetLink("FooterMobile") ?? null;
75 76 var disableWideBreakpoints = Model.Area?.Item?.GetRawValueString("DisableWideBreakpoints", "default");
77 78 string customHeaderInclude = !string.IsNullOrEmpty(Model.Area.Item.GetRawValueString("CustomHeaderInclude")) ? Model.Area.Item.GetFile("CustomHeaderInclude").Name : string.Empty;
79 80 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
81 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt;
82 83 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css"));
84 85 86 if (cssPageId != 0)
87 {
88 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css"));
89 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
90 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt)
91 {
92 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId);
93 cssPageview.Redirect = false;
94 cssPageview.Output();
95 }
96 }
97 98 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt)
99 {
100 //Branding page has been saved or the file is missing. Rewrite the file to disc.
101 if (brandingPageId > 0)
102 {
103 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId);
104 brandingPageview.Redirect = false;
105 brandingPageview.Output();
106 }
107 }
108109 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt)
110 {
111 //Branding page has been saved or the file is missing. Rewrite the file to disc.
112 if (themePageId > 0)
113 {
114 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId);
115 themePageview.Redirect = false;
116 themePageview.Output();
117 }
118 }
119120 // Schema.org details for PDP
121 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID");
122 bool isArticlePage = Model.ItemType == "Swift_Article";
123 string schemaOrgType = string.Empty;
124125 if (isProductDetailsPage)
126 {
127 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\"";
128 }
129130 if (isArticlePage)
131 {
132 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\"";
133 }
134135136 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css"));
137 var cssStyleFileInfoCustom = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/custom.css"));
138 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js"));
139140 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
141142 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png");
143 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png");
144145 string headerCssClass = "sticky-top";
146 bool movePageBehind = false;
147148 if (Model.PropertyItem != null)
149 {
150 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top");
151 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false;
152 }
153154 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass;
155 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass;
156157 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim();
158 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim();
159 string userCentrics = Model.Area.Item.GetString("UsercentricsScript");
160 bool allowTracking = true;
161162 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;");
163 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/custom.css?{cssStyleFileInfoCustom.LastWriteTime.Ticks}>; rel=preload; as=style;");
164 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;");
165 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;");
166167168 SetMetaTags();
169170 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>();
171172 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage;
173 languages.Add(masterPage);
174 if (masterPage?.Languages != null)
175 {
176 foreach (var language in masterPage.Languages)
177 {
178 languages.Add(language);
179 }
180 }
181182 Uri url = Dynamicweb.Context.Current.Request.Url;
183 string hostName = url.Host;
184185 <!doctype html>
186 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName">
187 <head>
188 <!-- @swiftVersion -->
189 @* Required meta tags *@
190 <meta charset="utf-8">
191 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0">
192 <link rel="shortcut icon" href="@favicon">
193 <link rel="apple-touch-icon" href="@appleTouchIcon">
194195 @Model.MetaTags
196197 @{
198 var alreadyWrittenTwoletterIsos = new List<string>();
199 @* Languages meta data *@
200 foreach (var language in languages)
201 {
202 hostName = url.Host;
203 if (language?.Area != null)
204 {
205 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock))
206 {
207 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk
208 }
209 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published)
210 {
211 if (!string.IsNullOrEmpty(language.Area.DomainLock))
212 {
213 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk
214 }
215 string querystring = $"Default.aspx?ID={language.ID}";
216 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"]))
217 {
218 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}";
219 }
220 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
221 {
222 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}";
223 }
224 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"]))
225 {
226 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}";
227 }
228229 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring);
230 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1)
231 {
232 friendlyUrl = "/";
233 }
234 string href = $"{url.Scheme}://{hostName}{friendlyUrl}";
235236237 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href">
238 if (!alreadyWrittenTwoletterIsos.Contains(language.Area.CultureInfo.TwoLetterISOLanguageName))
239 {
240 alreadyWrittenTwoletterIsos.Add(language.Area.CultureInfo.TwoLetterISOLanguageName);
241 <link rel="alternate" hreflang="@language.Area.CultureInfo.TwoLetterISOLanguageName.ToLower()" href="@href">
242 }
243 }
244 }
245 }
246 }
247248 <title>@Model.Title</title>
249 @* Bootstrap + Swift stylesheet *@
250 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
251 <link href="/Files/Templates/Designs/Swift/Assets/css/custom.css?@cssStyleFileInfoCustom.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
252253 @if (disableWideBreakpoints != "disableBoth")
254 {
255 <style>
256 @@media ( min-width: 1600px ) {
257 .container-xxl,
258 .container-xl,
259 .container-lg,
260 .container-md,
261 .container-sm,
262 .container {
263 max-width: 1520px;
264 }
265 }
266 </style>
267268269270 if (disableWideBreakpoints != "disableUltraWideOnly")
271 {
272 <style>
273 @@media ( min-width: 1920px ) {
274 .container-xxl,
275 .container-xl,
276 .container-lg,
277 .container-md,
278 .container-sm,
279 .container {
280 max-width: 1820px;
281 }
282 }
283 </style>
284 }
285 }
286287 @* Branding and Themes min stylesheet *@
288 <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">
289 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script>
290 <script type="module">
291 swift.Scroll.hideHeadersOnScroll();
292 swift.Scroll.handleAlternativeTheme();
293294 //Only load if AOS
295 const aosColumns = document.querySelectorAll('[data-aos]');
296 if (aosColumns.length > 0) {
297 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js');
298 document.addEventListener('load.swift.assetloader', function () {
299 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') });
300 });
301 }
302 </script>
303304 @if (!string.IsNullOrWhiteSpace(userCentrics))
305 {
306307 <link rel="preconnect" href="//app.usercentrics.eu">
308 <link rel="preconnect" href="//api.usercentrics.eu">
309 <link rel="preload" href="//app.usercentrics.eu/browser-ui/latest/loader.js" as="script">
310311 }
312313 @if (!string.IsNullOrWhiteSpace(userCentrics))
314 {
315 <text>@userCentrics</text>
316 }
317318 @* Google tag manager *@
319 @if (!string.IsNullOrWhiteSpace(userCentrics) && !string.IsNullOrWhiteSpace(googleTagManagerID))
320 {
321 <script type="text/plain" data-usercentrics="Google Tag Manager">
322 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
323 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
324 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
325 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
326 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
327328 function gtag() { dataLayer.push(arguments); }
329 </script>
330 } else if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
331 {
332 <script>
333 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
334 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
335 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
336 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
337 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
338339 function gtag() { dataLayer.push(arguments); }
340 </script>
341 }
342343 @if (!string.IsNullOrWhiteSpace(userCentrics) && !string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID))
344 {
345 var GoogleAnalyticsDebugMode = "";
346347 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
348 {
349 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
350 }
351352 <script type="text/plain" data-usercentrics="Google Analytics" async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
353 <script type="text/plain" data-usercentrics="Google Analytics">
354 window.dataLayer = window.dataLayer || [];
355 function gtag() { dataLayer.push(arguments); }
356 gtag('js', new Date());
357 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
358 </script>
359 } else if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking)
360 {
361 var GoogleAnalyticsDebugMode = "";
362363 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
364 {
365 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
366 }
367368 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
369 <script>
370 window.dataLayer = window.dataLayer || [];
371 function gtag() { dataLayer.push(arguments); }
372 gtag('js', new Date());
373 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
374 </script>
375 }
376377 @if (!string.IsNullOrWhiteSpace(customHeaderInclude))
378 {
379 @RenderPartial($"Components/Custom/{customHeaderInclude}")
380 }
381382 @if (allowTracking && !string.IsNullOrWhiteSpace(scriptsHeader)){
383 @scriptsHeader
384 }
385386 </head>
387 <body class="brand @(masterTheme)" id="page@(Model.ID)">
388389 @* Google tag manager *@
390 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
391 {
392 <noscript>
393 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)"
394 height="0" width="0" style="display:none;visibility:hidden"></iframe>
395 </noscript>
396 }
397398 @if (renderAsResponsive || !renderMobile)
399 {
400 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop">
401 @if (headerDesktopLink != null)
402 {
403 @RenderGrid(headerDesktopLink.PageId)
404 }
405 </header>
406 }
407408 @if ((renderAsResponsive || renderMobile))
409 {
410 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile">
411 @if (headerMobileLink != null)
412 {
413 @RenderGrid(headerMobileLink.PageId)
414 }
415 </header>
416 }
417418 <div data-intersect></div>
419420 <main id="content" @(schemaOrgType)>
421 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
422 @using System
423 @using Dynamicweb.Ecommerce.ProductCatalog
424425426 @{
427 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty;
428 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop";
429430 bool isArticlePagePage = Model.ItemType == "Swift_Article";
431 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage";
432 string schemaOrgProp = string.Empty;
433 if (isArticlePagePage)
434 {
435 schemaOrgProp = "itemprop=\"articleBody\"";
436 }
437438 string theme = "";
439 string gridContent = "";
440441 if (Model.PropertyItem != null)
442 {
443 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
444 }
445446 if (Model.Item != null || Pageview.IsVisualEditorMode)
447 {
448 if (!isProductDetail)
449 {
450 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page");
451 }
452 else
453 {
454 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId);
455 if (productObject != null)
456 {
457 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject?.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty;
458 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage");
459460 @RenderGrid(detailPageId)
461 }
462 }
463 }
464465 bool doNotRenderPage = false;
466467 //Check if we are on the poduct detail page, and if there is data to render
468 ProductViewModel product = new ProductViewModel();
469 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
470 {
471 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
472 if (string.IsNullOrEmpty(product.Id))
473 {
474 doNotRenderPage = true;
475 }
476 }
477478 //Render the page
479 if (!doNotRenderPage)
480 {
481 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page";
482483 if (Pageview.IsVisualEditorMode)
484 {
485 @Model.Placeholder("dwcontent", "content", "default:true;sort:1")
486 }
487488 <div class="@theme @itemIdentifier" @schemaOrgProp>
489 @if (isArticleListPage)
490 {
491 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\"";
492493 <form @hx id="ArticleFacetForm">
494 @gridContent
495 </form>
496 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/htmx.js"></script>
497 <script type="module">
498 document.addEventListener('htmx:confirm', (event) => {
499 let filters = event.detail.elt.querySelectorAll('select');
500 for (var i = 0; i < filters.length; i++) {
501 let input = filters[i];
502 if (input.name && !input.value) {
503 input.name = '';
504 }
505 }
506 });
507508 document.addEventListener('htmx:beforeOnLoad', (event) => {
509 swift.Scroll.stopIntersectionObserver();
510 });
511512 document.addEventListener('htmx:afterOnLoad', () => {
513 swift.Scroll.hideHeadersOnScroll();
514 swift.Scroll.handleAlternativeTheme();
515 });
516 </script>
517 }
518 else
519 {
520 @gridContent
521 }
522 </div>
523524 }
525 else
526 {
527 <div class="container">
528 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div>
529 </div>
530 }
531532 if (!Model.IsCurrentUserAllowed)
533 {
534 int signInPage = GetPageIdByNavigationTag("SignInPage");
535 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage");
536537 if (!Pageview.IsVisualEditorMode)
538 {
539 if (signInPage != 0)
540 {
541 if (signInPage != Model.ID)
542 {
543 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage);
544 }
545 else
546 {
547 if (dashboardPage != 0)
548 {
549 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage);
550 }
551 else
552 {
553 Dynamicweb.Context.Current.Response.Redirect("/");
554 }
555 }
556 }
557 else
558 {
559 <div class="alert alert-dark m-0" role="alert">
560 <span>@Translate("You do not have access to this page")</span>
561 </div>
562 }
563 }
564 else
565 {
566 <div class="alert alert-dark m-0" role="alert">
567 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span>
568 </div>
569 }
570 }
571 }
572573 </main>
574575 @if (renderAsResponsive || !renderMobile)
576 {
577 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop">
578 @if (footerDesktopLink != null)
579 {
580 @RenderGrid(footerDesktopLink.PageId)
581 }
582583 @if (allowTracking && !string.IsNullOrWhiteSpace(customFooterScripts)){
584 @customFooterScripts
585 }
586 </footer>
587 }
588589 @if (renderAsResponsive || renderMobile)
590 {
591 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile">
592 @if (footerMobileLink != null)
593 {
594 @RenderGrid(footerMobileLink.PageId)
595 }
596 </footer>
597 }
598599 @* Render any offcanvas menu here *@
600 @RenderSnippet("offcanvas")
601602 @{
603 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]);
604 }
605606 @* Language selector modal *@
607 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true">
608 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent">
609 @* The content here comes from an external request *@
610 </div>
611 </div>
612613 @* Favorite toast *@
614 <div aria-live="polite" aria-atomic="true">
615 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
616 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
617 <div class="toast-header">
618 <strong class="me-auto">@Translate("Favorite list updated")</strong>
619 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
620 </div>
621 <div class="toast-body d-flex gap-3">
622 <div id="favoriteNotificationToast_Image"></div>
623 <div id="favoriteNotificationToast_Text"></div>
624 </div>
625 </div>
626 </div>
627 </div>
628629 @* Modal for dynamic content *@
630 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true">
631 <div class="modal-dialog modal-dialog-centered modal-md">
632 <div class="modal-content theme light" id="DynamicModalContent">
633 @* The content here comes from an external request *@
634 </div>
635 </div>
636 </div>
637638 @* Offcanvas for dynamic content *@
639 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas">
640 @* The content here comes from an external request *@
641 </div>
642643 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]))
644 {
645 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light";
646647 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040">
648 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true">
649 <div class="toast-header">
650 <strong class="me-auto">@Translate("Connection down")</strong>
651 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
652 </div>
653 <div class="toast-body">
654 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.")
655 </div>
656 </div>
657 </div>
658 }
659660 @if (miniCartEnabled)
661 {
662 @* Open MiniCart when the cart is updated *@
663 <script type="module">
664 document.addEventListener('updated.swift.cart', (event) => {
665 let orderContext = event?.detail?.formData?.get("OrderContext");
666 updateCartSummary(orderContext);
667668 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") {
669 <text>openMiniCartOffcanvas();</text>
670 }
671 });
672 </script>
673674 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3")
675 {
676 @* Open MiniCart when toggle is clicked *@
677 <script type="module">
678 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity');
679 miniCartToggles?.forEach((toggle) => {
680 toggle.parentElement.addEventListener('click', (event) => {
681 event.preventDefault();
682 let orderContext = toggle.dataset?.orderContext;
683 updateCartSummary(orderContext);
684685 openMiniCartOffcanvas();
686 });
687 });
688 </script>
689 }
690691 <script>
692693 const updateCartSummary = (orderContext) => {
694 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
695 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas);
696 };
697698 const openMiniCartOffcanvas = () => {
699 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
700 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas);
701 dynamicOffcanvas.classList.add('overflow-y-auto');
702703 if (!miniCartOffcanvas._isShown) {
704 miniCartOffcanvas.show();
705 hideActiveOffcanvases(miniCartOffcanvas);
706 }
707 };
708709 const hideActiveOffcanvases = (miniCartOffcanvas) => {
710 let activeOffcanvases = document.querySelectorAll('.offcanvas.show');
711 activeOffcanvases?.forEach((offCanvas) => {
712 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas);
713 if (offCanvas !== miniCartOffcanvas) {
714 offCanvas.hide();
715 }
716 });
717 };
718719 </script>
720 }
721722 </body>
723724 </html>
725726 }
727 else if (Pageview.IsVisualEditorMode)
728 {
729 <head>
730 <title>@Model.Title</title>
731 @* Bootstrap + Swift stylesheet *@
732 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css">
733 </head>
734 <body class="p-3">
735 <div class="alert alert-danger" role="alert">
736 @Translate("Basic Swift setup is needed!")
737 </div>
738739 @if (brandingPage == null)
740 {
741 <div class="alert alert-warning" role="alert">
742 @Translate("Please add a Branding page and reference it in website settings")
743 </div>
744 }
745746 @if (themesParagraphs == null)
747 {
748 <div class="alert alert-warning" role="alert">
749 @Translate("Please add a Themes collection page and reference it in website settings")
750 </div>
751 }
752 </body>
753 }
754755756 @functions {
757 void SetMetaTags()
758 {
759 //Verification Tokens
760 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : "";
761762 //Generic Site Values
763 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : "";
764 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : "";
765 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : "";
766767 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : "";
768769 //Page specific values
770 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : "";
771 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image");
772 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : "";
773 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : "";
774775 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : "";
776 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : "";
777 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : "";
778 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image");
779 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : "";
780 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}";
781782 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
783 {
784 if (!string.IsNullOrEmpty(Model.Description))
785 {
786 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">");
787 }
788 else
789 {
790 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">");
791 }
792793 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
794 {
795 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
796 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
797 }
798 else if (openGraphImage != null)
799 {
800 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
801 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
802 }
803804 if (!string.IsNullOrEmpty(openGraphImageALT))
805 {
806 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">");
807 }
808 if (!string.IsNullOrEmpty(twitterCardDescription))
809 {
810 Pageview.Meta.AddTag("twitter:description", twitterCardDescription);
811 }
812813 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
814 {
815 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}");
816 }
817 else if (twitterCardImage != null)
818 {
819 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}");
820 }
821822 if (!string.IsNullOrEmpty(twitterCardImageALT))
823 {
824 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT);
825 }
826 }
827828 if (!string.IsNullOrEmpty(siteVerificationGoogle))
829 {
830 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle);
831 }
832833 if (!string.IsNullOrEmpty(openGraphFacebookAppID))
834 {
835 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">");
836 }
837838 if (!string.IsNullOrEmpty(openGraphType))
839 {
840 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">");
841 }
842843 if (!string.IsNullOrEmpty(openGraphSiteName))
844 {
845 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">");
846 }
847848 if (!string.IsNullOrEmpty(openGraphSiteName))
849 {
850 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">");
851 }
852853 if (!string.IsNullOrEmpty(Model.Title))
854 {
855 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">");
856 }
857 else
858 {
859 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">");
860 }
861862 if (!string.IsNullOrEmpty(twitterCardSite))
863 {
864 Pageview.Meta.AddTag("twitter:site", twitterCardSite);
865 }
866867 if (!string.IsNullOrEmpty(twitterCardURL))
868 {
869 Pageview.Meta.AddTag("twitter:url", twitterCardURL);
870 }
871872 if (!string.IsNullOrEmpty(twitterCardTitle))
873 {
874 Pageview.Meta.AddTag("twitter:title", twitterCardTitle);
875 }
876 }
877 }
878