135 lines
4.8 KiB
Swift
135 lines
4.8 KiB
Swift
import Foundation
|
|
|
|
final class PostListPageGenerator {
|
|
|
|
let source: PostListPageGeneratorSource
|
|
|
|
init(source: PostListPageGeneratorSource) {
|
|
self.source = source
|
|
}
|
|
|
|
private var language: ContentLanguage {
|
|
source.language
|
|
}
|
|
|
|
private var mainContentMaximumWidth: Int {
|
|
source.content.settings.posts.contentWidth
|
|
}
|
|
|
|
private func pageUrl(in language: ContentLanguage, pageNumber: Int) -> String {
|
|
source.content.settings.general.url + pageUrlWithoutDomain(in: language, pageNumber: pageNumber)
|
|
}
|
|
|
|
private func pageUrlWithoutDomain(in language: ContentLanguage, pageNumber: Int) -> String {
|
|
let base = source.pageUrlPrefix(for: language)
|
|
guard pageNumber > 1 else {
|
|
return base
|
|
}
|
|
return base + "/\(pageNumber)"
|
|
}
|
|
|
|
private func filePath(in language: ContentLanguage, pageNumber: Int) -> String {
|
|
"\(source.pageUrlPrefix(for: language))/\(pageNumber).html"
|
|
}
|
|
|
|
func createPages(for posts: [Post]) {
|
|
// Sort by newest first, filter drafts
|
|
let posts = posts
|
|
.filter { !$0.isDraft }
|
|
.sorted { $0.startDate > $1.startDate && $0.id < $1.id }
|
|
|
|
let totalCount = posts.count
|
|
guard totalCount > 0 else {
|
|
// Create one empty page
|
|
createPostFeedPage(1, pageCount: 1, posts: [])
|
|
return
|
|
}
|
|
let postsPerPage = source.postsPerPage
|
|
|
|
let numberOfPages = (totalCount + postsPerPage - 1) / postsPerPage // Round up
|
|
for pageIndex in 1...numberOfPages {
|
|
let startIndex = (pageIndex - 1) * postsPerPage
|
|
let endIndex = min(pageIndex * postsPerPage, totalCount)
|
|
let postsOnPage = posts[startIndex..<endIndex]
|
|
createPostFeedPage(pageIndex, pageCount: numberOfPages, posts: postsOnPage)
|
|
}
|
|
}
|
|
|
|
private func makePostData(post: Post) -> FeedEntryData {
|
|
let localized: LocalizedPost = post.localized(in: language)
|
|
|
|
let linkUrl: FeedEntryData.Link? = post.linkedPage.map {
|
|
guard !$0.isDraft else { return nil }
|
|
return .init(
|
|
url: $0.absoluteUrl(in: language),
|
|
text: localized.pageLinkText ?? post.content.settings.posts.localized(in: language).defaultPageLinkText)
|
|
}
|
|
|
|
// Use the tags of the page if one is linked
|
|
let tags: [FeedEntryData.Tag] = post.usedTags().filter { $0.isVisible }.map { tag in
|
|
.init(name: tag.localized(in: language).name,
|
|
url: tag.absoluteUrl(in: language))
|
|
}
|
|
|
|
let media: FeedEntryData.Media?
|
|
if localized.hasImages {
|
|
let images = localized.images.map { image in
|
|
image.imageSet(width: mainContentMaximumWidth, height: mainContentMaximumWidth, language: language)
|
|
}
|
|
images.forEach(source.results.require)
|
|
media = .images(images)
|
|
} else if localized.hasVideos {
|
|
media = .video(localized.images)
|
|
localized.images.forEach(source.results.require)
|
|
} else {
|
|
media = nil
|
|
}
|
|
|
|
return FeedEntryData(
|
|
entryId: post.id,
|
|
title: localized.title,
|
|
textAboveTitle: post.dateText(in: language),
|
|
link: linkUrl,
|
|
tags: tags,
|
|
labels: localized.labels,
|
|
text: localized.text.components(separatedBy: "\n\n"),
|
|
media: media)
|
|
#warning("Treat post text as markdown")
|
|
}
|
|
|
|
private func createPostFeedPage(_ pageIndex: Int, pageCount: Int, posts: ArraySlice<Post>) {
|
|
let posts: [FeedEntryData] = posts.map(makePostData)
|
|
|
|
let feedPageGenerator = FeedPageGenerator(content: source.content, results: source.results)
|
|
|
|
// Includes leading slash
|
|
let languageButtonUrl = pageUrlWithoutDomain(in: language.next, pageNumber: pageIndex)
|
|
|
|
// Includes leading slash
|
|
let pageUrl = pageUrl(in: language, pageNumber: pageIndex)
|
|
|
|
let fileContent = feedPageGenerator.generatePage(
|
|
language: language,
|
|
posts: posts,
|
|
title: source.linkTitle,
|
|
description: source.linkDescription,
|
|
image: source.linkImage,
|
|
pageUrl: pageUrl,
|
|
pageTitle: source.pageTitle,
|
|
pageNumber: pageIndex,
|
|
totalPages: pageCount,
|
|
languageButtonUrl: languageButtonUrl,
|
|
linkPrefix: source.pageUrlPrefix(for: language))
|
|
|
|
let filePath = self.filePath(in: language, pageNumber: pageIndex)
|
|
guard save(fileContent, to: filePath) else {
|
|
source.results.unsavedOutput(filePath, source: .feed)
|
|
return
|
|
}
|
|
}
|
|
|
|
private func save(_ content: String, to relativePath: String) -> Bool {
|
|
source.content.storage.write(content, to: relativePath)
|
|
}
|
|
}
|