Compare commits

..

1 Commits

22 changed files with 1148 additions and 1073 deletions

View File

@ -16,27 +16,12 @@ BaselineOfBrea >> baseline: spec [
for: #common
do: [
"Dependencies"
self miniDocs: spec.
spec
baseline: 'TaskIt' with: [ spec repository: 'github://pharo-contributions/taskit:v1.0' ]
"[ spec repository: 'github://noha/taskit:add-all-future' ]"
"Disabling Noha's Fork to make Brea installable.".
baseline: 'NeoJSON' with: [ spec repository: 'github://svenvc/NeoJSON/repository' ];
baseline: 'Mustache' with: [ spec repository: 'github://noha/mustache/repository' ];
baseline: 'TaskIt' with: [ spec repository: 'github://noha/taskit:add-all-future' ].
"Packages"
spec package: 'Brea' with: [ spec requires: #('MiniDocs' 'TaskIt') ].
spec package: 'Brea' with: [ spec requires: #('NeoJSON' 'Mustache' 'TaskIt') ].
]
]
{ #category : #baselines }
BaselineOfBrea >> miniDocs: spec [
| repo |
repo := ExoRepo new
repository: 'https://code.tupale.co/Offray/MiniDocs'.
repo
onConflict: [ :ex | ex useLoaded ];
onUpgrade: [ :ex | ex useLoaded ];
onDowngrade: [ :ex | ex useLoaded ];
onWarningLog;
load.
spec baseline: 'MiniDocs' with: [ spec repository: 'gitlocal://', repo local fullName ]
]

View File

@ -1,21 +0,0 @@
"
A BreaQueryTest is a test class for testing the behavior of BreaQuery
"
Class {
#name : #BreaOperatorTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #tests }
BreaOperatorTest >> testSTONSerialization [
| original store deserialized |
original := BreaOperator new
name: 'plus';
inputs: {'a' -> 3. 'b' -> 4} asDictionary;
codeBlock: [ :x :y | x + y ].
store := STON toString: original.
deserialized := (STONReader on: store readStream) next.
self assert: original execute equals: deserialized execute
]

View File

@ -1,204 +0,0 @@
"
A BreaPageTest is a test class for testing the behavior of BreaPage
"
Class {
#name : #BreaPageTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}
{ #category : #initialization }
BreaPageTest >> createHTMLTemplateFile [
| testFile contents |
testFile := FileLocator temp / 'template.mus.html'.
testFile ensureCreateFile.
contents :=
'<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<h1>{{title}}</h1>
<p>
{{#show}} You should see me. {{/show}}
</p>
<p>
{{#unhide}} You should not see me. {{/unhide}}
</p>
{{{ contents }}}
</body>
</html>'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createJSONFile [
| testFile contents |
testFile := self jsonTestFile.
testFile ensureCreateFile.
contents := '{ "title": "This is a test", "show": true, "unhide": false }'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #initialization }
BreaPageTest >> createMarkdownFile [
| testFile contents |
testFile := self markdownTestFile.
testFile ensureCreateFile.
contents :=
'---
title: This is a test
show: true
unhide: false
---
# Level one header
And paragraph contents with _emphasis_ and **strong emphasis**.'.
MarkupFile exportAsFileOn: testFile containing: contents.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlBodyContents [
^ '<h1 id="level-one-header">Level one header</h1>
<p>And paragraph contents with <em>emphasis</em> and <strong>strong emphasis</strong>.</p>
'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> htmlOutput [
^ '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>This is a test</title>
</head>
<body>
<h1>This is a test</h1>
<p>
You should see me.
</p>
<p>
</p>
', self htmlBodyContents,
'
</body>
</html>'
]
{ #category : #'as yet unclassified' }
BreaPageTest >> jsonTestFile [
^ FileLocator temp / 'test1.json'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> markdownTestFile [
^ FileLocator temp / 'test.md'.
]
{ #category : #'as yet unclassified' }
BreaPageTest >> setUp [
"I create disposable simple files for testing purposes."
super setUp.
self createMarkdownFile.
self createHTMLTemplateFile.
self createJSONFile
]
{ #category : #tests }
BreaPageTest >> testJSONMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testJSONPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test1';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]
{ #category : #tests }
BreaPageTest >> testMarkdownContentExtraction [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page contents equals: self markdownTestFile contents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownHTMLExport [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
template: 'template.mus.html';
bodyTag: 'contents'.
self assert: (page exportAsHTML contents) equals: self htmlOutput.
]
{ #category : #tests }
BreaPageTest >> testMarkdownMetadataExtraction [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
self assert: page metadata equals: testMetadata
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateBody [
| page |
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp;
bodyTag: 'contents'.
page populateTaggedBody.
self assert: (page templateData at: 'contents') equals: self htmlBodyContents.
]
{ #category : #tests }
BreaPageTest >> testMarkdownPopulateMetadata [
| page testMetadata |
testMetadata := {'title' -> 'This is a test' . 'show' -> true. 'unhide' -> false} asDictionary.
page := BreaPage new.
page
shortName: 'test';
folder: FileLocator temp.
page templateData at: 'extra' put: 'value'.
self assert: page populateMetadata equals: (testMetadata at: 'extra' put: 'value'; yourself)
]

View File

@ -1 +0,0 @@
Package { #name : #'Brea-Tests' }

View File

@ -1,20 +0,0 @@
Extension { #name : #BlockClosure }
{ #category : #'*Brea' }
BlockClosure class >> fromSton: stonReader [
^ self compilerClass new
source: stonReader parseListSingleton;
evaluate
]
{ #category : #'*Brea' }
BlockClosure >> stonContainSubObjects [
^ false
]
{ #category : #'*Brea' }
BlockClosure >> stonOn: stonWriter [
self isClean
ifTrue: [ stonWriter writeObject: self listSingleton: self printString ]
ifFalse: [ stonWriter error: 'Only clean block can be serialized' ]
]

View File

@ -1,104 +0,0 @@
Class {
#name : #BreaApp,
#superclass : #Object,
#instVars : [
'name',
'folder',
'host',
'componets'
],
#category : #Brea
}
{ #category : #accessing }
BreaApp >> add: anObject [
anObject class = String ifFalse: [ ].
self body
nextPutAll: (Pandoc htmlStringToMarkdown: anObject); cr.
]
{ #category : #accessing }
BreaApp >> appName [
^ self name asCamelCase
]
{ #category : #accessing }
BreaApp >> at: key put: anObject [
self components at: key put: anObject.
]
{ #category : #accessing }
BreaApp >> components [
^ componets ifNil: [ componets := OrderedDictionary new]
]
{ #category : #accessing }
BreaApp >> componentsWebView [
| response |
response := '' writeStream.
self components ifEmpty: [ ^ response contents ].
self components valuesDo: [ :component |
response
nextPutAll: component webView; cr
].
^ response contents
]
{ #category : #accessing }
BreaApp >> defaultView [
^ '<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark" />
<link rel="stylesheet" href="css/pico.min.css">
<title>', self name, '</title>
</head>
<body>
<main class="container">
', self componentsWebView,'
</main>
</body>
</html>'
]
{ #category : #accessing }
BreaApp >> folder [
^ folder
]
{ #category : #accessing }
BreaApp >> folder: aFileDirectory [
folder := aFileDirectory
]
{ #category : #accessing }
BreaApp >> name [
^ name
]
{ #category : #accessing }
BreaApp >> name: aString [
name := aString
]
{ #category : #accessing }
BreaApp >> parentFolder: anObject [
self folder: anObject / self name asCamelCase
]
{ #category : #accessing }
BreaApp >> preview [
| defaultRoute |
defaultRoute := 'http://localhost:',self webHost server port asString, '/', self appName.
self webHost
GET: self appName -> [ self defaultView ].
GoogleChrome openWindowOn: defaultRoute
]
{ #category : #accessing }
BreaApp >> webHost [
^ host ifNil: [ host := Teapot allInstances detect: [ :each | each server isRunning ] ifNone: [ host := Teapot on. host server start ]]
]

View File

@ -0,0 +1,31 @@
Class {
#name : #BreaDataSource,
#superclass : #Object,
#instVars : [
'source',
'queries'
],
#category : #Brea
}
{ #category : #accessing }
BreaDataSource >> queries [
^ queries
]
{ #category : #accessing }
BreaDataSource >> queries: anObject [
queries := anObject
]
{ #category : #accessing }
BreaDataSource >> source [
^ source
]
{ #category : #accessing }
BreaDataSource >> source: aDictionary [
"Key, value pair in aDictionary contain a short name and a url pointing to a local or a remote
resource. If is local a FileLocator should be provided."
source := aDictionary
]

View File

@ -1,78 +0,0 @@
"
I model the file where contents (data and/or metadata) for the Brea CSM pages are stored.
"
Class {
#name : #BreaFile,
#superclass : #Object,
#instVars : [
'folder',
'name'
],
#category : #Brea
}
{ #category : #'instance creation' }
BreaFile class >> fromShortName: nameString andFolder: aFileLocation [
"I create a new BreaFile assigning priorities to the filename discovery according to
their extension currently present in a particular folder."
| extensions |
extensions := #('md' 'json' 'yaml').
extensions do: [ :ext | | markupFile filename |
filename := nameString, '.', ext.
markupFile := aFileLocation / filename.
markupFile exists ifTrue: [ ^ self new name: filename; folder: aFileLocation ].
].
^ nil.
]
{ #category : #accessing }
BreaFile >> contentString [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents contents ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asString ].
]
{ #category : #accessing }
BreaFile >> contents [
| file |
self name ifNil: [ ^ nil ].
file := self folder / self name.
(self name endsWith: '.md') ifTrue: [ ^ Markdown fromFile: file ].
(self name endsWith: '.json') ifTrue: [ ^ NeoJSONObject fromString: file contents ]
]
{ #category : #accessing }
BreaFile >> file [
self folder ifNil: [ ^ self ].
self name ifNil: [ ^ self ].
^ self folder / self name.
]
{ #category : #accessing }
BreaFile >> folder [
^ folder
]
{ #category : #accessing }
BreaFile >> folder: anObject [
folder := anObject
]
{ #category : #accessing }
BreaFile >> metadata [
self name ifNil: [ ^ nil ].
(self name endsWith: '.md') ifTrue: [ ^ self contents metadata ].
(self name endsWith: '.json') ifTrue: [ ^ self contents asDictionary ].
]
{ #category : #accessing }
BreaFile >> name [
^ name
]
{ #category : #accessing }
BreaFile >> name: anObject [
name := anObject
]

View File

@ -0,0 +1,489 @@
"
I model a member of a Brea site, usually a human.
"
Class {
#name : #BreaMember,
#superclass : #Object,
#instVars : [
'givenName',
'familyName',
'picture',
'country',
'tags',
'email',
'password',
'webPresence',
'organizations'
],
#category : #Brea
}
{ #category : #converting }
BreaMember >> asStonModified [
"asSton is generated a core dumped now. This renaming is trying to solve that. Maybe
in the offical release it will be solved"
^ STON toStringPretty: self
]
{ #category : #accessing }
BreaMember >> country [
^ country
]
{ #category : #accessing }
BreaMember >> country: anObject [
country := anObject
]
{ #category : #public }
BreaMember >> countryTemplate [
^ '{{#country}}
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Country</b></td>
<td class="mdl-data-table__cell--non-numeric">{{.}}</td>
</tr>
{{/country}}' asMustacheTemplate value: self
]
{ #category : #helpers }
BreaMember >> createTestUser [
^ self class new
givenName: 'Test';
familyName: 'User';
country: 'Neverland';
memberOf: 'HackBo' withWebsite: 'http://hackbo.co/';
memberOf: 'mutabiT' withWebsite: 'http://mutabit.com/';
website: 'http://test.user';
twitter: '@offrayLC';
email: 'iam@test.user';
tags: 'just, a lot, of words, separated, by commas'.
]
{ #category : #accessing }
BreaMember >> email [
^ email
]
{ #category : #accessing }
BreaMember >> email: anEmailAddress [
email := (SHA1 new hashMessage: anEmailAddress) hex
]
{ #category : #accessing }
BreaMember >> facebook [
^ self webPresence facebook.
]
{ #category : #accessing }
BreaMember >> facebook: aProfileName [
aProfileName = ''
ifTrue: [ self webPresence facebook: nil ]
ifFalse: [ self webPresence facebook: aProfileName ]
]
{ #category : #public }
BreaMember >> facebookTemplate [
^ '{{#facebook}}
<tr>
<td class="mdl-data-table__cell--non-numeric">
<b>Facebook</b></td>
<td class="mdl-data-table__cell--non-numeric">
<a href="https://facebook.com/{{.}}">
{{.}}</a></td>
</tr>
{{/facebook}}' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> familyName [
^ familyName
]
{ #category : #accessing }
BreaMember >> familyName: anObject [
familyName := anObject
]
{ #category : #helpers }
BreaMember >> fullName [
^ self givenName asLowercase, '-', self familyName asLowercase
]
{ #category : #accessing }
BreaMember >> getGenericProfilePicture [
"Other considered avatars where:
'https://upload.wikimedia.org/wikipedia/commons/1/1e/Default-avatar.jpg'"
self picture: 'https://www.jamf.com/jamf-nation/img/default-avatars/generic-user.png'.
^ picture
]
{ #category : #accessing }
BreaMember >> givenName [
^ givenName
]
{ #category : #accessing }
BreaMember >> givenName: anObject [
givenName := anObject
]
{ #category : #public }
BreaMember >> head [
^ '<head>', self headMeta, self headTitle, self headStyles,'</head>'
]
{ #category : #utility }
BreaMember >> headMeta [
^ '<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="A portfolio template that uses Material Design Lite.">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">'
]
{ #category : #utility }
BreaMember >> headStyles [
^ '
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.grey-pink.min.css" />
<link rel="stylesheet" href="http://mutabit.com/repos.fossil/gig/doc/tip/styles.css" />
<link rel="stylesheet" href="styles.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
'
]
{ #category : #utility }
BreaMember >> headTitle [
^ self headTitled: 'GIG: Network'
]
{ #category : #utility }
BreaMember >> headTitled: aString [
^ '<title>', aString ,'</title>'
]
{ #category : #public }
BreaMember >> html [
"I show the member profile as HTML"
^ self head, self htmlOutput
]
{ #category : #public }
BreaMember >> htmlInput [
"I capture data in a HTML Form and use it to create a new BreaMember"
^ '
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="A portfolio template that uses Material Design Lite.">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Add Member | GIG Network</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.grey-pink.min.css" />
<link rel="stylesheet" href="styles.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
</head>
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<div class="mdl-layout__drawer mdl-layout--small-screen-only">
<nav class="mdl-navigation mdl-typography--body-1-force-preferred-font">
<a class="mdl-navigation__link is-active" href="index.html">Portfolio</a>
<a class="mdl-navigation__link" href="blog.html">Blog</a>
<a class="mdl-navigation__link" href="about.html">About</a>
<a class="mdl-navigation__link" href="contact.html">Contact</a>
</nav>
</div>
<main class="mdl-layout__content">
<div class="mdl-grid portfolio-max-width portfolio-contact">
<div class="mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">Add new member</h2>
</div>
<div class="mdl-card__supporting-text">
<p>
Fill out the form.
The fields preceded by [*] are obligatory.
</p>
<form enctype="application/x-www-form-urlencoded" action="summit" method="POST" class="">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="givenName">
<label class="mdl-textfield__label" for="givenName">[*]Given Name...</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="familyName">
<label class="mdl-textfield__label" for="familyName">[*]Family Name...</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="email">
<label class="mdl-textfield__label" for="email">[*]Email...</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="country">
<label class="mdl-textfield__label" for="country">[*]Country...</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" pattern="[A-Z,a-z, ]*" type="text" name="organizations">
<label class="mdl-textfield__label" for="organizations">
[*]Organization(s) (separated with commas)</label>
<span class="mdl-textfield__error">Letters and spaces only</span>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="picture">
<label class="mdl-textfield__label" for="website">Profile picture url...</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="website">
<label class="mdl-textfield__label" for="website">Personal website...</label>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="twitter">
<label class="mdl-textfield__label" for="twitter">Twitter...</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" name="facebook">
<label class="mdl-textfield__label" for="facebook">Facebook...</label>
</div><br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<textarea class="mdl-textfield__input" type="text" rows="5" name="tags"></textarea>
<label class="mdl-textfield__label" for="tags">Tags (separated with commas)...</label>
</div>
<p>
<button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect
mdl-button--accent" type="submit" value="Submit">
Submit
</button>
</p>
</form>
</div>
</div>
</div>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer__left-section">
<div class="mdl-logo">Simple portfolio website</div>
</div>
<div class="mdl-mini-footer__right-section">
<ul class="mdl-mini-footer__link-list">
<li><a href="#">Help</a></li>
<li><a href="#">Privacy & Terms</a></li>
</ul>
</div>
</footer>
</main>
</div>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
</body>
</html>
'
]
{ #category : #public }
BreaMember >> htmlOutput [
^ self htmlOutputTemplate asMustacheTemplate value: self
]
{ #category : #public }
BreaMember >> htmlOutputTemplate [
"I show the member profile as HTML"
^ '<div class="mdl-grid portfolio-max-width">
<div class="mdl-cell mdl-card mdl-shadow--4dp portfolio-card">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">{{givenName}} {{familyName}}</h2>
</div>
<div class="mdl-card__media">
<img class="article-image"
src="{{picture}}"
border="0" alt="">
</div>
<div class="mdl-card__supporting-text">
<table class="mdl-data-table mdl-js-data-table">
<tbody>
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Name</b></td>
<td class="mdl-data-table__cell--non-numeric">{{givenName}} {{familyName}}</td>
</tr>',
self countryTemplate,
self organizationsTemplate,
self websiteTemplate,
self twitterTemplate,
self facebookTemplate,
self tagsTemplate,
'
</tbody>
</table>
</div>
<div class="mdl-card__actions mdl-card--border">
<a class="mdl-button mdl-button--colored mdl-js-button
mdl-js-ripple-effect mdl-button--accent"
href="portfolio-example01.html">Read more</a>
</div>
</div>
</div>
'
]
{ #category : #accessing }
BreaMember >> instagram [
^ self webPresence instagram.
]
{ #category : #accessing }
BreaMember >> instagram: aProfileName [
self webPresence instagram: aProfileName
]
{ #category : #accessing }
BreaMember >> memberOf: anOrgName [
self organizations add:
(BreaOrganization new name: anOrgName)
]
{ #category : #accessing }
BreaMember >> memberOf: anOrgName withWebsite: aUrl [
self organizations add:
(BreaOrganization new
name: anOrgName;
website: aUrl)
]
{ #category : #accessing }
BreaMember >> organizations [
^ organizations ifNil: [ organizations := OrderedCollection new ]
]
{ #category : #accessing }
BreaMember >> organizations: anOrgListOrName [
anOrgListOrName splitOn: ',' do: [ :each | self memberOf: each ]
]
{ #category : #public }
BreaMember >> organizationsTemplate [
^ '
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Organization(s)</b></td>
<td class="mdl-data-table__cell--non-numeric">
{{#organizations}}
<a href="{{website}}">{{name}}</a>
{{/organizations}}
</td>
</tr>' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> password [
^ password
]
{ #category : #accessing }
BreaMember >> password: anObject [
password := anObject
]
{ #category : #accessing }
BreaMember >> picture [
^ picture ifNil: [ ^ self getGenericProfilePicture ]
]
{ #category : #accessing }
BreaMember >> picture: anImageFilePath [
picture := anImageFilePath
]
{ #category : #helpers }
BreaMember >> renderTestUserAsHtml [
^ self class new createTestUser html
]
{ #category : #'server handling' }
BreaMember >> storeInto: aFileDirectory [
| folder file |
folder := (aFileDirectory asFileReference / self fullName) ensureCreateDirectory.
file := (folder / 'info.ston') ensureCreateFile.
file writeStreamDo: [:stream |
(STON writer on: stream)
newLine: String crlf;
prettyPrint: true;
nextPut: self]
]
{ #category : #accessing }
BreaMember >> tags [
^ tags
]
{ #category : #accessing }
BreaMember >> tags: anObject [
tags := anObject
]
{ #category : #public }
BreaMember >> tagsTemplate [
^ '{{#tags}}
<tr>
<td colspan="2"; style="text-align:left">
<b>Tags</b><br>
{{.}}
</td>
</tr>
{{/tags}}' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> twitter [
^ self webPresence twitter.
]
{ #category : #accessing }
BreaMember >> twitter: aProfileName [
aProfileName = ''
ifTrue: [ self webPresence twitter: nil ]
ifFalse: [ self webPresence twitter: aProfileName ]
]
{ #category : #public }
BreaMember >> twitterTemplate [
^ '{{#twitter}}
<tr>
<td class="mdl-data-table__cell--non-numeric">
<b>Twitter</b></td>
<td class="mdl-data-table__cell--non-numeric">
<a href="https://twitter.com/{{.}}">
{{.}}</a></td>
</tr>
{{/twitter}}' asMustacheTemplate value: self
]
{ #category : #accessing }
BreaMember >> webPresence [
^ webPresence ifNil: [ webPresence := BreaWebPresence new ]
]
{ #category : #accessing }
BreaMember >> webPresence: anObject [
webPresence := anObject
]
{ #category : #accessing }
BreaMember >> website [
^ self webPresence website.
]
{ #category : #accessing }
BreaMember >> website: anUrl [
self webPresence website: anUrl
]
{ #category : #public }
BreaMember >> websiteTemplate [
^ '{{#website}}
<tr>
<td class="mdl-data-table__cell--non-numeric"><b>Website</b></td>
<td class="mdl-data-table__cell--non-numeric">
<a href="{{.}}">{{.}}</a>
</td>
{{/website}}' asMustacheTemplate value: self
]

View File

@ -0,0 +1,8 @@
"
A BreaMemberTest is a test class for testing the behavior of BreaMember
"
Class {
#name : #BreaMemberTest,
#superclass : #TestCase,
#category : #'Brea-Tests'
}

View File

@ -1,95 +0,0 @@
"
I represent a operation that can be done on data inputs to produce and output by executing
a code block.
I can be used by BreaThemes to produce outpus reflected in a particular set of theme pages.
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
codeBlock: <Object>
inputs: <Object>
name: <Object>
Implementation Points
"
Class {
#name : #BreaOperator,
#superclass : #Object,
#instVars : [
'name',
'inputs',
'codeBlock',
'cleanedInputs'
],
#category : #Brea
}
{ #category : #converting }
BreaOperator >> asSton [
^ STON toStringPretty: self
]
{ #category : #converting }
BreaOperator >> cleanInputs [
self cleanedInputs ifNil: [ ^ self ].
self cleanedInputs ifTrue: [
self inputs keysAndValuesDo: [ :k :v | | currentValue |
currentValue := self inputs at: k.
self inputs at: k put: currentValue class new
]
].
]
{ #category : #accessing }
BreaOperator >> cleanedInputs [
^ cleanedInputs
]
{ #category : #accessing }
BreaOperator >> cleanedInputs: aBoolean [
"I tell if the inputs should be cleaned when the query is serialized as STON, for
example when they contain sensible information, like API keys or passwords"
cleanedInputs := aBoolean
]
{ #category : #accessing }
BreaOperator >> codeBlock [
^ codeBlock
]
{ #category : #accessing }
BreaOperator >> codeBlock: anObject [
codeBlock := anObject
]
{ #category : #execution }
BreaOperator >> execute [
^ self codeBlock valueWithArguments: self inputs values.
]
{ #category : #accessing }
BreaOperator >> inputs [
^ inputs
]
{ #category : #accessing }
BreaOperator >> inputs: anOrderedDictionary [
inputs := anOrderedDictionary
]
{ #category : #accessing }
BreaOperator >> name [
^ name
]
{ #category : #accessing }
BreaOperator >> name: anObject [
name := anObject
]

View File

@ -0,0 +1,32 @@
"
I store the places a BreaMember is affiliated to.
"
Class {
#name : #BreaOrganization,
#superclass : #Object,
#instVars : [
'name',
'website'
],
#category : #Brea
}
{ #category : #accessing }
BreaOrganization >> name [
^ name
]
{ #category : #accessing }
BreaOrganization >> name: anObject [
name := anObject
]
{ #category : #accessing }
BreaOrganization >> website [
^ website
]
{ #category : #accessing }
BreaOrganization >> website: anObject [
website := anObject
]

View File

@ -1,255 +0,0 @@
"
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 commandParameters |
self contentsFile ifNil: [ ^ self ].
sourcePage := self file file.
Smalltalk os isWindows ifTrue: [
^ Pandoc markdownToHtml: sourcePage
].
commandParameters := ' -f markdown+startnum+task_lists -t html '.
^ GtSubprocessWithInMemoryOutput new
shellCommand: 'pandoc', commandParameters, sourcePage fullName;
runAndWait;
stdout.
]
{ #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 withInternetLineEndings.
]
{ #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 [
self templateData at: key put: self bodyContentsAsHTML.
^ 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 ].
^ self 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
]

View File

@ -0,0 +1,89 @@
"
I define a [Mustache][1] template and how it is used to create
derivate output files combining it with particular data sources.
[1]: https://mustache.github.io/
"
Class {
#name : #BreaTemplate,
#superclass : #Object,
#instVars : [
'template',
'data',
'location',
'queries',
'outputs'
],
#category : #Brea
}
{ #category : #adding }
BreaTemplate >> addDataSourceNamed: name with: source [
self
data at: name put: source.
self data.
]
{ #category : #accessing }
BreaTemplate >> data [
^ data ifNil: [ data := Dictionary new ]
]
{ #category : #accessing }
BreaTemplate >> data: aDictionary [
"Each item in the dictionary is a unique alias (as key) and a data location (as value),
usually on the web.
Alias and locations are used later to define data queries to feed into templates."
data := aDictionary
]
{ #category : #accessing }
BreaTemplate >> location [
^ location
]
{ #category : #accessing }
BreaTemplate >> location: aFolderPath [
"This is the place where a template and its derivate files are located.
A shared location is an easy approach to start with and creates more explicit
relation between derived files and templates.
Eventually some re-mapping or re-routing could be used so templates and their outputs
could be further apart."
location := aFolderPath
]
{ #category : #accessing }
BreaTemplate >> outputs [
^ outputs
]
{ #category : #accessing }
BreaTemplate >> outputs: fileNamesList [
"fileNamesList contain the files which are derived from the template."
outputs := fileNamesList
]
{ #category : #accessing }
BreaTemplate >> queries [
^ queries ifNil: [ queries := Dictionary new ]
]
{ #category : #accessing }
BreaTemplate >> queries: aDictionary [
"aDictionary contains the alias for the query as key and a block that will be executed
on a particular data source, as value."
queries := aDictionary
]
{ #category : #accessing }
BreaTemplate >> template [
^ template
]
{ #category : #accessing }
BreaTemplate >> template: aFileName [
"I provide the name of the mustache base template.
The file can have any name, but by convention they end in '.mus.html' 'mus.md' and
so on."
template := aFileName
]

View File

@ -1,229 +0,0 @@
"
I model a web theme.
For the Collaborators Part: State my main collaborators and one line about how I interact with them.
Public API and Key Messages
- message one
- message two
- (for bonus points) how to create instances.
One simple example is simply gorgeous.
Internal Representation and Key Implementation Points.
Instance Variables
name: <Object>
preview: <Object>
provider: <Object>
url: <Object>
Implementation Points
"
Class {
#name : #BreaTheme,
#superclass : #Object,
#instVars : [
'name',
'folder',
'provider',
'url',
'preview',
'license',
'operators'
],
#category : #Brea
}
{ #category : #accessing }
BreaTheme class >> availablePacks [
^ self downloadLinks keys
]
{ #category : #utilities }
BreaTheme class >> downloadLinks [
"Keys are the theme names and values are the url where it can be downloaded
as a zip file.
For the moment we work only with HTML5Up themes, but more could be added
and the code should be refactored accordingly."
| result providerUrl |
result := Dictionary new.
providerUrl := 'https://html5up.net'.
result
at: 'Paradigm Shift' put: providerUrl, '/paradigm-shift/download';
at: 'Massively' put: providerUrl, '/massively/download';
at: 'Ethereal' put: providerUrl, '/ethereal/download';
at: 'Story' put: providerUrl, '/story/download';
at: 'Dimension' put: providerUrl, '/dimension/download';
at: 'Editorial' put: providerUrl, '/editorial/download';
at: 'Forty' put: providerUrl, '/forty/download';
at: 'Stellar' put: providerUrl, '/stellar/download';
at: 'Multiverse' put: providerUrl, '/multiverse/download';
at: 'Phantom' put: providerUrl, '/phantom/download';
at: 'Hyperspace' put: providerUrl, '/hyperspace/download';
at: 'Future Imperfect' put: providerUrl, '/future-imperfect/download';
at: 'Solid State' put: providerUrl, '/solid-state/download';
at: 'Identity' put: providerUrl, '/identity/download';
at: 'Lens' put: providerUrl, '/lens/download';
at: 'Fractal' put: providerUrl, '/fractal/download';
at: 'Eventually' put: providerUrl, '/eventually/download';
at: 'Spectral' put: providerUrl, '/spectral/download';
at: 'Phonon' put: providerUrl, '/photon/download';
at: 'Highlights' put: providerUrl, '/highlights/download';
at: 'Landed' put: providerUrl, '/landed/download';
at: 'Strata' put: providerUrl, '/strata/download';
at: 'Read Only' put: providerUrl, '/read-only/download';
at: 'Alpha' put: providerUrl, '/alpha/download';
at: 'Directive' put: providerUrl, '/directive/download';
at: 'Aerial' put: providerUrl, '/aerial/download';
at: 'Twenty' put: providerUrl, '/twenty/download';
at: 'Big Picture' put: providerUrl, '/big-picture/download';
at: 'Tessellate' put: providerUrl, '/tessellate/download';
at: 'Overflow' put: providerUrl, 'overflow/download';
at: 'Prologue' put: providerUrl, '/prologue/download';
at: 'Helios' put: providerUrl, '/helios/download';
at: 'Telephasic' put: providerUrl, '/telephasic/download';
at: 'Strongly Typed' put: providerUrl, '/strongly-typed/download';
at: 'Parallelism' put: providerUrl, '/parallelism/download';
at: 'Escape Velocity' put: providerUrl, '/escape-velocity/download';
at: 'Astral' put: providerUrl, '/astral/download';
at: 'Striped' put: providerUrl, '/striped/download';
at: 'Dopetrope' put: providerUrl, '/dopetrope/download';
at: 'Miniport' put: providerUrl, '/miniport/download';
at: 'TXT' put: providerUrl, '/txt/download';
at: 'Verti' put: providerUrl, '/verti/download';
at: 'Zerofour' put: providerUrl, '/zerofour/download';
at: 'Arcana' put: providerUrl, '/arcana/download';
at: 'Halcyonic' put: providerUrl, '/halcyonic/download';
at: 'Minimaxing' put: providerUrl, '/minimaxing/download'.
^ result
]
{ #category : #operation }
BreaTheme >> addOperator: aBreaQuery [
self operators add: aBreaQuery cleanInputs
]
{ #category : #operation }
BreaTheme >> asSton [
^ STON toStringPretty: self
]
{ #category : #utilities }
BreaTheme >> dashedName [
^ self name asDashedLowercase
]
{ #category : #operation }
BreaTheme >> downloadInto: aFolder [
| tempName zippedFile |
self url ifNil: [ ^ self ].
tempName := self name.
zippedFile := aFolder / self dashedName , 'zip'.
aFolder ensureCreateDirectory.
GrafoscopioUtils
downloadingFrom: self url withMessage: 'Downloading ', tempName, '...' into: zippedFile.
self folder: aFolder.
^ zippedFile
]
{ #category : #accessing }
BreaTheme >> folder [
^ folder
]
{ #category : #accessing }
BreaTheme >> folder: anObject [
folder := anObject
]
{ #category : #installation }
BreaTheme >> installInto: aFolder [
| zippedFile |
self url ifNil: [ ^ self ].
zippedFile := FileLocator temp / 'download'.
zippedFile ensureDelete.
ZnClient new
url: self url;
downloadTo: FileLocator temp.
(ZipArchive new readFrom: zippedFile) extractAllTo: aFolder.
self folder: aFolder.
^ aFolder
]
{ #category : #accessing }
BreaTheme >> license [
^ license
]
{ #category : #accessing }
BreaTheme >> license: anObject [
license := anObject
]
{ #category : #operation }
BreaTheme >> loadConfiguration [
| config |
config := self folder / 'brea.yaml'.
config exists
ifTrue: [ ^ PPYAMLGrammar new parse: config contents ]
ifFalse: [ self inform:
'No configuration file found. A "brea.yaml" file should be located in the theme root folder.
please run "#updateCustomizations" after defining a theme name from the
"BreaTheme availablePacks".
If no configuration is defined for such theme name you can create and empty configuration
file by running "#createBaseConfiguration" and filing out the "brea.yaml" fields.
For more information or help ask at https://t.me/grafoscopio .' ]
]
{ #category : #accessing }
BreaTheme >> name [
^ name ifNil: [ name = 'unamed' ]
]
{ #category : #accessing }
BreaTheme >> name: anObject [
name := anObject
]
{ #category : #accessing }
BreaTheme >> operators [
^ operators ifNil: [ operators := OrderedCollection new ]
]
{ #category : #accessing }
BreaTheme >> operators: cleanedBreaQueriesCollection [
operators := cleanedBreaQueriesCollection
]
{ #category : #accessing }
BreaTheme >> preview [
^ preview
]
{ #category : #accessing }
BreaTheme >> preview: anObject [
preview := anObject
]
{ #category : #accessing }
BreaTheme >> provider [
^ provider
]
{ #category : #accessing }
BreaTheme >> provider: anObject [
provider := anObject
]
{ #category : #accessing }
BreaTheme >> url [
^ url ifNil: [ url := self class downloadLinks at: self name. ]
]
{ #category : #accessing }
BreaTheme >> url: anObject [
url := anObject
]

View File

@ -1,22 +0,0 @@
"
I provide common utilities for the use with the Brea CMS.
"
Class {
#name : #BreaUtils,
#superclass : #Object,
#category : #Brea
}
{ #category : #'as yet unclassified' }
BreaUtils class >> installSkeleton [
"I populate the folder and files structures for Brea documentation and customizations."
| skeleton destination |
GrafoscopioUtils
downloadingFrom: 'https://mutabit.com/repos.fossil/brea/zip'
withMessage: 'Dowloading files skeleton'
into: FileLocator temp.
skeleton := ZipArchive new readFrom: FileLocator temp / 'zip'.
destination := FileLocator home / '.local/share/Brea'.
destination ensureCreateDirectory.
skeleton extractAllTo: destination.
]

View File

@ -0,0 +1,54 @@
"
I store the common forms of web presence a BreaMember can have online.
"
Class {
#name : #BreaWebPresence,
#superclass : #Object,
#instVars : [
'website',
'twitter',
'facebook',
'instagram'
],
#category : #Brea
}
{ #category : #accessing }
BreaWebPresence >> facebook [
^ facebook
]
{ #category : #accessing }
BreaWebPresence >> facebook: anObject [
facebook := anObject
]
{ #category : #accessing }
BreaWebPresence >> instagram [
^ instagram
]
{ #category : #accessing }
BreaWebPresence >> instagram: anObject [
instagram := anObject
]
{ #category : #accessing }
BreaWebPresence >> twitter [
^ twitter
]
{ #category : #accessing }
BreaWebPresence >> twitter: anObject [
twitter := anObject
]
{ #category : #accessing }
BreaWebPresence >> website [
^ website
]
{ #category : #accessing }
BreaWebPresence >> website: anObject [
website := anObject
]

View File

@ -0,0 +1,292 @@
"
I model the fossil repository where public data is stored for the
building of this web site.
"
Class {
#name : #BreaWebsite,
#superclass : #Object,
#instVars : [
'fossilRepo',
'server',
'template',
'title'
],
#category : #Brea
}
{ #category : #utility }
BreaWebsite class >> availableTemplates [
self templates keys.
]
{ #category : #utility }
BreaWebsite class >> demoFolder [
^ FileLocator temp asFileReference / 'BreaDemo'.
]
{ #category : #example }
BreaWebsite class >> example [
"I run an example mockup of a website using Brea.
After runing me, go to:
- http://localhost:8080/demo
- http://localhost:8080/members/test
- http://localhost:8080/members/add "
self new
local: FileLocator temp asFileReference / 'BreaDemo';
template: 'portafolio';
downloadTemplate;
modifyTemplate;
start
]
{ #category : #example }
BreaWebsite class >> exampleDashboard [
"I run an example mockup of a website using Brea.
After runing me, go to: http://localhost:8080/demo "
self new
local: FileLocator temp asFileReference / 'BreaDemo';
template: 'dashboard';
downloadTemplate;
modifyTemplate;
start
]
{ #category : #'server handling' }
BreaWebsite class >> stopAll [
"I stop the server"
Teapot stopAll
]
{ #category : #utility }
BreaWebsite class >> templates [
"I provide the supported MDL templates taken from: https://getmdl.io/templates/"
^ Dictionary new
at: 'portafolio' put: 'https://code.getmdl.io/1.3.0/mdl-template-portfolio.zip';
at: 'dashboard' put: 'https://code.getmdl.io/1.3.0/mdl-template-dashboard.zip';
yourself.
]
{ #category : #utility }
BreaWebsite >> defaultTemplate [
self template
ifNil: [
self template: 'portafolio' ].
^ self template.
]
{ #category : #utility }
BreaWebsite >> downloadDefaultTemplate [
self downloadTemplateNamed: self defaultTemplate Into: self local.
]
{ #category : #utility }
BreaWebsite >> downloadDefaultTemplateInto: aDirectory [
| remoteUrl templatesFile |
aDirectory ensureDeleteAll.
aDirectory ensureCreateDirectory.
remoteUrl := self class templates at: self template.
GrafoscopioUtils
downloadingFrom: remoteUrl
withMessage: 'Downloading templates'
into: FileLocator temp asFileReference.
templatesFile := FileLocator temp asFileReference / (remoteUrl splitOn: '/') last.
ZipArchive new
readFrom: templatesFile;
extractAllTo: aDirectory
]
{ #category : #utility }
BreaWebsite >> downloadTemplate [
self downloadTemplateNamed: self template Into: self local.
]
{ #category : #utility }
BreaWebsite >> downloadTemplateNamed: aName Into: aDirectory [
"aName: String aDirectory: aFileLocation"
| remoteUrl templatesFile localDirectory |
localDirectory := aDirectory asFileReference.
localDirectory ensureDeleteAll.
localDirectory ensureCreateDirectory.
remoteUrl := self class templates at: aName.
GrafoscopioUtils
downloadingFrom: remoteUrl
withMessage: 'Downloading templates'
into: FileLocator temp asFileReference.
templatesFile := FileLocator temp asFileReference / (remoteUrl splitOn: '/') last.
ZipArchive new
readFrom: templatesFile;
extractAllTo: localDirectory
]
{ #category : #accessing }
BreaWebsite >> fossilRepo [
^ fossilRepo ifNil: [ fossilRepo := FossilRepo new ]
]
{ #category : #accessing }
BreaWebsite >> fossilRepo: aFossilRepo [
fossilRepo := aFossilRepo
]
{ #category : #utility }
BreaWebsite >> local [
^ self fossilRepo local
]
{ #category : #'server handling' }
BreaWebsite >> local: aFilePath [
"I define the local storage of the Fossil repository.
For the moment aFilePath must be an absolute "
| localSite |
aFilePath asFileReference exists
ifFalse: [
localSite := (FileLocator temp / 'breaSite') ensureCreateDirectory.
self fossilRepo local: localSite fullName ]
ifTrue: [ self fossilRepo local: aFilePath ].
]
{ #category : #'server handling' }
BreaWebsite >> local: aFilePath remote: anUrl [
"I define the local and remote storages of the Fossil repository"
self remote: anUrl.
self local: aFilePath
]
{ #category : #utility }
BreaWebsite >> modifyDashboardTemplate [
"I replace default templates with versioned files, that contains Mustache tags used
for examples."
"This part should be factorized and integrated into a single method tha modifies any
template, instead of repeated the code of modifyPortafolioTemplate."
| remoteRepoUrl files |
remoteRepoUrl := 'http://mutabit.com/repos.fossil/brea/templates/portaforlio'.
files := #('index.html' 'styles.css').
"files do: [ :file |
GrafoscopioUtils
downloadingFrom: remoteRepoUrl, 'doc/tip/', file
withMessage: 'Replacing ', file
into: self local ]"
]
{ #category : #utility }
BreaWebsite >> modifyPortafolioTemplate [
"I replace default templates with versioned files, that contains Mustache tags used
for examples."
| remoteRepoUrl files |
remoteRepoUrl := 'http://mutabit.com/repos.fossil/gig/'.
files := #('index.html' 'styles.css').
files do: [ :file |
GrafoscopioUtils
downloadingFrom: remoteRepoUrl, 'doc/tip/', file
withMessage: 'Replacing ', file
into: self local ]
]
{ #category : #utility }
BreaWebsite >> modifyTemplate [
"I replace default templates with versioned files, that contains Mustache tags used
for examples."
self template = 'portafolio' ifTrue: [ self modifyPortafolioTemplate ].
self template = 'dashboard' ifTrue: [ self modifyDashboardTemplate ]
]
{ #category : #'input processing' }
BreaWebsite >> processNewMember: request [
| member badRequest |
badRequest := [ ^ ZnResponse badRequest: request ].
(request hasEntity
and: [ request contentType matches: ZnMimeType applicationFormUrlEncoded ])
ifFalse: [ badRequest ].
member := BreaMember new
givenName: (request at: #givenName);
familyName: (request at: #familyName);
email: (request at: #email);
country: (request at: #country);
organizations: (request at: #organizations);
picture: (request at: #picture);
website: (request at: #website);
twitter: (request at: #twitter);
facebook: (request at: #facebook);
tags: (request at: #tags).
self store: member.
^ 'New member stored!'
]
{ #category : #'server handling' }
BreaWebsite >> remote: anUrl [
"I define the remote storage of the Fossil repository"
self remote: anUrl.
]
{ #category : #'server handling' }
BreaWebsite >> routes [
"I define how the website behaves accordingly to particular routes."
self server
serveStatic: 'demo' from: (self local);
GET: 'members/test' -> [ :req | BreaMember new renderTestUserAsHtml ];
GET: 'members/add' -> [ :req | BreaMember new htmlInput ];
POST: 'members/summit' -> [ :req | self processNewMember: req ]
]
{ #category : #accessing }
BreaWebsite >> server [
^ server ifNil: [ self setup ]
]
{ #category : #accessing }
BreaWebsite >> server: anObject [
server := anObject
]
{ #category : #accessing }
BreaWebsite >> setup [
^ server := Teapot
configure:
{(#port -> 8080).
(#debugMode -> true)}
]
{ #category : #'server handling' }
BreaWebsite >> start [
"I define the config and start the server"
self routes.
self server start
]
{ #category : #'server handling' }
BreaWebsite >> storageFor: anObject [
"I define the places where local storage is done for several types of objects"
anObject class = BreaMember
ifTrue: [ ^ self local asFileReference / 'members' ].
^ self
]
{ #category : #'server handling' }
BreaWebsite >> store: anObject [
"I store different kind of objects in the website repository.
For the moment I will only store BreaMembers, but as long as new
objects will emerge, I will specialize other ways of storage."
anObject storeInto: (self storageFor: anObject)
]
{ #category : #accessing }
BreaWebsite >> template [
^ template
]
{ #category : #accessing }
BreaWebsite >> template: aTemplateName [
"I define the default template to be used for the Brea website.
Available options are at self class templates."
template := aTemplateName
]
{ #category : #accessing }
BreaWebsite >> title [
^ title
]
{ #category : #accessing }
BreaWebsite >> title: anObject [
title := anObject
]

View File

@ -0,0 +1,149 @@
"
I model a wiki page of a Brea site.
"
Class {
#name : #BreaWikiPage,
#superclass : #Object,
#instVars : [
'shortName',
'template',
'templateData',
'namespace',
'bodyTag'
],
#category : #Brea
}
{ #category : #operation }
BreaWikiPage >> bodyContentsAsHTML [
| sourcePage |
self markdownFile ifNil: [ ^ self ].
sourcePage := FileLocator temp / 'wikiPage.md'.
MarkupFile exportAsFileOn: sourcePage containing: self markdownFile contents.
^ Pandoc markdownToHtml: sourcePage
]
{ #category : #accessing }
BreaWikiPage >> bodyTag [
^ bodyTag
]
{ #category : #accessing }
BreaWikiPage >> 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 : #'as yet unclassified' }
BreaWikiPage >> exportAsHTML [
| htmlContents allActions semaphore result |
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
self bodyTag ifNil: [ ^ self ].
allActions := TKTFuture all: {
[ self populateMetadata ] future.
[ self populateBodyAs: self bodyTag ] future.
}.
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 namespace / (self shortName, '.html' ) containing: htmlContents
]
{ #category : #'as yet unclassified' }
BreaWikiPage >> htmlContents [
self shortName ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ (MustacheTemplate on: self templateFile contents) value: self templateData.
]
{ #category : #operation }
BreaWikiPage >> markdownFile [
| localFile |
self namespace ifNil: [ ^ self ].
self shortName ifNil: [ ^ self ].
localFile := self namespace / (self shortName, '.md').
localFile exists ifFalse: [ ^ self ].
^ Markdown fromFile: localFile
]
{ #category : #accessing }
BreaWikiPage >> namespace [
^ namespace
]
{ #category : #accessing }
BreaWikiPage >> namespace: folderFileReference [
namespace := folderFileReference
]
{ #category : #'as yet unclassified' }
BreaWikiPage >> 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 : #operation }
BreaWikiPage >> populateMetadata [
self markdownFile metadata keysAndValuesDo: [ :key :value |
self templateData at: key put: value
].
^ templateData
]
{ #category : #accessing }
BreaWikiPage >> shortName [
^ shortName
]
{ #category : #accessing }
BreaWikiPage >> shortName: aString [
shortName := aString
]
{ #category : #accessing }
BreaWikiPage >> template [
^ template
]
{ #category : #accessing }
BreaWikiPage >> template: mustacheFileName [
"Usually templates and their pages are located in the same folder."
template := mustacheFileName
]
{ #category : #accessing }
BreaWikiPage >> templateData [
^ templateData ifNil: [ templateData := Dictionary new ]
]
{ #category : #accessing }
BreaWikiPage >> templateData: aDictionary [
templateData := aDictionary
]
{ #category : #'as yet unclassified' }
BreaWikiPage >> templateFile [
self namespace ifNil: [ ^ self ].
self template ifNil: [ ^ self ].
^ self namespace / self template
]

View File

@ -1,13 +0,0 @@
"
I store metadata for this package. These meta data are used by other tools such as the SmalllintManifestChecker and the critics Browser
"
Class {
#name : #ManifestBrea,
#superclass : #PackageManifest,
#category : #'Brea-Manifest'
}
{ #category : #'code-critics' }
ManifestBrea class >> ruleRBStringConcatenationRuleV1FalsePositive [
^ #(#(#(#RGMethodDefinition #(#BreaPage #contents #false)) #'2020-08-28T20:08:20.291489-05:00') #(#(#RGMethodDefinition #(#BreaFile #fromShortName:andFolder: #false)) #'2020-11-06T20:59:12.94748-05:00') #(#(#RGMethodDefinition #(#'BreaFile class' #fromShortName:andFolder: #true)) #'2020-11-06T21:02:25.564981-05:00') )
]

View File

@ -1,6 +0,0 @@
Extension { #name : #String }
{ #category : #'*Brea' }
String >> webView [
^ (Pandoc htmlStringToMarkdown: self) accentedCharactersCorrection
]

View File

@ -1,6 +0,0 @@
Extension { #name : #Teapot }
{ #category : #'*Brea' }
Teapot >> dynamicRoutes [
^ dynamicRouter routes
]