Close all but active Safari tab

Hi.

I’ve created a script to login to a website, clicking on specific links as it goes. The problem is, every time a URL is opened, it opens in a new tab, so I end up with unnecessary open tabs.

I’ve checked the .sdef for Safari, and whilst there are ‘current tab’ and ‘window’ properties, no matter how I try to use them or combine them, the script doesn’t compile.

I take it I need to reference the index name of the tab or window, but not sure how. Is there a simple way to simply open location/URL in the same tab?

Here’s the loop I’m currently using to open the URLs (the keystrokes are to highlight fields on the page and enter text “ I haven’t got around to parsing the HTML for form elements yet!).

tell application "System Events"
		tell process "Safari"
			activate
			open location loginPage
			my web_page_loading()
			keystroke tab
			keystroke userName
			keystroke tab
			keystroke login
			keystroke return
			my web_page_loading()
			open location itemsPage
			my web_page_loading()
			open location newItem
			my web_page_loading
			keystroke tab
			keystroke tab
			keystroke tab
		end tell
	end tell

Many thanks,
K@

Model: MacPro Qaud Xeon
AppleScript: 2.5 / 2.2.2
Browser: Safari 6
Operating System: Mac OS X (10.8)

Hi,

this opens an URL in the current tab


tell application "Safari"
	tell window 1 to set URL of current tab to "http://myDomain.com"
end tell

Hi Stefan.

I tried that, but get a syntax error:

I’ve tried using an explicit URL instead of a variable, but same error.

K@

It works stand-alone.
Probably you put the code into the System Events tell block.
You could put the code into the web_page_loading() handler and pass the URL as parameter

Ah … not sure I know how. The web_page_loading sub was taken from a script that I didn’t write, and is basically to ensure the page has fully loaded before progressing.

I don’t want you to write the script for me, but can you tell me, from looking at the routine, where the best place to put it would be? There’s a ‘System events’ call here, too, but I’m thinking that somewhere down near the end, after the repeat loops:

on web_page_loading()
	set theDelay to 10 -- the time in seconds the script will wait to let a web page load
	set numTries to 3 -- the number of stop/reload cycles before giving up
	set myCounter to 0
	set finished to false
	repeat until finished is true
		set myCounter to myCounter + 1
		set my_delay to 0.25
		set startTime to current date
		set endTime to startTime + theDelay
		set web_page_is_loaded to false
		delay my_delay
		tell application "Safari"
			activate
			repeat until web_page_is_loaded is true
				if endTime is greater than (current date) then -- only wait theDelay seconds for a web page to load otherwise stop the page loading and try to reload again
					if name of window 1 contains "Loading" or name of window 1 contains "Untitled" or name of window 1 contains "Failed to open page" then
						delay my_delay
					else
						set web_page_is_loaded to true
						set finished to true
						delay my_delay
					end if
				else
					tell application "System Events"
						tell process "Safari"
							if myCounter is numTries then -- give up if the page doesn't load after numTries stop/reload cycles
								keystroke "." using command down -- stop the page
								delay my_delay
								tell application "Finder"
									activate
									display dialog "The web page will not load!"
								end tell
								set connected to true -- a global variable which will stop this script if there's a problem
								set web_page_is_loaded to true
								set finished to true
								tell application "Safari" to activate
							else
								keystroke "." using command down -- stop the page
								delay my_delay
								keystroke "r" using command down -- reload the page
								delay my_delay
								set web_page_is_loaded to true
							end if
						end tell
					end tell
				end if
			end repeat
		end tell
	end repeat
end web_page_loading

as you call web_page_loading() always after an open location line
put it just at the beginning


on web_page_loading(theURL)
	tell application "Safari"
		tell window 1 to set URL of current tab to theURL
	end tell
	set theDelay to 10 -- the time in seconds the script will wait to let a web page load
	-- .



then replace


open location loginPage
my web_page_loading()

with

my web_page_loading(loginPage)

I gave it a try, but now it doesn’t login.

I think it’s because the sub now needs a URL parameter. It opens and gets to the login screen, but doesn’t do the keystrokes correctly, and doesn’t login.

I’ve tried putting an if loop in the sub, but that doesn’t work either.

I don’t really want to have to duplicate the whole sub without a parameter just for that step, but I may resort to that if I can’t tweak it in the right direction!

