[Qt-interest] QWebView for document editing

Nathan Carter nathancarter5 at gmail.com
Mon Jul 13 03:39:24 CEST 2009


On Jul 12, 2009, at 12:47 AM, Tony Rietwyk wrote:

> Nathan wrote:
>
>> What we do is as we generate the HTML from our model, we wrap those
>> blocks that we want to label in things of this form:
>>
>> 	<span id="our special id here"> ...actual content... </span>
>>
>> (or you could use div or whatever's appropriate).  This flags your
>> document with the points in your model that it represents.  So when
>> you get a hit in the web view, you can walk up the DOM tree to find
>> the first relevant span, get its id, and use it.  I won't describe
>> that Javascript here, since I'm assuming you could build it, but if
>> you want to see it, lemme know and I'll paste our code in.  It's not
>> long.
>
> Hi Nathan,
>
> Could you please send me that code snippet. Thanks!

Well the snippet that generates the HTML is highly specific to my  
application.  Here's the general idea.  My internal data is an  
OpenMath document, and I do a tree traversal on it, and after visiting  
each node and recursively computing the HTML representation of the  
subtree rooted at that node, I take that value (call it HTML) and do  
something like this:

	int n = indexOfCurrentNodeInItsParent();
	HTML = QString( "<span id='OpenMath_Child_Index_%1'>%2</span>" )
		.arg( n ).arg( HTML );

Then when you want to know where in the original OpenMath document the  
webview cursor sits, you use

	QString address = webview->page()->mainFrame()->evaluateJavaScript(
		"nodeAddress( window.getSelection().focusNode )" ).toString();

assuming that all the following Javascript has already been run in  
that same webview's JS engine.

	function childIndexOfNode ( node )
	{
	    if ( !( 'tagName' in node ) )
	        return '';
	    var tn = node.tagName.toLowerCase();
	    if ( ( tn == 'span' ) || ( tn == 'div' ) ) {
	        var match = /OpenMath_Child_Index_(\d+)/.exec( node.id );
	        if ( match && ( match.length > 0 ) )
	            return match[1];
	    }
	    return '';
	}

	function nextAncestorWithIndex ( node )
	{
	    while ( ( typeof( node ) != 'undefined' ) && ( node != null ) ) {
	        if ( childIndexOfNode( node ) != '' )
	            return node;
	        node = ( 'parentNode' in node ) ? node.parentNode : null;
	    }
	    return null;
	}

	function nodeAddress ( node )
	{
	    var result = '';
	    while ( ( typeof( node ) != 'undefined' ) && ( node != null ) ) {
	        var index = childIndexOfNode( node );
	        if ( index != '' )
	            result = index + ' ' + result;
	        node = nextAncestorWithIndex( node.parentNode );
	    }
	    return result;
	}

Then I use the address, a string like '6 2 0 5 19 2 3' to walk from  
the root through my original OpenMath document tree to get to the node  
in question.

This is not EXACTLY what I do, but it's pretty close.  It's a little  
messier than this because OpenMath has attributes, too, so I have  
different types of steps, not just into "child" nodes, and if you're  
truly interested in the grueling details, check out these pieces of  
source code.

http://sourceforge.net/apps/trac/lurch/browser/Lurch/trunk/utils/LurchLite/webviewutilities.js#L90
http://sourceforge.net/apps/trac/lurch/browser/Lurch/trunk/utils/LurchLite/alphawindow.cpp
(The latter is a mess; it's a work in progress that needs a lot of  
code cleaning up!  Sorry!)

> I have a similar requirement but I had problems when editing the  
> nodes in
> javascript. In particular, I dod NOT want to just replace nodes with  
> text
> HTML.  I need to replace some of the nodes, and copy other existing  
> ones (by
> ID) - which may be whole trees of nodes.  But I couldn't see how to  
> do this
> in a nice generic way through signals to the javascript.

I'm not sure exactly what you're saying here.  But note that in  
Javascript you can overwrite an entire node's content (though it be a  
whole tree) with another one very easily, by calling

	node.innerHTML = 'new html code here';

Then if node was a <p>, let's say, it will still be a <p>, but with  
all new content (however complex) that you specified inside the string  
that you assigned to innerHTML.

Is that what you meant?

Nathan



More information about the Qt-interest-old mailing list