Improve printing and image creation
This commit is contained in:
@ -4,15 +4,17 @@ struct OverviewPageGenerator {
|
||||
|
||||
private let factory: LocalizedSiteTemplate
|
||||
|
||||
init(factory: LocalizedSiteTemplate) {
|
||||
private let results: GenerationResultsHandler
|
||||
|
||||
init(factory: LocalizedSiteTemplate, results: GenerationResultsHandler) {
|
||||
self.factory = factory
|
||||
self.results = results
|
||||
}
|
||||
|
||||
func generate(
|
||||
section: Element,
|
||||
language: String) {
|
||||
let path = section.localizedPath(for: language)
|
||||
let url = files.urlInOutputFolder(path)
|
||||
|
||||
let metadata = section.localized(for: language)
|
||||
|
||||
@ -26,11 +28,8 @@ struct OverviewPageGenerator {
|
||||
content[.contentClass] = "overview"
|
||||
content[.header] = makeHeader(page: section, metadata: metadata, language: language)
|
||||
content[.content] = makeContent(section: section, language: language)
|
||||
content[.footer] = section.customFooterContent()
|
||||
guard factory.page.generate(content, to: url) else {
|
||||
return
|
||||
}
|
||||
files.generated(page: path)
|
||||
content[.footer] = results.getContentOfOptionalFile(at: section.additionalFooterContentPath, source: section.path)
|
||||
factory.page.generate(content, to: path, source: section.path)
|
||||
}
|
||||
|
||||
private func makeContent(section: Element, language: String) -> String {
|
||||
|
@ -8,10 +8,10 @@ struct OverviewSectionGenerator {
|
||||
|
||||
private let generator: ThumbnailListGenerator
|
||||
|
||||
init(factory: TemplateFactory) {
|
||||
init(factory: TemplateFactory, results: GenerationResultsHandler) {
|
||||
self.multipleSectionsTemplate = factory.overviewSection
|
||||
self.singleSectionsTemplate = factory.overviewSectionClean
|
||||
self.generator = ThumbnailListGenerator(factory: factory)
|
||||
self.generator = ThumbnailListGenerator(factory: factory, results: results)
|
||||
}
|
||||
|
||||
func generate(sections: [Element], in parent: Element, language: String, sectionItemCount: Int) -> String {
|
||||
@ -25,8 +25,13 @@ struct OverviewSectionGenerator {
|
||||
}
|
||||
|
||||
private func newsSectionContent(for element: Element, language: String, sectionItemCount: Int) -> String {
|
||||
let shownElements = element.mostRecentElements(sectionItemCount)
|
||||
// let shownElements = element.mostRecentElements(sectionItemCount)
|
||||
return ""
|
||||
// return generator.generateContent(
|
||||
// items: shownElements,
|
||||
// parent: element,
|
||||
// language: language,
|
||||
// style: element.thumbnailStyle)
|
||||
}
|
||||
|
||||
private func sectionsContent(_ sections: [Element], in parent: Element, language: String, sectionItemCount: Int) -> String {
|
||||
|
@ -10,9 +10,12 @@ struct PageContentGenerator {
|
||||
|
||||
private let siteRoot: Element
|
||||
|
||||
init(factory: TemplateFactory, siteRoot: Element) {
|
||||
private let results: GenerationResultsHandler
|
||||
|
||||
init(factory: TemplateFactory, siteRoot: Element, results: GenerationResultsHandler) {
|
||||
self.factory = factory
|
||||
self.siteRoot = siteRoot
|
||||
self.results = results
|
||||
}
|
||||
|
||||
func generate(page: Element, language: String, content: String) -> (content: String, includesCode: Bool) {
|
||||
@ -44,8 +47,7 @@ struct PageContentGenerator {
|
||||
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)
|
||||
guard let pagePath = results.getPagePath(for: pageId, source: page.path) else {
|
||||
// Remove link since the page can't be found
|
||||
return markdown.between("[", and: "]")
|
||||
}
|
||||
@ -57,13 +59,13 @@ struct PageContentGenerator {
|
||||
|
||||
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)
|
||||
results.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")
|
||||
// TODO: Check HTML code in markdown for required resources
|
||||
//print("[HTML] Found in page \(page.path):")
|
||||
//print(markdown)
|
||||
// Things to check:
|
||||
@ -123,7 +125,7 @@ struct PageContentGenerator {
|
||||
private func handleImage(page: Element, file: String, rightTitle: String?, leftTitle: String?) -> String {
|
||||
let imagePath = page.pathRelativeToRootForContainedInputFile(file)
|
||||
|
||||
let size = files.requireFullSizeMultiVersionImage(
|
||||
let size = results.requireFullSizeMultiVersionImage(
|
||||
source: imagePath,
|
||||
destination: imagePath,
|
||||
requiredBy: page.path)
|
||||
@ -140,28 +142,28 @@ struct PageContentGenerator {
|
||||
|
||||
private func handleVideo(page: Element, file: String, optionString: String?) -> String {
|
||||
let options: [PageVideoTemplate.VideoOption] = optionString.unwrapped { string in
|
||||
string.components(separatedBy: " ").compactMap { optionText in
|
||||
string.components(separatedBy: " ").compactMap { optionText -> PageVideoTemplate.VideoOption? in
|
||||
guard let optionText = optionText.trimmed.nonEmpty else {
|
||||
return nil
|
||||
}
|
||||
guard let option = PageVideoTemplate.VideoOption(rawValue: optionText) else {
|
||||
log.add(warning: "Unknown video option \(optionText)", source: page.path)
|
||||
results.warning("Unknown video option \(optionText)", source: page.path)
|
||||
return nil
|
||||
}
|
||||
return option
|
||||
}
|
||||
} ?? []
|
||||
#warning("Check page folder for alternative video versions")
|
||||
// TODO: Check page folder for alternative video versions
|
||||
let sources: [PageVideoTemplate.VideoSource] = [(url: file, type: .mp4)]
|
||||
|
||||
let filePath = page.pathRelativeToRootForContainedInputFile(file)
|
||||
files.require(file: filePath)
|
||||
results.require(file: filePath, source: page.path)
|
||||
return factory.video.generate(sources: sources, options: options)
|
||||
}
|
||||
|
||||
private func handleSvg(page: Element, file: String, area: String?) -> String {
|
||||
let imagePath = page.pathRelativeToRootForContainedInputFile(file)
|
||||
files.require(file: imagePath)
|
||||
results.require(file: imagePath, source: page.path)
|
||||
|
||||
guard let area = area else {
|
||||
return factory.html.svgImage(file: file)
|
||||
@ -172,7 +174,7 @@ struct PageContentGenerator {
|
||||
let y = Int(parts[1].trimmed),
|
||||
let width = Int(parts[2].trimmed),
|
||||
let height = Int(parts[3].trimmed) else {
|
||||
log.add(warning: "Invalid area string for svg image", source: page.path)
|
||||
results.warning("Invalid area string for svg image", source: page.path)
|
||||
return factory.html.svgImage(file: file)
|
||||
}
|
||||
|
||||
@ -180,7 +182,7 @@ struct PageContentGenerator {
|
||||
}
|
||||
|
||||
private func handleFile(page: Element, file: String, fileExtension: String) -> String {
|
||||
log.add(warning: "Unhandled file \(file) with extension \(fileExtension)", source: page.path)
|
||||
results.warning("Unhandled file \(file) with extension \(fileExtension)", source: page.path)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -190,7 +192,7 @@ struct PageContentGenerator {
|
||||
.compactMap { button -> (file: String, text: String, downloadName: String?)? in
|
||||
let parts = button.components(separatedBy: ",")
|
||||
guard parts.count == 2 || parts.count == 3 else {
|
||||
log.add(warning: "Invalid button definition", source: page.path)
|
||||
results.warning("Invalid button definition", source: page.path)
|
||||
return nil
|
||||
}
|
||||
let file = parts[0].trimmed
|
||||
@ -199,7 +201,7 @@ struct PageContentGenerator {
|
||||
|
||||
// Ensure that file is available
|
||||
let filePath = page.pathRelativeToRootForContainedInputFile(file)
|
||||
files.require(file: filePath)
|
||||
results.require(file: filePath, source: page.path)
|
||||
|
||||
return (file, title, downloadName)
|
||||
}
|
||||
@ -212,7 +214,7 @@ struct PageContentGenerator {
|
||||
.compactMap { button -> (url: String, text: String)? in
|
||||
let parts = button.components(separatedBy: ",")
|
||||
guard parts.count == 2 else {
|
||||
log.add(warning: "Invalid external link definition", source: page.path)
|
||||
results.warning("Invalid external link definition", source: page.path)
|
||||
return nil
|
||||
}
|
||||
let url = parts[0].trimmed
|
||||
@ -224,23 +226,14 @@ struct PageContentGenerator {
|
||||
}
|
||||
|
||||
private func handleExternalHTML(page: Element, file: String) -> String {
|
||||
let url = page.inputFolder.appendingPathComponent(file)
|
||||
guard url.exists else {
|
||||
log.add(error: "File \(file) not found", source: page.path)
|
||||
return ""
|
||||
}
|
||||
do {
|
||||
return try String(contentsOf: url)
|
||||
} catch {
|
||||
log.add(error: "File \(file) could not be read", source: page.path, error: error)
|
||||
return ""
|
||||
}
|
||||
let path = page.pathRelativeToRootForContainedInputFile(file)
|
||||
return results.getContentOfRequiredFile(at: path, source: page.path) ?? ""
|
||||
}
|
||||
|
||||
private func handleSimpleBox(page: Element, content: String) -> String {
|
||||
let parts = content.components(separatedBy: ";")
|
||||
guard parts.count > 1 else {
|
||||
log.add(error: "Invalid box specification", source: page.path)
|
||||
results.warning("Invalid box specification", source: page.path)
|
||||
return ""
|
||||
}
|
||||
let title = parts[0]
|
||||
@ -250,7 +243,8 @@ struct PageContentGenerator {
|
||||
|
||||
private func handlePageLink(page: Element, language: String, pageId: String) -> String {
|
||||
guard let linkedPage = siteRoot.find(pageId) else {
|
||||
log.add(warning: "Page id '\(pageId)' not found", source: page.path)
|
||||
// Checking the page path will add it to the missing pages
|
||||
_ = results.getPagePath(for: pageId, source: page.path)
|
||||
// Remove link since the page can't be found
|
||||
return ""
|
||||
}
|
||||
@ -259,6 +253,7 @@ struct PageContentGenerator {
|
||||
content[.title] = linkedPage.title(for: language)
|
||||
|
||||
let fullThumbnailPath = linkedPage.thumbnailFilePath(for: language).destination
|
||||
// Note: Here we assume that the thumbnail was already used elsewhere, so already generated
|
||||
let relativeImageUrl = page.relativePathToOtherSiteElement(file: fullThumbnailPath)
|
||||
let metadata = linkedPage.localized(for: language)
|
||||
|
||||
|
@ -7,20 +7,24 @@ struct PageGenerator {
|
||||
|
||||
private let contentGenerator: PageContentGenerator
|
||||
|
||||
init(factory: LocalizedSiteTemplate, siteRoot: Element) {
|
||||
private let results: GenerationResultsHandler
|
||||
|
||||
init(factory: LocalizedSiteTemplate, siteRoot: Element, results: GenerationResultsHandler) {
|
||||
self.factory = factory
|
||||
self.contentGenerator = PageContentGenerator(factory: factory.factory, siteRoot: siteRoot)
|
||||
self.results = results
|
||||
self.contentGenerator = PageContentGenerator(factory: factory.factory, siteRoot: siteRoot, results: results)
|
||||
}
|
||||
|
||||
func generate(page: Element, language: String, previousPage: Element?, nextPage: Element?) {
|
||||
guard !page.isExternalPage else {
|
||||
results.didCompletePage()
|
||||
return
|
||||
}
|
||||
let path = page.fullPageUrl(for: language)
|
||||
let inputContentPath = page.path + "/\(language).md"
|
||||
let metadata = page.localized(for: language)
|
||||
let nextLanguage = page.nextLanguage(for: language)
|
||||
let (pageContent, pageIncludesCode, pageIsEmpty) = makeContent(
|
||||
let (pageContent, pageIncludesCode) = makeContent(
|
||||
page: page, metadata: metadata, language: language, path: inputContentPath)
|
||||
|
||||
var content = [PageTemplate.Key : String]()
|
||||
@ -35,23 +39,17 @@ struct PageGenerator {
|
||||
content[.previousPageUrl] = navLink(from: page, to: previousPage, language: language)
|
||||
content[.nextPageLinkText] = nextText(for: nextPage, language: language)
|
||||
content[.nextPageUrl] = navLink(from: page, to: nextPage, language: language)
|
||||
content[.footer] = page.customFooterContent()
|
||||
content[.footer] = results.getContentOfOptionalFile(at: page.additionalFooterContentPath, source: page.path)
|
||||
|
||||
if pageIncludesCode {
|
||||
let highlightCode = factory.factory.html.codeHighlightFooter()
|
||||
content[.footer] = (content[.footer].unwrapped { $0 + "\n" } ?? "") + highlightCode
|
||||
}
|
||||
|
||||
let url = files.urlInOutputFolder(path)
|
||||
if page.state == .draft {
|
||||
files.isDraft(path: page.path)
|
||||
} else if pageIsEmpty, page.state != .hidden {
|
||||
files.isEmpty(page: path)
|
||||
results.markPageAsDraft(page: page.path)
|
||||
}
|
||||
guard factory.page.generate(content, to: url) else {
|
||||
return
|
||||
}
|
||||
files.generated(page: path)
|
||||
factory.page.generate(content, to: path, source: page.path)
|
||||
}
|
||||
|
||||
private func navLink(from element: Element, to destination: Element?, language: String) -> String? {
|
||||
@ -75,14 +73,14 @@ struct PageGenerator {
|
||||
return factory.factory.html.makeNextText(text)
|
||||
}
|
||||
|
||||
private func makeContent(page: Element, metadata: Element.LocalizedMetadata, language: String, path: String) -> (content: String, includesCode: Bool, isEmpty: Bool) {
|
||||
if let raw = files.contentOfMdFile(atPath: path, source: page.path)?.trimmed.nonEmpty {
|
||||
private func makeContent(page: Element, metadata: Element.LocalizedMetadata, language: String, path: String) -> (content: String, includesCode: Bool) {
|
||||
if let raw = results.getContentOfMdFile(at: path, source: page.path)?.trimmed.nonEmpty {
|
||||
let (content, includesCode) = contentGenerator.generate(page: page, language: language, content: raw)
|
||||
return (content, includesCode, false)
|
||||
return (content, includesCode)
|
||||
} else {
|
||||
let (content, includesCode) = contentGenerator.generate(page: page, language: language, content: metadata.placeholderText)
|
||||
let placeholder = factory.factory.makePlaceholder(title: metadata.placeholderTitle, text: content)
|
||||
return (placeholder, includesCode, true)
|
||||
return (placeholder, includesCode)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,16 @@ import Foundation
|
||||
|
||||
struct PageHeadGenerator {
|
||||
|
||||
// TODO: Add to configuration
|
||||
static let linkPreviewDesiredImageWidth = 1600
|
||||
|
||||
let factory: TemplateFactory
|
||||
|
||||
init(factory: TemplateFactory) {
|
||||
private let results: GenerationResultsHandler
|
||||
|
||||
init(factory: TemplateFactory, results: GenerationResultsHandler) {
|
||||
self.factory = factory
|
||||
self.results = results
|
||||
}
|
||||
|
||||
func generate(page: Element, language: String, includesCode: Bool = false) -> String {
|
||||
@ -24,14 +28,14 @@ struct PageHeadGenerator {
|
||||
let linkPreviewImageName = "thumbnail-link.\(image.lastComponentAfter("."))"
|
||||
let sourceImagePath = page.pathRelativeToRootForContainedInputFile(image)
|
||||
let destinationImagePath = page.pathRelativeToRootForContainedInputFile(linkPreviewImageName)
|
||||
files.requireSingleImage(
|
||||
results.requireSingleImage(
|
||||
source: sourceImagePath,
|
||||
destination: destinationImagePath,
|
||||
requiredBy: page.path,
|
||||
width: PageHeadGenerator.linkPreviewDesiredImageWidth)
|
||||
content[.image] = factory.html.linkPreviewImage(file: linkPreviewImageName)
|
||||
}
|
||||
content[.customPageContent] = page.customHeadContent()
|
||||
content[.customPageContent] = results.getContentOfOptionalFile(at: page.additionalHeadContentPath, source: page.path)
|
||||
if includesCode {
|
||||
let scriptPath = "assets/js/highlight.js"
|
||||
let relative = page.relativePathToOtherSiteElement(file: scriptPath)
|
||||
|
@ -6,9 +6,12 @@ struct SiteGenerator {
|
||||
|
||||
let templates: TemplateFactory
|
||||
|
||||
init() throws {
|
||||
let templatesFolder = files.urlInContentFolder("templates")
|
||||
self.templates = try TemplateFactory(templateFolder: templatesFolder)
|
||||
let results: GenerationResultsHandler
|
||||
|
||||
init(results: GenerationResultsHandler) throws {
|
||||
self.results = results
|
||||
let templatesFolder = results.contentFolder.appendingPathComponent("templates")
|
||||
self.templates = try TemplateFactory(templateFolder: templatesFolder, results: results)
|
||||
}
|
||||
|
||||
func generate(site: Element) {
|
||||
@ -22,11 +25,12 @@ struct SiteGenerator {
|
||||
let template = LocalizedSiteTemplate(
|
||||
factory: templates,
|
||||
language: language,
|
||||
site: site)
|
||||
site: site,
|
||||
results: results)
|
||||
|
||||
// Generate sections
|
||||
let overviewGenerator = OverviewPageGenerator(factory: template)
|
||||
let pageGenerator = PageGenerator(factory: template, siteRoot: site)
|
||||
let overviewGenerator = OverviewPageGenerator(factory: template, results: results)
|
||||
let pageGenerator = PageGenerator(factory: template, siteRoot: site, results: results)
|
||||
|
||||
var elementsToProcess: [LinkedElement] = [(nil, site, nil)]
|
||||
while let (previous, element, next) = elementsToProcess.popLast() {
|
||||
@ -34,7 +38,6 @@ struct SiteGenerator {
|
||||
elementsToProcess.append(contentsOf: element.linkedElements)
|
||||
|
||||
processAllFiles(for: element)
|
||||
|
||||
if !element.elements.isEmpty {
|
||||
overviewGenerator.generate(section: element, language: language)
|
||||
} else {
|
||||
@ -48,10 +51,10 @@ struct SiteGenerator {
|
||||
}
|
||||
|
||||
private func processAllFiles(for element: Element) {
|
||||
element.requiredFiles.forEach(files.require)
|
||||
element.externalFiles.forEach(files.exclude)
|
||||
element.externalFiles.forEach { results.exclude(file: $0, source: element.path) }
|
||||
element.requiredFiles.forEach { results.require(file: $0, source: element.path) }
|
||||
element.images.forEach {
|
||||
files.requireSingleImage(
|
||||
results.requireSingleImage(
|
||||
source: $0.sourcePath,
|
||||
destination: $0.destinationPath,
|
||||
requiredBy: element.path,
|
||||
|
@ -4,8 +4,11 @@ struct ThumbnailListGenerator {
|
||||
|
||||
private let factory: TemplateFactory
|
||||
|
||||
init(factory: TemplateFactory) {
|
||||
private let results: GenerationResultsHandler
|
||||
|
||||
init(factory: TemplateFactory, results: GenerationResultsHandler) {
|
||||
self.factory = factory
|
||||
self.results = results
|
||||
}
|
||||
|
||||
func generateContent(items: [Element], parent: Element, language: String, style: ThumbnailStyle) -> String {
|
||||
@ -37,7 +40,7 @@ struct ThumbnailListGenerator {
|
||||
factory.largeThumbnail.makeCorner(text: $0)
|
||||
}
|
||||
|
||||
files.requireMultiVersionImage(
|
||||
results.requireMultiVersionImage(
|
||||
source: thumbnailSourcePath,
|
||||
destination: thumbnailDestNoExtension + ".jpg",
|
||||
requiredBy: item.path,
|
||||
|
Reference in New Issue
Block a user