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

system.verbs.builtins.radio.macros.weblogRecentPosts

on weblogRecentPosts (adrdata=radio.weblog.init (), bgColor=radio.data.htmlColors.cellBgColor, hilightBgColor=radio.data.htmlColors.highlightColor, catname=nil) {
	<<Changes:
		<<11/5/02; 1:23:20 AM by JES
			<<Reversed the last change.
		<<10/28/02; 7:38:13 PM by JES
			<<Call html.processMacros with plainprocessing as true to prevent extra paragraph tags.
		<<10/12/02; 2:48:51 AM by JES
			<<Localized the header and delete button text.
		<<3/11/02; 8:57:40 AM by DW
			<<When displaying a recent post, use the title and link info, if it's available.
		<<2/13/02; 3:42:48 PM by JES
			<<Update relevant category RSS files, when post(s) are deleted. Don't update the main weblog archive pages when a post's flNotOnHomePage is true.
		<<2/10/02; 11:09:58 PM by JES
			<<Fixed a bug where when deleting a post from an archive page, the post would be deleted, but the public site would not be updated, and a macro error would appear when the browser reloads the page in the desktop website.
		<<2/10/02; 10:39:17 PM by JES
			<<Fixed a bug where archive pages would limit the number of posts displayed to the same number displayed on the home page, which could prevent editing of some items.
		<<2/5/02; 5:04:08 PM by JES
			<<Fixed a bug where navigating to previous posts using the calendar on the desktop website home page, would not display previous posts.
		<<2/4/02; 2:54:47 PM by JES
			<<Added an optional parameter, catname. If specified, only posts in the specified category will be listed.
		<<1/25/02; 1:26:05 PM by JES
			<<Applied the same optimization to add() that was applied to radio.html.viewNewsItems. Before, this script took 84 ticks. After this change, it takes 29 ticks -- more than twice as fast.
		<<1/19/02; 9:11:26 PM by JES
			<<Make sure that adrpost^.when is defined. If not, set it to when for a surrounding post if possible, or to clock.now if there are no other posts.
		<<1/15/02; 2:08:58 PM by DW
			<<Call callbacks in user.radio.callbacks.deleteItem.
			<<http://radio.userland.com/stories/storyReader$7740#userradiocallbacksdeleteitem
		<<1/9/02; 12:18:21 AM by JES
			<<Add a searchArg, uid, whose value is number (clock.now ()) -- to act as a browser cache confuser. This prevents the browser from loading up an old, cached version of a previously edited post, when clicking the Edit button a second time.
		<<1/6/02; 4:30:49 AM by JES
			<<Added table css classes.
		<<11/30/01; 12:32:04 PM by JES
			<<Convert line-endings in htmltext to \r, before returning.
		<<11/29/01; 5:50:39 PM by JES
			<<When a post is deleted, remove it from the storyList in all categories which include it.
		<<11/23/01; 9:53:05 PM by DW
			<<It's help support was archaic. Modernized.
		<<11/23/01; 9:47:05 PM by JES
			<<Call html.processMacros on the returned htmltext.
		<<11/14/01; 11:08:52 PM by JES
			<<Rewrote the post-handling code, which deletes posts and updates the relevant pages. Return the empty string for dynamic pages, which aren't the home page.
		<<10/29/01; 4:47:17 PM by JES
			<<Added optional parameters: bgColor and hilightBgColor.
		<<10/27/01; 9:08:01 AM by DW
			<<If static rendering, return the empty string.
		<<8/31/01; 8:38:06 PM by JES
			<<Factored from radio.weblog.main.
			<<Preserve the menu and d getArgs so that we stay on the same archive page, and menu mode when clicking an EDIT button.
	
	local (pta = html.getPageTableAddress ());
	<<scratchpad.pagetable = pta^; edit (@scratchpad.pagetable) //debugging code
	
	bundle { //if static rendering, return the empty string
		if pta^.radioResponder.flStaticRendering {
			return ("")}};
	bundle { //if not the weblog editor page, return the empty string
		if not pta^.radioResponder.flStaticRendering {
			if pta^.path != radio.data.systemUrls.weblogEditor {
				if not (string.lower (pta^.path) beginsWith string.lower (radio.data.systemUrls.newCategory)) {
					return ("")}}}};
	
	local (htmltext, indentlevel=0);
	on add (s) {
		htmltext = htmltext + (string.filledstring ("\t", indentlevel) + s + "\r\n");};
	
	local (d = clock.now (), flArchivePage = false, dateArg); //PBS 02/22/01: archive page support
	local (editbuttonimg = radio.images.systemImageRef ("icons/editbutton"));
	local (globeimg = radio.images.systemImageRef ("qbullet/remote"));
	local (xmlimg = radio.images.systemImageRef ("icons/xml"));
	local (mediaimg = radio.images.systemImageRef ("qbullet/sound"));
	local (checkmarkimg = radio.images.systemImageRef ("icons/checkmark"));
	
	local (helpurl = radio.userinterface.helpurl ("Previous Posts"));
	
	if pta^.method == "POST" {
		local (adrargs = @pta^.radioResponder.postArgs);
		if defined (adrargs^) {
			if defined (adrargs^.deletePosts) {
				delete (@adrargs^.deletePosts);
				local (postsToDelete); new (tableType, @postsToDelete);
				local (adr, adrpost);
				for adr in adrargs { //build a table containing addresses of posts to delete
					on isPostId (s) {
						try {
							local (id = number (s));
							return (defined (adrdata^.posts.[string.padWithZeros (id, 8)]))};
						return (false)};
					if isPostId (nameOf (adr^)) {
						local (adritem = table.uniqueName ("post", @postsToDelete, 8));
						adritem^ = @adrdata^.posts.[string.padwithzeros (nameof (adr^), 8)]}};
				local (flUpdateHomePage = false, datesToUpdate = {});
				local (catsToUpdate); new (tableType, @catsToUpdate);
				for adr in @postsToDelete { //go through all the posts, figure out which pages to update, deleting posts as we go
					adrpost = adr^; local (theDate);
					bundle { //get theDate
						local (day, month, year, hour, minute, second);
						date.get (adrpost^.when, @day, @month, @year, @hour, @minute, @second);
						theDate = date.set (day, month, year, 0, 0, 0)};
					if not flUpdateHomePage { //if flUpdateHome page is true, we already know we need to update
						if radio.weblog.isPostOnHomePage (adrpost) {
							flUpdateHomePage = true}};
					if not (datesToUpdate contains theDate) { //keep a list of archive dates to re-render
						if not adrpost^.flNotOnHomePage {
							datesToUpdate = datesToUpdate + theDate}};
					if defined (adrpost^.categories) { //go through categories and figure out what needs updating
						local (ixcat, sizecats = sizeOf (adrpost^.categories));
						for ixcat = 1 to sizecats {
							if adrpost^.categories[ixcat] { //a hit
								local (catname = nameOf (adrpost^.categories[ixcat]));
								local (adrcat = @adrdata^.categories.[catname]);
								if defined (adrcat^) {
									adrcat^.storyList = adrcat^.storyList - {number (nameOf (adrpost^))}};
								if not defined (catsToUpdate.[catname]) { //init our temp data
									new (tableType, @catsToUpdate.[catname]);
									catsToUpdate.[catname].flUpdateIndexPage = false;
									catsToUpdate.[catname].datesToUpdate = {}};
								if not catsToUpdate.[catname].flUpdateIndexPage { //is this post in the cat's index page?
									if radio.weblog.isPostOnHomePage (adrpost, catname) {
										catsToUpdate.[catname].flUpdateIndexPage = true}};
								if not (catsToUpdate.[catname].datesToUpdate contains theDate) { //the cat's archive page
									catsToUpdate.[catname].datesToUpdate = catsToUpdate.[catname].datesToUpdate + theDate}}}};
					bundle { //call the callbacks -- 1/15/02; 2:08:29 PM by DW
						try {
							if not defined (user.radio.callbacks.deleteItem) {
								new (tabletype, @user.radio.callbacks.deleteItem)};
							local (adrcallback);
							for adrcallback in @user.radio.callbacks.deleteItem {
								try {
									while typeOf (adrcallback^) == addressType {
										adrcallback = adrcallback^};
									adrcallback^ (adrpost)}}}};
					delete (adrpost)};
				bundle { //update all the pages
					local (dateToUpdate, adrCatToUpdate);
					if flUpdateHomePage { //update the weblog home page
						radio.weblog.publish (adrdata);
						thread.callScript (@radio.weblog.publishRss, {adrdata})};
					for dateToUpdate in datesToUpdate { //update weblog archive pages
						radio.weblog.publish (adrdata, d:dateToUpdate)};
					for adrCatToUpdate in @catsToUpdate { //update all the category pages
						local (catname = nameOf (adrCatToUpdate^), flUpdateRss = false);
						if adrCatToUpdate^.flUpdateIndexPage {
							radio.weblog.publish (adrdata, catname);
							flUpdateRss = true};
						for dateToUpdate in adrCatToUpdate^.datesToUpdate {
							radio.weblog.publish (adrdata, catname, dateToUpdate);
							flUpdateRss = true};
						if flUpdateRss {
							local (adrcat = @adrdata^.categories.[catname]);
							adrcat^.flDirty = true}}}}}};
				<<bundle //old code
					<<local (adr, adrpost, deletedPostDates = {}, deletedPostDate)
					<<for adr in adrargs
						<<adrpost = @adrdata^.posts.[string.padwithzeros (nameof (adr^), 8)]
						<<if defined (adrpost^)
							<<local (adrcats = @adrpost^.categories)
							<<if defined (adrcats^)
								<<local (adr)
								<<local (id = number (nameof (adrpost^)))
								<<for adr in @adrdata^.categories
									<<if adr^.storyList contains id
										<<adr^.storyList = adr^.storyList - {id}
										<<adr^.flDirty = true
								<<delete (adrcats)
							<<bundle //add the date for this post to the deletedPostDates list
								<<local (day, month, year, hour, minute, second)
								<<date.get (adrpost^.when, @day, @month, @year, @hour, @minute, @second)
								<<deletedPostDate = date.set (day, month, year, 0, 0, 0)
								<<if not (deletedPostDates contains deletedPostDate)
									<<deletedPostDates = deletedPostDates + deletedPostDate
							<<delete (adrpost)
					<<bundle //publish home page and archive pages in their own threads
						<<local (flPublishHomePage = false)
						<<for deletedPostDate in deletedPostDates
							<<if radio.weblog.isDateOnHomePage (deletedPostDate)
								<<flPublishHomePage = true
						<<if flPublishHomePage
							<<radio.weblog.publish (adrdata)
						<<for deletedPostDate in deletedPostDates
							<<local (day, month, year, hour, minute, second)
							<<date.get (deletedPostDate, @day, @month, @year, @hour, @minute, @second)
							<<local (maxDate = date.set (day, month, year, 23, 59, 59))
							<<thread.callScript (@radio.weblog.publishStaticPage, {adrdata, nil, 1, maxDate, deletedPostDate, false})
	
	local (adrPostToEdit);
	bundle { //process GET args
		local (adrargs = @pta^.radioResponder.getArgs);
		if defined (adrargs^) {
			if defined (adrargs^.d) { //PBS 02/22/01: archive page, possibly
				flArchivePage = true;
				local (year = string.nthField (adrargs^.d, '/', 1));
				local (month = string.nthField (adrargs^.d, '/', 2));
				local (day = string.nthField (adrargs^.d, '/', 3));
				d = date.set (day, month, year, 0, 0, 0);
				dateArg = year + "/" + string.padWithZeros (month, 2) + "/" + string.padWithZeros (day, 2);
				bundle { //check d against midnight of the day with the last post
					local (midnightMostRecentDay);
					local (adrLastPost = @adrdata^.posts [sizeOf (adrdata^.posts)]);
					local (day, month, year, hour, minute, second);
					date.get (adrLastPost^.when, @day, @month, @year, @hour, @minute, @second);
					midnightMostRecentDay = date.set (day, month, year, 0, 0, 0);
					if d >= midnightMostRecentDay {
						flArchivePage = false}}};
			if defined (adrargs^.itemToEdit) {
				adrPostToEdit = @adrdata^.posts.[string.padWithZeros (adrargs^.itemToEdit, 8)]}}};
	
	bundle { //add the posts
		local (ctposts = sizeof (adrdata^.posts));
		if ctposts > 0 {
			add ("<br>");
			add ("<form method=\"POST\" action=\"" + radio.data.systemUrls.weblogEditor + "\">"); indentlevel++;
			if flArchivePage {
				add ("<input type=\"hidden\" name=\"d\" value=\"" + dateArg + "\">")};
			add ("<table class=\"dwsFrameTable\" cellspacing=\"0\" cellpadding=\"0\"><tr bgcolor=\"" + radio.data.htmlColors.framecolor + "\"><td>"); indentlevel++;
			add ("<table class=\"dwsTable\" border=\"0\" cellspacing=\"1\" cellpadding=\"5\">"); indentlevel++;
			if flArchivePage {
				local (t); new (tabletype, @t);
				t.day = date.shortString (d);
				add (radio.html.prefsElement.separator (radio.string.getLocalizedString ("homePage.postsForDate", @t), false, 4, helpUrl))}
				<<"Posts for " + date.shortString (d) + "..."
			else {
				local (t); new (tabletype, @t);
				t.numposts = adrdata^.prefs.viewing.ctPosts;
				add (radio.html.prefsElement.separator (radio.string.getLocalizedString ("homePage.previousNPosts", @t), false, 4, helpUrl))};
				<<"Previous " + adrdata^.prefs.viewing.ctPosts + " posts..."
			local (ctlisted = 0);
			case adrdata^.prefs.viewing.mode {
				"byPosts" {
					local (adrpost, editurl, cellBgColor);
					<<local (lastitemnum = ctposts - adrdata^.prefs.viewing.ctPosts + 1)
					<<if lastitemnum < 1
						<<lastitemnum = 1
					<<local (start = ctposts, end = lastitemnum)
					local (i = ctposts);
					if flArchivePage {
						local (day, month, year, hour, minute, second);
						date.get (d, @day, @month, @year, @hour, @minute, @second);
						<<bundle //obsolete code
							<<local (adrFirstPost)
							<<local (firstOfDay = date.set (day, month, year, 0, 0, 0))
							<<radio.weblog.getNextPostAfterDate (adrdata, firstOfDay, @adrFirstPost)
							<<end = indexOf (adrFirstPost^) //reverse chronological order
						local (adrLastPost);
						local (lastOfDay = date.set (day, month, year, 23, 59, 59));
						radio.weblog.getLastPostBeforeDate (adrdata, lastOfDay, @adrLastPost, catname);
						i = indexOf (adrLastPost^)};
					loop {
						if i < 1 {
							break};
						if not flArchivePage {
							if ctlisted >= adrdata^.prefs.viewing.ctPosts {
								break}};
						adrpost = @adrdata^.posts [i];
						if flArchivePage { //the home page -- end is a post table index, if an archive page
							if adrpost^.when < d {
								break}};
						if catname != nil {
							if not radio.weblog.isPostInCategory (adrpost, catname) {
								i--;
								continue}};
						if adrpost == adrPostToEdit {
							cellBgColor = hilightBgColor}
						else {
							cellBgColor = bgcolor};
						add ("<tr class=\"dwsTableCell\" bgcolor=\"" + cellBgColor + "\">"); indentlevel++;
						bundle { //add checkbox
							local (name = number (nameof (adrpost^)));
							local (checkboxval = "xxx ");
							if false {
								checkboxval = checkboxval + "checked"};
							add ("<td class=\"dwsTableCell\" valign=\"top\"><input type=\"checkbox\" name=\"" + name + "\" value=" + checkboxval + "></td>")};
						bundle { //add the post text
							local (posttext = string (adrpost^.text));
							if defined (adrpost^.title) {
								local (titletext = adrpost^.title);
								if defined (adrpost^.link) {
									titletext = "<a href=\"" + adrpost^.link + "\" class=\"weblogItemTitle\">" + titletext + "</a>"};
								posttext = titletext + ". " + posttext};
							add ("<td class=\"dwsTableCell\" valign=\"top\">" + posttext + "</td>")};
						bundle { //make sure that adrpost^.when is defined
							if not defined (adrpost^.when) {
								local (ix = indexOf (adrpost^));
								if ix > 1 {
									adrpost^.when = date (adrdata^.posts[ix - 1].when + 1)}
								else {
									if sizeOf (adrdata^.posts) > 1 {
										adrpost^.when = date (adrdata^.posts[ix + 1].when - 1)}
									else {
										adrpost^.when = clock.now ()}}}};
						add ("<td class=\"dwsTableCell\" valign=\"top\" nowrap><font size=\"-1\">" + radio.string.getDateString (adrpost^.when) + "</font></td>");
						bundle { //add little icons
							add ("<td class=\"dwsTableCell\" valign=\"top\" nowrap>"); indentlevel++;
							bundle { //EDIT button, checkmark, enclosure icons
								local (args);
								new (tabletype, @args);
								args.itemToEdit = number (nameof (adrpost^));
								args.uid = number (clock.now ());
								<<if defined (pta^.radioResponder.getArgs.menu)
									<<args.menu = pta^.radioResponder.getArgs.menu
								if flArchivePage {
									args.d = dateArg};
								<<editurl = pta^.uri + "?" + webserver.encodeargs (@args)
								editurl = radio.data.systemUrls.weblogEditor + "?" + webserver.encodeargs (@args);
								editurl = string.replaceAll (editurl, "%2F", "/");
								local (checkmark = "");
								bundle { //an item has a checkmark if it's in at least one category
									if defined (adrpost^.categories) {
										if sizeOf (adrpost^.categories) > 0 {
											local (adr);
											for adr in @adrpost^.categories {
												if adr^ {
													checkmark = " <a title=\"" + radio.data.strings.checkmarktooltip + "\">" + checkmarkimg + "</a>";
													break}}}}};
								local (encl = "");
								bundle { //if it has an enclosure add a media link
									if defined (adrpost^.enclosure) {
										if not defined (adrpost^.enclosure.error) {
											encl = "<br><a href=\"" + adrpost^.enclosure.url + "\">" + mediaimg + "</a>"}}};
								add ("<a href=\"" + editurl + "\">" + editbuttonimg + "</a>" + checkmark + encl)};
							add ("</td>"); indentlevel--};
						add ("</tr>"); indentlevel--;
						i--; ctlisted++}}};
			if ctlisted == 0 {
				return ("")};
			add ("</table>"); indentlevel--;
			add ("</td></tr></table>"); indentlevel--;
			local (deleteButtonText = radio.string.getLocalizedString ("buttons.delete"));
			add ("<p><input type=\"submit\" name=\"deletePosts\" value=\"" + deleteButtonText + "\"></p>");
			add ("</form>"); indentlevel--}};
	bundle { //start the form
		local (actionString = "");
		if defined (pta^.radioResponder.getArgs) {
			if sizeOf (pta^.radioResponder.getArgs) > 0 {
				actionString = " action=\"" + pta^.uri + "?" + webserver.encodeArgs (@pta^.radioResponder.getArgs) + "\""}};
		add ("<form method=\"POST\"" + actionString + ">"); indentlevel++};
	if flArchivePage {
		add ("<input type=\"hidden\" name=\"d\" value=\"" + dateArg + "\">")};
	
	add ("</form>"); indentlevel--;
	
	<<return (htmltext)
	htmltext = string.replaceAll (htmltext, "\r\n", "\r");
	return (html.processMacros (htmltext, false, adrPageTable:pta))}
<<bundle //testing
	<<local (params = scratchpad.pagetable)
	<<html.setPageTableAddress (@params)
	<<radio.macros.weblogRecentPosts ()
	<<html.deletePageTableAddress ()



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.