B4J Library jScriptEngine

===================================
The Nashorn scriptengine is being removed in java 11
===================================
(but it hasn't gone yet. See post #26 of this thread)


Important:
the scriptengine has nothing to do with browsers nashorn cannot be run in a web page, it is for server side applications.

Here is a small library that allows use of javascript from B4J.
Some functions are easier to perform in js as you have basically all the java functions at your disposal to use.
The B4J project is overly commented to show how to use the lib.
It has example of converting a uniicode string to a string B4J understands.
It implements a crude split function.
The js script can be in-line or read from an external file.

The jNashorn (o-r-n) is the updated library using the preferred script engine for javaFX 8

Almost identical to jScriptEngine in use, but the engine itself very powerful.
Read up on Nashorn to see the full extent of the engine. Requires Java 8 to run.

UPDATE
Found a useful bit of code to allow access to b4j variables and routines from within the js script
(tested on Java 8, with jScriptEngine and jNashorn libraries)
B4X:
   ...
   Dim js As jScriptEngine
   Dim ss As String = Me
   ss = ss.SubString(ss.IndexOf(" ")+1) ' build class name b4j.example.main is default
   js.evalstring($"var b4j = Java.type(""$ & ss & $"");"$)
   js.evalString($"b4j._test(" there");"$) '<<< runs b4j sub test
End Sub
Sub test(s As String)
   Log("hello" & s)
End Sub

=================================================================
UPDATE 28/10/15

Added 2 new files
nashorn invocable test ( the test file)
jInvokeNashorn (the library)

The first is a test file for the second , which is a new version of the nashorn library.

This version is quite different to the original jNashorn library
It does not support engineGet/Put , evalString or evalFile.

It simply has 2 entry points,
1, initInvocable()
2, Invoke()

initInvocable takes one parameter, it can be a string containing the script or the name of a script file (ending with .js) , if it is a script file it will look in the folder ./scripts for the file.

Invoke takes as many parameters as you like, but the first is always the function name in the script you wish to run.

The test file is well commented on how to use the new library.
You no longer need the get/put/eval in the original library as you can directly invoke functions in the script, which can return values or even call b4j subs directly with parameters.

Forgot to comment some lines in the test program.
the dim b4j as string
and
b4j = me
b4j = b4j.replace("class ","")
is needed to allow the script to access the b4j subs and variables directly.
 

Attachments

  • jScriptTest.zip
    1.6 KB · Views: 973
  • jScriptEngine.zip
    2.3 KB · Views: 1,628
  • jNashorn.zip
    2.3 KB · Views: 803
  • nashorn invocable test.zip
    1.4 KB · Views: 560
  • jInvokeNashorn.zip
    2.7 KB · Views: 642
  • reels example.zip
    5.1 KB · Views: 653
Last edited:

Daestrum

Expert
Licensed User
Longtime User
I found another use for the library, one that justifies it's existance.
It allows you access to almost all of a controls properties and methods.
This code snippet, sets the TableView column count to what you want (three in the example code) not the default 'what you want plus one'
It also enables the TableView Menu button, you can click the columns listed in it, to hide or show them.

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private tab1 As TableView    
    Private js As jScriptEngine   ' need to add to libs
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("tabres1")  ' simple layout with a TableView only
    tab1.SetColumns(Array As String("One","Two","Three"))
    MainForm.Show
    js.enginePut("tab1",tab1)
    js.evalString("tab1.setColumnResizePolicy(tab1.CONSTRAINED_RESIZE_POLICY);")
    js.evalString("tab1.tableMenuButtonVisible = true;")
    js = Null   ' feed jScriptEngine to GC  :(
End Sub
 

Daestrum

Expert
Licensed User
Longtime User
Newer library for javaFX8 - uses the preferred script engine Nashorn ( o-r-n looks like om)
Same functions as old one - get put eval etc - but please read up on Nashorn as it's functions are far more powerful.
This works with javaFX8
 

Attachments

  • jNashorn.zip
    2.3 KB · Views: 530

Daestrum

Expert
Licensed User
Longtime User
I have successfully got groovy, python and ruby running as a script engine.
I don't know the languages well, so just how well they perform I can't tell.

If anyone wants to try them I can upload the libraries, just let me know.
 

Bruce Axtens

Active Member
Licensed User
Longtime User
Perl?
 

Daestrum

Expert
Licensed User
Longtime User
Not found a nice way to run perl from java (yet).
 

Daestrum

Expert
Licensed User
Longtime User
Just found that using the groovy scriptengine I can have a javaFX screen created and displayed in a non-ui b4j program.

I remember someone asking if it was possible to have a UI in a non-ui program, seems the answer is yes. :)

