mirror of
https://github.com/journeyman-cc/smeagol.git
synced 2026-04-12 18:05:06 +00:00
That proved a little more convoluted than expected, but now works well.
This commit is contained in:
parent
06773bd6f7
commit
ebfefd3edb
6 changed files with 390 additions and 56 deletions
|
|
@ -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]].
|
||||||
|
|
|
||||||
296
resources/public/content/stylesheet.css
Normal file
296
resources/public/content/stylesheet.css
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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,7 +35,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="main-container" class="container">
|
<div id="main-container" class="container">
|
||||||
|
|
||||||
{% if message %}
|
{% if message %}
|
||||||
<div id="message">
|
<div id="message">
|
||||||
<p class="message">{{message}}</p>
|
<p class="message">{{message}}</p>
|
||||||
|
|
|
||||||
22
resources/templates/edit-css.html
Normal file
22
resources/templates/edit-css.html
Normal 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 %}
|
||||||
|
|
@ -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 %}
|
||||||
|
|
|
||||||
|
|
@ -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]
|
([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))
|
(let [params (keywordize-keys (:params request))
|
||||||
src-text (:src params)
|
src-text (:src params)
|
||||||
page (or (:page params) "Introduction")
|
page (or (:page params) default)
|
||||||
file-path (str (io/resource-path) "content/" page ".md")
|
file-path (str (io/resource-path) "content/" page suffix)
|
||||||
exists? (.exists (cjio/as-file file-path))]
|
exists? (.exists (cjio/as-file file-path))]
|
||||||
(if (not exists?) (timbre/info (format "File '%s' not found; creating a new 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)
|
(cond src-text (process-source params suffix)
|
||||||
true
|
true
|
||||||
(layout/render "edit.html"
|
(layout/render template
|
||||||
{:title (str "Edit " page)
|
{:title (str "Edit " page)
|
||||||
:page page
|
:page page
|
||||||
:left-bar (local-links (util/md->html "/content/_edit-left-bar.md"))
|
:left-bar (local-links (util/md->html left-bar))
|
||||||
:header (local-links (util/md->html "/content/_header.md"))
|
:header (local-links (util/md->html "/content/_header.md"))
|
||||||
:content (if exists? (io/slurp-resource (str "/content/" page ".md")) "")
|
:content (if exists? (io/slurp-resource (str "/content/" page suffix)) "")
|
||||||
:user (session/get :user)
|
:user (session/get :user)
|
||||||
:exists exists?}))))
|
:exists exists?})))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn edit-css-page
|
||||||
|
"Render a stylesheet in a text-area for editing.."
|
||||||
|
[request]
|
||||||
|
(edit-page request "stylesheet" ".css" "edit-css.html" "/content/_edit-left-bar.md"))
|
||||||
|
|
||||||
|
|
||||||
(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))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue