A Busy Writers Guide to Radio Renderers
By Mark Woods, March 6, 2002.
This document provides a quick introduction to writing stories using HTML renderers in Radio 8.0. Renderers provide a simple mechanism for formatting text within specific HTML constructs (e.g. a table) without specifying the actual HTML tags. The renderer infers the desired HTML construct based on 1) a directive to use a specific renderer and 2) the hierarchical structure of an outline. For more background on how and why renderers simplify an author's work, please read "The Case For Renderers" (forthcoming).
It is easier to explain renderers once you have seen one in action, so let's start with an example. Open Radio on your desktop (in Windows you right-click the Radio icon in the System Tray and select "Open Radio"). Create a new outline in Radio using the Ctrl-N keyboard shortcut. Enter the text from the screenshot to the right into the outline (the indentation levels are important, follow them exactly). If you are new to Radio's outliner, I recommend reading How to use the outliner?
Using Radio's File/Save As... menu save this outline into your stories folder as myFirstRenderedStory.opml. Be sure to save it in some subfolder of stories because files in the stories folder itself are not included in your index. You may want to create a subfolder named "misc" in your stories folder. Your story should be rendered within just a few seconds. Open the story in your browser from your website rather than through your Desktop Home Page's Story menu. It should look like myFirstRenderedStory. A quick glance verifies that this story is formatted a bit differently than stories normally are, but without your specifying any HTML. Now for the explanation.
A Quick Rundown
If you have written stories in Radio, you have seen the #title directive before. It tells Radio what title to use for your story. It is used for both the <title> of the page and as a headline for the story. The #renderOutlineWith directive specifies what outline renderer you want Radio to use. The twoLevelOutline renderer we used in this example will format summit nodes (non-indented outline elements) as level 4 headings. All child nodes are formatted as individual paragraphs.
Let's gussy up this example to show off some of the other fun things you can do with Radio. Create a new outline in Radio (Ctrl-N), enter the text from the example to the right, and save it in your stories folder as mySecondRenderedStory.opml. When you are done, it should look like mySecondRenderedStory.
Notice that we used Radio's built-in <%authorName%> macro in this example. You can include any valid macro reference in your outline. See Radio's Built-In Macros page for more available macros. Note also that we left the first summit node empty to avoid the first paragraph heading colliding with the story's headline as they did in the first example. Finally, we wrote some native HTML code to create an ordered list. The ordered list looks a little flaky. That is because each item is formatted as a separate paragraph using the twoLevelOutline renderer. We will address both the flakiness and a way to avoid writing this ordered list HTML in a moment. At this point you really have everything you need to know to write stories using the twoLevelOutline renderer. In fact, this whole story was created as a twoLevelOutline using only techniques we have discussed so far (except for the images). You are now free from bondage to stories written without a renderer. But you may want to continue digging deeper to learn how to format tables and lists. You may also be wondering how you can use two renderers for one document - to embed a table or a list within a twoLevelOutline, for example. We will cover all this and more in the remainder of this BWG!
Warning! We are venturing into territory where the rules changed a bit between Radio 7.x and Radio 8.0. I am going to show you how to render HTML tables from outlines using Radio's tableOutliner renderer. However, like all of the renderers, this one is a holdover from Radio 7.x and it employs an old technique that will not work when you want to embed a table in another document. I have written a modified version that you are free to use, but first things first.
Let's create a new outline. You know the drill, enter the text from the screenshot to the right, save the outline as myFirstTable.opml, let it render, and then open the rendered document in your web browser. The final document should look like myFirstTable. I'll let Dr. Matt explain this one (note: Matt's tutorial is a bit outdated, but still very useful and very well-written).
The Uber Renderer (aka pikeRenderer)
A wise developer using Userland's Frontier noticed that most of the renderers they were building looked kind of the same. The only real variation was the kind of HTML tags to be produced based on the indentation level of the outline. It seemed possible to build a single renderer that was customizable by providing outline level formatting rules. Thus began development of the pikeRenderer. I cannot possibly do this renderer justice in this space. Besides, Dave has already written a pretty decent story explaining its use. [There used to be a story devoted to this topic, but I cannot find it. Look for the section on "rules" in this story.] Another article on pikeRenderer. Note: On 3/11/2002 I found this article on rules at Andy Sylvester's website. I highly recommend using the pikeRenderer for everything but tables (which it does not currently support).
A couple more notes on the pikeRenderer. You can redefine the formatting rules for a given level at any point in the document you want to. The new rules have to be defined as a summit, however. Thus, one paragraph might be single spaced and another double spaced depending on how you choose to define the rules. You can also do a limited amount of "mix & match" formatting. I frequently use a three level set of rules. The first two emulate a twoLevelOutline, the third creates unordered lists. This approach eliminates the flaky list item paragraph problem we saw in the prior lists example. You are free to download my three level rules, if you want.
Thanks for hanging in there. You either a) really need this stuff; b) are terribly interested; or c) are a glutton for punishment. This is about the end of my story (and my day). I promise you, there is a payoff. The pikeRenderer is a very powerful renderer, but sometimes you want to mix and match styles that you just cannot define within Pike's rules. For example, HTML tables rarely exist on their own; they are usually part of a larger HTML document. Further, you cannot define pikeRenderer rules to create a table (AFAIK). Here is the theory behind the solution I use. First, create an outline to be rendered as a table and save it. Second, create an outline to be rendered as a twoLevelOutline (or something) and within it ask Radio to render the first outline and include the results. We will walk through an example, but first there is a small problem to be fixed.
The technique outlined above was standard fare in Radio 7.x. Radio even provided a spiffy verb named renderObject that would render the specified outline and include the output (HTML) in the document currently being rendered. A nice way to mix and match rendering styles. However, the renderObject verb only works on outlines that live inside Radio. It won't work for outlines stored in the file system. There is a second, minor, problem. The tableOutliner discussed previously will not work with embedded documents in Radio 8. It has to do with the way the pagetable address is retrieved. The pagetable is a very important construct Radio uses during the rendering process. The API for retrieving the pagetable changed slightly in Radio 8, breaking the tableOutliner for embedded documents. We'll tackle this problem first.
There is one line in the tableOutliner that must be changed for it to work correctly in Radio 8. You can make this change. Or, if you prefer, you can download my handy-dandy, new and improved newTableOutliner. If you are comfortable making changes to Usertalk code, just open user.html.renderers.tableOutliner and replace the line of code reading: "with html.data.adrPageTable^" with a line of code like this: "local(pta = html.getPageTableAddress ())" followed by this: "with pta^". It might be safer to download my version! I added some extra features to this renderer to make tables look a little prettier. Here is a sample. My newTableOutliner works a lot like the old one, but gets the pagetable address using the newer API and uses a div with a background color exposed through a small cellspacing value to provide thin, clean borders around each cell. It looks good if the table has a width of 100%. Less so for narrower tables. Let me know if you see an easy fix!
As we discussed earlier, the renderObject verb only works on outlines living inside of Radio. We will need something that works in a similar way outside of Radio. Mark Paschal helped me find the answer. I wrote a new macro, cleverly named renderFile, that works just like renderObject, but operates on files in the file system. Download the renderFile macro and copy it into Radio's macros directory. Let's put it to use.
Embedding a Table
Create a new outline in Radio using the screenshot to the right as an example. This is a table that we will embed in another document. It is the Pretty Table we looked at earlier. Save this outline as #sampleToDoList.opml in your stories\misc subfolder. Note two things about this outline. We did not specify a title because this is going to be embedded in another document. With title directives, the last one defined wins. So, no title directive because the embedded docs will override the title in the main doc. Second, we saved this file with a # prefix. That tells Radio to not automatically render this file. You don't want this subdocument to be rendered as a "first class" document showing up in your index.
[This space intentionally left blank!]
Now create another outline. This will be the primary document and will embed the table document within it. Use the screenshot below as an example. Save this outline in your stories\misc subfolder (I named it embeddingATable.opml, but you can call it anything you want). After it renders, open it up in your browser. Mine looks like this embedded table example.
That is all I have time, or energy, for today. If you are interested in how this article was created as a twoLeveloutline, you can download the text file for A Busy Writers Guide To Radio Renderers. While working on this article I ran across a general rendering tutorial on the Frontier website and this article explaining what outline renderers are. You can find the renderers available to you in Radio at user.html.renderers. You are free to modify these or to create you own renderers.
Oliver Wrede wrote to mention that he has developed a Manila-plug named metaRenderer in that enables outline renderers to be switched mid-stream - within a single outline. This is really nice because it allows you to keep the entire document in a single outline file, while my technique requires the creation of one outline file for each section to be rendered with its own renderer. If you are using Radio to edit a Manila site, contact your Manila administrator about installing this plug-in.