mirror of
https://github.com/journeyman-cc/smeagol.git
synced 2026-04-12 18:05:06 +00:00
#45,#46: done
This commit is contained in:
parent
ee46b0d545
commit
151987e598
5 changed files with 131 additions and 63 deletions
|
|
@ -30,37 +30,35 @@
|
|||
:content-dir "resources/public/content"
|
||||
;; where content is served from.
|
||||
:default-locale "en-GB" ;; default language used for messages
|
||||
:extensions-from :local ;; where to load JavaScript libraries
|
||||
;; from: options are :local, :remote.
|
||||
:formatters ;; formatters for processing markdown
|
||||
;; extensions.
|
||||
{:backticks {:formatter "smeagol.formatting/process-backticks"
|
||||
:scripts {}
|
||||
:styles {}}
|
||||
:mermaid {:formatter "smeagol.extensions.mermaid/process-mermaid"
|
||||
:scripts {:core {:local "vendor/mermaid/dist/mermaid.js"}}
|
||||
:scripts {:core {:local "vendor/mermaid/dist/mermaid.js"
|
||||
:remote "https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.4.6/mermaid.min.js"}}
|
||||
:styles {}}
|
||||
:pswp {:formatter "smeagol.extensions.photoswipe/process-photoswipe"
|
||||
:scripts {:core {:local "/vendor/node_modules/photoswipe/dist/photoswipe.min.js"
|
||||
:scripts {:core {:local "vendor/node_modules/photoswipe/dist/photoswipe.min.js"
|
||||
:remote "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js"}
|
||||
:ui {:local "/vendor/node_modules/photoswipe/dist/photoswipe-ui-default.min.js"
|
||||
:ui {:local "vendor/node_modules/photoswipe/dist/photoswipe-ui-default.min.js"
|
||||
:remote "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe-ui-default.min.js"}}
|
||||
:styles {:core {:local "/vendor/node_modules/photoswipe/dist/photoswipe.css"
|
||||
:remote "/vendor/node_modules/photoswipe/dist/default-skin/default-skin.css"}}}
|
||||
:styles {:core {:local "vendor/node_modules/photoswipe/dist/photoswipe.css"}
|
||||
:skin {:local "vendor/node_modules/photoswipe/dist/default-skin/default-skin.css"}}}
|
||||
:test {:formatter "smeagol.extensions.test/process-test" }
|
||||
:vega {:formatter "smeagol.extensions.vega/process-vega"
|
||||
:scripts {:core {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega/5.9.1/vega.min.js"}
|
||||
:lite {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-lite/4.1.1/vega-lite.min.js"}
|
||||
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}
|
||||
:styles {}}}
|
||||
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}}}
|
||||
:vis {:formatter "smeagol.extensions.vega/process-vega"
|
||||
:scripts {:core {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega/5.9.1/vega.min.js"}
|
||||
:lite {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-lite/4.1.1/vega-lite.min.js"}
|
||||
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}
|
||||
:styles {}}}
|
||||
}
|
||||
:embed {:remote "https://cdnjs.cloudflare.com/ajax/libs/vega-embed/6.2.2/vega-embed.min.js"}}}}
|
||||
:log-level :info ;; the minimum logging level; one of
|
||||
;; :trace :debug :info :warn :error :fatal
|
||||
:js-from :cdnjs ;; where to load JavaScript libraries
|
||||
;; from: options are :local, :cdnjs
|
||||
:passwd "resources/passwd"
|
||||
;; where the password file is stored
|
||||
:site-title "Smeagol" ;; overall title of the site, used in
|
||||
|
|
@ -71,4 +69,10 @@
|
|||
;; stored in the /small directory
|
||||
:med 400 ;; maximum dimension of thumbnails
|
||||
;; stored in the /med directory
|
||||
}}
|
||||
;; you can add as many extra keys and values as
|
||||
;; you like here for additional sizes of images.
|
||||
;; Images will only be scaled if their maximum
|
||||
;; dimension (in pixels) is greater than the value;
|
||||
;; only JPEG and PNG images will be scaled.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
{% block extra-headers %}
|
||||
{% for script in scripts %}
|
||||
<script src="{{script}}"></script>
|
||||
{% endfor %}
|
||||
<script src="{{script}}"></script>{% endfor %}
|
||||
{% for style in styles %}
|
||||
<link href="{{style}}" rel="stylesheet" type="text/css" />
|
||||
{% endfor %}
|
||||
<link href="{{style}}" rel="stylesheet" type="text/css" />{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
fragments
|
||||
(cons fragment processed)))
|
||||
|
||||
|
||||
(defn deep-merge [v & vs]
|
||||
"Cripped in its entirety from https://clojuredocs.org/clojure.core/merge."
|
||||
(letfn [(rec-merge [v1 v2]
|
||||
|
|
@ -124,18 +125,18 @@
|
|||
fragments
|
||||
(cons ident processed))))
|
||||
|
||||
(apply-formatter
|
||||
3
|
||||
{:inclusions {}}
|
||||
'()
|
||||
'()
|
||||
"pswp
|
||||

|
||||

|
||||

|
||||
"
|
||||
"pswp"
|
||||
smeagol.extensions.photoswipe/process-photoswipe)
|
||||
;; (apply-formatter
|
||||
;; 3
|
||||
;; {:inclusions {}}
|
||||
;; '()
|
||||
;; '()
|
||||
;; "pswp
|
||||
;; 
|
||||
;; 
|
||||
;; 
|
||||
;; "
|
||||
;; "pswp"
|
||||
;; smeagol.extensions.photoswipe/process-photoswipe)
|
||||
|
||||
(defn process-text
|
||||
"Process this `text`, assumed to be markdown potentially containing both local links
|
||||
|
|
@ -145,6 +146,8 @@
|
|||
The map has two top-level keys: `:inclusions`, a map of constructed keywords to
|
||||
inclusion specifications, and `:text`, an HTML text string with the keywords
|
||||
present where the corresponding inclusion should be inserted."
|
||||
|
||||
;; TODO: the inclusion->index bug is in here somewhere.
|
||||
([^String text]
|
||||
(process-text 0 {} (cs/split (or text "") #"```") '()))
|
||||
([index result fragments processed]
|
||||
|
|
@ -185,19 +188,19 @@
|
|||
(rest fragments)
|
||||
(cons ident processed))
|
||||
{:inclusions {ident (apply formatter (list (subs fragment (count first-token)) index))}
|
||||
:extensions (cons kw (:extensions result))}))
|
||||
:extensions (assoc (or (:extensions result) {}) kw (-> config :formatters kw))}))
|
||||
:else
|
||||
;; Otherwise process the current fragment as markdown and recurse on
|
||||
;; down the list
|
||||
(process-markdown-fragment
|
||||
index result remarked (rest fragments) processed)))))
|
||||
|
||||
(process-text
|
||||
"pswp
|
||||

|
||||

|
||||

|
||||
" )
|
||||
;; (process-text
|
||||
;; "pswp
|
||||
;; 
|
||||
;; 
|
||||
;; 
|
||||
;; " )
|
||||
|
||||
(defn reintegrate-inclusions
|
||||
"Given a map of the form produced by `process-text`, return a string of HTML text
|
||||
|
|
@ -236,3 +239,4 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
[com.stuartsierra.component :as component]
|
||||
[smeagol.configuration :refer [config]]
|
||||
[smeagol.include.resolve-local-file :as resolve]
|
||||
[smeagol.include :as include]))
|
||||
[smeagol.include :as include]
|
||||
[smeagol.util :refer [content-dir local-url]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
|
|
@ -118,6 +119,9 @@
|
|||
|
||||
|
||||
(def md-include-system
|
||||
"Allowing Markdown includes. Unfortunately the contributor who contributed
|
||||
this didn't document it, and I haven't yet worked out how it works. TODO:
|
||||
investigate and document."
|
||||
(component/start
|
||||
(component/system-map
|
||||
:resolver (resolve/new-resolver util/content-dir)
|
||||
|
|
@ -125,6 +129,7 @@
|
|||
(include/new-includer)
|
||||
[:resolver]))))
|
||||
|
||||
|
||||
(defn preferred-source
|
||||
"Here, `component` is expected to be a map with two keys, `:local` and
|
||||
`:remote`. If the value of `:extensions-from` in `config.edn` is remote
|
||||
|
|
@ -132,26 +137,51 @@
|
|||
be returned. Otherwise, if the value of `:local` is nil and the value of
|
||||
`:remote` is non-nil, the value of `:remote` will be returned. By default,
|
||||
the value of `:local` will be returned."
|
||||
[component]
|
||||
(let [l (:local component) ;; TODO: look at the trick in Selmer to get relative URL
|
||||
r (:remote component)]
|
||||
(cond
|
||||
(= (:extensions-from config) :remote) (if (empty? r) l r)
|
||||
(empty? l) r
|
||||
:else l)))
|
||||
[component ks]
|
||||
(try
|
||||
(let [l (:local component)
|
||||
l' (if-not (empty? l) (local-url l) l)
|
||||
r (:remote component)]
|
||||
(cond
|
||||
(= (:extensions-from config) :remote)
|
||||
(if (empty? r) l' r)
|
||||
(empty? l') r
|
||||
:else l'))
|
||||
(catch Exception any
|
||||
(log/error "Failed to find appropriate source for component" ks "because:" any)
|
||||
nil)))
|
||||
|
||||
;; (preferred-source {:local "vendor/node_modules/photoswipe/dist/photoswipe.min.js",
|
||||
;; :remote "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js"} :core)
|
||||
|
||||
(defn collect-preferred
|
||||
"From extensions referenced in this `processed-text`, extract the preferred
|
||||
URLs for this keyword `k`, expected to be either `:scripts` or `:styles`."
|
||||
[processed-text k]
|
||||
(set
|
||||
(remove
|
||||
nil?
|
||||
(map
|
||||
preferred-source
|
||||
(apply
|
||||
concat
|
||||
(map vals (map k (vals (:extensions processed-text)))))))))
|
||||
([processed-text]
|
||||
(concat
|
||||
(collect-preferred processed-text :scripts)
|
||||
(collect-preferred processed-text :styles)))
|
||||
([processed-text resource-type]
|
||||
(reduce concat
|
||||
(map
|
||||
(fn [extension-key]
|
||||
(map
|
||||
(fn [requirement]
|
||||
(let [r (preferred-source
|
||||
(-> processed-text :extensions extension-key resource-type requirement)
|
||||
requirement)]
|
||||
(if (empty? r)
|
||||
(log/warn "Found no valid URL for requirement"
|
||||
requirement "of extension" extension-key))
|
||||
r))
|
||||
(keys (-> processed-text :extensions extension-key resource-type))))
|
||||
(keys (:extensions processed-text))))))
|
||||
|
||||
(cjio/file content-dir "vendor/node_modules/photoswipe/dist/photoswipe.min.js")
|
||||
|
||||
(def processed-text (md->html (slurp "resources/public/content/Simplified example gallery.md" )))
|
||||
|
||||
(preferred-source (-> processed-text :extensions :pswp :scripts :core) :pswp)
|
||||
|
||||
(collect-preferred processed-text :scripts)
|
||||
|
||||
(defn wiki-page
|
||||
"Render the markdown page specified in this `request`, if any. If none found, redirect to edit-page"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@
|
|||
(str (cjio/file content-dir "uploads")))
|
||||
|
||||
(def local-url-base
|
||||
"Essentially, the slash-terminated absolute path of the `public` resource
|
||||
directory."
|
||||
(let [a (str (fs/absolute content-dir))]
|
||||
(subs a 0 (- (count a) (count "content")))))
|
||||
|
||||
|
|
@ -59,7 +61,11 @@
|
|||
if it is safe to serve. This reason may be logged, but should *not* be
|
||||
shown to remote users, as it would allow file system probing."
|
||||
[file-path]
|
||||
(let [path (fs/absolute file-path)]
|
||||
(try
|
||||
(let [path (if
|
||||
(cs/starts-with? (str file-path) "/")
|
||||
file-path
|
||||
(cjio/file local-url-base file-path))]
|
||||
(cond
|
||||
(cs/includes? file-path "..")
|
||||
(cs/join " " file-path
|
||||
|
|
@ -69,31 +75,57 @@
|
|||
(not (fs/exists? path))
|
||||
(cs/join " " [path "does not exist"])
|
||||
(not (fs/readable? path))
|
||||
(cs/join " " [path "is not readable"]))))
|
||||
(cs/join " " [path "is not readable"])))
|
||||
(catch Exception any (cs/join " " file-path "is not servable because" (.getMessage any)))))
|
||||
|
||||
|
||||
;; (not-servable-reason "/home/simon/workspace/smeagol/resources/public/content/vendor/node_modules/photoswipe/dist/photoswipe.min.js")
|
||||
;; (not-servable-reason "/root/froboz")
|
||||
|
||||
(defn local-url?
|
||||
"True if this `file-path` can be served as a local URL, else false."
|
||||
[file-path]
|
||||
(empty? (not-servable-reason file-path)))
|
||||
(try
|
||||
(if
|
||||
(empty? (not-servable-reason file-path))
|
||||
true
|
||||
(do
|
||||
(log/error
|
||||
"In `smeagol.util/local-url? `" file-path "` is not a servable resource.")
|
||||
false))
|
||||
(catch Exception any
|
||||
(log/error
|
||||
"In `smeagol.util/local-url `" file-path "` is not a servable resource:" any)
|
||||
false)))
|
||||
|
||||
(defn local-url
|
||||
"Return a local URL for this `file-path`, or a deliberate 404 if none
|
||||
can be safely served."
|
||||
;; TODO: this actually returns a relative URL relative to local-url-base.
|
||||
;; That's not quite what we want because in Tomcat contexts the absolute
|
||||
;; URL may be different. We *ought* to be able to extract the offset from the
|
||||
;; servlet context, but it may be simpler to jam it in the config.
|
||||
[file-path]
|
||||
(try
|
||||
(let [path (fs/absolute file-path)
|
||||
(let [path (if
|
||||
(cs/starts-with? file-path local-url-base)
|
||||
(subs file-path (count local-url-base))
|
||||
file-path)
|
||||
problem (not-servable-reason path)]
|
||||
(if
|
||||
(empty? problem)
|
||||
(subs (str path) (count local-url-base))
|
||||
path
|
||||
(do
|
||||
(log/error
|
||||
"In `smeagol.util/local-url `" file-path "` is not a servable resource.")
|
||||
(str "404-not-found?path=" file-path))))
|
||||
(catch Exception any
|
||||
(log/error
|
||||
"In `smeagol.util/local-url `" file-path "` is not a servable resource:" any)
|
||||
(str "404-not-found?path=" file-path))))
|
||||
(log/error
|
||||
"In `smeagol.util/local-url `" file-path "` is not a servable resource:" any)
|
||||
(str "404-not-found?path=" file-path))))
|
||||
|
||||
(local-url? "vendor/node_modules/photoswipe/dist/photoswipe.min.js")
|
||||
(local-url? "/home/simon/workspace/smeagol/resources/public/vendor/node_modules/photoswipe/dist/photoswipe.min.js")
|
||||
|
||||
(defn standard-params
|
||||
"Return a map of standard parameters to pass to the template renderer."
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue