diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor b/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor index 4b973c48..8672c85a 100644 --- a/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor +++ b/Oqtane.Client/Themes/Controls/Container/ModuleActions.razor @@ -20,6 +20,7 @@ protected override void OnParametersSet() { // trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries + // only include properties required by the ModuleActionsInteractive component _pageState = new PageState { Alias = PageState.Alias, diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 717cc31e..f38a66c3 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -91,6 +91,7 @@ } // trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries + // only include properties required by the ControlPanelInteractive component _pageState = new PageState { Alias = PageState.Alias, diff --git a/Oqtane.Client/UI/ContainerBuilder.razor b/Oqtane.Client/UI/ContainerBuilder.razor index 6a769aed..76565c6b 100644 --- a/Oqtane.Client/UI/ContainerBuilder.razor +++ b/Oqtane.Client/UI/ContainerBuilder.razor @@ -6,7 +6,7 @@ @if (ComponentType != null && _visible) { - + @if (_useadminborder) {
diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index e9a634d3..0fda480f 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -10,11 +10,11 @@ @((MarkupString)_comment) @if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static) { - + } else { - + } } @if (PageState.ModuleId == -1) @@ -32,6 +32,7 @@ private bool _prerender; private string _comment; + private PageState _pageState; protected override void OnParametersSet() { @@ -48,11 +49,12 @@ } _comment += " -->"; + _pageState = PageState.Clone(); if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Interactive) { // trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries - // please note that this performance optimization results in the PageState.Pages property not being available for use in Interactive components - PageState.Site.Pages = new List(); + // please note that this performance optimization results in the PageState.Pages property not being available for use in downstream Interactive components + _pageState.Site.Pages = new List(); } } diff --git a/Oqtane.Client/UI/PageState.cs b/Oqtane.Client/UI/PageState.cs index a038a81e..91cf158c 100644 --- a/Oqtane.Client/UI/PageState.cs +++ b/Oqtane.Client/UI/PageState.cs @@ -37,5 +37,34 @@ namespace Oqtane.UI { get { return Site?.Languages; } } + + public PageState Clone() + { + return new PageState + { + Alias = Alias, + Site = Site, + Page = Page, + Modules = Modules, + User = User, + Uri = Uri, + Route = Route, + QueryString = QueryString, + UrlParameters = UrlParameters, + ModuleId = ModuleId, + Action = Action, + EditMode = EditMode, + LastSyncDate = LastSyncDate, + RenderMode = RenderMode, + Runtime = Runtime, + VisitorId = VisitorId, + RemoteIPAddress = RemoteIPAddress, + ReturnUrl = ReturnUrl, + IsInternalNavigation = IsInternalNavigation, + RenderId = RenderId, + Refresh = Refresh, + AllowCookies = AllowCookies + }; + } } } diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 70226c2e..633cd4fd 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -29,7 +29,7 @@ else RenderFragment DynamicComponent { get; set; } protected override void OnParametersSet() - { + { if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction) { _useadminborder = true; @@ -45,12 +45,6 @@ else { foreach (Module module in PageState.Modules) { - // set renderid - this allows the framework to determine which components should be rendered when PageState changes - if (module.RenderId != PageState.RenderId) - { - module.RenderId = PageState.RenderId; - } - var pane = module.Pane; if (module.ModuleId == PageState.ModuleId && PageState.Action != Constants.DefaultAction) { @@ -101,7 +95,7 @@ else if (authorized) { - CreateComponent(builder, module, module.PageModuleId); + CreateComponent(builder, module); } } } @@ -112,7 +106,7 @@ else // check if user is authorized to view module if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList)) { - CreateComponent(builder, module, -1); + CreateComponent(builder, module); } } } @@ -121,14 +115,11 @@ else }; } - private void CreateComponent(RenderTreeBuilder builder, Module module, int key) + private void CreateComponent(RenderTreeBuilder builder, Module module) { builder.OpenComponent(0, typeof(ContainerBuilder)); builder.AddAttribute(1, "ModuleState", module); - if (key != -1) - { - builder.SetKey(module.PageModuleId); - } + builder.SetKey(module.PageModuleId); builder.CloseComponent(); } } diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor index 2c451f29..dbaac7f5 100644 --- a/Oqtane.Client/UI/RenderModeBoundary.razor +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -4,8 +4,8 @@ @inject ILogService LoggingService @inherits ErrorBoundary - - + + @if (CurrentException is null) { @if (ModuleType != null) diff --git a/Oqtane.Client/UI/Routes.razor b/Oqtane.Client/UI/Routes.razor index 20dc0a09..6081966c 100644 --- a/Oqtane.Client/UI/Routes.razor +++ b/Oqtane.Client/UI/Routes.razor @@ -48,12 +48,18 @@ private bool _initialized = false; private bool _installed = false; - private string _display = "display: none;"; + private string _display = ""; private PageState _pageState { get; set; } protected override async Task OnParametersSetAsync() { + if (PageState != null && PageState.RenderMode == RenderModes.Interactive && PageState.Site.Prerender) + { + // prevents flash on initial interactive page load when using prerendering + _display = "display: none;"; + } + SiteState.AntiForgeryToken = AntiForgeryToken; SiteState.AuthorizationToken = AuthorizationToken; SiteState.Platform = Platform; @@ -61,7 +67,7 @@ if (Runtime == Runtimes.Hybrid) { - var installation = await InstallationService.IsInstalled(); + var installation = await InstallationService.IsInstalled(); _installed = installation.Success; if (installation.Alias != null) { @@ -73,8 +79,8 @@ if (PageState != null) { _pageState = PageState; - SiteState.Alias = PageState.Alias; - SiteState.RemoteIPAddress = (PageState != null) ? PageState.RemoteIPAddress : ""; + SiteState.Alias = _pageState.Alias; + SiteState.RemoteIPAddress = _pageState.RemoteIPAddress; _installed = true; } } @@ -85,9 +91,7 @@ { if (firstRender) { - // prevents flash on initial interactive page load _display = ""; - StateHasChanged(); } } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 3c3c81fe..a345a7f0 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -71,7 +71,7 @@ { if (PageState == null || PageState.Refresh) { - await Refresh(); + await Refresh(false); } } @@ -79,7 +79,7 @@ { _absoluteUri = args.Location; _isInternalNavigation = true; - await Refresh(); + await Refresh(true); } Task IHandleAfterRender.OnAfterRenderAsync() @@ -93,7 +93,7 @@ } [SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")] - private async Task Refresh() + private async Task Refresh(bool locationChanged) { Site site = null; Page page = null; @@ -103,6 +103,7 @@ var refresh = false; var lastsyncdate = DateTime.MinValue; var visitorId = -1; + var renderid = Guid.Empty; _error = ""; Route route = new Route(_absoluteUri, SiteState.Alias.Path); @@ -288,11 +289,21 @@ modules = PageState.Modules; } + // renderid allows the framework to determine which module components should be rendered on a page + if (PageState == null || locationChanged) + { + renderid = Guid.NewGuid(); + } + else + { + renderid = PageState.RenderId; + } + // load additional metadata for current page page = ProcessPage(page, site, user, SiteState.Alias, action); // load additional metadata for modules - (page, modules) = ProcessModules(site, page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias); + (page, modules) = ProcessModules(site, page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias, renderid); //cookie consent var _allowCookies = PageState?.AllowCookies; @@ -324,7 +335,7 @@ RemoteIPAddress = SiteState.RemoteIPAddress, ReturnUrl = returnurl, IsInternalNavigation = _isInternalNavigation, - RenderId = Guid.NewGuid(), + RenderId = renderid, Refresh = false, AllowCookies = _allowCookies.GetValueOrDefault(true) }; @@ -447,7 +458,7 @@ return page; } - private (Page Page, List Modules) ProcessModules(Site site, Page page, List modules, int moduleid, string action, string defaultcontainertype, Alias alias) + private (Page Page, List Modules) ProcessModules(Site site, Page page, List modules, int moduleid, string action, string defaultcontainertype, Alias alias, Guid renderid) { var paneindex = new Dictionary(); @@ -592,6 +603,8 @@ { module.ContainerType = defaultcontainertype; } + + module.RenderId = renderid; } foreach (Module module in modules.Where(item => item.PageId == page.PageId))