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

system.verbs.builtins.radio.html.viewNewsItems

on viewNewsItems (ctStoriesToList = user.radio.prefs.ctStoriesOnNewsPage) {
	<<Changes:
		<<9/20/04; 4:46:35 PM by SK
			<<Cleaned up some of the HTML and added new sort order preference.
		<<1/23/03; 11:45:46 AM by DW
			<<If the item has a permalink display it under the POST button.
		<<11/10/02; 1:02:01 PM by DW
			<<The <a name> element we were adding spanned the text in each item. This would, in some browsers, make the text be displayed hotted-up. Not good. Now we place the </a> element right after the <a name> element.
		<<10/18/02; 12:52:52 PM by JES
			<<Reduced the vertical space between the Post button and the comment icon. Added valign="top" to the table cells containing the item text.
		<<10/17/02; 5:20:53 PM by JES
			<<Comment links are now displayed as an icon below the Post button for items which have a comments link. Localized comment link tool-tip text.
		<<10/12/02; 4:07:09 AM by JES
			<<Localized the message saying there are no stories to list.
		<<6/29/02; 5:54:49 PM by JES
			<<Generate the globe icon in a try block. Prevents the news page from failing completely if a service doesn't have a channellink or channeldescription.
		<<5/13/02; 1:09:13 PM by JES
			<<Don't decode HTML entities when adding story text to the page. Entities have already been decoded when the aggregator did its scan.
		<<1/28/02; 6:27:56 PM by JES
			<<Convert line endings in news items to CR line endings, so auto-paragraph expansion will work as expected.
		<<1/25/02; 10:37:48 AM by DW
			<<Another optimization for the News Aggregator page. In the local "add" procedure, we parenthesize the text we're adding to htmltext, this triggers an ancient optimization in the kernel that doesn't do any handle copying on string assignments of the form x = x + s. Before parenthesizing average time was 104 ticks, after -- 45! More than double the speed. Worth doing.
		<<1/24/02; 6:19:18 PM by DW
			<<Tweak for performance. Uncached news page went from approx 220 ticks to approx 40 ticks. Thanks to Duncan Smeed for the trick to get add () to be so much faster. We'll surely use this in other places.
		<<1/9/02; 12:34:03 AM by JES
			<<Fixed a bug where the class="dwsTableCellHeader" was mistakenly added to the <tr/>'s for the headers, instead of being added to the <td/>'s.
		<<1/6/02; 4:00:15 AM by JES
			<<Added table css classes.
		<<12/19/01; 11:04:58 AM by JES
			<<If user.radio.prefs.flNewsPageReturnAfterPost is true, add the referer to the searchArgs on the link for the Post button. This causes the weblog post form to redirect back to the News page after posting an item.
		<<12/18/01; 3:43:14 PM by JES
			<<Don't add the referer to the searchArgs on the link for the Post button. This prevents you from being redirected back to the News page after posting an item.
		<<12/8/01; 11:56:49 AM by DW
			<<Intro text says "uncheck those you want to keep" if the preference is set to have checkboxes turned on by default. 
		<<12/1/01; 3:00:09 PM by JES
			<<Fixed a macro error when the user has hit the Back button after deleting a story, and tries to delete the story again. Added a Delete button to the bottom of the page. Decode entities and untaint channel titles and news items' text.
		<<11/24/01; 3:31:11 PM by DW
			<<Linked into help system.
		<<11/23/01; 4:41:15 PM by JES
			<<Changed user.radio.prefs.newsPageDeleteCheckboxesDefault to user.radio.prefs.flNewsPageDeleteCheckboxesDefault.
		<<11/21/01; 3:31:33 PM by JES
			<<Fixed macro error: "[Macro error: Can't find a sub-table named "system.verbs.builtins.radio.html.viewNewsItems".]", when deleting items while a scan is in progress.
				<<if defined (adrcache^)
					<<...references to adrincache^ are ok
		<<11/3/01; 10:51:00 PM by JES
			<<Fixed the url on the redirect searchArg, so that the page will load to the last-posted news item.
		<<10/22/01; 1:55:35 PM by JES
			<<Fixed a bug where news items could not be deleted because an address was improperly dereferenced.
		<<10/20/01; 12:38:03 AM by JES
			<<Added the menu searcharg to the mag-glass links, and to the redirect url for the Unsubscribe button, which appears on single-channel pages.
		<<8/14/01; 11:50:02 PM by JES
			<<If storyText is not defined for a given story, skip it. This averts "storyText hasn't been defined" errors.
		<<8/14/01; 1:58:42 AM by JES
			<<Add the post number to the path-part of the referer searchArg, so the page will reload to the same news item after posting.
		<<Archive:
			<<1/8/01; 8:53:17 AM by DW
				<<Added support for the viewStories cache.
			<<1/8/01; 10:55:56 AM by DW
				<<Factored calls to myUserLandSuite.images.imageRef.
			<<1/11/01; 4:40:45 PM by PBS
				<<If displaying a category page, add the attributes at the top. The title and description of the category can be edited. This is actually handled in another script: radio.html.editCategory
				<<Commented out some debugging code (a scratchpad reference) that had been left in place.
				<<If displaying a category page, use the displayName for the category.
				<<Make sure the title of the page changes when the category name has changed.
			<<1/12/01; 1:48:52 PM by PBS
				<<When editing a category, title and description appear at the end.
			<<1/13/01; 6:08:33 PM by DW
				<<Only show items with enclosures after the enclosure has been downloaded.
			<<1/19/01; 5:03:23 PM by DW
				<<Undo the last change, items with enclosures are visible. Items with enclosures have a media icon, if it's been downloaded, the icon points into the local file system, otherwise it points onto the Web. 
			<<1/21/01; 3:47:55 PM by DW
				<<Link the EDIT button to myBlog.wsf, instead of addRemove.wsf.
			<<1/24/01; 4:29:55 PM by DW
				<<Show a checkmark if the item has an adrBlogPost in its table.
			<<1/27/01; 5:01:03 PM by DW
				<<Change the EDIT button to POST.
			<<2/12/01; 4:21:06 PM by PBS
				<<Link title for the magnifying glass: "View all stories in the [channel title] channel."
			<<2/12/01; 4:34:35 PM by PBS
				<<Fixed bug where quotes and carets in a channel description would mess up rendering -- an example was Dave Winer: Two-Way Web, which has a description of You're soaking in it! ";->"
			<<2/12/01; 5:25:25 PM by PBS
				<<Terminology fix -- when viewing one channel, refer to it as a channel, not as a service.
				<<Also, use different text at the top of the page when viewing one channel, since the page is *not* showing you the recent stories from all the channels you're subscribed to.
				<<Skip empty stories.
			<<2/15/01; 2:49:58 PM by PBS
				<<Cleaned up. Mostly removed single-category stuff that was no longer used. Stories that are just images get displayed again.
			<<2/23/01; 10:55:23 AM by PBS
				<<Terminology: weblog, not blog.
			<<2/23/01; 4:04:47 PM by PBS
				<<Slight change to punctuation in the description at the top of the page.
			<<2/23/01; 10:53:19 PM by JES
				<<Linked the Post button to weblog.wsf, instead of myBlog.wsf.
			<<2/24/01; 9:40:04 PM by PBS
				<<Help link.
			<<2/24/01; 11:35:08 PM by JES
				<<Bug fix: the default cache was not deleted when deleting stories while viewing a single channel.
			<<2/24/01; 11:52:11 PM by JES
				<<Fixed cache deletion logic: When deleting an item via either the home page or a service page, delete both the default cache, and the service's cache.
			<<2/25/01; 1:31:32 PM by PBS
				<<Set up a second cache for when it's not the same machine.
			<<2/25/01; 2:26:50 PM by JES
				<<Separate cache for viewing single channels when it's not the same machine.
			<<3/4/01; 6:11:10 PM by JES
				<<Reality check: Don't add the magnifying glass if the service's table is not defined.
			<<3/5/01; 2:14:08 AM by JES
				<<Fixed bug where "default" is undefined when deleting a story while accessing the home page remotely.
	local (pta = html.getpagetableaddress ());
	<<scratchpad.params = pta^
	
	pta^.title = radio.string.getlocalizedstring ("aggregator.title");
	local (uri = pta^.uri);
	local (adrdata = xml.aggregator.init ());
	local (htmltext = "", indentlevel = 0);
	on add (s) {
		htmltext = htmltext + (string.filledstring ("\t", indentlevel) + s + "\r\n");};
	
	on decodeEntities (s) {
		s = string.replaceAll (s, "\r\n", "\r");
		s = string.replaceAll (s, "\n", "\r");
		return (radio.string.decodeEntities (s, flNeuterJavaScript:false))};
	
	local (flOneService = false, xmlUrl = "", adrservice);
	bundle { //parse args
		if defined (pta^.radioResponder.getArgs) {
			local (adrargs = @pta^.radioResponder.getArgs);
			if defined (adrargs^.xmlUrl) {
				flOneService = true;
				xmlurl = adrargs^.xmlUrl;
				adrservice = @adrdata^.services.[xmlurl];
				if defined (adrservice^.compilation.channeltitle) { //avoid errors for non-compliant channels
					add ("<b>Channel: " + decodeEntities (adrservice^.compilation.channeltitle) + "</b><p>");
					pta^.title = "Channel: " + decodeEntities (adrservice^.compilation.channeltitle)}}}};
	
	local (adrcache = @adrdata^.cache.[this], adrincache, defaultcachename = "default");
	if not defined (adrcache^) { //make sure the cache table is defined
		new (tabletype, adrcache)};
	bundle { //set adrincache
		if user.radio.prefs.flCacheNewsItemsPage {
			local (cachename = defaultcachename);
			if sizeof (xmlUrl) > 0 {
				cachename = xmlUrl};
			if not pta^.radioResponder.flSameMachine {
				cachename = cachename + "Remote"};
			adrincache = @adrcache^.[cachename]}};
	
	bundle { //catch post
		if pta^.method == "POST" {
			local (adrargs = @pta^.radioResponder.postArgs);
			<<scratchpad.args = args; edit (@scratchpad.args)
			if defined (adrargs^.formName) {
				if string.lower (adrargs^.formName) == "editstories" {
					delete (@adrargs^.formName);
					if defined (adrargs^.unsubscribe) {
						local (args);
						new (tabletype, @args);
						args.xmlUrl = xmlUrl;
						if defined (adrdata^.services.[xmlUrl]) {
							if defined (pta^.radioResponder.getArgs.menu) {
								args.menu = pta^.radioResponder.getArgs.menu};
							local (url = "unsubscribe?" + webserver.encodeargs (@args));
							radio.webServer.redirect (url);
							return ("")}};
					local (adrdefaultcache = @adrcache^.[defaultcachename]);
					for adrarg in adrargs {
						local (name = string.padwithzeros (number (nameof (adrarg^)), 8));
						local (adrstory = @adrdata^.stories.[name]);
						if defined (adrstory^) {
							adrdata^.trash.[name] = adrstory^;
							delete (adrstory)};
						if user.radio.prefs.flCacheNewsItemsPage {
							if defined (adrcache^) {
								if defined (adrincache^) { //posting invalidates the cache
									delete (adrincache)};
								if adrdefaultcache == adrincache { //02/24/2001 JES: delete the cache for the service
									if defined (adrstory^) {
										local (adrservicecache = @adrcache^.["xmlUrl=" + string.urlEncode (adrstory^.url)]);
										if defined (adrservicecache^) {
											delete (adrservicecache)}}}
								else { //02/24/2001 JES: we're on the service page -- delete the default cache
									if defined (adrdefaultcache^) {
										delete (adrdefaultcache)}}}}}}}}};
	
	bundle { //see if we can serve from the cache
		if defined (adrcache^) {
			if defined (adrincache^) {
				return (adrincache^)}}};
	
	local (globeimg, xmlimg, searchimg, checkmarkimg, mediaimg, commentimg, postbuttonimg, permalinkimg);
	bundle { //precalc img refs
		local (flSameMachine = pta^.radioResponder.flSameMachine);
		globeimg = radio.images.systemImageRef ("qbullet/remote", flFileUrl:flSameMachine);
		xmlimg = radio.images.systemImageRef ("icons/xml", flFileUrl:flSameMachine);
		searchimg = radio.images.systemImageRef ("qbullet/search", flFileUrl:flSameMachine);
		checkmarkimg = radio.images.systemImageRef ("icons/checkmark", flFileUrl:flSameMachine);
		postbuttonimg = radio.images.systemImageRef ("icons/post", flFileUrl:flSameMachine);
		mediaimg = radio.images.systemImageRef ("qbullet/sound", flFileUrl:flSameMachine);
		commentimg = radio.images.systemImageRef ("icons/pencil", flFileUrl:flSameMachine);
		permalinkimg = radio.images.systemImageRef ("icons/itemPermalink", flFileUrl:flSameMachine)};
	
	add ("<form method=\"POST\">"); indentlevel++;
	add ("<input type=\"hidden\" name=\"formname\" value=\"editStories\">"); //PBS  01/11/01: name the form, so the script doesn't try to process some other script's form
	add ("<table align=\"right\" cellspacing=\"0\" cellpadding=\"1\"><tr><td valign=\"top\">  <input type=\"submit\" value=\"" + radio.string.getlocalizedstring ("aggregator.delete") + "\"></td></tr></table>");
	bundle { //message at the top of the page
		if flOneService {
			local (t);
			new (tabletype, @t);
			t.channeltitle = decodeEntities (adrservice^.compilation.channeltitle);
			add (radio.string.getlocalizedstring ("aggregator.oneChannelMessage", @t))}
		else {
			local (t);
			new (tabletype, @t);
			t.subscriptionurl = radio.data.systemurls.subscriptionsList;
			add (radio.string.getlocalizedstring ("aggregator.standardMessage", @t))};
		add (radio.string.getlocalizedstring ("aggregator.clickThePostButton"));
		if user.radio.prefs.flNewsPageDeleteCheckboxesDefault {
			add (radio.string.getlocalizedstring ("aggregator.checkBoxesOnIntro"))}
		else {
			add (radio.string.getlocalizedstring ("aggregator.checkBoxesOffIntro"))};
		if flOneService {
			add (radio.string.getlocalizedstring ("aggregator.howToUnsubscribe"))};
		add (" " + radio.userinterface.helpLink ("The News Aggregator page"))};
	local (adrtable = @adrdata^.stories, sizetable = sizeof (adrtable^), i);
	add ("<br /><br />Total number of articles: "+sizetable);
	add ("<br /><br />");
	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++;
	local (lastchanneltitle = "", ctstories = 0);
	if user.radio.prefs.flNewsPageSortNewestFirst { //sort newest first
		for i = sizetable downto 1 {
			local (adritem = @adrdata^.stories [i]);
			bundle { //skip missing or empty stories
				if not defined (adritem^.storyText) { //skip this story -- this can happen if the scan is interrupted
					continue};
				if (string.trimWhiteSpace (searchEngine.stripMarkup (adrItem^.storyText)) == "") and (not (string.lower (adrItem^.storyText) contains "<img ")) { //PBS 02/12/01: skip empty stories
					continue}};
			if flOneService {
				local (flskip = true);
				if adritem^.url == xmlUrl {
					flskip = false};
				if flskip {
					continue}};
			<<bundle //only show items with enclosures after the enclosure has been downloaded
				<<if defined (adritem^.enclosure)
					<<if not defined (adritem^.enclosure.f)
						<<if string.lower (adritem^.url) != "local" //I want to see my local items with enclosures
							<<continue
			local (adrservice = @adrdata^.services.[adritem^.url]);
			if not defined (adrservice^) {
				continue};
			ctstories++;
			if ctstories > ctStoriesToList {
				break};
			if adritem^.channeltitle != lastchanneltitle { //display channel title
				local (globe = "");
				try { //link the globe to the HTML rendering of the channel
					with adrservice^.compilation {
						globe = "<a href=\"" + channellink + "\" title=\"" + radio.html.translateToEntities (channeldescription) + "\">" + globeimg + "</a>"}}; //PBS 02/12/01: fix bug where quotes and carets in a channel description would mess up rendering -- an example was Dave Winer: Two-Way Web, which has a description of You're soaking in it! ";->"
				local (xmllink);
				bundle { //link the XML icon to the source XML file for the channel
					xmllink = "<center><a href=\"" + adritem^.url + "\" title=\"" + radio.data.strings.xmltooltip + "\">" + xmlimg + "</a></center>"};
				local (magglass = "");
				bundle { //load up the magnifying glass with some HTML
					if not flOneService {
						local (url, args);
						new (tabletype, @args);
						args.xmlUrl = adritem^.url;
						if defined (pta^.radioResponder.getArgs.menu) {
							args.menu = pta^.radioResponder.getArgs.menu};
						url = "?" + webserver.encodeArgs (@args);
						magglass = " <a href=\"" + url + "\" title=\"View stories in the " + decodeEntities (adrItem^.channelTitle) + " channel.\">" + searchimg + "</a>"}};
				add ("<tr bgcolor=\"" + "#F5F5F5" + "\"><td class=\"dwsTableCellHeader\"> </td><td class=\"dwsTableCellHeader\"><b>" + globe + " " + decodeEntities (adrItem^.channelTitle) + ", " + adritem^.time + ".</b>" + magglass + "</td><td class=\"dwsTableCellHeader\" valign=\"bottom\">" + xmllink + "</td></tr>");
				lastchanneltitle = adritem^.channeltitle};
			bundle { //add story
				add ("<tr bgcolor=\"" + radio.data.htmlColors.cellbgcolor + "\">"); indentlevel++;
				bundle { //add checkbox
					local (name = number (nameof (adritem^)));
					local (checkboxval = "xxx ");
					if user.radio.prefs.flNewsPageDeleteCheckboxesDefault {
						checkboxval = checkboxval + "checked"};
					add ("<td class=\"dwsTableCell\" valign=\"top\"><input type=\"checkbox\" name=\"" + name + "\" value=" + checkboxval + "></td>")};
				
				add ("<td class=\"dwsTableCell\" valign=\"top\"><table><tr><td class=\"dwsTableCell\">  </td><td class=\"dwsTableCell\"><a name=\"" + i + "\"></a>" + adritem^.storytext + "</td></tr></table></td>");
				bundle { //add POST button, checkmark
					local (url);
					bundle { //set url
						local (args); new (tabletype, @args);
						if user.radio.prefs.flNewsPageReturnAfterPost { //add referer arg to redirect back to this item after posting it to your weblog
							if pta^.searchargs != "" {
								args.referer = uri + "?" + pta^.searchargs + "#" + i}
							else {
								args.referer = uri + "#" + i}};
						args.idStory = number (nameof (adritem^));
						url = radio.data.systemUrls.weblogEditor + "?" + webserver.encodeArgs (@args)};
					
					local (checkmark = "", enclosure = "", comments = "", permalink = "");
					bundle { //an item has a checkmark if it's been blogged
						if defined (adritem^.adrBlogPost) {
							checkmark = " <a title=\"This story has been blogged.\">" + checkmarkimg + "</a>"}};
					bundle { //if it has an enclosure add a media link
						if defined (adritem^.enclosure) {
							if not defined (adritem^.enclosure.error) {
								local (url);
								if defined (adritem^.enclosure.f) {
									url = html.getfileurl (adritem^.enclosure.f)}
								else {
									url = adritem^.enclosure.url};
								enclosure = " <a href=\"" + url + "\">" + mediaimg + "</a>"}}};
					bundle { //if it has comments add a comment link
						if defined (adritem^.comments) {
							local (onclick = "window.open (this.href, \'comments\', \'width=515, height=480, location=0, resizable=1, scrollbars=1, status=0, toolbar=0, directories=0\'); return(false);");
							local (tooltip = radio.string.getLocalizedString ("misc.clickToCommentOnThisPost"));
							comments = "<br/><a href=\"" + adritem^.comments + "\" onclick=\"" + onclick + "\" title=\"" + tooltip + "\">" + commentimg + "</a><br/>"}};
					bundle { //if it has permalink add a permalink link
						if defined (adritem^.permalink) {
							permalink = "<a href=\"" + adritem^.permalink + "\">" + permalinkimg + "</a>"}};
					
					local (icons = "");
					bundle { //set icons
						if (sizeof (checkmark) > 0) or (sizeof (enclosure) > 0) or (sizeof (permalink) > 0) or (sizeof (comments) > 0) {
							icons = "<p style=\"margin-top: 3px\">" + comments + checkmark + enclosure + permalink + "</p>"}};
					
					add ("<td class=\"dwsTableCell\" valign=\"top\"><center><a href=\"" + url + "\" title=\"Add this story to your weblog.\">" + postbuttonimg + "</a>" + icons + "</center></td>")};
				add ("</tr>"); indentlevel--}}}
	else { //sort oldest first
		for i = 1 to sizetable {
			local (adritem = @adrdata^.stories [i]);
			bundle { //skip missing or empty stories
				if not defined (adritem^.storyText) { //skip this story -- this can happen if the scan is interrupted
					continue};
				if (string.trimWhiteSpace (searchEngine.stripMarkup (adrItem^.storyText)) == "") and (not (string.lower (adrItem^.storyText) contains "<img ")) { //PBS 02/12/01: skip empty stories
					continue}};
			if flOneService {
				local (flskip = true);
				if adritem^.url == xmlUrl {
					flskip = false};
				if flskip {
					continue}};
			<<bundle //only show items with enclosures after the enclosure has been downloaded
				<<if defined (adritem^.enclosure)
					<<if not defined (adritem^.enclosure.f)
						<<if string.lower (adritem^.url) != "local" //I want to see my local items with enclosures
							<<continue
			local (adrservice = @adrdata^.services.[adritem^.url]);
			if not defined (adrservice^) {
				continue};
			ctstories++;
			if ctstories > ctStoriesToList {
				break};
			if adritem^.channeltitle != lastchanneltitle { //display channel title
				local (globe = "");
				try { //link the globe to the HTML rendering of the channel
					with adrservice^.compilation {
						globe = "<a href=\"" + channellink + "\" title=\"" + radio.html.translateToEntities (channeldescription) + "\">" + globeimg + "</a>"}}; //PBS 02/12/01: fix bug where quotes and carets in a channel description would mess up rendering -- an example was Dave Winer: Two-Way Web, which has a description of You're soaking in it! ";->"
				local (xmllink);
				bundle { //link the XML icon to the source XML file for the channel
					xmllink = "<center><a href=\"" + adritem^.url + "\" title=\"" + radio.data.strings.xmltooltip + "\">" + xmlimg + "</a></center>"};
				local (magglass = "");
				bundle { //load up the magnifying glass with some HTML
					if not flOneService {
						local (url, args);
						new (tabletype, @args);
						args.xmlUrl = adritem^.url;
						if defined (pta^.radioResponder.getArgs.menu) {
							args.menu = pta^.radioResponder.getArgs.menu};
						url = "?" + webserver.encodeArgs (@args);
						magglass = " <a href=\"" + url + "\" title=\"View stories in the " + decodeEntities (adrItem^.channelTitle) + " channel.\">" + searchimg + "</a>"}};
				add ("<tr bgcolor=\"" + "#F5F5F5" + "\"><td class=\"dwsTableCellHeader\"> </td><td class=\"dwsTableCellHeader\"><b>" + globe + " " + decodeEntities (adrItem^.channelTitle) + ", " + adritem^.time + ".</b>" + magglass + "</td><td class=\"dwsTableCellHeader\" valign=\"bottom\">" + xmllink + "</td></tr>");
				lastchanneltitle = adritem^.channeltitle};
			bundle { //add story
				add ("<tr bgcolor=\"" + radio.data.htmlColors.cellbgcolor + "\">"); indentlevel++;
				bundle { //add checkbox
					local (name = number (nameof (adritem^)));
					local (checkboxval = "xxx ");
					if user.radio.prefs.flNewsPageDeleteCheckboxesDefault {
						checkboxval = checkboxval + "checked"};
					add ("<td class=\"dwsTableCell\" valign=\"top\"><input type=\"checkbox\" name=\"" + name + "\" value=" + checkboxval + "></td>")};
				
				add ("<td class=\"dwsTableCell\" valign=\"top\"><table><tr><td class=\"dwsTableCell\">  </td><td class=\"dwsTableCell\"><a name=\"" + i + "\"></a>" + adritem^.storytext + "</td></tr></table></td>");
				bundle { //add POST button, checkmark
					local (url);
					bundle { //set url
						local (args); new (tabletype, @args);
						if user.radio.prefs.flNewsPageReturnAfterPost { //add referer arg to redirect back to this item after posting it to your weblog
							if pta^.searchargs != "" {
								args.referer = uri + "?" + pta^.searchargs + "#" + i}
							else {
								args.referer = uri + "#" + i}};
						args.idStory = number (nameof (adritem^));
						url = radio.data.systemUrls.weblogEditor + "?" + webserver.encodeArgs (@args)};
					
					local (checkmark = "", enclosure = "", comments = "", permalink = "");
					bundle { //an item has a checkmark if it's been blogged
						if defined (adritem^.adrBlogPost) {
							checkmark = " <a title=\"This story has been blogged.\">" + checkmarkimg + "</a>"}};
					bundle { //if it has an enclosure add a media link
						if defined (adritem^.enclosure) {
							if not defined (adritem^.enclosure.error) {
								local (url);
								if defined (adritem^.enclosure.f) {
									url = html.getfileurl (adritem^.enclosure.f)}
								else {
									url = adritem^.enclosure.url};
								enclosure = " <a href=\"" + url + "\">" + mediaimg + "</a>"}}};
					bundle { //if it has comments add a comment link
						if defined (adritem^.comments) {
							local (onclick = "window.open (this.href, \'comments\', \'width=515, height=480, location=0, resizable=1, scrollbars=1, status=0, toolbar=0, directories=0\'); return(false);");
							local (tooltip = radio.string.getLocalizedString ("misc.clickToCommentOnThisPost"));
							comments = "<br/><a href=\"" + adritem^.comments + "\" onclick=\"" + onclick + "\" title=\"" + tooltip + "\">" + commentimg + "</a><br/>"}};
					bundle { //if it has permalink add a permalink link
						if defined (adritem^.permalink) {
							permalink = "<a href=\"" + adritem^.permalink + "\">" + permalinkimg + "</a>"}};
					
					local (icons = "");
					bundle { //set icons
						if (sizeof (checkmark) > 0) or (sizeof (enclosure) > 0) or (sizeof (permalink) > 0) or (sizeof (comments) > 0) {
							icons = "<p style=\"margin-top: 3px\">" + comments + checkmark + enclosure + permalink + "</p>"}};
					
					add ("<td class=\"dwsTableCell\" valign=\"top\"><center><a href=\"" + url + "\" title=\"Add this story to your weblog.\">" + postbuttonimg + "</a>" + icons + "</center></td>")};
				add ("</tr>"); indentlevel--}}};
	if ctstories == 0 {
		add ("<tr bgcolor=\"" + radio.data.htmlColors.cellbgcolor + "\"><td class=\"dwsTableCell\">" + radio.string.getLocalizedString ("viewNewsItems.noStories") + "</td></tr>")};
	add ("</table>"); indentlevel--;
	add ("</table>"); indentlevel--;
	local (flDeleteButtonAdded = false);
	if flOneService {
		if defined (adrservice^) {
			add ("<p align=\"right\"><input type=\"submit\" name=\"unsubscribe\" value=\"" + radio.string.getlocalizedstring ("aggregator.unsubscribeButton") + "\">  <input type=\"submit\" value=\"" + radio.string.getlocalizedstring ("aggregator.delete") + "\"></p>");
			flDeleteButtonAdded = true}};
	if not flDeleteButtonAdded {
		add ("<p align=\"right\"><input type=\"submit\" value=\"" + radio.string.getlocalizedstring ("aggregator.delete") + "\"></p>")};
	add ("</form>"); indentlevel--;
	
	if user.radio.prefs.flCacheNewsItemsPage {
		adrincache^ = htmltext};
	return (htmltext)}
<<bundle //test code
	<<try {delete (@aggregatorData.cache.["system.verbs.builtins.radio.html.viewNewsItems"])}
	<<local (pagetable = scratchpad.params)
	<<html.setPageTableAddress (@pagetable)
	<<local (tc = clock.ticks ())
	<<viewNewsItems ()
	<<dialog.alert (clock.ticks () - tc)
	<<html.deletePageTableAddress ()
<<bundle //more test code
	<<local (pagetable)
	<<new (tabletype, @pagetable)
	<<pagetable.method = "GET"
	<<pagetable.flsamemachine = true
	<<pagetable.searchargs = ""
	<<html.setpagetableaddress (@pagetable)
	<<viewNewsItems ()



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.