From c19580a23e503c3a8e6cf3a1f7fbe5830d0c7f66 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 20 Feb 2020 12:35:00 +0000 Subject: [PATCH] War on TODOs Improved mermaid and photoswipe extensions, handled control-s on the edit page. --- .../content/Simplified example gallery.md | 2 +- resources/templates/edit.html | 14 ++- resources/templates/wiki.html | 10 --- src/smeagol/extensions/mermaid.clj | 17 +++- src/smeagol/extensions/photoswipe.clj | 85 ++++++++++++------- src/smeagol/formatting.clj | 4 - src/smeagol/local_links.clj | 3 +- src/smeagol/routes/wiki.clj | 22 +++-- test/smeagol/test/extensions/photoswipe.clj | 45 ++++++++++ test/smeagol/test/local_links.clj | 1 - 10 files changed, 142 insertions(+), 61 deletions(-) create mode 100644 test/smeagol/test/extensions/photoswipe.clj diff --git a/resources/public/content/Simplified example gallery.md b/resources/public/content/Simplified example gallery.md index eac0394..32dc0bc 100644 --- a/resources/public/content/Simplified example gallery.md +++ b/resources/public/content/Simplified example gallery.md @@ -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, edit this page. ```pswp ![Frost on a gate, Laurieston](content/uploads/g1.jpg) diff --git a/resources/templates/edit.html b/resources/templates/edit.html index 44ee54a..840491d 100644 --- a/resources/templates/edit.html +++ b/resources/templates/edit.html @@ -11,7 +11,7 @@ {% block content %}
-
+ {% csrf-field %} @@ -21,12 +21,20 @@ value="{%if exists%}{%else%}New file {{page}}{%endif%}" required/>

- - + +

{% endblock %} diff --git a/src/smeagol/extensions/mermaid.clj b/src/smeagol/extensions/mermaid.clj index 6185b5d..60cf04f 100644 --- a/src/smeagol/extensions/mermaid.clj +++ b/src/smeagol/extensions/mermaid.clj @@ -79,7 +79,22 @@ (log/info "Retrieved graph-spec from " (:from data) " `" ((:from data) data) "`") (str "
\n" graph-spec - "\n
"))) + "\n + + "))) ;; (fs/file? (str (nio/resource-path) "data/classes.mermaid")) ;; (slurp (str (nio/resource-path) "data/classes.mermaid")) diff --git a/src/smeagol/extensions/photoswipe.clj b/src/smeagol/extensions/photoswipe.clj index d145943..766fef0 100644 --- a/src/smeagol/extensions/photoswipe.clj +++ b/src/smeagol/extensions/photoswipe.clj @@ -42,11 +42,14 @@ specification based on that documented on the Photoswipe website." [^String spec ^Integer index] (str - "
+
\n" (slurp (str (io/resource-path) "html-includes/photoswipe-boilerplate.html")) "
+

-

")) @@ -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 diff --git a/src/smeagol/formatting.clj b/src/smeagol/formatting.clj index 8f0d92b..a2d245e 100644 --- a/src/smeagol/formatting.clj +++ b/src/smeagol/formatting.clj @@ -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 diff --git a/src/smeagol/local_links.clj b/src/smeagol/local_links.clj index f1bed0b..0fdf09c 100644 --- a/src/smeagol/local_links.clj +++ b/src/smeagol/local_links.clj @@ -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?") diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index 27ec424..17c46a4 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -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 diff --git a/test/smeagol/test/extensions/photoswipe.clj b/test/smeagol/test/extensions/photoswipe.clj new file mode 100644 index 0000000..34674ea --- /dev/null +++ b/test/smeagol/test/extensions/photoswipe.clj @@ -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")))) diff --git a/test/smeagol/test/local_links.clj b/test/smeagol/test/local_links.clj index dc3682d..e02d727 100644 --- a/test/smeagol/test/local_links.clj +++ b/test/smeagol/test/local_links.clj @@ -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]))