239 lines
6.0 KiB
Swift
239 lines
6.0 KiB
Swift
import Foundation
|
|
|
|
final class Page: Item, DateItem, LocalizedItem {
|
|
|
|
override var itemType: ItemType { .page }
|
|
|
|
/**
|
|
The external link this page points to.
|
|
|
|
If this value is not `nil`, then the page has no content
|
|
and many other features are disabled.
|
|
*/
|
|
@Published
|
|
var externalLink: String?
|
|
|
|
@Published
|
|
var isDraft: Bool
|
|
|
|
@Published
|
|
var createdDate: Date
|
|
|
|
@Published
|
|
var hideDate: Bool
|
|
|
|
@Published
|
|
var startDate: Date
|
|
|
|
@Published
|
|
var hasEndDate: Bool
|
|
|
|
@Published
|
|
var potentialEndDate: Date
|
|
|
|
@Published
|
|
var german: LocalizedPage
|
|
|
|
@Published
|
|
var english: LocalizedPage
|
|
|
|
@Published
|
|
var tags: [Tag]
|
|
|
|
var savedData: Data?
|
|
|
|
init(content: Content,
|
|
id: String,
|
|
externalLink: String?,
|
|
isDraft: Bool,
|
|
createdDate: Date,
|
|
hideDate: Bool,
|
|
startDate: Date,
|
|
endDate: Date?,
|
|
german: LocalizedPage,
|
|
english: LocalizedPage,
|
|
tags: [Tag]) {
|
|
self.externalLink = externalLink
|
|
self.isDraft = isDraft
|
|
self.createdDate = createdDate
|
|
self.hideDate = hideDate
|
|
self.startDate = startDate
|
|
self.hasEndDate = endDate != nil
|
|
self.potentialEndDate = endDate ?? startDate
|
|
self.german = german
|
|
self.english = english
|
|
self.tags = tags
|
|
|
|
super.init(content: content, id: id)
|
|
}
|
|
|
|
func isValid(id: String) -> Bool {
|
|
!id.isEmpty &&
|
|
content.isValidIdForTagOrPageOrPost(id) &&
|
|
content.isNewIdForPage(id)
|
|
}
|
|
|
|
@discardableResult
|
|
func update(id newId: String) -> Bool {
|
|
guard content.storage.move(page: id, to: newId) else {
|
|
print("Failed to move files of page \(id)")
|
|
return false
|
|
}
|
|
id = newId
|
|
return true
|
|
}
|
|
|
|
var isExternalUrl: Bool {
|
|
externalLink != nil
|
|
}
|
|
|
|
// MARK: Tags
|
|
|
|
/**
|
|
Check if a tag is associated with this page
|
|
*/
|
|
func contains(_ tag: Tag) -> Bool {
|
|
tags.contains(tag)
|
|
}
|
|
|
|
func toggle(_ tag: Tag) {
|
|
guard let index = tags.firstIndex(of: tag) else {
|
|
tags.append(tag)
|
|
return
|
|
}
|
|
tags.remove(at: index)
|
|
}
|
|
|
|
func remove(_ tag: Tag) {
|
|
tags.remove(tag)
|
|
}
|
|
|
|
func associate(_ tag: Tag) {
|
|
guard !tags.contains(tag) else {
|
|
return
|
|
}
|
|
tags.append(tag)
|
|
}
|
|
|
|
// MARK: Paths
|
|
|
|
override func absoluteUrl(in language: ContentLanguage) -> String {
|
|
if let url = externalLink {
|
|
return url
|
|
}
|
|
// TODO: Record link to trace connections between pages
|
|
return makeCleanAbsolutePath(internalPath(for: language))
|
|
}
|
|
|
|
override func title(in language: ContentLanguage) -> String {
|
|
localized(in: language).title
|
|
}
|
|
|
|
func filePathRelativeToOutputFolder(for language: ContentLanguage) -> String {
|
|
makeCleanRelativePath(internalPath(for: language))
|
|
}
|
|
|
|
private func internalPath(for language: ContentLanguage) -> String {
|
|
content.settings.paths.pagesOutputFolderPath + "/" + localized(in: language).urlString
|
|
}
|
|
|
|
override var itemReference: ItemReference {
|
|
.page(self)
|
|
}
|
|
|
|
func contains(urlComponent: String) -> Bool {
|
|
english.urlString == urlComponent || german.urlString == urlComponent
|
|
}
|
|
|
|
func pageContent(in language: ContentLanguage) -> String? {
|
|
content.storage.pageContent(for: id, language: language)
|
|
}
|
|
|
|
func removeContent(in language: ContentLanguage) -> Bool {
|
|
guard content.storage.remove(pageContent: id, in: language) else {
|
|
return false
|
|
}
|
|
localized(in: language).hasContent = false
|
|
return true
|
|
}
|
|
|
|
func save(pageContent: String, in language: ContentLanguage) -> Bool {
|
|
guard content.storage.save(pageContent: pageContent, for: id, in: language) else {
|
|
return false
|
|
}
|
|
localized(in: language).hasContent = true
|
|
return true
|
|
}
|
|
|
|
/**
|
|
Update the `hasContent` property of all localized pages.
|
|
*/
|
|
func updateContentExistence() {
|
|
for language in ContentLanguage.allCases {
|
|
localized(in: language).hasContent = content.storage.hasPageContent(for: id, language: language)
|
|
}
|
|
}
|
|
|
|
/// All languages for which the page has no content
|
|
var missingContentLanguages: [ContentLanguage] {
|
|
ContentLanguage.allCases.filter { !localized(in: $0).hasContent }
|
|
}
|
|
|
|
func remove(_ file: FileResource) {
|
|
english.linkPreview.remove(file)
|
|
german.linkPreview.remove(file)
|
|
}
|
|
}
|
|
|
|
// MARK: Storage
|
|
|
|
extension Page: StorageItem {
|
|
|
|
convenience init(context: LoadingContext, id: String, data: Data) {
|
|
self.init(
|
|
content: context.content,
|
|
id: id,
|
|
externalLink: data.externalLink,
|
|
isDraft: data.isDraft,
|
|
createdDate: data.createdDate,
|
|
hideDate: data.hideDate ?? false,
|
|
startDate: data.startDate,
|
|
endDate: data.endDate,
|
|
german: .init(context: context, data: data.german),
|
|
english: .init(context: context, data: data.english),
|
|
tags: data.tags.compactMap(context.tag))
|
|
savedData = data
|
|
}
|
|
|
|
/// The structure to store the metadata of a page on disk
|
|
struct Data: Codable, Equatable {
|
|
let isDraft: Bool
|
|
let externalLink: String?
|
|
let tags: [String]
|
|
let hideDate: Bool?
|
|
let createdDate: Date
|
|
let startDate: Date
|
|
let endDate: Date?
|
|
let german: LocalizedPage.Data
|
|
let english: LocalizedPage.Data
|
|
}
|
|
|
|
|
|
var data: Data {
|
|
.init(
|
|
isDraft: isDraft,
|
|
externalLink: externalLink,
|
|
tags: tags.map { $0.id },
|
|
hideDate: hideDate ? true : nil,
|
|
createdDate: createdDate,
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
german: german.data,
|
|
english: english.data)
|
|
}
|
|
|
|
func saveToDisk(_ data: Data) -> Bool {
|
|
content.storage.save(page: data, for: id)
|
|
}
|
|
}
|