jQuery and QWebElement

Any tools which can save the developers the cost of headache pills are always valuable. For web development, JavaScript frameworks such as Prototype and jQuery (and many other similar ones) are these valuable tools. Just for doing content manipulation via JavaScript, using jQuery instead of the standard DOM API would save many precious working hours. No wonder they become so popular these days. Nokia packs jQuery for its Web Run Time, Microsoft bundles it with ASP.NET AJAX.

The QtWebKit team at Qt Software often gets the question like "Can I use jQuery in QtWebKit?". Since QtWebKit is just a normal web-rendering engine, of course the answer is "Yes". To get your feet wet quickly for using the deadly combination of QtWebKit and jQuery, continue reading and examine the demo presented in the following explanation.

There are two ways you can jQuerify your HTML content. If you have total control over the content that you want to display (e.g. using QWebView to display help or other rich-text), then you can refer jQuery directly in the HTML, i.e. inserting the proper <script> referring to the jQuery JavaScript code. If you don't have a control over the content that you want to display (e.g. using QWebView for a web browser), then the best bet is to inject the jQuery JavaScript code. This can be carried out using QWebFrame::evaluateJavaScript. A nice place to do is after the document is fully loaded. The drawback is that you can't do any manipulation while loading is in progress, but hey, you don't have a control over the content anyway.

There are also two methods to pass the jQuery JavaScript code. For convenient access, you may want to store it as a file in the resource, thus it will be shipped along with your application. After that, the code can be referred from within QtWebKit using the qrc:/ URL, i.e. <script src="qrc:/jQuery.js">. If your application is pure web-based or an online hybrid C++/web, you can also source the script from e.g. Google AJAX libraries or using the network access manager to retrieve it (see the previous Monster example for similar trick). This means downloading the script at run-time (eating the bandwidth), but then you get the benefit of automatically update (zero-cost deployment). Judge it based on your needs, which trade-off suits you better.

Without further ado, the code is available in Graphics Dojo repository (no time to git-pull? download the gzipped archive), under the directory fancybrowser. You need Qt 4.5 to build the example. It is basically a normal minimalistic web browser with two extra buttons: to toggle the images upside down and to perform several actions, notably to highlight all links and removing certain types of elements.

For a quick glance of what the demo can do, enjoy the following screencast (watch on YouTube or download/view 18 MB Ogg Theora video).

As an example, here is the function to highlight all the links (yes, it is extremely short!):

void highlightAllLinks() {
QString code = "$('a').each( function () { $(this).css('background-color', 'yellow') } )";

Imagine if we would have to implement the same function using DOM API.

Careful readers might notice that the rotation is effect is achieved through two cool features implemented in WebKit: CSS Animation and CSS Transform. If you check out the rotateImages() function, it is also as simple as 7 lines of code. Couldn't be simpler.


So far so good. But then, Qt 4.6 will sport QWebElement, as Tor Arne recently blogged about. Although it is not replacement for jQuery, for most cases this new element API allows a wide range of content manipulation. It is based on the concept of CSS 3 Selectors, whose query language is surprisingly very similar to jQuery. QWebElement was relatively easy to implement, in particular because WebKit supports CSS 3 Selector since some time already (thanks to David Smith for the implementation).

Although 4.6 is still not on the horizon yet, I modified the example demo to be able to use QWebElement when you build it with Qt > 4.5 (thus, after 4.6 will be released sometime in future, come back and recompile the demo). It is of course no magic that the code change is pretty minimal, in fact the implementation is very similar. For example, here is highlightAllLinks() function implemented using QWebElement (compare it to the previous jQuery flavor):

void highlightAllLinks() {
foreach (QWebElement element, view->page()->mainFrame()->findAllElements("a"))
element.setStyleProperty("background-color", "yellow");

(As you can witness above, we even went so far to implement the necessary iterator, then foreach works flawlessly!)

As an exercise for the reader, implement a new functionality to undo the highlighting of links. For this to work, you need to change the highlighting code to use a new class (in the context of CSS class, not C++ class), instead of just modifying the background color of the link elements. You need to inject the suitable class definition into the stylesheet as well. Removing the highlighting is then as easy as removing the class from each of the link elements.

Happy CSS-Selecting!

Blog Topics: