From 06362272848f99cfc0a141ae3c03efb741c0cd8b Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 17 Jun 2020 10:27:14 -0400 Subject: [PATCH] refactored script resource declaration to allow for bundling, made script loading async, refactored RichTextEditor to use new method --- .../Modules/Controls/RichTextEditor.razor | 4 +- Oqtane.Client/Modules/ModuleBase.cs | 8 +- .../Themes/BlazorTheme/Default.razor | 13 +-- .../Themes/OqtaneTheme/Default.razor | 14 +-- Oqtane.Client/Themes/ThemeBase.cs | 8 +- Oqtane.Client/UI/Interop.cs | 18 +--- Oqtane.Client/UI/ThemeBuilder.razor | 7 +- Oqtane.Server/wwwroot/js/interop.js | 91 +++++++++---------- Oqtane.Server/wwwroot/js/quill-interop.js | 10 +- Oqtane.Shared/Models/Resource.cs | 1 + 10 files changed, 70 insertions(+), 104 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 6a34e0f6..28888050 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -109,7 +109,9 @@ public override List Resources => new List() { - new Resource { ResourceType = ResourceType.Script, Url = "js/quill-interop.js" } + new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.6.min.js" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" } }; protected override void OnInitialized() diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index ce4ed823..f36a04ae 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -52,11 +52,13 @@ namespace Oqtane.Modules { if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script)) { - var interop = new Interop(JSRuntime); - foreach (var resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) + var scripts = new List(); + foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) { - await interop.LoadScript(resource.Url, resource.Integrity ?? "", resource.CrossOrigin ?? ""); + scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "" }); } + var interop = new Interop(JSRuntime); + await interop.IncludeScripts(scripts.ToArray()); } } } diff --git a/Oqtane.Client/Themes/BlazorTheme/Default.razor b/Oqtane.Client/Themes/BlazorTheme/Default.razor index 0b664c50..81c7122a 100644 --- a/Oqtane.Client/Themes/BlazorTheme/Default.razor +++ b/Oqtane.Client/Themes/BlazorTheme/Default.razor @@ -32,15 +32,10 @@ public override List Resources => new List() { new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css", Integrity = "sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T", CrossOrigin = "anonymous" }, - new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" } + new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.3.1.slim.min.js", Integrity = "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js", Integrity = "sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js", Integrity = "sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM", CrossOrigin = "anonymous" } }; - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - var interop = new Interop(JSRuntime); - await interop.LoadBootstrapJS(); - } - } } \ No newline at end of file diff --git a/Oqtane.Client/Themes/OqtaneTheme/Default.razor b/Oqtane.Client/Themes/OqtaneTheme/Default.razor index 09035b5a..5d4e4df9 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/Default.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Default.razor @@ -25,15 +25,9 @@ public override List Resources => new List() { new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css", Integrity = "sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM", CrossOrigin = "anonymous" }, - new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" } + new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.3.1.slim.min.js", Integrity = "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js", Integrity = "sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js", Integrity = "sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM", CrossOrigin = "anonymous" } }; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - var interop = new Interop(JSRuntime); - await interop.LoadBootstrapJS(); - } - } } diff --git a/Oqtane.Client/Themes/ThemeBase.cs b/Oqtane.Client/Themes/ThemeBase.cs index 0d3d9454..d4400ec1 100644 --- a/Oqtane.Client/Themes/ThemeBase.cs +++ b/Oqtane.Client/Themes/ThemeBase.cs @@ -31,11 +31,13 @@ namespace Oqtane.Themes { if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script)) { - var interop = new Interop(JSRuntime); - foreach (var resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) + var scripts = new List(); + foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) { - await interop.LoadScript(resource.Url, resource.Integrity ?? "", resource.CrossOrigin ?? ""); + scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "" }); } + var interop = new Interop(JSRuntime); + await interop.IncludeScripts(scripts.ToArray()); } } } diff --git a/Oqtane.Client/UI/Interop.cs b/Oqtane.Client/UI/Interop.cs index f403ab23..53b8df4f 100644 --- a/Oqtane.Client/UI/Interop.cs +++ b/Oqtane.Client/UI/Interop.cs @@ -117,23 +117,13 @@ namespace Oqtane.UI } } - public async Task LoadScript(string url, string integrity, string crossorigin) + public async Task IncludeScripts(object[] scripts) { try { - await _jsRuntime.InvokeVoidAsync("Oqtane.Interop.loadScript", url, integrity, crossorigin); - } - catch - { - // ignore exception - } - } - - public async Task LoadBootstrapJS() - { - try - { - await _jsRuntime.InvokeVoidAsync("Oqtane.Interop.loadBootstrapJS"); + await _jsRuntime.InvokeVoidAsync( + "Oqtane.Interop.includeScripts", + (object)scripts); } catch { diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 35a9f331..60c40e59 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -33,12 +33,9 @@ // manage stylesheets for this page string batch = DateTime.Now.ToString("yyyyMMddHHmmssfff"); var links = new List(); - foreach (Resource resource in PageState.Page.Resources) + foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet)) { - if (resource.ResourceType == ResourceType.Stylesheet) - { - links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" }); - } + links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" }); } await interop.IncludeLinks(links.ToArray()); await interop.RemoveElementsById("app-stylesheet", "", "app-stylesheet-" + batch + "-00"); diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index 7588de0f..96cae4d4 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -198,32 +198,49 @@ Oqtane.Interop = { script.onerror = rej(); }); }, - loadScript: async function (url, integrity, crossorigin) { - const promise = new Promise((resolve, reject) => { - - if (loadjs.isDefined(url)) { - resolve(true); - return; + includeScripts: async function (scripts) { + const bundles = []; + for (let s = 0; s < scripts.length; s++) { + if (scripts[s].bundle === '') { + scripts[s].bundle = scripts[s].href; } - - loadjs(url, url, { - async: false, - returnPromise: true, - before: function (path, element) { - if (path === url && integrity !== '') { - element.integrity = integrity; - } - if (path === url && crossorigin !== '') { - element.crossOrigin = crossorigin; - } + if (!bundles.includes(scripts[s].bundle)) { + bundles.push(scripts[s].bundle); + } + } + const urls = []; + for (let b = 0; b < bundles.length; b++) { + for (let s = 0; s < scripts.length; s++) { + if (scripts[s].bundle === bundles[b]) { + urls.push(scripts[s].href); } - }) - .then(function () { resolve(true) }) - .catch(function (pathsNotFound) { reject(false) }); - }); - - const result = await promise; - return; + } + const promise = new Promise((resolve, reject) => { + if (loadjs.isDefined(bundles[b])) { + resolve(true); + } + else { + loadjs(urls, bundles[b], { + async: true, + returnPromise: true, + before: function (path, element) { + for (let s = 0; s < scripts.length; s++) { + if (path === scripts[s].href && scripts[s].integrity !== '') { + element.integrity = scripts[s].integrity; + } + if (path === scripts[s].href && scripts[s].crossorigin !== '') { + element.crossOrigin = scripts[s].crossorigin; + } + } + } + }) + .then(function () { resolve(true) }) + .catch(function (pathsNotFound) { reject(false) }); + } + }); + await promise; + urls = []; + } }, getAbsoluteUrl: function (url) { var a = document.createElement('a'); @@ -343,31 +360,5 @@ Oqtane.Interop = { setInterval(function () { window.location.href = url; }, wait * 1000); - }, - loadBootstrapJS: async function () { - if (!loadjs.isDefined('Bootstrap')) { - const bootstrap = loadjs(['https://code.jquery.com/jquery-3.3.1.slim.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js', 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js'], 'Bootstrap', { - async: false, - returnPromise: true, - before: function (path, element) { - if (path === 'https://code.jquery.com/jquery-3.3.1.slim.min.js') { - element.integrity = 'sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo'; - element.crossOrigin = 'anonymous'; - } - if (path === 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js') { - element.integrity = 'sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1'; - element.crossOrigin = 'anonymous'; - } - if (path === 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js') { - element.integrity = 'sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM'; - element.crossOrigin = 'anonymous'; - } - } - }) - .then(function () { }) - .catch(function (pathsNotFound) { }); - - await bootstrap; - } } }; diff --git a/Oqtane.Server/wwwroot/js/quill-interop.js b/Oqtane.Server/wwwroot/js/quill-interop.js index 9467584a..13664fd4 100644 --- a/Oqtane.Server/wwwroot/js/quill-interop.js +++ b/Oqtane.Server/wwwroot/js/quill-interop.js @@ -5,15 +5,7 @@ Oqtane.RichTextEditor = { quillElement, toolBar, readOnly, placeholder, theme, debugLevel) { - if (!loadjs.isDefined('Quill')) { - const loadQuill = loadjs(['js/quill1.3.6.min.js', 'js/quill-blot-formatter.min.js'], 'Quill', - { async: true, returnPromise: true }) - .then(function () { - Quill.register('modules/blotFormatter', QuillBlotFormatter.default); - }) - .catch(function (pathsNotFound) { }); - await loadQuill; - } + Quill.register('modules/blotFormatter', QuillBlotFormatter.default); var options = { debug: debugLevel, diff --git a/Oqtane.Shared/Models/Resource.cs b/Oqtane.Shared/Models/Resource.cs index 81dc50fd..01bc57ba 100644 --- a/Oqtane.Shared/Models/Resource.cs +++ b/Oqtane.Shared/Models/Resource.cs @@ -8,5 +8,6 @@ namespace Oqtane.Models public string Url { get; set; } public string Integrity { get; set; } public string CrossOrigin { get; set; } + public string Bundle { get; set; } } }