1 comments Friday, July 11, 2008

I have found a better way of saving NewNewsWire articles to read later in Safari on my desktop or iPhone:

LaterLoop is a site that allows you to add links to your reading list, then later easily view those links in your desktop or mobile browser. This is similar to Instapaper, Delicious (using a toread tag), etc.

I like the interface better, however, because when you save a link, rather than opening a pop-up or redirecting you to a new page to save the link, the page simply flashes. This is a nice feature when using it in the browser, but it ends up being crucial to being able to use it within NetNewsWire.

I hadn't realized this when I made an AppleScript script to save NNW articles to Delicious, but NNW has the ability to run JavaScript "bookmarklets" located in the Scripts menu. Normally, you can take a bookmarklet such as LaterLoop's "Save for Later" bookmarklet, copy the address, paste it in a text file whose name ends in .js, and place it in NNW's Scripts folder (you can find this folder by clicking "Open Scripts Folder" from the Scripts menu in NNW).

Unfortunately, NetNewsWire returns the homepage of the RSS feed as the current URL rather than the URL of the specific article. To correct this, I had to download and modify the LaterLoop script and bookmarklet so that they pull the actual URL of the article.

To use my modified version, save this as ll.js and remember which directory you saved it in:

(function(){
__ll_u = 'http://www.laterloop.com/post/?key=' + document._ll;
document._ll = '';
function getFirstElementByClassName(tag, className, dom){
var elems = dom.getElementsByTagName(tag);
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
if (elem.className.indexOf(className) != -1)
return elem;
}
return null;
}
function unescapeHTML(str, doc){
var dom = doc || document;
var div = dom.createElement('div');
div.innerHTML = str;
return div.childNodes[0].nodeValue;
}
function getGoogleReaderItem(){
var page_url = null, page_title = null, source_title = '', do_save = false, is_google_reader = false;
var google_reader = /\/\/www\.google\.com\/reader\/view/ig;
var location = dom.getElementById('newsItemTitle').firstChild.getAttribute('href');
var dom = window.document;
if (location.match(google_reader)) { //if (page_url.indexOf('//www.google.com/reader') != -1) {
is_google_reader = true;
var current_item = dom.getElementById('current-entry');
if (current_item) {
var h2 = current_item.getElementsByTagName('h2');
var link = getFirstElementByClassName('a', 'entry-original', current_item);
var stream_title = getFirstElementByClassName('span', 'entry-source-title', current_item);
var is_stream_title_and_not_shared_item = !stream_title.getElementsByTagName('img') || stream_title.getElementsByTagName('img').length == 0;
if (stream_title) {
if (is_stream_title_and_not_shared_item) {
source_title = stream_title.innerHTML;
}
else {
stream_title = getFirstElementByClassName('a', 'entry-source-title', current_item);
source_title = stream_title.innerHTML;
}
}
if (source_title == '') {
stream_title = dom.getElementById('chrome-stream-title');
if (stream_title) {
stream_title = stream_title.getElementsByTagName('a');
if (stream_title && stream_title.length) {
source_title = stream_title[0].innerHTML;
}
}
}
if (h2.length && link) {
page_title = unescapeHTML(h2[0].innerHTML, dom);
page_url = link.href;
source_title = unescapeHTML(source_title, dom);
}
}
}

if (page_url && page_title && page_url != '' && page_title != '') {
do_save = true;
}

return {
is_google_reader: is_google_reader,
do_save: do_save,
url: page_url,
title: page_title,
source: source_title
};

}
var google_reader_item = null;
try {
google_reader_item = getGoogleReaderItem();
}
catch(x) {}

__ll_w = window;
__ll_d = __ll_w.top.document;
__ll_e = encodeURIComponent;

var do_save = true;
var do_fade = true;

if (google_reader_item && google_reader_item.is_google_reader) {
if (google_reader_item.do_save) {
var referrer = 'http://www.google.com/reader/view/#bkml1';
__ll_u += '&title=' + __ll_e(google_reader_item.title) + '&url=' + __ll_e(google_reader_item.url) + '&via=' + __ll_e(referrer) + '&greader=1&source_title=' + __ll_e(google_reader_item.source) + '&src=wk&v=1&fmt=js&t=' + (new Date().getTime());
do_fade = false;
}
else {
alert('LaterLoop could not identify which item is currently selected. Please click on a story and try again.')
do_save = false;
}
}
else {
__ll_u += '&title=' + __ll_e(__ll_d && __ll_d.title.replace(/^\[(Saving...|Saved)\]\s/, '') || '') + '&url=' + __ll_e(__ll_d.getElementById('newsItemTitle').firstChild.getAttribute('href')) + '&via=' + __ll_e(__ll_d.referrer) + '&src=wk&v=1&fmt=js&t=' + (new Date().getTime());
}

if (do_save) {
__ll_e = document.createElement('script');
__ll_e.setAttribute('type', 'text/javascript');
__ll_e.setAttribute('charset', 'UTF-8');
__ll_e.setAttribute('src', __ll_u);

document.body.appendChild(__ll_e);
}

var __ll_ID = 'laterloop-overlay-shadow';
var shadow = document.getElementById(__ll_ID);
if (shadow) {shadow.parentNode.removeChild(shadow);}
shadow = document.createElement('div');
shadow.id = 'laterloop-overlay-shadow';
shadow.style.opacity = "0.0";
shadow.style.MozOpacity = shadow.style.opacity;
shadow.style.top="0";
shadow.style.left="0";
shadow.style.width="100%";
shadow.style.height="100%";
shadow.style.display="block";
shadow.style.position="fixed";
shadow.style.backgroundColor="#fff";
shadow.style.zIndex = "99997";
shadow.onclick=function() {this.style.display='none';};
document.body.appendChild(shadow);
function fadeIn(obj, max, current) {
if (!current) {
current = 0.1;
}
else {
current = Math.min(current+0.15, 1);
}
obj.style.opacity = current;
obj.style.MozOpacity = shadow.style.opacity;
if (current < max) {
setTimeout(function() {fadeIn(obj, max, current);}, 15);
}
else {
setTimeout(function() {document.__ll_elapsed=true;}, 500);
}
}
document.__ll_elapsed=false;
if (do_save && do_fade) {
fadeIn(shadow, 0.7);
}
if (!do_save) {
setTimeout(function() {
document.title = document.title.replace(/^\[(Saved|Saving...)\]\s/, '');
}, 500);
}
})();

