AppleScript browser tab weirdness

I was playing around with an AppleScript tonight and ran into an odd bug when trying to write a script that worked whether my default browser was Safari or Chrome. It happens when I use a variable to hold the browser’s application ID—com.google.chrome, for example—and try to access any information about its tabs.

For example, this

set browser to "com.google.chrome"

tell application id browser
  get active tab index of front window
end tell

won’t compile. It throws a syntax error at the word tab and says

Expected end of line but found property.

I get a similar thing when I try this

set browser to "com.apple.Safari"

tell application id browser
  get URL of tab 1 of front window
end tell

In this case, the syntax error is at the 1, and the error message is

Expected end of line but found number.

Since both this

tell application id "com.google.chrome"
  get active tab index of front window
end tell

and this

tell application id "com.apple.Safari"
  get URL of tab 1 of front window
end tell

compile and run just fine, you might think the problem lies with using a variable to hold the application ID instead of using a string literal. But you’d be wrong, because this

set browser to "com.google.chrome"

tell application id browser
  get bounds of front window
end tell

and this

set browser to "com.apple.Safari"

tell application id browser
  get visible of front window
end tell

both work even though I’m using a variable. Window properties like visible, name, id, and zoomable work regardless of whether I use a variable or a literal, but tab properties only work with a literal.

In the script I’m noodling with, the browser variable isn’t set by a simple assignment as in these examples, it’s set according to the user’s default browser. I can certainly get around the bug by doing something like this

if browser is "com.google.chrome"
  tell application "Google Chrome"
    <whatever>
  end tell
else
  if browser is "com.apple.Safari"
    tell application "Safari"
      <whatever>
    end tell
  end if
end if

but I was hoping to write something that was a little less clumsy and redundant. The Chrome and Safari AppleScript libraries are enough alike that you can often use the same code for either, and I was hoping to take advantage of that by doing something clever and sleek, like

tell application id browser
  set theURL to URL of tab n of front window
end tell

Sadly, this simplicity isn’t to be.


8 Responses to “AppleScript browser tab weirdness”

  1. Tobias says:

    I think the problem is that AppleScript needs to look up terms like tab at compile time, and without a literal tell block it doesn’t know where to look. Also you can’t assume that just because Safari and Chrome use the same term, their dictionaries map it to the same event ID.

    A workaround might be writing a file full of handlers and saving it once with Safari and after search and replace with Chrome as the target. Then load the appropriate copy from your main script.

    Or just use pyappscript :)

    py-appscript

  2. Lri says:

    Yeah, you can’t use app-specific terms, just ones in Standard Suite.

    set a to "Finder"
    tell app a to windows -- works
    tell app a to insertion location -- doesn't work
    tell app a to activate -- works
    

    Application references in variables behave the same way:

    set a to app "Finder"
    tell a to windows -- works
    tell a to insertion location -- doesn't work
    tell a to activate -- works
    

    Another appscript-ism that works only partially:

    app "Finder"'s windows -- works
    app "Finder"'s insertion location -- doesn't work
    app "Finder"'s activate -- doesn't work
    
  3. Dr. Drang says:

    The active tab index property appears in the Standard Suite section of Chrome’s dictionary, but it’s clearly specific to Chrome, so Lri’s explanation makes sense. Tobias’s compile time/run time distinction seems plausible, too. Maybe the limited knowledge the script has at compile time is the reason app-specific properties can’t be accessed when the application is provided in a variable.

  4. Clark says:

    I’m surprised you even bother programming in Applescript. Of course Appscript has its own big flaws.

    A lot of us wish Apple would come up with something different. However Apple’s stretched so thin right now and even iOS5 won’t make iOS mature. Probably not until iOS6. With the focus on the consumer space I think pro-users will be left in the cold a little longer.

  5. Dr. Drang says:

    Honestly, Clark, I don’t find Appscript syntax like

    frontIndex = app('Google Chrome').windows[1].active_tab_index.get()
    

    especially intuitive. My rule of thumb for choosing between AppleScript and Python/Appscript is this: If all I’m doing is getting info from or giving a command to an application, I stick with AppleScript; if I need to do any string or list manipulation, I shift to Python/Appscript.

  6. Clark says:

    Really? Huh. That seems way more intuitive (and far less ambiguous) than Applescript. Maybe I’ve just done object oriented programming of that style for too long.

  7. Dr. Drang says:

    Well, there’s the fact that windows and tabs arrays are 1-based instead of the more Pythonic 0-based. Worse, perhaps, is that 0 is a synonym for 1, so you can happily be using windows[0] and then later run into a bug when windows[1] refers to the same window instead of the one behind it.

    And don’t get me started on get(), which always strikes me as superfluous.

  8. Clark says:

    You can ignore the get typically. So windows[1].name() is the same as windows[1].name.get()