276 lines
11 KiB
Plaintext
276 lines
11 KiB
Plaintext
@namespace Oqtane.UI
|
|
@using System.Net
|
|
@inject IJSRuntime JSRuntime
|
|
@inject NavigationManager NavigationManager
|
|
@inject SiteState SiteState
|
|
|
|
@DynamicComponent
|
|
|
|
@code {
|
|
[CascadingParameter] PageState PageState { get; set; }
|
|
|
|
RenderFragment DynamicComponent { get; set; }
|
|
|
|
private string lastPagePath = "";
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
// handle page redirection
|
|
if (!string.IsNullOrEmpty(PageState.Page.Url))
|
|
{
|
|
NavigationManager.NavigateTo(PageState.Page.Url);
|
|
return;
|
|
}
|
|
|
|
// force authenticated user to provide email address (email may be missing if using external login)
|
|
if (PageState.User != null && PageState.User.IsAuthenticated && string.IsNullOrEmpty(PageState.User.Email) && PageState.Route.PagePath != "profile")
|
|
{
|
|
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, "profile", "returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery)));
|
|
return;
|
|
}
|
|
|
|
// set page title
|
|
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
|
{
|
|
SiteState.Properties.PageTitle = PageState.Page.Title;
|
|
}
|
|
else
|
|
{
|
|
SiteState.Properties.PageTitle = PageState.Page.Name + " - " + PageState.Site.Name;
|
|
}
|
|
|
|
// set page head content
|
|
var headcontent = "";
|
|
|
|
// favicon
|
|
if (PageState.Site.FaviconFileId != null)
|
|
{
|
|
headcontent += $"<link id=\"app-favicon\" rel=\"icon\" href=\"{Utilities.FileUrl(PageState.Alias, PageState.Site.FaviconFileId.Value)}\" />\n";
|
|
}
|
|
else
|
|
{
|
|
headcontent += $"<link id=\"app-favicon\" rel=\"icon\" type=\"image/x-icon\" href=\"favicon.ico\" />\n";
|
|
}
|
|
|
|
// head content
|
|
if (!string.IsNullOrEmpty(PageState.Site.HeadContent))
|
|
{
|
|
headcontent = AddHeadContent(headcontent, PageState.Site.HeadContent);
|
|
}
|
|
if (!string.IsNullOrEmpty(PageState.Page.HeadContent))
|
|
{
|
|
headcontent = AddHeadContent(headcontent, PageState.Page.HeadContent);
|
|
}
|
|
SiteState.Properties.HeadContent = headcontent;
|
|
|
|
DynamicComponent = builder =>
|
|
{
|
|
builder.OpenComponent(0, Type.GetType(PageState.Page.ThemeType));
|
|
builder.CloseComponent();
|
|
};
|
|
}
|
|
|
|
private string AddHeadContent(string headcontent, string content)
|
|
{
|
|
if (!string.IsNullOrEmpty(content))
|
|
{
|
|
var elements = content.Split('<', StringSplitOptions.RemoveEmptyEntries);
|
|
foreach (var element in elements)
|
|
{
|
|
if (PageState.RenderMode == RenderModes.Static || (!element.ToLower().StartsWith("script") && !element.ToLower().StartsWith("/script")))
|
|
{
|
|
if (!headcontent.Contains("<" + element) || element.StartsWith("/"))
|
|
{
|
|
headcontent += "<" + element;
|
|
}
|
|
}
|
|
}
|
|
headcontent += "\n";
|
|
}
|
|
return headcontent;
|
|
}
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (!firstRender && PageState.Page.Path != lastPagePath)
|
|
{
|
|
if (!string.IsNullOrEmpty(PageState.Site.HeadContent) && PageState.Site.HeadContent.Contains("<script"))
|
|
{
|
|
await InjectScripts(PageState.Site.HeadContent, ResourceLocation.Head);
|
|
}
|
|
if (!string.IsNullOrEmpty(PageState.Site.BodyContent) && PageState.Site.BodyContent.Contains("<script"))
|
|
{
|
|
await InjectScripts(PageState.Site.BodyContent, ResourceLocation.Body);
|
|
}
|
|
if (!string.IsNullOrEmpty(PageState.Page.HeadContent) && PageState.Page.HeadContent.Contains("<script"))
|
|
{
|
|
await InjectScripts(PageState.Page.HeadContent, ResourceLocation.Head);
|
|
}
|
|
if (!string.IsNullOrEmpty(PageState.Page.BodyContent) && PageState.Page.BodyContent.Contains("<script"))
|
|
{
|
|
await InjectScripts(PageState.Page.BodyContent, ResourceLocation.Body);
|
|
}
|
|
lastPagePath = PageState.Page.Path;
|
|
}
|
|
|
|
// style sheets
|
|
if (PageState.Page.Resources != null && PageState.Page.Resources.Exists(item => item.ResourceType == ResourceType.Stylesheet))
|
|
{
|
|
var interop = new Interop(JSRuntime);
|
|
string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
|
|
var links = new List<object>();
|
|
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet))
|
|
{
|
|
var prefix = "app-stylesheet-" + resource.Level.ToString().ToLower();
|
|
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
|
links.Add(new { id = prefix + "-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", insertbefore = prefix });
|
|
}
|
|
if (links.Any())
|
|
{
|
|
await interop.IncludeLinks(links.ToArray());
|
|
}
|
|
await interop.RemoveElementsById("app-stylesheet-page-", "", "app-stylesheet-page-" + batch + "-00");
|
|
await interop.RemoveElementsById("app-stylesheet-module-", "", "app-stylesheet-module-" + batch + "-00");
|
|
}
|
|
}
|
|
|
|
private async Task InjectScripts(string content, ResourceLocation location)
|
|
{
|
|
// inject scripts into page dynamically
|
|
var interop = new Interop(JSRuntime);
|
|
var scripts = new List<object>();
|
|
var count = 0;
|
|
var index = content.IndexOf("<script");
|
|
while (index >= 0)
|
|
{
|
|
var script = content.Substring(index, content.IndexOf("</script>", index) + 9 - index);
|
|
// get script attributes
|
|
var attributes = script.Substring(0, script.IndexOf(">")).Replace("\"", "").Split(" ");
|
|
string id = "";
|
|
string src = "";
|
|
string integrity = "";
|
|
string crossorigin = "";
|
|
string type = "";
|
|
var dataAttributes = new Dictionary<string, string>();
|
|
foreach (var attribute in attributes)
|
|
{
|
|
if (attribute.Contains("="))
|
|
{
|
|
var value = attribute.Split("=");
|
|
switch (value[0])
|
|
{
|
|
case "id":
|
|
id = value[1];
|
|
break;
|
|
case "src":
|
|
src = value[1];
|
|
break;
|
|
case "integrity":
|
|
integrity = value[1];
|
|
break;
|
|
case "crossorigin":
|
|
crossorigin = value[1];
|
|
break;
|
|
case "type":
|
|
type = value[1];
|
|
break;
|
|
default:
|
|
if(!string.IsNullOrWhiteSpace(value[0]) && value[0].StartsWith("data-"))
|
|
{
|
|
dataAttributes.Add(value[0], value[1]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// inject script
|
|
if (!string.IsNullOrEmpty(src))
|
|
{
|
|
src = (src.Contains("://")) ? src : PageState.Alias.BaseUrl + src;
|
|
scripts.Add(new { href = src, type = type, bundle = "", integrity = integrity, crossorigin = crossorigin, location = location.ToString().ToLower(), dataAttributes = dataAttributes });
|
|
}
|
|
else
|
|
{
|
|
if (dataAttributes == null || !dataAttributes.ContainsKey("data-reload") || dataAttributes["data-reload"] != "false")
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
index = content.IndexOf("<script", index + 1);
|
|
}
|
|
if (scripts.Any())
|
|
{
|
|
await interop.IncludeScripts(scripts.ToArray());
|
|
}
|
|
}
|
|
|
|
private string ManageStyleSheets(List<Resource> resources, Alias alias)
|
|
{
|
|
var stylesheets = "";
|
|
if (resources != null)
|
|
{
|
|
string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
|
|
int count = 0;
|
|
foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Stylesheet))
|
|
{
|
|
if (resource.Url.StartsWith("~"))
|
|
{
|
|
resource.Url = resource.Url.Replace("~", "/Themes/" + Utilities.GetTypeName(resource.Namespace) + "/").Replace("//", "/");
|
|
}
|
|
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
|
{
|
|
resource.Url = alias.BaseUrl + resource.Url;
|
|
}
|
|
|
|
if (!stylesheets.Contains(resource.Url, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
count++;
|
|
string id = "id=\"app-stylesheet-" + ResourceLevel.Page.ToString().ToLower() + "-" + batch + "-" + count.ToString("00") + "\" ";
|
|
stylesheets += "<link " + id + "rel=\"stylesheet\" href=\"" + resource.Url + "\"" + (!string.IsNullOrEmpty(resource.Integrity) ? " integrity=\"" + resource.Integrity + "\"" : "") + (!string.IsNullOrEmpty(resource.CrossOrigin) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") + " type=\"text/css\"/>" + Environment.NewLine;
|
|
}
|
|
}
|
|
}
|
|
return stylesheets;
|
|
}
|
|
|
|
private string ManageScripts(List<Resource> resources, Alias alias)
|
|
{
|
|
var scripts = "";
|
|
if (resources != null)
|
|
{
|
|
foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Script && item.Location == ResourceLocation.Head))
|
|
{
|
|
var script = CreateScript(resource, alias);
|
|
if (!scripts.Contains(script, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
scripts += script + Environment.NewLine;
|
|
}
|
|
}
|
|
}
|
|
return scripts;
|
|
}
|
|
|
|
private string CreateScript(Resource resource, Alias alias)
|
|
{
|
|
if (!string.IsNullOrEmpty(resource.Url))
|
|
{
|
|
var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
|
|
return "<script src=\"" + url + "\"" +
|
|
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
|
|
((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") +
|
|
"></script>";
|
|
}
|
|
else
|
|
{
|
|
// inline script
|
|
return "<script>" + resource.Content + "</script>";
|
|
}
|
|
}
|
|
}
|