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.