Thursday, March 31, 2011 at 1:05 AM.
river2Suite.viewJsonNews3
on viewJsonNews3 (adrcal=nil, version=3, adruser=nil) { <<Changes <<3/29/11; 5:40:49 PM by DW <<Respect the users' preference for max items on the home page. <<3/24/11; 1:02:48 PM by DW <<Call river2Suite.userFollows to determine if a user follows a feed. This also takes into account whether or not the feed was in a list. <<3/24/11; 11:00:50 AM by DW <<Fix bug where this script would fail if the user had no items visible in his river. <<3/24/11; 9:46:08 AM by DW <<Pass adrdata^.prefs.maxDaysNews to mainresponder.calendar.visitReverseChronologic to limit the number of days we're willing to go back in time. <<3/22/11; 5:22:16 PM by DW <<New optional param, adruser. If non-nil we use that address, instead of getting it out of the pagetable. Makes it possible for us to be called without having to set up a pagetable. <<2/13/11; 4:34:16 PM by DW <<Run text through xml.entityencode so that characters with high bits set are encoded. <<12/30/10; 2:23:06 PM by DW <<Rewrite of river2Suite.viewJsonNews to not use json.decompile, so we have better control of the JSON that's generated. This is the third version. <<12/18/10; 7:06:55 PM by DW <<New optional param, version, defaults to 1 -- the original format. In version 2, each "updatedFeed" has exactly one item it. You'll never see a list where an item could be. This means the info is repeated, so the file is a little fatter. You should still group updates from a single feed that happened at the same time. But now that grouping is not reflected in the structure. <<12/7/10; 10:15:28 AM by DW <<Add a docs value to the metadata section, pointing to a Scripting News article that explains what's going on here. <<12/5/10; 3:07:42 PM by DW <<Return a JSON representation of the news page. local (adrdata = river2suite.init (), startticks = clock.ticks (), maxitems); bundle { //set adruser if it's nil, 3/22/11 by DW if adruser == nil { try { local (pta = html.getpagetableaddress ()); adruser = pta^.adruser}}}; bundle { //set maxitems, 3/29/11 by DW maxitems = adrdata^.prefs.maxItemsHomePage; if adruser != nil { if adruser^.prefs.maxRiverItems < maxitems { maxitems = adruser^.prefs.maxRiverItems}}}; local (flhomepage = true, ct = 0, errorstring = "", flcache = true, jsontext = "", indentlevel = 0, lastFeedUrl, flFirstItemAtLevel, flAtLeastOneItem = false); on add (s) { <<if indentlevel < 0 <<indentlevel = 0 jsontext = jsontext + string.filledstring ("\t", indentlevel) + s + "\r"}; <<scratchpad.jsontext = jsontext //debugging on encode (s) { s = string.multiplereplaceall (s, @json.data.replaceTable); s = xml.entityencode (s); //2/13/11 by DW return (s)}; add ("{"); indentlevel++; add ("\"updatedFeeds\": {"); indentlevel++; add ("\"updatedFeed\": ["); indentlevel++; lastFeedUrl = ""; //force the first item to create a new updated feed table on visit (adritem) { if typeof (adritem^) != tabletype { //for processing podcasts and picture calender items local (name = nameof (adritem^)); local (adrday = mainresponder.calendar.getdayaddress (@adrdata^.river, adritem^)); adritem = @adrday^.[name]}; <<bundle //check type and flags, possibly return, 9/9/09 by DW <<if defined (adritem^.type) <<if flhomepage //9/15/09 by DW <<if not adrdata^.prefs.flPodcastsOnHomePage <<if adritem^.type.flPodcast <<return (true) <<if not adrdata^.prefs.flPhotosOnHomePage <<if adritem^.type.flPhoto <<return (true) bundle { //don't display items from feeds that have been unsubbed, 9/15/09 by DW if not defined (adrdata^.feeds.[adritem^.feedurl]) { //9/15/09 by DW return (true)}}; bundle { //display the item in a try, 1/2/10 by DW try { local (title = adritem^.title, feedurl = adritem^.feedurl, link, flTitleEndsWithPunc); local (flduplicatedescription = title == adritem^.description); //10/1/10 by DW bundle { //set flTitleEndsWithPunc, 5/20/10 by DW local (s = string.trimwhitespace (title), x = sizeof (s)); if x > 0 { local (ch = s [x]); flTitleEndsWithPunc = (ch == '!') or (ch == '?')} else { flTitleEndsWithPunc = false}}; local (itemnum = number (nameof (adritem^)), itemname = "item" + itemnum); local (namelink = "<a name=\"" + itemname + "\"></a>"); if adruser != nil { //12/2/09 by DW if not river2Suite.userFollows (adruser, feedurl) { //3/24/11 by DW return (true)}; }; <<if not defined (adruser^.feeds.[feedurl]) //user isn't following this feed <<return (true) local (adrfeed = @adrdata^.feeds.[feedurl]); if not defined (adrfeed^) { //8/17/09 by DW -- feed has been deleted return (true)}; bundle { //if feedurl changed, add a new "updatedFeed" if feedurl != lastfeedurl { local (adrfeedinfo = @adrfeed^.feedinfo); if lastfeedurl != "" { add ("]"); indentlevel--; add ("},"); indentlevel--}; add ("{"); indentlevel++; add ("\"feedUrl\": \"" + feedurl + "\","); add ("\"websiteUrl\": \"" + adrfeedinfo^.link + "\","); add ("\"feedTitle\": \"" + adrfeedinfo^.title + "\","); add ("\"whenLastUpdate\": \"" + date.netstandardstring (timeCreated (adritem)) + "\","); add ("\"item\": ["); indentlevel++; flFirstItemAtLevel = true; lastfeedurl = feedurl}}; bundle { //output one item bundle { //put out a comma if it's not the first item at this level if not flFirstItemAtLevel { add (",")}; flFirstItemAtLevel = false}; flAtLeastOneItem = true; //3/24/11 by DW add ("{"); indentlevel++; bundle { //add body if (not defined (adritem^.body)) or (not flcache) { if flduplicatedescription { //10/1/10 by DW adritem^.body = ""} else { adritem^.body = searchengine.stripmarkup (adritem^.description)}; if sizeof (adritem^.body) > adrdata^.prefs.maxBodyLength { adritem^.body = string.mid (adritem^.body, 1, adrdata^.prefs.maxBodyLength); while adritem^.body [sizeof (adritem^.body)] != " " { adritem^.body = string.delete (adritem^.body, sizeof (adritem^.body), 1)}; adritem^.body = string.delete (adritem^.body, sizeof (adritem^.body), 1); adritem^.body = adritem^.body + "..."}}; add ("\"body\": \"" + encode (adritem^.body) + "\",")}; add ("\"permaLink\": \"" + adritem^.permalink + "\","); add ("\"pubDate\": \"" + date.netstandardstring (adritem^.pubDate) + "\","); add ("\"title\": \"" + encode (adritem^.title) + "\","); add ("\"link\": \"" + adritem^.link + "\","); bundle { //comments if sizeof (adritem^.comments) > 0 { add ("\"comments\": \"" + adritem^.comments + "\",")}}; bundle { //enclosure if defined (adritem^.enclosure) { add ("\"enclosure\": ["); indentlevel++; add ("{"); indentlevel++; add ("\"url\": \"" + adritem^.enclosure.url + "\","); add ("\"type\": \"" + adritem^.enclosure.type + "\","); add ("\"length\": \"" + adritem^.enclosure.length + "\""); add ("}"); indentlevel--; add ("],"); indentlevel--}}; bundle { //thumbnail if defined (adritem^.thumbnail) { //9/7/09 by DW add ("\"thumbnail\": ["); indentlevel++; add ("{"); indentlevel++; add ("\"url\": \"" + adritem^.thumbnail.url + "\","); add ("\"width\": \"" + adritem^.thumbnail.width + "\","); add ("\"height\": \"" + adritem^.thumbnail.height + "\""); add ("}"); indentlevel--; add ("],"); indentlevel--}}; add ("\"id\": \"" + nameof (adritem^) + "\""); add ("}"); indentlevel--}} else { return (false)}}; return (++ct <= maxitems)}; if adrcal == nil { adrcal = @adrdata^.river}; mainresponder.calendar.visitReverseChronologic (adrcal, @visit, maxDays:adrdata^.prefs.maxDaysNews); if flAtLeastOneItem { //3/24/11 by DW add ("]"); indentlevel--; //close off last item list add ("}"); indentlevel--}; //close off last updatedFeed add ("]"); indentlevel--; //close off updatedFeed add ("},"); indentlevel--; //close off updatedFeeds bundle { //add metadata local (now = clock.now ()); add ("\"metadata\": {"); indentlevel++; add ("\"docs\": \"" + "http://scripting.com/stories/2010/12/06/innovationRiverOfNewsInJso.html" + "\","); add ("\"whenGMT\": \"" + date.netstandardstring (now) + "\","); add ("\"whenLocal\": \"" + now + " Eastern" + "\","); add ("\"version\": \"" + version + "\","); add ("\"secs\": \"" + string.formatdouble (double (clock.ticks () - startticks) / 60) + "\""); add ("}"); indentlevel--}; add ("}"); indentlevel--; <<wp.newtextobject (jsontext, @scratchpad.jsontext3) return (jsontext)}; bundle { //test code local (pt); new (tabletype, @pt); pt.adruser = nil; html.setpagetableaddress (@pt); local (tc = clock.ticks ()); viewJsonNews3 (adruser:@config.river2.users.adam); dialog.alert (clock.ticks () - tc)}
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.