[Robot Wisdom home page]

Writing embedded-date bookmarklets

Jorn Barger 22 May 1999



Bookmarklets are simple programs written in the JavaScript language, stored like regular links or bookmarks, and executed by clicking on the link or selecting the bookmark. So they only work in browsers that support JavaScript.

Their leading proponent and innovator is Steve Kangas at bookmarklets.com.

This page offers a tutorial on writing one particular kind of bookmarklet, that generates a URL based on the current date.

Normally, you copy URLs by selecting them in the little URL-field at the top of the browser window, but you can't do this with bookmarklets. Instead, you have to use the popup menu that appears on a Mac when you click on the link and hold the mouse-button down, or in Windows when you click the link with the right mouse-button, instead of the left.

And if you need a full JavaScript reference, Netscape offers this one.


Basic stuff:

Here's a very simple bookmarklet that moves your current window to the upper left corner of the screen:

Move window

Try the 'Copy This Link Location' item in the popup menu, if you've never done that before, and make sure you can paste the javascript into a word-processing document.

All of the following forms work identically (note parens and semicolons):

javascript:
moveTo(4,4)
 
javascript:
(moveTo(4,4))
 
javascript:
void moveTo(4,4)
 
javascript:
void(moveTo(4,4))
 
javascript:
moveTo(4,4);
 
javascript:
(moveTo(4,4));
 
javascript:
void moveTo(4,4);
 
javascript:
void(moveTo(4,4));

JavaScript will ignore the carriage returns and whitespace, generally, but the convention is to omit them for compactness.

At the same time you relocate the window, you can resize it (which comes in handy if a badly-behaved site changes your default window size):

Move and resize window

javascript:
moveTo(4,4);
resizeTo(645,450)

Here the semicolon is required between the two commands.

Bookmarklets can also cause a link to open in a new window:

Open Yahoo in new window

javascript:
open('http://www.yahoo.com/');
void 1

(The final 'void 1' here keeps the original window from being overwritten like this.)

This technique gets really useful for opening several windows at once. I have one batch (of nine!) that I open first thing in the morning, another batch of weblogs for mid-morning, and this batch of three pages that occasionally offer new, sample 'first chapters':

Three first-chapters pages

javascript:
open('http://www.washingtonpost.com/wp-srv/style/books/front.htm');
open('http://www.usatoday.com/life/enter/books/chapter.htm');
open('http://www.cnn.com/books/beginnings/');
void 1



Embedded dates:

(The first embedded-date bookmark, for CNN EarthWeek, was written by Dan Budiac.)

The reason for embedded-date bookmarklets is that many web periodicals require you to link to a homepage with no content, and then click on a second link for the current issue's table of contents. For example, Lingua Franca's homepage is at: http://www.linguafranca.com/ but the table of contents for May 1999 is at: http://www.linguafranca.com/9905/toc.9905.html

Here's a bookmarklet that can generate the embedded-date URL:

Lingua Franca

javascript:
var t=new Date();
var m=t.getMonth()+1+'';
var y=t.getYear()%100+'';
if(m.length==1)m='0'+m;
if(y.length==1)y='0'+y;
location.href='http://www.linguafranca.com/'+y+m+'/toc.'+y+m+'.html';

Looking at this line-by-line:

var t=new Date();

Creates a variable 't' and assigns it the value of the current date, in JavaScript format.

var m=t.getMonth()+1+'';

Extracts the current month from the date 't', adds '1' to it (because they perversely call January '0' not '1'), and then changes it to a string rather than a number by appending an empty string.

var y=t.getYear()%100+'';

Extracts the current year, in an odd format that counts 1900 as '0', divides by 100 and keeps the remainder (the 'modulo' operation), and converts it to a string.

if(m.length==1)m='0'+m;

Tests to see if the month is one digit or two, and pre-pends a zero if it's just one (so '5' becomes '05').

if(y.length==1)y='0'+y;

Ditto for the year.

location.href='http://www.linguafranca.com/'+y+m+'/toc.'+y+m+'.html';

Links together all the pieces to get something like:

http://www.linguafranca.com/9905/toc.9905.html

Here's a very similar one for Sun's column on scripting:

Regular Expressions

javascript:
var t=new Date();
var m=t.getMonth()+1+'';
var y=t.getYear()+1900+'';
if(m.length==1)m='0'+m;
location.href='http://www.sunworld.com/swol-'+m+'-'+y+'/swol-'+m+'-regex.html';

The big difference here is that the year has to be converted to four digits rather than two: http://www.sunworld.com/swol-05-1999/swol-05-regex.html

