GWT - Inject external JavaScript file into GWT application without ScriptInjector - java

I'm working on maintenance project which was developed with GWT version 1.x. Now I have to add some extra features in the same project and for that I have to inject external JavaScript file into GWT application. So I have done a bit of research to achieve the same and I can understand that I can inject the external JavaScript with the help of ScriptInjector class [Source]. but this class is available in GWT version GWT 2.7.0 and I'm using the older version of GWT.
So I would like to know that Can I inject the external JavaScript file without ScriptInjectorclass?

Maybe you can copy the sources of ScriptInjector into your project:
https://gwt.googlesource.com/gwt/+/master/user/src/com/google/gwt/core/client/ScriptInjector.java

public class JavaScriptInjector {
private static ScriptElement createScriptElement() {
ScriptElement script = Document.get().createScriptElement();
script.setAttribute("type", "text/javascript");
script.setAttribute("charset", "UTF-8");
return script;
}
protected static HeadElement getHead() {
Element element = Document.get().getElementsByTagName("head")
.getItem(0);
assert element != null : "HTML Head element required";
return HeadElement.as(element);
}
/**
* Injects the JavaScript code into a
* {#code <script type="text/javascript">...</script>} element in the
* document header.
*
* #param javascript
* the JavaScript code
*/
public static void inject(String javascript) {
HeadElement head = getHead();
ScriptElement element = createScriptElement();
element.setText(javascript);
head.appendChild(element);
}
}
This works if you have your JavaScript as a TextResource. If you want to load from a URL, you can specify the element.setSrc(yourURL) instead of element.setText(javascript). You can also load the javascript from the URL as a HTTP GET and do the setText anyway.

Related

Usage of ScriptInjector in GWT

I want to use javascript library in java source code. I read sth about it and I read, that I should use ScriptInjector. This class has 2 inner classes: ScriptInjector.FromString and ScriptInjector.FromUrl. I want to load javascript library from local file, so I should use from string. How to do it?
ScriptInjector.fromString("myLibrary.js");
does not work. Where to add library?
1) fromUrl - creates script tag with specified src attribute and appends it to the page. E.g.
ScriptInjector.fromUrl("http://example.com/my-script.js").inject();
will simply produce:
<script type="text/javascript" src="http://example.com/my-script.js" />
You can host your files on the web site and inject each of them on demand
2) fromString - creates script tag with specified body of the script, so:
ScriptInjector.fromString("alert('Injected!')").inject();
will give
<script type="text/javascript">
alert('Injected!')
</script>
In this case JS code is a part of your compiled GWT code and browser doesn't require to load it with separate request. I think it is possible to include native JS file into compiled output with TextResource. So you need following:
Define resources
public interface JsResources extends ClientBundle {
final JsResources INSTANCE = GWT.create(JsResources.class);
#Source("first.js")
TextResource firstScript();
#Source("second.js")
TextResource secondScript();
}
Inject required script
ScriptInjector.fromString(JsResources.INSTANCE.firstScript().getText()).inject();
To use .fromString() you'd have to load the JS into a String and pass that.
If you need to load the script using the .fromUrl() you'll have to put it somewhere "Internet" accessible, since the inject() ends up in
private static native void nativeSetSrc(JavaScriptObject element, String url) /*-{
element.src = url;
}-*/;
(See it here)
So: Extract or otherwise expose the script to your webserver.
Cheers,

Input to JavaFX from JSP

I want to give dynamic input to Java FX application from a JSP page. I am not able to find any suitable way.
Dynamic in the sense that I want to give input to JavaFX application based on user input in a JSP page. I am embedding the same Java FX application in the same JSP page.
Any help is welcome regarding the same.
I want to give input to Java FX application when it is running through JSP page.
See the JavaFX deployment topic: Accessing a JavaFX Application from a Web Page.
The JavaScript => JavaFX interface in JavaFX is the same as that used for a traditional Java applet - it makes use of a technology known as LiveConnect. Further documentation on using LiveConnect is in the LiveConnect documentation topic: Calling from JavaScript to Java.
The JavaFX documentation provides the following sample code:
Java Code
package testapp;
public class MapApp extends Application {
public static int ZOOM_STREET = 10;
public static class City {
public City(String name) {...}
...
}
public int currentZipCode;
public void navigateTo(City location, int zoomLevel) {...}
....
}
JavaScript Code
function navigateTo(cityName) {
//Assumes that the Ant task uses "myMapApp" as id for this application
var mapApp = document.getElementById("myMapApp");
if (mapApp != null) {
//City is nested class. Therefore classname uses $ char
var city = new mapApp.Packages.testapp.MapApp$City(cityName);
mapApp.navigateTo(city, mapApp.Packages.testapp.MapApp.ZOOM_STREET);
return mapApp.currentZipCode;
}
return "unknown";
}
window.alert("Area zip: " + navigateTo("San Francisco"));
Note the important comment in the JavaScript code "Assumes that the Ant task uses "myMapApp" as id for this application". The id referred to is the placeholderid parameter of the fx:deploy task.
Now, because you are using a JSP, presumably the html page containing the application is dynamically generated by the JSP processor. So, what you may want to do is make use of the fx:template task to generate modified jsp source which invokes the dtjava deployment script to embed your target JavaFX application.
I'm not sure, but try: HostServices.getWebContext

