Error executing template "Designs/Swift/Swift_Page.cshtml"
System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
---> System.ComponentModel.Win32Exception (2): The system cannot find the file specified.
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.Open()
at Dynamicweb.Data.DatabaseConnectionProvider.CreateConnection(Boolean open)
at Dynamicweb.Data.Database.CreateConnection()
at Dynamicweb.Data.Database.CreateDataReader(CommandBuilder commandBuilder, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout)
at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductById(String productId, String productVariantId, String productLanguageId)
at Dynamicweb.Ecommerce.Products.ProductService.FetchMissingProducts(IEnumerable`1 keys)
at Dynamicweb.Caching.ServiceCache`2.GetCache(IEnumerable`1 keys)
at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, User user, Boolean showUntranslated)
at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId)
at CompiledRazorTemplates.Dynamic.RazorEngine_c08ef14740574a9286ee76cd6f22f7ae.ExecuteAsync()
at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
at Dynamicweb.Rendering.Template.RenderRazorTemplate()
ClientConnectionId:00000000-0000-0000-0000-000000000000
Error Number:2,State:0,Class:20
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
2 @using System
3 @using Dynamicweb
4 @using Dynamicweb.Environment
5 @using Dynamicweb.Frontend
6 7 @functions {
8 string GetCookieOptInPermission(string category)
9 {
10 bool categoryOrAllGranted = false;
11 12 if (CookieManager.IsCookieManagementActive)
13 {
14 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
15 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
16 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All;
17 }
18 19 return categoryOrAllGranted ? "granted" : "denied";
20 }
21 22 bool AllowTracking()
23 {
24 bool allowTracking = true;
25 if (CookieManager.IsCookieManagementActive)
26 {
27 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
28 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
29 30 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing"));
31 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional;
32 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither);
33 34 allowTracking = consentAtLeastOne;
35 }
36 return allowTracking;
37 }
38 }
39 40 @{
41 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID;
42 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false;
43 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3";
44 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart;
45 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0;
46 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0;
47 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0;
48 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null;
49 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null;
50 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null;
51 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