The next one is for NASA's daily AstroPic, and includes the day as well as the month and year. (There's a standard URL for this page as well: http://antwrp.gsfc.nasa.gov/apod/astropix.html but it's no good for linking to particular pictures, which need this format: http://antwrp.gsfc.nasa.gov/apod/ap990522.html

AstroPic

javascript:
var t=new Date();
var d=t.getDate()+'';
var m=t.getMonth()+1+'';
var y=t.getYear()%100+'';
if(d.length==1)d='0'+d;
if(m.length==1)m='0'+m;
if(y.length==1)y='0'+y;
location.href='http://antwrp.gsfc.nasa.gov/apod/ap'+y+m+d+'.html';

Harper's magazine offers very little content on the Web, as yet, but they do post the previous month's 'Index' around the first of each month:

Harper's Index

javascript:
var t=new Date();
t.setMonth(t.getMonth()-1);
var m=t.getMonth()+1+'';
var y=t.getYear()+1900+'';
if(m.length==1)m='0'+m;
location.href='http://www.harpers.org/harpers-index/listing.phtml?sub_month='+m+'&sub_year='+y;

The result here is a messy search engine query: http://www.harpers.org/harpers-index/listing.phtml?sub_month=04&sub_year=1999

The only new feature is the third line:

t.setMonth(t.getMonth()-1);

The current date has both the current month and current year, but every January we'll need to roll back both the month and the year. JavaScripts 'date object' knows how to do this automatically if you use the setMonth/ getMonth format.

Dilbert holds back the daily cartoon for a week before posting it, and then after a day moves it from the undated URL: http://www.unitedmedia.com/comics/dilbert/ab.html to a dated URL (for the next month): http://www.unitedmedia.com/comics/dilbert/archive/dilbert19990529.html

For a lazy weblogger, it's easiest to just follow the eight-day-old URL: Dilbert

javascript:
var t=new Date();t.setDate(t.getDate()-8);
var m=t.getMonth()+1+'';
var y=t.getYear()+1900+'';
if(m.length==1)m='0'+m;
var d=t.getDate()+'.html';
if(d.length==6)d='0'+d;
location.href='http://www.unitedmedia.com/comics/dilbert/archive/dilbert'+y+m+d;


Sometimes, annoyingly, the month will be expressed as an abbreviation: http://boardwatch.internet.com/mag/99/apr/fable.html

This bookmarklet handles this by brute force:

BoardWatch

javascript:
mn=new Array('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec');
var t=new Date();
t.setMonth(t.getMonth()-1);
var m=t.getMonth();
var y=t.getYear()%100+'';
if(y.length==1)y='0'+y;
location.href='http://boardwatch.internet.com/mag/'+y+'/'+mn[m]+'/fable.html';

This line creates an array of month abbreviations:

mn=new Array('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec');

which are accessed by the form 'mn[m]' in the last line.

Weekly periodicals require a new complication depending on which day of the week they're posted. If the new issues come out on Friday, you want the bookmarklet to work right for the rest of the week:

CNN EarthWeek

javascript:
var t=new Date();
t.setDate(t.getDate()-(t.getDay()+2)%7);
var y=t.getYear()+'';
var m=t.getMonth()+1+'';
var d=t.getDate()+'';
if(m.length==1)m='0'+m;
if(d.length==1)d='0'+d;
location.href='http://www.cnn.com/NATURE/'+y+m+'/'+d+'/diary.planet/index.html';

You need to rewind the date to the previous Friday, which requires a somewhat unintuitive operation on the getDay value:

   getDay  offset
 
F     5     -0
S     6     -1
S     0     -2
M     1     -3
T     2     -4
W     3     -5
T     4     -6

So the offset is "(getDay + 2) modulo 7"

(t.getDay()+2)%7)

An alternate approach is via a for-loop:

for(
   var t=new Date();
   t.getDay()!=5;
   t.setDate(t.getDate()-1));

which can be broken down as:

for(

which sets up the loop

var t=new Date();

which initialises the loop

t.getDay()!=5;

which tests if the day of the week is Friday (where Sunday = 0)

t.setDate(t.getDate()-1));

and keeps subtracting one day per loop, if it isn't.

The same techniques work for daily periodicals that suspend publication on weekends:

Salon's Blue Glow

javascript:
var t=new Date();
t.setDate(t.getDate()-(t.getDay()==0?2:(t.getDay()==6?1:0)));
var y=t.getYear()+1900+'/';
var m=t.getMonth()+1+'/';
var d=t.getDate()+'/';
if(m.length==2)m='0'+m;
if(d.length==2)d='0'+d;
location.href='http://www.salon.com/ent/tv/glow/'+y+m+d+'glow/print.html';

