Invoke JavaScript callback from QT with structure/object argument - javascript

I am using QT 5.5 version.
I need to invoke javascript callback function from QT plugin with Structure/Object as argument. I could not modify HTML Application since it is not in our scope.
HTML application code snippet
var obj1 = document.getElementById('obj1_id'); //QT plugin object 1
var obj2 = document.getElementById('obj2_id'); //QT plugin object 2
obj2.init(obj1,callback); //QT API
function callback(arg1)
{
if ( obj1 === arg1){
// SUCCESS
else
// FAILURE
}
QT plugin code snippet
class::init(QWebElement obj, QString callback)
{
//need to Invoke callback with obj argument
}
Can any one help me on this?

Using Qt Signals and Slots -
In your javascript function -
add the following line -
myoperation.alert_script_signal.connect(callback);
In the Qt framework based C++ class - constructor, add the following line -
Register your Javascript callback --
view->page()->mainFrame()->addToJavaScriptWindowObject("myoperation", this);
// now invoke the callback from some method in that Qt class.
emit alert_script_signal();
You need to understand one thing that QtWebkit is the platform here. So, basically, the html, javascript is running on the Qt Webkit.
I have some examples - http://www.tune2wizard.com/linux-qt-callback-from-c-to-the-javascript-function/

Related

Fable: Calling a native Javascript function that requires JQuery

I have F# experience, but am new to Fable (and Javascript, npm, webpack, etc.). In my app, I'm trying to call an external Javascript library called cardsJS in order to display playing cards. However, this library requires JQuery, so I'm not sure how to call it from Fable/F#.
To be specific, one of the Javascript functions exposed by the library is:
// Gets the ID of the card, e.g. "KS" for the king of spades.
cid: function (card) {
var s = card.attr('src');
return s.substring(s.length - 6, s.length - 4);
},
In cardsJS, a card is just an HTML img element, so I tried to import the cid function in my Fable code via:
type ICardsJS =
abstract member cid : HTMLImageElement -> string
let iCardsJS : ICardsJS = importDefault "cardsJS/cards.js"
However, when I call iCardsJS.cid(card) this way, I get a Javascript runtime error:
Uncaught TypeError: card.attr is not a function
at Object.cid (cards.js:30:26)
The problem here is that the library apparently expects a JQuery object, rather than the raw DOM element, so it can call the object's attr function. So I guess my F# interface should actually look something like this instead:
type ICardsJS =
abstract member cid : JQueryThing??? -> string
If I was writing in raw Javascript, I could wrap the DOM element as a JQuery object, like this: $(card). How can I accomplish the same thing in Fable? I'm sure I need to import JQuery into my F# code somehow, but I don't know the right incantation. The only lead I've found so far is this issue, which suggests something like:
let jq : obj = importDefault "jquery"
let jqCard = jq $ card
But that doesn't compile in Fable 3:
error FSHARP: Value restriction. The value 'jqCard' has been inferred to have generic type
val jqCard : obj
I think the problem there is that jq has the wrong type (obj instead of some sort of IJQuery interface) and the compiler thinks that $ is from Fable.Core.JsInterop:
///<summary>
/// Destructure and apply a tuple to an arbitrary value.
/// E.g. `myFn $ (arg1, arg2)` in JS becomes `myFn(arg1, arg2)`
///</summary>
val ($) : callee: obj -> args: obj -> 'a

How do I call javascript(node.js) function from plain old c++ function?

I'm now struggling to integrate C++ library(zserge/webview) with V8. This library is designed to invoke C function whenever I run certain Javascript code on Webview.
As an example:
When you run this code below (inside a webview instance made by zserge/webview)
window.external.invoke('hello world');
then the C function is executed.
void my_cb(struct webview *w, const char *arg){
...
}
As I stated, I'm now integrating this with V8, so I want this function 'my_cb' to invoke Javascript function that I stored into a variable.
I made a function name as 'SetCallback' like below and exposed to node,
void SetCallback(const FunctionCallbackInfo<v8::Value> & args){
Environment *env = Environment::GetCurrent(args);
Isolate *isolate = env->isolate();
auto cb = v8::Local<v8::Function>::Cast(args[0]);
//g_callback is defined like this-> v8::Persistent<v8::Function> g_callback;
g_callback = v8::Persistent<v8::Function>::New(cb);
}
I thought that if I insert some code to my_cb I can invoke a function that I stored to g_callback.
So I coded like below:
void my_cb(struct webview *w, const char *arg){
Isolate *isolate = Isolate::GetCurrent();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Function> cb = v8::Local<v8::Function>::New(isolate, g_callback);
v8::Local<v8::Value> argv[] = {};
cb->Call(isolate->GetCurrentContext()->Global(), 0, argv);
}
But this code doesn't work. I assume that my_cb is unsafe to call v8 function because it's outside of v8 instance. However, I don't know how I can fix this.
Thank you in advance, please help me fix this.

DukTape Display JavaScript Canvas on GLUT Window

I managed to get DukTape working in my GLUT project (it is able to run inline javascript with duk_eval_string();). Is it possible to display a static html canvas with javascript graphics in a C++ GLUT window using DukTape?
Using the HTML5 canvas drawing methods is not possible in Duktape.
Duktape is a Javascript engine, what means that it allows you to execute ES5/5.1 compliant code. Displaying a HTML canvas is a task Duktape can't do.
If you ultimately want to achieve this, try searching for a library to achieve such a task, maybe look at the Firefox source.
If you want to do it completely from scratch you would need to add C function bindings (Example at duktape.org/) for every draw method you want. An example would be like this:
// C/C++ code:
// C function to be used in the Javascript engine
int js_draw_rect(duk_context *ctx) {
// get parameters from javascript function call
int pos_x = duk_get_number(ctx, -4);
int pos_y = duk_get_number(ctx, -3);
...
// C/C++ code to draw the rectangle (in your case probably GLUT)
draw_rectangle(pos_x, pos_y, ...);
return 0;
}
int main(void) {
duk_context *ctx;
...
// this snippet adds a binding for the function 'js_draw_rect' so it can be called from Javascript code
duk_push_global_object(ctx);
duk_push_c_function(ctx, js_draw_rect, 4/*number of args the JS function has*/);
duk_put_prop_string(ctx, -2 /*idx:global*/, "drawRect"/*name of function in JS environment*/);
duk_pop(ctx);
}
// Javascript code:
drawRect(50, 50, 100, 200);
...
This method allows you to create C/C++ functions which handle all drawing and later bind them all to the Javascript engine so they can be called in JS.

pass string from C# to Javascript with Phonegap and Windows Phone 8

When developing a plugin, how is possible to get the result of my C# function to my javascript.
For instance having the echo plugin as in the official cordova doc
When I pass a result from C# to Javascript calling
DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "{result:\"super awesome!\"}"));
Please How can I get the result inside my javascript code (how can I get: "super awesome")?
When you dispacth the plugin result with status OK from C#, the win callback is called, and it brigns the result with this.
Example, your javascript plugin calls this from javascript:
cordova.exec(win, fail, "Echo", "echo", ["input string"]);
So you have to create a win function that will get the result:
function win(result) {
alert(result);
}
You could just write the string directly :
<script> var JavascriptBlah = '<%=yourString%>'</script>
or use the method InvokeScript to call a function to set the string :
webBrowser.InvokeScript("yourStringSetter", "yourString");
demo of a simple setter in js
source for the first solution

JS Function Invocation from AS3 with Complex Object in Parameter

I'm building an AIR desktop application. At one point the application loads a popup window (an MXML component based on s:Window), which contains an mx:HTML component which loads a local (in the application directory) html file, blank.html. The relevant elements in blank.html are:
<script src="jw/jwplayer.js"/> <!--JW Player's JS-based Embedder-->
...
<div id="jwtarget" /> <!-- the target that the embedder will use -->
Since the parameters I want to use are determined at runtime, I use the domWindow property to invoke the method which loads the player. Here's an example that works:
private function injectPlayer():void {
var playerVars:Object = {};
playerVars.flashplayer = "jw/player.swf";
playerVars.file = "http://www.archive.org/download/meet_john_doe_ipod/meet_john_doe_512kb.mp4";
playerVars.height = 360;
playerVars.width = 640;
try { // attempt to invoke the js function
htmlComponent.domWindow.jwplayer("jwtarget").setup(playerVars);
} catch(e:Error) {}
}
which is called when the page finishes loading by:
<mx:HTML id="htmlComponent" location="assets/blank.html" complete="injectPlayer()" />
That all works fine.
Now to the question. I need to be able to pass a more complex playerVars Object to the function, but I don't seem to be getting the syntax correct. Here's the simplest example I've been attempting:
private function injectPlayer():void {
var playerVars:Object = {};
//playerVars.flashplayer = "jw/player.swf";
playerVars.file = "http://www.archive.org/download/meet_john_doe_ipod/meet_john_doe_512kb.mp4";
playerVars.height = 360;
playerVars.width = 640;
playerVars.modes = [{"type":"flash","src":"jw/player.swf"}];
try { // attempt to invoke the js function
htmlComponent.domWindow.jwplayer("jwtarget").setup(playerVars);
} catch(e:Error) {}
}
This code should create the exact same thing as the above code, but it fails to execute. I assume I need to change the syntax in some way to allow the array of Objects (modes) to be passed properly as a parameter to the js function.
I've tried various things, like passing the modes as a String, or putting the whole thing through JSON.stringify() first, but to no avail. Anyone know the correct way for constructing a complex object for a parameter?
Other details, if you haven't inferred them by now: Flex 4.5.1 is the SDK I'm building with, including the AIR 3.0 extensions (which means targeting FP11).
Update:
Another configuration I tried, which does work:
playerVars.modes = {"type":"flash", "src":"jw/player.swf"};
However, this still doesn't solve the problem that I should be able to pass an Array of Objects in the modes property. But at least this way loads the video player.
More Update:
So, I found this little section of code from jwplayer.js where I suspected the player loading was failing:
if (typeof parsedConfig.modes == "string") {
_modes = _playerDefaults();
_modes[0].src = parsedConfig.modes;
} else if (parsedConfig.modes instanceof Array) { // I suspect this was eval'd as false
_modes = parsedConfig.modes;
} else if (typeof parsedConfig.modes == "object" && parsedConfig.modes.type) {
_modes = [parsedConfig.modes];
}
And to test my suspicion I added the following function to my blank.html:
<script type="text/javascript">
var instanceOfArrayTest = function(arr) {
return arr instanceof Array;
}
</script>
And in my ActionScript code tried the following:
trace([1,2,3] is Array); // true
trace(htmlComponent.domWindow.instanceOfArrayTest([1,2,3])); // false!!!!
So, it seems that the problem is that ActionScript is not passing AS3 Array objects as JS Array objects!
Try doing this instead:
playerVars.modes = [{type:"flash",src:"jw/player.swf"}];
Unlike the call() method of the ExternalInterface class, the mx:HTML does not automatically convert AS3 classes to corresponding JS classes when they are passed as parameters to a JS function. Instead, the HTML Control maintains an environment where methods and properties native to the AS3 classes are preserved and made accessible to JS directly.
If a JS function requires a JS Array object, one must create the JS Array explicitly using the JavaScript Window object to access the JS Array constructor. The HTML Control provides access to this with it's domWindow property. Otherwise, there is no way to "cast" an AS3 Array to a JS Array.
Here's a basic example:
var JSArray:Function = htmlComponent.domWindow.Array;
htmlComponent.domWindow.instanceOfArrayTest( JSArray(1,2,3) ); // true
And for the more complex example using the config parameter for JW Player:
playerVars.modes = JSArray({"type":"flash","src":"jw/player.swf"},{"type":"html5"});
which creates a JS Array of two Objects.
For more info on the JavaScript environment in the HTML Control, check out the JavaScript in AIR section of Adobe's Developing AIR Applications with Flex.

Categories