Monday, November 08, 2010 at 12:03 AM.
system.verbs.builtins.html.data.standardMacros.opmlToBlogroll
on opmlToBlogroll (opmlUrl, flProcessMacros=true, cssPrefix="blogroll", cacheSeconds=60, flXmlButton=true, recentlyUpdatedLinkPrefix="", recentlyUpdatedLinkSuffix="") {
<<Changes
<<7/29/02; 2:06:22 AM by JES
<<New optional parameters, recentlyUpdatedLinkPrefix and recentlyUpdatedLinkSuffix, specify snippets of HTML text to prepend and append to links generated from OPML elements that have an isRecent attribute whose value is true.
<<Respect title and target attributes of outline elements if present, and include them in the link tag.
<<6/2/02; 3:18:11 PM by DW
<<Leave behind clues for the blogroll link.
<<http://radio.userland.com/radioMacrosHeadLinks
<<5/28/02; 2:25:05 PM by JES
<<New optional parameter, flXmlButton specifies whether to add an XML button after the links. Defaults to true.
<<5/22/02; 3:37:18 PM by JES
<<Created. Renders blogroll links given the URL of an OPML file.
bundle { //leave hint for link generator, 6/2/02 by DW
local (pta = html.getpagetableaddress ());
if not defined (pta^.blogRollUrls) {
pta^.blogRollUrls = {}};
pta^.blogRollUrls = pta^.blogRollUrls + {opmlUrl}};
bundle { //make sure prefix and suffix don't contain un-necoded quite characters
recentlyUpdatedLinkPrefix = string.replaceAll (recentlyUpdatedLinkPrefix, "\"", """);
recentlyUpdatedLinkSuffix = string.replaceAll (recentlyUpdatedLinkSuffix, "\"", """)};
local (htmltext = "", indentlevel = 0);
on add (s) {
htmltext = htmltext + (string.filledstring ("\t", indentlevel) + s + "\r");};
local (miniMugIcon, miniXmlButton);
bundle { //set miniMugIcon and miniXmlButton
miniXmlButton = "<img src=\"http://static.userland.com/shortcuts/images/misc/miniXmlButton.gif\" width=\"19\" height=\"9\" border=\"0\" valign=\"middle\" alt=\"miniXmlButton.gif\" />";
miniMugIcon = "<img src=\"http://static.userland.com/shortcuts/images/misc/miniXmlCoffeeMug.gif\" width=\"10\" height=\"10\" border=\"0\" valign=\"middle\" alt=\"miniXmlCoffeeMug.gif\" />"};
local (adrincache);
bundle { //set adrincache
local (adrcache = @system.temp.blogrollCache);
if not defined (adrcache^) {
new (tableType, adrcache)};
adrincache = @adrcache^.[opmlUrl];
if not defined (adrincache^) {
new (tableType, adrincache);
adrincache^.whenLastRead = date (0);
adrincache^.whenLastSizeCheck = date (0)}};
bundle { //load the outline if necessary, and compile the xml
local (lo);
local (flRead = false);
local (adrOpenUrlCache = @system.temp.Frontier.openUrlCache);
if not defined (adrOpenUrlCache^) {
flRead = true};
if not defined (adrOpenUrlCache^.[opmlUrl]) {
flRead = true};
if not defined (adrOpenUrlCache^.[opmlUrl].outline) {
flRead = true};
if clock.now () > date (adrincache^.whenLastSizeCheck + cacheSeconds) { //only check size if cache is expired
Frontier.tools.windowTypes.commands.openUrl (opmlUrl, adroutline:@lo);
adrincache^.whenLastSizeCheck = clock.now ()};
if timeModified (@adrOpenUrlCache^.[opmlUrl].outline) > adrincache^.whenLastRead {
flRead = true};
if not defined (adrincache^.xstruct) {
flRead = true};
if flRead { //read the outline, compile the xml and store it in the cache
local (xtext = op.outlineToXml (@lo));
xml.compile (xtext, @adrincache^.xstruct);
adrincache^.whenLastRead = timeModified (@adrOpenUrlCache^.[opmlUrl].outline)}};
on hasSubs (adr) {
local (adritem);
for adritem in adr {
if not (nameOf (adritem^) beginsWith "/") {
return (true)}};
return (false)};
on addItem (text, url, xmlurl, isRecent, target="", tooltip="") {
local (xmllinks = "", targetstring = "", titlestring = "", prefix = "", suffix = "");
if xmlurl != "" { //get coffee mug and xml button links
xmllinks = "<a href=\"http://127.0.0.1:5335/system/pages/subscriptions?url=" + string.urlEncode (xmlurl) + "\" title=\"Click to subscribe to "" + string.replaceAll (text, "\"", """) + "" in Radio UserLand.\">" + miniMugIcon + "</a> ";
xmllinks = xmllinks + "<a href=\"" + xmlurl + "\" title=\"Click to view the XML source for "" + string.replaceAll (text, "\"", """) + "".\">" + miniXmlButton + "</a> "};
if url == "" { //not linked
add ("<div class=\"" + cssPrefix + "Text\">" + xmllinks + text + "</div>")}
else { // linked
if sizeOf (target) > 0 {
targetstring = " target=\"" + string.replaceAll (target, "\"", "") + "\""};
if sizeOf (tooltip) > 0 {
titlestring = " title=\"" + string.replaceAll (tooltip, "\"", "&") + "\""};
if isRecent {
prefix = recentlyUpdatedLinkPrefix;
suffix = recentlyUpdatedLinkSuffix};
text = prefix + "<a href=\"" + url + "\" class=\"" + cssPrefix + "Link\"" + targetstring + titlestring + ">" + text + "</a>" + suffix;
add ("<div class=\"" + cssPrefix + "LinkedText\">" + xmllinks + text + "</div>")}};
on renderOneLevel (adr) {
local (text = "", url = "", xmlurl = "", isRecent = false, tooltip = "", target = "");
local (adratts = @adr^.["/atts"]);
if defined (adratts^) { //set text, url and xmlurl
if defined (adratts^.text) {
text = xml.entityDecode (adratts^.text, true)};
if defined (adratts^.url) {
url = adratts^.url};
if defined (adratts^.htmlUrl) {
url = adratts^.htmlUrl};
if defined (adratts^.xmlUrl) {
xmlurl = adratts^.xmlUrl};
if defined (adratts^.isRecent) {
if adratts^.isRecent {
isRecent = true}};
if defined (adratts^.title) {
tooltip = adratts^.title};
if defined (adratts^.target) {
target = adratts^.target}};
addItem (text, url, xmlurl, isRecent, target, tooltip);
if hasSubs (adr) { //recurse
indentlevel++;
local (adrsub);
for adrsub in adr {
if not (nameOf (adrsub^) beginsWith "/") {
renderOneLevel (adrsub)}};
indentlevel--}};
local (nomad = xml.getaddress (@adrincache^.xstruct, "opml"));
nomad = xml.getaddress (nomad, "body");
local (adr);
for adr in nomad {
renderOneLevel (adr)};
if flProcessMacros {
htmltext = html.processMacros (htmltext)};
if flXmlButton { //add a link to the OPML source
add ("<div class=\"" + cssPrefix + "LinkedText\"> <br /><a class=\"" + cssPrefix + "SourceLink\" href=\"" + opmlUrl + "\" title=\"Click on this icon to view the OPML source for these links.\"><img src=\"http://www.scripting.com/images/xmlIcon2.gif\" height=\"14\" width=\"36\" border=\"0\"></a></div>")};
return (htmltext)};
<<bundle //test code
<<local (f = user.radio.prefs.wwwFolder + "gems" + file.getPathChar () + "mySubscriptions.opml")
<<local (url = radio.upstream.getFileUrl (f))
<<local (startticks = clock.ticks ())
<<blogroll (url, false)
<<local (totalticks = clock.ticks () - startticks)
<<dialog.notify (totalticks)
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.