add extensions/middleware for web app usage
This commit is contained in:
parent
72f44a278c
commit
7161e66381
|
@ -8,6 +8,7 @@
|
||||||
(:require [clojure.walk :refer [stringify-keys]]
|
(:require [clojure.walk :refer [stringify-keys]]
|
||||||
[clj-pebble.extensions :as ext]
|
[clj-pebble.extensions :as ext]
|
||||||
[clj-pebble.standard-extensions :as std]
|
[clj-pebble.standard-extensions :as std]
|
||||||
|
[clj-pebble.web.extensions :as web]
|
||||||
[clj-pebble.options :refer [options]]))
|
[clj-pebble.options :refer [options]]))
|
||||||
|
|
||||||
(defonce classpath-loader (ClasspathLoader.))
|
(defonce classpath-loader (ClasspathLoader.))
|
||||||
|
@ -29,7 +30,8 @@
|
||||||
|
|
||||||
(defn- make-pebble-engine []
|
(defn- make-pebble-engine []
|
||||||
(let [engine (-> (PebbleEngine. classpath-loader)
|
(let [engine (-> (PebbleEngine. classpath-loader)
|
||||||
(ext/add-extensions-library! std/extensions))]
|
(ext/add-extensions-library! std/extensions)
|
||||||
|
(ext/add-extensions-library! web/extensions))]
|
||||||
(apply-options! engine)
|
(apply-options! engine)
|
||||||
engine))
|
engine))
|
||||||
|
|
||||||
|
|
27
src/clj_pebble/utils.clj
Normal file
27
src/clj_pebble/utils.clj
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
(ns clj-pebble.utils
|
||||||
|
(:import (java.net URL)
|
||||||
|
(java.io File)))
|
||||||
|
|
||||||
|
(defn inside-jar? [^File file]
|
||||||
|
(-> file
|
||||||
|
(.getPath)
|
||||||
|
; the path of a file inside a jar looks something like "jar:file:/path/to/file.jar!/path/inside/jar/to/file"
|
||||||
|
(.contains "jar!")))
|
||||||
|
|
||||||
|
(defn get-file-last-modified [^File file]
|
||||||
|
(if (inside-jar? file)
|
||||||
|
0
|
||||||
|
(.lastModified file)))
|
||||||
|
|
||||||
|
(defn get-resource-path
|
||||||
|
(^URL [^String filename]
|
||||||
|
(-> (Thread/currentThread)
|
||||||
|
(.getContextClassLoader)
|
||||||
|
(.getResource filename))))
|
||||||
|
|
||||||
|
(defn get-resource-modification-date [^String filename]
|
||||||
|
(when-let [resource-filename (get-resource-path filename)]
|
||||||
|
(->> resource-filename
|
||||||
|
(.getPath)
|
||||||
|
(new File)
|
||||||
|
(get-file-last-modified))))
|
80
src/clj_pebble/web/extensions.clj
Normal file
80
src/clj_pebble/web/extensions.clj
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
(ns clj-pebble.web.extensions
|
||||||
|
(:import (java.net URI))
|
||||||
|
(:require [clojure.string :as str]
|
||||||
|
[clj-pebble.web.middleware :refer [*servlet-context-path*]]
|
||||||
|
[clj-pebble.options :refer [options]])
|
||||||
|
(:use [clj-pebble.utils]))
|
||||||
|
|
||||||
|
;; TODO: while 'public' is the default with Compojure, applications can override with something else ...
|
||||||
|
;; should make this customizable (some option added to clj-pebble.options likely ...)
|
||||||
|
(def root-resource-path "public")
|
||||||
|
|
||||||
|
(defn- get-context-url [url]
|
||||||
|
(str *servlet-context-path* url))
|
||||||
|
|
||||||
|
(defn- relative-url? [url]
|
||||||
|
(if-not (str/blank? url)
|
||||||
|
(let [uri (new URI url)]
|
||||||
|
(str/blank? (.getScheme uri)))))
|
||||||
|
|
||||||
|
(defn- get-resource-modification-timestamp [^String resource-url]
|
||||||
|
(if (relative-url? resource-url)
|
||||||
|
(->> (str root-resource-path resource-url)
|
||||||
|
(get-context-url)
|
||||||
|
(get-resource-modification-date))))
|
||||||
|
|
||||||
|
(defn- get-url-string [url]
|
||||||
|
(if-let [modification-timestamp (get-resource-modification-timestamp url)]
|
||||||
|
; because it looks kind of dumb to have '?0' at the end of URLs when running from a jar ...
|
||||||
|
(if (= modification-timestamp 0)
|
||||||
|
url
|
||||||
|
(str url "?" modification-timestamp))
|
||||||
|
url))
|
||||||
|
|
||||||
|
(defn- minified-url? [url]
|
||||||
|
(re-matches #"^(.+\.)min\.(css|js)$" url))
|
||||||
|
|
||||||
|
(defn- make-minified-url [^String url]
|
||||||
|
(let [pos (.lastIndexOf url (int \.))]
|
||||||
|
(if (> pos -1)
|
||||||
|
(let [name (subs url 0 pos)
|
||||||
|
extension (subs url (inc pos))]
|
||||||
|
(str name ".min." extension))
|
||||||
|
url)))
|
||||||
|
|
||||||
|
(defn- get-minified-resource-url [url]
|
||||||
|
(if (or (not (:check-for-minified-web-resources @options))
|
||||||
|
(minified-url? url))
|
||||||
|
url
|
||||||
|
(let [minified-url (make-minified-url url)]
|
||||||
|
(if (get-resource-path (str root-resource-path minified-url))
|
||||||
|
minified-url
|
||||||
|
url))))
|
||||||
|
|
||||||
|
; defined using the same type of map structure as in clj-pebble.standard-extensions
|
||||||
|
|
||||||
|
(defonce extensions
|
||||||
|
{:functions
|
||||||
|
{"path"
|
||||||
|
{:fn (fn [url]
|
||||||
|
(get-context-url url))}
|
||||||
|
|
||||||
|
"stylesheet"
|
||||||
|
{:fn (fn [url & [media]]
|
||||||
|
(let [fmt (if media
|
||||||
|
"<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\" media=\"%s\" />"
|
||||||
|
"<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\" />")
|
||||||
|
resource-path (get-minified-resource-url url)]
|
||||||
|
(format fmt (get-url-string resource-path) media)))}
|
||||||
|
|
||||||
|
"javascript"
|
||||||
|
{:fn (fn [url]
|
||||||
|
(let [fmt "<script type=\"text/javascript\" src=\"%s\"></script>"
|
||||||
|
resource-path (get-minified-resource-url url)]
|
||||||
|
(format fmt (get-url-string resource-path))))}}
|
||||||
|
|
||||||
|
:filters
|
||||||
|
{}
|
||||||
|
|
||||||
|
:tests
|
||||||
|
{}})
|
8
src/clj_pebble/web/middleware.clj
Normal file
8
src/clj_pebble/web/middleware.clj
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
(ns clj-pebble.web.middleware)
|
||||||
|
|
||||||
|
(declare ^:dynamic *servlet-context-path*)
|
||||||
|
|
||||||
|
(defn wrap-servlet-context-path [handler]
|
||||||
|
(fn [req]
|
||||||
|
(binding [*servlet-context-path* (:context req)]
|
||||||
|
(handler req))))
|
Loading…
Reference in a new issue