From 35f87d25be70b2c12b111a26e0b8f0200be68cd1 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 30 Mar 2020 20:42:43 -0400 Subject: [PATCH] Added Favicon support, Progressive Web App support, page title and url support, and private/public user registration options --- Oqtane.Client/Modules/Admin/Pages/Add.razor | 22 ++- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 28 +++- Oqtane.Client/Modules/Admin/Site/Index.razor | 130 +++++++++++++++--- Oqtane.Client/Modules/Admin/Sites/Add.razor | 5 + Oqtane.Client/Modules/ModuleBase.cs | 4 +- Oqtane.Client/Themes/Controls/Menu.razor | 39 +++++- .../Themes/Controls/UserProfile.razor | 5 +- Oqtane.Client/Themes/ThemeControlBase.cs | 4 +- Oqtane.Client/UI/Installer.razor | 7 +- Oqtane.Client/UI/Interop.cs | 29 +++- Oqtane.Client/UI/ThemeBuilder.razor | 61 +++++++- Oqtane.Client/wwwroot/index.html | 3 + Oqtane.Client/wwwroot/js/interop.js | 50 ++++++- Oqtane.Client/wwwroot/service-worker.js | 2 + Oqtane.Server/Controllers/PageController.cs | 2 + Oqtane.Server/Pages/_Host.cshtml | 3 + Oqtane.Server/Repository/SiteRepository.cs | 2 + Oqtane.Server/Scripts/Tenant.00.00.00.sql | 7 + Oqtane.Server/wwwroot/js/interop.js | 50 ++++++- Oqtane.Server/wwwroot/service-worker.js | 2 + Oqtane.Shared/Models/Page.cs | 2 + Oqtane.Shared/Models/Site.cs | 5 + Oqtane.Shared/Shared/Utilities.cs | 7 + 23 files changed, 422 insertions(+), 47 deletions(-) create mode 100644 Oqtane.Client/wwwroot/service-worker.js create mode 100644 Oqtane.Server/wwwroot/service-worker.js diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index fc0644a3..77af0407 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -15,6 +15,14 @@ + + + + + + + + @@ -74,6 +82,14 @@ + + + + + + + + @@ -151,12 +167,14 @@ List _themeList; List _pageList; - string _name; + string _name = ""; + string _title = ""; string _path = ""; string _parentid; string _insert = ">>"; List _children; int _childid = -1; + string _url = ""; string _isnavigation = "True"; string _ispersonalizable = "False"; string _mode = "view"; @@ -244,6 +262,7 @@ page = new Page(); page.SiteId = PageState.Page.SiteId; page.Name = _name; + page.Title = _title; if (_path == "") { _path = _name; @@ -289,6 +308,7 @@ break; } page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation)); + page.Url = _url; page.EditMode = (_mode == "edit" ? true : false); page.ThemeType = _themetype; page.LayoutType = (_layouttype == null ? "" : _layouttype); diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 91a57188..7dc91d72 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -15,6 +15,14 @@ + + + + + + + + @@ -74,6 +82,14 @@ } + + + + + + + + @@ -153,7 +169,7 @@ - + @@ -173,14 +189,16 @@ List _themeList; List _pageList; int _pageId; - string _name; - string _path; + string _name = ""; + string _title = ""; + string _path = ""; string _currentparentid; string _parentid; string _insert = "="; List _children; int _childid = -1; string _isnavigation; + string _url = ""; string _ispersonalizable; string _mode; string _themetype; @@ -213,6 +231,7 @@ if (page != null) { _name = page.Name; + _title = page.Title; _path = page.Path; if (_path.Contains("/")) { @@ -228,6 +247,7 @@ } _currentparentid = _parentid; _isnavigation = page.IsNavigation.ToString(); + _url = page.Url; _ispersonalizable = page.IsPersonalizable.ToString(); _mode = (page.EditMode) ? "edit" : "view"; _themetype = page.ThemeType; @@ -313,6 +333,7 @@ string currentPath = page.Path; page.Name = _name; + page.Title = _title; if (_path == "" && _name.ToLower() != "home") { _path = _name; @@ -361,6 +382,7 @@ } } page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation)); + page.Url = _url; page.EditMode = (_mode == "edit"); page.ThemeType = _themetype; page.LayoutType = _layouttype ?? ""; diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index a6bdcac0..9e36c6ba 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -12,7 +12,7 @@ + + + + + + + +
- + @@ -20,7 +20,7 @@
- + @@ -28,7 +28,7 @@
- + @@ -36,15 +36,23 @@
- + - +
- + + + +
+
- +
- +
- + + + +
+
- + @@ -119,7 +138,7 @@
- + @@ -127,7 +146,7 @@
- + @@ -135,7 +154,7 @@
- + @@ -143,7 +162,7 @@
- + @@ -151,6 +170,43 @@
+ + +
+ + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+
+
Cancel @@ -173,10 +229,13 @@ List _aliasList; string _urls = ""; int _logofileid = -1; - FileManager _filemanager; + FileManager _logofilemanager; + int _faviconfileid = -1; + FileManager _faviconfilemanager; string _themetype; string _layouttype; string _containertype; + string _allowregistration; string _smtphost = ""; string _smtpport = ""; @@ -184,6 +243,12 @@ string _smtpusername = ""; string _smtppassword = ""; + string _pwaisenabled; + int _pwaappiconfileid = -1; + FileManager _pwaappiconfilemanager; + int _pwasplashiconfileid = -1; + FileManager _pwasplashiconfilemanager; + string _createdby; DateTime _createdon; string _modifiedby; @@ -212,10 +277,15 @@ { _logofileid = site.LogoFileId.Value; } + if (site.FaviconFileId != null) + { + _faviconfileid = site.FaviconFileId.Value; + } _themetype = site.DefaultThemeType; _panelayouts = ThemeService.GetPaneLayoutTypes(_themeList, _themetype); _layouttype = site.DefaultLayoutType; _containertype = site.DefaultContainerType; + _allowregistration = site.AllowRegistration.ToString(); Dictionary settings = await SettingService.GetSiteSettingsAsync(site.SiteId); _smtphost = SettingService.GetSetting(settings, "SMTPHost", ""); @@ -224,6 +294,16 @@ _smtpusername = SettingService.GetSetting(settings, "SMTPUsername", ""); _smtppassword = SettingService.GetSetting(settings, "SMTPPassword", ""); + _pwaisenabled = site.PwaIsEnabled.ToString(); + if (site.PwaAppIconFileId != null) + { + _pwaappiconfileid = site.PwaAppIconFileId.Value; + } + if (site.PwaSplashIconFileId != null) + { + _pwasplashiconfileid = site.PwaSplashIconFileId.Value; + } + _createdby = site.CreatedBy; _createdon = site.CreatedOn; _modifiedby = site.ModifiedBy; @@ -286,16 +366,34 @@ { site.Name = _name; site.LogoFileId = null; - int logofileid = _filemanager.GetFileId(); + int logofileid = _logofilemanager.GetFileId(); if (logofileid != -1) { site.LogoFileId = logofileid; } + int faviconfileid = _faviconfilemanager.GetFileId(); + if (faviconfileid != -1) + { + site.FaviconFileId = faviconfileid; + } site.DefaultThemeType = _themetype; site.DefaultLayoutType = (_layouttype == null ? "" : _layouttype); site.DefaultContainerType = _containertype; + site.AllowRegistration = (_allowregistration == null ? true : Boolean.Parse(_allowregistration)); site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted)); + site.PwaIsEnabled = (_pwaisenabled == null ? true : Boolean.Parse(_pwaisenabled)); + int pwaappiconfileid = _pwaappiconfilemanager.GetFileId(); + if (pwaappiconfileid != -1) + { + site.PwaAppIconFileId = pwaappiconfileid; + } + int pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId(); + if (pwasplashiconfileid != -1) + { + site.PwaSplashIconFileId = pwasplashiconfileid; + } + site = await SiteService.UpdateSiteAsync(site, PageState.Alias); _urls = _urls.Replace("\n", ","); diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index 2afb5ed4..6bfc7cfe 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -248,9 +248,14 @@ else site.TenantId = int.Parse(_tenantid); site.Name = _name; site.LogoFileId = null; + site.FaviconFileId = null; site.DefaultThemeType = _themetype; site.DefaultLayoutType = (_layouttype == null ? "" : _layouttype); site.DefaultContainerType = _containertype; + site.PwaIsEnabled = false; + site.PwaAppIconFileId = null; + site.PwaSplashIconFileId = null; + site.AllowRegistration = false; site.SiteTemplateType = _sitetemplatetype; site = await SiteService.AddSiteAsync(site, aliases[0]); diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 4e0b54a7..1fa56c65 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -87,9 +87,7 @@ namespace Oqtane.Modules public string ContentUrl(int fileid) { - string url = (PageState.Alias.Path == "") ? "/~" : PageState.Alias.Path; - url += Constants.ContentUrl + fileid.ToString(); - return url; + return Utilities.ContentUrl(PageState.Alias.Path, fileid); } // user feedback methods diff --git a/Oqtane.Client/Themes/Controls/Menu.razor b/Oqtane.Client/Themes/Controls/Menu.razor index 07e09d34..fc7c8bed 100644 --- a/Oqtane.Client/Themes/Controls/Menu.razor +++ b/Oqtane.Client/Themes/Controls/Menu.razor @@ -41,7 +41,19 @@ securitylevel = int.MaxValue; menu += "
  • "; - menu += ""; + if (string.IsNullOrEmpty(p.Url)) + { + menu += ""; + } + else + { + string target = ""; + if (p.Url.StartsWith("http")) + { + target = " target=\"_new\""; + } + menu += ""; + } if (p.HasChildren) { menu += ""; @@ -69,6 +81,9 @@ private void CreateHorizontalMenu() { + string url = ""; + string target = ""; + menu = ""; menu += "
    "; menu += "
      "; @@ -76,18 +91,32 @@ { if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, p.Permissions) && p.ParentId == PageState.Page.ParentId && p.Level == PageState.Page.Level) { + if (string.IsNullOrEmpty(p.Url)) + { + url = NavigateUrl(p.Path); + target = ""; + } + else + { + url = p.Url; + if (p.Url.StartsWith("http")) + { + target = " target=\"_new\""; + } + } + if (p.PageId == PageState.Page.PageId) { menu += "
    • " + - "" + - ((p.Icon != "") ? " " : "") + + "" + + ((p.Icon != "") ? " " : "") + p.Name + " (current)
    • "; } else { menu += "
    • " + - "" + - ((p.Icon != "") ? " " : "") + + "" + + ((p.Icon != "") ? " " : "") + p.Name + "
    • "; } } diff --git a/Oqtane.Client/Themes/Controls/UserProfile.razor b/Oqtane.Client/Themes/Controls/UserProfile.razor index f43f3747..1f101caf 100644 --- a/Oqtane.Client/Themes/Controls/UserProfile.razor +++ b/Oqtane.Client/Themes/Controls/UserProfile.razor @@ -10,7 +10,10 @@ - + @if (PageState.Site.AllowRegistration) + { + + } diff --git a/Oqtane.Client/Themes/ThemeControlBase.cs b/Oqtane.Client/Themes/ThemeControlBase.cs index 13cc1923..91b2a7cf 100644 --- a/Oqtane.Client/Themes/ThemeControlBase.cs +++ b/Oqtane.Client/Themes/ThemeControlBase.cs @@ -41,9 +41,7 @@ namespace Oqtane.Themes public string ContentUrl(int fileid) { - string url = (PageState.Alias.Path == "") ? "/~" : PageState.Alias.Path; - url += Constants.ContentUrl + fileid.ToString(); - return url; + return Utilities.ContentUrl(PageState.Alias.Path, fileid); } } } diff --git a/Oqtane.Client/UI/Installer.razor b/Oqtane.Client/UI/Installer.razor index f2985b1c..5c4d0312 100644 --- a/Oqtane.Client/UI/Installer.razor +++ b/Oqtane.Client/UI/Installer.razor @@ -185,16 +185,21 @@ }; Installation installation = await InstallationService.Install(config); - //TODO: Should be moved to Database manager + //TODO: Should be moved to Database manager if (installation.Success) { Site site = new Site(); site.TenantId = -1; // will be populated on server site.Name = "Default Site"; site.LogoFileId = null; + site.FaviconFileId = null; site.DefaultThemeType = Constants.DefaultTheme; site.DefaultLayoutType = Constants.DefaultLayout; site.DefaultContainerType = Constants.DefaultContainer; + site.PwaIsEnabled = false; + site.PwaAppIconFileId = null; + site.PwaSplashIconFileId = null; + site.AllowRegistration = false; site = await SiteService.AddSiteAsync(site, null); User user = new User(); diff --git a/Oqtane.Client/UI/Interop.cs b/Oqtane.Client/UI/Interop.cs index 5b2c6b7c..b57d1444 100644 --- a/Oqtane.Client/UI/Interop.cs +++ b/Oqtane.Client/UI/Interop.cs @@ -58,12 +58,12 @@ namespace Oqtane.UI } } - public Task UpdateMeta(string id, string attribute, string name, string content) + public Task IncludeMeta(string id, string attribute, string name, string content) { try { _jsRuntime.InvokeAsync( - "interop.updateMeta", + "interop.includeMeta", id, attribute, name, content); return Task.CompletedTask; } @@ -73,13 +73,28 @@ namespace Oqtane.UI } } - public Task UpdateLink(string id, string rel, string type, string url) + public Task IncludeLink(string id, string rel, string url, string type) { try { _jsRuntime.InvokeAsync( - "interop.updateLink", - id, rel, type, url); + "interop.includeLink", + id, rel, url, type); + return Task.CompletedTask; + } + catch + { + return Task.CompletedTask; + } + } + + public Task IncludeScript(string id, string src, string content, string location) + { + try + { + _jsRuntime.InvokeAsync( + "interop.includeScript", + id, src, content, location); return Task.CompletedTask; } catch @@ -93,8 +108,8 @@ namespace Oqtane.UI try { _jsRuntime.InvokeAsync( - "interop.updateLink", - id, "stylesheet", "text/css", url); + "interop.includeLink", + id, "stylesheet", url, "text/css"); return Task.CompletedTask; } catch diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 2be44081..b16368b2 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -1,5 +1,6 @@ @namespace Oqtane.UI @inject IJSRuntime JsRuntime +@inject NavigationManager NavigationManager @DynamicComponent @@ -8,8 +9,26 @@ RenderFragment DynamicComponent { get; set; } - protected override void OnParametersSet() + protected override async Task OnParametersSetAsync() { + var interop = new Interop(JsRuntime); + if (!string.IsNullOrEmpty(PageState.Page.Title)) + { + await interop.UpdateTitle(PageState.Page.Title); + } + else + { + await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name); + } + if (PageState.Site.FaviconFileId != null) + { + await interop.IncludeLink("fav-icon", "shortcut icon", Utilities.ContentUrl(PageState.Alias.Path, PageState.Site.FaviconFileId.Value), "image/x-icon"); + } + if (PageState.Site.PwaIsEnabled) + { + await InitializePwa(interop); + } + DynamicComponent = builder => { Type themeType = Type.GetType(PageState.Page.ThemeType); @@ -27,4 +46,44 @@ } }; } + + private async Task InitializePwa(Interop interop) + { + // dynamically create manifest.json and add to page + string manifest = "setTimeout(() => { " + + "var manifest = { " + + "\"name\": \"" + PageState.Site.Name + "\", " + + "\"short_name\": \"" + PageState.Site.Name + "\", " + + "\"start_url\": \"/\", " + + "\"display\": \"standalone\", " + + "\"background_color\": \"#fff\", " + + "\"description\": \"" + PageState.Site.Name + "\", " + + "\"icons\": [{ " + + "\"src\": \"" + Utilities.ContentUrl(PageState.Alias.Path, PageState.Site.PwaAppIconFileId.Value) + "\", " + + "\"sizes\": \"192x192\", " + + "\"type\": \"image/png\" " + + "}, { " + + "\"src\": \"" + Utilities.ContentUrl(PageState.Alias.Path, PageState.Site.PwaSplashIconFileId.Value) + "\", " + + "\"sizes\": \"512x512\", " + + "\"type\": \"image/png\" " + + "}] " + + "} " + + "const serialized = JSON.stringify(manifest); " + + "const blob = new Blob([serialized], {type: 'application/javascript'}); " + + "const url = URL.createObjectURL(blob); " + + "document.getElementById('pwa-manifest').setAttribute('href', url); " + + "} " + + ", 1000);"; + await interop.IncludeScript("pwa-manifestscript", "", manifest, "body"); + + // service worker must be in root of site + string serviceworker = "if ('serviceWorker' in navigator) { " + + "navigator.serviceWorker.register('/service-worker.js').then(function(registration) { " + + "console.log('ServiceWorker Registration Successful'); " + + "}).catch (function(err) { " + + "console.log('ServiceWorker Registration Failed ', err); " + + "}); " + + "}"; + await interop.IncludeScript("pwa-serviceworker", "", serviceworker, "body"); + } } diff --git a/Oqtane.Client/wwwroot/index.html b/Oqtane.Client/wwwroot/index.html index 16cb5285..4244d8d4 100644 --- a/Oqtane.Client/wwwroot/index.html +++ b/Oqtane.Client/wwwroot/index.html @@ -5,6 +5,9 @@ Oqtane + + + diff --git a/Oqtane.Client/wwwroot/js/interop.js b/Oqtane.Client/wwwroot/js/interop.js index c9860f68..ec289bbe 100644 --- a/Oqtane.Client/wwwroot/js/interop.js +++ b/Oqtane.Client/wwwroot/js/interop.js @@ -25,7 +25,7 @@ window.interop = { document.title = title; } }, - updateMeta: function (id, attribute, name, content) { + includeMeta: function (id, attribute, name, content) { var meta; if (id !== "") { meta = document.getElementById(id); @@ -48,7 +48,7 @@ window.interop = { } } }, - updateLink: function (id, rel, type, url) { + includeLink: function (id, rel, url, type) { var link; if (id !== "") { link = document.getElementById(id); @@ -62,14 +62,58 @@ window.interop = { link.id = id; } link.rel = rel; - link.type = type; link.href = url; + if (type !== "") { + link.type = type; + } document.head.appendChild(link); } else { + if (link.rel !== rel) { + link.setAttribute('rel', rel); + } if (link.href !== url) { link.setAttribute('href', url); } + if (type !== "" && link.type !== type) { + link.setAttribute('type', type); + } + } + }, + includeScript: function (id, src, content, location) { + var script; + if (id !== "") { + script = document.getElementById(id); + } + if (script === null) { + script = document.createElement("script"); + if (id !== "") { + script.id = id; + } + if (src !== "") { + script.src = src; + } + else { + script.innerHTML = content; + } + if (location === 'head') { + document.head.appendChild(script); + } + if (location === 'body') { + document.body.appendChild(script); + } + } + else { + if (src !== "") { + if (script.src !== src) { + script.src = src; + } + } + else { + if (script.innerHTML !== content) { + script.innerHTML = content; + } + } } }, getElementByName: function (name) { diff --git a/Oqtane.Client/wwwroot/service-worker.js b/Oqtane.Client/wwwroot/service-worker.js new file mode 100644 index 00000000..0c55c1b1 --- /dev/null +++ b/Oqtane.Client/wwwroot/service-worker.js @@ -0,0 +1,2 @@ +// always fetch from the network and do not enable offline support +self.addEventListener('fetch', () => { }); \ No newline at end of file diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 3a65407d..607ceaef 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -146,10 +146,12 @@ namespace Oqtane.Controllers page = new Page(); page.SiteId = parent.SiteId; page.Name = parent.Name; + page.Title = parent.Title; page.Path = parent.Path; page.ParentId = parent.PageId; page.Order = 0; page.IsNavigation = false; + page.Url = ""; page.EditMode = false; page.ThemeType = parent.ThemeType; page.LayoutType = parent.LayoutType; diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index c5a90e79..ac372241 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -9,6 +9,9 @@ Oqtane + + + diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index dc10fb3b..dc40978b 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -634,8 +634,10 @@ namespace Oqtane.Repository SiteId = site.SiteId, ParentId = parentid, Name = pagetemplate.Name, + Title = "", Path = pagetemplate.Path, Order = 1, + Url = "", IsNavigation = pagetemplate.IsNavigation, EditMode = pagetemplate.EditMode, ThemeType = "", diff --git a/Oqtane.Server/Scripts/Tenant.00.00.00.sql b/Oqtane.Server/Scripts/Tenant.00.00.00.sql index 5157b401..1d0e540f 100644 --- a/Oqtane.Server/Scripts/Tenant.00.00.00.sql +++ b/Oqtane.Server/Scripts/Tenant.00.00.00.sql @@ -9,9 +9,14 @@ CREATE TABLE [dbo].[Site]( [TenantId] [int] NOT NULL, [Name] [nvarchar](200) NOT NULL, [LogoFileId] [int] NULL, + [FaviconFileId] [int] NULL, [DefaultThemeType] [nvarchar](200) NOT NULL, [DefaultLayoutType] [nvarchar](200) NOT NULL, [DefaultContainerType] [nvarchar](200) NOT NULL, + [PwaIsEnabled] [bit] NOT NULL, + [PwaAppIconFileId] [int] NULL, + [PwaSplashIconFileId] [int] NULL, + [AllowRegistration] [bit] NOT NULL, [CreatedBy] [nvarchar](256) NOT NULL, [CreatedOn] [datetime] NOT NULL, [ModifiedBy] [nvarchar](256) NOT NULL, @@ -31,11 +36,13 @@ CREATE TABLE [dbo].[Page]( [SiteId] [int] NOT NULL, [Path] [nvarchar](50) NOT NULL, [Name] [nvarchar](50) NOT NULL, + [Title] [nvarchar](200) NULL, [ThemeType] [nvarchar](200) NULL, [Icon] [nvarchar](50) NOT NULL, [ParentId] [int] NULL, [Order] [int] NOT NULL, [IsNavigation] [bit] NOT NULL, + [Url] [nvarchar](500) NULL, [LayoutType] [nvarchar](200) NOT NULL, [EditMode] [bit] NOT NULL, [UserId] [int] NULL, diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index c9860f68..ec289bbe 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -25,7 +25,7 @@ window.interop = { document.title = title; } }, - updateMeta: function (id, attribute, name, content) { + includeMeta: function (id, attribute, name, content) { var meta; if (id !== "") { meta = document.getElementById(id); @@ -48,7 +48,7 @@ window.interop = { } } }, - updateLink: function (id, rel, type, url) { + includeLink: function (id, rel, url, type) { var link; if (id !== "") { link = document.getElementById(id); @@ -62,14 +62,58 @@ window.interop = { link.id = id; } link.rel = rel; - link.type = type; link.href = url; + if (type !== "") { + link.type = type; + } document.head.appendChild(link); } else { + if (link.rel !== rel) { + link.setAttribute('rel', rel); + } if (link.href !== url) { link.setAttribute('href', url); } + if (type !== "" && link.type !== type) { + link.setAttribute('type', type); + } + } + }, + includeScript: function (id, src, content, location) { + var script; + if (id !== "") { + script = document.getElementById(id); + } + if (script === null) { + script = document.createElement("script"); + if (id !== "") { + script.id = id; + } + if (src !== "") { + script.src = src; + } + else { + script.innerHTML = content; + } + if (location === 'head') { + document.head.appendChild(script); + } + if (location === 'body') { + document.body.appendChild(script); + } + } + else { + if (src !== "") { + if (script.src !== src) { + script.src = src; + } + } + else { + if (script.innerHTML !== content) { + script.innerHTML = content; + } + } } }, getElementByName: function (name) { diff --git a/Oqtane.Server/wwwroot/service-worker.js b/Oqtane.Server/wwwroot/service-worker.js new file mode 100644 index 00000000..0c55c1b1 --- /dev/null +++ b/Oqtane.Server/wwwroot/service-worker.js @@ -0,0 +1,2 @@ +// always fetch from the network and do not enable offline support +self.addEventListener('fetch', () => { }); \ No newline at end of file diff --git a/Oqtane.Shared/Models/Page.cs b/Oqtane.Shared/Models/Page.cs index d9c40e36..f1268875 100644 --- a/Oqtane.Shared/Models/Page.cs +++ b/Oqtane.Shared/Models/Page.cs @@ -9,8 +9,10 @@ namespace Oqtane.Models public int SiteId { get; set; } public int? ParentId { get; set; } public string Name { get; set; } + public string Title { get; set; } public string Path { get; set; } public int Order { get; set; } + public string Url { get; set; } public string ThemeType { get; set; } public string LayoutType { get; set; } public string Icon { get; set; } diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index 700209b2..4b6b7f86 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -9,9 +9,14 @@ namespace Oqtane.Models public int TenantId { get; set; } public string Name { get; set; } public int? LogoFileId { get; set; } + public int? FaviconFileId { get; set; } public string DefaultThemeType { get; set; } public string DefaultLayoutType { get; set; } public string DefaultContainerType { get; set; } + public bool PwaIsEnabled { get; set; } + public int? PwaAppIconFileId { get; set; } + public int? PwaSplashIconFileId { get; set; } + public bool AllowRegistration { get; set; } public string CreatedBy { get; set; } public DateTime CreatedOn { get; set; } diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 1e2a568c..46c02fa7 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -56,6 +56,13 @@ namespace Oqtane.Shared return url; } + public static string ContentUrl(string alias, int fileid) + { + string url = (alias == "") ? "/~" : alias; + url += Constants.ContentUrl + fileid.ToString(); + return url; + } + public static string GetTypeName(string fullyqualifiedtypename) { if (fullyqualifiedtypename.Contains(","))