Add page id feature

This commit is contained in:
Christoph Hagen 2022-08-31 00:02:42 +02:00
parent ee1ad60b77
commit 268ab205b5
5 changed files with 87 additions and 21 deletions

View File

@ -255,6 +255,20 @@ struct Element {
extension Element {
/**
The localized html file name for a language, including a leading slash.
*/
static func htmlPagePathAddition(for language: String) -> String {
"/" + htmlPageName(for: language)
}
/**
The localized html file name for a language, without the leading slash.
*/
static func htmlPageName(for language: String) -> String {
"\(language).html"
}
var containsElements: Bool {
!elements.isEmpty
}
@ -286,7 +300,30 @@ extension Element {
The url of the top-level section of the element.
*/
func sectionUrl(for language: String) -> String {
path.components(separatedBy: "/").first! + "/\(language).html"
path.components(separatedBy: "/").first! + Element.htmlPagePathAddition(for: language)
}
/**
Create a relative link to another page in the tree.
- Parameter pageUrl: The full page url of the target page, including localization
- Returns: The relative url from a localized page of the element to the target page.
*/
func relativePathToOtherSiteElement(pageUrl: String) -> String {
// Note: The element `path` is missing the last component
// i.e. travel/alps instead of travel/alps/en.html
let ownParts = path.components(separatedBy: "/")
let pageParts = pageUrl.components(separatedBy: "/")
// Find the common elements of the path, which can be discarded
var index = 0
while pageParts[index] == ownParts[index] {
index += 1
}
// The relative path needs to go down to the first common folder,
// before going up to the target page
let allParts = [String](repeating: "..", count: ownParts.count-index)
+ pageParts.dropFirst(index)
return allParts.joined(separator: "/")
}
/**
@ -381,7 +418,10 @@ extension Element {
Returns the full path (relative to the site root for a page of the element in the given language.
*/
func localizedPath(for language: String) -> String {
path != "" ? "\(path)/\(language).html" : "\(language).html"
guard path != "" else {
return Element.htmlPageName(for: language)
}
return path + Element.htmlPagePathAddition(for: language)
}
/**

View File

@ -440,6 +440,10 @@ final class FileSystem {
pagePaths[id] = page
}
func getPage(for id: String) -> String? {
pagePaths[id]
}
// MARK: Writing files

View File

@ -12,11 +12,11 @@ struct HTMLElementsGenerator {
// - TODO: Make link relative
func topBarWebsiteTitle(language: String) -> String {
"/\(language).html"
Element.htmlPagePathAddition(for: language)
}
func topBarLanguageButton(_ language: String) -> String {
"<a href=\"\(language).html\">\(language)</a>"
"<a href=\"\(Element.htmlPageName(for: language))\">\(language)</a>"
}
func topBarNavigationLink(url: String, text: String, isActive: Bool) -> String {
@ -46,7 +46,7 @@ struct HTMLElementsGenerator {
func svgImage(file: String, x: Int, y: Int, width: Int, height: Int) -> String {
"""
<span class="image">
<img src="\(file)#svgView(viewBox(\(x), \(y), \(width), \(height))" style="aspect-ratio:\(Float(width)/Float(height))"/>
<img src="\(file)#svgView(viewBox(\(x), \(y), \(width), \(height)))" style="aspect-ratio:\(Float(width)/Float(height))"/>
</span>
"""
}

View File

@ -27,27 +27,49 @@ struct PageContentGenerator {
return html
}
let linkModifier = Modifier(target: .links) { html, markdown in
handleLink(page: page, language: language, html: html, markdown: markdown)
}
let htmlModifier = Modifier(target: .html) { html, markdown in
handleHTML(page: page, language: language, html: html, markdown: markdown)
}
let parser = MarkdownParser(modifiers: [imageModifier, codeModifier, linkModifier, htmlModifier])
return (parser.html(from: content), hasCodeContent)
}
private func handleLink(page: Element, language: String, html: String, markdown: Substring) -> String {
let file = markdown.between("(", and: ")")
if file.hasPrefix("page:") {
let pageId = file.replacingOccurrences(of: "page:", with: "")
guard let pagePath = files.getPage(for: pageId) else {
log.add(warning: "Page id '\(pageId)' not found", source: page.path)
// Remove link since the page can't be found
return markdown.between("[", and: "]")
}
let fullPath = pagePath + Element.htmlPagePathAddition(for: language)
// Adjust file path to get the page url
let url = page.relativePathToOtherSiteElement(pageUrl: fullPath)
return html.replacingOccurrences(of: file, with: url)
}
if let filePath = page.nonAbsolutePathRelativeToRootForContainedInputFile(file) {
// The target of the page link must be present after generation is complete
files.expect(file: filePath, source: page.path)
}
return html
}
let htmlModifier = Modifier(target: .html) { html, markdown in
private func handleHTML(page: Element, language: String, html: String, markdown: Substring) -> String {
#warning("Check HTML code in markdown for required resources")
//print("[HTML] Found in page \(page.path):")
//print(markdown)
// Thinks to check
// Things to check:
// <img src=
// <a href=
//
return html
}
let parser = MarkdownParser(modifiers: [imageModifier, codeModifier, linkModifier, htmlModifier])
return (parser.html(from: content), hasCodeContent)
}
private func processMarkdownImage(markdown: Substring, html: String, page: Element) -> String {
// Split the markdown ![alt](file title)
// For images: ![left_title](file right_title)
@ -127,7 +149,7 @@ struct PageContentGenerator {
guard let area = area else {
return factory.html.svgImage(file: file)
}
let parts = area.components(separatedBy: ",")
let parts = area.components(separatedBy: ",").map { $0.trimmed }
guard parts.count == 4,
let x = Int(parts[0]),
let y = Int(parts[1]),

View File

@ -58,7 +58,7 @@ struct LocalizedSiteTemplate {
let sections = site.sortedItems.map {
PrefilledTopBarTemplate.SectionInfo(
name: $0.title(for: language),
url: "\($0.path)/\(language).html")
url: $0.path + Element.htmlPagePathAddition(for: language))
}
self.topBar = try .init(
@ -83,7 +83,7 @@ struct LocalizedSiteTemplate {
func makeBackLink(text: String, language: String) -> String {
let content: [BackNavigationTemplate.Key : String] = [
.text: text,
.url: "../\(language).html"
.url: ".." + Element.htmlPagePathAddition(for: language)
]
return backNavigation.generate(content)
}