cljfx

https://github.com/cljfx/cljfx
genekim 2020-09-01T00:18:18.026600Z

@vlaaad — I’m having a blast learning cljfx, and am amazed at what I can do with so little code. I love the re-frame-like event model, and how you’ve wrapped javafx! The :web-view UI controls was an incredible and delightful surprise to find — a full WebKit browser! Suddenly, there’s a whole bunch of apps that I want to write, that I normally would have tried to use Selenium/jBrowser, or Ruby Mechanize to write. (e.g., log into LinkedIn and automate the process of accepting connection requests…. I love the idea of having a live browser session, and potentially have buttons/command line to execute commands!). I’m trying to understand how I can use cljfx to access/manipulate the DOM in WebView— e.g., scroll the DOM to a certain x/y position, execute JavaScript, send a click event to a DOM element. All of these seem possible with the WebView.getEngine.executeScript() command — but I can’t quite visualize how to write the extension for WebView. Where would a new :execute-script method reside? Where does it get its arguments from? Where does it store the output? Does it post an event upon completion? Similarly, how would you write a :scroll-to-x-y method? Where does it get inputs? How can I trigger it to be executed from an event? Normally I would have skipped doing this, as it’s outside “toy app” scope, but I’m dazzled by all the things I could do with WebView if I could actually interact with the DOM! And WebView UI control could be so useful! Thanks in advance! https://stackoverflow.com/questions/31264847/how-to-set-remember-scrollbar-thumb-position-in-javafx-8-webview https://stackoverflow.com/questions/52652179/javafx-webview-how-to-scroll-it-to-the-bottom

genekim 2020-09-01T05:42:48.028600Z

(I just added @logbot to enable archiving in clojurians slack archive)

seancorfield 2020-09-01T06:03:47.029800Z

@genekim The @zulip-mirror-bot archives it to Zulip and is free and searchable, just FYI (but having both bots is a good idea).

seancorfield 2020-09-01T06:05:13.030500Z

See https://clojurians.zulipchat.com/#narrow/stream/180378-slack-archive/topic/cljfx for the searchable archive of this channel on Zulip back to February 25, 2019 (when I added the Zulip bot).

genekim 2020-09-01T06:06:08.031400Z

@seancorfield Whoa… Thank you! Was despairing at the loss of all the messages here! Checking it out now! 🙂

seancorfield 2020-09-01T06:06:34.031900Z

Zulip is also really nice for being entirely keyboard driven 🙂

seancorfield 2020-09-01T06:08:18.033100Z

If you find any channel that doesn't have the Zulip bot, please feel free to add it. Some of us Admins try to do that but it's hard to keep track of channels here at the rate people keep creating them!

genekim 2020-09-01T06:08:51.033200Z

Freaking awesome, @seancorfield — never used Zulip until today. Look at all this history!!! And will do on the mirror bot!

seancorfield 2020-09-01T06:10:23.033400Z

It's mostly how I keep track of everything happening in this Slack because it also shows the contents of threads, so I get to see stuff that wasn't even posted to the main channel. It's very useful to me as an Admin 🙂

genekim 2020-09-01T06:15:04.033600Z

Uncanny. Reading about your depstar work on the hn.core app, found on the Zulip archive from this channel. 🙂

seancorfield 2020-09-01T06:17:44.034Z

Even tho' I'm one of the founding admins of this Slack, I would shed no tears if all 19,700 17,000 of us decamped to Zulip at some point 🙂

seancorfield 2020-09-01T06:17:57.034200Z

