Monday, November 08, 2010 at 12:00 AM.
scripting2Suite.server.buildStoryPage
on buildStoryPage (username, adrstory, flupload=true) {
<<Changes
<<8/4/10; 7:02:21 PM by DW
<<Define urlNext and urlPrev. If it's the first, urlPrev is the emptystring, if it's the last, urlNext is the empty string.
<<7/6/10; 4:46:56 AM by DW
<<Go from 2-level hierarchy to N-level hierarchy.
<<6/30/10; 2:48:51 PM by DW
<<If a story has a flVisibleSubtext attribute and it's true, render the outline differently.
<<6/14/10; 3:21:04 AM by DW
<<In addition to <%pubDate%> add <%bylineDate%> specifically for display in the byline of the story. It uses the longstring date format.
<<6/11/10; 7:54:02 AM by DW
<<Now we allow paragraphs to have subtext that is hidden until you expand it.
<<6/3/10; 9:23:48 AM by DW
<<Created.
local (adrsystemdata = scripting2suite.init (), now = clock.now (), fldebug = true, flVisibleSubtext);
local (adrdata = scripting2suite.inituser (username));
local (storytext = "\r\r", indentlevel = 0, adr, ct=0);
local (imgPermalink = string (scripting2Suite.data.html.sharpPermalinkImg));
<<edit (adrstory)
scripting2Suite.server.initStory (adrstory); //6/14/10 by DW -- make absolutely sure it has all fields it's supposed to
bundle { //set flVisibleSubtext
if defined (adrstory^.flVisibleSubtext) {
flVisibleSubtext = adrstory^.flVisibleSubtext}
else {
flVisibleSubtext = false}};
on add (s) {
storytext = storytext + string.filledstring ("\t", indentlevel) + s + "\r\n"};
on decode (s) {
return (xml.entitydecode (s, true))};
if not defined (adrstory^.xstruct) {
xml.compile (adrstory^.opmltext, @adrstory^.xstruct)};
local (adropml = xml.getaddress (@adrstory^.xstruct, "opml"));
local (adrbody = xml.getaddress (adropml, "body"));
local (adrsummit = xml.getaddress (adrbody, "outline"));
bundle { //add the outline structure
on gettextatt (adrx) {
return (decode (xml.getattributevalue (adrx, "text")))};
on hassubs (adrx) { //return true if the outline node has sub-outlines
local (adr);
for adr in adrx {
if nameof (adr^) endswith "outline" { //contains at least one sub
return (true)}};
return (false)};
on dolevel (adrlevel, textClass) {
local (adr);
for adr in adrlevel {
if nameof (adr^) endswith "outline" {
local (s = gettextatt (adr), idPgf = "p" + ++ct, idDiv = "div" + ct, icon="");
bundle { //change idPgf if it has a paragraph-level serial number, 6/23/10 by DW
try {
idPgf = "p" + xml.getattributevalue (adr, "pgfnum")}};
local (flhassubs = hassubs (adr));
if flhassubs {
icon = scripting2Suite.server.getExpandCollapseIcon (idDiv, flVisibleSubtext)};
bundle { //add a blue arrow link, if it's a node of type link, 6/28/10 by DW
s = s + scripting2Suite.server.getLinkHtml (adr)};
if adrdata^.prefs.flPgfPermalinks {
s = "<a name=\"" + idPgf + "\"></a>" + icon + s + " <a href=\"#" + idPgf + "\">" + imgPermalink + "</a>"};
if flhassubs {
local (adrsub, class="hide");
add ("<p class=\"" + textClass + "\">" + s); indentlevel++;
if flVisibleSubtext {
class = "show"};
add ("<div class=\"" + class + "\" id=\"" + idDiv + "\" name=\"" + idDiv + "\">"); indentlevel++;
dolevel (adr, "storySubtext");
add ("</div>"); indentlevel--;
add ("</p>"); indentlevel--}
else {
add ("<p class=\"" + textClass + "\">" + s + "</p>")}}}};
dolevel (adrsummit, "storyPageText")};
adrstory^.storytext = storytext;
local (t = adrstory^);
t.whenLastUpdate = date.longstring (t.whenLastSave) + "; " + date.timestring (t.whenLastSave);
t.bodytext = storytext;
t.pubDate = t.postdate; //I prefer to use RSS terminology in the story template
t.localPubDate = scripting2Suite.server.getLocalTime (username, t.pubDate); //6/14/10 by DW
t.bylineDate = date.longstring (t.localPubDate) + " at " + date.timestring (t.localPubDate, false); //6/14/10 by DW
t.author = adrdata^.prefs.ownerName; //RSS terminology
scripting2Suite.server.setupMacrosTable (username, @t); //add common elements
t.crumbTrail = scripting2Suite.server.getCrumbTrail (t.baseurl, t.postdate); //6/8/10 by DW
bundle { //set nextPrev
local (nextlink = "Next", prevlink = "Previous");
if adrstory^.adrprev != "" {
local (adrprev = address (adrstory^.adrprev)); //we store addresses as strings, and convert when we use them
prevlink = "<a href=\"" + adrprev^.url + "\">" + prevlink + "</a>"};
if adrstory^.adrnext != "" {
local (adrnext = address (adrstory^.adrnext)); //we store addresses as strings, and convert when we use them
nextlink = "<a href=\"" + adrnext^.url + "\">" + nextlink + "</a>"};
t.nextPrev = prevlink + " / " + nextlink};
bundle { //set urlNext and urlPrev, 8/4/10 by DW
if adrstory^.adrprev != "" {
local (adrprev = address (adrstory^.adrprev));
t.urlPrev = adrprev^.url}
else {
t.urlPrev = ""};
if adrstory^.adrnext != "" {
local (adrnext = address (adrstory^.adrnext));
t.urlNext = adrnext^.url}
else {
t.urlNext = ""};
t.urlParent = "";
t.urlChild = ""};
bundle { //set up calendar
scripting2Suite.server.getCalendarText (username, adrstory^.postdate, t.baseurl, @t.calendar, @t.nextPrevMonths)};
bundle { //set editButton 7/3/10 by DW
t.editButton = "<script type=\"text/javascript\" src=\"http://127.0.0.1:5337/scripting2/editor/controls?username=" + username + "&url=" + adrstory^.url + "\"></script>"};
bundle { //run it all through the template, ship the file to the server
local (pagetext = string.multiplereplaceall (string (adrdata^.prefs.storytemplate), @t, false, "<%", "%>"));
pagetext = scripting2Suite.server.glossarySubstitution (@adrdata^.prefs.glossary, pagetext);
pagetext = scripting2Suite.server.glossarySubstitution (@scripting2Suite.data.systemGlossary, pagetext);
if flupload {
scripting2Suite.writeStaticFile (username, adrstory^.path, pagetext);
if not defined (adrstory^.ctUploads) {
adrstory^.ctUploads = 1};
adrstory^.ctUploads++;
adrstory^.whenLastUpload = clock.now ()}}};
bundle { //test code
local (adrstory = @scripting2Data.server.users.davewiner.calendar.["2010"].["06"].["11"].["00246"]);
local (tc = clock.ticks ());
script.startProfile (true);
buildStoryPage ("davewiner", adrstory, false);
script.stopProfile (@scratchpad.storyProfile)}
<<dialog.alert (clock.ticks () - tc)
<<webbrowser.openurl (adrstory^.url)
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.