War on TODOs

Improved mermaid and photoswipe extensions, handled control-s on the edit page.
This commit is contained in:
Simon Brooke 2020-02-20 12:35:00 +00:00
parent ac433c3afa
commit c19580a23e
No known key found for this signature in database
GPG key ID: A7A4F18D1D4DF987
10 changed files with 142 additions and 61 deletions

View file

@ -13,7 +13,7 @@ That's all there is to it - a sequence of image links just as you'd write them a
## The Gallery
This page holds another example Photoswipe gallery, this time using a simpler, Markdown-based specification. Processing this specification takes more work than the full syntax used in the other [[Example gallery]], so the gallery may be slower to load; but it's much easier to configure.
This page holds another example Photoswipe gallery, this time using a simpler, Markdown-based specification. Processing this specification takes more work than the full syntax used in the other [[Example gallery]], so the gallery may be slower to load; but it's much easier to configure. To see it, <a href="edit?page=Simplified%20example%20gallery">edit this page.</a>
```pswp
![Frost on a gate, Laurieston](content/uploads/g1.jpg)

View file

@ -11,7 +11,7 @@
{% block content %}
<div id="content" class="edit">
<form action="{{servlet-context}}/edit" method="POST">
<form id="edit-form" action="{{servlet-context}}/edit" method="POST">
{% csrf-field %}
<input type="hidden" name="page" value="{{page}}"/>
<textarea name="src" id="src" rows="25" cols="80">{{content}}</textarea>
@ -21,12 +21,20 @@
value="{%if exists%}{%else%}New file {{page}}{%endif%}" required/>
</p>
<p class="widget">
<label for="submit">{% i18n save-prompt %}</label>
<input name="submit" id="submit" type="submit" class="action" value="{% i18n save-label %}"/>
<label for="submit-button">{% i18n save-prompt %}</label>
<input name="submit-button" id="submit-button" type="submit" class="action" value="{% i18n save-label %}"/>
</p>
</form>
</div>
<script>
// intercept control-S (or on Mac meta-S) and submit the form. Saves much annoyance.
document.addEventListener("keydown", function(e) {
if (e.keyCode == 83 && (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey)) {
e.preventDefault();
document.getElementById('edit-form').submit();
}
}, false);
// initialise the editor
var simplemde = new SimpleMDE({
autosave: {
enabled: true,

View file

@ -17,14 +17,4 @@
{% endif %}
{{content|safe}}
</div>
<script>
//<![CDATA[
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function(event) {
mermaid.initialize({startOnLoad:true});
});
}
//]]
</script>
{% endblock %}

View file

@ -79,7 +79,22 @@
(log/info "Retrieved graph-spec from " (:from data) " `" ((:from data) data) "`")
(str "<div class=\"mermaid data-visualisation\" id=\"mermaid" index "\">\n"
graph-spec
"\n</div>")))
"\n</div>
<script>
//<![CDATA[
/* don't do this twice! */
if ( document.mermaidListenerAdded != true)
{
if (document.addEventListener) {
document.addEventListener(\"DOMContentLoaded\", function(event) {
mermaid.initialize({startOnLoad:true});
});
document.mermaidListenerAdded = true;
}
}
//]]
</script>
")))
;; (fs/file? (str (nio/resource-path) "data/classes.mermaid"))
;; (slurp (str (nio/resource-path) "data/classes.mermaid"))

View file

@ -42,11 +42,14 @@
specification based on that documented on the Photoswipe website."
[^String spec ^Integer index]
(str
"<div class=\"pswp\" id=\"pswp-"
"<div class='gallery'>
<div class=\"pswp\" id=\"pswp-"
index "\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\">\n"
(slurp
(str (io/resource-path) "html-includes/photoswipe-boilerplate.html"))
"</div>
<p><button id=\"open-gallery-" index "\" onclick=\"gallery" index
".init(); document.getElementById(`open-gallery-" index "`).style.display = 'none';\">Open the gallery</button></p>
<script>
\n//<![CDATA[\n
var pswpElement = document.getElementById('pswp-" index "');
@ -56,11 +59,12 @@
var gallery" index
" = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, spec"
index ".slides, spec" index ".options);
if (spec" index ".openImmediately) { gallery" index ".init(); }
if (spec" index ".openImmediately) {
document.getElementById(`open-gallery-" index "`).style.display = 'none';
gallery" index ".init();
}
\n//]]\n
</script>
<p><button onclick=\"gallery" index
".init()\">Open the gallery</button></p>
</div>"))
@ -68,19 +72,25 @@
"Parser to transform a sequence of Markdown image links into something we
can build into JSON. Yes, this could all have been done with regexes, but
they are very inscrutable."
(insta/parser "SLIDE := START-CAPTION title END-CAPTION src END-SRC;
(insta/parser "SLIDES := SLIDE | SLIDE SPACE SLIDES;
SLIDE := START-CAPTION title END-CAPTION src END-SRC;
START-CAPTION := '![' ;
END-CAPTION := '](' ;
END-SRC := ')' ;
title := #'[^]]*' ;
src := #'[^)]*' ;
SPACE := #'[\\r\\n\\W]*'"))
SPACE := #'[\\s]*'"))
(defn- simplify
(defn simplify
"Simplify a parse-`tree` created by `simple-grammar`, q.v."
[tree]
(if
(coll? tree)
(case (first tree)
:SLIDES (cons
(simplify (first (rest tree)))
(first (simplify (rest (rest tree)))))
:SLIDE (remove empty? (map simplify (rest tree)))
:title tree
:src tree
@ -89,6 +99,7 @@
:END-SRC nil
(remove empty? (map simplify tree)))))
(defn slide-merge-dimensions
"If this `slide` appears to be local, return it decorated with the
dimensions of the image it references."
@ -109,29 +120,40 @@
;; {:title "Frost on a gate, Laurieston",
;; :src "content/uploads/g1.jpg"})
(defn- process-simple-slide
[slide-spec]
(let [s (simplify (simple-grammar slide-spec))
s'(zipmap (map first s) (map #(nth % 1) s))
(defn find-thumb
[url thumbsize]
(if
(and
(uploaded? url)
thumbsize)
(let [p (str (cio/file "uploads" (name thumbsize) (fs/base-name url)))
p' (cio/file content-dir p)
r (str (cio/file "content" p))]
(if
(and (fs/exists? p') (fs/readable? p'))
r))))
(defn process-simple-slide
"Process a single `slide`, as decoded by `simple-grammar`. At this stage a
slide is expected to be represented as a sequence of vectors, one for each
property of the slide (`:title`, `:src`). Each vector contains the name of
the property as a keyword as its first element, and the value of the
property as its second element.
Returns a map of these properties, with, if possible, `:w` (width), `:h`
(height), and `:msrc` (source URL of a low resolution variant) added."
[slide]
(let [s' (zipmap (map first slide) (map #(nth % 1) slide))
thumbsizes (:thumbnails config)
thumbsize (first
(sort
#(> (%1 thumbsizes) (%2 thumbsizes))
(keys thumbsizes)))
url (:url s')
thumb (if
(and
(uploaded? url)
thumbsize)
(let [p (str (cio/file "uploads" (name thumbsize) (fs/base-name url)))
p' (cio/file content-dir p)]
(if
(and (fs/exists? p') (fs/readable? p'))
p)))]
url (:src s')]
(slide-merge-dimensions
(if thumb
(assoc s' :msrc thumb)
s'))))
(assoc s' :msrc (find-thumb url thumbsize)))))
(process-simple-slide '([:title "Frost on a gate, Laurieston"] [:src "content/uploads/g1.jpg"]))
(def process-simple-photoswipe
"Process a simplified specification for a photoswipe gallery, comprising just
@ -144,8 +166,7 @@
(json/write-str
{:slides (map
process-simple-slide
(re-seq #"!\[[^(]*\([^)]*\)" spec))
;; TODO: better to split slides in instaparse
(simplify (simple-grammar spec)))
:options { :timeToIdle 100 }
:openImmediately true}) index))))
@ -157,12 +178,12 @@
;; ![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
;; ![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)"))
;; (process-simple-photoswipe
;; "![Frost on a gate, Laurieston](content/uploads/g1.jpg)
;; ![Feathered crystals on snow surface, Taliesin](content/uploads/g2.jpg)
;; ![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
;; ![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)"
;; 1)
(process-simple-photoswipe
"![Frost on a gate, Laurieston](content/uploads/g1.jpg)
![Feathered crystals on snow surface, Taliesin](content/uploads/g2.jpg)
![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)"
1)
(defn process-photoswipe
"Process a Photoswipe specification which may conform either to the

View file

@ -165,10 +165,6 @@
([inclusions text]
(let [ks (keys inclusions)]
(if (empty? (keys inclusions))
;; TODO: this is one opportunity to add scripts at the end of the
;; constructed text. I've a feeling that that would be a mistake and
;; that instead we should hand back a map comprising the text and the
;; keys of the extensions
text
(let [kw (first ks)]
(reintegrate-inclusions

View file

@ -29,7 +29,8 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Error to show if text to be rendered is nil.
;; TODO: this should go through i18n
;; TODO: this should go through i18n, but for that to happen we need the
;; request passed through to here.
(def no-text-error "No text: does the file exist?")

View file

@ -320,14 +320,14 @@
uploaded (if upload (ul/store-upload params data-path))
user (session/get :user)
summary (format "%s: %s" user (or (:summary params) "no summary"))]
;; TODO: Get this working! it MUST work!
;; (if-not
;; (empty? uploaded)
;; (do
;; (map
;; #(git/git-add git-repo (str :resource %))
;; (remove nil? uploaded))
;; (git/git-commit git-repo summary {:name user :email (auth/get-email user)})))
(log/info (session/get :user) "has uploaded" (cs/join "; " (map :resource uploaded)))
(if-not
(empty? uploaded)
(do
(map
#(git/git-add git-repo (str :resource %))
(remove nil? uploaded))
(git/git-commit git-repo summary {:name user :email (auth/get-email user)})))
(layout/render "upload.html"
(merge (util/standard-params request)
{:title (util/get-message :file-upload-title request)
@ -408,7 +408,13 @@
(defn wrap-restricted-redirect
;; TODO: this is not idiomatic, and it's too late to write something idiomatic just now
;; TODO TODO: it's also not working.
;; TODO: probably I need to use either the 'buddy' or 'friend' authentication libraries
;; see https://github.com/cemerick/friend and
;; https://github.com/metosin/compojure-api/wiki/Authentication-and-Authorization
;; but I don't yet see even so how to do redirect to the failed page after successful
;; authorisation.
[f request]
(log/info "wrap-restricted-redirect: f:" f "; request " (with-out-str (clojure.pprint/pprint request)))
(route/restricted
(apply
f

View file

@ -0,0 +1,45 @@
(ns smeagol.test.extensions.photoswipe
(:require [clojure.test :refer :all]
[clojure.string :as cs]
[smeagol.extensions.photoswipe :refer :all]))
(deftest simple-syntax-tests
(testing "Process simple slide"
(let [expected {:title "Frost on a gate, Laurieston",
:src "content/uploads/g1.jpg",
:w 2592,
:h 1944
:msrc "content/uploads/med/g1.jpg"}
actual (process-simple-slide
'([:title "Frost on a gate, Laurieston"]
[:src "content/uploads/g1.jpg"]))]
(is (= actual expected))))
(testing "Find thumbnail"
(let [expected "content/uploads/med/g1.jpg"
actual (find-thumb "content/uploads/g1.jpg" :med)]
(is (= actual expected) "`resources/content/uploads/med/g1.jpg` is in
the repository, so should be found"))
(let [expected nil
actual (find-thumb "passwd" :med)]
(is (= actual expected) "`resources/passwd` is in
the repository, but is not uploaded so should NOT be found")))
(testing "Simple slide grammar"
(let [expected '(([:title "Frost on a gate, Laurieston"] [:src "content/uploads/g1.jpg"]))
actual (simplify
(simple-grammar
"![Frost on a gate, Laurieston](content/uploads/g1.jpg)"))]
(is (= actual expected) "Valid syntax, should parse")
(is (empty? (simplify (simple-grammar "[Fred](fred.jpg)")))
"Invalid syntax (no leading `!`), should not parse."))
(let [expected '(([:title "Frost on a gate, Laurieston"] [:src "content/uploads/g1.jpg"])
([:title "Feathered crystals on snow surface, Taliesin"] [:src "content/uploads/g2.jpg"])
([:title "Feathered snow on log, Taliesin"] [:src "content/uploads/g3.jpg"])
([:title "Crystaline growth on seed head, Taliesin"] [:src "content/uploads/g4.jpg"]))
actual (simplify
(simple-grammar
"![Frost on a gate, Laurieston](content/uploads/g1.jpg)
![Feathered crystals on snow surface, Taliesin](content/uploads/g2.jpg)
![Feathered snow on log, Taliesin](content/uploads/g3.jpg)
![Crystaline growth on seed head, Taliesin](content/uploads/g4.jpg)"))]
(is (= actual expected) "Valid syntax, should parse"))))

View file

@ -1,7 +1,6 @@
(ns smeagol.test.local-links
(:require [clojure.test :refer :all]
[clojure.string :as cs]
[smeagol.local-links :refer [local-links no-text-error]]
[smeagol.extensions.test :refer :all]
[smeagol.local-links :refer :all]))