(and I'm not an Admin of the Zulip space)

genekim 2020-09-01T06:21:04.034500Z

Haha. Despite free Slack tier limits, I can’t even imagine the conditions that would lead to people fleeing Slack to another platform…. (Actually, I guess I can think of a few bad scenarios, and holy cow, those are scenarios I’d hope to avoid… 🙂

seancorfield 2020-09-01T06:49:48.035Z

It is somewhat amazing how much inertia a large community can have...

genekim 2020-09-01T06:57:54.040800Z

@vlaaad — thank you for this… I will give this a try tomorrow! Very exciting! (I’ve been studying the cljfx docs all day today between meetings, and the docs are superb. So many questions got answered.) Some questions that remain: 1. Can that code in the :on-action event be put into a function, and then called from a cljfx event? Are there any reasons not to do this? (I.e., imagine that button dispatches a cljx event, which would then execute that .executeScriptfunction). 2. Is there a way to store the results of the .executeScript, and send that to an cljfx event? (i.e., imagine an event that executes some WebView JS query as in #1, and then stores it in the app state, where other events could access/process it. ) Regarding #2, is the only way to pass values back is registering a Java object as a callback? (https://stackoverflow.com/questions/30390257/how-to-catch-return-value-from-javascript-in-javafx) Thanks again!

genekim 2020-09-01T07:01:17.041200Z

…stand by… cleaning up/clarifying the question ^^^

😀 1
genekim 2020-09-01T07:08:56.041800Z

Hopefully the question is clearer now…. 🙏

genekim 2020-09-01T07:16:19.044800Z

@vlaaad #2 rewritten. Suppose I want to get the entire contents of the DOM. In Java, you apparently do, Document document = webEngine.getDocument(); I’m guessing that to do this in cljfx, we’d do the same trick: in the cljfx event, copy your technique (I.e., .lookup().getEngine().getDocumen , and then store the results in the state/context. Am I on target now?

genekim 2020-09-01T07:18:57.046700Z

(Big ahas tonight: 1) you can use .lookup() to access the objects outside of cljfx; 2) the rendering of cljfx components are one way — they’re not meant to call functions which return values, to be stored in app state. Yes?)

vlaaad 2020-09-01T07:29:29.047900Z

@genekim I’m not sure I understand your first question: the code in :on-action is already a function that is called from cljfx

genekim 2020-09-01T07:33:51.050600Z

...just want to validate that moving that function into a “defn” and calling it from a cljfx event isn’t considered catastrophic, in poor taste, or immoral. :) 😂

vlaaad 2020-09-01T07:34:33.051400Z

no-no, quite on the contrary!

vlaaad 2020-09-01T07:38:10.058200Z

I’d say my example is in a poor taste — for the sake of simplicity — because putting anonymous function in a function component will create a new instance of that function on every re-render, causing unnecessary :on-action reassignments. For example:

(defn my-button [_]
  {:fx/type :button :on-action #(do-stuff %)})
Calling my-button will create a different instance of anonymous function. That’s why map event handlers are preferred: it’s easier to make maps “stable” in terms of equality

🎉 1
genekim 2020-09-01T07:38:33.058300Z

Excellent! And I’m assuming use case #2 is similarly ok... When I get this working, i propose an example that does this get added? I spent an hour or two exploring how I might be able to do this in the extended lifecycle mechanisms you provide. Maybe even a sentence in the docs. I can propose some ideas in a PR?

vlaaad 2020-09-01T07:42:37.061300Z

2. rendering cljfx components is one way, yes: cljfx description is a sort of a template, and you can reuse this template in the multiple times in the same description tree. That’s why my suggestion is a hack: if you have multiple web views, you’ll need to make sure they have different ids, so your event handlers can find both.

vlaaad 2020-09-01T07:44:25.063100Z

I wouldn’t suggest taking component instances produced from the app state and putting them back in the state, this looks fragile — might cause infinite loops and will require tricky logic

vlaaad 2020-09-01T07:50:27.068300Z

@genekim I would suggest you create an issue in cljfx repo, I’ll think how this kind of stuff can be done more idiomatically. I have a couple of ideas so far: 1. if your app has a single WebView, you can create it at the startup and put it into state straight away. Your cljfx component tree will need to take it from the state and put it in the right place in the tree. There is no built in lifecycle for that, but I had it done for cljfx projects a couple of times already, I think I’ll just add it to built in lifecycles. 2. it’s possible to define and pass references to nodes in the component tree with ext-let-refs/ext-get-ref, it should be possible to augment cljfx to make event handlers receive these nodes.

genekim 2020-09-01T15:01:37.069Z

Will do, today or tomorrow! Thanks for all the help, @vlaaad!!