Seems I got itslightly wrong, after further testing, you can display the FX screen, but it blocks the messageloop. So its good for splash screens etc.
 
Last edited:

raphaelcno

Active Member
Licensed User
Longtime User
Hello,

I try to use the jScriptEngine library to make some interaction between a TableView containing GPS coordinates and a WebView with Google Maps JavaScript API.

Here is a part of the JavaScript code contained in the HTML string loaded by WebView_Map.LoadHtml:
B4X:
[...]
' Initial position of the marker (coordinates from row 0 in the table/array)
"var latLng = new google.maps.LatLng(" & Arr_Gps(0, 0) & ", " & Arr_Gps(0, 1) & ");"
[...]
' Function to move the marker when you click on the map
"google.maps.event.addListener(map, 'click', function(event) {"
    "latLng = event.latLng;"
    "marker.setPosition(latLng);"
"});"
[...]
This JavaScript code seems to work correctly.

Now I want to click on a row in the table and make the marker move to the coordinates contained in this row.
I try this code:
B4X:
Sub Process_Globals
    [...]
    Dim WebView_Map As WebView
    ' WebEngine
    Private Java_WebEng, Java_Map As JavaObject
    Private jSE As jScriptEngine
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    [...]
    'Initialize the WebEngine:
    Java_WebEng.InitializeNewInstance("javafx.scene.web.WebEngine", Null)
    Java_Map = WebView_Map
    Java_WebEng = Java_Map.RunMethod("getEngine", Null)
    WebView_Map.LoadHtml(xxxxxxxxxxx)  ' HTML with JavaScript
End Sub

' Event when clicking in the TableView
Sub TblView_Gps_SelectedRowChanged(Index As Int, Row() As Object)
    If Index > -1 Then
        ' The log shows correct values of Index and GPS coordinates
        Log("SelectedRowChanged: Index = " & Index)
        Log("Lat = Arr_Gps(Index, 0) = " & Arr_Gps(Index, 0))
        Log("Long = Arr_Gps(Index, 1) = " & Arr_Gps(Index, 1))
        ' The following lines are probably not correct, the marker does not move on the map
        jSE.enginePut("doc", Java_WebEng.RunMethod("getDocument", Null))
        jSE.evalString("doc.latLng = google.maps.LatLng(" & Arr_Gps(Index, 0) & ", " & Arr_Gps(Index, 1) & ");")
        jSE.evalString("doc.marker.setPosition(doc.latLng);")
    End If
End Sub

How should I use the methods in jScriptEngine?
Should I create a function called moveMarker in the JavaScript code and call this function from the SelectedRowChanged Sub?

Raphaël
 

CHAUVET

Member
Licensed User
Longtime User
hello,

I am a new user of B4J.

With B4J I have a webview that load a page eg www.google.fr, and I want to change the value of an input text on the page.

I load the page with command line :

zoneweb.LoadUrl("http://www.google.fr") -> zoneweb is the name of my webview objet

When page is loaded i have this code :

Try
Dim joWV As JavaObject = zoneweb
joWV.RunMethodJO("getEngine", Null).RunMethod("executeScript", Array As String("My JavaScript code here"))
Catch
html_txtarea.Text = LastException.Message
End Try

If i replace : "My JavaScript code here" by : "history.back()" -> it's OK
But if i try to use :

"document.form[0].getElementByName('q').value = 'Hello'"

But in this case i have the error : netscape.javascript.JSException: TypeError: 'undefined' is not an object

With : document.form[0].getElementById('q').value = 'Hello' -> I have the same error.

In fact i need the word hello in the <input type=text name="q" value=""> with the parameter: name = "q" on the webpage loaded in the webview...

Can you help me please ?
 
Last edited:

Daestrum

Expert
Licensed User
Longtime User
Added a bit of example code to show how to access variables and routines in the B4J program without using enginePut/Get
 

Daestrum

Expert
Licensed User
Longtime User
Added new version of nashorn library - read the notes it's completely different to the original, but far more efficient and easier to use.
 

Daestrum

Expert
Licensed User
Longtime User
Added another example (hope I included all the needed files) reels example.zip

It won't win awards for graphics lol, but it does show a functioning slot machine in 107 lines of code :)

It does show
1, How to use the userData (B4J = Tag) to store code that can be executed later in javascript.
2, How to wrap an image onto a cylinder
3, How to spin the cylinders, to give the impression of slot machine reels.

Have fun - and someone please give it some nice graphics :)
 

Bel

Member
Licensed User
Hi thanks for library
Can i get selection text in webview? or set selection text or change it?
 
Top