dup empty?
[ drop f ] [ "," split [ dup value ] H{ } map>assoc ] if ;
-CHLOE: atom
- [ children>string ]
- [ "href" required-attr ]
- [ "query" optional-attr parse-query-attr ] tri
- <url>
- swap >>query
- swap >>path
- adjust-url relative-to-request
- add-atom-feed ;
+: a-url-path ( tag -- string )
+ [ "href" required-attr ] [ "rest" optional-attr value ] bi
+ [ [ "/" ?tail drop "/" ] dip present 3append ] when* ;
+
+: a-url ( tag -- url )
+ dup "value" optional-attr [ ] [
+ <url>
+ swap
+ [ a-url-path >>path ]
+ [ "query" optional-attr parse-query-attr >>query ]
+ bi
+ ] ?if
+ adjust-url relative-to-request ;
+
+CHLOE: atom [ children>string ] [ a-url ] bi add-atom-feed ;
CHLOE: write-atom drop write-atom-feeds ;
M: object link-attr 2drop ;
: link-attrs ( tag -- )
+ #! Side-effects current namespace.
'[ , _ link-attr ] each-responder ;
: a-start-tag ( tag -- )
- [
- <a
- dup link-attrs
- dup "value" optional-attr [ value f ] [
- [ "href" required-attr ]
- [ "query" optional-attr parse-query-attr ]
- bi
- ] ?if
- <url>
- swap >>query
- swap >>path
- adjust-url relative-to-request =href
- a>
- ] with-scope ;
+ [ <a [ link-attrs ] [ a-url =href ] bi a> ] with-scope ;
CHLOE: a
[ a-start-tag ]
[
[
<form
- "POST" =method
- [ link-attrs ]
- [ "action" required-attr resolve-base-path =action ]
- [ tag-attrs non-chloe-attrs-only print-attrs ]
- tri
+ {
+ [ link-attrs ]
+ [ "method" optional-attr "post" or =method ]
+ [ "action" required-attr resolve-base-path =action ]
+ [ tag-attrs non-chloe-attrs-only print-attrs ]
+ } cleave
form>
]
[ form-magic ] bi
: <edit-post-action> ( -- action )
<page-action>
+ "id" >>rest
+
[
validate-integer-id
"id" value <post> select-tuple from-object
<div class="posting-footer">
Post by
- <t:a t:href="$blogs/" t:query="author">
+ <t:a t:href="$blogs/by" t:rest="author">
<t:label t:name="author" />
</t:a>
on
<t:label t:name="date" />
|
- <t:a t:href="$blogs/post" t:for="id">View Post</t:a>
+ <t:a t:href="$blogs/post" t:rest="id">View Post</t:a>
|
<t:button t:action="$blogs/delete-post" t:for="id,author" class="link-button link">Delete Post</t:button>
</div>
<t:bind-each t:name="posts">
<h2 class="post-title">
- <t:a t:href="$blogs/post" t:query="id">
+ <t:a t:href="$blogs/post" t:rest="id">
<t:label t:name="title" />
</t:a>
</h2>
<div class="posting-footer">
Post by
- <t:a t:href="$blogs/by" t:query="author">
+ <t:a t:href="$blogs/by" t:rest="author">
<t:label t:name="author" />
</t:a>
on
<t:label t:name="date" />
|
- <t:a t:href="$blogs/post" t:query="id">
+ <t:a t:href="$blogs/post" t:rest="id">
<t:label t:name="comments" />
comments.
</t:a>
<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
- <t:atom t:href="$blogs/by" t:query="author">
+ <t:atom t:href="$blogs/by" t:rest="author">
Recent Posts by <t:label t:name="author" />
</t:atom>
<t:bind-each t:name="posts">
<h2 class="post-title">
- <t:a t:href="$blogs/post" t:query="id">
+ <t:a t:href="$blogs/post" t:rest="id">
<t:label t:name="title" />
</t:a>
</h2>
<div class="posting-footer">
Post by
- <t:a t:href="$blogs/by" t:query="author">
+ <t:a t:href="$blogs/by" t:rest="author">
<t:label t:name="author" />
</t:a>
on
<t:label t:name="date" />
|
- <t:a t:href="$blogs/post" t:query="id">
+ <t:a t:href="$blogs/post" t:rest="id">
<t:label t:name="comments" />
comments.
</t:a>
<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
- <t:atom t:href="$blogs/post.atom" t:query="id">
+ <t:atom t:href="$blogs/post.atom" t:rest="id">
<t:label t:name="author" />: <t:label t:name="title" />
</t:atom>
- <t:atom t:href="$blogs/by.atom" t:query="author">
+ <t:atom t:href="$blogs/by.atom" t:rest="author">
Recent Posts by <t:label t:name="author" />
</t:atom>
<div class="posting-footer">
Post by
- <t:a t:href="$blogs/" t:query="author">
+ <t:a t:href="$blogs/" t:rest="author">
<t:label t:name="author" />
</t:a>
on
<t:label t:name="date" />
|
- <t:a t:href="$blogs/edit-post" t:query="id">Edit Post</t:a>
+ <t:a t:href="$blogs/edit-post" t:rest="id">Edit Post</t:a>
|
<t:button t:action="$blogs/delete-post" t:for="id,author" class="link-button link">Delete Post</t:button>
</div>
<ul>
<t:bind-each t:name="articles">
<li>
- <t:a t:href="view" t:query="title"><t:label t:name="title"/></t:a>
+ <t:a t:href="$wiki/view" t:rest="title"><t:label t:name="title"/></t:a>
</li>
</t:bind-each>
</ul>
<t:title>Recent Changes</t:title>
- <ul>
- <t:bind-each t:name="changes">
- <li>
- <t:a t:href="view" t:query="title"><t:label t:name="title" /></t:a>
- on
- <t:a t:href="revision" t:query="id"><t:label t:name="date" /></t:a>
- by
- <t:a t:href="user-edits" t:query="author"><t:label t:name="author" /></t:a>
- </li>
- </t:bind-each>
- </ul>
+ <div class="revisions">
+
+ <table>
+
+ <tr>
+ <th>Article</th>
+ <th>Date</th>
+ <th>By</th>
+ </tr>
+
+ <t:bind-each t:name="changes">
+ <tr>
+ <td><t:a t:href="$wiki/view" t:rest="title"><t:label t:name="title" /></t:a></td>
+ <td><t:a t:href="$wiki/revision" t:rest="id"><t:label t:name="date" /></t:a></td>
+ <td><t:a t:href="$wiki/user-edits" t:rest="author"><t:label t:name="author" /></t:a></td>
+ </tr>
+ </t:bind-each>
+
+ </table>
+
+ </div>
</t:chloe>
<tr>
<th class="field-label">Old revision:</th>
<t:bind t:name="old">
- <td>Created on <t:label t:name="date" /> by <t:a t:href="user-edits" t:query="author"><t:label t:name="author" /></t:a>.</td>
+ <td>Created on <t:label t:name="date" /> by <t:a t:href="user-edits" t:rest="author"><t:label t:name="author" /></t:a>.</td>
</t:bind>
</tr>
<tr>
<th class="field-label">New revision:</th>
<t:bind t:name="old">
- <td>Created on <t:label t:name="date" /> by <t:a t:href="user-edits" t:query="author"><t:label t:name="author" /></t:a>.</td>
+ <td>Created on <t:label t:name="date" /> by <t:a t:href="user-edits" t:rest="author"><t:label t:name="author" /></t:a>.</td>
</t:bind>
</tr>
</table>
<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
- <t:atom t:href="$wiki/revisions.atom" t:query="title">
+ <t:atom t:href="$wiki/revisions.atom" t:rest="title">
Revisions of <t:label t:name="title" />
</t:atom>
<t:call-next-template />
<div class="navbar">
- <t:a t:href="$wiki/view" t:query="title">Latest</t:a>
- | <t:a t:href="$wiki/revisions" t:query="title">Revisions</t:a>
- | <t:a t:href="$wiki/edit" t:query="title">Edit</t:a>
+ <t:a t:href="$wiki/view" t:rest="title">Latest</t:a>
+ | <t:a t:href="$wiki/revisions" t:rest="title">Revisions</t:a>
+ | <t:a t:href="$wiki/edit" t:rest="title">Edit</t:a>
| <t:button t:action="$wiki/delete" t:for="title" class="link-button link">Delete</t:button>
</div>
<table>
<tr>
<th>Revision</th>
- <th>Author</th>
+ <th>By</th>
<th>Rollback</th>
</tr>
<t:bind-each t:name="revisions">
<tr>
- <td> <t:a t:href="revision" t:query="id"><t:label t:name="date" /></t:a> </td>
- <td> <t:a t:href="user-edits" t:query="author"><t:label t:name="author" /></t:a> </td>
+ <td> <t:a t:href="$wiki/revision" t:rest="id"><t:label t:name="date" /></t:a> </td>
+ <td> <t:a t:href="$wiki/user-edits" t:rest="author"><t:label t:name="author" /></t:a> </td>
<td> <t:button t:action="rollback" t:for="id" class="link link-button">Rollback</t:button> </td>
</tr>
</t:bind-each>
<h2>View Differences</h2>
- <form action="diff" method="get">
+ <t:form t:action="$wiki/diff" t:method="get">
<table>
<tr>
<th class="field-label">Old revision:</th>
</table>
<input type="submit" value="View" />
- </form>
+ </t:form>
</t:chloe>
<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
- <t:atom t:href="$wiki/user-edits.atom" t:query="author">
+ <t:atom t:href="$wiki/user-edits.atom" t:rest="author">
Edits by <t:label t:name="author" />
</t:atom>
<ul>
<t:bind-each t:name="user-edits">
<li>
- <t:a t:href="view" t:query="title"><t:label t:name="title" /></t:a>
+ <t:a t:href="$wiki/view" t:rest="title"><t:label t:name="title" /></t:a>
on
- <t:a t:href="revision" t:query="id"><t:label t:name="date" /></t:a>
+ <t:a t:href="$wiki/revision" t:rest="id"><t:label t:name="date" /></t:a>
</li>
</t:bind-each>
</ul>
<t:farkup t:name="content" />
</div>
- <p><em>This revision created on <t:label t:name="date" /> by <t:a t:href="user-edits" t:query="author"><t:label t:name="author" /></t:a>.</em></p>
+ <p><em>This revision created on <t:label t:name="date" /> by <t:a t:href="$wiki/user-edits" t:rest="author"><t:label t:name="author" /></t:a>.</em></p>
</t:chloe>
! Copyright (C) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel hashtables calendar
-namespaces splitting sequences sorting math.order
+namespaces splitting sequences sorting math.order present
html.components syndication
http.server
http.server.dispatchers
db.types db.tuples lcs farkup urls ;
IN: webapps.wiki
-: view-url ( title -- url )
- "$wiki/view/" prepend >url ;
+: wiki-url ( rest path -- url )
+ [ "$wiki/" % % "/" % % ] "" make
+ <url> swap >>path ;
-: edit-url ( title -- url )
- "$wiki/edit" >url swap "title" set-query-param ;
+: view-url ( title -- url ) "view" wiki-url ;
-: revisions-url ( title -- url )
- "$wiki/revisions" >url swap "title" set-query-param ;
+: edit-url ( title -- url ) "edit" wiki-url ;
-: revision-url ( id -- url )
- "$wiki/revision" >url swap "id" set-query-param ;
+: revisions-url ( title -- url ) "revisions" wiki-url ;
-: user-edits-url ( author -- url )
- "$wiki/user-edits" >url swap "author" set-query-param ;
+: revision-url ( id -- url ) "revision" wiki-url ;
+
+: user-edits-url ( author -- url ) "user-edits" wiki-url ;
TUPLE: wiki < dispatcher ;
: <view-article-action> ( -- action )
<action>
"title" >>rest
-
[
validate-title
- "view?title=" relative-link-prefix set
] >>init
-
[
"title" value dup <article> select-tuple [
revision>> <revision> select-tuple from-object
: <view-revision-action> ( -- action )
<page-action>
+ "id" >>rest
[
validate-integer-id
"id" value <revision>
select-tuple from-object
- "view?title=" relative-link-prefix set
+ URL" $wiki/view/" adjust-url present relative-link-prefix set
] >>init
-
{ wiki "view" } >>template ;
: add-revision ( revision -- )
: <edit-article-action> ( -- action )
<page-action>
+ "title" >>rest
[
validate-title
"title" value <article> select-tuple [
revision>> <revision> select-tuple from-object
] when*
] >>init
-
{ wiki "edit" } >>template
-
[
validate-title
{ { "content" [ v-required ] } } validate-params
: <list-revisions-action> ( -- action )
<page-action>
+ "title" >>rest
[
validate-title
list-revisions "revisions" set-value
: <list-revisions-feed-action> ( -- action )
<feed-action>
+ "title" >>rest
[ validate-title ] >>init
[ "Revisions of " "title" value append ] >>title
[ "title" value revisions-url ] >>url
: <rollback-action> ( -- action )
<action>
[ validate-integer-id ] >>validate
-
[
"id" value <revision> select-tuple clone f >>id
[ add-revision ] [ title>> view-url <redirect> ] bi
] >>submit ;
: list-changes ( -- seq )
- "id" value <revision> select-tuples
+ f <revision> select-tuples
reverse-chronological-order ;
: <list-changes-action> ( -- action )
<page-action>
[ list-changes "changes" set-value ] >>init
-
{ wiki "changes" } >>template ;
: <list-changes-feed-action> ( -- action )
: <delete-action> ( -- action )
<action>
[ validate-title ] >>validate
-
[
"title" value <article> delete-tuples
f <revision> "title" value >>title delete-tuples
[ [ content>> string-lines ] bi@ diff "diff" set-value ]
2bi
] >>init
-
{ wiki "diff" } >>template ;
: <list-articles-action> ( -- action )
[ [ title>> ] compare ] sort
"articles" set-value
] >>init
-
{ wiki "articles" } >>template ;
: list-user-edits ( -- seq )
: <user-edits-action> ( -- action )
<page-action>
+ "author" >>rest
[
validate-author
list-user-edits "user-edits" set-value
: <user-edits-feed-action> ( -- action )
<feed-action>
+ "author" >>rest
[ validate-author ] >>init
[ "Edits by " "author" value append ] >>title
[ "author" value user-edits-url ] >>url