Custom Elements on WebKit Pages

By uliwitness

Recently, I wanted to create a simple HTML editor. basically, I just wanted to WYSIWYG-edit styled text, and maybe insert a few images. But, of course there was one reason I could not use one of the existing HTML editors:

I needed to be able to insert special placeholder items. Little boxes, that could be double clicked for editing, and would otherwise just be part of the text like a regular character. In the final output, these would expand to special commands in a server-side scripting language, but I didn’t want to see them in the editor of course.

Luckily, after a bunch of code contributions and bug reports by Karelia, makers of SandVox, and then Mail.app using WebKit for editing styled e-mails, WebKit supports in-line editing. It is quite easy, actually: You just call [myWebView setEditable: YES] and give the WebView an empty HTML document. That is all you need to have a styled edit field from which you can get HTML and to which you can assign HTML.

Apple’s website also documents how to load HTML into the WebView, and how to get it back out. Loading is trivial using [[myWebView mainFrame] loadHTMLString: @"<html><body></body></html>"], and of course you can insert your HTML text in between these two tags. Writing them back out is slightly more complicated: What you do is get to the DOMDocument and then the documentElement from the mainFrame, then grab the element named @"body" out of that, and then you can typecast that to a DOMHTMLElement to obtain its innerHTML, which is a string containing the HTML for your styled text. If you want the full document and not just edit HTML fragments, you can simply take the document element’s outerHTML.

That was all straightforward so far, once I’d grown used to WebKit’s terminology. Now, how to manage the placeholders? Well, first, you will have to create a new WebKit plug-in project from the Standard Apple plug-ins category. This gives you a simple NSView, which you can associate with a MIME type by editing its Info.plist. Set up this project, so that it is built with your application project, and make sure you have a Copy Files build phase that copies it into a PlugIns folder in your application’s bundle.

You should now be able to specify an embed tag in your HTML source code with the type attribute set to your plugin’s MIME type, and WebKit will automatically load your plug-in and place it in this spot. However, you will either have to manually specify width and height attributes on the embed tag, or your plug-in will have to calculate the sizes, and use the arguments dictionary it gets passed on creation to add to them to the embed tag in code by manipulating the DOM tree through the DOMElement in WebPlugInContainingElementKey in the arguments dictionary. Since this key already refers to our embed tag, this is as simple as using the -setAttribute:value: call on this object, and using +stringWithFormat: to convert our sizes into strings.

What I learned from this? Once you know that there is no way to load a plug-in directly from inside your application, it is fairly straightforward to add your own objects to a WebView. Sadly, you always only know that after…

Share your thoughts