Add page id feature
This commit is contained in:
parent
ee1ad60b77
commit
268ab205b5
@ -255,6 +255,20 @@ struct Element {
|
|||||||
|
|
||||||
extension 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 {
|
var containsElements: Bool {
|
||||||
!elements.isEmpty
|
!elements.isEmpty
|
||||||
}
|
}
|
||||||
@ -286,7 +300,30 @@ extension Element {
|
|||||||
The url of the top-level section of the element.
|
The url of the top-level section of the element.
|
||||||
*/
|
*/
|
||||||
func sectionUrl(for language: String) -> String {
|
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.
|
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 {
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -440,6 +440,10 @@ final class FileSystem {
|
|||||||
pagePaths[id] = page
|
pagePaths[id] = page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPage(for id: String) -> String? {
|
||||||
|
pagePaths[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Writing files
|
// MARK: Writing files
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ struct HTMLElementsGenerator {
|
|||||||
|
|
||||||
// - TODO: Make link relative
|
// - TODO: Make link relative
|
||||||
func topBarWebsiteTitle(language: String) -> String {
|
func topBarWebsiteTitle(language: String) -> String {
|
||||||
"/\(language).html"
|
Element.htmlPagePathAddition(for: language)
|
||||||
}
|
}
|
||||||
|
|
||||||
func topBarLanguageButton(_ language: String) -> String {
|
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 {
|
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 {
|
func svgImage(file: String, x: Int, y: Int, width: Int, height: Int) -> String {
|
||||||
"""
|
"""
|
||||||
<span class="image">
|
<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>
|
</span>
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -27,27 +27,49 @@ struct PageContentGenerator {
|
|||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
let linkModifier = Modifier(target: .links) { html, markdown in
|
let linkModifier = Modifier(target: .links) { html, markdown in
|
||||||
let file = markdown.between("(", and: ")")
|
handleLink(page: page, language: language, html: html, markdown: markdown)
|
||||||
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
|
let htmlModifier = Modifier(target: .html) { html, markdown in
|
||||||
//print("[HTML] Found in page \(page.path):")
|
handleHTML(page: page, language: language, html: html, markdown: markdown)
|
||||||
//print(markdown)
|
|
||||||
// Thinks to check
|
|
||||||
// <img src=
|
|
||||||
// <a href=
|
|
||||||
//
|
|
||||||
return html
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let parser = MarkdownParser(modifiers: [imageModifier, codeModifier, linkModifier, htmlModifier])
|
let parser = MarkdownParser(modifiers: [imageModifier, codeModifier, linkModifier, htmlModifier])
|
||||||
return (parser.html(from: content), hasCodeContent)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
// Things to check:
|
||||||
|
// <img src=
|
||||||
|
// <a href=
|
||||||
|
//
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
|
||||||
private func processMarkdownImage(markdown: Substring, html: String, page: Element) -> String {
|
private func processMarkdownImage(markdown: Substring, html: String, page: Element) -> String {
|
||||||
// Split the markdown ![alt](file title)
|
// Split the markdown ![alt](file title)
|
||||||
// For images: ![left_title](file right_title)
|
// For images: ![left_title](file right_title)
|
||||||
@ -127,7 +149,7 @@ struct PageContentGenerator {
|
|||||||
guard let area = area else {
|
guard let area = area else {
|
||||||
return factory.html.svgImage(file: file)
|
return factory.html.svgImage(file: file)
|
||||||
}
|
}
|
||||||
let parts = area.components(separatedBy: ",")
|
let parts = area.components(separatedBy: ",").map { $0.trimmed }
|
||||||
guard parts.count == 4,
|
guard parts.count == 4,
|
||||||
let x = Int(parts[0]),
|
let x = Int(parts[0]),
|
||||||
let y = Int(parts[1]),
|
let y = Int(parts[1]),
|
||||||
|
@ -58,7 +58,7 @@ struct LocalizedSiteTemplate {
|
|||||||
let sections = site.sortedItems.map {
|
let sections = site.sortedItems.map {
|
||||||
PrefilledTopBarTemplate.SectionInfo(
|
PrefilledTopBarTemplate.SectionInfo(
|
||||||
name: $0.title(for: language),
|
name: $0.title(for: language),
|
||||||
url: "\($0.path)/\(language).html")
|
url: $0.path + Element.htmlPagePathAddition(for: language))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.topBar = try .init(
|
self.topBar = try .init(
|
||||||
@ -83,7 +83,7 @@ struct LocalizedSiteTemplate {
|
|||||||
func makeBackLink(text: String, language: String) -> String {
|
func makeBackLink(text: String, language: String) -> String {
|
||||||
let content: [BackNavigationTemplate.Key : String] = [
|
let content: [BackNavigationTemplate.Key : String] = [
|
||||||
.text: text,
|
.text: text,
|
||||||
.url: "../\(language).html"
|
.url: ".." + Element.htmlPagePathAddition(for: language)
|
||||||
]
|
]
|
||||||
return backNavigation.generate(content)
|
return backNavigation.generate(content)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user