WAComponent subclass: #SLCommentViewer
    instanceVariableNames: 'story '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



!SLCommentViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:18'!

addComment
    | comment |
    comment _ SLComment parent: story.
    (self call: (SLCommentEditor new story: story; comment: comment))
        ifTrue: [comment post]! !

!SLCommentViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:19'!
renderAddCommentLinkOn: html
    html spanClass: 'blogStamp' with: [html anchorWithAction: [self addComment] text: 'add']! !

!SLCommentViewer methodsFor: 'as yet unclassified' stamp: 'lr 10/26/2003 10:40'!
renderComment: aComment on: html
    html divClass: 'commentStamp' with: [
        html text: aComment author.
        aComment email isEmptyOrNil ifFalse: [
            self renderEmail: aComment email on: html ].
        html text: ', '.
        html text: aComment timeStamp.
    ].
    html divClass: 'commentBody' with: [ html blogText: aComment text ].! !

!SLCommentViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:19'!
renderContentOn: html
    story hasComments ifFalse: [^ self].
    html divClass: 'commentTitle' with: [
        html text: 'Comments '.
        self renderAddCommentLinkOn: html
    ].
    story comments do: [:ea | self renderComment: ea on: html].! !

!SLCommentViewer methodsFor: 'as yet unclassified' stamp: 'lr 10/26/2003 10:31'!
renderEmail: aString on: html
    | stream |
    stream _ aString withBlanksTrimmed readStream.
    html text: ' ('; text: (stream upTo: $@).
    stream atEnd ifFalse: [
        html text: ' AT '; text: stream upToEnd ].
    html text: ')'    ! !

!SLCommentViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:28'!
story: aStory
    story _ aStory! !


SLCommentViewer subclass: #SLCommentEditor
    instanceVariableNames: 'comment '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



!SLCommentEditor methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 12:44'!

comment: aComment
    comment _ aComment! !

!SLCommentEditor methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:19'!
renderAddCommentLinkOn: html
    ! !

