"Autosave" Functionality in ClojureScript - clojurescript

I'd like to add an "autosave" feature to a Reagent form in a ClojureScript function. In Clojure, I usually make something out of a ScheduledExecutorService. Since that isn't available in ClojureScript, I came up with the following.
(def delay-handle (atom nil))
(defn clear-autosave-delay! []
(.clearTimeout js/window #delay-handle))
(defn start-autosave-delay!
[doc-save-fn delay-ms page-map-atom]
(reset! delay-handle (.setTimeout js/window doc-save-fn delay-ms page-map-atom)))
(defn change-watcher!
[doc-save-fn page-map-atom]
(let [delay (* 1000 (get-in #page-map-atom [:options :editor_autosave_interval]))]
(when (pos? delay)
(clear-autosave-delay!)
(start-autosave-delay! doc-save-fn delay page-map-atom))))
I put the change-watcher! function in the Reagent :on-change handlers for the input controls. Whenever a change occurs, it resets the delay. If the delay expires, the doc-save-fn is called to do the save.
It seems to work Ok, but isn't very "Clojuresque." Is there a more idiomatic way to write this?​

Use debouncer for this issue. It's pretty simple and does same
(goog.functions.debounce auto-save-action 1000)

Related

reitit.frontend - HTML5Router does not prevent anchor click as should on matching route

if we choose HTML5Router or Fragment router - in both cases reitit should prevent default anchor click behavior
however, ignore-anchor-click function here is never called
https://github.com/metosin/reitit/blob/0.5.18/modules/reitit-frontend/src/reitit/frontend/history.cljs#L109
because a few lines below goog.events/listen is missing true 4th arg - so browser first captures click and never gets to document.click
https://github.com/metosin/reitit/blob/0.5.18/modules/reitit-frontend/src/reitit/frontend/history.cljs#L124
is
(gevents/listen js/document goog.events.EventType.CLICK ignore-anchor-click))
should be - then all works
(gevents/listen js/document goog.events.EventType.CLICK ignore-anchor-click true))
question
is there a way to change this behavior without PR or forking?
solution
copy function code from reitit.frontent.history
using history ref unsubscribe and resubscribe
(let [history (Yzma.frontend.easy/start! _ _ _)]
(goog.events/unlistenByKey (:click-listen-key history))
(goog.events/listen
js/document
goog.events.EventType.CLICK
(fn [event]
(when-let [element (Yzma.frontend.history/closest-by-tag
(Yzma.frontend.history/event-target event) "a")]
(let [uri (.parse goog.Uri (.-href element))]
(when (Yzma.frontend.history/ignore-anchor-click?
(.-router history) event element uri)
(.preventDefault event)
(let [path (str (.getPath uri)
(when (.hasQuery uri)
(str "?" (.getQuery uri)))
(when (.hasFragment uri)
(str "#" (.getFragment uri))))]
(.pushState js/window.history nil "" path)
(Yzma.frontend.history/-on-navigate history path)))))) true))

Render html to racket gui

I'm trying to write a WYSIWYG text editor that allows me to write text in the top window, and have the resulting scribble text rendered in the bottom window. I figured the way I would do this would be to call scribble myfile.rkt in the background periodically, and then render the resulting output to a bottom screen using render-html-to-text. I'm having some trouble getting the render to work. Based on the documentation I need
in : input-port?
dest : (is-a? html-text<%>)
load-img? : any/c
eval-rkt? : any/c
The relevant parts of my script look like this
#lang racket/gui
(require racket/os racket/runtime-path "init.rkt"
browser/htmltext)
(require browser)
(define f (new frame% [label (~a "Dremacs" "#" (gethostname))]
[width 960]
[height 540]))
(define new-cnv (new cnv% [parent f]))
(send t insert ";; This buffer is for text that is not saved, and for Lisp evaluation.
;; To create a file, visit it with C-x C-f and enter text in its buffer.")
(send new-cnv set-editor t)
(define html-renderer%
(interface (html-text<%>)))
(define viewer (new panel%
[parent f]
[min-width 300]
[min-height 300]))
(render-html-to-text (open-input-file "TODO.html") html-renderer% #t #t)
(send f show #t)
But I get the error
render-html-to-text: expects argument of type <html-text<%> object>; given: '(#<input-port:/home/diego/repos/dremacs/dremacs/TODO.html> #<interface:html-renderer%>)
context...:
/usr/share/racket/pkgs/drracket/browser/htmltext.rkt:61:0: render-html-to-text
"/home/diego/repos/dremacs/dremacs/editor.rkt": [running body]
temp37_0
And I'm not sure what I'm doing wrong. Could anyone help?
The html-renderer% is not created correctly.
Use html-text-mixin to turn a text% into something that handles html-text.
But ... don't expect too much from the html-renderer.
It's old and doesn't support stylesheets.
Back in the day it was used to display documentation for DrRacket.

Emacs: Universal argument (C-u) in a function

I would like to use C-u in a function (for instance, regexp) where calling it with C-u has a different effect. How can I do this in Emacs? The documentation doesn't show how to do this with Emacs Lisp.
(defun test ()
(interactive)
(align-regexp)) ; I would like to add the C-u prefix to this.
(defun my/test ()
(interactive)
(let ((current-prefix-arg 4)) ;; emulate C-u
(call-interactively 'align-regexp) ;; invoke align-regexp interactively
)
)
Hope that helps.
I arrived here looking for a way to detect if my function had been called with C-u. This is how you do it:
(defun my-function ()
(interactive)
(if (equal current-prefix-arg nil) ; no C-u
;; then
(message "my-function was called normally")
;; else
(message "my-function was called with C-u")))
What the original poster was asking is how to call another function with C-u, from inside his/her function.
I post this as a clarification to #codyChan's comment above, in the hope that it might help others.

Normal instance method calls within a clojure doto

I'm setting up a swing UI in clojure and have a block like:
(doto main-frame
(.setUndecorated true)
(.setExtendedState Frame/MAXIMIZED_BOTH)
(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
(.setVisible true)
)
But now I want to call
(.setBackground (.getContentPane main-frame) Color/BLACK)
before I set the frame visible, is there a nicer way to do this than ending the doto and using the (.instanceMember instance args*) syntax?
If you really want a single doto, then maybe this will do:
(doto main-frame
(.setUndecorated true)
(.setExtendedState Frame/MAXIMIZED_BOTH)
(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
(-> (.getContentPane) (.setBackground Color/BLACK))
(.setVisible true))
The above relies on the fact that doto is not confined to Java methods, it just inserts its first argument (evaluated) as first argument of every form that follows.
I'd go with ending the doto though as the above is not very readable. Alternatively, maybe just define a set-background-on-content-pane function (that obviously takes the main-frame) and use that in the doto:
(defn set-bg-on-frame [fr color] (.setBackground (.getContentPane fr) color))
(doto main-frame
.
.
.
(set-bg-on-frame Color/BLACK)
(.setVisible true))

Image Processing, extending JPanel and Simulating Classes in Clojure

there! I'm building an image-processing application in swing/clojure, and right now I need to develop an image panel in which I can click and compute data. Thanks to coobird, I now have a good idea on how to do it in Java, but I still don't get many issues on its integration with Clojure.
Let's take a look at how coobird suggested me doing. First, we should extend a class in Java. In clojure, we do this with the proxy macro, so we'd have something like this:
(def painting-panel
(proxy [JPanel] []))
The next step is to create the class constructor and set some variables.
I can define functions after the second argument of proxy, but how can I create the constructor? Is painting-panel the name of this class (therefore the name of the function I should create)?
How can I deal with class variables? Should I define them with a let, like I did?
Are this and super available for me to use, like I did below?
(def painting-panel
(let [background-image (Image.)
point-clicked (Point.)]
(proxy [JPanel] []
(paintComponent [g]
(do ((.paintComponent super) g)
(doto g
(.drawImage background-image 0 0 nil)
(.fillRect (.x point-clicked) (.y point-clicked) 1 1))))
(painting-panel []; constructor?
((.addMouseListener this)
(proxy [MouseAdapter] []
(mouseClicked [e]
(do
(def point-clicked (.getPoint e))
(.repaint this)))))))))
Suggestions and code corrections are also welcome!
Thank you!
proxy actually creates an instance tada! You don't need to create a constructor.
Yes, but consider using a clojure ref instead. Also using def like that on the second last line is nasty! it creates a global binding for point-clicked when your logic relies on the lexically scoped one created by let.
(proxy-super paintComponent g), and yes "this" is available
This works for me:
(let [click (ref nil)
panel (proxy [javax.swing.JPanel] []
(paintComponent [g]
(proxy-super paintComponent g)
(.drawImage g (.getImage
(javax.swing.ImageIcon. "play.png"))
0 0 (.getWidth this) (.getHeight this) nil)
(if #click
(.fillRect g (:x #click) (:y #click) 10 10))))]
(.addMouseListener panel
(proxy [java.awt.event.MouseAdapter] []
(mouseClicked [e]
(let [p (.getPoint e)]
(dosync (ref-set click {:x (.x p), :y (.y p)})))
(javax.swing.SwingUtilities/invokeLater #(.repaint panel)))))
(doto (javax.swing.JFrame.)
(.setContentPane panel)
(.setSize 200 200)
(.show)))