Safari AppleScript – Can’t Filter Tabs of Inactive Windows

applescriptsafari

I've got a bit of AppleScript that is frustrating the heck out of me. I need to get a list of all Safari tabs, then filter them down. I was expecting this to be very simple. It's not.

tell application "Safari"
    set tabSet to {}
    repeat with w in (get every window)
        repeat with t in (get every tab of w)
            set the end of tabSet to t
        end repeat
    end repeat
    --set tabSet to every tab of every window -- a one-liner here would be convenient

    set firstTab to first item of tabSet -- works, see edit
    set targetTab to first item of tabSet whose name is "Untitled" -- this fails
end tell

First of all, every tab of every window returns a nested list of lists of tabs (grouped by window) instead of just a flat list. I just ended up going with repeats. (If there is a way to make this a one-liner, it would be nice). But so far, so good.

The result I was getting from first item of tabSet was throwing me off because it looked like it was returning a form of the entire list:

item 1 of {tab 1 of window id 15557 of application "Safari", tab 2 of window id 15557 of application "Safari", tab 3 of window id 15557 of application "Safari", tab 4 of...

The actual problem occurs on the filter line where I try to get the first item of tabSet whose name is "Untitled". (Replace with a valid name of course). Then, I get this error:

error "Safari got an error: Can’t get tab 1 of window id 15561 whose name = \"Untitled\". Invalid index." number -1719

EDIT 2:

I added the following block:

repeat with t in tabSet
    set n to (get name of t)
    try
        set targetTab to (first item in tabSet whose name is n)
        set targetWindow to (first window whose tabs contains targetTab)
        log (get id of targetWindow) & (get name of t)
    on error
        log "ERROR: " & n
    end try
end repeat

This revealed that, once again, the problem was not as it seemed, but was actually something completely different:

Only tabs in the frontmost window can be filtered. It appears that the statement first item of tabSet whose name is "Untitled" fails if the tab "Untitled" is in any window other than the frontmost window.

Any ideas?

Best Answer

This is how AppleScript refers to items from lists. You're not doing anything wrong.

When you say ‘first item’ of a list, you get ‘item 1 of {some list}’, that is literally equivalent to the first item in the list as you'd expect it in other languages.

All 3 of these are equivalent and refer to exactly the same thing, even though they show differently.

tab 1 of window id 1
item 1 of {tab 1 of window id 1}
item 1 of {tab 1 of window id 1, tab 2 of …, …}

You can get properties from this item as if it had never been in a list.

set targetName to name of targetTab -- gets the name of the tab

It may be confusing coming from other languages to see the entire list shown when you just want a single item, but it's likely for performance, since it doesn't attempt to extract anything from the list or even show a different representation of the item just because you don't want to see the rest of the list in some sort of output.