diff --git a/Oqtane.Client/Modules/Controls/TabStrip.razor b/Oqtane.Client/Modules/Controls/TabStrip.razor
index 8d8d3838..ee6a6c82 100644
--- a/Oqtane.Client/Modules/Controls/TabStrip.razor
+++ b/Oqtane.Client/Modules/Controls/TabStrip.razor
@@ -11,13 +11,13 @@
@if (tabPanel.Name == ActiveTab)
{
-
+
@DisplayHeading(tabPanel.Name, tabPanel.Heading)
}
else
{
-
+
@DisplayHeading(tabPanel.Name, tabPanel.Heading)
}
diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs
index b4d8eb7e..ce4ed823 100644
--- a/Oqtane.Client/Modules/ModuleBase.cs
+++ b/Oqtane.Client/Modules/ModuleBase.cs
@@ -55,7 +55,7 @@ namespace Oqtane.Modules
var interop = new Interop(JSRuntime);
foreach (var resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
{
- await interop.LoadScript(resource.Url);
+ await interop.LoadScript(resource.Url, resource.Integrity ?? "", resource.CrossOrigin ?? "");
}
}
}
diff --git a/Oqtane.Client/Themes/BlazorTheme/Default.razor b/Oqtane.Client/Themes/BlazorTheme/Default.razor
index 14b7df03..0b664c50 100644
--- a/Oqtane.Client/Themes/BlazorTheme/Default.razor
+++ b/Oqtane.Client/Themes/BlazorTheme/Default.razor
@@ -1,5 +1,6 @@
@namespace Oqtane.Themes.BlazorTheme
@inherits ThemeBase
+@implements IThemeControl
@@ -30,6 +31,16 @@
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" }
};
+
+ 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 7d8fa135..09035b5a 100644
--- a/Oqtane.Client/Themes/OqtaneTheme/Default.razor
+++ b/Oqtane.Client/Themes/OqtaneTheme/Default.razor
@@ -1,5 +1,6 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ThemeBase
+@implements IThemeControl
-
-
-
@if (Configuration.GetSection("Runtime").Value == "WebAssembly")
{
diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js
index b5c866ec..7588de0f 100644
--- a/Oqtane.Server/wwwroot/js/interop.js
+++ b/Oqtane.Server/wwwroot/js/interop.js
@@ -198,12 +198,30 @@ Oqtane.Interop = {
script.onerror = rej();
});
},
- loadScript: async function (path) {
+ loadScript: async function (url, integrity, crossorigin) {
const promise = new Promise((resolve, reject) => {
- loadjs(path, { returnPromise: true })
- .then(function () { resolve(true) })
- .catch(function (pathsNotFound) { reject(false) });
+
+ if (loadjs.isDefined(url)) {
+ resolve(true);
+ return;
+ }
+
+ 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;
+ }
+ }
+ })
+ .then(function () { resolve(true) })
+ .catch(function (pathsNotFound) { reject(false) });
});
+
const result = await promise;
return;
},
@@ -325,5 +343,31 @@ 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 22332064..9467584a 100644
--- a/Oqtane.Server/wwwroot/js/quill-interop.js
+++ b/Oqtane.Server/wwwroot/js/quill-interop.js
@@ -5,27 +5,28 @@ Oqtane.RichTextEditor = {
quillElement, toolBar, readOnly,
placeholder, theme, debugLevel) {
- 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);
+ 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;
+ }
- var options = {
- debug: debugLevel,
- modules: {
- toolbar: toolBar,
- blotFormatter: {}
- },
- placeholder: placeholder,
- readOnly: readOnly,
- theme: theme
- };
+ var options = {
+ debug: debugLevel,
+ modules: {
+ toolbar: toolBar,
+ blotFormatter: {}
+ },
+ placeholder: placeholder,
+ readOnly: readOnly,
+ theme: theme
+ };
- new Quill(quillElement, options);
- })
- .catch(function (pathsNotFound) { });
-
- await loadQuill;
+ new Quill(quillElement, options);
},
getQuillContent: function (editorElement) {
return JSON.stringify(editorElement.__quill.getContents());