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_20a0dc2f3e08498eab9eff0fe10a5e0f.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\hctswift.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\_parsed\Swift_Page.parsed.cshtml:line 457
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 @functions {
8 string GetCookieOptInPermission(string category)
9 {
10 bool categoryOrAllGranted = false;
11 12 if (CookieManager.IsCookieManagementActive)
13 {
14 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
15 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
16 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All;
17 }
18 19 return categoryOrAllGranted ? "granted" : "denied";
20 }
21 22 bool AllowTracking()
23 {
24 bool allowTracking = true;
25 if (CookieManager.IsCookieManagementActive)
26 {
27 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
28 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
29 30 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing"));
31 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional;
32 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither);
33 34 allowTracking = consentAtLeastOne;
35 }
36 return allowTracking;
37 }
38 }
39 40 @{
41 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID;
42 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false;
43 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3";
44 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart;
45 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0;
46 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0;
47 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0;
48 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null;
49 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null;
50 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null;
51 var customFooterScripts = Model.Area.Item?.GetRawValueString("FooterScripts", "") ?? "";
52 var scriptsHeader = Model.Area.Item?.GetRawValueString("ScriptsHeader", "") ?? "";
53 54 }
55 56 @if (themesParagraphs != null || brandingPage != null)
57 {
58 string swiftVersion = ReadFile("/Files/Templates/Designs/Swift/swift_version.txt");
59 bool renderAsResponsive = Model.Area.Item.GetString("DeviceRendering", "responsive").Equals("responsive", StringComparison.OrdinalIgnoreCase);
60 bool renderMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet;
61 string responsiveClassDesktop = string.Empty;
62 string responsiveClassMobile = string.Empty;
63 if (renderAsResponsive)
64 {
65 responsiveClassDesktop = " d-none d-xl-block";
66 responsiveClassMobile = " d-block d-xl-none";
67 }
68 69 var headerDesktopLink = Model.Area.Item?.GetLink("HeaderDesktop") ?? null;
70 var headerMobileLink = Model.Area.Item?.GetLink("HeaderMobile") ?? null;
71 72 var footerDesktopLink = Model.Area.Item?.GetLink("FooterDesktop") ?? null;
73 var footerMobileLink = Model.Area.Item?.GetLink("FooterMobile") ?? null;
74 75 var disableWideBreakpoints = Model.Area?.Item?.GetRawValueString("DisableWideBreakpoints", "default");
76 77 string customHeaderInclude = !string.IsNullOrEmpty(Model.Area.Item.GetRawValueString("CustomHeaderInclude")) ? Model.Area.Item.GetFile("CustomHeaderInclude").Name : string.Empty;
78 79 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
80 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt;
81 82 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css"));
83 84 85 if (cssPageId != 0)
86 {
87 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css"));
88 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
89 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt)
90 {
91 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId);
92 cssPageview.Redirect = false;
93 cssPageview.Output();
94 }
95 }
96 97 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt)
98 {
99 //Branding page has been saved or the file is missing. Rewrite the file to disc.
100 if (brandingPageId > 0)
101 {
102 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId);
103 brandingPageview.Redirect = false;
104 brandingPageview.Output();
105 }
106 }
107108 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt)
109 {
110 //Branding page has been saved or the file is missing. Rewrite the file to disc.
111 if (themePageId > 0)
112 {
113 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId);
114 themePageview.Redirect = false;
115 themePageview.Output();
116 }
117 }
118119 // Schema.org details for PDP
120 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID");
121 bool isArticlePage = Model.ItemType == "Swift_Article";
122 string schemaOrgType = string.Empty;
123124 if (isProductDetailsPage)
125 {
126 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\"";
127 }
128129 if (isArticlePage)
130 {
131 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\"";
132 }
133134135 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css"));
136 var cssStyleFileInfoCustom = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/custom.css"));
137 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js"));
138139 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
140141 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png");
142 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png");
143144 string headerCssClass = "sticky-top";
145 bool movePageBehind = false;
146147 if (Model.PropertyItem != null)
148 {
149 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top");
150 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false;
151 }
152153 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass;
154 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass;
155156 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim();
157 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim();
158 string userCentrics = Model.Area.Item.GetString("UsercentricsScript");
159 bool allowTracking = true;
160161 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;");
162 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/custom.css?{cssStyleFileInfoCustom.LastWriteTime.Ticks}>; rel=preload; as=style;");
163 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;");
164 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;");
165166167 SetMetaTags();
168169 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>();
170171 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage;
172 languages.Add(masterPage);
173 if (masterPage?.Languages != null)
174 {
175 foreach (var language in masterPage.Languages)
176 {
177 languages.Add(language);
178 }
179 }
180181 Uri url = Dynamicweb.Context.Current.Request.Url;
182 string hostName = url.Host;
183184 <!doctype html>
185 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName">
186 <head>
187 <!-- @swiftVersion -->
188 @* Required meta tags *@
189 <meta charset="utf-8">
190 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0">
191 <link rel="shortcut icon" href="@favicon">
192 <link rel="apple-touch-icon" href="@appleTouchIcon">
193194 @Model.MetaTags
195196 @{
197 var alreadyWrittenTwoletterIsos = new List<string>();
198 @* Languages meta data *@
199 foreach (var language in languages)
200 {
201 hostName = url.Host;
202 if (language?.Area != null)
203 {
204 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock))
205 {
206 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk
207 }
208 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published)
209 {
210 if (!string.IsNullOrEmpty(language.Area.DomainLock))
211 {
212 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk
213 }
214 string querystring = $"Default.aspx?ID={language.ID}";
215 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"]))
216 {
217 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}";
218 }
219 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
220 {
221 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}";
222 }
223 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"]))
224 {
225 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}";
226 }
227228 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring);
229 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1)
230 {
231 friendlyUrl = "/";
232 }
233 string href = $"{url.Scheme}://{hostName}{friendlyUrl}";
234235236 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href">
237 if (!alreadyWrittenTwoletterIsos.Contains(language.Area.CultureInfo.TwoLetterISOLanguageName))
238 {
239 alreadyWrittenTwoletterIsos.Add(language.Area.CultureInfo.TwoLetterISOLanguageName);
240 <link rel="alternate" hreflang="@language.Area.CultureInfo.TwoLetterISOLanguageName.ToLower()" href="@href">
241 }
242 }
243 }
244 }
245 }
246247 <title>@Model.Title</title>
248 @* Bootstrap + Swift stylesheet *@
249 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
250 <link href="/Files/Templates/Designs/Swift/Assets/css/custom.css?@cssStyleFileInfoCustom.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
251252 @if (disableWideBreakpoints != "disableBoth")
253 {
254 <style>
255 @@media ( min-width: 1600px ) {
256 .container-xxl,
257 .container-xl,
258 .container-lg,
259 .container-md,
260 .container-sm,
261 .container {
262 max-width: 1520px;
263 }
264 }
265 </style>
266267268269 if (disableWideBreakpoints != "disableUltraWideOnly")
270 {
271 <style>
272 @@media ( min-width: 1920px ) {
273 .container-xxl,
274 .container-xl,
275 .container-lg,
276 .container-md,
277 .container-sm,
278 .container {
279 max-width: 1820px;
280 }
281 }
282 </style>
283 }
284 }
285286 @* Branding and Themes min stylesheet *@
287 <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">
288 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script>
289 <script type="module">
290 swift.Scroll.hideHeadersOnScroll();
291 swift.Scroll.handleAlternativeTheme();
292293 //Only load if AOS
294 const aosColumns = document.querySelectorAll('[data-aos]');
295 if (aosColumns.length > 0) {
296 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js');
297 document.addEventListener('load.swift.assetloader', function () {
298 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') });
299 });
300 }
301 </script>
302303 @if (!string.IsNullOrWhiteSpace(userCentrics))
304 {
305306 <link rel="preconnect" href="//app.usercentrics.eu">
307 <link rel="preconnect" href="//api.usercentrics.eu">
308 <link rel="preload" href="//app.usercentrics.eu/browser-ui/latest/loader.js" as="script">
309310 }
311312 @if (!string.IsNullOrWhiteSpace(userCentrics))
313 {
314 <text>@userCentrics</text>
315 }
316317 @* Google tag manager *@
318 @if (!string.IsNullOrWhiteSpace(userCentrics) && !string.IsNullOrWhiteSpace(googleTagManagerID))
319 {
320 <script type="text/plain" data-usercentrics="Google Tag Manager">
321 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
322 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
323 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
324 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
325 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
326327 function gtag() { dataLayer.push(arguments); }
328 </script>
329 } else if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
330 {
331 <script>
332 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
333 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
334 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
335 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
336 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
337338 function gtag() { dataLayer.push(arguments); }
339 </script>
340 }
341342 @if (!string.IsNullOrWhiteSpace(userCentrics) && !string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID))
343 {
344 var GoogleAnalyticsDebugMode = "";
345346 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
347 {
348 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
349 }
350351 <script type="text/plain" data-usercentrics="Google Analytics" async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
352 <script type="text/plain" data-usercentrics="Google Analytics">
353 window.dataLayer = window.dataLayer || [];
354 function gtag() { dataLayer.push(arguments); }
355 gtag('js', new Date());
356 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
357 </script>
358 } else if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking)
359 {
360 var GoogleAnalyticsDebugMode = "";
361362 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
363 {
364 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
365 }
366367 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
368 <script>
369 window.dataLayer = window.dataLayer || [];
370 function gtag() { dataLayer.push(arguments); }
371 gtag('js', new Date());
372 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
373 </script>
374 }
375376 @if (!string.IsNullOrWhiteSpace(customHeaderInclude))
377 {
378 @RenderPartial($"Components/Custom/{customHeaderInclude}")
379 }
380381 @if (allowTracking && !string.IsNullOrWhiteSpace(scriptsHeader)){
382 @scriptsHeader
383 }
384385 </head>
386 <body class="brand @(masterTheme)" id="page@(Model.ID)">
387388 @* Google tag manager *@
389 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
390 {
391 <noscript>
392 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)"
393 height="0" width="0" style="display:none;visibility:hidden"></iframe>
394 </noscript>
395 }
396397 @if (renderAsResponsive || !renderMobile)
398 {
399 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop">
400 @if (headerDesktopLink != null)
401 {
402 @RenderGrid(headerDesktopLink.PageId)
403 }
404 </header>
405 }
406407 @if ((renderAsResponsive || renderMobile))
408 {
409 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile">
410 @if (headerMobileLink != null)
411 {
412 @RenderGrid(headerMobileLink.PageId)
413 }
414 </header>
415 }
416417 <div data-intersect></div>
418419 <main id="content" @(schemaOrgType)>
420 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
421 @using System
422 @using Dynamicweb.Ecommerce.ProductCatalog
423424425 @{
426 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty;
427 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop";
428429 bool isArticlePagePage = Model.ItemType == "Swift_Article";
430 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage";
431 string schemaOrgProp = string.Empty;
432 if (isArticlePagePage)
433 {
434 schemaOrgProp = "itemprop=\"articleBody\"";
435 }
436437 string theme = "";
438 string gridContent = "";
439440 if (Model.PropertyItem != null)
441 {
442 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
443 }
444445 if (Model.Item != null || Pageview.IsVisualEditorMode)
446 {
447 if (!isProductDetail)
448 {
449 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page");
450 }
451 else
452 {
453 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId);
454 if (productObject != null)
455 {
456 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject?.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty;
457 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage");
458459 @RenderGrid(detailPageId)
460 }
461 }
462 }
463464 bool doNotRenderPage = false;
465466 //Check if we are on the poduct detail page, and if there is data to render
467 ProductViewModel product = new ProductViewModel();
468 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
469 {
470 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
471 if (string.IsNullOrEmpty(product.Id))
472 {
473 doNotRenderPage = true;
474 }
475 }
476477 //Render the page
478 if (!doNotRenderPage)
479 {
480 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page";
481482 if (Pageview.IsVisualEditorMode)
483 {
484 @Model.Placeholder("dwcontent", "content", "default:true;sort:1")
485 }
486487 <div class="@theme @itemIdentifier" @schemaOrgProp>
488 @if (isArticleListPage)
489 {
490 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\"";
491492 <form @hx id="ArticleFacetForm">
493 @gridContent
494 </form>
495 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/htmx.js"></script>
496 <script type="module">
497 document.addEventListener('htmx:confirm', (event) => {
498 let filters = event.detail.elt.querySelectorAll('select');
499 for (var i = 0; i < filters.length; i++) {
500 let input = filters[i];
501 if (input.name && !input.value) {
502 input.name = '';
503 }
504 }
505 });
506507 document.addEventListener('htmx:beforeOnLoad', (event) => {
508 swift.Scroll.stopIntersectionObserver();
509 });
510511 document.addEventListener('htmx:afterOnLoad', () => {
512 swift.Scroll.hideHeadersOnScroll();
513 swift.Scroll.handleAlternativeTheme();
514 });
515 </script>
516 }
517 else
518 {
519 @gridContent
520 }
521 </div>
522523 }
524 else
525 {
526 <div class="container">
527 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div>
528 </div>
529 }
530531 if (!Model.IsCurrentUserAllowed)
532 {
533 int signInPage = GetPageIdByNavigationTag("SignInPage");
534 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage");
535536 if (!Pageview.IsVisualEditorMode)
537 {
538 if (signInPage != 0)
539 {
540 if (signInPage != Model.ID)
541 {
542 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage);
543 }
544 else
545 {
546 if (dashboardPage != 0)
547 {
548 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage);
549 }
550 else
551 {
552 Dynamicweb.Context.Current.Response.Redirect("/");
553 }
554 }
555 }
556 else
557 {
558 <div class="alert alert-dark m-0" role="alert">
559 <span>@Translate("You do not have access to this page")</span>
560 </div>
561 }
562 }
563 else
564 {
565 <div class="alert alert-dark m-0" role="alert">
566 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span>
567 </div>
568 }
569 }
570 }
571572 </main>
573574 @if (renderAsResponsive || !renderMobile)
575 {
576 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop">
577 @if (footerDesktopLink != null)
578 {
579 @RenderGrid(footerDesktopLink.PageId)
580 }
581582 @if (allowTracking && !string.IsNullOrWhiteSpace(customFooterScripts)){
583 @customFooterScripts
584 }
585 </footer>
586 }
587588 @if (renderAsResponsive || renderMobile)
589 {
590 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile">
591 @if (footerMobileLink != null)
592 {
593 @RenderGrid(footerMobileLink.PageId)
594 }
595 </footer>
596 }
597598 @* Render any offcanvas menu here *@
599 @RenderSnippet("offcanvas")
600601 @{
602 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]);
603 }
604605 @* Language selector modal *@
606 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true">
607 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent">
608 @* The content here comes from an external request *@
609 </div>
610 </div>
611612 @* Favorite toast *@
613 <div aria-live="polite" aria-atomic="true">
614 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
615 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
616 <div class="toast-header">
617 <strong class="me-auto">@Translate("Favorite list updated")</strong>
618 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
619 </div>
620 <div class="toast-body d-flex gap-3">
621 <div id="favoriteNotificationToast_Image"></div>
622 <div id="favoriteNotificationToast_Text"></div>
623 </div>
624 </div>
625 </div>
626 </div>
627628 @* Modal for dynamic content *@
629 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true">
630 <div class="modal-dialog modal-dialog-centered modal-md">
631 <div class="modal-content theme light" id="DynamicModalContent">
632 @* The content here comes from an external request *@
633 </div>
634 </div>
635 </div>
636637 @* Offcanvas for dynamic content *@
638 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas">
639 @* The content here comes from an external request *@
640 </div>
641642 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]))
643 {
644 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light";
645646 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040">
647 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true">
648 <div class="toast-header">
649 <strong class="me-auto">@Translate("Connection down")</strong>
650 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
651 </div>
652 <div class="toast-body">
653 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.")
654 </div>
655 </div>
656 </div>
657 }
658659 @if (miniCartEnabled)
660 {
661 @* Open MiniCart when the cart is updated *@
662 <script type="module">
663 document.addEventListener('updated.swift.cart', (event) => {
664 let orderContext = event?.detail?.formData?.get("OrderContext");
665 updateCartSummary(orderContext);
666667 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") {
668 <text>openMiniCartOffcanvas();</text>
669 }
670 });
671 </script>
672673 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3")
674 {
675 @* Open MiniCart when toggle is clicked *@
676 <script type="module">
677 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity');
678 miniCartToggles?.forEach((toggle) => {
679 toggle.parentElement.addEventListener('click', (event) => {
680 event.preventDefault();
681 let orderContext = toggle.dataset?.orderContext;
682 updateCartSummary(orderContext);
683684 openMiniCartOffcanvas();
685 });
686 });
687 </script>
688 }
689690 <script>
691692 const updateCartSummary = (orderContext) => {
693 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
694 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas);
695 };
696697 const openMiniCartOffcanvas = () => {
698 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
699 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas);
700 dynamicOffcanvas.classList.add('overflow-y-auto');
701702 if (!miniCartOffcanvas._isShown) {
703 miniCartOffcanvas.show();
704 hideActiveOffcanvases(miniCartOffcanvas);
705 }
706 };
707708 const hideActiveOffcanvases = (miniCartOffcanvas) => {
709 let activeOffcanvases = document.querySelectorAll('.offcanvas.show');
710 activeOffcanvases?.forEach((offCanvas) => {
711 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas);
712 if (offCanvas !== miniCartOffcanvas) {
713 offCanvas.hide();
714 }
715 });
716 };
717718 </script>
719 }
720721 </body>
722723 </html>
724725 }
726 else if (Pageview.IsVisualEditorMode)
727 {
728 <head>
729 <title>@Model.Title</title>
730 @* Bootstrap + Swift stylesheet *@
731 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css">
732 </head>
733 <body class="p-3">
734 <div class="alert alert-danger" role="alert">
735 @Translate("Basic Swift setup is needed!")
736 </div>
737738 @if (brandingPage == null)
739 {
740 <div class="alert alert-warning" role="alert">
741 @Translate("Please add a Branding page and reference it in website settings")
742 </div>
743 }
744745 @if (themesParagraphs == null)
746 {
747 <div class="alert alert-warning" role="alert">
748 @Translate("Please add a Themes collection page and reference it in website settings")
749 </div>
750 }
751 </body>
752 }
753754755 @functions {
756 void SetMetaTags()
757 {
758 //Verification Tokens
759 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : "";
760761 //Generic Site Values
762 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : "";
763 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : "";
764 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : "";
765766 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : "";
767768 //Page specific values
769 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : "";
770 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image");
771 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : "";
772 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : "";
773774 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : "";
775 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : "";
776 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : "";
777 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image");
778 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : "";
779 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}";
780781 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
782 {
783 if (!string.IsNullOrEmpty(Model.Description))
784 {
785 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">");
786 }
787 else
788 {
789 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">");
790 }
791792 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
793 {
794 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
795 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
796 }
797 else if (openGraphImage != null)
798 {
799 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
800 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
801 }
802803 if (!string.IsNullOrEmpty(openGraphImageALT))
804 {
805 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">");
806 }
807 if (!string.IsNullOrEmpty(twitterCardDescription))
808 {
809 Pageview.Meta.AddTag("twitter:description", twitterCardDescription);
810 }
811812 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
813 {
814 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}");
815 }
816 else if (twitterCardImage != null)
817 {
818 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}");
819 }
820821 if (!string.IsNullOrEmpty(twitterCardImageALT))
822 {
823 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT);
824 }
825 }
826827 if (!string.IsNullOrEmpty(siteVerificationGoogle))
828 {
829 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle);
830 }
831832 if (!string.IsNullOrEmpty(openGraphFacebookAppID))
833 {
834 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">");
835 }
836837 if (!string.IsNullOrEmpty(openGraphType))
838 {
839 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">");
840 }
841842 if (!string.IsNullOrEmpty(openGraphSiteName))
843 {
844 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">");
845 }
846847 if (!string.IsNullOrEmpty(openGraphSiteName))
848 {
849 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">");
850 }
851852 if (!string.IsNullOrEmpty(Model.Title))
853 {
854 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">");
855 }
856 else
857 {
858 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">");
859 }
860861 if (!string.IsNullOrEmpty(twitterCardSite))
862 {
863 Pageview.Meta.AddTag("twitter:site", twitterCardSite);
864 }
865866 if (!string.IsNullOrEmpty(twitterCardURL))
867 {
868 Pageview.Meta.AddTag("twitter:url", twitterCardURL);
869 }
870871 if (!string.IsNullOrEmpty(twitterCardTitle))
872 {
873 Pageview.Meta.AddTag("twitter:title", twitterCardTitle);
874 }
875 }
876 }
877