Tuesday, August 18, 2009 at 7:34 PM.

newsRiverSuite.viewNewsItems

on viewNewsItems (adrargs=nil, ctStoriesToList=nil, adrcallback=nil, flPostButton=false) {
	<<Changes:
		<<4/25/09; 1:39:29 PM by DW
			<<Hmmm. We had code for a cache here, but it was commented out. I want it, so I uncommented. Let's see what problems come up. (Haven't released the changes.)
			<<The cache-tossing code is in newsRiverSuite.updateAfterScan, unreleased.
		<<3/11/09; 11:49:37 AM by DW
			<<New optional parameter, flPostButton, allows the caller to ask for it, even if the 8/17/08 conditions aren't met. NewsJunk needs this.
		<<8/17/08; 10:24:27 AM by DW
			<<Converted to use newsRiverSuite.imageRef instead of the one in dotOpml.root. The POST button appears conditionally, only present if dotOpmlSuite is defined, which is what its implementation depends on.
		<<5/26/08; 7:39:28 PM by DW
			<<The labels were derived from the index of the item in the stories table. But this can change while the user is viewing the page. Must use the name of the item instead, which is fixed.
		<<5/25/08; 10:56:49 AM by DW
			<<We were generating name elements that begin with numeric characters, which is not legal HTML. Add an "a" in front of each name, and reference to the name.
		<<5/24/08; 6:42:48 PM by DW
			<<Added a callback, takes one param, the address of a story; if the callback returns true, we include the story in the view. 
		<<8/26/06; 4:34:56 PM by DW
			<<Support for eliminating duplicates.
		<<8/26/06; 6:18:54 AM by DW
			<<Added a pref, cleanStoryText (defaults false). If true, we strip out Feedburner junk from each story.
		<<10/16/05; 10:58:30 AM by DW
			<<Began work on this code after a long hiatus. 
			<<Make it work inside the OPML Editor.
	local (pta = html.getpagetableaddress ());
	<<scratchpad.newsparams = pta^
	
	pta^.title = newsRiverSuite.getString ("aggregator.title");
	local (uri = pta^.uri);
	local (adrdata = newsRiverSuite.init ());
	if ctStoriesToList == nil {
		ctStoriesToList = adrdata^.newsRiver.ctStoriesOnNewsPage};
	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 (newsRiverSuite.decodeEntities (s, flNeuterJavaScript:false))};
	
	local (flOneService = false, xmlUrl = "", adrservice);
	bundle { //parse args
		local (args);
		new (tabletype, @args);
		webserver.parseArgs (pta^.searchArgs, @args);
		if defined (args.xmlUrl) {
			flOneService = true;
			xmlurl = args.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 adrdata^.newsRiver.flCacheNewsItemsPage {
			local (cachename = defaultcachename);
			if sizeof (xmlUrl) > 0 {
				cachename = xmlUrl};
			adrincache = @adrcache^.[cachename]}};
	
	bundle { //catch post
		if pta^.method == "POST" {
			local (args);
			new (tabletype, @args);
			webserver.parseArgs (pta^.requestBody, @args);
			<<scratchpad.args = args; edit (@scratchpad.args)
			if defined (args.formName) {
				if string.lower (args.formName) == "editstories" {
					delete (@args.formName);
					if defined (args.unsubscribe) {
						local (args);
						new (tabletype, @args);
						args.xmlUrl = xmlUrl;
						if defined (adrdata^.services.[xmlUrl]) {
							adrargs^.redirect = newsRiverData.systemUrls.unsub + "?" + webserver.encodeargs (@args);
							return ("")}};
					local (adrdefaultcache = @adrcache^.[defaultcachename]);
					for adrarg in @args {
						try {
							local (name = string.padwithzeros (number (nameof (adrarg^)), 8));
							local (adrstory = @adrdata^.stories.[name]);
							if defined (adrstory^) {
								adrdata^.trash.[name] = adrstory^;
								delete (adrstory)};
							if adrdata^.newsRiver.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, uncommented 4/25/09 by DW
		if defined (adrcache^) {
			if defined (adrincache^) {
				return (adrincache^)}}};
	
	local (globeimg, xmlimg, searchimg, checkmarkimg, mediaimg, commentimg, postbuttonimg, permalinkimg);
	bundle { //precalc img refs
		globeimg = newsRiverSuite.imageRef ("newsRiver/qbullet/remote");
		xmlimg = newsRiverSuite.imageRef ("newsRiver/icons/xml");
		searchimg = newsRiverSuite.imageRef ("newsRiver/qbullet/search");
		checkmarkimg = newsRiverSuite.imageRef ("newsRiver/icons/checkmark");
		postbuttonimg = newsRiverSuite.imageRef ("newsRiver/icons/post");
		mediaimg = newsRiverSuite.imageRef ("newsRiver/qbullet/sound");
		commentimg = newsRiverSuite.imageRef ("newsRiver/icons/pencil");
		permalinkimg = newsRiverSuite.imageRef ("newsRiver/icons/itemPermalink")};
	
	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=\"" + newsRiverSuite.getString ("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 (newsRiverSuite.getString ("aggregator.oneChannelMessage", @t));
			pta^.title = t.channeltitle}
		else {
			local (t);
			new (tabletype, @t);
			t.subscriptionurl = newsRiverData.systemUrls.subscriptionList;
			add (newsRiverSuite.getString ("aggregator.standardMessage", @t))};
		add (newsRiverSuite.getString ("aggregator.clickThePostButton"));
		if adrdata^.newsRiver.flNewsPageDeleteCheckboxesDefault {
			add (newsRiverSuite.getString ("aggregator.checkBoxesOnIntro"))}
		else {
			add (newsRiverSuite.getString ("aggregator.checkBoxesOffIntro"))};
		if flOneService {
			add (newsRiverSuite.getString ("aggregator.howToUnsubscribe"))}};
	local (adrtable = @adrdata^.stories, sizetable = sizeof (adrtable^), i);
	local (urlstable); new (tabletype, @urlstable);
	add ("<table class=\"dwsFrameTable\" cellspacing=\"0\" cellpadding=\"0\"><tr bgcolor=\"" + newsRiverData.htmlColors.framecolor + "\"><td>"); indentlevel++;
	add ("<table class=\"dwsTable\" border=\"0\" cellspacing=\"1\" cellpadding=\"5\">" ); indentlevel++;
	local (lastchanneltitle = "", ctstories = 0);
	bundle { //loop over the news items
		for i = sizetable downto 1 {
			local (adritem = @adrdata^.stories [i], nameitem = nameof (adritem^));
			bundle { //skip duplicate stories
				if adrdata^.newsRiver.flEliminateDuplicateStories {
					if newsRiverSuite.eliminateDuplicates (adritem, @urlstable) {
						continue}}};
				<<old code
					<<An interesting story here...
						<<You might think that a guid or a permalink would be the same even if the story appeared in different departments, but apparently not.
						<<What to do? Well, headline writers tend to be creative, but they don't come up with different headlines when a story appears in more than one feed, so I tried using that as the guid, it worked. 
						<<Now if two headline writers for different pubs use exactly the same headline, we'll have a problem...
						<<8/23/06; 6:34:45 AM by DW
					<<local (guid = "")
					<<if defined (adritem^.data.title)
						<<guid = adritem^.data.title
					<<else
						<<if defined (adritem^.permalink)
							<<guid = adritem^.permalink
						<<else
							<<if defined (adritem^.guid)
								<<guid = adritem^.guid
					<<if sizeof (guid) > 0
						<<local (adr = @urlstable.[guid])
						<<if defined (adr^) //duplicate
							<<adr^++
							<<continue
						<<adr^ = 1
					<<if defined (adritem^.url)
						<<if (adritem^.url beginswith "http://www.nytimes.com") or (adritem^.url beginswith "http://newsrss.bbc.co.uk") or (adritem^.url contains "http://news.com.com")
							<<local (s = adritem^.storytext, ix)
							<<ix = string.patternmatch ('"', s)
							<<s = string.delete (s, 1, ix) //pop off everything before the first url
							<<ix = string.patternmatch ('"', s)
							<<s = string.mid (s, 1, ix-1)
							<<local (adr = @urlstable.[s])
							<<if defined (adr^) //duplicate
								<<adr^++
								<<continue
							<<adr^ = 1
			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 { //check with callback, if defined, 5/24/08 by DW
				if adrcallback != nil {
					try {
						if not adrcallback^ (adritem) {
							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 {
						local (desc = searchengine.stripmarkup (channeldescription));
						globe = "<a href=\"" + channellink + "\" title=\"" + newsRiverSuite.translateToEntities (desc) + "\">" + 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=\"" + newsRiverData.english.strings.misc.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;
						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=\"" + newsRiverData.htmlColors.cellBgColor + "\">"); indentlevel++;
				bundle { //add checkbox
					local (checkboxtext = " ");
					if adrdata^.newsRiver.flItemCheckboxes {
						local (name = number (nameitem));
						local (checkboxval = "xxx ");
						if adrdata^.newsRiver.flNewsPageDeleteCheckboxesDefault {
							checkboxval = checkboxval + "checked"};
						checkboxtext = "<input type=\"checkbox\" name=\"" + name + "\" value=" + checkboxval + ">"};
					
					add ("<td class=\"dwsTableCell\" valign=\"top\">" + checkboxtext + "</td>")};
				
				local (storytext);
				bundle { //get storytext, 8/26/06; 6:14:56 AM by DW
					if adrdata^.newsRiver.flCleanStoryText { //remove Feedburner web bugs, maybe other stuff later
						storytext = newsRiverSuite.cleanStoryText (adritem^.storytext)}
					else {
						storytext = adritem^.storytext};
					};
				add ("<td class=\"dwsTableCell\" valign=\"top\"><table><tr><td class=\"dwsTableCell\">  </td><td class=\"dwsTableCell\"><a name=\"a" + nameitem + "\"></a>" + string (storytext) + "</td></tr></table></td>");
				bundle { //add POST button, checkmark
					local (url);
					bundle { //set url
						local (args); new (tabletype, @args);
						if adrdata^.newsRiver.flNewsPageReturnAfterPost { //add referer arg to redirect back to this item after posting it to your weblog
							if pta^.searchargs != "" {
								args.referer = uri + "?" + pta^.searchargs + "#a" + nameitem}
							else {
								args.referer = uri + "#a" + nameitem}};
						args.idStory = number (nameitem);
						url = newsRiverData.systemUrls.postToWeblog + "?" + 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 = newsRiverSuite.getString ("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 = "", postbutton = "");
					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>"}};
					bundle { //set postbutton, 8/17/08 by DW, 3/11/09 by DW
						if defined (dotOpmlSuite) or flPostButton {
							postbutton = "<a href=\"" + url + "\" title=\"Add this story to your weblog.\">" + postbuttonimg + "</a>"}};
					add ("<td class=\"dwsTableCell\" valign=\"top\"><center>" + postbutton + icons + "</center></td>")};
				add ("</tr>"); indentlevel--}}};
	if ctstories == 0 {
		add ("<tr bgcolor=\"" + newsRiverData.htmlColors.cellBgColor + "\"><td class=\"dwsTableCell\">" + newsRiverSuite.getString ("aggregator.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=\"" + "Unsubscribe" + "\">  <input type=\"submit\" value=\"" + "Delete" + "\"></p>");
			flDeleteButtonAdded = true}};
	if not flDeleteButtonAdded {
		add ("<p align=\"right\"><input type=\"submit\" value=\"" + "Delete" + "\"></p>")};
	add ("</form>"); indentlevel--;
	
	if adrdata^.newsRiver.flCacheNewsItemsPage {
		adrincache^ = htmltext};
	<<scratchpad.urlstable = urlstable
	return (htmltext)};
bundle { //test code
	html.setpagetableaddress (@scratchpad.newsparams);
	webbrowser.displaytext (viewNewsItems ());
	webbrowser.bringtofront ()}



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.