Then save this bookmarklet to NNW's Scripts folder with a name ending in .js:
javascript:void((function(){var%20d=document;var%20h='file:///Users/andrew/';d._ll='KNsDvhqgrfcpJBmWtjfe';try{var%20e=d.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src',h+'ll.js');d.body.appendChild(e);}catch(x){e=encodeURIComponent;w=window;qs='&key='+d._ll+'&title='+e(d.title||'')+'&url='+e(d.getElementById('newsItemTitle').firstChild.getAttribute('href'))+'&via='+e(d.referrer)+'&fmt=html&src=wk&v=1&t='+(new%20Date().getTime());u=h+'/post/?'+qs;w.top.location.assign(u);return;}s='[Saving...]%20';d.title=s+d.title.replace(s,'');})());

You will need to replace file:///Users/andrew/ with the path to the directory in which you saved ll.js.

For this script to work, you will also need to select Enable JavaScript under NNW preferences > Browsing > News Items. The script should show up in the scripts menu, where you can click it to save the current article to LaterLoop (assuming you are logged in). To make this even more convenient, you can easily add a keyboard shortcut to this script. Go to System Preferences > Keyboard & Mouse > Keyboard Shortcuts, press the + button to add a new shortcut, select NetNewsWire as the application, type in the filename of your script as the Menu Title, and assign whatever keyboard shortcut you want. I assigned it to Cmd-1, which is the keyboard shortcut I use for the LaterLoop bookmarklet in Safari.

Now I can press Cmd-1, and the current article flashes to let me know it's been saved to LaterLoop.

Here's a brief video of it in action (this video would only play in Firefox for me).

You might be thinking, why couldn't I use this technique with Delicious or Instapaper (the other two services I've tried)? Well, the Delicious bookmarklet doesn't seem to do anything in NNW, and the Instapaper bookmarklet replaces the article's text with "Saved", then closes NNW. However, I'm sure there are other services out there that will work with the technique I've described, so if you are using another service you may want to try it out using your existing bookmarklet.

This system works very well, but the one other thing I would really like to be able to do would be to view my unread LaterLoop links in NNW. LaterLoop does in fact publish an RSS feed of your links, but they a.) Include links you've already read and b.) limit the number of links in your feed to 30.

As an aside, the NetNewsWire style you see in the video is called Bullit.