Created
July 11, 2023 15:05
-
-
Save rickbutterfield/7e567d689e41102eb8228cc0fa1514d1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class StringExtensionMethods | |
{ | |
public static string AddHeadingAnchorsToHtml(this string html) | |
{ | |
var doc = new HtmlDocument(); | |
doc.LoadHtml(html); | |
// select all possible headings in the document | |
var headings = doc.DocumentNode.SelectNodes("//h2"); | |
if (headings != null) | |
{ | |
foreach (var heading in headings) | |
{ | |
var headingText = heading.InnerText; | |
// if heading has id, use it | |
string headingId = heading.Attributes["id"]?.Value; | |
if (headingId == null) | |
{ | |
// if heading does not have an id, generate a safe id by creating a slug based on the heading text | |
// slug is a URL/SEO friendly part of a URL, this is a good option for generating anchor fragments | |
// Source: http://predicatet.blogspot.com/2009/04/improved-c-slug-generator-or-how-to.html | |
// assumption: Prase should only contain standard a-z characters or numbers | |
headingId = headingText.ToCssClass(); | |
// for the fragment to work (jump to the relevant content), the heading id and fragment needs to match | |
heading.Attributes.Append("id", headingId); | |
heading.Attributes.Append("class", "anchor"); | |
} | |
// use a non-breaking space to make sure the heading text and the #-sign don't appear on a separate line | |
//heading.InnerHtml += " "; | |
// create the heading anchor which points to the heading | |
//var headingAnchor = HtmlNode.CreateNode($"<a href=\"#{headingId}\" aria-label=\"Anchor for heading: {headingText}\">#</a>"); | |
// append the anchor behind the heading text content | |
//heading.AppendChild(headingAnchor); | |
} | |
} | |
return doc.DocumentNode.InnerHtml; | |
} | |
public static List<KeyValuePair<string, string>> GetHeadingAnchorsFromHtml(this IHtmlEncodedString html) | |
{ | |
List<KeyValuePair<string, string>> headingData = new(); | |
var doc = new HtmlDocument(); | |
doc.LoadHtml(html.ToHtmlString()); | |
// select all possible headings in the document | |
var headings = doc.DocumentNode.SelectNodes("//h2"); | |
if (headings != null) | |
{ | |
foreach (var heading in headings) | |
{ | |
var headingText = heading.InnerText; | |
// if heading has id, use it | |
string headingId = heading.Attributes["id"]?.Value; | |
if (headingId == null) | |
{ | |
// if heading does not have an id, generate a safe id by creating a slug based on the heading text | |
// slug is a URL/SEO friendly part of a URL, this is a good option for generating anchor fragments | |
// Source: http://predicatet.blogspot.com/2009/04/improved-c-slug-generator-or-how-to.html | |
// assumption: Prase should only contain standard a-z characters or numbers | |
headingId = headingText.ToCssClass(); | |
// for the fragment to work (jump to the relevant content), the heading id and fragment needs to match | |
} | |
headingData.Add(new KeyValuePair<string, string>(headingId, headingText)); | |
} | |
} | |
return headingData; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment