Skip to content

Commit cb80249

Browse files
committed
Extract DocToStaticPagesTransformer.
1 parent 0115f45 commit cb80249

9 files changed

Lines changed: 527 additions & 455 deletions

converter/generator/DocBookTransformer.cs

Lines changed: 185 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
using System.Xml.Linq;
1+
using System.Diagnostics;
2+
using System.Xml.Linq;
3+
using AngleSharp.Dom;
4+
using AngleSharp.Html.Dom;
25
using OriginLab.DocumentGeneration.Templates;
36

47
namespace OriginLab.DocumentGeneration;
58

6-
internal sealed class DocBookTransformer : DocTransformer
9+
internal sealed class DocBookTransformer : DocToStaticPagesTransformer
710
{
11+
private readonly string AvailableLanguagesExpression;
12+
813
private readonly string BookDirName;
914
private readonly (string url, string file, string titleEn, NavFiles navFiles)[] Pages;
1015

11-
public DocBookTransformer(DocTransformerArgs args, ProblemRecorder problems) : base(args, problems)
16+
public DocBookTransformer(DocToStaticPagesTransformerArgs args, ProblemRecorder problems) : base(args, problems)
1217
{
18+
AvailableLanguagesExpression = String.Join(',', AvailableLanguages);
1319
BookDirName = Path.GetFileName(Directory.EnumerateDirectories(Path.Combine(SourceFolder, "en")).Single());
1420

1521
var bookXml = XElement.Load(Path.Combine(SourceFolder, "en", BookDirName, "book.xml"));
@@ -61,7 +67,7 @@ public DocBookTransformer(DocTransformerArgs args, ProblemRecorder problems) : b
6167
}
6268
}
6369

64-
public override async Task TransformFilesAsync(string language)
70+
protected override async Task TransformAsync(string language)
6571
{
6672
var srcDir = Path.Combine(SourceFolder, language, BookDirName);
6773
var srcEnDir = Path.Combine(SourceFolderEn, BookDirName);
@@ -112,4 +118,179 @@ public override async Task TransformFilesAsync(string language)
112118
}
113119
}
114120
}
121+
122+
private void Transform(string srcFile, string dstFile, Nav nav, string? bannerHtml = null)
123+
{
124+
Transform(srcFile, dstFile, (document, head, body, file) =>
125+
{
126+
if (bannerHtml is string banner)
127+
{
128+
var div = document.CreateElement<IHtmlDivElement>();
129+
div.InnerHtml = banner;
130+
131+
body.PrependNodes(div.ChildNodes.ToArray());
132+
}
133+
134+
var navDataDiv = CreateNavDataDiv(document, nav, Path.GetDirectoryName(file)!);
135+
body.AppendChild(navDataDiv);
136+
});
137+
}
138+
139+
140+
string? CachedSiblingsParent;
141+
int CachedSiblingsCurrentIndex;
142+
IHtmlElement? CachedSiblings;
143+
144+
private IHtmlDivElement CreateNavDataDiv(IHtmlDocument document, in Nav nav, string sourceDir)
145+
{
146+
var navDataDiv = document.CreateElement<IHtmlDivElement>();
147+
148+
navDataDiv.Id = "doc-nav-data";
149+
navDataDiv.IsHidden = true;
150+
151+
navDataDiv.SetAttribute("data-lang", Language);
152+
navDataDiv.SetAttribute("data-lang-list", AvailableLanguagesExpression);
153+
154+
var files = nav.Files;
155+
156+
if (!files.Parent.IsEmpty)
157+
{
158+
if (TryResolveHref(sourceDir, "../" + files.Parent, out var url, out var _))
159+
{
160+
navDataDiv.SetAttribute("data-parent-link", url);
161+
}
162+
}
163+
else
164+
{
165+
navDataDiv.SetAttribute("data-parent-link", Language == "en" ? "/" : $"/{Language}");
166+
}
167+
168+
if (nav.IsBookIndex)
169+
{
170+
navDataDiv.SetAttribute("data-book-index", BookUrlName);
171+
}
172+
173+
if (files.Siblings is not null)
174+
{
175+
IHtmlElement ul;
176+
177+
if (nav.Files.Parent is string parent && parent == CachedSiblingsParent)
178+
{
179+
ul = CreateSiblingsULFromCache(CachedSiblings!, files.Siblings, nav.Titles);
180+
}
181+
else
182+
{
183+
CachedSiblingsParent = nav.Files.Parent;
184+
CachedSiblings = ul = CreateDataUL("doc-siblings-data", files.Siblings, nav.Titles);
185+
}
186+
187+
navDataDiv.AppendChild(ul);
188+
}
189+
190+
if (files.Children is not null)
191+
{
192+
var ul = CreateDataUL("doc-children-data", files.Children, nav.Titles);
193+
navDataDiv.AppendChild(ul);
194+
}
195+
196+
return navDataDiv;
197+
198+
IHtmlElement CreateDataUL(string id, string[] files, Dictionary<string, string> titles)
199+
{
200+
var ul = document.CreateElement<IHtmlUnorderedListElement>();
201+
202+
ul.Id = id;
203+
204+
for (int i = 0; i < files.Length; i++)
205+
{
206+
string? path = files[i];
207+
var li = document.CreateElement<IHtmlListItemElement>();
208+
var a = document.CreateElement<IHtmlAnchorElement>();
209+
var pathSpan = path.AsSpan();
210+
var isCurrent = false;
211+
212+
if (path.StartsWith('*'))
213+
{
214+
pathSpan = pathSpan[1..];
215+
isCurrent = true;
216+
CachedSiblingsCurrentIndex = i;
217+
}
218+
219+
if (TryResolveHref(sourceDir, $"../{pathSpan}", out var url, out var _))
220+
{
221+
if (isCurrent)
222+
{
223+
li.ClassName = "disabled";
224+
}
225+
else
226+
{
227+
a.SetAttribute("href", url);
228+
}
229+
230+
a.TextContent = titles.GetAlternateLookup<ReadOnlySpan<char>>()[pathSpan];
231+
}
232+
233+
li.AppendChild(a);
234+
ul.AppendChild(li);
235+
}
236+
237+
return ul;
238+
}
239+
240+
IHtmlElement CreateSiblingsULFromCache(IHtmlElement ul, string[] files, Dictionary<string, string> titles)
241+
{
242+
document.AdoptNode(ul);
243+
244+
var currentIdx = Array.FindIndex(files, CachedSiblingsCurrentIndex, files.Length - CachedSiblingsCurrentIndex, f => f.StartsWith('*'));
245+
var previousLi = ul.Children[CachedSiblingsCurrentIndex].SelfOrNextElementSibling(li => li.FirstElementChild!.GetAttribute("href").IsEmpty);
246+
247+
Debug.Assert(currentIdx > 0);
248+
Debug.Assert(previousLi is not null);
249+
250+
if (TryResolveHref(sourceDir, $"../{files[currentIdx - 1]}", out var url, out var _))
251+
{
252+
previousLi.FirstElementChild!.SetAttribute("href", url);
253+
}
254+
255+
previousLi.ClassName = null;
256+
257+
var currentLi = previousLi.NextElementSibling!;
258+
currentLi.FirstElementChild!.SetAttribute("href", null);
259+
currentLi.ClassName = "disabled";
260+
261+
if (ul.ChildElementCount < files.Length)
262+
{
263+
var li = document.CreateElement<IHtmlListItemElement>();
264+
var a = document.CreateElement<IHtmlAnchorElement>();
265+
266+
if (TryResolveHref(sourceDir, $"../{files[^1]}", out var endUrl, out var _))
267+
{
268+
a.SetAttribute("href", endUrl);
269+
a.TextContent = titles[files[^1]];
270+
}
271+
272+
li.AppendChild(a);
273+
ul.AppendChild(li);
274+
}
275+
else if (currentIdx == MaxSiblingNodes / 2 && currentIdx != files.Length - 1 && currentIdx == CachedSiblingsCurrentIndex)
276+
{
277+
var li = (IHtmlElement)ul.RemoveChild(ul.FirstElementChild!);
278+
279+
if (TryResolveHref(sourceDir, $"../{files[^1]}", out var endUrl, out var _)
280+
&& endUrl != ul.LastElementChild!.FirstElementChild!.GetAttribute("href"))
281+
{
282+
var a = li.FirstElementChild!;
283+
284+
a.SetAttribute("href", endUrl);
285+
a.TextContent = titles[files[^1]];
286+
287+
ul.AppendChild(li);
288+
}
289+
}
290+
291+
CachedSiblingsCurrentIndex = currentIdx;
292+
return ul;
293+
}
294+
}
295+
115296
}

converter/generator/DocIndexTransformer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
namespace OriginLab.DocumentGeneration;
44

5-
internal class DocIndexTransformer : DocTransformer
5+
internal class DocIndexTransformer : DocToStaticPagesTransformer
66
{
7-
public DocIndexTransformer(DocTransformerArgs args, ProblemRecorder problems) : base(args, problems)
7+
public DocIndexTransformer(DocToStaticPagesTransformerArgs args, ProblemRecorder problems) : base(args, problems)
88
{
99
}
1010

11-
public override async Task TransformFilesAsync(string language)
11+
protected override async Task TransformAsync(string language)
1212
{
1313
foreach (var sourceFile in Directory.EnumerateFiles(SourceFolder, "index.html", SearchOption.AllDirectories))
1414
{

0 commit comments

Comments
 (0)