script reload improvements
This commit is contained in:
parent
4630ee6e93
commit
0204ff8dd5
|
@ -70,7 +70,7 @@
|
|||
if (!script.Contains("><") && !script.Contains("data-reload"))
|
||||
{
|
||||
// add data-reload attribute to inline script
|
||||
headcontent = headcontent.Replace(script, script.Replace("<script", "<script data-reload=\"true\""));
|
||||
headcontent = headcontent.Replace(script, script.Replace("<script", "<script data-reload=\"always\""));
|
||||
}
|
||||
index = headcontent.IndexOf("<script", index + 1);
|
||||
}
|
||||
|
|
|
@ -191,16 +191,13 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
if (dataAttributes == null || !dataAttributes.ContainsKey("data-reload") || dataAttributes["data-reload"] != "false")
|
||||
if (id == "")
|
||||
{
|
||||
if (id == "")
|
||||
{
|
||||
count += 1;
|
||||
id = $"page{PageState.Page.PageId}-script{count}";
|
||||
}
|
||||
var pos = script.IndexOf(">") + 1;
|
||||
await interop.IncludeScript(id, "", "", "", type, script.Substring(pos, script.IndexOf("</script>") - pos), location.ToString().ToLower(), dataAttributes);
|
||||
count += 1;
|
||||
id = $"page{PageState.Page.PageId}-script{count}";
|
||||
}
|
||||
var pos = script.IndexOf(">") + 1;
|
||||
await interop.IncludeScript(id, "", "", "", type, script.Substring(pos, script.IndexOf("</script>") - pos), location.ToString().ToLower(), dataAttributes);
|
||||
}
|
||||
index = content.IndexOf("<script", index + 1);
|
||||
}
|
||||
|
|
|
@ -514,7 +514,7 @@
|
|||
private void AddScript(Resource resource, Alias alias)
|
||||
{
|
||||
var script = CreateScript(resource, alias);
|
||||
if (resource.Location == Shared.ResourceLocation.Head && !resource.Reload)
|
||||
if (resource.Location == Shared.ResourceLocation.Head && resource.LoadBehavior != ResourceLoadBehavior.BlazorPageScript)
|
||||
{
|
||||
if (!_headResources.Contains(script))
|
||||
{
|
||||
|
@ -532,11 +532,27 @@
|
|||
|
||||
private string CreateScript(Resource resource, Alias alias)
|
||||
{
|
||||
if (!resource.Reload)
|
||||
if (resource.LoadBehavior == ResourceLoadBehavior.BlazorPageScript)
|
||||
{
|
||||
return "<page-script src=\"" + resource.Url + "\"></page-script>";
|
||||
}
|
||||
else
|
||||
{
|
||||
var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
|
||||
|
||||
var dataAttributes = "";
|
||||
if (!resource.DataAttributes.ContainsKey("data-reload"))
|
||||
{
|
||||
switch (resource.LoadBehavior)
|
||||
{
|
||||
case ResourceLoadBehavior.Once:
|
||||
dataAttributes += " data-reload=\"once\"";
|
||||
break;
|
||||
case ResourceLoadBehavior.Always:
|
||||
dataAttributes += " data-reload=\"always\"";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (resource.DataAttributes != null && resource.DataAttributes.Count > 0)
|
||||
{
|
||||
foreach (var attribute in resource.DataAttributes)
|
||||
|
@ -552,10 +568,6 @@
|
|||
((!string.IsNullOrEmpty(dataAttributes)) ? dataAttributes : "") +
|
||||
"></script>";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "<page-script src=\"" + resource.Url + "\"></page-script>";
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLocalizationCookie(string cookieValue)
|
||||
|
|
|
@ -1,67 +1,74 @@
|
|||
const scriptInfoBySrc = new Map();
|
||||
const scriptKeys = new Set();
|
||||
|
||||
export function onUpdate() {
|
||||
// determine if this is an enhanced navigation
|
||||
let enhancedNavigation = scriptKeys.size !== 0;
|
||||
|
||||
// iterate over all script elements in document
|
||||
const scripts = document.getElementsByTagName('script');
|
||||
for (const script of Array.from(scripts)) {
|
||||
// only process scripts that include a data-reload attribute
|
||||
if (script.hasAttribute('data-reload')) {
|
||||
let key = getKey(script);
|
||||
|
||||
if (enhancedNavigation) {
|
||||
// reload the script if data-reload is always or if the script has not been loaded previously and data-reload is once
|
||||
let dataReload = script.getAttribute('data-reload');
|
||||
if (dataReload === 'always' || (!scriptKeys.has(key) && dataReload == 'once')) {
|
||||
reloadScript(script);
|
||||
}
|
||||
}
|
||||
|
||||
// save the script key
|
||||
if (!scriptKeys.has(key)) {
|
||||
scriptKeys.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getKey(script) {
|
||||
if (script.hasAttribute("src") && script.src !== "") {
|
||||
if (script.src) {
|
||||
return script.src;
|
||||
} else if (script.id) {
|
||||
return script.id;
|
||||
} else {
|
||||
return script.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
export function onUpdate() {
|
||||
let timestamp = Date.now();
|
||||
let enhancedNavigation = scriptInfoBySrc.size !== 0;
|
||||
|
||||
// iterate over all script elements in page
|
||||
const scripts = document.getElementsByTagName("script");
|
||||
for (const script of Array.from(scripts)) {
|
||||
let key = getKey(script);
|
||||
let scriptInfo = scriptInfoBySrc.get(key);
|
||||
if (!scriptInfo) {
|
||||
// new script added
|
||||
scriptInfo = { timestamp: timestamp };
|
||||
scriptInfoBySrc.set(key, scriptInfo);
|
||||
if (enhancedNavigation) {
|
||||
reloadScript(script);
|
||||
}
|
||||
} else {
|
||||
// existing script
|
||||
scriptInfo.timestamp = timestamp;
|
||||
if (script.hasAttribute("data-reload") && script.getAttribute("data-reload") === "true") {
|
||||
reloadScript(script);
|
||||
}
|
||||
function reloadScript(script) {
|
||||
try {
|
||||
if (isValid(script)) {
|
||||
replaceScript(script);
|
||||
}
|
||||
}
|
||||
|
||||
// remove scripts that are no longer referenced
|
||||
for (const [key, scriptInfo] of scriptInfoBySrc) {
|
||||
if (scriptInfo.timestamp !== timestamp) {
|
||||
scriptInfoBySrc.delete(key);
|
||||
} catch (error) {
|
||||
if (script.src) {
|
||||
console.error(`Script Reload failed to load external script: ${script.src}`, error);
|
||||
} else {
|
||||
console.error(`Script Reload failed to load inline script: ${script.innerHTML}`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reloadScript(script) {
|
||||
try {
|
||||
replaceScript(script);
|
||||
} catch (error) {
|
||||
if (script.hasAttribute("src") && script.src !== "") {
|
||||
console.error("Failed to load external script: ${script.src}", error);
|
||||
} else {
|
||||
console.error("Failed to load inline script: ${script.innerHtml}", error);
|
||||
}
|
||||
function isValid(script) {
|
||||
if (script.innerHTML.includes('document.write(')) {
|
||||
console.log(`Script using document.write() not supported by Script Reload: ${script.innerHTML}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function replaceScript(script) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var newScript = document.createElement("script");
|
||||
var newScript = document.createElement('script');
|
||||
|
||||
// replicate attributes and content
|
||||
for (let i = 0; i < script.attributes.length; i++) {
|
||||
newScript.setAttribute(script.attributes[i].name, script.attributes[i].value);
|
||||
}
|
||||
newScript.innerHTML = script.innerHTML;
|
||||
newScript.removeAttribute('data-reload');
|
||||
|
||||
// dynamically injected scripts cannot be async or deferred
|
||||
newScript.async = false;
|
||||
|
@ -70,11 +77,10 @@ function replaceScript(script) {
|
|||
newScript.onload = () => resolve();
|
||||
newScript.onerror = (error) => reject(error);
|
||||
|
||||
// remove existing script
|
||||
// remove existing script element
|
||||
script.remove();
|
||||
|
||||
// replace with new script to force reload in Blazor
|
||||
// replace with new script element to force reload in Blazor
|
||||
document.head.appendChild(newScript);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
10
Oqtane.Shared/Enums/ResourceLoadBehavior.cs
Normal file
10
Oqtane.Shared/Enums/ResourceLoadBehavior.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Oqtane.Shared
|
||||
{
|
||||
public enum ResourceLoadBehavior
|
||||
{
|
||||
Once,
|
||||
Always,
|
||||
Never,
|
||||
BlazorPageScript
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Models
|
||||
|
@ -13,7 +12,7 @@ namespace Oqtane.Models
|
|||
private string _url;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ResourceType"/> so the Interop can properly create `script` or `link` tags
|
||||
/// A <see cref="ResourceType"/> to define the type of resource ie. Script or Stylesheet
|
||||
/// </summary>
|
||||
public ResourceType ResourceType { get; set; }
|
||||
|
||||
|
@ -45,7 +44,7 @@ namespace Oqtane.Models
|
|||
public string CrossOrigin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For Scripts a Bundle can be used to identify dependencies and ordering in the script loading process
|
||||
/// For Scripts a Bundle can be used to identify dependencies and ordering in the script loading process (for Interactive rendering only)
|
||||
/// </summary>
|
||||
public string Bundle { get; set; }
|
||||
|
||||
|
@ -60,7 +59,7 @@ namespace Oqtane.Models
|
|||
public ResourceLocation Location { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allows specification of inline script - not applicable to Stylesheets
|
||||
/// For Scripts this allows for the specification of inline script - not applicable to Stylesheets
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
|
||||
|
@ -70,9 +69,9 @@ namespace Oqtane.Models
|
|||
public string RenderMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a script should be reloaded on every page transition - not applicable to Stylesheets
|
||||
/// Specifies how a script should be loaded in Static rendering - not applicable to Stylesheets
|
||||
/// </summary>
|
||||
public bool Reload { get; set; }
|
||||
public ResourceLoadBehavior LoadBehavior { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cusotm data-* attributes for scripts - not applicable to Stylesheets
|
||||
|
@ -96,7 +95,7 @@ namespace Oqtane.Models
|
|||
resource.Location = Location;
|
||||
resource.Content = Content;
|
||||
resource.RenderMode = RenderMode;
|
||||
resource.Reload = Reload;
|
||||
resource.LoadBehavior = LoadBehavior;
|
||||
resource.DataAttributes = new Dictionary<string, string>();
|
||||
if (DataAttributes != null && DataAttributes.Count > 0)
|
||||
{
|
||||
|
@ -125,5 +124,18 @@ namespace Oqtane.Models
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Reload is deprecated. Use LoadBehavior property instead for scripts.", false)]
|
||||
public bool Reload
|
||||
{
|
||||
get => (LoadBehavior == ResourceLoadBehavior.BlazorPageScript);
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
LoadBehavior = ResourceLoadBehavior.BlazorPageScript;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Shared;
|
||||
|
||||
|
@ -27,6 +28,13 @@ namespace Oqtane.Models
|
|||
this.Type = Type;
|
||||
}
|
||||
|
||||
public Script(string Content, ResourceLoadBehavior LoadBehavior)
|
||||
{
|
||||
SetDefaults();
|
||||
this.Content = Content;
|
||||
this.LoadBehavior = LoadBehavior;
|
||||
}
|
||||
|
||||
public Script(string Src, string Integrity, string CrossOrigin)
|
||||
{
|
||||
SetDefaults();
|
||||
|
@ -35,6 +43,22 @@ namespace Oqtane.Models
|
|||
this.CrossOrigin = CrossOrigin;
|
||||
}
|
||||
|
||||
public Script(string Src, string Integrity, string CrossOrigin, string Type, string Content, ResourceLocation Location, string Bundle, ResourceLoadBehavior LoadBehavior, Dictionary<string, string> DataAttributes, string RenderMode)
|
||||
{
|
||||
SetDefaults();
|
||||
this.Url = Src;
|
||||
this.Integrity = Integrity;
|
||||
this.CrossOrigin = CrossOrigin;
|
||||
this.Type = Type;
|
||||
this.Content = Content;
|
||||
this.Location = Location;
|
||||
this.Bundle = Bundle;
|
||||
this.LoadBehavior = LoadBehavior;
|
||||
this.DataAttributes = DataAttributes;
|
||||
this.RenderMode = RenderMode;
|
||||
}
|
||||
|
||||
[Obsolete("This constructor is deprecated. Use constructor with LoadBehavior parameter instead.", false)]
|
||||
public Script(string Src, string Integrity, string CrossOrigin, string Type, string Content, ResourceLocation Location, string Bundle, bool Reload, Dictionary<string, string> DataAttributes, string RenderMode)
|
||||
{
|
||||
SetDefaults();
|
||||
|
@ -45,9 +69,10 @@ namespace Oqtane.Models
|
|||
this.Content = Content;
|
||||
this.Location = Location;
|
||||
this.Bundle = Bundle;
|
||||
this.Reload = Reload;
|
||||
this.LoadBehavior = (Reload) ? ResourceLoadBehavior.BlazorPageScript : ResourceLoadBehavior.Once;
|
||||
this.DataAttributes = DataAttributes;
|
||||
this.RenderMode = RenderMode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user