14. Juni 2011

An HTML based Chat Window with WebKit, jQuery, and tricks

Over the weekend I was working on the OVW chat window. The chat window is very similar to the avatar display and also very different. The similarities are:

  • both are display modules
  • both use WebKit
Because they are both display modules, I could take the avatar display module code and strip away the avatar part to keep only nicknames. The chat window needs only nicknames. Later there will be images and more features. But for the start we need only text. The chat module has the same structure as the avatar module. It subscribes to a small number of virtual presence model events and then turns around and paints the display in HTML.

See the ui-layout-* CSS-classes? They are used by jQuery UI Layout. There is a bit of configuration necessary, but only a bit: http://code.google.com/p/ovw/source/browse/trunk/Apollo/bin/Win32/Debug/modules/Chat/Chat.html?r=255#153

As always, styling is very simple. Need bold nicknames? Here they are:
#ChatOut .cNickname { font-weight:bold; }
On the other hand, chat window and avatar display are very different:
  • chat is a dialog where the Chat.html code is in an IFRAME
  • avatar display paints directly, has no dialog frame
Calling the avatar display I can simply call a JavaScript function in WebKit. But in case of a Dialog with IFRAME, things are a bit more complicated. The IFRAME is a HTML window inside the HTML window. The WebView module has only a handle to the outer HTML/JavaScript. There is no direct access to the JavaScript of the inner HTML. I can call a JavaScript function in WebKit, but the function is executed in the context of the dialog wrapper. This is OK, if I want to control the dialog functions. But talking to the inner HTML is more difficult.

I am sure there are way to get to an embedded IFRAME from C++. But I did not want to get too deep into enumerating WebKit objects from C++. I needed a way to call JavaScript in the embedded IFRAME from the parent frame. Luckily we are in the same security domain, so calling JavaScript across frames is no problem. My solution is to call a function in the Dialog, which calls a function in the IFRAME, which evals the code I want to execute in the IFRAME.
function ContentEval(sCode)

return document.getElementById('Content').contentWindow.EvalJS(sCode);
Not very nice. A bit dirty, but it works. Also not very fast. Anyway, there are not many messages which take this route. Just adding participants and chat lines. I am confident, that we find a better way to do this later.


UPDATE: a week later, I have direct access to embedded frames. I am searching the frame by it's DOM-ID, then call the function inside the frame. I do GetFrameByPath to find the frame, because the frame may be inside another frame. Frames inside frames will be identified by a "/" separated list of DOM-IDs. That's my so called frame-path: http://code.google.com/p/ovw/source/browse/trunk/Apollo/bin/Win32/Debug/modules/Chat/Chat.html?r=414#200

The GetFrameByPath function is a mess of COM auto-pointers and QueryInterface. The ugly face of C++. Thank FSM someone invented better ways.

3 Kommentare:

Sven hat gesagt…

Why do you need an IFrame in the first place?

Heiner hat gesagt…

I want to separate window frame from window content. The Dialog-module makes the frame. Another module makes the content.

It is good to have the window content as a self contained HTML document. It can be opened in a browser for development. The dialog could even embed a remote web page

I could load the content into the same document, but then the window content gets the same URL base folder as the dialog frame. Dialog frame and window content should be independent. They are from different modules. They should have their own independent base folders. The dialog gets HTML and icons from the Dialog-module folder. The chat window content gets HTML and images from the Chat-module folder.

Sven hat gesagt…


just call $('#chatBox').load("mypage.html");

or similar calls in other frameworks.