mirror of
https://github.com/journeyman-cc/smeagol.git
synced 2026-04-12 18:05:06 +00:00
Simplified syntax for Photoswipe galleries now works
This commit is contained in:
parent
fc4dcdb5d3
commit
d2e20162ef
10 changed files with 283 additions and 83 deletions
|
|
@ -17,6 +17,7 @@
|
|||
[hiccup "1.0.5"]
|
||||
[im.chit/cronj "1.4.4"]
|
||||
[image-resizer "0.1.10"]
|
||||
[instaparse "1.4.10"]
|
||||
[lib-noir "0.9.9" :exclusions [org.clojure/tools.reader]]
|
||||
[markdown-clj "0.9.99" :exclusions [com.keminglabs/cljx]]
|
||||
[me.raynes/fs "1.4.6"]
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
"vis" smeagol.formatting/process-vega
|
||||
"mermaid" smeagol.extensions.mermaid/process-mermaid
|
||||
"backticks" smeagol.formatting/process-backticks
|
||||
"pswp" smeagol.formatting/process-photoswipe}
|
||||
"pswp" smeagol.extensions.photoswipe/process-photoswipe}
|
||||
:log-level :info ;; the minimum logging level; one of
|
||||
;; :trace :debug :info :warn :error :fatal
|
||||
:js-from :cdnjs ;; where to load JavaScript libraries
|
||||
|
|
|
|||
|
|
@ -1,26 +1,3 @@
|
|||
## The Gallery
|
||||
|
||||
This page holds an example Photoswipe gallery.
|
||||
|
||||
```pswp
|
||||
{
|
||||
slides: [
|
||||
{ src: 'content/uploads/g1.jpg', w: 2592, h:1944,
|
||||
title: 'Frost on a gate, Laurieston' },
|
||||
{ src: 'content/uploads/g2.jpg', w: 2560, h:1920,
|
||||
title: 'Feathered crystals on snow surface, Taliesin' },
|
||||
{ src: 'content/uploads/g3.jpg', w: 2560, h:1920,
|
||||
title: 'Feathered snow on log, Taliesin' },
|
||||
{ src: 'content/uploads/g4.jpg', w: 2560, h:1920,
|
||||
title: 'Crystaline growth on seed head, Taliesin' }],
|
||||
options: {
|
||||
timeToIdle: 100
|
||||
},
|
||||
openImmediately: true
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## How this works
|
||||
|
||||
The specification for this gallery is as follows:
|
||||
|
|
@ -57,3 +34,27 @@ Optional. The value of `options` is a JSON object [as documented here](https://p
|
|||
### openImmediately
|
||||
|
||||
Optional. If the value of `openImmediately` is `true`, the gallery will open immediately, covering the whole page. If false, only a button with the label 'Open the gallery' will be shown. Selecting this button will cause the gallery to open.
|
||||
|
||||
## The Gallery
|
||||
|
||||
This page holds an example Photoswipe gallery.
|
||||
|
||||
```pswp
|
||||
{
|
||||
slides: [
|
||||
{ src: 'content/uploads/g1.jpg', w: 2592, h:1944,
|
||||
title: 'Frost on a gate, Laurieston' },
|
||||
{ src: 'content/uploads/g2.jpg', w: 2560, h:1920,
|
||||
title: 'Feathered crystals on snow surface, Taliesin' },
|
||||
{ src: 'content/uploads/g3.jpg', w: 2560, h:1920,
|
||||
title: 'Feathered snow on log, Taliesin' },
|
||||
{ src: 'content/uploads/g4.jpg', w: 2560, h:1920,
|
||||
title: 'Crystaline growth on seed head, Taliesin' }],
|
||||
options: {
|
||||
timeToIdle: 100
|
||||
},
|
||||
openImmediately: true
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -68,9 +68,8 @@ data/classes.mermaid
|
|||
|
||||
## Photoswipe galleries
|
||||
|
||||
Not so much a formatter, this is an extension to allow you to embed image galleries in your markdown. To specify a gallery, use three backticks followed by `pswp`, followed on the following lines by a Photoswipe specification in [JSON](https://www.json.org/json-en.html)
|
||||
followed by three backticks on a line by themselves. There is an [[Example gallery]] so that you can see how this works.
|
||||
|
||||
Not so much a formatter, this is an extension to allow you to embed image galleries in your markdown. To specify a gallery, use three backticks followed by `pswp`, followed on the following lines by a [Photoswipe](https://photoswipe.com/documentation/getting-started.html) specification in [JSON](https://www.json.org/json-en.html)
|
||||
followed by three backticks on a line by themselves. There is an [[Example gallery]] with the full PhotoSwipe configuration, and a [[Simplified example gallery]] using a much simpler syntax, so that you can see how this works.
|
||||
|
||||
## Writing your own custom formatters
|
||||
|
||||
|
|
|
|||
24
resources/public/content/Simplified example gallery.md
Normal file
24
resources/public/content/Simplified example gallery.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
## How this works
|
||||
|
||||
The specification for this gallery is as follows:
|
||||
|
||||
```
|
||||

|
||||

|
||||

|
||||

|
||||
```
|
||||
|
||||
That's all there is to it - a sequence of image links just as you'd write them anywhere else in the wiki.
|
||||
|
||||
## 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.
|
||||
|
||||
```pswp
|
||||

|
||||

|
||||

|
||||

|
||||
```
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
(ns ^{:doc "Format Semagol's extended markdown format."
|
||||
(ns ^{:doc "Mermaid formatter for Semagol's extendsible markdown format."
|
||||
:author "Simon Brooke"}
|
||||
smeagol.extensions.mermaid
|
||||
(:require [smeagol.extensions.utils :refer :all]
|
||||
|
|
|
|||
181
src/smeagol/extensions/photoswipe.clj
Normal file
181
src/smeagol/extensions/photoswipe.clj
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
(ns ^{:doc "Photoswipe gallery formatter for Semagol's extendsible markdown
|
||||
format."
|
||||
:author "Simon Brooke"}
|
||||
smeagol.extensions.photoswipe
|
||||
(:require [clojure.data.json :as json]
|
||||
[clojure.java.io :as cio]
|
||||
[clojure.string :as cs]
|
||||
[image-resizer.util :refer [buffered-image dimensions]]
|
||||
[instaparse.core :as insta]
|
||||
[me.raynes.fs :as fs]
|
||||
[noir.io :as io]
|
||||
[smeagol.configuration :refer [config]]
|
||||
[smeagol.extensions.utils :refer :all]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; Smeagol: a very simple Wiki engine.
|
||||
;;;;
|
||||
;;;; 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.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2017 Simon Brooke
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn process-full-photoswipe
|
||||
"Process a specification for a photoswipe gallery, using a JSON
|
||||
specification based on that documented on the Photoswipe website."
|
||||
[^String spec ^Integer index]
|
||||
(str
|
||||
"<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>
|
||||
<script>
|
||||
\n//<![CDATA[\n
|
||||
var pswpElement = document.getElementById('pswp-" index "');
|
||||
var spec" index " = "
|
||||
spec
|
||||
";
|
||||
var gallery" index
|
||||
" = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, spec"
|
||||
index ".slides, spec" index ".options);
|
||||
if (spec" index ".openImmediately) { gallery" index ".init(); }
|
||||
\n//]]\n
|
||||
</script>
|
||||
<p><button onclick=\"gallery" index
|
||||
".init()\">Open the gallery</button></p>
|
||||
</div>"))
|
||||
|
||||
|
||||
(def simple-grammar
|
||||
"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;
|
||||
START-CAPTION := '' ;
|
||||
title := #'[^]]*' ;
|
||||
src := #'[^)]*' ;
|
||||
SPACE := #'[\\r\\n\\W]*'"))
|
||||
|
||||
(defn simplify
|
||||
[tree]
|
||||
(if
|
||||
(coll? tree)
|
||||
(case (first tree)
|
||||
:SLIDE (remove empty? (map simplify (rest tree)))
|
||||
:title tree
|
||||
:src tree
|
||||
:START-CAPTION nil
|
||||
:END-CAPTION nil
|
||||
:END-SRC nil
|
||||
(remove empty? (map simplify tree)))))
|
||||
|
||||
(defn uploaded?
|
||||
"Does this `url` string appear to be one that has been uploaded to our
|
||||
`uploads` directory?"
|
||||
[url]
|
||||
(and
|
||||
(cs/starts-with? (str url) "content/uploads")
|
||||
(fs/exists? (cio/file upload-dir (fs/base-name url)))))
|
||||
|
||||
;; (uploaded? "content/uploads/g1.jpg")
|
||||
|
||||
(defn slide-merge-dimensions
|
||||
"If this `slide` appears to be local, return it decorated with the
|
||||
dimensions of the image it references."
|
||||
[slide]
|
||||
(let [url (:src slide)
|
||||
dimensions (try
|
||||
(if (uploaded? url)
|
||||
(dimensions
|
||||
(buffered-image (cio/file upload-dir (fs/base-name url)))))
|
||||
(catch Exception x (.getMessage x)))]
|
||||
(if dimensions
|
||||
(assoc slide :w (first dimensions) :h (nth dimensions 1))
|
||||
slide)))
|
||||
|
||||
;; (slide-merge-dimensions
|
||||
;; {: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))
|
||||
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)))]
|
||||
(slide-merge-dimensions
|
||||
(if thumb
|
||||
(assoc s' :msrc thumb)
|
||||
s'))))
|
||||
|
||||
(def process-simple-photoswipe
|
||||
"Process a simplified specification for a photoswipe gallery, comprising just
|
||||
a sequence of MarkDown image links. This is REALLY expensive to do, we don't
|
||||
want to do it often. Hence memoised."
|
||||
(memoize
|
||||
(fn
|
||||
[^String spec ^Integer index]
|
||||
(process-full-photoswipe
|
||||
(json/write-str
|
||||
{:slides (map
|
||||
process-simple-slide
|
||||
(re-seq #"!\[[^(]*\([^)]*\)" spec))
|
||||
;; TODO: better to split slides in instaparse
|
||||
:options { :timeToIdle 100 }
|
||||
:openImmediately true}) index))))
|
||||
|
||||
;; (map
|
||||
;; process-simple-slide
|
||||
;; (re-seq #"!\[[^(]*\([^)]*\)"
|
||||
;; "
|
||||
;; 
|
||||
;; 
|
||||
;; "))
|
||||
|
||||
;; (process-simple-photoswipe
|
||||
;; "
|
||||
;; 
|
||||
;; 
|
||||
;; "
|
||||
;; 1)
|
||||
|
||||
(defn process-photoswipe
|
||||
[^String url-or-pswp-spec ^Integer index]
|
||||
(let [data (resource-url-or-data->data url-or-pswp-spec)
|
||||
spec (cs/trim (:data data))]
|
||||
(if
|
||||
(cs/starts-with? spec "![")
|
||||
(process-simple-photoswipe spec index)
|
||||
(process-full-photoswipe spec index))))
|
||||
|
|
@ -2,9 +2,11 @@
|
|||
:author "Simon Brooke"}
|
||||
smeagol.extensions.utils
|
||||
(:require [cemerick.url :refer (url url-encode url-decode)]
|
||||
[clojure.java.io :as cjio]
|
||||
[clojure.string :as cs]
|
||||
[me.raynes.fs :as fs]
|
||||
[noir.io :as io]
|
||||
[smeagol.configuration :refer [config]]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
@ -30,7 +32,17 @@
|
|||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn resource-url-or-data->data
|
||||
(def content-dir
|
||||
(str
|
||||
(fs/absolute
|
||||
(or
|
||||
(:content-dir config)
|
||||
(cjio/file (io/resource-path) "content")))))
|
||||
|
||||
(def upload-dir
|
||||
(str (cjio/file content-dir "uploads")))
|
||||
|
||||
(def resource-url-or-data->data
|
||||
"Interpret this `resource-url-or-data` string as data to be digested by a
|
||||
`process-extension` function. It may be a URL or the pathname of a local
|
||||
resource, in which case the content should be fetched; or it may just be
|
||||
|
|
@ -40,7 +52,8 @@
|
|||
`:text`, and a key `:data` whose value is the data. There will be an
|
||||
additional key being the value of the `:from` key, whose value will be the
|
||||
source of the data."
|
||||
[^String resource-url-or-data]
|
||||
(memoize
|
||||
(fn [^String resource-url-or-data]
|
||||
(let [default {:from :text
|
||||
:text resource-url-or-data
|
||||
:data resource-url-or-data}]
|
||||
|
|
@ -69,4 +82,4 @@
|
|||
"` because "
|
||||
(.getName (.getClass x))
|
||||
(.getMessage x) )
|
||||
default))))
|
||||
default))))))
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
[cemerick.url :refer (url url-encode url-decode)]
|
||||
[clj-yaml.core :as yaml]
|
||||
[markdown.core :as md]
|
||||
[noir.io :as io] ;; used by photoswipe, only
|
||||
[smeagol.configuration :refer [config]]
|
||||
[smeagol.extensions.mermaid :refer [process-mermaid]]))
|
||||
[smeagol.extensions.mermaid :refer [process-mermaid]]
|
||||
[smeagol.extensions.photoswipe :refer [process-photoswipe]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
|
|
@ -86,28 +86,6 @@
|
|||
index
|
||||
");\n//]]\n</script>"))
|
||||
|
||||
(defn process-photoswipe
|
||||
"Process specification for a photoswipe gallery"
|
||||
[^String spec ^Integer index]
|
||||
(str
|
||||
"<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>
|
||||
<script>
|
||||
\n//<![CDATA[\n
|
||||
var pswpElement = document.getElementById('pswp-" index "');
|
||||
var spec" index " = "
|
||||
spec
|
||||
";
|
||||
var gallery" index
|
||||
" = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, spec" index ".slides, spec" index ".options);
|
||||
if (spec" index ".openImmediately) { gallery" index ".init(); }
|
||||
\n//]]\n
|
||||
</script>
|
||||
<p><button onclick=\"gallery" index ".init()\">Open the gallery</button></p>
|
||||
</div>"))
|
||||
|
||||
|
||||
(defn process-backticks
|
||||
"Effectively, escape the backticks surrounding this `text`, by protecting them
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@
|
|||
(:content-dir config)
|
||||
(cjio/file (io/resource-path) "content")))))
|
||||
|
||||
(def upload-dir
|
||||
(str (cjio/file content-dir "uploads")))
|
||||
|
||||
(defn standard-params
|
||||
"Return a map of standard parameters to pass to the template renderer."
|
||||
[request]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue