Brea/repository/Brea/BreaPage.class.st

263 lines
7.2 KiB
Smalltalk

"
I model a wiki page of a Brea site.
I am modelled after common wiki pages, where a document in a light markup laguage
is converted in HTML and is expected to access document history (I am helped by
FossilRepo for that).
I can be used for other types of publications, like blog post though.
"
Class {
#name : #BreaPage,
#superclass : #Object,
#instVars : [
'shortName',
'template',
'templateData',
'bodyTag',
'splitters',
'subpages',
'metadata',
'folder',
'file'
],
#category : #Brea
}
{ #category : #operation }
BreaPage >> bodyContentsAsHTML [
| sourcePage |
self contentsFile ifNil: [ ^ self ].
Smalltalk os isWindows ifTrue: [
^ Pandoc markdownToHtml: self file file
].
sourcePage := FileLocator temp / 'wikiPage.md'.
MarkupFile exportAsFileOn: sourcePage containing: self contents.
^ Pandoc markdownToHtml: sourcePage
]
{ #category : #accessing }
BreaPage >> bodyTag [
^ bodyTag
]
{ #category : #accessing }
BreaPage >> bodyTag: aString [
"I represent the Mustache Template tag used to denote the body part of a page.
While the metadata is self describing via YAML metadata blocks in Markddown, so
they map where ever they are needed in a template, the Markdown file that will be converted
in HTML via a template doesn't know which part should occupy once the conversion is done.
I provide such knowledge. So if a page template puts the body content under the mustache tag
{{content}}, I should use bodyTag: 'content'.
bodyTag: is template dependant."
bodyTag := aString
]
{ #category : #accessing }
BreaPage >> contents [
| result |
self contentsFile ifNil: [ ^ nil ].
result := '' writeStream.
result nextPutAll: self contentsFile contentString.
self subpages ifNotNil: [
self subpages do: [ :sp | | markdownTempFile |
markdownTempFile := self folder / (sp, '.md').
result nextPutAll: (Markdown fromFile: markdownTempFile) contents.
]
].
^ result contents.
]
{ #category : #operation }
BreaPage >> contentsFile [
self folder ifNil: [ ^ self ].
self shortName ifNil: [ ^ self ].
^ BreaFile fromShortName: self shortName andFolder: self folder.
]
{ #category : #'as yet unclassified' }
BreaPage >> exportAsHTML [
| htmlContents allActions actionsArray semaphore result |
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
actionsArray := { [ self populateMetadata ] future. }.
self splitters ifNotEmpty: [ actionsArray := actionsArray copyWith: [ self split ] future ].
self bodyTag ifNotNil: [
actionsArray := actionsArray copyWith: [ self populateBodyAs: self bodyTag ] future ].
allActions := TKTFuture fromCollectionOfFutures: actionsArray.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal.
].
semaphore wait.
htmlContents := (MustacheTemplate on: result templateFile contents) value: result templateData.
^ MarkupFile exportAsFileOn: self folder / (self shortName, '.html' ) containing: htmlContents
]
{ #category : #accessing }
BreaPage >> file [
(self shortName isNil or: [ self folder isNil ]) ifTrue: [ ^ nil ].
^ file ifNil: [ ^ BreaFile fromShortName: self shortName andFolder: self folder ]
]
{ #category : #accessing }
BreaPage >> file: anObject [
file := anObject
]
{ #category : #accessing }
BreaPage >> folder [
^ folder
]
{ #category : #accessing }
BreaPage >> folder: folderFileReference [
folder := folderFileReference
]
{ #category : #'as yet unclassified' }
BreaPage >> htmlContents [
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ (MustacheTemplate on: self templateFile contents) value: self templateData.
]
{ #category : #accessing }
BreaPage >> metadata [
^ metadata ifNil: [ self contentsFile metadata ]
]
{ #category : #accessing }
BreaPage >> metadata: aDictionary [
"External place where page metadata is located (on Internet or the local file system) in JSON format.
If nil, is suposed that is placed in the Markdown file with the page contents."
metadata := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> populateBodyAs: key [
| allActions result semaphore |
allActions := TKTFuture all: {
[ self bodyContentsAsHTML ] future.
}.
semaphore := Semaphore new.
allActions onSuccessDo: [ :values |
result := values last.
semaphore signal ].
semaphore wait.
self templateData at: key put: result contents.
^ self.
]
{ #category : #'as yet unclassified' }
BreaPage >> populateExternalMetadata [
self metadata ifNil: [ ^ self ].
self
]
{ #category : #operation }
BreaPage >> populateMetadata [
| metadataTemp |
self metadata
ifNotNil: [ metadataTemp := self metadata ]
ifNil: [ metadataTemp := self contentsFile metadata].
metadataTemp keysAndValuesDo: [ :key :value |
self templateData at: key put: value ].
^ templateData
]
{ #category : #operation }
BreaPage >> populateTaggedBody [
self bodyTag ifNil: [ ^ self ].
^ self populateBodyAs: self bodyTag.
]
{ #category : #accessing }
BreaPage >> shortName [
^ shortName
]
{ #category : #accessing }
BreaPage >> shortName: aString [
"The name of the file tha contains the light markup to produce the web page, without file extension.
By default I work with Markdown files."
shortName := aString
]
{ #category : #'as yet unclassified' }
BreaPage >> split [
self splitters ifEmpty: [ ^ self ].
self splitters keysAndValuesDo: [ :key :value | self split: key with: value ].
]
{ #category : #'as yet unclassified' }
BreaPage >> split: key with: subkey [
"I split a comma separated collection of subkeys stored in the 'key' field and name each one as 'subkey'
to put it indiviudally in a Mustache template."
| allSubkeys cleaned data |
allSubkeys := (self populateMetadata at: key) splitOn: ','.
cleaned := allSubkeys collect: [ :item | item withBlanksCondensed ].
data := OrderedCollection new.
cleaned do: [ :item |
data add: { subkey -> item } asDictionary ].
self populateMetadata at: key put: data; yourself.
]
{ #category : #'as yet unclassified' }
BreaPage >> splitterAt: key with: subkey [
self splitters at: key put: subkey
]
{ #category : #accessing }
BreaPage >> splitters [
^ splitters ifNil: [ splitters := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> splitters: aDictionary [
"I model the pattern where a Mustache template contains something like
{{# key}} {{value}} {{/ key}} and has data that needs to be split before injecting it in the template."
splitters := aDictionary
]
{ #category : #accessing }
BreaPage >> subpages [
^ subpages
]
{ #category : #accessing }
BreaPage >> subpages: shortNamesList [
"I am used when a page is composed of other subpages (for example with link aliases) that are shared
accross several pages."
subpages := shortNamesList
]
{ #category : #accessing }
BreaPage >> template [
^ template
]
{ #category : #accessing }
BreaPage >> template: mustacheFileName [
"Usually templates and their pages are located in the same folder."
template := mustacheFileName
]
{ #category : #accessing }
BreaPage >> templateData [
^ templateData ifNil: [ templateData := Dictionary new ]
]
{ #category : #accessing }
BreaPage >> templateData: aDictionary [
templateData := aDictionary
]
{ #category : #'as yet unclassified' }
BreaPage >> templateFile [
self folder ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ self folder / self template
]