That proved a little more convoluted than expected, but now works well.

This commit is contained in:
simon 2016-08-21 12:19:54 +01:00
parent 06773bd6f7
commit ebfefd3edb
6 changed files with 390 additions and 56 deletions

View file

@ -57,4 +57,4 @@ Alternatively, if you want to deploy to a servlet container (which I would stron
## Editing the framing content ## Editing the framing content
You can edit the [[\_left-bar]], the [[\_edit-left-bar]], and the [[\_header]]. You can edit the [stylesheet](/edit-css?page=stylesheet), the [[\_left-bar]], the [[\_edit-left-bar]], and the [[\_header]].

View file

@ -0,0 +1,296 @@
/*
## Smeagol: a very simple Wiki engine
## Copyright and licence
Copyright (C) 2014 Simon Brooke
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
# The Stylesheet
*/
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
/* ids generally in document order */
/* top-of-page navigation, not editable, provided by Smeagol */
#nav{
margin: 0;
padding: 0;
top: 0;
width: 100%;
_position: absolute;
_top: expression(document.documentElement.scrollTop);
z-index: 149;
background:rgba(40,40,40,0.8);
}
#user {
font-height: 66%;
float: right;
padding: 0.1em 0.75em;
margin: 0;
color: white;
}
#user a {
color: silver;
}
/* only needed for fly-out menu effect on tablet and phone stylesheets */
#nav-icon {
display: none;
}
#nav-menu {
margin: 0;
padding: 0;
}
#nav ul li {
padding: 0;
margin: 0;
display: inline;
}
#nav ul li a {
color: white;
text-decoration: none;
font-weight: bold;
padding: 0.1em 0.75em;
margin: 0;
}
#nav ul li.active a { background: silver;}
li.nav-item a:hover { background: rgb( 240, 240, 240) }
li.nav-item a:active { background: gray; color: white; }
/* Overall container div, holds all content of page. Yes, I know it shouldn't have fixed width */
#main-container{
}
/* header for all pages in the Wiki - editable, provided by users. Within main-container */
#header {
margin-top: 0;
width:100%;
background-color: gray;
color: white;
}
#header h1 {
margin-top: 0;
}
/* left bar for all pages in the Wiki - editable, provided by users. Within main-container */
#left-bar {
width: 17%;
height: 100%;
float: left;
}
/* content of the current in the Wiki - editable, provided by users. Within main-container */
#content {
border: thin solid silver;
width: 80%;
float: right;
padding-bottom: 5em;
}
/* cookies information box, fixed, in right margin, just above footer */
#cookies {
width: 30%;
float: right;
position: fixed;
bottom: 1.5em;
right: 0;
z-index: 150;
background: transparent;
}
/* about-cookies box: permanently visible part of cookies information box */
#about-cookies {
clear: right;
width: 10em;
font-size: 66%;
float: right;
text-align: right;
padding: 0.25em 2em;
color: white;
background:rgba(40,40,40,0.8);
}
/* more-about-cookies box, normally hidden */
#more-about-cookies {
display: none;
padding: 0.25em 2em;
color: white;
background:rgba(40,40,40,0.8);
border-bottom: thin solid white;
}
/* but magically appears on mouseover */
#cookies:hover #more-about-cookies {
display: block;
}
/* footer of the page - not-editable, provided by Smeagol */
#footer {
clear: both;
font-size: smaller;
text-align: center;
color:white;
background:rgba(128,128,128,0.95);
width: 100%;
margin: 0;
padding: 0.25em 0;
bottom:0;
position:fixed;
vertical-align: top;
z-index:150;
_position:absolute;
_top:expression(eval(document.documentElement.scrollTop+
(document.documentElement.clientHeight-this.offsetHeight)));
}
.change {
background-color: rgb( 223, 223, 223);
border: thin solid silver;
}
.error {
width: 100%;
background-color: red;
color: white;
}
.message {
border: thin solid red;
}
.minor-controls {
list-style: none;
float: right;
padding: 0.25em 2em;
color: white;
background:rgba(40,40,40,0.8);
font-size: 66%;
}
.minor-controls li {
display: inline;
}
.minor-controls a {
float: right;
padding: 0.25em 2em;
color: white;
}
.warn {
color: maroon;
}
.widget {
background-color: silver;
border: thin solid white;
margin-top: 0;
margin-bottom: 0;
width: 100%;
}
.wiki {
margin: 0;
}
form {
border: thin solid silver;
}
del {
color: red;
}
div.content, form, p, pre, h1, h2, h3, h4, h5 {
padding: 0.25em 5%;
}
dl, menu, ol, table, ul {
margin: 0.25em 5%;
}
input {
background-color: white;
}
input.action {
background-color: green;
}
input.action-dangerous {
color: white;
background-color: red;
}
input.required:after {
content: " \*";
color: red;
}
ins {
color: green;
}
label {
width: 20%;
min-width: 20em;
border-right: thin solid gray;
}
menu li {
display: inline;
}
menu li::before {
content: "|| ";
}
table {
border: 2px solid black;
border-collapse: collapse;
}
table.music-ruled tr:nth-child(odd) {
background-color: silver;
}
th, td {
text-align: left;
vertical-align: top;
padding: 0.15em 1.5em;
border: 1px solid gray;
}
th {
background-color: silver;
}

