-
-
Notifications
You must be signed in to change notification settings - Fork 595
Fix #5511: refactor wiki lists to use bbcode #6858
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
f843d79
f959e0f
fceaf81
e5f4354
d0c32d3
8e89168
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -222,6 +222,27 @@ private static HashSet<string> LoadGameTranslationKeys() | |
| return result; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Converts formatted HTML text into BBCode. | ||
| /// </summary> | ||
| private static string ConvertTextToBbcode(string paragraph) | ||
| { | ||
| return paragraph | ||
| .Replace("\n", string.Empty) | ||
| .Replace("<b>", "[b]") | ||
| .Replace("</b>", "[/b]") | ||
| .Replace("<i>", "[i]") | ||
| .Replace("</i>", "[/i]") | ||
| .Replace("<u>", "[u]") | ||
| .Replace("</u>", "[/u]") | ||
| .Replace("<code>", "[code]") | ||
| .Replace("</code>", "[/code]") | ||
| .Replace("<pre>", "[code]") | ||
| .Replace("</pre>", "[/code]") | ||
| .Replace("<br>", "\n") | ||
| .Replace("\"", "\\\""); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Fetches a page from the online wiki | ||
| /// </summary> | ||
|
|
@@ -528,49 +549,46 @@ private Stage[] StageStringToEnumValues(string rawStageStrings) | |
| private List<GameWiki.Page.Section> GetMainBodySections(IHtmlElement body) | ||
| { | ||
| var sections = new List<GameWiki.Page.Section> { new(null, string.Empty) }; | ||
|
|
||
| var children = body.QuerySelector(".mw-parser-output")!.Children; | ||
| var text = new StringBuilder(); | ||
| foreach (var child in children) | ||
| { | ||
| if (child.TagName == "H2") | ||
| { | ||
| // Complete the previous section and start a new one with this heading | ||
| sections.Add(new GameWiki.Page.Section(child.TextContent, string.Empty)); | ||
| continue; | ||
| } | ||
|
|
||
| string text; | ||
| switch (child.TagName) | ||
| { | ||
| case "H2": | ||
| { | ||
| // Complete the previous section | ||
| sections[^1].SectionBody = text.ToString().Trim(); | ||
|
|
||
| // and start a new one with this heading | ||
| sections.Add(new GameWiki.Page.Section(child.TextContent, string.Empty)); | ||
| text = new StringBuilder(); | ||
| continue; | ||
| } | ||
| case "P": | ||
| text = ConvertParagraphToBbcode(child) + "\n\n"; | ||
| text = ConvertParagraphToBbcode(child, text); | ||
| break; | ||
| case "UL": | ||
|
|
||
| // TODO: switch to the Godot 4 way to handle this: | ||
| // https://github.com/Revolutionary-Games/Thrive/issues/5511 | ||
| // Godot 3 does not support lists in BBCode, so use custom formatting | ||
| text = child.Children | ||
| .Where(c => c.TagName == "LI") | ||
| .Select(l => $"[indent]— {ConvertParagraphToBbcode(l)}[/indent]") | ||
| .Aggregate((a, b) => a + "\n" + b) + "\n\n"; | ||
| case "UL" or "OL": | ||
| text = ConvertListToBbcode(child, text); | ||
| break; | ||
| case "H3": | ||
| var headline = child.Children | ||
| .First(c => c.ClassList.Contains("mw-headline")); | ||
|
|
||
| text = $"[b][u]{headline.TextContent}[/u][/b]\n\n"; | ||
| text = text.Append($"[b][u]{headline.TextContent}[/u][/b]"); | ||
| break; | ||
| default: | ||
| // Ignore all other tag types | ||
| continue; | ||
| } | ||
|
|
||
| // Concatenate this tag with the rest of the section so far | ||
| sections[^1] = new GameWiki.Page.Section(sections[^1].SectionHeading, sections[^1].SectionBody + text); | ||
| text.Append("\n\n"); | ||
| } | ||
|
|
||
| return sections.Select(s => new GameWiki.Page.Section(s.SectionHeading, s.SectionBody.Trim())).ToList(); | ||
| // ensuring sections have their SectionBody | ||
| sections[^1].SectionBody = text.ToString().Trim(); | ||
|
|
||
| return sections; | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -586,18 +604,38 @@ private GameWiki.Page.Section UntranslateSection(GameWiki.Page.Section section, | |
| return new GameWiki.Page.Section(heading, body); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Converts HTML for a single paragraph into BBCode. Paragraph must not contain lists, headings, etc. | ||
| /// </summary> | ||
| private string ConvertParagraphToBbcode(IElement paragraph) | ||
| private StringBuilder ConvertListToBbcode(IElement list, StringBuilder builder) | ||
| { | ||
| var bbcode = new StringBuilder(); | ||
| switch (list) | ||
| { | ||
| case IHtmlUnorderedListElement or IHtmlOrderedListElement: | ||
| { | ||
| var tag = list is IHtmlOrderedListElement ? "ol" : "ul"; | ||
|
|
||
| ConvertParagraphToBbcode(paragraph, bbcode); | ||
| return bbcode.ToString(); | ||
| builder.Append($"[{tag}]"); | ||
| foreach (var item in list.Children) | ||
| { | ||
| ConvertListToBbcode(item, builder); | ||
| builder.Append('\n'); | ||
| } | ||
|
|
||
| builder.Append($"[/{tag}]"); | ||
| break; | ||
| } | ||
| case IHtmlListItemElement: | ||
| ConvertParagraphToBbcode(list, builder); | ||
| break; | ||
|
|
||
| // ordered lists have not been required so far and other tags are invalid in the context of a list | ||
|
||
| } | ||
|
|
||
| return builder; | ||
| } | ||
|
|
||
| private void ConvertParagraphToBbcode(INode paragraph, StringBuilder result) | ||
| /// <summary> | ||
| /// Converts HTML for a single paragraph into BBCode. Paragraph must not contain lists, headings, etc. | ||
| /// </summary> | ||
| private StringBuilder ConvertParagraphToBbcode(INode paragraph, StringBuilder result) | ||
| { | ||
| var children = paragraph.ChildNodes; | ||
| foreach (var child in children) | ||
|
|
@@ -629,7 +667,7 @@ private void ConvertParagraphToBbcode(INode paragraph, StringBuilder result) | |
| case IElement { TagName: "B", Children.Length: > 0 } element: | ||
| // Deal with items inside bold tags, e.g. links | ||
| result.Append("[b]"); | ||
| result.Append(ConvertParagraphToBbcode(element)); | ||
| ConvertParagraphToBbcode(element, result); | ||
| result.Append("[/b]"); | ||
| continue; | ||
| case IElement element: | ||
|
|
@@ -640,6 +678,8 @@ private void ConvertParagraphToBbcode(INode paragraph, StringBuilder result) | |
| break; | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -718,27 +758,6 @@ private bool IsThriveIcon(string? iconName) | |
| return EmbeddedThriveIconExtensions.TryGetIcon(iconName, out _); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Converts formatted HTML text into BBCode. | ||
| /// </summary> | ||
| private string ConvertTextToBbcode(string paragraph) | ||
| { | ||
| return paragraph | ||
| .Replace("\n", string.Empty) | ||
| .Replace("<b>", "[b]") | ||
| .Replace("</b>", "[/b]") | ||
| .Replace("<i>", "[i]") | ||
| .Replace("</i>", "[/i]") | ||
| .Replace("<u>", "[u]") | ||
| .Replace("</u>", "[/u]") | ||
| .Replace("<code>", "[code]") | ||
| .Replace("</code>", "[/code]") | ||
| .Replace("<pre>", "[code]") | ||
| .Replace("</pre>", "[/code]") | ||
| .Replace("<br>", "\n") | ||
| .Replace("\"", "\\\""); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Inserts into en.po the English translations for all the translation keys in a list of wiki pages. | ||
| /// </summary> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.