diff --git a/resources/public/index.html b/resources/public/index.html
index 3857862..94741ca 100644
--- a/resources/public/index.html
+++ b/resources/public/index.html
@@ -5,8 +5,8 @@
+
+
+
SCI script tag
- What is this
+ What is this?
This project exposes the Small Clojure Interpreter in the
browser in such a way that you can use it with the script tag.
Project status
@@ -43,56 +46,67 @@
+ Include sci-script-tag.js and write a script tag
+ where type is set
+ to application/x-sci . Use :export to make the function
+ available in the JavaScript environment. The name is processed
+ using munge .
+
- <head>
- <script src="https://borkdude.github.io/sci-script-tag/js/sci-script-tag.js" type="application/javascript"></script>
- <script type="application/x-sci">
- (defn my-alert []
- (js/alert "alert!"))
- </script>
- </head>
+ <head>
+ <script src="https://borkdude.github.io/sci-script-tag/js/sci-script-tag.js"
+ type="application/javascript">
+ </script>
- <body>
- <button onclick="user.myAlert()">
- Click me!
- </button>
- </body>
-
+ <script type="application/x-sci">
+ (defn ^:export my-alert []
+ (js/alert "You clicked!"))
+ </script>
-
- Click me
+</head>
+
+<body>
+ <button onclick="my_alert()">
+ Click me!
+ </button>
+</body>
+
+
+
+
+ Click me!
When you have a file on your server, say cljs/script.cljs , you can load it using the src attribute:
-
- <script src="cljs/script.cljs" type="application/x-sci"></script>
-
+
+<script src="cljs/script.cljs" type="application/x-sci"></script>
+
To enable reagent ,
in addition to sci-script-tag.js , you need to include sci-script-tag-plugin-reagent.js .
-
- <script src="https://borkdude.github.io/sci-script-tag/js/sci-script-tag-plugin-reagent.js" type="application/javascript"></script>
- <script type="application/x-sci">
- (require '[reagent.core :as r]
- '[reagent.dom :as rdom])
+
+<script src="https://borkdude.github.io/sci-script-tag/js/sci-script-tag-plugin-reagent.js" type="application/javascript"></script>
+<script type="application/x-sci">
+ (require '[reagent.core :as r]
+ '[reagent.dom :as rdom])
- (def state (r/atom {:clicks 0}))
+ (def state (r/atom {:clicks 0}))
- (defn my-component []
- [:div
- [:p "Clicks: " (:clicks @state)]
- [:p [:button {:on-click #(swap! state update :clicks inc)}
- "Click me!"]]])
+ (defn my-component []
+ [:div
+ [:p "Clicks: " (:clicks @state)]
+ [:p [:button {:on-click #(swap! state update :clicks inc)}
+ "Click me!"]]])
- (rdom/render [my-component] (.getElementById js/document "app"))
- </script>
-
+ (rdom/render [my-component] (.getElementById js/document "app"))
+</script>
+
diff --git a/src/sci/script_tag.cljs b/src/sci/script_tag.cljs
index 7b993cf..fe271ed 100644
--- a/src/sci/script_tag.cljs
+++ b/src/sci/script_tag.cljs
@@ -1,50 +1,59 @@
(ns sci.script-tag
- (:require [clojure.string :as str]
+ (:refer-clojure :exclude [defn])
+ (:require [clojure.core :as c]
+ [clojure.string :as str]
[goog.object :as gobject]
[goog.string]
[sci.core :as sci]))
-(defn kebab->camel [s]
- (str/replace s #"-[a-zA-Z0-9]"
- (fn [s]
- (str/upper-case (.charAt s 1)))))
+(c/defmacro defn [fn-name & args]
+ (let [ns-sym (gensym "ns")]
+ `(let [~ns-sym (ns-name *ns*)]
+ (clojure.core/defn ~fn-name ~@args)
+ ~(when (:export (meta fn-name))
+ `(sci.script-tag/-export ~fn-name (str ~ns-sym "." '~fn-name))))))
-(defn- defn-macro [_ _ fn-name & args]
- `(let [ns# (ns-name *ns*)]
- (clojure.core/defn ~fn-name ~@args)
- (sci.script-tag/-export ~fn-name (str ns# "." '~fn-name))))
+(c/defn -export [f k]
+ (let [k (munge k)
+ parts (str/split k #"\.")]
+ (loop [parts parts
+ prev js/window]
+ (let [fpart (first parts)]
+ (cond (= "user" fpart)
+ (recur (rest parts) prev)
+ (= 1 (count parts))
+ (gobject/set prev fpart f)
+ :else
+ (if-let [obj (gobject/get prev fpart)]
+ (recur (rest parts) obj)
+ (let [obj #js {}]
+ (gobject/set prev fpart obj)
+ (recur (rest parts)
+ obj))))))
+ (gobject/set js/window k f)))
-(def ctx (atom (sci/init {:namespaces {'sci.script-tag
- {'defn (with-meta defn-macro
- {:sci/macro true})
- '-export (fn [f k]
- (let [parts (str/split k #"\.")]
- (loop [parts parts
- prev js/window]
- (let [fpart (first parts)
- fpart (kebab->camel fpart)]
- (if (= 1 (count parts))
- (gobject/set prev fpart f)
- (if-let [obj (gobject/get prev fpart)]
- (recur (rest parts) obj)
- (let [obj #js {}]
- (gobject/set prev fpart obj)
- (recur (rest parts)
- obj))))))
- (gobject/set js/window k f)))}
- 'clojure.core {'println println}}
+(def stns (sci/create-ns 'sci.script-tag nil))
+
+(def namespaces
+ {'sci.script-tag
+ {'defn (sci/copy-var defn stns)
+ '-export (sci/copy-var -export stns)}
+ 'clojure.core {'println (sci/copy-var println stns)
+ 'prn (sci/copy-var prn stns)}})
+
+(def ctx (atom (sci/init {:namespaces namespaces
:classes {'js js/window
:allow :all}})))
-(defn eval-string [s]
+(c/defn eval-string [s]
(sci/eval-string* @ctx
(str "(require '[sci.script-tag :refer :all])"
s)))
-(defn merge-ctx [opts]
+(c/defn merge-ctx [opts]
(swap! ctx sci/merge-opts opts))
-(defn- load-contents [script-tags]
+(c/defn- load-contents [script-tags]
(when-first [tag script-tags]
(if-let [text (not-empty (gobject/get tag "textContent"))]
(do (eval-string text)