View file

@ -3,11 +3,8 @@
<head> <head>
<title>{{title}}</title> <title>{{title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="{{servlet-context}}/css/phone.css" media="only screen and (max-device-width: 480px)" rel="stylesheet" type="text/css" /> <link href="{{servlet-context}}/content/stylesheet.css" media="screen and (min-device-width: 1025px)" rel="stylesheet" type="text/css" />
<link href="{{servlet-context}}/css/tablet.css" media="only screen and (min-device-width: 481px) and (max-device-width: 1024px)" rel="stylesheet" type="text/css" />
<link href="{{servlet-context}}/css/standard.css" media="screen and (min-device-width: 1025px)" rel="stylesheet" type="text/css" />
<link href="{{servlet-context}}/css/print.css" media="print" rel="stylesheet" type="text/css" /> <link href="{{servlet-context}}/css/print.css" media="print" rel="stylesheet" type="text/css" />
<link href="{{servlet-context}}/css/states.css" rel="stylesheet" type="text/css" />
{% block extra-headers %} {% block extra-headers %}
{% endblock %} {% endblock %}
</head> </head>
@ -22,7 +19,6 @@
<img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/> <img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/>
<ul id="nav-menu" class="nav"> <ul id="nav-menu" class="nav">
<li class="{{wiki-selected}}"><a href="{{servlet-context}}/">Home</a></li> <li class="{{wiki-selected}}"><a href="{{servlet-context}}/">Home</a></li>
<li class="{{edit-selected}}"><a href="{{servlet-context}}/edit?page={{title}}">Edit this page</a></li>
<li class="{{auth-selected}}"><a href="{{servlet-context}}/auth"> <li class="{{auth-selected}}"><a href="{{servlet-context}}/auth">
{% if user %} {% if user %}
Log out Log out
@ -39,31 +35,30 @@
</div> </div>
<div id="main-container" class="container"> <div id="main-container" class="container">
{% if message %}
<div id="message">
<p class="message">{{message}}</p>
</div>
{% endif %}
{% if error %}
<div id="error">
<p class="error">{{error}}</p>
</div>
{% endif %}
{% if message %} {% block content %}
<div id="message"> {% endblock %}
<p class="message">{{message}}</p>
</div>
{% endif %}
{% if error %}
<div id="error">
<p class="error">{{error}}</p>
</div>
{% endif %}
{% block content %}
{% endblock %}
</div> </div>
<div id="cookies"> <div id="cookies">
<div id="more-about-cookies"> <div id="more-about-cookies">
This website stores session information as a 'cookie' on your browser. This helps us show you the content This website stores session information as a 'cookie' on your browser. This helps us show you the content
you want to see. This cookie does not identify you, and cannot be read by other websites. It is deleted by you want to see. This cookie does not identify you, and cannot be read by other websites. It is deleted by
your browser as soon as you leave this site. This website does not use any third party cookies, so your your browser as soon as you leave this site. This website does not use any third party cookies, so your
visit here cannot be tracked by other websites. visit here cannot be tracked by other websites.
</div> </div>
<div id="about-cookies"> <div id="about-cookies">
About cookies About cookies
</div> </div>
</div> </div>
<div id="footer"> <div id="footer">
<div id="credits"> <div id="credits">

View file

@ -0,0 +1,22 @@
{% extends "templates/base.html" %}
{% block content %}
<div id="content" class="edit">
<form action="{{servlet-context}}/edit-css" method="POST">
<input type="hidden" name="page" value="{{page}}"/>
<textarea name="src" id="src" rows="25" cols="80">{{content}}</textarea>
<p class="widget">
<label for="summary">What have you changed?</label>
<input name="summary" id="summary" type="text"
value="{%if exists%}{%else%}New file {{title}}{%endif%}" required/>
</p>
<p class="widget">
<label for="submit">When you have finished editing</label>
<input name="submit" id="submit" type="submit" class="action" value="Save!"/>
</p>
</form>
</div>
<script>
var simplemde = new SimpleMDE();
</script>
{% endblock %}

View file

@ -1,9 +1,11 @@
{% extends "templates/base.html" %} {% extends "templates/base.html" %}
{% block content %} {% block content %}
<div id="content" class="wiki"> <div id="content" class="wiki">
<div class="minor-controls"> <ul class="minor-controls">
<a href="history?page={{page}}">History</a> <li><a href="{{servlet-context}}/edit?page={{title}}">Edit this page</a></li>
</div> <li><a href="history?page={{page}}">History</a></li>
</ul>
{{content|safe}} {{content|safe}}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -2,11 +2,12 @@
:author "Simon Brooke"} :author "Simon Brooke"}
smeagol.routes.wiki smeagol.routes.wiki
(:require [clojure.walk :refer :all] (:require [clojure.walk :refer :all]
[clojure.java.io :as cjio]
[clojure.string :as cs]
[compojure.core :refer :all] [compojure.core :refer :all]
[clj-jgit.porcelain :as git] [clj-jgit.porcelain :as git]
[cemerick.url :refer (url url-encode url-decode)] [cemerick.url :refer (url url-encode url-decode)]
[markdown.core :as md] [markdown.core :as md]
[clojure.java.io :as cjio]
[noir.io :as io] [noir.io :as io]
[noir.response :as response] [noir.response :as response]
[noir.util.route :as route] [noir.util.route :as route]
@ -44,11 +45,14 @@
(defn local-links (defn local-links
"Rewrite text in `html-src` surrounded by double square brackets as a local link into this wiki." "Rewrite text in `html-src` surrounded by double square brackets as a local link into this wiki."
[^String html-src] [^String html-src]
(clojure.string/replace html-src #"\[\[[^\[\]]*\]\]" (cs/replace html-src #"\[\[[^\[\]]*\]\]"
#(let [text (clojure.string/replace %1 #"[\[\]]" "") #(let [text (clojure.string/replace %1 #"[\[\]]" "")
encoded (url-encode text)] encoded (url-encode text)
(timbre/debug (format "URL encode: '%s' -> '%s'" text encoded)) ;; I use '\_' to represent '_' in wiki markup, because
(format "<a href='wiki?page=%s'>%s</a>" encoded text)))) ;; '_' is meaningful in Markdown. However, this needs to
;; be stripped out when interpreting local links.
munged (cs/replace encoded #"%26%2395%3B" "_")]
(format "<a href='wiki?page=%s'>%s</a>" munged text))))
(defn get-git-repo (defn get-git-repo
@ -63,10 +67,10 @@
(defn process-source (defn process-source
"Process `source-text` and save it to the specified `file-path`, committing it "Process `source-text` and save it to the specified `file-path`, committing it
to Git and finally redirecting to wiki-page." to Git and finally redirecting to wiki-page."
[params] [params suffix]
(let [source-text (:src params) (let [source-text (:src params)
page (:page params) page (:page params)
file-name (str page ".md") file-name (str page suffix)
file-path (str (io/resource-path) "/content/" file-name) file-path (str (io/resource-path) "/content/" file-name)
exists? (.exists (clojure.java.io/as-file file-path)) exists? (.exists (clojure.java.io/as-file file-path))
git-repo (get-git-repo) git-repo (get-git-repo)
@ -77,30 +81,43 @@
(spit file-path source-text) (spit file-path source-text)
(if (not exists?) (git/git-add git-repo file-name)) (if (not exists?) (git/git-add git-repo file-name))
(git/git-commit git-repo summary {:name user :email email}) (git/git-commit git-repo summary {:name user :email email})
(response/redirect (str "/wiki?page=" (url-encode page))) (response/redirect
)) (str
"/wiki?page="
(if
(= suffix ".md")
(url-encode page)
"Introduction")))))
(defn edit-page (defn edit-page
"Render a page in a text-area for editing. This could have been done in the same function as wiki-page, "Render a page in a text-area for editing. This could have been done in the same function as wiki-page,
and that would have been neat, but I couldn't see how to establish security if that were done." and that would have been neat, but I couldn't see how to establish security if that were done."
([request]
(edit-page request "Introduction" ".md" "edit.html" "/content/_edit-left-bar.md"))
([request default suffix template left-bar]
(let [params (keywordize-keys (:params request))
src-text (:src params)
page (or (:page params) default)
file-path (str (io/resource-path) "content/" page suffix)
exists? (.exists (cjio/as-file file-path))]
(if (not exists?) (timbre/info (format "File '%s' not found; creating a new file" file-path)))
(cond src-text (process-source params suffix)
true
(layout/render template
{:title (str "Edit " page)
:page page
:left-bar (local-links (util/md->html left-bar))
:header (local-links (util/md->html "/content/_header.md"))
:content (if exists? (io/slurp-resource (str "/content/" page suffix)) "")
:user (session/get :user)
:exists exists?})))))
(defn edit-css-page
"Render a stylesheet in a text-area for editing.."
[request] [request]
(let [params (keywordize-keys (:params request)) (edit-page request "stylesheet" ".css" "edit-css.html" "/content/_edit-left-bar.md"))
src-text (:src params)
page (or (:page params) "Introduction")
file-path (str (io/resource-path) "content/" page ".md")
exists? (.exists (cjio/as-file file-path))]
(if (not exists?) (timbre/info (format "File '%s' not found; creating a new file" file-path)))
(cond src-text (process-source params)
true
(layout/render "edit.html"
{:title (str "Edit " page)
:page page
:left-bar (local-links (util/md->html "/content/_edit-left-bar.md"))
:header (local-links (util/md->html "/content/_header.md"))
:content (if exists? (io/slurp-resource (str "/content/" page ".md")) "")
:user (session/get :user)
:exists exists?}))))
(defn wiki-page (defn wiki-page
@ -236,6 +253,8 @@
(GET "/" request (wiki-page request)) (GET "/" request (wiki-page request))
(GET "/edit" request (route/restricted (edit-page request))) (GET "/edit" request (route/restricted (edit-page request)))
(POST "/edit" request (route/restricted (edit-page request))) (POST "/edit" request (route/restricted (edit-page request)))
(GET "/edit-css" request (route/restricted (edit-css-page request)))
(POST "/edit-css" request (route/restricted (edit-css-page request)))
(GET "/history" request (history-page request)) (GET "/history" request (history-page request))
(GET "/version" request (version-page request)) (GET "/version" request (version-page request))
(GET "/changes" request (diff-page request)) (GET "/changes" request (diff-page request))