;; Copyright (c) Rich Hickey. All rights reserved. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns ^{:doc "Receive - Eval - Print - Loop Receive a block of JS (presumably generated by a ClojureScript compiler) Evaluate it naively Print the result of evaluation to a string Send the resulting string back to the server Loop!" :author "Bobby Calderwood and Alex Redington"} clojure.browser.repl (:require [clojure.browser.net :as net] [clojure.browser.event :as event])) (def xpc-connection (atom nil)) (defn repl-print [data] (if-let [conn @xpc-connection] (net/transmit conn :print (pr-str data)))) (defn evaluate-javascript "Process a single block of JavaScript received from the server" [conn block] (let [result (try {:status :success :value (str (js* "eval(~{block})"))} (catch js/Error e {:status :exception :value (pr-str e) :stacktrace (if (.hasOwnProperty e "stack") (.-stack e) "No stacktrace available.")}))] (pr-str result))) (defn send-result [connection url data] (net/transmit connection url "POST" data nil 0)) (defn send-print "Send data to be printed in the REPL. If there is an error, try again up to 10 times." ([url data] (send-print url data 0)) ([url data n] (let [conn (net/xhr-connection)] (event/listen conn :error (fn [_] (if (< n 10) (send-print url data (inc n)) (.log js/console (str "Could not send " data " after " n " attempts."))))) (net/transmit conn url "POST" data nil 0)))) (def order (atom 0)) (defn wrap-message [t data] (pr-str {:type t :content data :order (swap! order inc)})) (defn start-evaluator "Start the REPL server connection." [url] (if-let [repl-connection (net/xpc-connection)] (let [connection (net/xhr-connection)] (event/listen connection :success (fn [e] (net/transmit repl-connection :evaluate-javascript (.getResponseText e/currentTarget ())))) (net/register-service repl-connection :send-result (fn [data] (send-result connection url (wrap-message :result data)))) (net/register-service repl-connection :print (fn [data] (send-print url (wrap-message :print data)))) (net/connect repl-connection (constantly nil)) (js/setTimeout #(send-result connection url (wrap-message :ready "ready")) 50)) (js/alert "No 'xpc' param provided to child iframe."))) (defn connect "Connects to a REPL server from an HTML document. After the connection is made, the REPL will evaluate forms in the context of the document that called this function." [repl-server-url] (let [repl-connection (net/xpc-connection {:peer_uri repl-server-url})] (swap! xpc-connection (constantly repl-connection)) (net/register-service repl-connection :evaluate-javascript (fn [js] (net/transmit repl-connection :send-result (evaluate-javascript repl-connection js)))) (net/connect repl-connection (constantly nil) (fn [iframe] (set! (.-display (.-style iframe)) "none")))))