Closing a Safari tab

Probably the latter. The empty braces represent windows without tabs, not empty tabs.

Hello.

You are absolutely right Nigel.

I still think it is a good idea to test for missing values of names of tabs as well, if it is to be solid, because before you know it, someone comes up with such as a “posh” thing to do. :slight_smile:

By the way, I just found this on the net, it gives you the prosess id of a a single process, (all instances), just by the name, less to read when you are searching then.

It compiles with : make pidof
(If you stand in the folder where you saved it as pidof.c. (by just copying it off the html page, and then cat >pidof.c) cmd-v, ctl-c).

If you look at the list carefully, those are windows with no tabs. :slight_smile:

This returned:

doesn’t work :stuck_out_tongue:
The issue is simply it’s not working, I think that AppleScript thinks it works. It always says close tab in the log as it should…

Hello.

Please check, just for the hell of it, that you have "enabled access to assitive devices in your System preferences (under “Universal access”. Thats a very long shot in the dark.

I really guess you have some kind of plugin that sabotages your browser in some way.

Hello.

I started out by mentioning the pidof.c program, that returns process id’s for a given process name, and since I am utterly lazy, I wrote a little applet, for using that program. (there are instructions for compiling in post #22 but you need to have Developer tools or similiar installed.

This applet takes a process name, or from history, and lets you choose the process number by that name to kill, the highest number is the latest running process with that name, unless your uptime has been really really long, and your process numbering is in a state of transitioning.

After you have saved the applet, you need to open its bundle, and add the key LSUIElement and set it to true. It’s best done with property list editor, or from XCode. (The idea is to execute it from Spotlight.)
But in order to save you all the trouble, there is a fully packed zipfile, with the pidof utility in its tummy; you can download from here

Enjoy!

-- http://macscripter.net/viewtopic.php?pid=164214#p164214 post #25
-- © McUsr and put in public domain you may not post this elsewhere.

property tlvl : me
property currentProcessName : ""
property histList : {"No Process names entered."}
property scriptTitle : "Pid list."
global executableIcon
script getpids
	local thNm, res
	set {thNm, res} to {false, false, "", false}
	
	tell application id "sevs"
		if UI elements enabled is not true then
			set UI elements enabled to true
		end if
		set thNm to name of item 1 of (every application process whose visible is true and frontmost is true)
	end tell
	repeat while res = false
		tell application thNm to activate
		
		set executableIcon to a reference to file ((path to library folder from system domain as text) & "CoreServices:CoreTypes.bundle:Contents:Resources:ExecutableBinaryIcon.icns")
		try
			tell current application
				activate
				
				set {tlvl's currentProcessName, tbutton, givenUP} to {text returned, button returned, gave up} of (display dialog "Enter Process name" with title "Proces Id's" default answer tlvl's currentProcessName buttons {"History", "Cancel", "Ok"} default button 3 with icon executableIcon giving up after 120)
			end tell
			if givenUP then error number 3000
		on error e number n
			tell application thNm to activate
			tell application id "sevs"
				click window 1 of application process thNm
			end tell
			error number -128
		end try
		if tbutton = "History" then
			
			tell current application
				activate
				try
					with timeout of 120 seconds
						
						set formerProcessIds to choose from list tlvl's histList default items item 1 of tlvl's histList with title scriptTitle
					end timeout
				on error e number n
					tell application thNm to activate
					tell application id "sevs"
						click window 1 of application process thNm
					end tell
					error number -128
				end try
			end tell
			
			if formerProcessIds is not false and formerProcessIds = {"No Process names entered."} then set formerProcessIds to false
			
			
			if formerProcessIds = false then
				tell application thNm to activate
				tell application id "sevs"
					click window 1 of application process thNm
				end tell
				try
					tell current application
						activate
						display dialog "Do you want to enter one after all?" with title scriptTitle with icon executableIcon giving up after 120
						if gave up of the result then error number 3000
					end tell
				on error e number nu
					tell application thNm to activate
					tell application id "sevs"
						click window 1 of application process thNm
					end tell
					error number -128
				end try
				try
					tell current application
						activate
						set {tlvl's currentProcessName, gaveUp} to {text returned, gave up} of (display dialog "Enter process name" with title scriptTitle default answer tlvl's currentProcessName with icon executableIcon giving up after 120)
						if gaveUp then error number 3000
					end tell
				on error e number nu
					tell application thNm to activate
					tell application id "sevs"
						click window 1 of application process thNm
					end tell
					error number -128
				end try
				
			else
				set tlvl's currentProcessName to formerProcessIds as text
				if tlvl's currentProcessName = "No process name  entered." then
					tell application thNm to activate
					tell application id "sevs"
						click window 1 of application process thNm
					end tell
					error number -128
				end if
			end if
		end if
		set pidof to quoted form of POSIX path of ((path to me as text) & "Contents:Resources:pidof")
		set res to (do shell script pidof & " " & quoted form of tlvl's currentProcessName)
		if res ≠ "" then
			
			if "No Process names entered." is in tlvl's histList then
				set tlvl's histList to rest of tlvl's histList
			end if
			if tlvl's currentProcessName is not in tlvl's histList then
				set end of tlvl's histList to tlvl's currentProcessName
			end if
			set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
			set pidList to items 1 thru -2 of text items of res
			set AppleScript's text item delimiters to tids
			tell application "SystemUIServer"
				activate
				set tokill to (choose from list pidList default items (item 1 of pidList) with prompt "choose one or more processes to terminate" with title "Pidoff" with multiple selections allowed)
			end tell
			if tokill is not false then
				set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
				set tokill to tokill as text
				set AppleScript's text item delimiters to tids
				do shell script "kill -9 " & tokill
			end if
		end if
		tell application thNm to activate
		tell application id "sevs"
			click window 1 of application process thNm
		end tell
	end repeat
	# error number -128
	return "done"
end script
on run
	tell getpids to run
	quit
end run


The Universal Access thing is on. Can someone explain the log for one of the scripts that should work? The log says it closed!

HAHAHAAAAA!!! Solved it

It doesn’t like full screen windows! Now can anyone offer a fix?

Hello.

I think you’ll be able to circumvent the problem, now that it is identified. :wink:

The thing is I have no idea about scripting full screen windows. What’s the difference?

Hello.

I was more thinking that you’ll just leave full screen mode before running the script.

Hey Richard,

Theoretically there should be no practical difference, but this is the Mac OS… For instance Safari loses its front-window reference when the app is hidden, and this makes scripting it reliably more difficult.

It would appear that Safari windows in Spaces will respond to do javascript calls:

tell application "Safari"
	tell (first window whose name contains "Google")
		do JavaScript "window.close()" in tab 1
	end tell
end tell

In this case my only window with Google in the name is in full-screen mode and has two tabs. The script closes tab-index-1 in that window.

Someone with enough Javascript could probably do this very efficiently, but I think this should give you the tools to accomplish it with mostly Applescript.

Hey Richard,

Okay, I fiddled with it a little more. This works on my machine whether the tab is in a full-screen window or not:

set tabName to "Google"
tell application "Safari"
	set winList to (windows where its document is not missing value)
	repeat with _win in winList
		set tabIndex to (index of tabs of _win where its name is tabName)
		repeat with j in tabIndex
			do JavaScript "window.close()" in tab j of _win
		end repeat
	end repeat
end tell

Now that was a great solution! :slight_smile: It newer occured to me that javascript could circumvent it.

This looks very clever but sadly it didn’t work! The javascript returned a missing value, is that useful?
PS - I am sure that it found the correct tab and sent the java to it.

Hi Chris.

As I noted somewhere above, when closing, deleting, or otherwise removing application objects referred to by predetermined indices, you have to start with the higher indices, because each time an object’s removed, the ones after it are immediately renumbered.

-- .
		set tabIndex to (index of tabs of _win where its name is tabName)
		repeat with j in reverse of tabIndex -- Work through the indices from highest to lowest.
			do JavaScript "window.close()" in tab j of _win
		end repeat
-- .

Or I suppose one could work from the beginning and maintain a compensation variable: :slight_smile:

-- .
		set tabIndex to (index of tabs of _win where its name is tabName)
		set tabsClosed to 0
		repeat with j in tabIndex
			do JavaScript "window.close()" in tab (j - tabsClosed) of _win
			set tabsClosed to tabsClosed + 1
		end repeat
-- .

Still gives missing value :frowning:

Hello. This works for me, hopefully it will work for you as well. :wink:

property tabname : "Facebook"
on run
	script o
		property l : {}
	end script
	tell application "Safari"
		set o's l to every window where its document is not missing value
		
		repeat with t from 1 to (count o's l)
			tell item t of o's l
				set n to count tabs
				repeat with i from n to 1 by -1
					if name of tab i of item t of o's l is my tabname then
						tell item t of o's l
							try
								tell tab i to do JavaScript "window.close()"
							end try
						end tell
					end if
				end repeat
			end tell
		end repeat
	end tell
end run

Thank you so much for being so patient with my problem and trying to fix it, I appreciate it.

(Still not working)

Hello.

I am not trying to be funny, but you do have javascript enabled, don’t you? You sure would if you where connecting to Facebook.

I wonder if you can produce a log over what happens when in fullscreen mode and you run the script.

I’ll see if I can make it work better in the mean time.

Hello.

See if this works: if this doesn’t work for you, then I really don’t know what to do. (Rhyme, soon rhum :smiley: )

property tabname : "Facebook"
on run
	script o
		property l : {}
	end script
	tell application "Safari"
		set o's l to every window where its document is not missing value
		
		repeat with t from 1 to (count o's l)
			tell item t of o's l
				set n to count tabs
				repeat with i from n to 1 by -1
					if name of tab i of item t of o's l is my tabname then
						tell item t of o's l
							tell tab i to do JavaScript "self.focus"
							do JavaScript "window.close()" in tab i
						end tell
					end if
				end repeat
			end tell
		end repeat
	end tell
end run