Frontier Web TutorialAbout This Tutorial
About Web Site Management
Why Frontier?
Starting Up
Getting Comfortable With Tables
Exploring the Examples
Your First Web Site
Frontier HTML Basics, and the Directive Hierarchy
Other Automatic HTML
Getting Comfortable With Outlines
Templates
Outline Formatting
Includes and Macros
Handling Images
Glossaries and Filters
Defines and Custom Directives
Releasing
Site Outline and NextPrev
Relative References
Leveraging Your Work
Narrative of a Rendering
Where To Go From Here
|
|
Narrative of a Rendering
|
For advanced work it is useful to know the narrative of the process
whereby a page is built; this averts mistakes, and orients you when
exploring or debugging. There are various such narratives available; no
criticism of these is intended! These are just the particular details I've
found it useful to have on hand.
In what follows, I refer to the thing we are rendering as "the object". I
refer to user.html.prefs as prefs. I refer to html.data.page as "the data page";
and, as a shorthand, I refer to things in the data page like directives,
starting with "#", even though names in the data page do not actually start
with "#".
So, when I say #folder is set, I generally mean html.data.page.folder is set.
When I say #tagSubstitution is consulted I generally mean that
html.getPref() is called to check both the data page and prefs, but note that
this isn't always done -- sometimes the data page is consulted directly [in
theory I suppose this shouldn't be the case].
Note: The discussion is schematized with nested levels of
indendation. On my machine, Netscape doesn't render it properly; if
you don't see the nesting, try MSIE.
Here we go. Suppose you select a page and choose View In Browser.
If prefs.threadedRendering, semaphores are used; this doesn't cause
rendering to be threaded, but rather keeps it safe from threading -- if a
second thread might do rendering, it should wait until active rendering is
done.
The data page is cleaned out; #f is defined as the empty string [I don't
understand why] and #flPreview made true to show
we're previewing. We call...
|
|
html.buildObject()
Various user tables and prefs are initialized if they don't exist. Then we
call...
|
|
html.buildPageTable()
We point #adrObject at the object.
Now we collect table-based directives, examining the table containing the
object, then the table containing that, then the table containing that, and so
on until we hit the top level of the database. At each level, we copy
information into the data page; generally, outlines and tables are "copied"
by address, other things are copied by value. If we've already copied
something with a certain name, though, we don't copy it again -- thus enforcing
object-orientation.
What we're looking for are: a tools table; a glossary table; and anything
starting with "#". Two directives are handled in special ways:
|
|
For #template, if it's an outline or wptext, we also make #indirectTemplate
false, and if it's an outline, we copy the outline itself. Otherwise
#indirectTemplate is true. Thus #template can be direct (an outline or
wptext) or indirect (a name, taken to be in user.html.templates); we'll see
later how this is handled.
When we come to #ftpSite, we also set #adrSiteRootTable to point to the
table where we found it, and #subdirectoryPath to the pathname of the
object relative to that [this is how the location of #ftpSite shows
where the whole site is, within the database]. Note that #ftpsite too can
be direct (a table) or indirect (a name, taken to be in user.html.sites): this
is handled later by going through html.getSiteTable() whenever we want to
look inside our #ftpsite.
|
|
We construct #fname (the name of the file we'll be writing to disk) based
on the name of the object being rendered, by calling html.getFileName(),
which adds the #fileExtension suffix and calls html.normalizeName() to
adjust the name depending on #dropNonAlphas, #lowerCaseFileNames, and
#maxFileNameLength.
From #fname, we construct #f, the full pathname of the file we'll be
writing to disk -- since this is a preview (that's what #flpreview was for),
it's the Frontier folder, plus a Websites folder, plus a folder representing
#adrSiteRootTable, plus a folder or folders representing #subdirectoryPath,
plus #fname.
We also construct #url, the URL for our page, based on the url value in
#ftpsite, using #subdirectoryPath and #fname.
|
|
Next we "render" the object (collect its internal directives and turn it into a
string) by calling...
|
|
html.data.standardMacros.renderObject()
The object is copied into a local called lo (for "local object", no doubt). What
happens next depends upon what kind of object it is.
If it's an address,
|
|
we call renderObject() on what it points to.
|
|
we construct an HTML table that schematizes it.
|
|
we call the script (with no parameters) to get its result. [Since we're working
with a renamed copy of the script, the script must not have an
eponymous handler.]
|
|
If it's a string, a wptext, or a fileSpec,
|
|
we call html.runDirectives() on it (or
its contents), to gather page-based directives...
|
|
html.runDirectives()
We examine the string line by line, looking for directives (paragraphs
beginning with "#"), until the end, or (if #directivesOnlyAtBeginning) until
we hit a non-directive. Each time we find one, we delete it and call
html.runDirective() on it...
|
|
html.runDirective()
The "#" has already been removed, and the directive paragraph is divided
into two pieces: everything before the first space (the name) and
everything after it (the value). From these we construct a statement of the
following form:
dataPageEntry = theValue
and evaluate that statement in order to perform the assignment. [That's
important to understand in writing directive values.]
Note that we are now over-writing any directives of the same name that we
put into the page table earlier, i.e. in html.BuildPageTable(); this enforces
object-orientation further: page-based directives have priority over table-
based.
If we encounter a #template, we additionally set #indirectTemplate to
true.
|
|
we call html.runOutlineDirectives() on it, to gather its
directives...
|
|
html.runOutlineDirectives()
We examine the outline line by line, looking for directives (summit-level
lines beginning with "#"). No attention is paid to
#directivesOnlyAtBeginning, probably because we have to cycle through
the whole outline regardless in order to delete summit-level comments.
Each time we find a directive, we delete it and call html.runDirective() on it
to get it into the page table (see above). If the directive is a #define or a
#defineScript, we also obey it: we put an entry in the data page with the
defined name, then grab the material subordinate to the directive (with
toys.outlineToList()) and stick it in as the value of that entry (with
toys.listToOutline()).
|
|
We then render the outline. First, we find the renderer, from
#renderOutlineWith: first we try to interpret it directly as an object
reference; then we look in the tools table pointed to from the data page;
then we look in user.html.renderers. Next, we call the renderer; or, if no
#renderOutlineWith was present, we call html.ucmds.getOutlineHtml() to
render the outline as a UL-type list (the "default renderer"). Now the
outline has become a string with HTML formatting inserted (plus anything
else like returns, tabs, etc.).
|
|
If the object to be rendered wasn't any of those types,
|
|
we just make it a
string and surround it by "<PRE>" tags.
|
|
The rendered object now sits in a local called ro (for "rendered object",
surely).
We now construct #fname and #f all over again, just as we did in
html.buildPageTable()! I take it that this is because the object being
rendered might have contained new #fileExtension, #dropNonAlphas,
#lowerCaseFileNames, or #maxFileNameLength directives. [Indeed, in
theory it could have contained new #ftpSite, #subdirectoryPath,
#adrSiteRootTable, and #url directives (note that #url is not recalculated
here, a mistake?); the page, instead of being located meaningfully in the
database, might thus explicitly specify its own location in the site.]
We call the pageFilter (with no parameters); if it likes, it can operate on
html.data.page.bodytext to revise our thus-far rendered object. The default
pageFilter makes a dropcap, and creates a glossPatch entry for this page in
the glossary pointed to by the data page. [It uses the location of the #filters
table to mark the top of the hierarchy -- not the #ftpSite table or
#adrSiteRootTable.]
We are now ready to integrate the rendered object into the template. We
obtain the template, either from user.html.templates (if indirectTemplate)
or from the page table. We gather its directives: either we call
html.runDirectives(), or, if it's an outline, we call
html.runOutlineDirectives() and convert directly to a string (a template has
no outline renderer). If #tagSubstitution, we now replace "<title>" with
#title, and "<bodytext>" (or "<meat>") with the rendered object, ro.
Now we deal with macros and glossary items. We call...
|
|
html.processMacros()
This calls...
|
|
string.processHtmlMacros()
This is a kernel call so it's a black box; however, one can guess what it
does.
Things in angle-brackets and in quotes are protected from macro
expansion unless the first angle-bracket or quote is escaped.
Things in curly braces (unless the first curly brace is escaped) are
processed as macros (if #processMacros) by evaluating as a UserTalk
expression; this takes place in the context of a "with" so that we look for
object references first in the tools table pointed to by the data page, then
in user.html.macros, then in html.data.standardmacros, then in
html.data.page (in case it's a directive name or a name put in via
#defineScript or #define).
|
|
the pageHeader() and pageFooter macros
A template typically starts with a {pageHeader()} call and ends with a
{pageFooter()} call. This creates the surrounding HTML. If there is a #meta
it is inserted literally; we also add our own name and content meta, and, if
prefs.includeMetaCharset, a charset meta is constructed using #charset. If
there is a #javascript, a script tag is constructed. The body tag is
constructed using #background, #alink, #bgcolor, #text, #link, #vlink,
#topmargin, and #leftmargin. In the footer, if #noHintsInHeader is false,
suites.fatPages.buildPageAtts() is called to construct the hint comment; this
includes the netAddress based on #serverNetAddress, the menubar based
on #menubar, and the fat page data based on #adrPageData.
|
|
Literal strings (unless the first quote is escaped) are processed as glossary
entries (if #expandGlossaryItems) by calling html.refGlossary()...
|
|
html.refGlossary()
We look for the glossary entry first in the glossary table pointed to by the
data page, then in any glossary tables encountered up through the
database hierarchy from the object being rendered, then in
user.html.glossary. Finally, as a last ditch effort, we look in the table
containing the object being rendered to see if it's the name of another Web
page, and if so we construct a relative reference link to it [this last bit of
code is repeated identically twice, probably a mistake].
|
|
Now "<p>" is substituted for two return-characters if #autoParagraphs, lines
starting with "***" are surrounded with "<b>" tags if #clayCompatibility, and
URLs are turned into live links if #activeURLs. Finally, escaped characters
are simplified: so, "\{" becomes "{", "\\" becomes "\", and so on.
|
|
If #isoFilter, toys.isoFilter() is called to perform character translation. This
calls string.iso8859encode(). An internal substitution table, identical to the
one at html.utilities.iso8859.table, is used unless there is a table at
user.html.prefs.iso8859map.
|
|
The finalFilter is called (with no parameters); if desired, it can revise
html.data.page.renderedText. [The default finalFilter contains a call to
html.data.standardMacros.glossaryPatcher(), probably a mistake as we are
about to call it anyway.]
We resolve glossPatch calls into relative links, by calling...
|
|
html.data.standardMacros.glossaryPatcher()
If #useGlossPatcher, we look in renderedText for substrings of the form
"[[#glossPatch xxx|yyy]]" and make "xxx" a relative link to "yyy". [The
procedure take no advantage of #adrSiteRootTable, #subdirectoryPath, and
#url, but assumes the #ftpSite table sits in the site itself to mark top of the
hierarchy; this breaks if #ftpSite is indirect. Also, note the inconsistency:
automatic glossPatch glossary entries were created relative to the location
of the #filters table, but are resolved relative to the location of the #ftpSite
table.]
|
|
We construct #fname for a third time (!!!) and call html.ftpText(), which
writes the rendered text out to disk at pathname #f, assigning it the creator
#textFileCreator. We ask the web browser to open that file, and we're done.
Releasing a page and releasing a table are fundamentally similar to the
above. The main things to know are these: #flPreview is now false, so
#ftpSite.folder is used (and so View In Finder works afterwards); and,
when releasing a table, each entry in the table is checked with
html.traversalSkip() to see if there's a reason not to release it (such
reasons are that its name starts with "#" or is "images", "glossary", or
"tools").
|
[ Previous |
Next ]
This page was built on a Macintosh running
Frontier.
Last modified 7/8/97; 1:28:24 PM. © Copyright 1997,
Userland Software, Inc. Written by Matt Neuburg,
matt@tidbits.com.
|