How to execute JavaScript on Android?

I have code which uses ScriptEngineManager, ScriptEngine class for executing JavaScript code using Java. But it works fine in Java SE, and doesn't work in Android - SDK show error of missing classes. Is it possible to execute JS code in Android? Thank you.
AndroidJSCore is a great one. And here is another little library I wrote for evaluating JavaScript:
https://github.com/evgenyneu/js-evaluator-for-android
jsEvaluator.evaluate("function hello(){ return 'Hello world!'; } hello();", new JsCallback() {
#Override
public void onResult(final String result) {
// get result here (optional)
}
});
It creates a WebView behind the scenes. Works on Android version 3 and newer.
You can use Webview which inherits View class. Make an XML tag and use findViewById() function to use in the activity. But to use the JavaScript, you can make a HTML file containing the JavaScript code. The example blelow might help.
Webview browser=(Webview) findViewById(R.main.browser); //if you gave the id as browser
browser.getSettings().setJavaScriptEnabled(true); //Yes you have to do it
browser.loadUrl("file:///android_asset/JsPage.html"); //If you put the HTML file in asset folder of android
Remember that the JS will run on WebView, not in native environment, thus you might experience a lag or slow FPS in emulator. However when using on an actual phone, the code may run fast, depending on how fast is your phone.
http://divineprogrammer.blogspot.com/2009/11/javascript-rhino-on-android.html will get you started. ScriptEngine is a java thing. Android doesn't have a JVM but a DalvikVM which is not identical but similar.
UPDATE 2018: AndroidJSCore has been superseded by LiquidCore, which is based on V8. Not only does it include the V8 engine, but all of Node.js is available as well.
Original answer:
AndroidJSCore is an Android Java JNI wrapper around Webkit's JavaScriptCore C library. It is inspired by the Objective-C JavaScriptCore Framework included natively in iOS 7. Being able to natively use JavaScript in an app without requiring the use of JavaScript injection on a bloated, slow, security-constrained WebView is very useful for many types of apps, such as games or platforms that support plugins. However, its use is artificially limited because the framework is only supported on iOS. Most developers want to use technologies that will scale across both major mobile operating systems. AndroidJSCore was designed to support that requirement.
For example, you can share Java objects and make async calls:
public interface IAsyncObj {
public void callMeMaybe(Integer ms, JSValue callback) throws JSException;
}
public class AsyncObj extends JSObject implements IAsyncObj {
public AsyncObj(JSContext ctx) throws JSException { super(ctx,IAsyncObj.class); }
#Override
public void callMeMaybe(Integer ms, JSValue callback) throws JSException {
new CallMeLater(ms).execute(callback.toObject());
}
private class CallMeLater extends AsyncTask<JSObject, Void, JSObject> {
public CallMeLater(Integer ms) {
this.ms = ms;
}
private final Integer ms;
#Override
protected JSObject doInBackground(JSObject... params) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
Thread.interrupted();
}
return params[0];
}
#Override
protected void onPostExecute(JSObject callback) {
JSValue args [] = { new JSValue(context,
"This is a delayed message from Java!") };
try {
callback.callAsFunction(null, args);
} catch (JSException e) {
System.out.println(e);
}
}
}
}
public void run() throws JSException {
AsyncObj async = new AsyncObj(context);
context.property("async",async);
context.evaluateScript(
"log('Please call me back in 5 seconds');\n" +
"async.callMeMaybe(5000, function(msg) {\n" +
" alert(msg);\n" +
" log('Whoomp. There it is.');\n" +
"});\n" +
"log('async.callMeMaybe() has returned, but wait for it ...');\n"
);
}
I was also looking for a way to run javascript on Android and came across j2v8 library. This is a java wrapper for Google's v8 engine.
To use it add a dependency:
compile 'com.eclipsesource.j2v8:j2v8_android:3.0.5#aar'
It has pretty simple api, but I haven't found any docs online apart from javadoc in maven repository. The articles on their blog are also useful.
Code sample from this article:
public static void main(String[] args) {
V8 runtime = V8.createV8Runtime();
int result = runtime.executeIntegerScript(""
+ "var hello = 'hello, ';\n"
+ "var world = 'world!';\n"
+ "hello.concat(world).length;\n");
System.out.println(result);
runtime.release();
}
The javax.script package is not part of the Android SDK. You can execute JavaScript in a WebView, as described here. You perhaps can use Rhino, as described here. You might also take a look at the Scripting Layer for Android project.
You can use Rhino library to execute JavaScript without WebView.
Download Rhino first, unzip it, put the js.jar file under libs folder. It is very small, so you don't need to worry your apk file will be ridiculously large because of this one external jar.
Here is some simple code to execute JavaScript code.
Object[] params = new Object[] { "javaScriptParam" };
// Every Rhino VM begins with the enter()
// This Context is not Android's Context
Context rhino = Context.enter();
// Turn off optimization to make Rhino Android compatible
rhino.setOptimizationLevel(-1);
try {
Scriptable scope = rhino.initStandardObjects();
// Note the forth argument is 1, which means the JavaScript source has
// been compressed to only one line using something like YUI
rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);
// Get the functionName defined in JavaScriptCode
Object obj = scope.get(functionNameInJavaScriptCode, scope);
if (obj instanceof Function) {
Function jsFunction = (Function) obj;
// Call the function with params
Object jsResult = jsFunction.call(rhino, scope, scope, params);
// Parse the jsResult object to a String
String result = Context.toString(jsResult);
}
} finally {
Context.exit();
}
You can see more details at my post.
Given that ScriptEngineManager and ScriptEngine are part of the JDK and Android SDK is not the same thing as the JDK I would say that you can't use these classes to work with JavaScript under Android.
You can check the Android SDK's reference documentation/package index to see what classes are included (what can you work on Android out of the box) and which of them are missing.
I just found the App JavaScript for Android, which is the Rhino JavaScript engine for Java. It can use all Java-classes, so it has BIG potential. The problem is it might be slow, since it is not really optimized (heavy CPU load). There is another JavaScript engine named Nashorn, but that unfortunately doesn't works on Google's DalvikVM Java engine (does not support the optimizations of Oracle Java engine). I hope Google keeps up with that, I would just love it!
If you want to run some javascript code on chrome browser as per the question copy this code and paste it into address bar:
data:text/html, <html contenteditable> <title> Notepad </title> <script> alert('Abhasker Alert Test on Mobile'); </script> </html>