The offsets here will be:

   getDay  offset
 
M     1     -0
T     2     -0
W     3     -0
T     4     -0
F     5     -0
S     6     -1
S     0     -2

because Salon's TV column for Friday includes the Sat and Sun highlights as well.

So the offset is "if getDay==0 then 2 else (if getday==6 then 1 else 0)" where the form "if x then y else z" can be represented as 'x ? y : z':

t.getDay()==0?2:(t.getDay()==6?1:0)

Or, with the looping approach:

for(
  var t=new Date();
  t.getDay()==(6||0);
  t.setDate(t.getDate()-1));

The test here uses the '||' operator to mean OR (Saturday OR Sunday).

Messier still is the case of the New Scientist, where the issue dated Saturday is posted to the Web on Wednesday:

New Scientist

javascript:
var t=new Date();
var d=t.getDay();
t.setDate(t.getDate()-((d>2)?(d-6):(d+1)));
var y=t.getYear()+1900+'';
var m=t.getMonth()+1+'';
var d=t.getDate()+'';
if(m.length==1)m='0'+m;
if(d.length==1)d='0'+d;
location.href='http://www.newscientist.com/ns/'+y+m+d+'/news1.html';

On Wed, Thurs, and Fri you want to advance the date to Saturday. From Sun thru Tues you want to step back to the Sat before:

   getDay  offset
 
S     0     -1
M     1     -2
T     2     -3
W     3     +3
T     4     +2
F     5     +1
S     6      0


(d > 2) ? (d - 6) : (d + 1)


Finally, the 'new Date' command automatically assumes that the date advances at midnight in your local timezone, but daily periodicals post at some arbitrary time in their own time zone. So to be accurate, we need to compensate with the 'getTimezoneOffset' operator:

Irish Times

javascript:
var t=new Date();
t.setHours(t.getHours()-3+t.getTimezoneOffset()/60);
t.setDate(t.getDate()-((t.getDay()==0)?1:0));
var y=t.getYear()+1900+'/';
var m=t.getMonth()+1+'';
var d=t.getDate()+'/';
if(m.length==1)m='0'+m;
if(d.length==2)d='0'+d;
location.href='http://www.ireland.com/newspaper/features/'+y+m+d+'index.htm';

The Irish Times posts around 0300 GMT:

t.setHours(t.getHours()-3+t.getTimezoneOffset()/60);

(TimezoneOffset is measured in minutes, not hours, because a few locations require it.)

And they take Sunday off:

t.setDate(t.getDate()-((t.getDay()==0)?1:0));


And the London Times posts around 0100 GMT, and has a slightly different URL-format on Sundays:

UK Times

javascript:
var t=new Date();
t.setHours(t.getHours()-1+t.getTimezoneOffset()/60);
var y=t.getYear()%100+'/';
var m=t.getMonth()+1+'/';
var d=t.getDate()+'/';
if(m.length==2)m='0'+m;
if(d.length==2)d='0'+d;
location.href='http://www.sunday-times.co.uk/news/pages/'+
  ((t.getDay()==0)?'sti/':'tim/')
  +y+m+d+
  ((t.getDay()==0)?'fpcontent':'timconcon01001')
  +'.html?1334425';

Here's the two compact tests for Sunday:

(t.getDay()==0)?'sti/':'tim/'
 
(t.getDay()==0)?'fpcontent':'timconcon01001'


Web-design pages:
main : academia : info-design : adding value : resource-pages : lessons-learned : best-worst : plugging leaks

Special topics:
surfing-skills : url-hacking : open content : semantics : pagelength : linktext : startpages : bookmarklets : weblogging : colors : autobiographical pages : thumbnail-graphics : web-video : timeline of hypertext

Anti-XML/W3C/etc:
structure-myth : page-parsing : firstcut-parser : html-history : semantic web

Design prototypes:
topical portal : dense-content faq : annotated lit : random-access lit-summary : poetry sampler : gossipy history : author-resources : hyperlinked-timeline : horizontal-timeslice : web-dossier

Website-resource pages:
RobotWisdom.com : Altavista.com : 1911encyclopedia.com : Google.com : IMDb.com : Perseus.org : Salon.com : Yahoo.com

Older stuff:
design-lab : design-checklist : HyperTerrorist : design-theory : design cog-sci



Search this site Search full Web

Before you leave this site: Be sure you've checked out Jorn's weblog which offers daily updates on the best of the Web-- news etc, plus new pages on this site. See also the overview of the hundreds of pages of original content offered here, and the offer for a printed version of the site.

Hosting provided by instinct.org. Content may be copied under Open Web Content License.