public async Task InvokeAsync(HttpContext context, IHeadElementHelperStore store) { var filter = new FilterStream(context, store); try { await _next(context); if (filter.IsCaptured()) { filter.MemoryStream.Seek(0, SeekOrigin.Begin); var parser = new HtmlParser(); using var doc = parser.ParseDocument(filter.MemoryStream); SetDocumentTitle(store, doc); SetMetaElements(store, doc); SetLinkElements(store, doc); filter.MemoryStream.SetLength(0); var encoding = Encoding.UTF8; using var writer = new StreamWriter(filter.MemoryStream, bufferSize: -1, leaveOpen: true, encoding: encoding) { AutoFlush = true }; doc.ToHtml(writer, new PrettyMarkupFormatter()); filter.MemoryStream.Seek(0, SeekOrigin.Begin); await filter.MemoryStream.CopyToAsync(filter.OriginalStream); } } finally { filter.RevertResponseBodyHooking(); } }
private void SetLinkElements(IHeadElementHelperStore store, IHtmlDocument doc, string indentText) { if (store.LinkElementCommands.Count == 0) { return; } var linkTags = doc.Head.QuerySelectorAll("link").Cast <IHtmlLinkElement>().ToList(); SaveDefault(doc, indentText, linkTags); foreach (var cmd in store.LinkElementCommands) { var e = cmd.Element; var link = linkTags.FirstOrDefault(m => SameLink(m, e)); if (cmd.Operation == LinkElementOperations.Set) { if (link == null) { link = CreateAndAddToHead <IHtmlLinkElement>(doc, indentText); linkTags.Add(link); } link.Relation = e.Rel; link.Href = e.Href; foreach (var(name, value) in new[] {
internal HeadElementHelperService(IServiceProvider services) { this._JS = services.GetService <IJSRuntime>(); this._NavigationManager = services.GetRequiredService <NavigationManager>(); this._Store = services.GetRequiredService <IHeadElementHelperStore>(); this._NavigationManager.LocationChanged += _NavigationManager_LocationChanged; }
private void SetMetaElements(IHeadElementHelperStore store, IHtmlDocument doc) { if (store.MetaElementCommands.Count == 0) { return; } var metaTags = doc.Head.QuerySelectorAll("meta[name],meta[property],meta[http-equiv]").Cast <IHtmlMetaElement>().ToList(); var metaElements = metaTags.Select(m => new MetaElement { Name = m.Name ?? "", Property = m.GetAttribute("property") ?? "", HttpEquiv = m.HttpEquivalent ?? "", Content = m.Content }); SaveDefault(doc, metaElements, "text/default-meta-elements"); foreach (var cmd in store.MetaElementCommands) { var meta = metaTags.FirstOrDefault(m => (cmd.Element.Name != "" && cmd.Element.Name == m.Name) || (cmd.Element.Property != "" && cmd.Element.Property == m.GetAttribute("property")) || (cmd.Element.HttpEquiv != "" && cmd.Element.HttpEquiv == m.HttpEquivalent)); if (cmd.Operation == MetaElementOperations.Set) { if (meta == null) { meta = doc.CreateElement("meta") as IHtmlMetaElement; if (cmd.Element.Name != "") { meta.Name = cmd.Element.Name; } if (cmd.Element.Property != "") { meta.SetAttribute("property", cmd.Element.Property); } if (cmd.Element.HttpEquiv != "") { meta.HttpEquivalent = cmd.Element.HttpEquiv; } doc.Head.AppendChild(meta); metaTags.Add(meta); } meta.Content = cmd.Element.Content; } else if (cmd.Operation == MetaElementOperations.Remove) { if (meta != null) { doc.Head.RemoveChild(meta); metaTags.Remove(meta); } } } }
private static void SetDocumentTitle(IHeadElementHelperStore store, IHtmlDocument doc, string indentText) { if (store.Title == null) { return; } store.DefaultTitle = doc.Title ?? ""; doc.Title = store.Title; SaveDefault(doc, indentText, store.DefaultTitle, "text/default-title"); }
private static void SetDocumentTitle(IHeadElementHelperStore store, AngleSharp.Html.Dom.IHtmlDocument doc) { if (store.Title == null) { return; } store.DefaultTitle = doc.Title ?? ""; doc.Title = store.Title; SaveDefault(doc, store.DefaultTitle, "text/default-title"); }
private void SetMetaElements(IHeadElementHelperStore store, IHtmlDocument doc, string indentText) { if (store.MetaElementCommands.Count == 0) { return; } var metaTags = doc.Head.QuerySelectorAll("meta[name],meta[property],meta[http-equiv]").Cast <IHtmlMetaElement>().ToList(); SaveDefault(doc, indentText, metaTags); foreach (var cmd in store.MetaElementCommands) { var meta = metaTags.FirstOrDefault(m => (cmd.Element.Name != "" && cmd.Element.Name == m.Name) || (cmd.Element.Property != "" && cmd.Element.Property == m.GetAttribute("property")) || (cmd.Element.HttpEquiv != "" && cmd.Element.HttpEquiv == m.HttpEquivalent)); if (cmd.Operation == MetaElementOperations.Set) { if (meta == null) { meta = CreateAndAddToHead <IHtmlMetaElement>(doc, indentText); metaTags.Add(meta); if (cmd.Element.Name != "") { meta.Name = cmd.Element.Name; } if (cmd.Element.Property != "") { meta.SetAttribute("property", cmd.Element.Property); } if (cmd.Element.HttpEquiv != "") { meta.HttpEquivalent = cmd.Element.HttpEquiv; } } meta.Content = cmd.Element.Content; } else if (cmd.Operation == MetaElementOperations.Remove) { if (meta != null) { doc.Head.RemoveChild(meta); metaTags.Remove(meta); } } } }
public async Task InvokeAsync(HttpContext context, IHeadElementHelperStore store) { var filter = new FilterStream(context, store); try { await this._next(context); if (filter.IsCaptured()) { filter.MemoryStream.Seek(0, SeekOrigin.Begin); var parser = new HtmlParser(); using var doc = parser.ParseDocument(filter.MemoryStream); var indentText = doc.Head.Descendents <IText>() .Select(t => t.Data.Trim('\r', '\n')) .Where(t => Regex.IsMatch(t, @"^[\t ]+$")) .OrderByDescending(t => t.Length) .FirstOrDefault() ?? ""; SetDocumentTitle(store, doc, indentText); this.SetMetaElements(store, doc, indentText); this.SetLinkElements(store, doc, indentText); doc.Head.AppendChild(doc.CreateTextNode("\n")); filter.MemoryStream.SetLength(0); var encoding = Encoding.UTF8; using var writer = new StreamWriter(filter.MemoryStream, bufferSize: -1, leaveOpen: true, encoding: encoding) { AutoFlush = true }; // WORKAROUND: The HtmlMarkupFormatter class in AngleSharp doesn't append slash for closing tag, so I implemented custom version of it. doc.ToHtml(writer, new CustomHtmlMarkupFormatter()); filter.MemoryStream.Seek(0, SeekOrigin.Begin); await filter.MemoryStream.CopyToAsync(filter.OriginalStream); } } finally { filter.RevertResponseBodyHooking(); } }
private void SetLinkElements(IHeadElementHelperStore store, IHtmlDocument doc) {
private void SetLinkElements(IHeadElementHelperStore store, IHtmlDocument doc, string indentText) {