How do I mimic HybridUrlCodingStrategy in Wicket 1.5?

We have an existing Java Wicket 1.4 application which uses the HybridUrlCodingStrategy extensively:
mount(new HybridUrlCodingStrategy("/myurl", MyPage.class));
This results in our URL's looking like:
http://host/myurl/paramName1/paramValue1/paramName2/paramValue2
I would like to maintain this URL format in Wicket 1.5, however the HybridUrlCodingStrategy has been removed. In wicket 1.5, pages are mounted as:
mountPage("/myurl", MyPage.class);
Which results in traditional URLs like:
http://host/myurl?paramName1=paramValue2&paramName2=paramValue2
I have read that we should be using the MountedMapper class, but looking at the Wicket 1.5 examples, API docs, and source code, it is still not clear to me how to get the same behavior with MountedMapper as we are getting with the HybridUrlCodingStrategy.
Does anyone know how to do this?
Maybe something like this:
mountPage("/myurl/paramName1/${paramValue1}/paramName2/${paramValue2}", MyPage.class)
would work? Granted, you'd have to manually specify your parameters, which could be a lot more work.
The MountedMapper class javadoc explains how to use parameters.
The other option I can think of would be (Note: this is untested):
class MyPageParametersEncoder implements IPageParametersEncoder() {
public PageParameters decodePageParameters(Request request)
{
PageParameters parameters = new PageParameters();
int i = 0;
for (Iterator<String> segment = request.getUrl().getSegements().iterator(); segment.hasNext()) {
String key = segment.next();
String value = segment.next();
parameters.add(key, value);
}
return parameters.isEmpty() ? null : parameters;
}
public Url encodePageParameters(PageParameters pageParameters)
{
Url url = new Url();
for (PageParemeters.NamedPair pair : pageParameters.getAllNamed() {
url.getSegments().add(pair.getKey());
url.getSegments().add(pair.getValue());
}
return url;
}
}
mount(new MountedMapper("/myurl/", MyPage.class, new MyPageParametersEncoder());
No need of custom IPageParametersEncoder.
With mountPage("/myurl/paramName1/${paramValue1}/paramName2/${paramValue2}", MyPage.class) the URL will look like in 1.4 but the values will be reachable as StringValue value1 = parameters.get("paramValue1"). Similar for value2.
With mountPage("/myurl/${paramValue1}/${paramValue2}", MyPage.class) is the same according to extracting the values, just shorter URL will be used.
It also supports optional paramaters - #{optionalValue3}.
NOTE: A new class has been added to Wicket 1.5.2 for backwards compatibility with 1.4 style URL encoding. It's called UrlPathPageParametersEncoder - use that if you're migrating a wicket 1.4 app to 1.5 and you have bookmarkable page links of the style:
www.mysite.com/name1/value1/name2/value2
We had the exact same issue when migrating from 1.4 to 1.5. Any 1.4 app that has been live for a while would likely have a collection of links pointing to it from external sites on the web. You really want the Wicket 1.5 version of your app to be able to handle these existing hybrid links without generating an error.
When migrating to 1.5, without a 1.4 compatible IPageParametersEncoder implementation, you need to include the full parameter specification in every mount if you want to avoid making changes to each individual Page class that reads parameters. The implementation below means that is no longer necessary. Just mount the page as livid suggests above.
I'm submitting this .java file as a patch to the Wicket devs - they may include it in Wicket in the future to make it easy to implement backwards compatible URL parameter encoding for other 1.4 migrators.
I took luniv's sample code above and made a few small changes to get it compiling/working. The following should work as a parameter encoder to provide 1.4.x style parameter encoding in 1.5.
package org.apache.wicket.request.mapper.parameter;
import java.lang.*;
import org.apache.wicket.request.mapper.parameter.IPageParametersEncoder;
import java.util.Iterator;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.mapper.parameter.PageParameters;
public
class HybridPageParametersEncoder implements IPageParametersEncoder
{
/**
* Encodes a URL in the form:
*
* /mountpoint/paramName1/paramValue1/paramName2/paramValue2
*
* (i.e. a URL using the pre wicket 1.5 Hybrid URL strategy)
*/
public Url encodePageParameters(PageParameters pageParameters)
{
Url url = new Url();
for (PageParameters.NamedPair pair : pageParameters.getAllNamed())
{
url.getSegments().add(pair.getKey());
url.getSegments().add(pair.getValue());
}
return url;
}
/**
* Decodes a URL in the form:
*
* /mountpoint/paramName1/paramValue1/paramName2/paramValue2
*
* (i.e. a URL using the pre wicket 1.5 Hybrid URL strategy)
*/
public PageParameters decodePageParameters(Request request)
{
PageParameters parameters = new PageParameters();
int i = 0;
for (Iterator<String> segment = request.getUrl().getSegments().iterator(); segment.hasNext(); )
{
String key = segment.next();
String value = segment.next();
parameters.add(key, value);
}
return parameters.isEmpty() ? null : parameters;
}
}

How to call jquery trigger from gwt?

public static native void doConnect() /*-{
$wnd.jQuery(document).trigger('connect',
{
jid: 'sss',
password: 'sss'
}
);
}-*/;
i tried the above ,but there is no error in firebug or gwt hosted mode
console(so i cannot know whether the code is success or not). may i know is this the correct way to call jquery trigger? but when i put alert() in bind('connect'), it was not called
inside .js file
$(document).bind('connect', function (ev, data) {
alert('not call.....at all');
var conn = new Strophe.Connection(
"http://bosh/xmpp-httpbind");
conn.connect(data.jid, data.password, function (status) {
if (status === Strophe.Status.CONNECTED) {
$(document).trigger('connected');
} else if (status === Strophe.Status.DISCONNECTED) {
$(document).trigger('disconnected');
}
});
Hello.connection = conn;
});
I had similar issues when using jQuery UI with GWT - no errors in console/dev mode, yet the code did not behave like I wanted. The reason was that jQuery (and such frameworks) extend/change many core elements of JavaScript and expect it to stay that way - however, GWT code (meaning, also JSNI stuff) is executed from a "clean" iframe (so that no external frameworks can mess with the language and cause some weird errors in GWT, that's why you have to reference to the main window via $wnd).
I'd suggest moving your doConnect function to the host page (or external js file linked to the host page) and instead just call that function from your JSNI stub:
public static native void doConnect() /*-{
$wnd._doConnect('sss','sss'); //_doConnect defined in the host page
}-*/;
Or provide helper functions that will return Arrays, etc, from the host page, so that they include all the changes that jQuery made and expects.
It's a bit late for this answer, but your original code did not work due to a simple mistake: You have properly used $win instead of window but a few characters later you have used document instead of $doc :)
public static native void doConnect() /*-{
$wnd.jQuery($doc).trigger($wnd.jQuery.Event('connect', {
jid: 'sss',
password: 'sss'
}));
}-*/;

Categories