!SLCommentEditor methodsFor: 'as yet unclassified' stamp: 'lr 10/26/2003 10:36'!
renderContentOn: html
    super renderContentOn: html.
    html divClass: 'commentBody' with: [
        html divClass: 'commentTitle' with: 'Add Comment'.
        html cssClass: 'addComment'; form: [
            html layoutTableOfWidth: '100%' do: [
                html tableRowWith: 'Author:' with: [html textInputOn: #author of: comment].
                html tableRowWith: 'Email: ' with: [html textInputOn: #email of: comment].
                html tableRowWith: [
                    html cssClass: 'commentTextArea'; textAreaOn: #text of: comment.
                ] span: 2.
                html attributes alignCenter.
                html tableRowWith: [
                    html submitButtonWithAction: [self answer: true] text: 'Save'.
                    html space.
                    html submitButtonWithAction: [self answer: false] text: 'Cancel'.
                ] span: 2.
            ]
        ]
    ]! !


Object subclass: #SLCss
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

SLCss class
    instanceVariableNames: ''!



!SLCss class methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 17:15'!

blaineCss
^'BODY {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; BACKGROUND: #f6f6f6; PADDING-BOTTOM: 0px; MARGIN: 0px; COLOR: #000000; PADDING-TOP: 0px; FONT-FAMILY: "Trebuchet MS",Trebuchet,Verdana,Sans-Serif
}
A {
    COLOR: #800080
}
A:hover {
    COLOR: #e0ad12
}
DIV.title {
    PADDING-RIGHT: 0px; BORDER-TOP: #800000 1px solid; PADDING-LEFT: 0px; BACKGROUND: #800080; PADDING-BOTTOM: 0px; MARGIN: 0px; COLOR: white; PADDING-TOP: 0px; BORDER-BOTTOM: #800000 1px dotted
}
DIV.titleDescription {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; BACKGROUND: none transparent scroll repeat 0% 0%; PADDING-BOTTOM: 0px; MARGIN: 7px 12% 7px 5%; FONT: bold 85% Verdana,Sans-Serif; COLOR: #ffde80; PADDING-TOP: 0px
}
DIV.mainContent {
    float: right ; width: 60%; PADDING-RIGHT: 7%; PADDING-LEFT: 3%; PADDING-BOTTOM: 10px; BORDER-LEFT: #800000 1px dotted; PADDING-TOP: 30px
}

.title A {
    COLOR: #f5deb3; TEXT-DECORATION: none ;
}

DIV.sideBar {
    float: left ; PADDING-RIGHT: 4px; PADDING-LEFT: 10px; PADDING-BOTTOM: 0px; MARGIN: 20px 0px 0px 0px; PADDING-TOP: 0px; TEXT-ALIGN: left
}


P.blogPostTitle {
    FONT-WEIGHT: bold;
}

.blogStamp {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 90%; PADDING-BOTTOM: 0px; MARGIN: 0px; COLOR: #444444; PADDING-TOP: 0px
}

.blogStamp A {
    COLOR: #800000; BORDER-TOP-STYLE: none; BORDER-RIGHT-STYLE: none; BORDER-LEFT-STYLE: none; TEXT-DECORATION: none; BORDER-BOTTOM-STYLE: none
}

.blogStamp A:hover {
    TEXT-DECORATION: underline
}

H1 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H2 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H3 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H4 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H5 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H6 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H1 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 5%; BACKGROUND: #800080; PADDING-BOTTOM: 10px; FONT: bold 175% Verdana,Sans-Serif; COLOR: #f5deb3; PADDING-TOP: 25px; BORDER-BOTTOM: #ffde80 1px solid; LETTER-SPACING: -2px
}
H2 {
    FONT-WEIGHT: bold; COLOR: #9e5205; FONT-FAMILY: Verdana,Sans-Serif; LETTER-SPACING: -1px
}
H3 {
    FONT-SIZE: 100%; MARGIN: 10px 0px 0px; COLOR: #700070
}
H4 {
    COLOR: #aa0033
}
H6 {
    FONT-SIZE: 100%; COLOR: #800080
}
.blogPost {
    FONT-SIZE: 80%; MARGIN: 0px 0px 30px
}
.blogPost STRONG {
    FONT-WEIGHT: bold; COLOR: #000000
}
#sideBar UL {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 85%; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 33px; PADDING-TOP: 0px; LIST-STYLE-TYPE: none
}
#sideBar LI {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 85%; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px; LIST-STYLE-TYPE: none
}
#sideBar UL A {
    PADDING-RIGHT: 2px; PADDING-LEFT: 2px; PADDING-BOTTOM: 2px; MARGIN: 1px; COLOR: #999999; BORDER-TOP-STYLE: none; PADDING-TOP: 2px; BORDER-RIGHT-STYLE: none; BORDER-LEFT-STYLE: none; TEXT-DECORATION: none; BORDER-BOTTOM-STYLE: none
}
#sideBar UL A:link {
    COLOR: #800000
}
#sideBar UL A:visited {
    COLOR: #800000
}
#sideBar UL A:active {
    COLOR: #ff0000
}
#sideBar UL A:hover {
    COLOR: #de7008; TEXT-DECORATION: none
}
PRE {
    COLOR: #999999
}
CODE {
    COLOR: #999999
}
STRIKE {
    COLOR: #999999
}
.syndicate {
    FONT-SIZE: 90%; COLOR: #800080 ; PADDING-LEFT: 8px;
}

.recentEntries {
    FONT-SIZE: 100%; COLOR: #800080
}

.archiveEntries {
    FONT-SIZE: 100%; COLOR: #800080
}

Div.calendar {
    PADDING-BOTTOM: 20px ; PADDING-TOP: 15px; COLOR: #800000;
}

.calendar {
    font-size: 80%
}

