How to call a java class method from javascript - javascript

I'd an applet "edu.MGT.MainApplet" implemented in a jar "MGT2-0.0.1.jar". A local html page used the tag <applet> to call methods of this class. Everything was working correctly some time ago.
(In detail: the applet provides a set of methods for analysis and transformation of mathematical expression. Mathematical expressions are stored as data trees, and the set of methods allows apply to them usual math operations, finding sub-expressions, execute calculus, ... . The API of the applet is very simple: methods have a name and simple arguments, usually only one integer or one string and returns one string. The trees with the math expressions are never transferred, they are keep at applet. The html/javascript GUI contains buttons to execute the methods and transforms the string result, using MathJax, to graphical mathematical expressions).
The related javascript lines are:
> <applet id="mgt"
> archive="MGT2-0.0.1.jar" style="width: 1px; height: 1px; float: left;"
> code="edu.MGT.MainApplet">
> </applet>
>
> <script>
> var TeX = mgt.predefined(1);
> ...
where "mgt.predefined(1)" is one example of a call to one method of the java class that is the applet.
Nowadays, with navigator firefox 57.0, the console shows the error:
TypeError: mgt.predefined is not a function [Learn More]
gtexpression1.html:90:15
I've checked the content of the jar. Class exists and method exists:
$ jar -xvf MGT2-0.0.1.jar
...
inflated: edu/MGT/MainApplet.class
...
and the class has the related method:
$ javap edu/MGT/MainApplet.class
Compiled from "MainApplet.java"
public class edu.MGT.MainApplet extends java.applet.Applet {
...
public java.lang.String predefined(int);
After lots of hours googling and trying ...
Try number 1:
use <object> instead of <applet>: no changes in the result.
Try number 2:
Move to Java Web Start. I've wrote following MGT2.jnlp file:
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="" href="">
<information>
<title>MGT</title>
<vendor>private</vendor>
</information>
<resources>
<j2se version="1.7+"
href="http://java.sun.com/products/autodl/j2se" />
<jar href="MGT2-0.0.1.jar" main="true" />
</resources>
<applet-desc main-class="edu.MGT.MainApplet"
name="MGT"
width="1" height="1">
</applet-desc>
<update check="background"/>
</jnlp>
and changed the javascript part to:
<script src="http://www.java.com/js/deployJava.js"></script>
<script>
var attributes = {
code: "edu.MGT.MainApplet",
id: "MGT",
width:1, height:1} ;
var parameters = {jnlp_href: 'MGT2.jnlp'} ;
deployJava.runApplet(attributes, parameters, '1.7');
but following error appears:
ReferenceError: mgt is not defined [Learn More]
gtexpression1.html:103:9
Try number 3:
Same jnlp file than in previous, one more line in the javascript code:
<script src="http://www.java.com/js/deployJava.js"></script>
<script>
var attributes = {
code: "edu.MGT.MainApplet",
id: "mgt",
width:1, height:1} ;
var parameters = {jnlp_href: 'MGT2.jnlp'} ;
deployJava.runApplet(attributes, parameters, '1.7');
var mgt = document.getElementById("MGT");
and the error is:
TypeError: mgt is null [Learn More] gtexpression1.html:103:9
Nowadays, how to call Java code from www page ?

the <applet> tag has been obsolete for several years now, and definitely does nothing in any recent version of Firefox. So the simplest answer here would be that if you really are using firefox (you say you're using a firefox user agent, so it's unclear whether you mean you're using firefox, or you've change the useragent string to claim your non-firefox browser is firefox), the applet is never loaded, so your JS is trying to call something that doesn't exist as a function, and that's not going to work.
At the very least, you want to try to load your code with <object> instead (and then you'll need to have an applet execution plugin installed, FF/Chrome no longer execute java themselves), but an even better suggestion would be to not use Java at all, as modern JS has obviated the need for Java integration into pages.

Related

How can I escape a string to ensure that it is a valid string literal in JS source?

I have a Qt application that embeds a web browser (QWebEngineView). I would like to call a javascript function with a string argument from the C++ application. The means of doing this is calling
page()->runJavaScript("setContent(\"hello\");");
This works in simple cases. However, if I try and load, say, a C++ source file and use that as the parameter of setContent, this will break, because I can't simply assemble the string like this:
auto js = QString("setContent(\"%1\");").arg(fileStr);
I tried the following:
fileStr = fileStr.replace('"', "\\\"");
fileStr = fileStr.replace("\n", "\\n");
But apparently this could not escape the string, I get an error when I call this javascript. How can I universally escape a long string with newlines and possible special characters so that I can construct a valid js fragment like this?
So, after some research, I came across QWebChannel which is meant for bi-directional communication between the application and the hosted webpage. The imported qwebchannel.js in the examples can be found here. From there, this is what I did:
In C++:
auto channel = new QWebChannel(this);
page()->setWebChannel(channel);
channel->registerObject("doc", Doc);
In HTML/JS:
new QWebChannel(qt.webChannelTransport,
function(channel) {
var doc = channel.objects.doc; // this is "doc" from the registerObject call
editor.setValue(doc.text);
doc.textChanged.connect(updateText); // textChanged is a signal of the class of doc.
}
);
So, even though this does not directly answer the question, what is presented here can be used to achieve the same effect.

Sending Javascript code to client-side is not escaped correctly

I'm struggling with an encoding-problem in a small system I'm constructing.
In an HTML, this script is loaded
<script src="http://localhost:8000/serving/dk-711218"></script>
and normally I can't access the HTML so everything has to be done inside the javascript file.
The server-side scripts are made in Node.js and it returns pieces of code depending on some settings in customizable XML files. For instance, when displaying an image the system returns a simple
<img src="mypicture.jpg" />
and if it's a text, it returns
<div class="myClass">This is a test</div>
and if they have special behaviors, this code is included as well.
These parts work as intended. These chunks of code resides inside a number of classes and are returned as needed so that the code is gradually built.
So far, so good.
The problem is returning the SWFobject library code, because it seems to corrupt the code on the fly.
All code has been escaped and encoded with encodeURIComponent so that the system just needs to decode and unescape. But the validation fails.
Here's an example of the first few lines before encoding/escaping:
var%2520swfobject%253Dfunction%2528%2529%257Bvar...
Here's how a piece of the SWFObject looks like in the Firefox source code window when accessing the page:
and here's how a piece of the decoded SWFObject looks like in the same window:
This occurs at several places and something that's common for these occurrences is that it looks like the less-than character for unknown reasons is interpreted differently.
Here's the view renderer and I can't figure out if problem is caused in the code or when rendering the code.
Any ideas to what's causing this behavior? Or perhaps some advices on best practice when including code this way?
Responses to comments:
try JSON.stringify
I've tried the JSON solution out as well and it does the trick!
What I did was - as before - to pre-process the included code, using a little tool I built with two input-fields and a JSON.stringify-command between the two. This resulted in the content of returnvar:
Module.prototype.opens = function () {
var returnvar = "var swfobject=function(){var D=\"undefined\",r=\"object\",S=\"Shockwave Flash\",W=\"ShockwaveFlash.ShockwaveFlash\",q=\"application/x-shockwave-flash\",R=\"SWFObjectExprInst\"... etc.
and a JSON.parse is used to correct it again in the renderer:
router.get('/serving/:id', function (req, res) {
var readSymbolicsXMLCallback = function(data) {
res.render('index', {
id: req.params.id,
embedcode: JSON.parse(data)
});
}
var embedcode = readSymbolicsXML(req.params.id, readSymbolicsXMLCallback);
});

How to check if JSF resource exists before loading view

In a project using JSF, we have JavaScript files located here:
MyProject/view/javascript/*.js
In the xhtml file, I include these resources as
<script type="text/javascript" src="javascript/#{myBean.jsFileName}.js" />
This works fine, but it's possible that #{myBean.jsFileName}.js doesn't exist, in which case I want to load "Default.js".
In myBean (or in the xhtml file itself), how can I first check for the existence of a js file before setting the #{myBean.jsFileName} value? I've tried variations of this:
File f = new File("javascript/myFile.js");
if (!f.exists){ jsFileName="Default"};
But I don't think that's right. Am I on the right track?
You can use ExternalContext#getResource() to obtain a web resource as URL. It will return null if resource doesn't exist. It takes a path relative to the web root and should preferably always start with /.
So. this should do in bean:
String fullPath = "/view/javascript/myFile.js";
URL resource = FacesContext.getCurrentInstance().getExternalContext().getResource(fullPath);
if (resource == null) {
fullPath = "/view/javascript/default.js";
}
Or, equivalently, this in the view, which is IMO somewhat hacky:
<c:set var="available" value="#{not empty facesContext.externalContext.getResource(bean.fullPath)}" />
<script src="#{available ? bean.fullPath : bean.fullDefaultPath}" />
See also:
getResourceAsStream() vs FileInputStream
Unrelated to the concrete problem, if you were using JSF 2.x (at least Facelets, as implied by being able to use unified EL in template text in your code snippet), you should be using resource libraries with <h:outputScript>. See also How to reference CSS / JS / image resource in Facelets template?

Firefox addon SDK and DOM manipulation problems

I'm trying to get to grips with the Firefox addon SDK (previously known as Jetpack from what I understand), but I'm having problems working with the DOM.
I need to iterate over all of the text nodes in the DOM when a web page loads and make changes to some of the strings that they contain. I've posted a simplified version of what I'm doing below (new to Javascript, so forgive me any oddities).
// test.js
function parseElement(Element)
{
if (Element == null)
return;
var i = 0;
var Result = false;
if (Element.hasChildNodes)
{
var children = Element.childNodes;
while (i <= children.length - 1)
{
var child = children.item(i);
parseElement(child);
i++;
}
}
if (Element.nodeType == 3)
{
// For testing - see what the text node contains
alert(Element.nodeValue);
Result = true;
}
return Result;
}
window.addEventListener("load", function load(event)
{
window.removeEventListener("load", load, false);
parseElement(document.body);
}
When I create a basic HTML document:
<!-- test.html -->
<html>
<head>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<b>hello world</b>
<p>foo</p>
<i>test</i>
</body>
</html>
...include this Javascript file in the HEAD section then open it in Firefox, the "alert" displays 6 dialog boxes containing:
1) "hello world"
2) blank -> no visible characters, just a newline
3) "foo"
4) blank -> no visible characters, just a newline
5) "test"
6) blank -> no visible characters, just a newline
Exactly what I would expect to see.
The problem arises when I create an addon and use test.js as a page-mod Content Script from my main.js file (modified to remove the "addEventListener" part). When I use "cfx run" to start Firefox with my addon installed, then open the same HTML document (with the "script" part for the test.js file commented), the alerts do not display at all.
So that's the first puzzle. But having also navigated to other web pages - for example, a YouTube video page - the alert DOES display several dialogs, but they include very strange strings, mostly the content of script tags:
EDIT I don't have enough reputation to embed an image, so here's a link instead showing the sort of thing I mean instead: http://img46.imageshack.us/img46/5994/mtpd.jpg
And again, the text I would expect to see is absent.
Apologies for some of the redundancy below, but just to be clear: this is my main.js:
main.js
var data = require("sdk/self").data;
var data = require("sdk/self").data;
exports.main = function()
{
pageMod.PageMod({
include: "*",
contentScriptFile: [data.url("test.js")]
});
}
And the modified version of the Javascript file is identical to the "test.js" listing above, but for the end part:
test.js
<snip>
...
return Result;
}
parseElement(document.body);
I've included my project files (if I can call them that) in a zip if it makes things easier to visualise: http://www.mediafire.com/?774iprbngtlgkcp
I've tried changing
parseElement(document.body);
to
parseElement(unsafeWindow.document.body);
in case it makes any difference, but the outcome is identical.
So I'm very puzzled about what's happening. I can't understand why the test.js file isn't picking out the text nodes (and only the text nodes) from the DOM when I use it as part of an addon, but does exactly what I would anticipate when included as a script in a HTML document. Can anyone shed any light on this?
Thank you in advance.
Errors in your lib code and contentScripts are usually logged to the Error Console. Check what is printed there. Also see the SDK console module.
Your page-mod won't run because by default page-mods will run only after the load event.
See the contentScriptWhen documentation.
script tags actually often have a text-node child containing the inline script source. So it is absolutely normal that those are enumerated as well.
For some discussion about walking tree nodes, see: getElementsByTagName() equivalent for textNodes
However, if you're after the text of specific ids/classes, consider using document.querySelector/.querySelectorAll, or if you're after nodes that have a specific XPath, use document.evaluate. This very likely will be a lot faster.
Other than that, I cannot really tell what exactly your remaining issues are and what you're trying to achieve in the first place exactly, so I cannot advice on that.
You wondered that
I've discovered that my add-on is NOT executed when a document is
accessed via File->Open File.
That is by design. At match-pattern, it says that
A single asterisk matches any URL with an http, https, or ftp scheme.
For other schemes like file, resource, or data, use a scheme followed
by an asterisk, as below.
You can use the regular expression /.*/ to match all sites and all schemas.

Using javascript to rename multiple HTML files using the <TITLE></TITLE> in each file

I have used HTTRACK to download Federal regulations from a government website, and the resulting HTML files are not intuitively named. Each file has a <TITLE></TITLE> tag set, that would serve nicely to name each file in a fashion that will lend itself to ebook creation. I want to turn these regulations into an ebook for my Kindle, so that I can have the regulations readily available for reference, rather than having to carry volumes of books with me everywhere.
My preferred text/hex editor, UltraEdit Professional 15.20.0.1026, has scripting commands enable through embedding of the JavaScript engine. In researching possible solutions to my problem, I found xmlTitleSave on the IDM UltraEdit website.
// ----------------------------------------------------------------------------
// Script Name: xmlTitleSave.js
// Creation Date: 2008-06-09
// Last Modified:
// Copyright: none
// Purpose: find the <title> value in an XML document, then saves the file as the
// title.xml in a user-specified directory
// ----------------------------------------------------------------------------
//Some variables we need
var regex = "<title>(.*)</title>" //Perl regular expression to find title string
var file_path = UltraEdit.getString("Path to save file at? !! MUST PRE EXIST !!",1);
// Start at the beginning of the file
UltraEdit.activeDocument.top();
UltraEdit.activeDocument.unicodeToASCII();
// Turn on regular expressions
UltraEdit.activeDocument.findReplace.regExp = true;
// Find it
UltraEdit.activeDocument.findReplace.find(regex);
// Load it into a selection
var titl = UltraEdit.activeDocument.selection;
// Javascript function 'match' will match the regex within the javascript engine
// so we can extract the actual title via array
t = titl.match(regex);
// 't' is an array of the match from 'titl' based on the var 'regex'
// the 2nd value of the array gives us what we need... then append '.xml'
saveTitle = t[1]+".xml";
UltraEdit.saveAs(file_path + saveTitle);
// Uncomment for debugging
// UltraEdit.outputWindow.write("titl = " + titl);
// UltraEdit.outputWindow.write("t = " + t);
My question is two-fold:
Can this JavaScript be modified to extract the <TITLE></TITLE> contents from an HTML file and rename the files?
If the JavaScript cannot be modified easily, is there a script/program/black magic/animal sacrifice that can accomplish the same thing?
EDIT:
I have been able to get the script to work as desired by removing the UltraEdit.activeDocument.unicodeToASCII(); line and changing the file extension to .html. My only issue now is that while this script works on single open files, it does not batch process the directory.
You can use just about any "scriptable" language to do something like this pretty quickly. Ruby is my favorite:
require 'fileutils'
dir = "/your/directory"
files = Dir["#{dir}/*.html"]
files.each do |file|
html = IO.read file
title = $1 if html.match /<title>([^<]+)<\/title>/i
FileUtils.mv file "#{dir}/#{title}.html"
puts "Renamed #{file} to #{title}.html."
end
Obviously if your UltraEdit script worked for you this might be obtuse, but for anybody running a different env, hopefully this is useful.
Does this not work out of the box?
I don't know anything about UltraEdit, but as far as a regex engine is concerned, if it can parse <title>(.*)</title> out of an XML document, it can do the exact same for HTML.
Just modify the final file title to .html instead of .xml
saveTitle = t[1]+".html";
Assuming you can get that script to work as it's intended (point being I don't know UltraEdit), I'm pretty confident that same process will work for HTML.
XML and HTML are both plain text, and that script is simply running a regular expression on the text to extract the title tags, which are the same in both; the only thing you need to do is change this line:
saveTitle = t[1]+".xml";
to this:
saveTitle = t[1]+".html";
After much searching and trial and error on the scripting side, I ran across a fantastic program for Windows that will do the renaming via TITLE tags: Flexible Renamer 8.3. The author's website is http://hp.vector.co.jp/authors/VA014830/english/FlexRena/, and it manages to handle every bit of what I needed. Many thanks to #coreyward and #Yuji for their fantastic advice on the scripting end of things.

Categories