Sunday, September 11, 2005


Real Work Interfering

As is often the case, I've been excrutiatingly busy the last few days and I've done just about no scripting during that time. However, this morning, I returned my attention to an old favorite, my Insert Date script.

This little script is one of the first I wrote when I originally switched to JavaScript from AppleScript back in the early days of InDesign CS. A few weeks ago, an improvement was requested by one of my friends on the BlueWorld list and I have finally gotten around to upgrading my own copy of the script to include the improvement.

The script is instructive in a couple of ways: it shows how to use the JavaScript Date object to get information about a date, and it also shows how to manipulate substrings within JavaScript. Here is the original version of the script:
today = new Date();
myDateString = today.toLocaleDateString();
app.selection[0].contents = myDateString;
Briefly, the first line creates a new date in a variable named today. When you create a new date object, if you don't set it to a value, then it defaults to the current date (i.e., the date when the script is run).

If you look at DevGuru's JavaScript Date Object page, you'll see that one of the methods available for date objects is the toLocateDateString() method I use in the second line to create the date string that corresponds to the locale where the script is being run. The third line simply inserts this string into the current selection.

This early version has a number of problems, some of which are already familiar: what if there is no selection? What if it's the wrong kind of selection. We know from previous scripts how to deal with those two: wrap the script in the selection framework and add a check that the current selection is pure text.

But there are also problems with the string itself. Run it today, and the result doesn't look too bad:
Sunday, September 11 2005
But had I run it two days ago, the result would have been
Friday, September 09 2005

Ugh! Who wants the leading zero in the number of the day? And shouldn't there be a comma after that number? Most people would think so.

There are many ways that these two problems could be solved. To solve the leading zero problem, I added this immediately after forming myDateString
myParts = myDateString.split(" 0");
if (myParts.length != 1) {
 myDateString = myParts[0] + " " + myParts[1];
The split() for strings breaks a string into an array of parts (hence my name for the variable I used) using the argument (in this case a space followed by a zero) as a separator. If that argument does not appear in the original string (as it doesn't today) then myParts is an array of length 1, in which case there is nothing to do, but on Friday, there would have been two parts, so I knit them back together using just a space as a separator.

It is worth noting that this piece of code is very much oriented to the specific string that I get here in New Jersey using the English language. In other parts of the world, in other languages, the string might look completely different, so this particular script might not work for you.

We still need to deal with the missing comma. For that, I use the slice() method.
myDateString = myDateString.slice(0,-5) + "," + myDateString.slice(-5);
As you can see, I use it in two forms, first with a second argument and then with just one. You can read all about the JavaScript String object and its methods on DevGuru's JavaScript String Object page. When looking at that page remember two things:
  1. String literals can be formed by simply assigning a string to a variable; such strings act very like string objects
  2. Many of the methods on that page relate displaying strings on web pages; they are not supported by InDesign's ExtendScript
Generally speaking, you do not need to use the String() method to create a string. Just pass a string to a variable. The most common time you'll find yourself using the String() method is when you are attempting to concatenate a number with a string. If the number is before the string, you must explicitly coerce the number to a string by writing something like
String(4) + " times a day"
to produce the string "4 times a day". This looks a bit silly, but if that 4 was contained in a variable it would make more sense
String(frequency) + " times a day"
So, with all the additions listed here, our script ends up looking like this:
//DESCRIPTION: Insert date at text selection

Object.prototype.isPureText = function() {
  case "InsertionPoint":
  case "Character":
  case "Word":
  case "TextStyleRange":
  case "Line":
  case "Paragraph":
  case "TextColumn":
  case "Text":
   return true;
  default :
   return false;

if ((app.documents.length != 0) && (app.selection.length != 0)) {
 if (!app.selection[0].isPureText()) { errorExit() }
 today = new Date();
 myDateString = today.toLocaleDateString();
 myParts = myDateString.split(" 0");
 if (myParts.length != 1) {
  myDateString = myParts[0] + " " + myParts[1];
 myDateString = myDateString.slice(0,-5) + "," + myDateString.slice(-5);
 app.selection[0].contents = myDateString;
} else {

// +++++++ Functions Start Here +++++++++++++++++++++++

function errorExit(message) {
 if (app.version != 3) { beep() } // CS2 includes beep() function.
 if (arguments.length > 0) {
 exit(); // CS exits with a beep; CS2 exits silently.

I read you date script and changed it for my purpose. Now I am wondering if there would be a way for me to have this automated in my files. I work on books and when I open a new revision, I would like this revision date to be inserted automatically in the text field without my intervention.
Yes, it could be done, but it is quite a project. You'd have to use event handling to recognize the need to run the script and some other mechanism to tell the script where the text field is.
Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?