--- /dev/null
+! Copyright (C) 2008 Slava Pestov
+! See http://factorcode.org/license.txt for BSD license.
+USING: lcs html.elements kernel qualified ;
+FROM: accessors => item>> ;
+FROM: io => write ;
+FROM: sequences => each empty? ;
+FROM: xml.entities => escape-string ;
+IN: lcs.diff2html
+
+GENERIC: diff-line ( obj -- )
+
+: write-item ( item -- )
+ item>> dup empty? [ drop " " ] [ escape-string ] if write ;
+
+M: retain diff-line
+ <tr>
+ dup [
+ <td "retain" =class td>
+ write-item
+ </td>
+ ] bi@
+ </tr> ;
+
+M: insert diff-line
+ <tr>
+ <td> </td>
+ <td "insert" =class td>
+ write-item
+ </td>
+ </tr> ;
+
+M: delete diff-line
+ <tr>
+ <td "delete" =class td>
+ write-item
+ </td>
+ <td> </td>
+ </tr> ;
+
+: htmlize-diff ( diff -- )
+ <table "comparison" =class table>
+ <tr> <th> "Old" write </th> <th> "New" write </th> </tr>
+ [ diff-line ] each
+ </table> ;
http.server.auth.providers.db
http.server.boilerplate
html.templates.chloe
-webapps.user-admin
webapps.pastebin
webapps.planet
-webapps.todo ;
+webapps.todo
+webapps.wiki
+webapps.user-admin ;
IN: webapps.factor-website
: test-db "resource:test.db" sqlite-db ;
init-postings-table
init-todo-table
+
+ init-articles-table
+ init-revisions-table
] with-db ;
: <factor-website> ( -- responder )
<todo-list> "todo" add-responder
<pastebin> "pastebin" add-responder
<planet-factor> "planet" add-responder
+ <wiki> "wiki" add-responder
<user-admin> "user-admin" add-responder
<login>
users-in-db >>users
}
.description {
- border: 1px dashed #ccc;
- background-color: #f5f5f5;
padding: 5px;
color: #000;
}
+.description pre {
+ border: 1px dashed #ccc;
+ background-color: #f5f5f5;
+}
+
.description p:first-child {
margin-top: 0px;
}
--- /dev/null
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+ <t:title>All Articles</t:title>
+
+ <ul>
+ <t:each-tuple t:values="articles">
+ <li>
+ <t:a t:href="view" t:query="title"><t:label t:name="title"/></t:a>
+ </li>
+ </t:each-tuple>
+ </ul>
+
+</t:chloe>
--- /dev/null
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+ <t:bind-tuple t:name="old">
+ <t:title>Diff: <t:label t:name="title" /></t:title>
+ </t:bind-tuple>
+
+ <table>
+ <tr>
+ <th class="field-label">Old revision:</th>
+ <t:bind-tuple t:name="old">
+ <td>Created on <t:label t:name="date" /> by <t:label t:name="author" />.</td>
+ </t:bind-tuple>
+ </tr>
+ <tr>
+ <th class="field-label">New revision:</th>
+ <t:bind-tuple t:name="old">
+ <td>Created on <t:label t:name="date" /> by <t:label t:name="author" />.</td>
+ </t:bind-tuple>
+ </tr>
+ </table>
+
+ <t:comparison t:name="diff" />
+
+ <t:bind-tuple t:name="old">
+ <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:button t:action="$wiki/delete" t:for="title" class="link-button link">Delete</t:button>
+ </div>
+ </t:bind-tuple>
+
+</t:chloe>
--- /dev/null
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+ <t:title>Edit: <t:label t:name="title" /></t:title>
+
+ <t:form t:action="$wiki/edit" t:for="title">
+
+ <p>
+ <t:textarea t:name="content" t:rows="30" t:cols="80" />
+ </p>
+
+ <p>
+ <input type="submit" value="Save" />
+ </p>
+
+ </t:form>
+
+ <t:button t:action="$wiki/delete" t:for="title" class="link-button link">Delete</t:button>
+</t:chloe>
--- /dev/null
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+ <t:title>Revisions of <t:label t:name="title" /></t:title>
+
+ <ul>
+ <t:each-tuple t:values="revisions">
+ <li>
+ <t:a t:href="revision" t:query="id">
+ <t:label t:name="date" /> by <t:label t:name="author" />
+ </t:a>
+ </li>
+ </t:each-tuple>
+ </ul>
+
+ <h2>View Differences</h2>
+
+ <form action="diff" method="get">
+ <table>
+ <tr>
+ <th class="field-label">Old revision:</th>
+
+ <td>
+ <select name="old-id">
+ <t:each-tuple t:values="revisions">
+ <option> <t:label t:name="id" /> </option>
+ </t:each-tuple>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <th class="field-label">New revision:</th>
+
+ <td>
+ <select name="new-id">
+ <t:each-tuple t:values="revisions">
+ <option> <t:label t:name="id" /> </option>
+ </t:each-tuple>
+ </select>
+ </td>
+ </tr>
+ </table>
+
+ <input type="submit" value="View" />
+ </form>
+
+</t:chloe>
--- /dev/null
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+ <t:title><t:label t:name="title" /></t:title>
+
+ <div class="description">
+ <t:farkup t:name="content" />
+ </div>
+
+ <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:button t:action="$wiki/delete" t:for="title" class="link-button link">Delete</t:button>
+ | This revision created on <t:label t:name="date" /> by <t:label t:name="author" />.
+ </div>
+
+</t:chloe>
--- /dev/null
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+ <t:style t:include="resource:extra/webapps/wiki/wiki.css" />
+
+ <div class="navbar">
+
+ <t:a t:href="$wiki">Front Page</t:a>
+ | <t:a t:href="$wiki/articles">All Articles</t:a>
+
+ <t:if t:code="http.server.sessions:uid">
+
+ <t:if t:code="http.server.auth.login:allow-edit-profile?">
+ | <t:a t:href="$login/edit-profile" t:flow="begin">Edit Profile</t:a>
+ </t:if>
+
+ | <t:button t:action="$login/logout" t:flow="begin" class="link-button link">Logout</t:button>
+
+ </t:if>
+
+ </div>
+
+ <h1><t:write-title /></h1>
+
+ <t:call-next-template />
+
+</t:chloe>
--- /dev/null
+.comparison table, {
+ border-color: #666;
+ border-style: solid;
+}
+
+.comparison th {
+ border-width: 1px;
+ border-color: #666;
+ border-style: solid;
+}
+
+.comparison table {
+ border-width: 1px;
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+
+.insert {
+ background-color: #9f9;
+}
+
+.delete {
+ background-color: #f99;
+}
--- /dev/null
+! 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
+html.components
+html.templates.chloe
+http.server
+http.server.actions
+http.server.auth
+http.server.auth.login
+http.server.boilerplate
+validators
+db.types db.tuples lcs farkup ;
+IN: webapps.wiki
+
+TUPLE: article title revision ;
+
+article "ARTICLES" {
+ { "title" "TITLE" { VARCHAR 256 } +not-null+ +user-assigned-id+ }
+ ! { "AUTHOR" INTEGER +not-null+ } ! uid
+ ! { "PROTECTED" BOOLEAN +not-null+ }
+ { "revision" "REVISION" INTEGER +not-null+ } ! revision id
+} define-persistent
+
+: <article> ( title -- article ) article new swap >>title ;
+
+: init-articles-table article ensure-table ;
+
+TUPLE: revision id title author date content ;
+
+revision "REVISIONS" {
+ { "id" "ID" INTEGER +db-assigned-id+ }
+ { "title" "TITLE" { VARCHAR 256 } +not-null+ } ! article id
+ { "author" "AUTHOR" { VARCHAR 256 } +not-null+ } ! uid
+ { "date" "DATE" TIMESTAMP +not-null+ }
+ { "content" "CONTENT" TEXT +not-null+ }
+} define-persistent
+
+: <revision> ( id -- revision )
+ revision new swap >>id ;
+
+: init-revisions-table revision ensure-table ;
+
+: wiki-template ( name -- template )
+ "resource:extra/webapps/wiki/" swap ".xml" 3append <chloe> ;
+
+: <title-redirect> ( title next -- response )
+ swap "title" associate <standard-redirect> ;
+
+: validate-title ( -- )
+ { { "title" [ v-one-line ] } } validate-params ;
+
+: <main-article-action> ( -- action )
+ <action>
+ [ "Front Page" "$wiki/view" <title-redirect> ] >>display ;
+
+: <view-article-action> ( -- action )
+ <action>
+ "title" >>rest-param
+
+ [
+ validate-title
+ "view?title=" relative-link-prefix set
+ ] >>init
+
+ [
+ "title" value dup <article> select-tuple [
+ revision>> <revision> select-tuple from-tuple
+ "view" wiki-template <html-content>
+ ] [
+ "$wiki/edit" <title-redirect>
+ ] ?if
+ ] >>display ;
+
+: <view-revision-action> ( -- action )
+ <page-action>
+ [
+ { { "id" [ v-integer ] } } validate-params
+ "id" value <revision>
+ select-tuple from-tuple
+ ] >>init
+
+ "view" wiki-template >>template ;
+
+: add-revision ( revision -- )
+ [ insert-tuple ]
+ [
+ dup title>> <article> select-tuple [
+ swap id>> >>revision update-tuple
+ ] [
+ [ title>> ] [ id>> ] bi article boa insert-tuple
+ ] if*
+ ] bi ;
+
+: <edit-article-action> ( -- action )
+ <page-action>
+ [
+ validate-title
+ "title" value <article> select-tuple [
+ revision>> <revision> select-tuple from-tuple
+ ] when*
+ ] >>init
+
+ "edit" wiki-template >>template
+
+ [
+ validate-title
+ { { "content" [ v-required ] } } validate-params
+
+ f <revision>
+ "title" value >>title
+ now >>date
+ logged-in-user get username>> >>author
+ "content" value >>content
+ [ add-revision ]
+ [ title>> "$wiki/view" <title-redirect> ] bi
+ ] >>submit ;
+
+: <list-revisions-action> ( -- action )
+ <page-action>
+ [
+ validate-title
+ f <revision> "title" value >>title select-tuples
+ [ [ date>> ] compare invert-comparison ] sort
+ "revisions" set-value
+ ] >>init
+
+ "revisions" wiki-template >>template ;
+
+: <delete-action> ( -- action )
+ <action>
+ [ validate-title ] >>validate
+
+ [
+ "title" value <article> delete-tuples
+ f <revision> "title" value >>title delete-tuples
+ "" f <standard-redirect>
+ ] >>submit ;
+
+: <diff-action> ( -- action )
+ <page-action>
+ [
+ {
+ { "old-id" [ v-integer ] }
+ { "new-id" [ v-integer ] }
+ } validate-params
+
+ "old-id" "new-id"
+ [ value <revision> select-tuple ] bi@
+ [ [ "old" set-value ] [ "new" set-value ] bi* ]
+ [ [ content>> string-lines ] bi@ diff "diff" set-value ]
+ 2bi
+ ] >>init
+
+ "diff" wiki-template >>template ;
+
+: <list-articles-action> ( -- action )
+ <page-action>
+ [ f <article> select-tuples "articles" set-value ] >>init
+ "articles" wiki-template >>template ;
+
+TUPLE: wiki < dispatcher ;
+
+: <wiki> ( -- dispatcher )
+ wiki new-dispatcher
+ <main-article-action> "" add-responder
+ <view-article-action> "view" add-responder
+ <view-revision-action> "revision" add-responder
+ <edit-article-action> { } <protected> "edit" add-responder
+ <list-revisions-action> "revisions" add-responder
+ <delete-action> "delete" add-responder
+ <diff-action> "diff" add-responder
+ <list-articles-action> "articles" add-responder
+ <boilerplate>
+ "wiki-common" wiki-template >>template ;