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.