QWebKit - adding custom script objects to JavaScriptCore engine
-
Hi Ricardo,
of course it's possible but not using addToJavaScriptWindowObject but evaluateJavascript instead.
You can load a javascript file storing it into a QString a later on evaluate the javascript making all the contained javascript in the file accesible in the QWebPage or write the javascript directly to a QString.
If you load a page after doing this all the loaded javascript will be cleared as the context has changed. To make this javascript available throught loaded pages just listen to the javaScriptWindowObjectCleared
signal to reload them again.A good resource with examples to this is the "fancybrowser example":http://doc.qt.nokia.com/4.5/webkit-fancybrowser.html which uses jQuery to modify the DOM while displaying a page.
-
bq. also the possibility to add a new JavaScript class to WebKit’s engine
I understood that you wanted to include a JAVASCRIPT class inside the Webkit. If you want to expose a QObject have a look to this code:
@class FileSystem : public QObject
{
Q_OBJECTpublic:
FileSystem(QObject *parent = 0);
~FileSystem();void setBasedir(QString basedir); QString getBasedir();
private:
QString _basedir;public slots:
QString read(QString fileName);
void write(QString fileName, QString data, QString mode = "+w");
void copy(QString source, QString target);
void rename(QString fileName, QString newName);
void remove(QString fileName);
};
@Basicly this is the header definition of a filesystem class that I have builded for Kas an HTTP Restful server intented for data minning, including webkit, tokio cabinet, databases, xapian and files.
All the slots are accesible to the engine as methods of the objects if you want to expose members you have to declare them using the meta:Q_PROPERTY(QVariant SERVER READ SERVER);
Here a header definition of a worker:
@class KasEngine : public QThread
{
Q_OBJECT
Q_PROPERTY(QVariant SERVER READ SERVER);
Q_PROPERTY(QVariant GET READ GET);
Q_PROPERTY(QVariant POST READ POST);public:
KasEngine(int socketDescriptor, QObject *parent = 0);
~KasEngine();void run();
QString serve();private:
int _socketDescriptor;
HttpRequestHeader _requestHeader;
HttpResponseHeader _responseHeader;
QString _output;
QWebPage* _webView;public slots:
void echo(QString message);
void require(QString fileName);
void log(QString message, QString type = LogType::info);
QVariant SERVER();
QVariant GET();
QVariant POST();
}@;As you see POST, GET and SERVER variables are exposed to the javascript engine.
My work is pretty similar to Node.js or narwhaljs but using Qt...
-
That is a very common use case of QtWebKit actually.
Here is the documentation describing which kind of objects can be passed to QtWebKit's Javascript runtime: "http://doc.qt.nokia.com/4.7-snapshot/qtwebkit-bridge.html":http://doc.qt.nokia.com/4.7-snapshot/qtwebkit-bridge.html
-
@DavidGOrtega: And what methods do you use to expose KasEngine class into WebKit JavaScript engine so you could issue this call in html's javascript section
...
var ke = new KasEngine(12312);
ke.log("message");
... -
@this->_webView->mainFrame()->addToJavaScriptWindowObject("core", this);
this->_webView->mainFrame()->addToJavaScriptWindowObject("fs", _fileSystem);
this->_webView->mainFrame()->addToJavaScriptWindowObject("browser", _browser);
this->_webView->mainFrame()->addToJavaScriptWindowObject("reader", _reader);@in javascript file that is requested like:
http://localhost:8080/test.js?name=rikardo@core.echo('Hello' + core.GET['name']);@
-
DavidGOrtega: all that I understand, but this is not completely what I want. With this functionality one can expose QObject as javascript object. That means this object is already instantiated in javascript environment (engine). What I would like is to expose C++ class to JS engine in a way I can access it's constructor from JS environment. I would like to be able to execute the following script in webkit
@
var ocr = new OCR(OCR.AllMatrixes); // calling my C++ class's constructor
ocr.begin();
...
@ -
You cannot directly.
What you could do is expose a factory, add it to the runtime and creates your objects from it.
In javascript, you would have:
@var ocr = factory.createOCRInstance(arg);
ocr.begin();@ -
As Benjamin stated the only way to do this is using a factory pattern the trick here is returning the object created...
@QVariant factory::createFSInstance() //this is a slot
{
FileSystem* fs = new FileSystem();
this->_webView->mainFrame()->addToJavaScriptWindowObject("fsInstance", fs);return this->_webView->mainFrame()->evaluateJavascript("fsInstance;");
}@in javascript looks:
@var fs = factory.createFSInstance();
fs.read(filename);@If you have a look to any CommonJS implementation like node.js they use require as a reserved method and of course the new desired impementation exists thought javascript objects that do what I have exposed loaded in a bootstrap.js. As I have said have a look to node.js to have an idea of what is happening behind