.calendarCaption {
    FONT-SIZE: 100%; FONT-WEIGHT: bold; COLOR: #800080
}


tr.calendarTitle {
    FONT-SIZE: 90%; COLOR: #800080
   
}

.calendar td {
    font-size: 80% ; TEXT-ALIGN: center ;
   
}

.calendarTitle td {
   
}

td.calendarArchiveDate {
    BACKGROUND: lightGrey ; font-size: 80% ; TEXT-ALIGN: center ;
}

.commentTitle {
    PADDING-TOP: 10px; COLOR: #800000;
}

.commentStamp {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 90%; PADDING-BOTTOM: 0px; MARGIN: 0px; COLOR: #444444; PADDING-TOP: 0px
}

textArea.commentTextArea {
    width : 100%;
    height: 200px;;
}

'! !

!SLCss class methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 17:28'!
defaultCss
    ^ self standardCss! !

!SLCss class methodsFor: 'as yet unclassified' stamp: 'lr 10/26/2003 10:14'!
standardCss
^'BODY {
    BACKGROUND: #eee; MARGIN: 20px
}
A {
    FONT-WEIGHT: bold; COLOR: #003366; TEXT-DECORATION: none
}
A:link {
    COLOR: #003366; TEXT-DECORATION: none
}
A:visited {
    COLOR: #003366; TEXT-DECORATION: none
}
A:active {
    COLOR: #ffcc66
}
A:hover {
    COLOR: #ffcc66
}

