Up and Running with Frontier Web Site Management
by Matt Neuburg
One of the features of computer work, and this is very commonly true with Web pages and even more so when you have to deal with HTML, is that there is a lot of repetitive typing of the same fixed phrases over and over.Frontier provides a way out of such annoying repetitive labor. (After all, what's a computer for if it doesn't save you from just this kind of busy work?)
This is the Glossary mechanism. You keep a table of text substitutions; when your page is rendered, the substitutions are performed. In effect, you get to make yourself a set of shorthand abbreviations for some stock phrases. The idea is utterly simple; yet it's such a handy tool that you'll use it all the time.
To see an example of the glossary at work, go into myFirstSite.default and, where it says "thanks to Frontier", surround the word "Frontier" with quotes. Now view the page in the browser. The word "Frontier" doesn't appear in quotes in the browser, but it has become a link, leading to the Frontier Web site at scripting.com.
The way this happens is that, at rendering time, Frontier searches for tables called "glossary", and it looks in these for entries whose name matches any quoted material in your Web page.
If it finds such an entry, it substitutes the value of the entry for the quoted material in the page. If it doesn't find such an entry, it just leaves the original quoted material alone. Before it gives up, it looks in user.html.glossary. That's where it found the entry for "Frontier" -- take a look at it.
You can see that user.html.glossary.Frontier has a value which is an <a> tag, the word "Frontier", and the closing </a> tag; this is what eventually made its way into the rendered version of our default page.
You can prevent any particular quoted phrase in your page from being searched as a glossary item by putting a backslash before the first quotation mark. You can also turn off the whole glossary mechanism, for one page or a group of pages, by means of the #expandGlossaryItems directive; this is "true" by default, but you can set it to "false".
Things in angle-brackets (HTML tags) are normally protected from having their contents seen as possible glossary items; things could get pretty crazy otherwise.
Of course you can create glossary items manually; they're just table entries.You also get a shortcut from within your browser to build glossary entries like "Frontier" and the others already in user.html.glossary.
When Frontier is running, the browser has an extra Scripts menu containing an item Add To Glossary, from which you can insert into user.html.glossary a reference to the page you're currently looking at in the browser. (User.html.glossary may not be where you ultimately want to keep the reference, but it is a good initial storage location; you can easily cut and paste the entry to another glossary table later if you like.)
You can also use items in the Scripts menu to get quickly to user.html.glossary, and even to see user.html.glossary converted into an actual page of links in the browser.
You'll doubtless find many uses for the glossary mechanism, since many kinds of boilerplate or repetition are likely to occur throughout your pages. People's tastes and needs vary.Personally, although I like to use the glossary for link references, I don't always use the mechanism quite the way it's illustrated by the entries at user.html.glossary, because I don't like being restricted to one fixed phrase which is going to appear between the <a> and the </a> tags.
For example, right now the glossary item "Frontier" resolves to a link emanating from the word "Frontier". It would be nice to have more flexibility about what text the link emanates from.
One solution I used to use is to have a glossary entry for "Frontier" which consists of just the <a> tag, like this:
<a href="http://www.scripting.com/frontier/">That way, I can have any phrase I want become a link to the Frontier Web site; of course I have to put in the final </a> myself, but that's no trouble. So, for instance, I might write:
There is a "Frontier"really cool tool</a> you should know about.This ends up rendered as a good HTML link.
Now I mostly use a different solution: a macro. I call it glossSub. Here's what it does. Suppose our Frontier glossary entry is the one in user.html.glossary.Frontier. In my page, instead of putting a glossary item (a phrase in quotes), I put a macro. Like this:
There is a {glossSub("Frontier", "really cool tool")} you should know about.That ends up saying: "There is a really cool tool you should know about.", with the link to the Frontier site emanating from the words "really cool tool". The first thing in parentheses is the name of the glossary table entry; the second is the text we want the link to emanate from. (This assumes, of course, that the glossary item's value is a link.)
You really ought to try this, it's fun! Oh, but you can't; you don't have the glossSub macro. But you could create it yourself...
Now, I am not going to explain UserTalk just for this one macro. So you'll just have to copy it (very, very carefully, or it won't work). Open up user.html.macros, choose New Script from the Table menu, call it "glossSub" (without the quotes), and when the script edit window opens, delete what's in it and put this:
Wow, does it have to be so long and complicated? Yes, because I'm planning ahead; this macro actually does two different things, so we're going to use it again in a later chapter. Sneaky, eh? Anyhow, type it, getting it all exactly right including the indentation. When you're all done, hit the Compile button at the upper right of the window; that's important, since without it your script may not "take".
Now use it! Go into myFirstSite.default, and where you previously had "Frontier", take it out (including the quotes around it) and in its place put:
{glossSub("Frontier", "a really cool tool")}View that in the browser. Getting the idea now?
Notice how we've only just learned about glossaries and already we're fiddling with how they work. In setting up the original glossary mechanism, Dave has done what's convenient for him, given the way he works and thinks; I substitute what's convenient for me, given the way I work and think; you'll eventually substitute what's convenient for you. And that's the whole idea! And of course links are far from being the only kinds of things you are liable to write glossary entries for.
The behavior of the glossary mechanism, in the way it searches for each quoted phrase as a glossary entry, is really special -- nothing else in the Web site management tools acts quite like this. So let's be clear about it, so you can take full advantage of it!First, your page can have a special glossary of its own. This can be anywhere in the database. Just use a #glossary directive in the page:
#glossary "people.MAN.mySpecialGlossary"Next, we look for a glossary table in the same table as the page we're rendering. Then in the table that contains that, and so on. And we always look in user.html.glossary last.
So, if myFirstSite has a sub-table called someFolder, and you're rendering a page in it called myPage, which has the #glossary directive above, then for each glossary item in myPage:
As soon as we find the item we're looking for, we stop looking and perform the substitution. You can use this to give glossaries the same hierarchical object-oriented power as directives and images.
- First we look in people.MAN.mySpecialGlossary
- Then we look in user.websites.myFirstSite.someFolder.glossary (if there is one)
- Then we look in user.websites.myFirstSite.glossary (if there is one)
- Then we look in user.websites.glossary (if there is one)
- Then we look in user.glossary -- hey, this is getting silly...
- Ultimately we look in user.html.glossary
At this point a word is in order about the relationship between glossary items and macros.Perhaps you noticed while doing the Images exercise that typing the imageRef call was rather a pain. If you wanted to include the same imageRef call at several places in your page or site, things might become particularly trying.
This comes up for me all the time, such as when I have a list of items and some of them are marked with a little GIF that says "new" or "cool". I don't want to have to write a whole imageRef call for every occurrence of this GIF; I want to just put "new" or "cool" and have the glossary put the imageRef call in for me.
Unfortunately, this doesn't work as Frontier comes configured out of the box, because macros are interpreted before glossary entries.
You'll have to see this for yourself. Go into the template, and select the entire imageRef call, including the curly braces at both ends.
Cut, and now type "ourLogo", including the quotes, thus replacing the call with the quoted phrase. Open myFirstSite.glossary (ignoring anything that may be in there; I'll explain all that later), and from the Table menu use New Scalar to create a new String.
Call the string "ourLogo" (without the quotes), tab into its value, and Paste (and hit Enter to set it). Now go to any page, such as myFirstSite.default, and view it in the browser. Instead of the logo appearing, the imageRef call is there as text.
In cases like this we need a way to give Frontier a little nudge, to ask it to interpret macros one more time after glossary items have been interpreted. The authors in their infinite wisdom have provided hooks for us to do this, in the form of Filters.You probably didn't know you had any Filters, but you do; look in myFirstSite.#filters and you'll see there are two. They are both scripts.
Pagefilter is so that you can do things to your page before it has been embedded into its template; it is called after directives in your page have been processed but before anything else has happened, and you are expected to modify an object called html.data.page.bodytext as desired.
Finalfilter is called at the end of the rendering process, and you are expected to modify an object called html.data.page.renderedtext.
If you look inside pagefilter and finalfilter you will see that in fact they already do something by default.
Pagefilter makes the first letter of your page larger than all the others, and helps build your glossary to prepare it for use of the glossPatch mechanism (that's how all those entries got into your glossary; I'll explain about the glossPatch mechanism later). Finalfilter actually calls the glossPatch mechanism (redundantly, since it is called again a moment later in html.buildObject).
Now I'll tell you how to modify finalfilter so that our macro call inside a glossary value will work.
Just go into myFirstSite.#filters.finalfilter and add a line that says (get this exactly right, now):
html.data.page.renderedtext = html.processmacros(html.data.page.renderedtext)This should be just a single line (I've split it here only for easier legibility), and should be at the same level as the lines that are already there; in fact, just for good measure hit command-U until it is the first line of the script.
Now hit the Compile button or your change won't "take". Now go back to myFirstSite.default and view it in the browser; presto, the logo is back.
With this system you can have glossary items with values that are macro calls!
(If you want to do this in any other sites, you're going to need to copy that line into the finalfilter for those sites as well.)
The routine html.processmacros is what interprets macro calls and glossary items in our pages. It was called as part of the normal rendering process, and that's how "ourLogo" was interpreted as a glossary item and turned into an imageRef macro call.Now, after the rendering process is basically over, we're asking for a second round of macro (and glossary item) processing. So our imageRef macro call is seen and interpreted, and we end up with an <img> tag.
But there are cautions that go with this trick. Remember how putting a backslash can protect things from being processed as macro calls, live URLs, and such? Well, processing the page removes those backslashes (so that they won't appear in the final HTML). That means that on our second round of macro processing, things we protected during the first round won't be protected any more!
The solution is simple: if you're going to use two rounds of macro processing like this, double your backslashes (turn one into two, and two -- in case you need to signify a literal backslash -- into four).
Similarly, if you do two rounds of macro processing and you've got #autoParagraphs set to "true", you'll end up with two <p> tags before each pair of returns (because when the first round of macro processing inserted the <p>, it didn't remove the two returns). This is probably harmless but it's good to be aware of.
Despite the complications involved, asking for a second round of macro processing has lots of extra benefits. It lets us do tricks we couldn't do before.For example it sees to it that if you used the Include mechanism discussed earlier, any macros and glossary items in the included text are processed properly. You see why this is needed, don't you?
We process macros normally, and one of them is our renderObject call. Okay, now we've included an object, but macro processing is over, so none of that object's macros or glossary items got processed! So our second round of macro processing in the finalfilter takes care of that too.
Here's another benefit of the second round of macro processing: it makes it easy to make images that are clickable links. For example, suppose you have an image called "site". Let's make that image clickable as a link to the Frontier site.To do so, just type this somewhere in myFirstSite.default, and then view it in the browser:
{glossSub("Frontier", "{imageRef(\"site\")}")}Be careful about all the curly braces and parentheses, and especially the backslash-plus-quote (that's how you say a quote inside a string in UserTalk; these are all things you get very used to as you learn UserTalk).
Do you see what we're doing? It's a glossSub call, just like the ones we already looked at. But what we're making the link emanate from is an imageRef macro call. Then, on the second round of macro processing, that imageRef macro call is turned into an <img> tag, and presto, we've got a clickable image!
So now you know how to make any image be a clickable link to any site for which you've got an anchor-type glossary entry.
You might want to modify pagefilter so that it doesn't make the first character of every page large any more. To do so, just select the third line, the one that starts "try", and choose Toggle Comment from the Script menu. (And hit the Compile button.)Don't worry; making the first character of every page larger was just put there as an example of the kind of thing Frontier's pagefilter can do. You're expected to customize this routine.
All text is by Matt Neuburg, phd, matt@tidbits.com. This page created with Frontier, 7/8/97; 9:14:45 AM.