Why does a window reference in Safari change when I move a window forward?

In Safari, I want to search all windows for a tab with a specific URL and activate that tab/bring it to the foreground. I loop through all tabs in all windows until I found a tab with the URL I am looking for:

	repeat with aWindow in windows
		repeat with aTab in tabs of aWindow
			if (URL of aTab) is equal to targetURL then
				set targetTab to aTab
			end if
		end repeat

Now I expect aWindow to be a reference to the window that contains the found tab but if the aWindow is in the background and I move it to the front like this

	set index of aWindow to 1

and then change the tab

	set current tab of aWindow to targetTab

it changes the tab of the window that took over aWindow’s position in the background!?!?

An example: I have two windows, fg (foreground) and bg (background), and in both windows, tab 1 is displayed. I then loop through both windows and find the tab I am looking for, tab 3 in bg. If I then raise the bg window to the foreground and change the tab, tab 3 in fg is activated while bg still is at tab 1!?!?

However, if I first change the tab and then bring the parental window to the front it works.

Hmm, I tried using windows IDs instead of indexes (which I guess is the default):

repeat with aWindow in windows
	repeat with aTab in tabs of aWindow
		if (URL of aTab) is equal to targetURL then
			set targetTab to aTab
			set targetWinID to id of aWindow
		end if
	end repeat

	set current tab of (window id targetWinID) to targetTab
	set index of (window id targetWinID) to 1

Result:

set current tab of window id 16642 to item 8 of every tab of item 2 of every window|
set index of window id 16642 to 1|

But it is the same problem here: if I bring the window to the front first

set current tab of (window id targetWinID) to targetTab|
set index of (window id targetWinID) to 1|

switching tab fails:

set index of window id 16642 to 1
set current tab of window id 16642 to item 8 of every tab of item 2 of every window
	--> error number -10000

I suspect the culprit is this part of the log of item 2 of every window but where does it come from??

All this code is just surrounded by a tell application "safari".

I think it has to do with ‘repeat with aWindow in windows’.
When you use this command, ‘aWindow’ does not contain a window, but a reference to a window. The reference then fails if the order of windows gets changed while its executing.

Try putting this line directly after.

repeat with aWindow in windows
	set aWindows to contents of aWindow
	• • •
end repeat

or you can dot the loop by using

repeat with i from 1 to count windows
	set aWindow to window i
	• • •
end repeat

In both instances ‘aWindow’ should now contain a window object, not a reference to a window.

I just realized you might also run into another similar issue.
If the window order changes the window command will also return a list in z order,
and it also gets re-calculated each time called.
you might want to call it once and save the results in a variable like so…

set allWindows to windows
repeat with aWindow in allWindows
	set aWindows to contents of aWindow
	• • •
end repeat

but this might cause another issue such as what if a window gets closed in the middle of execution. One of the windows in the saved variable will now be a non-existent window. You would have to put code in to check if window still exists.

Does this really apply when you use window ID instead of index? I have logged the ID at every step and it stays constant during the whole process.

What do you say about the result? This is the result when it fails:

set current tab of window id 16642 to item 8 of every tab of item 2 of every window|

It feels weird to have both window id and item 2 of every window - doesn’t it?

This is the result when it succeeds. The only difference is the last item number, 1 or 2.

set current tab of window id 16642 to item 8 of every tab of item 1 of every window|

I am not following you here. Can you elaborate?

I had some trouble following the discussion and decided to write a full script, which worked as expected on my Sonoma computer. However, there can be an issue when the URL of a tab is not precisely what is expected, causing the test for equality to fail. An alternative is to test if the URL of the tab begins with the target URL; another might be to test for tab names.

set targetURL to "https://www.google.com/"

tell application "Safari"
	set theWindows to every window
	repeat with aWindow in theWindows
		set theTabs to every tab of aWindow
		repeat with aTab in theTabs
			if (URL of aTab) is equal to targetURL then -- consider "begins with" instead of "is equal to"
				set index of aWindow to 1
				set current tab of aWindow to aTab
				error number -128
			end if
		end repeat
	end repeat
end tell

display alert "A tab with the target URL was not found" message targetURL

What you did was to move the activation of the window/tab with the URL you are looking for into the loop rather than, as I did, have it outside the loop? Or was it something more that you changed?

Hmm, moving the window activation into the inner loop worked. I am bit surprised, but when I write this I realise that I had more than two windows open and that the looping continued after the tab was found. OTOH, I used window IDs which should be constant. Confusing.

AFAIK the window ID does not change as long as the window exists. Have you tried it?

Exiting two repeat loops in AppleScript is not always a simple matter, and that’s why I wrote my script as I did. Bash has a break [n] command that will exit multiple repeat loops, but I don’t know of anything similar in AppleScript. FWIW, the following is functionally equivalent to my earlier script.

set targetURL to "https://www.macscripter.net"

tell application "Safari"
	set matchFound to false
	set theWindows to every window
	repeat with aWindow in theWindows
		set theTabs to every tab of aWindow
		repeat with aTab in theTabs
			if (URL of aTab) begins with targetURL then -- use "is" instead of "begins with" if desired
				set matchFound to true
				exit repeat -- exit inner repeat loop
			end if
		end repeat
		if matchFound is true then exit repeat -- exit outer repeat loop
	end repeat
	if matchFound is true then
		set index of aWindow to 1
		set current tab of aWindow to aTab
	else
		display dialog "A tab with the target URL was not found" buttons {"OK"} default button 1
	end if
end tell

An easier way is to put the double loop into a function and use return.

lagr. I rewrote my script to implement your suggestion, and, while it worked, it was pretty ugly. Please post your script that puts the repeat loop in a handler. Thanks!