H1 {
    FONT-SIZE: x-large; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H2 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
H3 {
    PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
DIV.title {
    BORDER-RIGHT: #fff 1px solid; PADDING-RIGHT: 15px; BORDER-TOP: #fff 1px solid; PADDING-LEFT: 15px; FONT-WEIGHT: bold; FONT-SIZE: x-large; BACKGROUND: #003366; PADDING-BOTTOM: 15px; BORDER-LEFT: #fff 1px solid; COLOR: #fff; PADDING-TOP: 15px; FONT-FAMILY: georgia, verdana, arial, sans-serif
}


.title A {
    FONT-SIZE: x-large; COLOR: #fff; FONT-FAMILY: georgia, verdana, arial, sans-serif; TEXT-DECORATION: none
}
.title A:link {
    FONT-SIZE: x-large; COLOR: #fff; FONT-FAMILY: georgia, verdana, arial, sans-serif; TEXT-DECORATION: none
}
.title A:visited {
    FONT-SIZE: x-large; COLOR: #fff; FONT-FAMILY: georgia, verdana, arial, sans-serif; TEXT-DECORATION: none
}
.title A:active {
    FONT-SIZE: x-large; COLOR: #fff; FONT-FAMILY: georgia, verdana, arial, sans-serif; TEXT-DECORATION: none
}
.title A:hover {
    FONT-SIZE: x-large; COLOR: #fff; FONT-FAMILY: georgia, verdana, arial, sans-serif; TEXT-DECORATION: none
}

DIV.titleDescription {
    FONT-WEIGHT: bold; FONT-SIZE: x-small; BACKGROUND: #003366; TEXT-TRANSFORM: none; COLOR: #fff; FONT-FAMILY: verdana, arial, sans-serif
}

DIV.mainContent {
    PADDING-RIGHT: 15px; PADDING-LEFT: 15px; BACKGROUND: #fff; PADDING-BOTTOM: 15px; PADDING-TOP: 15px; BORDER-RIGHT: #fff 1px solid; BORDER-TOP: #fff 1px solid; BACKGROUND: #fff; FLOAT: left; MARGIN-BOTTOM: 20px; BORDER-LEFT: #fff 1px solid; WIDTH: 60%; MARGIN-RIGHT: 15px; BORDER-BOTTOM: #fff 1px solid; POSITION: relative;
}

DIV.mainBody {
    BACKGROUND: white
}


DIV.sideBar {
    BORDER-RIGHT: #fff 1px solid; PADDING-RIGHT: 15px; BORDER-TOP: #fff 1px solid; PADDING-LEFT: 15px; BACKGROUND: #999; PADDING-BOTTOM: 15px; BORDER-LEFT: #fff 1px solid; PADDING-TOP: 15px; BORDER-BOTTOM: #fff 1px solid
}

P.blogPostTitle {
    FONT-WEIGHT: bold;
}

.blogStamp {
    PADDING-TOP 16px; FONT-SIZE: x-small; MARGIN-BOTTOM: 25px; COLOR: #000000; FONT-FAMILY: verdana, arial, sans-serif
}

.blogPost {
    PADDING-BOTTOM: 15px; FONT-WEIGHT: normal; FONT-SIZE: small; BACKGROUND: #fff; COLOR: #666; LINE-HEIGHT: 150%; FONT-FAMILY: georgia, verdana, arial, sans-serif
}
.blogPost A {
    FONT-WEIGHT: normal; TEXT-DECORATION: underline
}
.blogPost A:link {
    FONT-WEIGHT: normal; TEXT-DECORATION: underline
}
.blogPost A:visited {
    FONT-WEIGHT: normal; TEXT-DECORATION: underline
}
.blogPost A:active {
    FONT-WEIGHT: normal; TEXT-DECORATION: underline
}
.blogPost A:hover {
    FONT-WEIGHT: normal; TEXT-DECORATION: underline
}




.blogDate {
    FONT-WEIGHT: bold; FONT-SIZE: small; MARGIN-BOTTOM: 10px; COLOR: #666; BORDER-BOTTOM: #999 1px solid; FONT-FAMILY: georgia, verdana, arial, sans-serif
}

.blogPostTitle {
    FONT-SIZE: small; TEXT-TRANSFORM: uppercase; COLOR: #000000; FONT-FAMILY: verdana, arial, sans-serif
}

.posted {
    FONT-SIZE: x-small; MARGIN-BOTTOM: 25px; COLOR: #000000; FONT-FAMILY: verdana, arial, sans-serif
}

.recentEntries {
    PADDING-RIGHT: 2px; MARGIN-TOP: 10px; PADDING-LEFT: 2px; FONT-WEIGHT: normal; FONT-SIZE: small; BACKGROUND: #999; PADDING-BOTTOM: 2px; COLOR: #fff; PADDING-TOP: 2px; BORDER-BOTTOM: #fff 1px dotted; FONT-FAMILY: georgia, verdana, arial, sans-serif; LETTER-SPACING: 0.1em; TEXT-ALIGN: center
}

.archiveEntries {
    PADDING-RIGHT: 2px; MARGIN-TOP: 10px; PADDING-LEFT: 2px; FONT-WEIGHT: normal; FONT-SIZE: small; BACKGROUND: #999; PADDING-BOTTOM: 2px; COLOR: #fff; PADDING-TOP: 2px; BORDER-BOTTOM: #fff 1px dotted; FONT-FAMILY: georgia, verdana, arial, sans-serif; LETTER-SPACING: 0.1em; TEXT-ALIGN: center
}

.syndicate {
    PADDING-RIGHT: 2px; MARGIN-TOP: 10px; PADDING-LEFT: 2px; FONT-WEIGHT: bold; FONT-SIZE: xx-small; BACKGROUND: #ccc; PADDING-BOTTOM: 2px; LINE-HEIGHT: 140%; PADDING-TOP: 2px; FONT-FAMILY: verdana, arial, sans-serif; TEXT-ALIGN: center
}

DIV.sideEntry {
    MARGIN-LEFT: 10px; PADDING-RIGHT: 2px; PADDING-LEFT: 2px; FONT-WEIGHT: normal; FONT-SIZE: small; BACKGROUND: #999; PADDING-BOTTOM: 2px; COLOR: #333; LINE-HEIGHT: 140%; PADDING-TOP: 2px; FONT-FAMILY: verdana, arial, sans-serif
}
#sideBar UL {
    PADDING-RIGHT: 0px; PADDING-LEFT: 10px; FONT-SIZE: 85%; PADDING-BOTTOM: 0px; MARGIN: 0px 0px 33px; PADDING-TOP: 0px; LIST-STYLE-TYPE: none
}

.calendar {
    TEXT-ALIGN: center; MARGIN-LEFT: 10px; PADDING-RIGHT: 2px; PADDING-LEFT: 2px; FONT-WEIGHT: normal; FONT-SIZE: 85%; BACKGROUND: #999; PADDING-BOTTOM: 2px; COLOR: #333; LINE-HEIGHT: 140%; PADDING-TOP: 16px; FONT-FAMILY: verdana, arial, sans-serif
}


.calendarCaption {
    PADDING-RIGHT: 2px; MARGIN-TOP: 10px; PADDING-LEFT: 2px; FONT-WEIGHT: normal; BACKGROUND: #999; PADDING-BOTTOM: 2px; COLOR: #fff; PADDING-TOP: 2px; BORDER-BOTTOM: #fff 1px dotted; FONT-FAMILY: georgia, verdana, arial, sans-serif; LETTER-SPACING: 0.1em; TEXT-ALIGN: center
}

.calendar table {
margin-left: auto;
margin-right: auto;
}

tr.calendarTitle {
    font-size: 90%; COLOR: #003366; TEXT-DECORATION: none ; FONT-WEIGHT: bold
}

.calendar td {
    TEXT-ALIGN: center; MARGIN-LEFT: 10px; PADDING-RIGHT: 2px; PADDING-LEFT: 2px; FONT-WEIGHT: normal; FONT-SIZE: 80%; BACKGROUND: #999; PADDING-BOTTOM: 2px; COLOR: #333; LINE-HEIGHT: 140%; PADDING-TOP: 2px; FONT-FAMILY: verdana, arial, sans-serif
}

.calendarTitle td {
    font-size: 75%; COLOR: #003366; TEXT-DECORATION: none ; FONT-WEIGHT: bold
}

.calendarArchiveDate {
    TEXT-ALIGN: center; MARGIN-LEFT: 10px; PADDING-RIGHT: 2px; PADDING-LEFT: 2px; FONT-WEIGHT: normal; FONT-SIZE: 80%; BACKGROUND: lightgrey; PADDING-BOTTOM: 2px; COLOR: #333; LINE-HEIGHT: 140%; PADDING-TOP: 2px; FONT-FAMILY: verdana, arial, sans-serif
}

.commentBody {
    PADDING-BOTTOM: 15px; FONT-WEIGHT: normal; FONT-SIZE: small; BACKGROUND: #fff; COLOR: #666; LINE-HEIGHT: 150%; FONT-FAMILY: georgia, verdana, arial, sans-serif
}

.commentBody td {
    PADDING-BOTTOM: 15px; FONT-WEIGHT: normal; FONT-SIZE: small; BACKGROUND: #fff; COLOR: #666; LINE-HEIGHT: 150%; FONT-FAMILY: georgia, verdana, arial, sans-serif
}


.commentTitle {
    FONT-WEIGHT: bold; FONT-SIZE: small; MARGIN-BOTTOM: 10px; COLOR: #666; BORDER-BOTTOM: #999 1px solid; FONT-FAMILY: georgia, verdana, arial, sans-serif
}

.commentStamp {
    PADDING-TOP 16px; FONT-SIZE: x-small; MARGIN-BOTTOM: 8px; FONT-FAMILY: verdana, arial, sans-serif
}

textArea.commentTextArea {
    width : 100%;
    height: 200px;;
}

.newStory {
TEXT-ALIGN: left ; PADDING-RIGHT: 15px;
}

.newStory A {
    COLOR: darkgreen ; TEXT-DECORATION: underline
}

.configure {
TEXT-ALIGN: left;
}

.configure A {
    COLOR: darkgreen ; TEXT-DECORATION: underline
}

.login A {
COLOR: #003366; ; TEXT-DECORATION: underline
}

.editStory {
    PADDING-BOTTOM: 15px; FONT-WEIGHT: normal; FONT-SIZE: small; BACKGROUND: #fff; COLOR: #666; LINE-HEIGHT: 150%; FONT-FAMILY: georgia, verdana, arial, sans-serif
}

'! !


WAComponent subclass: #SLFrame
    instanceVariableNames: 'main blog '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



!SLFrame methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:55'!

blogName
    | url |
    url _ self session initialRequest path allButFirst: self session basePath size.
    ^ (url findTokens: $/) first! !

!SLFrame methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:52'!
initialize
    (SLBlogStore current blogs includesKey: self blogName) ifFalse: [self noSuchBlog].
    blog _ SLBlogStore current blogNamed: self blogName.
    main _ SLFrontPage new blog: blog.
    main processRequest: self session initialRequest.! !

!SLFrame methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 22:48'!
renderContentOn: html
    html title: blog title.
    html divClass: 'title' with: [
        html anchorWithUrl: self session basePath do: blog title.
        html divClass: 'titleDescription' with: blog description.
    ].
   
    html divClass: 'mainBody' with: main! !

!SLFrame methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 14:33'!
style
    ^ SLCss defaultCss! !

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

SLFrame class
    instanceVariableNames: ''!



!SLFrame class methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:49'!

initialize
    self registerAsApplication: 'blog'! !


WAComponent subclass: #SLFrontPage
    instanceVariableNames: 'blog calendar storyList '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'mas 10/26/2003 19:35'!

baseUrl
    ^ (self session initialRequest headers at: 'host'), (self session basePath)! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:31'!
blog: aBlog
    blog _ aBlog! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 17:06'!
chooseDate: aDate
    storyList storyBlock: [blog storiesOnDate: aDate].
    self session addToPath: (self pathForDate: aDate)
       
    ! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:56'!
chooseStory: aStory
    self session addToPath: blog name, '/', aStory id asString.
    calendar date: nil.
    storyList storyBlock: [Array with: aStory]! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'mas 10/25/2003 20:16'!
displayAllRss
    | response xml |
    response _ WAGenericResponse new.
    xml _ String streamContents: [:s | SLRssWriter writeBlog: blog on: s].
    response contentType: 'text/xml'.
    response nextPutAll: xml.
    self session returnResponse: response.! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'mas 10/26/2003 01:56'!
displayRss
    | response xml |
    response _ WAGenericResponse new.
    xml _ String streamContents: [:s | SLRssWriter writeBlog: blog stories: storyList stories on: s withBaseUrl: self baseUrl].
    response contentType: 'text/xml'.
    response nextPutAll: xml.
    self session returnResponse: response.! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:34'!
initialize
    storyList _ SLStoryList new
                storyBlock: [blog recentStories];
                selectBlock: [:story | self chooseStory: story].
    calendar _ SLMiniCalendar new
                canSelectBlock: [:date | blog hasStoriesOnDate: date];
                selectBlock: [:date | self chooseDate: date]! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 14:43'!
login
    (self call: (SLLoginPage new validateBlock: [:u :p | blog checkUsername: u password: p]))
        ifTrue: [self session isolate: [self call: (SLAdminPage new blog: blog)]]! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:57'!
pathForDate: aDate
    ^ blog name, '/', (aDate printFormat: #(3 2 1 $/ 1 1 2))! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:56'!
processRequest: aRequest
    | url tokens |
    url _ aRequest path allButFirst: self session basePath size.
    tokens _ url findTokens: '/'.
    [
        tokens size = 4 ifTrue: [self requestDay: tokens fourth month: tokens third year: tokens second].
        tokens size = 3 ifTrue: [tokens second = 'rss' ifTrue: [self requestFeed: tokens third]].
        tokens size = 2 ifTrue: [self requestStory: tokens second].
        tokens size = 1 ifTrue: [self session addToPath: blog name].
    ] on: Error do: []! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 14:35'!
renderContentOn: html
    html divClass: 'mainContent' with: storyList.
    html divClass: 'sideBar' with: [self renderSideBarOn: html].! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:57'!
renderLoginOn: html
    html divClass: 'login' with: [html anchorWithAction: [self login] text: 'login']! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:58'!
renderSideBarOn: html
    html render: calendar.
    html cssClass: 'syndicate'; paragraph: [
        html anchorWithUrl: (self session basePath, '/', blog name, '/rss/recent.xml') do:
            [html attributes border: 0.
            html image: 'http://www.scripting.com/images/xml.gif' altText: 'xml'].
    ].
    self renderLoginOn: html.! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:29'!
requestDay: dayString month: monthString year: yearString
    | date |
    date _ Date
            newDay: dayString asNumber
            monthNumber: monthString asNumber
            year: yearString asNumber.
    calendar select: date! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:39'!
requestFeed: feedName
    feedName = 'recent.xml' ifTrue: [self displayRss].
    feedName = 'all.xml' ifTrue: [self displayAllRss].! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:29'!
requestStory: idString
    | id |
    id _ UUID fromString: idString.
    self chooseStory: (blog storyWithId: id)! !

!SLFrontPage methodsFor: 'as yet unclassified' stamp: 'mas 10/26/2003 01:36'!
setBaseUrl
    baseUrl _ self session basePath.
    self halt.

       
    ! !


WAComponent subclass: #SLMiniCalendar
    instanceVariableNames: 'month date canSelectBlock selectBlock '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 14:38'!

canSelect: aDate
    ^ canSelectBlock notNil and: [canSelectBlock value: aDate]! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 15:16'!
canSelectBlock: aBlock
    canSelectBlock _ aBlock! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 15:25'!
date
    ^ date contents! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 17:40'!
date: aDate
    date contents: aDate! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 22:56'!
initialize
    month _ WAStateHolder new contents: Date today month.
    date _ WAStateHolder new.! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 22:56'!
month
    ^ month contents! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 22:56'!
month: aMonth
    ^ month contents: aMonth! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 22:56'!
monthHeading
    ^ self month name, ' ', self month year asString! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:14'!
renderCellForDate: aDate on: html
    html tableData: [
        aDate month = self month ifTrue:
            [html cssClass: (self date = aDate ifTrue: ['calendarArchiveDate']).
            html span: [
            (self canSelect: aDate)
                ifTrue: [html anchorWithAction: [self select: aDate] text: aDate dayOfMonth]
                ifFalse: [html text: aDate dayOfMonth]
            ]]
    ]! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 11:35'!
renderContentOn: html
    html divClass: 'calendar' with: [
    html spanClass: 'calendarCaption' with: self monthHeading.
    html table: [
        html cssClass: 'calendarTitle'; tableRow: [
            self weekDays do: [:ea | html tableData: ea].
        ].
        self month eachWeekDo: [:week | self renderRowForWeek: week on: html].
    ].
    self renderMonthNavigationOn: html.
    ]! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:14'!
renderMonthNavigationOn: html
    html spanClass: 'calendarPrevious' with: [
        html
            anchorWithAction: [self month: self month previous]
            text: (self month previous name first: 3).
    ].
    html space.
    html spanClass: 'calendarNext' with: [
        html
            anchorWithAction: [self month: self month next]
            text: (self month next name first: 3).
    ]
    ! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 14:23'!
renderRowForWeek: aWeek on: html
    html tableRow: [
        aWeek do: [:ea | self renderCellForDate: ea on: html].
    ]! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 17:40'!
select: aDate
    self date: aDate.
    selectBlock ifNotNil: [selectBlock value: aDate]! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 17:39'!
selectBlock: aBlock
    selectBlock _ aBlock! !

!SLMiniCalendar methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 14:25'!
weekDays
    ^ (1 to: 7) collect: [:i | (Date nameOfDay: i) first: 3]! !


WAComponent subclass: #SLStoryList
    instanceVariableNames: 'storyBlock selectBlock storyViewers '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:14'!

initialize
    storyBlock _ WAStateHolder new.
    storyViewers _ Dictionary new.! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 12:31'!
renderContentOn: html
    self storiesByDate do:
        [:group |
        self renderStoryGroup: group on: html]! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 15:46'!
renderDateHeader: aDate on: html
    html divClass: 'blogDate' with: aDate! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:14'!
renderStoryGroup: aCollection on: html
    self renderDateHeader: aCollection anyOne date on: html.
    aCollection do:
        [:ea |
        html render: (self storyViewerFor: ea)].! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:25'!
select: aStory
    selectBlock ifNotNil: [selectBlock value: aStory]! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:25'!
selectBlock: aBlock
    selectBlock _ aBlock! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 14:18'!
stories
    ^ storyBlock contents value! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/23/2003 13:52'!
storiesByDate
    | dictionary |
    dictionary _ self stories groupBy: [:ea | ea date] having: [:ea | true].
    ^ dictionary keys asSortedCollection reversed collect: [:ea | dictionary at: ea]! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 13:21'!
storyBlock: aBlock
    storyBlock contents: aBlock! !

!SLStoryList methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:26'!
storyViewerFor: aStory
    ^ storyViewers at: aStory ifAbsentPut: [SLStoryViewer new list: self; story: aStory]! !


WAComponent subclass: #SLStoryViewer
    instanceVariableNames: 'story list commentViewer showComments '
    classVariableNames: ''
    poolDictionaries: ''
    category: 'SBlogLite-UI'!



!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 16:54'!

addComment
    self showComments: true.
    self commentViewer addComment.! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 16:43'!
commentInfo
    ^ self showComments
        ifFalse: [story comments size asString, ' comments, last by ', story comments last author]
        ifTrue: ['hide comments']! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:27'!
commentViewer
    ^ commentViewer ifNil: [commentViewer _ SLCommentViewer new story: story]! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:20'!
initialize
    showComments _ WAStateHolder new contents: false! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:12'!
list: aStoryList
    list _ aStoryList! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 16:51'!
renderCommentInfoOn: html
    story hasComments
        ifTrue: [html anchorWithAction: [self toggleComments] text: self commentInfo]
        ifFalse: [html anchorWithAction: [self addComment] text: 'add comment'].! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'lr 10/26/2003 10:41'!
renderContentOn: html
    html divClass: 'blogPost' with: [
        self renderTitleOn: html.
        html blogText: story text.
        self renderStampOn: html.
        self showComments ifTrue: [html render: self commentViewer].
    ]! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/25/2003 23:57'!
renderPermalinkOn: html
    html anchorWithUrl: self session basePath, '/', story blog name, '/', story id asString title: story title do: 'link'.
! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 16:50'!
renderStampOn: html
    html divClass: 'blogStamp' with: [
        self renderPermalinkOn: html.
        html space.
        html text: story time.
        html space.
        self renderCommentInfoOn: html.
    ].
! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:22'!
renderTitleOn: html       
    html cssClass: 'blogPostTitle'; paragraph: [
        html anchorWithAction: [self select] text: story title.
    ].
! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:12'!
select
    list select: story! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:06'!
selectBlock: aBlock
    selectBlock _ aBlock! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:20'!
showComments
    ^ showComments contents! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 16:54'!
showComments: aBoolean
    showComments contents: aBoolean! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 15:06'!
story: aStory
    story _ aStory! !

!SLStoryViewer methodsFor: 'as yet unclassified' stamp: 'avi 10/24/2003 16:54'!
toggleComments
    self showComments: self showComments not! !

SLFrame initialize!