cljfx

https://github.com/cljfx/cljfx
wilkerlucio 2020-12-10T03:40:54.183600Z

hello, I'm trying to use a web-view and have some control over it, how do I make an event listener to fire when the page is loaded? I'm trying to port this JavaFX example: http://www.java2s.com/Code/Java/JavaFX/WebEngineLoadListener.htm

vlaaad 2020-12-10T08:07:06.183800Z

Hi! Your message reminded me that I wanted to add extension lifecycle for web-view because there is a bunch of useful props that are currently missing. If you are in a hurry you can create needed props yourself using fx/make-ext-with-props (documented in this readme section: https://github.com/cljfx/cljfx#included-extension-lifecycles)

wilkerlucio 2020-12-10T13:24:44.184200Z

hello, thanks for the pointers, I was able to know when the page loaded using a custom make-ext-with-props, but the event handler only gets me the prop value, now I want to trigger a javascript exec on the web engine of the web view, how can I access those instances?

wilkerlucio 2020-12-10T13:24:46.184400Z

current code:

wilkerlucio 2020-12-10T13:24:48.184600Z

(ns com.wsscode.demos.reveal
  (:require [vlaaad.reveal :as reveal]
            [vlaaad.reveal.ext :as rx]
            [cljfx.api :as fx]
            [cljfx.prop :as prop]
            [cljfx.mutator :as mutator]
            [cljfx.lifecycle :as lifecycle])
  (:import (javafx.scene.web WebView)))

(def web-view-with-ext-props
  (fx/make-ext-with-props
    {:on-load-state-changed
     (prop/make
       (mutator/property-change-listener #(-> (.getEngine ^WebView %)
                                              (.getLoadWorker)
                                              (.stateProperty)))
       lifecycle/change-listener)}))

(comment
  (tap>
    {:fx/type web-view-with-ext-props
     :desc    {:fx/type :web-view
               :url     "<http://localhost:3000/embed.html>"}
     :props   {:on-load-state-changed
               (fn [e]
                 (tap&gt; ["state changed" e]))}}))

wilkerlucio 2020-12-10T13:30:27.184900Z

my goal is to be able to do a postMessage in the browser window after it loads, so I can communicate something to the page

wilkerlucio 2020-12-10T13:31:38.185100Z

I believe I can achieve it with (-&gt; web-view (.getEngine) (.executeScript "window.postMessage('the-message')"))

wilkerlucio 2020-12-10T13:56:28.185400Z

tried to use a custom change-listener, but when I try to do it the view stops working

(def web-view-with-ext-props
  (fx/make-ext-with-props
    {:on-load-state-changed
     (prop/make
       (mutator/property-change-listener #(-&gt; (.getEngine ^WebView %)
                                              (.getLoadWorker)
                                              (.stateProperty)))
       #(reify ChangeListener
          (changed [a b c value]
            (tap&gt; [a b c])
            (% value))))}))

vlaaad 2020-12-10T14:06:30.185800Z

Hmm, that’s because the second arg to prop/make should be something that satisfies lifecycle protocol

vlaaad 2020-12-10T14:07:00.186Z

you can try lifecycle/scalar that passes values from description as-is

vlaaad 2020-12-10T14:07:31.186200Z

and then you can use #(reify ChangeListener ...) in the description

wilkerlucio 2020-12-10T14:12:55.186400Z

not sure if I understand how to use it, can you send an example snippet?

vlaaad 2020-12-10T14:15:05.186600Z

(def web-view-with-ext-props
  (fx/make-ext-with-props
    {:on-load-state-changed
     (prop/make
       (mutator/property-change-listener #(-&gt; (.getEngine ^WebView %)
                                            (.getLoadWorker)
                                            (.stateProperty)))
       lifecycle/scalar)}))

{:fx/type web-view-with-ext-props
 :desc    {:fx/type :web-view
           :url     "<http://localhost:3000/embed.html>"}
 :props   {:on-load-state-changed
           (reify javafx.beans.value.ChangeListener
             (changed [a b c d]
               (tap&gt; [a b c d])))}}

wilkerlucio 2020-12-10T14:22:06.186800Z

cool, thanks!

wilkerlucio 2020-12-10T14:23:21.187Z

I got to render some of what I want, but seems like the built-in browser is lacking some features that cytoscape may require, didnt worked (it renders, but the graph itself doesn't work properly), do you know if there is another option for internal web view, some way to use webkit or something?

vlaaad 2020-12-10T14:23:54.187200Z

hmm, I thought javafx’s web view IS webkit

wilkerlucio 2020-12-10T14:25:51.187700Z

seems like the webkit renderer there is not been updated in a while

vlaaad 2020-12-10T15:32:16.188400Z

It seems to be updated regularly. Do you use Java 8 or Java 11?

wilkerlucio 2020-12-10T16:43:37.189100Z

using Java 11

wilkerlucio 2020-12-10T16:55:22.189500Z

tried bumping:

org.openjfx/javafx-controls {:mvn/version "15"}
  org.openjfx/javafx-base     {:mvn/version "15"}
  org.openjfx/javafx-graphics {:mvn/version "15"}
  org.openjfx/javafx-media    {:mvn/version "15"}
  org.openjfx/javafx-web      {:mvn/version "15"}

wilkerlucio 2020-12-10T16:55:24.189700Z

but still same results

vlaaad 2020-12-10T16:55:37.189900Z

Aww, that's sad

vlaaad 2020-12-10T16:59:51.190100Z

What's the library you are trying to use from within webview?

vlaaad 2020-12-10T17:01:55.190300Z

Ah, I saw you mentioned cytoscape

vlaaad 2020-12-10T17:01:57.190500Z

https://cytoscape.org/release_notes_3_8_0.html

vlaaad 2020-12-10T17:02:45.191Z

There is something about javafx and Java 11, it seems like it's supposed to work?

wilkerlucio 2020-12-10T17:05:00.191200Z

I guess what you are seeing is about their desktop app, I'm using the JS version of it: https://js.cytoscape.org/

wilkerlucio 2020-12-10T17:05:36.191500Z

so, seems like I could try to use their Java version, but its a different thing (I'm trying to re-use the views I already made for the web)

wilkerlucio 2020-12-10T17:06:05.191700Z

I'm trying to take a spin on JxBrowser (which claims to solve the problem by using Chromium instead of webkit)

wilkerlucio 2020-12-10T17:26:15.192100Z

I'm trying to follow the code from other components, but Im not sure how to do the initialization described here https://jxbrowser-support.teamdev.com/docs/quickstart/hello-world.html#run-the-javafx-example with cljfx, because there is the Browser to control things and BrowserView to render it

wilkerlucio 2020-12-10T17:37:04.192500Z

is there something already written in cljfx that looks like that so I can try to base my impl on?

vlaaad 2020-12-10T18:07:17.192900Z

I'll try to come up with example once I'm at the keyboard

πŸ™ 1
vlaaad 2020-12-10T18:07:44.193100Z

But I would suggest looking at components in cljfx.fx nses

vlaaad 2020-12-10T18:08:49.193300Z

The idea is that you create one "composite lifecycle" per mutable object, and then use maps to describe the composition of those mutable objects

vlaaad 2020-12-10T20:57:53.193600Z

grr, they require license and I'm too lazy to fill the form

vlaaad 2020-12-10T20:57:56.193800Z

(require '[cljfx.composite :as composite]
         '[cljfx.fx.node :as fx.node]
         '[cljfx.mutator :as fx.mutator]
         '[cljfx.lifecycle :as fx.lifecycle])

(import '[com.teamdev.jxbrowser.browser Browser]
        '[com.teamdev.jxbrowser.engine Engine EngineOptions RenderingMode]
        '[com.teamdev.jxbrowser.view.javafx BrowserView])

(def browser
  (composite/lifecycle
    {:props (composite/props Browser
              :url [(fx.mutator/setter
                      (fn [^Browser browser ^String url]
                        (when url
                          (.loadUrl (.navigation browser) url))))
                    fx.lifecycle/scalar])
     :args []
     :ctor (fn []
             (-&gt; (EngineOptions/newBuilder RenderingMode/HARDWARE_ACCELERATED)
                 .build
                 Engine/newInstance
                 .newBrowser))}))

(def browser-view
  (composite/lifecycle
    {:props (merge
              fx.node/props
              (composite/props BrowserView
                :browser [fx.mutator/forbidden fx.lifecycle/dynamic]))
     :args [:browser]
     :ctor (fn [^Browser browser]
             (BrowserView/newInstance browser))}))

{:fx/type browser-view
 :browser {:fx/type browser
           :url "<https://github.com/cljfx/cljfx>"}}

vlaaad 2020-12-10T20:58:22.194Z

here is the snippet, it does not work for me without license, but it might work if you have license πŸ˜„

wilkerlucio 2020-12-10T21:27:39.194200Z

hehe, thanks, I'll try it out! but a bummer the license thing

wilkerlucio 2020-12-10T21:52:30.195200Z

its working! very bad its paid... but I learned a lot about cljfx in process, thanks for the help @vlaaad πŸ™

vlaaad 2020-12-10T22:02:47.195600Z

awesome!

vlaaad 2020-12-10T22:02:57.195800Z

my pleasure!

wilkerlucio 2020-12-10T22:49:06.196Z

is there a way to start a view like this strait from the repl?

wilkerlucio 2020-12-10T23:54:11.196200Z

(instead of sending the form, and then requesting "view" via the context menu)

vlaaad 2020-12-11T06:29:22.196600Z

Currently β€” no. I want to make it possible in some way eventually

vlaaad 2020-12-11T07:10:33.197300Z

I have a couple of ideas, yes. Like, having "autoview" behavior that automatically executes "view" action on submitted values, or a special command object, akin to :repl/quit

vlaaad 2020-12-11T07:11:40.197500Z

But instead it shows last submitted value

wilkerlucio 2020-12-11T07:14:42.197700Z

yeah, maybe a new ns just to deal with ways to interact with reveal, so users could do something like (render-view-in-panel {...})

wilkerlucio 2020-12-11T07:15:34.197900Z

I just created also my first custom action, pretty easy πŸ™‚

πŸ‘ 1
wilkerlucio 2020-12-11T20:05:21.198400Z

I wrote a blog post with some of the things from this process: https://blog.wsscode.com/extending-reveal/