change the handler to


on web_page_loading(theURL)
	if theURL is not missing value then
		tell application "Safari"
			tell window 1 to set URL of current tab to theURL
		end tell
	end if
	set theDelay to 10 -- the time in seconds the script will wait to let a web page load
	-- .

in the case you call web_page_loading() after the keystrokes use


web_page_loading(missing value) 

Well, I tried it and it worked “ once!

It still messes up the page-loading check. It’s not major, so I’m not too worried. It just seemed like it should be a very simple thing to do, but perhaps not.

Many thanks for your help though.

Once your specified page is loaded, you might try getting rid of the undesired tabs using a repeat loop.

The first approach creates a new document and sets its url to that of the desired web page. The original page containing the multiple tabs is then discarded using the close window 2 command found at the end of the script. Advantage of this approach: It works relatively quickly and cleanly, without resorting to GUI scripting. Possible disadvantage: Will reopening the desired web page retain the login information that has been entered? If not, using this approach would be pointless.

New document, non-GUI approach:

tell application "Safari"
	tell window 1
		set my_url to "enter desired url here"
		set all_tabs to every tab
		repeat with a_tab in all_tabs
			set current tab to a_tab
			if URL of current tab = my_url then
				tell application "Safari" to make new document
				set URL of document 1 to my_url
				exit repeat
			end if
		end repeat
	end tell
	close window 2
end tell

Another approach uses GUI scripting in order to manipulate the Close Other Tabs command in Safari’s File menu. Advantage: the specified page is left untouched; no need to reopen it. Disadvantage: GUI scripting can be slow and unreliable.

“Close Other Tabs” approach, using GUI scripting:

tell application "Safari"
	activate
	tell window 1
		set my_url to "enter desired url here"
		set all_tabs to every tab
		repeat with a_tab in all_tabs
			set current tab to a_tab
			if URL of current tab = my_url then
				tell application "System Events"
					tell process "Safari"
						click menu item "Close Other Tabs" of menu "File" of menu bar 1
						exit repeat
					end tell
				end tell
			end if
		end repeat
	end tell
end tell

Scripts tested using Mac OS 10.4.11 and Safari 4.1.3. Your results may vary; modify as needed. Hope this helps.

Model: iMac 1 GHz PowerPC G4
AppleScript: 2.1.2
Browser: Safari 4.1.3
Operating System: Mac OS X (10.4)

How about this?

Edit
It is revised, tested, and works for me!


tell application "Safari"
	tell window 1
		set my_url to "desired urll"
		set all_tabs to every tab
		
		repeat with i from (count all_tabs) to 1 by -1
			set current tab to item i of all_tabs
			if URL of current tab = my_url then
			else
				tell current tab to close
			end if
		end repeat
	end tell
end tell


This works:


tell application "Safari"
	tell current tab of its window 1 to close
end tell

Just to add to the collection: :slight_smile:

-- These work with Safari 5.1.2 in Snow Leopard.
tell application "Safari" to close (tabs of front window whose visible is false) -- Close all but the current tab.
tell application "Safari" to close (tabs of front window whose URL is not my_url) -- Close all which don't have the specified URL.

-- This works with Safari 5.1.2 in Snow Leopard and with Safari 4.1.3 in Tiger.
tell application "System Events"
	set frontmost of application process "Safari" to true
	keystroke "w" using {option down, command down} -- Close all but the current tab.
end tell

Edit: It was Safari 5.1.2 when I wrote these. They still work in Safari 5.1.7. :slight_smile: But I notice that Option-Command-“w” crassly has a different meaning (Close All Windows) if there’s only one tab open in the front window, so that method’s best avoided!

Nice Nigel!

Your ways are even better. I hope to take up on Safari scripting soon, it still feels a bit odd and strange, but your examples helps.

And kudos to andmr for figuring out the two other scripts, and the efforts. I find Safari quirky. And I have experience with it before. I could easily see what was going on in Script Debugger. And saw that the list of tabs, was a list of references, when deleted from the start, every thing goes well, until one tab is passed over (the current tab, from then on, the next tab doesn’t exist, and that error occured. Not inituive without Script Debugger!

I better go hide, from the picket fence that is waiting .:slight_smile: