Monday, November 08, 2010 at 12:05 AM.

system.verbs.builtins.radio.weblog.render

on render (adrblog, dayTemplate, itemTemplate, catname=nil, flSameMachine=false, flIEditLinks=false, maxDays=nil, maxDate=nil, minDate=nil, adratts=nil, flStaticRendering=false, archiveFileExtension="html") {
	<<Changes
		<<8/30/03; 12:50:24 PM by JES
			<<Add TrackBack auto-discovery RDF bits inside an HTML comment. Fixes HTML validation errors.
		<<7/20/03; 6:14:16 PM by JES
			<<Added trackback support.
		<<11/11/02; 5:33:38 PM by JES
			<<Use & instead of & for the path-argument delimiter for the comment-counter JavaScript source url.
		<<10/28/02; 7:36:24 PM by JES
			<<Removed an extra cr/lf pair between the permalink anchor tag and the weblog item, which was causing extra paragraph tags. 
		<<9/3/02; 6:53:29 PM by LL
			<<Set defaults for maxdays for weekly and monthly archive pages by checking the pageTable.
		<<8/28/02; 6:09:17 PM by LL
			<<Call bottleneck scripts, radio.weblog.getUrlForDay and radio.weblog.getUrlForPost, to get the URLs for day and item permalinks.
		<<3/31/02; 10:45:22 PM by JES
			<<Add the anchor tag for the permalinks before the entire item, instead of before the itemtext.
		<<3/13/02; 1:13:58 AM by JES
			<<Only insert the comment counter javascript if the preference is enabled *and* the item template contains a <%commentCount%> macro. Prevents JavaScript when the <%commentCount%> macro is present but the comments feature is disabled.
		<<3/12/02; 5:00:00 PM by JES
			<<If the auto-generated title links feature is enabled, and no link is specified for a post, use the auto-generated link.
		<<3/11/02; 3:37:57 PM by DW
			<<Instead of tacking the title/link combo at the beginning of itemText, there's now a new element of an item template called itemLink. 
		<<3/11/02; 11:47:52 AM by DW
			<<Use the title and link info, if it's available.
		<<2/23/02; 1:15:20 AM by JES
			<<If the commentLinkText pref contains a <%commentCount%> macro, add the code to the page that loads the external JavaScript that renders the comment count.
		<<2/16/02; 6:27:43 PM by JES
			<<Added <%commentLink%> pseudo-macro. Call radio.html.commentLink to get the HTML for the link.
		<<2/13/02; 1:42:38 PM by JES
			<<Get permalink, source and enclosure image prefs using calls to radio.weblog.getThemePref.
		<<2/10/02; 11:20:22 PM by JES
			<<Make sure that adrsource^.compilation.channeltitle and adrsource^.compilation.channellink both exist, before attempting to generate the source-link. Prevents macro errors on pages which link to items from a source which doesn't have a complete compilation.
		<<1/25/02; 11:19:25 AM by JES
			<<Don't include posts which have an flNotOnHomePage == true, in the post table.
		<<1/24/02; 9:43:44 PM by JES
			<<New optional parameter, archiveFileExtension, specifies the extension to use for permalinks. Defaults to "html", and replaces the hard-coded extensions within the script. If pta^.renderedFileExtension is defined, use its value instead of the value of the archiveFileExtension parameter.
		<<1/24/02; 11:35:59 AM by JES
			<<Get the img tags for the item-level permalink, source and enclosure icons from weblogData.prefs, instead of from radio.data.strings.
		<<1/14/02; 7:13:15 PM by DW
			<<Add callbacks support in user.radio.callbacks.publishItem. Each callback gets the address of a post which is being published.
			<<http://radio.userland.com/stories/storyReader$7740.
		<<12/12/01; 12:57:41 PM by JES
			<<If the channel corresponding to the sourceUrl is no longer defined in aggregatorData, don't cause an error when expanding the <%source%> macro in the itemTemplate.
		<<12/10/01; 10:32:58 PM by JES
			<<Added support for the <%itemNum%> and <%paddedItemNum%> macros: <%itemNum%> is expanded to the non-padded number of the item being rendered; <%paddedItemNum%> is expanded to the zero-padded number of the item being rendered.
		<<12/7/01; 3:58:51 PM by JES
			<<Trim whitespace in the templates, to prevent extra <p> tags in the rendered HTML.
		<<12/5/01; 9:34:13 PM by JES
			<<Prepend an 'a' character onto the name for the <a name> tags (permalinks).
		<<11/30/01; 12:33:06 PM by JES
			<<Convert line-endings in bodytext to \r, before returning.
		<<11/16/01; 7:20:35 PM by JES
			<<Fixed the anchor tags that the permalinks point to.
		<<11/15/01; 3:44:24 PM by JES
			<<Make the item-level and day-level permanent links work for category index and archive pages. Make the item-level permalinks point into the archive page.
		<<11/12/01; 1:47:55 PM by DW
			<<Add support for the item-level permalink.
		<<11/12/01; 1:24:08 AM by JES
			<<Ignore adrblog^.prefs.maxOutputItemsPerChannel, which is for rss files, and not for HTML renderings. Instead, always render the number of days specified by the maxDays parameter. This makes category index pages work just like the weblog home page.
		<<10/30/01; 9:13:12 PM by PBS
			<<Use the new string.multipleReplaceAll verb if available.
		<<10/29/01; 10:49:55 PM by PBS
			<<Fixed a bug -- introduced in the last bug fix -- where the current day would be repeated on the home page.
		<<10/29/01; 4:27:47 PM by PBS
			<<Don't process macros with html.processMacros -- use string.replaceAll. It's faster, and it partly fixes a bug where html.processMacros is called too often.
		<<10/9/01; 1:15:12 PM by JES
			<<Added support for category HTML rendering. The only change is to limit the number of items rendered to the number defined by adrblog^.prefs.maxOutputItemsPerChannel, rather than to limit by maxDays, when catname is non-nil.
		<<9/3/01; 4:34:24 PM by JES
			<<New optional parameter: flStaticRendering, defaults to false.
			<<If true, then archive links will point at the static site, instead of the dynamic site.
		<<9/2/01; 10:26:39 PM by JES
			<<New optional parameter: adratts. If non-nil, then the table at adratts is copied into the radioResponder sub-table of the pageTable, before calling html.processMacros. This puts the atts in scope so that user macros can get at them.
		<<8/15/01; 6:53:34 PM by JES
			<<If the app version is less than 7.1b1, patch the templates to use the older { and } macro delimiters.
		<<8/12/01; 2:28:40 AM by JES
			<<Do replcaements using html.processMacros, instead of with string.replaceAll. This opens up user.html.macros, as well as glossary processing.
			<<Changed the <%text%> macro in the itemTemplate to <%itemText%> since <%text%> was rendering as garbage.
		<<6/25/01; 1:41:54 PM by DW
			<<Changes. General purpose weblog renderer. We have no say in how the text flows. We just generate the HTML from the templates, and return it.
	local (savedArgs = "", flArchivePage = false);
	local (dateZero = date.set (1, 1, 1904, 0, 0, 0), dateInfinity = date.set (1, 1, 2040, 0, 0, 0));
	bundle { //set defaults if not specified
		if maxDays == nil {
			<<if catname == nil //home or archive page
			maxdays = adrblog^.prefs.ctDaysToDisplay};
			<<else //category page -- the limit is a count of items, not based on date
				<<maxdays = infinity
		if minDate == nil {
			minDate = dateZero};
		if maxDate == nil {
			maxDate = dateInfinity};
		try { //get some info out of the pagetable if possible
			local (pta = html.getPageTableAddress ());
			if defined (pta^.flArchivePage) {
				flArchivePage = pta^.flArchivePage};
			if defined (pta^.flMonthlyArchive) {
				maxDays = 31};
			if defined (pta^.flWeeklyArchive) {
				maxDays = 7};
			if defined (pta^.renderedFileExtension) {
				archiveFileExtension = pta^.renderedFileExtension};
			bundle { //save getArgs -- so that the archive calendar on the weblog page will show the correct day, and the menu remembers its state
				local (adrargs = @pta^.radioResponder.getArgs);
				if defined (adrargs^) {
					if defined (adrargs^.d) {
						savedArgs = "&d=" + adrargs^.d};
					if defined (adrargs^.menu) {
						if sizeOf (args^.menu) > 0 {
							savedArgs = savedArgs + "&menu=" + adrargs^.menu}}}}}};
	if archiveFileExtension beginsWith "." { //it's expected not to
		archiveFileExtension = string.delete (archiveFileExtension, 1, 1)};
	bundle { //trim whitespace on templates
		dayTemplate = string.trimWhiteSpace (dayTemplate);
		itemTemplate = string.trimWhiteSpace (itemTemplate)};
	local (adrsite = @radio.data.website);
	local (editbuttonimg = radio.images.systemImageRef ("icons/editbutton", flFileUrl:flSameMachine));
	local (bodytext);
	local (flUseMultipleReplaceAll = defined (string.multipleReplaceAll));
	on doReplacements (adrText, adrTable) {
		if flUseMultipleReplaceAll { //use string.multipleReplaceAll
			adrText^ = string.multipleReplaceAll (adrText^, adrTable, false, "<%", "%>");
			return (true)}
		else { //old-fashioned way
			local (adr);
			for adr in adrTable {
				adrText^ = string.replaceAll (adrText^, "<%" + nameOf (adr^) + "%>", adr^, false)};
			return (true)}};
	bundle { //if the app version is less than 7.1b1, patch the templates to use the old macro delimiters
		if date.versionLessThan (Frontier.version (), "7.1b1") {
			if defined (adrsite^.["#prefs"].macroStartCharacters) {
				itemTemplate = string.replaceAll (itemTemplate, adrsite^.["#prefs"].macroStartCharacters, "{", false);
				dayTemplate = string.replaceAll (dayTemplate, adrsite^.["#prefs"].macroStartCharacters, "{", false)};
			if defined (adrsite^.["#prefs"].macroEndCharacters) {
				itemTemplate = string.replaceAll (itemTemplate, adrsite^.["#prefs"].macroEndCharacters, "}", false);
				dayTemplate = string.replaceAll (dayTemplate, adrsite^.["#prefs"].macroEndCharacters, "}", false)}}};
	bundle { //set bodytext
		local (ctdays = 0, lastday = -1, itemstext = "", lastitemdate);
		on addDay () {
			local (t);
			new (tableType, @t); //PBS 10/30/01: table used for string replacements
			t.longDate = date.longstring (lastitemdate);
			t.shortDate = date.shortstring (lastitemdate);
			t.dayOfWeek = date.dayOfWeekToString (date.dayOfWeek (lastitemdate));
			t.items = itemstext; itemstext = "";
			bundle { //build archiveLink
				local (url = radio.weblog.getUrlForDay (lastitemdate, catname, adrblog) );
				t.archiveLink = "<a href=\"" + url + "\">" + radio.weblog.getThemePref ("archiveLinkImgTag", adrblog) + "</a>"};
				<<bundle //old code
					<<if flStaticRendering //the archiveLink points at the static site
						<<local (extension = "")
						<<local (partialpath = adrblog^.prefs.homePageFilePath)
						<<local (fname = string.nthField (partialpath, '/', string.countFields (partialpath, '/')))
						<<if fname contains "."
							<<extension = "." + string.nthField (fname, '.', string.countFields (fname, '.'))
						<<t.archiveLink = "<a href=\"/" + yr + "/" + mo + "/" + dy + extension + "\">" + adrblog^.prefs.archiveLinkImgTag + "</a>"
					<<else //dynamic link
						<<t.archiveLink = "<a href=\"?d=" + yr + "/" + mo + "/" + dy + "\">" + adrblog^.prefs.archiveLinkImgTag + "</a>"
			bundle { //process (pseudo) macros -- PBS 10/29/01
				local (s = daytemplate); //PBS 10/29/01: make a copy of daytemplate, so day doesn't get repeated
				doReplacements (@s, @t);
				bodytext = bodytext + s;}};
		bodytext = "";
		local (i);
		for i = sizeOf (adrblog^.posts) downto 1 {
			local (adrpost);
			adrpost = @adrblog^.posts [i];
			bundle { //check min and max dates
				if adrpost^.when < minDate {
					break};
				if adrpost^.when > maxDate {
					continue}};
			bundle { //only include if in category, if catname was specified
				if catname != nil {
					local (flskip = true);
					if defined (adrpost^.categories) {
						local (adrthiscat = @adrpost^.categories.[catname]);
						if defined (adrthiscat^) {
							if adrthiscat^ {
								flskip = false}}};
					if flskip {
						continue}}};
			bundle { //if rendering the home page, or a non-category archive page, skip posts with flNotOnHomePage == true
				if catname == nil {
					if defined (adrpost^.flNotOnHomePage) {
						if adrpost^.flNotOnHomePage {
							continue}}}};
			bundle { //check date rollover
				local (when = adrpost^.when, day, month, year, hour, minute, second);
				date.get (when, @day, @month, @year, @hour, @minute, @second);
				if lastday == -1 { //first time through loop
					lastday = day}
				else {
					if day != lastday {
						ctdays++;
						if ctdays == maxdays {
							break};
						lastday = day;
						addDay ()}}};
			bundle { //call the callbacks -- 1/14/02; 7:15:52 PM by DW
				try {
					local (pta = html.getpagetableaddress ());
					if pta^.radioresponder.flstaticrendering {
						if not defined (user.radio.callbacks.publishItem) {
							new (tabletype, @user.radio.callbacks.publishItem)};
						local (adrcallback);
						for adrcallback in @radio.weblog.builtinCallbacks.publishItem {
							try {
								adrcallback^ (adrpost)}};
						for adrcallback in @user.radio.callbacks.publishItem {
							try {
								while typeOf (adrcallback^) == addressType {
									adrcallback = adrcallback^};
								adrcallback^ (adrpost)}}}}};
			local (t);
			new (tableType, @t);
			bundle { //set macro strings
				bundle { //set itemTitle
					t.itemTitle = "";
					if defined (adrpost^.title) {
						if adrblog^.prefs.flTitleAndLinkOnPostForm {
							if defined (adrpost^.link) {
								t.itemTitle = "<a href=\"" + adrpost^.link + "\" class=\"weblogItemTitle\">" + adrpost^.title + "</a>"}
							else {
								local (url, flLink = false);
								if adrblog^.prefs.flAutoGenerateLinks {
									flLink = radio.weblog.getUrlForPost (adrpost, @url, catname, adrblog)};
								if flLink {
									t.itemTitle = "<a href=\"" + url + "\" class=\"weblogItemTitle\">" + adrpost^.title + "</a>"}
								else {
									t.itemTitle = adrpost^.title}}}}};
				bundle { //set itemtext
					<<t.itemtext = "<a name=\"a" + number (nameOf (adrpost^)) + "\"></a>" + string (adrpost^.text)
					t.itemtext = string.trimWhiteSpace (string (adrpost^.text))};
				bundle { //set itemNum
					t.itemNum = number (nameOf (adrpost^))};
				bundle { //set paddedItemNum
					t.paddedItemNum = nameOf (adrpost^)};
				bundle { //set permalink
					local (url);
					bundle { //build linkurl
						radio.weblog.getUrlForPost (adrpost, @url, catname, adrblog)};
					t.permalink = "<a href=\"" + url + "\">" + radio.weblog.getThemePref ("itemPermaLinkImgTag", adrblog) + "</a>"};
				bundle { //set enclosure
					if defined (adrpost^.enclosure) {
						t.enclosure = "<a href=\"" + adrpost^.enclosure.url + "\">" + radio.weblog.getThemePref ("enclosureImgTag", adrblog) + "</a>"}
					else {
						t.enclosure = ""}};
				bundle { //set editButton
					if flIEditLinks {
						local (url = radio.data.systemUrls.weblogEditor + "?itemtoedit=" + number (nameof (adrpost^)) + savedArgs);
						t.editButton = "<a href=\"" + url + "\">" + editbuttonimg + "</a>"}
					else {
						t.editButton = ""}};
				bundle { //set source
					t.source = "";
					if defined (adrpost^.sourceUrl) {
						local (adrdata = xml.aggregator.init ());
						local (adrsource = @adrdata^.services.[adrpost^.sourceUrl]);
						if defined (adrsource^) {
							if defined (adrsource^.compilation.channellink) and defined (adrsource^.compilation.channeltitle) {
								t.source = "<a href=\"" + adrsource^.compilation.channellink + "\" title=\"Source: " + adrsource^.compilation.channeltitle + ".\">" + radio.weblog.getThemePref ("sourceImgTag", adrblog) + "</a>"}}}};
				bundle { //set when
					t.when = date.timestring (adrpost^.when)};
				bundle { //set commentLink
					t.commentLink = radio.html.commentLink (t.itemNum, adrblog)};
				bundle { //set trackbackLink
					t.trackbackLink = "";
					if adrblog^.prefs.trackback.flEnabled {
						if adrblog^.prefs.trackback.flAddTrackbackLinks {
							try {
								t.trackbackLink = radio.html.trackbackLink (t.itemNum, adrblog)}}}}};
			local (s = itemtemplate);
			doReplacements (@s, @t); //PBS 10/30/01: process (pseudo) macros
			itemstext = itemstext + ("<a name=\"a" + number (nameOf (adrpost^)) + "\"></a>\r\n" + s);;
			bundle { //trackback autodiscovery support
				if adrblog^.prefs.trackback.flEnabled {
					if string.lower (adrblog^.prefs.trackback.trackbackLinkText) contains "<%trackbackcount%>" {
						local (pingurl = radio.weblog.getTrackbackPingUrl (adrpost, adrblog));
						if sizeOf (pingurl) > 0 {
							local (permalinkurl);
							if radio.weblog.getUrlForPost (adrpost, @permalinkurl, catname, adrblog) {
								local (tbtitle = "");
								if defined (adrpost^.title) {
									tbtitle = adrpost^.title};
								if sizeOf (tbtitle) == 0 { //if the post doesn't have a title, use the blog's title
									tbtitle = adrblog^.prefs.title};
								local (excerpt);
								bundle { //create exceprt from post text
									excerpt = string.firstsentence (searchengine.stripmarkup (t.itemtext));
									excerpt = string.replaceAll (excerpt, "\r\n", "\r");
									excerpt = string.replaceAll (excerpt, "\r", " ")};
								itemstext = "<!--\r" + trackback.getAutodiscoveryXml (permalinkurl, pingUrl, tbtitle, "", excerpt, adrblog^.prefs.authorName, adrpost^.when) + "-->" + itemstext}}}}};
			lastitemdate = adrpost^.when};
			<<ctitems++
			<<if catname != nil
				<<if ctitems >= adrblog^.prefs.maxOutputItemsPerChannel
					<<if mindate > dateZero and maxDate < dateInfinity
						<<break
		if itemstext != "" { //there was some text left over when loop finished
			addDay ()}};
	bodytext = string.replaceAll (bodytext, "\r\n", "\r");
	if adrblog^.prefs.flCommentLinksEnabled { //add JavaScript to support comment counters
		if string.lower (adrblog^.prefs.commentLinkText) contains "<%commentcount%>" {
			bodytext = "<script src=\"" + adrblog^.prefs.commentsPageUrl + "?u=" + user.radio.prefs.usernum + "&c=counts\" type=\"text/javascript\"></script>\r" + bodytext}};
	if adrblog^.prefs.trackback.flEnabled { //add JavaScript to support TrackBack counters
		try {
			if string.lower (adrblog^.prefs.trackback.trackbackLinkText) contains "<%trackbackcount%>" {
				bodytext = "<script src=\"" + adrblog^.prefs.trackback.trackbackPageUrl + "?u=" + user.radio.prefs.usernum + "&c=counts\" type=\"text/javascript\"></script>\r" + bodytext}}};
	return (bodytext)}
<<bundle //test code
	<<local (folder = user.radio.prefs.wwwfolder)
	<<local (daytemplate = string (file.readwholefile (folder + "#dayTemplate.txt")))
	<<local (itemtemplate = string (file.readwholefile (folder + "#itemTemplate.txt")))
	<<local (catname = nil, flSameMachine = false)
	<<local (htmltext = render (radio.weblog.init (), daytemplate, itemtemplate, catname, flSameMachine, flStaticRendering:true))
	<<local (f = folder + "tmp.html")
	<<file.writewholefile (f, htmltext)
	<<webbrowser.openurl ("http://127.0.0.1:" + user.inetd.config.http.port + "/tmp.html")



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.