Merge pull request #3968 from sbwalker/dev
add ability to reload JavaScript on page transitions with enhanced navigation
This commit is contained in:
		| @ -580,6 +580,7 @@ | ||||
|                             ES6Module = resource.ES6Module, | ||||
|                             Content = resource.Content, | ||||
|                             RenderMode = resource.RenderMode, | ||||
|                             Reload = resource.Reload, | ||||
|                             Level = level, | ||||
|                             Namespace = name | ||||
|                         }); | ||||
|  | ||||
| @ -526,12 +526,20 @@ | ||||
|     { | ||||
|         if (!string.IsNullOrEmpty(resource.Url)) | ||||
|         { | ||||
|             var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url; | ||||
|             return "<script" + | ||||
|                 ((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") + | ||||
|                 ((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") + | ||||
|                 ((resource.ES6Module) ? " type=\"module\"" : "") + | ||||
|                 " src =\"" + url + "\"></script>"; // src at end of element due to enhanced navigation patch algorithm | ||||
|             if (!resource.Reload) | ||||
|             { | ||||
|                 var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url; | ||||
|                 return "<script" + | ||||
|                     ((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") + | ||||
|                     ((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") + | ||||
|                     ((resource.ES6Module) ? " type=\"module\"" : "") + | ||||
|                     " src =\"" + url + "\"></script>"; // src at end of element due to enhanced navigation patch algorithm | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // use custom element which can execute script on every page transition | ||||
|                 return "<page-script src=\"" + resource.Url + "\"></page-script>"; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| @ -684,6 +692,7 @@ | ||||
|                         ES6Module = resource.ES6Module, | ||||
|                         Content = resource.Content, | ||||
|                         RenderMode = resource.RenderMode, | ||||
|                         Reload = resource.Reload, | ||||
|                         Level = level, | ||||
|                         Namespace = name | ||||
|                     }); | ||||
|  | ||||
							
								
								
									
										90
									
								
								Oqtane.Server/wwwroot/Oqtane.Server.lib.module.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								Oqtane.Server/wwwroot/Oqtane.Server.lib.module.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| const pageScriptInfoBySrc = new Map(); | ||||
|  | ||||
| function registerPageScriptElement(src) { | ||||
|     if (!src) { | ||||
|         throw new Error('Must provide a non-empty value for the "src" attribute.'); | ||||
|     } | ||||
|  | ||||
|     let pageScriptInfo = pageScriptInfoBySrc.get(src); | ||||
|  | ||||
|     if (pageScriptInfo) { | ||||
|         pageScriptInfo.referenceCount++; | ||||
|     } else { | ||||
|         pageScriptInfo = { referenceCount: 1, module: null }; | ||||
|         pageScriptInfoBySrc.set(src, pageScriptInfo); | ||||
|         initializePageScriptModule(src, pageScriptInfo); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function unregisterPageScriptElement(src) { | ||||
|     if (!src) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const pageScriptInfo = pageScriptInfoBySrc.get(src); | ||||
|     if (!pageScriptInfo) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     pageScriptInfo.referenceCount--; | ||||
| } | ||||
|  | ||||
| async function initializePageScriptModule(src, pageScriptInfo) { | ||||
|     // If the path is relative, normalize it by by making it an absolute URL | ||||
|     // with document's the base HREF. | ||||
|     if (src.startsWith("./")) { | ||||
|         src = new URL(src.substr(2), document.baseURI).toString(); | ||||
|     } | ||||
|  | ||||
|     const module = await import(src); | ||||
|  | ||||
|     if (pageScriptInfo.referenceCount <= 0) { | ||||
|         // All page-script elements with the same 'src' were | ||||
|         // unregistered while we were loading the module. | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     pageScriptInfo.module = module; | ||||
|     module.onLoad?.(); | ||||
|     module.onUpdate?.(); | ||||
| } | ||||
|  | ||||
| function onEnhancedLoad() { | ||||
|     // Start by invoking 'onDispose' on any modules that are no longer referenced. | ||||
|     for (const [src, { module, referenceCount }] of pageScriptInfoBySrc) { | ||||
|         if (referenceCount <= 0) { | ||||
|             module?.onDispose?.(); | ||||
|             pageScriptInfoBySrc.delete(src); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Then invoke 'onUpdate' on the remaining modules. | ||||
|     for (const { module } of pageScriptInfoBySrc.values()) { | ||||
|         module?.onUpdate?.(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export function afterWebStarted(blazor) { | ||||
|     customElements.define('page-script', class extends HTMLElement { | ||||
|         static observedAttributes = ['src']; | ||||
|  | ||||
|         // We use attributeChangedCallback instead of connectedCallback | ||||
|         // because a page-script element might get reused between enhanced | ||||
|         // navigations. | ||||
|         attributeChangedCallback(name, oldValue, newValue) { | ||||
|             if (name !== 'src') { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.src = newValue; | ||||
|             unregisterPageScriptElement(oldValue); | ||||
|             registerPageScriptElement(newValue); | ||||
|         } | ||||
|  | ||||
|         disconnectedCallback() { | ||||
|             unregisterPageScriptElement(this.src); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     blazor.addEventListener('enhancedload', onEnhancedLoad); | ||||
| } | ||||
| @ -67,6 +67,11 @@ namespace Oqtane.Models | ||||
|         /// </summary> | ||||
|         public string RenderMode { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Indicates that a script should be reloaded on every page transition - not applicable to Stylesheets | ||||
|         /// </summary> | ||||
|         public bool Reload { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// The namespace of the component that declared the resource - only used in SiteRouter | ||||
|         /// </summary> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Shaun Walker
					Shaun Walker