Ariya Hidayat
WebKit
Graphics Dojo
Posted by Ariya Hidayat
 in WebKit, Graphics Dojo
 on Friday, April 17, 2009 @ 10:56

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') } )";
    view->page()->mainFrame()->evaluateJavaScript(code);
}

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.

fancybrowser.png

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!

17 Responses to “jQuery and QWebElement”

» Posted by Tim
 on Friday, April 17, 2009 @ 11:43

“because WebKit supports CSS 3 Selector since some time already”

No. Bad. Repeat after me:

“because WebKit has supported CSS 3 Selectors for some time already”

The thing after ’since’ has to be an actual time. E.g. “since last Friday” or “since the dawn of time”. When exactly was “some time”?

» Posted by ariya
 on Friday, April 17, 2009 @ 12:05
Ariya Hidayat

@Tim: thanks for the correction!

» Posted by Anon
 on Friday, April 17, 2009 @ 13:03

Could you quickly answer my question on Tor’s blog ( http://labs.trolltech.com/blogs/2009/04/07/qwebelement-sees-the-light-do-i-hear-a-booyakasha/ - Anon
on Sunday, April 12, 2009) - I fear it has fallen through the cracks :)

» Posted by dao
 on Friday, April 17, 2009 @ 14:08

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

https://developer.mozilla.org/En/DOM/Document.querySelectorAll

» Posted by Qtuser
 on Friday, April 17, 2009 @ 15:20

So long story short. Much of what we wanted to do, but had to wait for QWebElement in Qt 4.6 can be recreated in 4.5 using Jquery.

Of course I am over simplifying it a bit but still, I was not expecting this ease in Qt WebKit Dom Manipulation till 4.6.

Kudos and thank you!

» Posted by Piotr Gabryjeluk
 on Friday, April 17, 2009 @ 15:39

You can do highlightAllLinks even shorter with jQuery:

void highlightAllLinks() {
QString code = “$(’a').css(’background-color’, ‘yellow’)”;
view->page()->mainFrame()->evaluateJavaScript(code);
}

» Posted by ariya
 on Friday, April 17, 2009 @ 16:36
Ariya Hidayat

@dao: That is CSS 3 Selector, exactly the back-end for QWebElement. What I meant by DOM API in that context is http://www.w3.org/DOM/

» Posted by ariya
 on Friday, April 17, 2009 @ 16:40
Ariya Hidayat

@Piotr: I had chosen the “each” variant intentionally so that the readers can draw the similarity with the QWebElement + foreach version thereof. But yeah, I should have mentioned that one, too. Thanks!

» Posted by Paul Tomkins
 on Friday, April 17, 2009 @ 20:15

I like the direction WebKit is moving. Keep up the great work :-)

» Posted by TJ
 on Monday, April 20, 2009 @ 01:04

Your jQuery-foo is weak :p

$(’a').each( function () { $(this).css(’background-color’, ‘yellow’) } )

should be

$(’a').css(’background-color’, ‘yellow’)

» Posted by ariya
 on Monday, April 20, 2009 @ 06:30
Ariya Hidayat

@TJ: See my reply to Piotr above.

» Posted by harpic
 on Monday, April 20, 2009 @ 20:22

Hi ariya. This is a little off topic. I’ve been developing an app with Qt and QWebKit and for the life of me I can’t figure out how to prevent mouse text selection without compromising functionality.

I checked the docs over and over and over. yeah I can write my own mousePress and mouseMove event but then sites like Google Maps will stop working because they rely on those events to work in the normal fashion. I tried to set the text hilight color to transparent but it doesn’t seem to take effect, it’s always dark blue-ish.

Is there no way to set text interaction flags on a QWebPage or something? I’m pulling my hair out on this. I was going to post this in the flickcharm blog entry but I wasn’t sure if you noticed or were notified of new comments in old posts…

Thanks in advance!

» Posted by ariya
 on Tuesday, April 21, 2009 @ 08:06
Ariya Hidayat

@harpic: There is no support for disabling text selection. And next time, use our support channel for that kind of question.

» Posted by lolik
 on Tuesday, April 21, 2009 @ 09:56

That’s great!! Nice! Short in understand!
I like your post! Keep Working!!!

» Posted by projetmbc
 on Friday, April 24, 2009 @ 09:32

Thanks for the example but what about the communication from a JavaScript program to a PyQt application. This could be very usefull.
For example with the following HTML page opened in QWebView, how can a PyQt application knows the javascript variable nom, and how can we define a slot wich will tell to the PyQt application that the function affiche() has been called ?
With this kind of feature it would be possible to use HTLM pages to show pictures and then to know on wich picture the user has clicked.

(Sorry for my english…)

CODE
==============================

nom = ”;
function show(){
for(var i=0; i

» Posted by projetmbc
 on Friday, April 24, 2009 @ 09:42

Oups, the code is missing. I put it here the HTML page here : http://christophe_bal.club.fr/TestJavaScriptToPyQt.html .

» Posted by projetmbc
 on Friday, April 24, 2009 @ 09:42

Oups, the code is missing. I put the HTML page here : http://christophe_bal.club.fr/TestJavaScriptToPyQt.html .



© 2008 Nokia Corporation and/or its subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation in Finland and/or other countries worldwide.
All other trademarks are property of their respective owners.