With Qt 5.5, using the Minibrowser example they provide, it uses something different than QWebView widget. Instead, it uses QML and a QtWebView module. When you look in Javascript's navigator.appVersion, it lets you know that QWebView loads a custom AppleWebKit/538.1 (a thing shipped with Qt5.5), while QtWebView (note the difference) loads the native core OS AppleWebKit/601.1.56. This is confirmed because when I load Safari on my OSX (El Capitan version), it says 601.1.56.
The problem, however, is how can my Javascript functions in Minibrowser call C++ functions on the backend to do more powerful stuff? When I was using the QWebView widget, I was able to use the C++ webkit bridge that let me inject into the DOM my C++ object and therefore could call my C++ code. I'm not seeing any technique documented for how to do this with the QML-based Minibrowser example that uses QtWebView. What's the technique?
EDIT: Oh, and to clarify, I'm not calling remote web pages with this, via a web server. I'm just calling stuff through file://. In other words, I'm using the rich webkit interface to give me a super powerful GUI that goes way beyond what the Qt widgets and QML can provide for me.
I found the answer. Basically, in Qt5.5, I'm diving into experimental land with QtWebView. The class methods are largely undocumented and may change in the future.
For now, the only technique is message passing, not native C++ class method invocation like you could use in the QWebView C++ Bridge. The QWebView C++ Bridge only works with QWebView widgets, not the QtWebView QML. So, you do this message passing with navigator.qt.postMessage() API from your Javascript to your QML, and then QML can call C++. In order to get that extra functionality, you'll need to do a few steps. Here's an example:
Invoke C++ method from webviews Javascript
This is blogged a little here:
http://rschroll.github.io/beru/2013/08/21/qtwebview.experimental.html
As you can see from the example, you have to add these imports to your main.qml:
import QtWebKit 3.0
import QtWebKit.experimental 1.0
Then, in your WebView{} section, you have to add this line:
experimental.preferences.navigatorQtObjectEnabled: true
At that point, you can call navigator.qt.postMessage("call foo in C++"); to send a message to the QML, which you can then pick up inside your WebView{} section with:
experimental.onMessageReceived: { ...do something here in the QML... }
Your QML can then pass a message right back to the Javascript with:
experimental.postMessage("okay, I called foo in C++")
And then in your Javascript you can add an event listener like so:
navigator.qt.onmessage = function(ev) {
$('BODY').prepend(ev.data); // since console.log() is not possible
}
As for how to get your QML to call C++, here's an example:
https://stackoverflow.com/a/17881019/105539
EDIT: After more experimentation in Qt 5.5 with QtWebView, it appears fairly flaky in the following respects. I don't recommend it in 5.5 -- it's not ready for primetime. In Qt 5.5, you're better off using the QWebView widget for now and then migrate to QtWebEngine when the next version of Qt comes out (Qt 5.6, 5.7?).
By default, it gives you a rightclick context menu you may not want. Interestingly, you can turn it off if you import the experimental library and then set this property in your QML: experimental.preferences.navigatorQtObjectEnabled: true.
By default, HTML5 postMessage() API (the one native with HTML5) doesn't appear to work unless you enable experimental.preferences.navigatorQtObjectEnabled: true.
When you enable experimental.preferences.navigatorQtObjectEnabled: true, the scrollbars disappear if you enabled them on some HTML page elements, the checkboxes and radio buttons look extremely funky, and popdown select listboxes stopped working.
When you doubleclick a page, it zooms it.
Related
I am implementing the autosuggestions feature for a web-based JS editor. While the user is typing, I want to show him suggestions of all the variables, functions, and classes already declared or used by himself only. I can get variables and functions from window, but I am not able to get the list of classes declared. Let say following is the code entered till now:
class FooClass {
constructor() {
console.log("I am the constructor of ECMA6 class");
}
};
After declaring the class, if the user enters Foo, I want to show him suggestions as FooClass.
Most IDEs perform autocomplete and other intelligent refactors and defect detection using AST.
One of the most well-known Javascript AST tools is Esprima, which along with parsing Javascript, it also runs in JS (both browser and node).
Here's a demo it provides of how it can be used for autocomplete:
http://esprima.org/demo/autocomplete.html
If you are creating a web-based JS editor, this tool will likely save you a lot of time, don't re-invent the wheel.
In the context of CodeMirror, you might find this helpful:
https://github.com/maxogden/javascript-editor
codemirror + esprima powered html5 javascript editor component
Both firebug and the built in console in webkit browsers make it possible to set breakpoints in running Javascript code, so you can debug it as you would with any other language.
What I'm wondering is if there is any way that I can instruct firebug or webkit that I'd like to set a breakpoint on line X in file Y at runtime, and to be able to examine variables in the specific scope that I have paused in.
I need something that can work in both Chrome (or any other webkit browser) and Firefox. For the latter Firebug is an acceptable dependency. Supporting IE is not a requirement.
I've been building an in-browser IDE ( quick video for the interested: http://www.youtube.com/watch?v=c5lGwqi8L_g ) and want to give it a bit more meat.
One thing I did try was just adding debugger; as an extra line where users set them, but this isn't really an ideal solution.
I'd say you can definitely do this for webkit browsers using the remote debugging protocol. This is based on a websocket connection and a json message protocol that goes back and forth.
You can read the announcement and the whole protocol schema.
Chrome also offers more information about this inside its remote developer-tools docs.
For the debugger domain, for instance, you can see how you can use Debugger.setBreakpoint, Debugger.setBreakpointByUrl and Debugger.setBreakpointsActive to work with breakpoints.
On the other hand, Mozilla also seems to be working on this as you can see in https://developer.mozilla.org/en-US/docs/Tools/Debugger-API and https://wiki.mozilla.org/Remote_Debugging_Protocol though I don't know the completion status of it.
In this case, you can work with breakpoints using the Debugger.Script APIs setBreakPoint, getBreakPoint, getBreakpoints, clearBreakpoints and clearAllBreakpoints
I hope this helps you move forward.
There isn't such a thing, at least not using the public, scriptable side of JavaScript. It would be possible if you have a privileged browser extension that could do that for you. For example, Firebug has a debug method which you can call from its command line, but not from scripts inside a page.
So, you have two solutions:
Implement your own JavaScript interpreter, which you can control as you wish. Might be a bit too ambitious, though...
Rely on a browser extension that can set breakpoints anywhere in the code, expose some API to public code, and interact with it from your JavaScript. But that means that users will have to install some extra piece of software before they can use your "Web IDE".
Use _defineSetter__ to watch variables, and combine it with a call to debugger when an assignment happens.
__defineSetter__("name", function() { debugger; });
or defineProperty:
function setter () { debugger; }
Object.defineProperty(Math, 'name', { set: setter });
References
MDN: Object.defineProperty
A List Apart: Advanced Debugging With JavaScript
JavaScript Getters and Setters
I have implemented an MSR OPOS ActiveX control for use in an IE-based web application. I have tested the device and it works; however, I'm trying to port the VBScript code found here to JavaScript for easier maintainability.
I'm having trouble binding to the DataEvent with JavaScript though -- when I put the card to the reader, the data definitely appears to take, as I can query the object directly through the console with ReaderControl.Track1Data and see that there is in fact data there.
In the VBScript version, there seems to be a method called [control]_DataEvent that you can simply override in order to bind to the event. I have tried ReaderControl.attachEvent("DataEvent", function() { alert(ReaderControl.Track1Data); }), which does seem to work, for some reason, only when subsequently set ReaderControl.DataEventEnabled = true;.
Any ideas?
Android lets you add a Javascript Interface, that will let you use "window.interfacename.myfunction()" to call a function in the Java program.
Is there any similar feature that allows a PyGTK with embedded webkit browser to have similar functionality, to call a specific Python function from Javascript?
You can do it in C using the JavaScriptCore library that comes with WebKit. I don't know any examples in PyGTK, but I assume that JavaScriptCore is available through GObject Introspection.
I ended up adding a handler for special urls. I overrode the webkit with:
webview.connect("navigation-policy-decision-requested", self.webkitGo)
where self.webkitGo is the name of the function: def webkitGo(self, view, frame, net_req, nav_act, pol_dec):
In this function, you can receive the url data from net_req.get_uri() and decide what to do with it, and return true to not do the default behavior.
we have developed an Intranet Management Application with Silverlight 4. We have been asked to add the functionality to call a remote desktop tool which is installed on clients using the Intranet SL App. In an earlier version of the tool written in ASP.NET we just added a Javascript function to the aspx page like this:
function RunShellCommand()
{
var launcher = new ActiveXObject("WScript.Shell");
launcher.Run("mstsc.exe");
}
and called it from ASP.NET.
Now it's clear that SL4 is running in a sandbox and that I cant use the AutomationFactory to create a WScript.Shell object (out of browser mode is not an option).
I thought I could circle around the problem by, again, adding the RunShellCommand javascript method in the aspx page where the SL4 control is hosted and call it via
HtmlPage.RegisterScriptableObject("Page", this);
HtmlPage.Window.Invoke("RunShellCommand", "dummydata");
from my ViewModel. When I run the Application the debugger just skips the RegisterScriptableObject method and quits. Nothing happens.
My question is if am doing something wrong or if this just wont work this way.
Is it possible that I cant do a RegisterScriptableObject from a viewmodel?
EDIT: When I explicitly put a try, catch block around the two methods I get an ArgumentException from the first method stating that the current instance has no scriptable members. When I delete the first method and only run the Invoke, I get a browser error stating that the automation server cant create the object. So is there really no way (except OOB mode) to do this?
Yes, the explanation is correct: you should add at least one method with the ScriptableMember attribute in order that you can use the RegisterScriptableObjectmethod. But it is used only for calling C#-methods from JavaScript.
As far as I see, you want to do the opposite: to call JavaScript code from the Silverlight application. Then you need only one line:
HtmlPage.Window.Invoke("RunShellCommand");
The error automation server cant create the object has nothing to do with Silverlight. I'm sure that if you call the JS function directly - the error will remain.
According to the internet, the reason might be not installed Microsoft Windows Script. Or it is because of security restrictions of the browser.