Safari Tabs Window

Hi,

I’d like to make a window for Safari like Chrome’s “Task Manager” - a window listing All tabs in All windows, so you could jump to any one at a click. Here’s my first attempt (which gets the -10000 event handler error)

[code]try
tell application “Safari”
activate
– set numWindows to count windows
– set numTabs to 0
– set tabName[]

	set tabsList to {}
	set windowList to every window
	
	set pageContent to "<html><body>" & linefeed
	repeat with thisWindow in windowList
		set myName to the name of thisWindow
		if myName is not "" then
			set myTabs to every tab of thisWindow
			copy myTabs to the end of tabsList
			set numTabs to count of myTabs
			-- display dialog "There are " & numTabs & " tabs in window " & name of thisWindow buttons {"OK"} default button {"OK"}
			repeat with thisTab in myTabs
				set tabName to the name of thisTab
				set tabURL to the URL of thisTab
				set pageContent to (pageContent & "<a href=" & (tabURL as text) & ">" & tabName & "</a><br>" & linefeed)
			end repeat
		end if
	end repeat
	set pageContent to (pageContent & "</body></html>")
	-- set numTabs to count of tabsList
	-- display dialog "There are " & numTabs & " tabs in Safari " buttons {"OK"} ¬
	--	default button {"OK"}
	try
		make new document at end of documents with properties {name:"Safari Tabs", source:pageContent}
	on error error_message
		activate
		display dialog error_message buttons {"OK"} default button 1
	end try
end tell

on error error_message
activate
display dialog error_message buttons {“OK”} default button 1
end try[/code]

Hello.

Have a look at this. You’ll get a list of all tabs if you don’t enter any search string, regular expressions is allowed, and it searches both the url, and the tabname, fast, thanks to Nigel Garvey. It even tells you that the tab is in another space.

Caveat: Not idiot proof, it fails if the downloads window is in front, or you have no windows open in Safari.

Well, McUsrII, I appreciate your suggestion. But it might be more helpful to understand why my approach is failing and how to make it work.

The error occurs because the source property is read only

Hi murkie. Welcome to MacScripter.

I also get an error from your script which is caused trying to get the tabs of an invisible, tabless “Bookmarks” window which Safari appears to have. I’ve coded round this in the adaptation of your script below.

As a work-round to the ‘new document’ problem, you could write your HTML to a temporary file and have Safari open the file. This works for me, but it may be because my Safari preferences are set to open things in new tabs.

Unfortunately, clicking the links shown in the new tab opens yet more tabs instead of going to the existing ones. You may be able to achieve what you want by writing the links in “applescript” protocol instead of “http” and using them to trigger another, suitably set-up script (or more code in the same script) which makes Safari switch to the existing tabs instead of connecting to the remote sites again. I’ve never tried this myself, but there’s a tutorial here if you fancy it as a project.

MacScripter’s BBCode has [applescript] and [/applescript] tags which you can put round your script code when posting it to make it appear as below. It’s considered good practice to use these. The “Open this Scriplet in your Editor:” link in the resulting script display uses the “applescript” protocol I mentioned above to open the script in your default script editor. (This is already set up. You don’t need to do anything special in this case.)

The correct forum here for posting queries about AppleScript code is AppleScript | Mac OS X. “Code Exchange” is for sharing working code or techniques which you think may be useful to others.

try
	tell application "Safari"
		activate
		-- set numWindows to count windows
		-- set numTabs to 0
		-- set tabName[]
		
		set tabsList to {}
		set windowList to windows where its document is not missing value -- 'its' or 'of it' necessary to avoid confusion with the 'document' class.
		
		set pageContent to "<html><body>" & linefeed
		repeat with thisWindow in windowList
			set myName to the name of thisWindow
			if myName is not "" then
				set myTabs to every tab of thisWindow
				copy myTabs to the end of tabsList
				set numTabs to count of myTabs
				-- display dialog "There are " & numTabs & " tabs in window " & name of thisWindow buttons {"OK"} default button {"OK"}
				repeat with thisTab in myTabs
					set tabName to the name of thisTab
					set tabURL to the URL of thisTab
					set pageContent to (pageContent & "<a href=" & (tabURL as text) & ">" & tabName & "</a><br>" & linefeed)
				end repeat
			end if
		end repeat
		set pageContent to (pageContent & "</body></html>")
		
		-- Write the HTML to a temporary file.
		set tempFilePath to (path to temporary items as text) & "Safari Tabs.html"
		set accessRef to (open for access file tempFilePath with write permission)
		try
			set eof accessRef to 0
			write pageContent to accessRef
		end try
		close access accessRef
		
		-- Open the file in Safari.
		open file tempFilePath
		
		-- set numTabs to count of tabsList
		-- display dialog "There are " & numTabs & " tabs in Safari " buttons {"OK"} ¬
		-- default button {"OK"}
	end tell
on error error_message
	activate
	display dialog error_message buttons {"OK"} default button 1
end try

Well. I thought it was interesting enough to make it a weekend project of my own. Here in the spirit of Code Exchange is what I got.

It turns out that the “applescript” protocol I mentioned is already claimed by the default AppleScript editor on one’s computer, so you have to invent your own. The script below periodically scans the tabs in all suitable Safari windows and creates an HTML page in the same way as murkie’s script. However, the URLs in it are of the “safaritabchooser:” protocol, which I’ve invented. Its form is:


. where and should be replaced by respectively a Safari window ID and the URL of a page displayed in a tab of that window. I used murkie’s name in the bundle identifier as it’s unique on my machine. Professional developers will no doubt want to use their own personal identifiers.

The ‘open location’ handler in the script receives a URL from the operating system when a “safaritabchooser:” link is clicked and it tells Safari to display the relevant tab. For the script to receive these URLs, it has to claim the “safaritabchooser:” protocol, and this is arranged by adding details to the Info.plist file in its bundle’s “Contents” folder.

So first save the script as a stay-open application. The script code can be altered later if necessary, but the initial creation of the applet must be in the final form. If it’s resaved as stay-open when it originally wasn’t, the edits about to made in its Info.plist file will be lost.

-- This is two scripts in one applet.
-- The 'idle' handler calls the 'updateTabBookmarks()' handler, which creates and/or updates a "Tab Bookmarks" window in Safari.
-- The 'open location' handler receives a URL from the system when one of the custom-protocol links in the window is clicked. It analyses the URL and tells Safari to display the relevant tab.

-- The script should be saved as a stay-open application and then its "Info.plist" file edited as described elsewhere to set up its custom "safaritabchooser:" URL protocol.

-- Based on a script idea by "murkie" <http://macscripter.net/viewtopic.php?pid=161636#p161636>
------------------------------------------

-- CREATE OR UPDATE A "TAB BOOKMARKS" WINDOW.

on idle
	-- If Safari's open, check the tabs in all its applicable windows and create or update a "Tab Bookmarks" window accordingly. Idle for ten seconds between rounds.
	-- Otherwise idle for two minutes between tests for Safari being open.
	
	tell application "System Events" to set SafariOpen to (application process "Safari" exists)
	
	if (SafariOpen) then
		updateTabBookmarks()
		return 10
	else
		return 2 * minutes
	end if
end idle

on updateTabBookmarks()
	set tabBookmarkWindowName to "Tab Bookmarks"
	-- The HTML for the "Tab Bookmarks" window can't be inserted directly into Safari and will have to be saved to a temporary file.
	set tempFilePath to (path to temporary items as text) & tabBookmarkWindowName & ".html"
	
	-- We'll use a unique HTML comment for positive identification of the "Tab Bookmarks" tab when updating.
	set tabBookmarkHTMLComment to "<!--- MURKIE'S TAB BOOKMARKS --->"
	
	try
		-- Get the names and URLs of all Safari's existing tabs and the IDs of its windows. Unsuitable windows without tabs will be ignored below.
		tell application "Safari" to set {{tabNames, tabURLs}, windowIDs} to {{name, URL} of tabs, id} of windows
		
		-- Build a simple HTML page source containing clickable links to the tabs with URLs in our custom protocol. The links are grouped by window and the Tab Bookmark tab itself is not included. The urls are in the form:
		-- safaritabchooser://com.murkie.SafariTabChooser?windowid=<ID>&taburl=<URL>.
		set pageContent to "<html><head><title>" & tabBookmarkWindowName & "</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>" & linefeed & tabBookmarkHTMLComment & linefeed
		set tabBookmarksExist to false
		repeat with i from 1 to (count tabNames)
			set theseTabNames to item i of tabNames
			if (theseTabNames is not {}) then
				set theseTabURLs to item i of tabURLs
				set thisWindowID to item i of windowIDs
				repeat with j from 1 to (count theseTabNames)
					set notTabBookmarkTab to true
					set thisTabName to item j of theseTabNames
					if (thisTabName is tabBookmarkWindowName) then
						set tabBookmarkTabURL to item j of theseTabURLs
						set tabBookmarkWindowID to thisWindowID
						tell application "Safari" to set thisTabSource to (source of first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL)
						set tabBookmarksExist to (paragraph 2 of thisTabSource is tabBookmarkHTMLComment)
						set notTabBookmarkTab to (not tabBookmarksExist)
					end if
					if (notTabBookmarkTab) then
						set pageContent to pageContent & "<a href=safaritabchooser://com.murkie.SafariTabChooser?windowid=" & thisWindowID & "&taburl=" & item j of theseTabURLs & ">" & thisTabName & "</a><br>" & linefeed
					end if
				end repeat
				if ((notTabBookmarkTab) or (j > 1)) then set pageContent to pageContent & "<br>" & linefeed
			end if
		end repeat
		set pageContent to (pageContent & "</body></html>")
		
		-- Write the HTML to a temporary file.
		set accessRef to (open for access file tempFilePath with write permission)
		try
			set eof accessRef to 0
			write pageContent as «class utf8» to accessRef
		end try
		close access accessRef
		
		-- Get the file's URL and open it in Safari ” in the existing Tab Bookmarks window if there is one; in a new one if not.
		tell application "System Events" to set u to URL of disk item tempFilePath
		
		tell application "Safari"
			if (tabBookmarksExist) then
				set URL of (first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL) to u
			else
				make new document with properties {URL:u}
				set bounds of window 1 to {1125, 180, 1440, 800} -- Adjust as required.
			end if
		end tell
	on error error_message
		displayError(error_message)
	end try
end updateTabBookmarks


-- HANDLE THE URL ISSUED WHEN A TAB BOOKMARK IS CLICKED.

on open location this_url
	-- Handle a URL with our custom protocol, passed to the script by the system.
	-- Parse it for the window ID and tab URL and get Safari to act accordingly.
	-- As a reminder, the form of the URL is:
	-- safaritabchooser://com.murkie.SafariTabChooser?windowid=<ID>&taburl=<URL>.
	
	-- It's assumed the ID will come before the URL, but the code can cope with the URL not being given should it ever be decided to add the facility just to bring a window to the front without going to a particular tab.
	
	try
		set c to (offset of "&taburl=" in this_url)
		if (c > 0) then
			set tabURL to text (c + 8) thru -1 of this_url
		else
			set tabURL to missing value
		end if
		set windowID to (text ((offset of "?windowid=" in this_url) + 10) thru (c - 1) of this_url) as integer
		
		tell application "Safari"
			activate
			tell window id windowID
				if (it exists) then
					-- AppleScript can only focus a Safari 5.1.8 window by flicking its visibility off and on again, which looks bad. The JavaScript focus() function smoothly focuses both window and tab, but only if the tab's been in focus before! The trick appears to be to use JavaScript to focus the window in the current tab and then switch tabs with AppleScript.
					do JavaScript "window.focus()" in current tab
					if ((tabURL is not missing value) and (URL of tabs contains tabURL)) then set current tab to first tab whose URL is tabURL
				end if
			end tell
		end tell
	on error error_message
		displayError(error_message)
	end try
end open location


on displayError(msg)
	tell application (path to frontmost application as text)
		display dialog msg buttons {"OK"} default button 1 with title "Safari Tab Chooser" with icon caution
	end tell
end displayError

Ignore the “Bundle Contents” button in AppleScript Editor. Instead, control-click the applet file wherever it’s been saved and select “Show Package Contents” from the contextual menu. A window should appear showing the Contents folder. In this is the Info.plist file, which should be opened in a plain text editor like TextWrangler or possibly TextEdit.

Here’s what my plist text looked like after I’d added the extra details. I’ve coloured my bits red here for clarity, but of course they shouldn’t be coloured in the plist file! The keys are presumably mandatory, but the strings can be whatever you decide in the given format. I used murkie’s posting name in the bundle identifier, because using “apple” as in the tutorial caused another stay-open applet I have to come to the front whenever relevant links were clicked. Presumably it was being passed the URLs, but that particular script wouldn’t know a URL if it met one in the street. The one string in the CFBundleURLSchemes array is the protocol name I chose with which to head the URLs.

I typed the addtional stuff at the top of the main dict, as shown. But after the script had been run once, everything had been resorted alphabetically by key.

In theory, the protocol recognition should be effective from the moment the script’s first run, but you may find you need to try a few things first like quitting any other script applets or (according to one theory I read on the Web) move the applet to another folder to get the system to notice it.

There are several cosmetic improvements one would want to make to what’s presented on screen, but this is just to crack the nut of getting a script to respond to dedicated links in a Web browser.

Edit: Now uses a simple JavaScript function to bring the appropriate window to the front, in focus, and with the required tab displayed.
Edit 2: Dropped “AppleScript.” from the bundle identifier. Slightly reduced the size of the tab link window. Worked round the unreliability of the JavaScript function. Expanded the HTML to give the Tab Bookmarks window a definite title and to recognise UTF-8 Unicode text. The temporary file is now also written as «class utf8».

Hello.

It seems appropriate to add to Nigel’s excellent project, that you can indeed have javascripts installed on your bookmark bar, that calls such a non-standard protocol, providing another interface for an application that works closely with Safari. in fact giving you the same close interfacing with Safari, as a Safari plugin. ( I am a huge fan of a plugin called Sessions, that present all webpages and tabs in a single window, it has a sidebare, like the read later facility, so you can choose what session, (organized by date), to choose from. )

I am seriously considering such an approach, since I actually sometimes ends up with like 250 tabs in my browser. The downside for me right now, is that the number of tabs aren’t persistant, and that the output adds to the tab count, I am still processing the approach however, for there are upsides to this as well, making a whole slew of sought for functionality available for Safari. :slight_smile:

If someone should be interested in watching a full blown example of an app, that is triggered by bookmarks of javascript, then skip over to MacOSAutomation.com, and look for linktrigger.

Edit

Using your own protocol with such an app that is registred for said protocol, also enables you to provide cheap and different interfaces, that aren’t dependent of safari or any other browser, as you can launch the generated html file with qlmanage -p. The links in the webpage, referencing your protocol, should still work. :slight_smile:

Edit+

I had to test if it acutally worked, by clicking a link, since it sunk in over me that I had just tested links that would open in a browser earlier, and just local anchors.

So I used the command line qlmanage -p qlmandemo.html in a terminal window, on the html below that I saved as qlmandemo.html, and it worked! I do take that as a proof of qlmanage invoking the launchd service with clickable links from a webpage, so a homegrown protocol should work equally well from this interface as well.

What I haven’t tried, is to set the size of the window with css, maybe that works too. :slight_smile: Colors and fonts works with CSS from qlmanage however, so the interface to a “protocol-app” can be made good looking.

[code]

QLmanage Demo Go to Macscripter [/code] [b]Edit++[/b]

There is nothing that would hinder you to build a really beautiful interface to an applescript “protocol-app”, by using dashcode, providing you have the resources for it, as dashboard widgets are rather expensive, -but can be truly good looking.

I’ve just edited my script to use a single JavaScript command instead of the AppleScript three (including an invisible/visible hack) to bring the target window to the front in focus with the required tab displayed. The effect is much more pleasing. Is it possible for JavaScripts triggered by links in one window to affect other windows? That would of course make the whole custom protocol discussion here obsolete. :rolleyes:

I think nothing is impossible, as you indeed can inject javascript into a page, an evenhandler, and then trigger that javascript from another page. Now, how I would commence to get that javascript injected, by only using javascript, I am unsure of as I don’t have overview over to what extent Safari support javascript, as a scripting language.

Maybe this page may give you some answers.

Javascript is difficult to debug when you start out, so I recommend getting a lint function for BBEdit, or a whole Javascript development environment. It may save time, when you have to track that “;” down.

I would have thought the sandboxing in recent versions would have ruled that out.

I think that maybe updating the plist file of the applet with a new (higher) version number should help. But you must of course quit the old one, and re-register it. Adding a higher number to the end of its name should also work, according to Apples documentation. (Property list key reference?). Here is a script for setting the version number from within Applescript Editor when the main.scpt is the frontmost document.

Pardon this diversion from the main thread, but I have a JavaScript bookmark that I use to get a page in Readability form (which I prefer to Safari’s “Reader” button).

javascript:(function()%7BreadStyle='style-novel';readSize='size-large';readMargin='margin-wide';_readability_script=document.createElement('SCRIPT');_readability_script.type='text/javascript';_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());document.getElementsByTagName('head')%5B0%5D.appendChild(_readability_script);_readability_css=document.createElement('LINK');_readability_css.rel='stylesheet';_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';_readability_css.type='text/css';_readability_css.media='screen';document.getElementsByTagName('head')%5B0%5D.appendChild(_readability_css);_readability_print_css=document.createElement('LINK');_readability_print_css.rel='stylesheet';_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')%5B0%5D.appendChild(_readability_print_css);%7D)();

or, more legibly in full script form (which I use with a hot key):

(*
The following JavaScript from Arc90 "makes reading on the web more enjoyable by removing the clutter around what you're reading" and the Readability site allows you to set Style, Size and Margin in the material. It is normally used by dragging a link from the Readability page to your Bookmarks Bar, and that puts the JavaScript below as the content of the bookmark. The page thus created in your browser has a link on it to return to the original source.

Visit "http://lab.arc90.com/experiments/readability/" for your own copy.

Because I'm an avid Quicksilver fan (but there are lots of alternatives), I prefer to set up a trigger to run the script below so I can enhance the readability of an article I'm looking at with a simple key combination. Although it cannot render every site I visit, it does remarkably well.
-- Note that the script below has been altered for readability. The original is all one string.
*)

set JS to "readStyle='style-novel';
	readSize='size-large';
	readMargin='margin-wide';
	_readability_script=document.createElement('SCRIPT');
	_readability_script.type='text/javascript';
	_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());
	document.getElementsByTagName('head')[0].appendChild(_readability_script);
	_readability_css=document.createElement('LINK');
	_readability_css.rel='stylesheet';
	_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';
	_readability_css.type='text/css';
	_readability_css.media='screen';
	document.getElementsByTagName('head')[0].appendChild(_readability_css);
	_readability_print_css=document.createElement('LINK');
	_readability_print_css.rel='stylesh  eet';
	_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';
	_readability_print_css.media='print';
	_readability_print_css.type='text/css';
	document.getElementsByTagName('head')[0].appendChild(_readability_print_css);"

tell application "System Events" to set last_app to item 1 of (get name of processes whose frontmost is true)
if last_app is "Safari" then
	tell document 1 of application "Safari" to do JavaScript JS
else if last_app is "NetNewsWire" then
	tell document 1 of application "NetNewsWire" to do JavaScript JS
else
	beep 3
end if

Wow, I really appreciate everyone’s help here. I’d like to share my most recent implementation. I’ve based this on the work of Nigel Garvey. I’ve polished up the resulting window, here’s how I like it:


-- This is two scripts in one applet.
-- The 'idle' handler calls the 'updateTabBookmarks()' handler, which creates and/or updates a "Tab Bookmarks" window in Safari.
-- The 'open location' handler receives a URL from the system when one of the custom-protocol links in the window is clicked. It analyses the URL and tells Safari to display the relevant tab.

-- The script should be saved as a stay-open application and then its "Info.plist" file edited as described elsewhere to set up its custom "safaritabchooser:" URL protocol.

-- Based on a script idea by "murkie" <http://macscripter.net/viewtopic.php?pid=161636#p161636>
------------------------------------------

-- CREATE OR UPDATE A "TAB BOOKMARKS" WINDOW.

on idle
	-- If Safari's open, check the tabs in all its applicable windows and create or update a "Tab Bookmarks" window accordingly. Idle for ten seconds between rounds.
	-- Otherwise idle for two minutes between tests for Safari being open.
	
	tell application "System Events" to set SafariOpen to (application process "Safari" exists)
	
	if (SafariOpen) then
		updateTabBookmarks()
		return 10
	else
		return 2 * minutes
	end if
end idle

on updateTabBookmarks()
	-- The HTML for the "Tab Bookmarks" window can't be inserted directly into Safari and will have to be saved to a temporary file, whose name will set the name of the window.
	set tempFileName to "SafariTabs.html"
	-- We'll use a unique HTML comment for positive identification of the "Tab Bookmarks" tab when updating.
	set bookmarksHTMLComment to "<!--- MURKIE'S TAB BOOKMARKS --->"
	
	try
		-- Get the names and URLs of all Safari's existing tabs and the IDs of its windows. Unsuitable windows without tabs will be ignored below.
		tell application "Safari" to set {{tabNames, tabURLs}, windowIDs} to {{name, URL} of tabs, id} of windows
		
		-- Build a simple HTML page source containing clickable links to the tabs with URLs in our custom protocol. The links are grouped by window and the Tab Bookmark tab itself is not included. The urls are in the form:
		-- safaritabchooser://com.murkie.AppleScript.SafariTabChooser?windowid=<ID>&taburl=<URL>.
		set pageContent to "<html>" & linefeed & bookmarksHTMLComment & linefeed & "<head><style>a {color:#09c; font-size:11px; font-family:verdana, arial, helvetica, sans-serif; 
	font-weight:600;  text-decoration:none;} a:link {color:#09c;} a:visited {color:#07a;} a:hover {background-color:#eee;}</style></head><body><table>" & linefeed
		set tabBookmarksExist to false
		set rowCount to 1
		repeat with i from 1 to (count tabNames)
			set theseTabNames to item i of tabNames
			if (theseTabNames is not {}) then
				set theseTabURLs to item i of tabURLs
				set thisWindowID to item i of windowIDs
				repeat with j from 1 to (count theseTabNames)
					set notBookmarkTab to true
					set thisTabName to item j of theseTabNames
					if (thisTabName is tempFileName) then
						set tabBookmarkTabURL to item j of theseTabURLs
						set tabBookmarkWindowID to thisWindowID
						tell application "Safari" to set thisTabSource to (source of first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL)
						-- set myParagraphs to paragraphs of thisTabSource
						-- displayError(myParagraphs)
						set tabBookmarksExist to (paragraph 2 of thisTabSource is bookmarksHTMLComment)
						set notBookmarkTab to (not tabBookmarksExist)
					end if
					if (notBookmarkTab) then
						if (rowCount mod 2 = 0) then
							set rowColor to "#aaaaff"
						else
							set rowColor to "#aaffaa"
						end if
						set linkText to "<tr bgcolor=" & rowColor & "><td><a href=safaritabchooser://com.murkie.AppleScript.SafariTabChooser?windowid=" & thisWindowID & "&taburl=" & item j of theseTabURLs & ">" & thisTabName & "</a></td><tr>"
						set pageContent to pageContent & linkText & linefeed
						set rowCount to rowCount + 1
					end if
				end repeat
				if ((notBookmarkTab) or (j > 1)) then set pageContent to pageContent & "<br>" & linefeed
			end if
		end repeat
		set pageContent to (pageContent & "</table></body></html>")
		
		-- Write the HTML to a temporary file.
		set tempFilePath to (path to temporary items as text) & tempFileName
		set accessRef to (open for access file tempFilePath with write permission)
		try
			set eof accessRef to 0
			write pageContent to accessRef
		end try
		close access accessRef
		
		-- Get the file's URL and open it in Safari ” in the existing Tab Bookmarks window if there is one; in a new one if not.
		tell application "System Events" to set u to URL of disk item tempFilePath
		
		tell application "Safari"
			if (tabBookmarksExist) then
				set URL of (first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL) to u
			else
				make new document with properties {URL:u}
				set bounds of window 1 to {900, 280, 1440, 900} -- Adjust as required.
			end if
		end tell
	on error error_message
		displayError(error_message)
	end try
end updateTabBookmarks


-- HANDLE THE URL ISSUED WHEN A TAB BOOKMARK IS CLICKED.

on open location this_url
	-- Handle a URL with our custom protocol, passed to the script by the system.
	-- Parse it for the window ID and tab URL and get Safari to act accordingly.
	-- As a reminder, the form of the URL is:
	-- safaritabchooser://com.murkie.AppleScript.SafariTabChooser?windowid=<ID>&taburl=<URL>.
	
	-- It's assumed the ID will come before the URL, but the code can cope with the URL not being given should it ever be decided to add the facility just to bring a window to the front without going to a particular tab.
	
	try
		set c to (offset of "&taburl=" in this_url)
		if (c > 0) then
			set tabURL to text (c + 8) thru -1 of this_url
		else
			set tabURL to missing value
		end if
		set windowID to (text ((offset of "?windowid=" in this_url) + 10) thru (c - 1) of this_url) as integer
		
		tell application "Safari"
			activate
			tell window id windowID
				if (it exists) then
					-- JavaScript does a better job than AppleScript here.
					if ((tabURL is missing value) or (URL of tabs does not contain tabURL)) then
						do JavaScript "window.focus()" in current tab
					else
						do JavaScript "window.focus()" in first tab whose URL is tabURL
					end if
				end if
			end tell
		end tell
	on error error_message
		displayError(error_message)
	end try
end open location


on displayError(msg)
	tell application (path to frontmost application as text)
		display dialog msg buttons {"OK"} default button 1 with title "Safari Tab Chooser" with icon caution
	end tell
end displayError

And make sure you don’t forget the Info.plist mods described in his post.

Hi murkie.

Glad the ideas helped. Thanks for posting your own version.

I’ve edited my script (post #6 above) a couple of times since posting it, based on my experience with it. Of interest to you may be that the HTML is now written to file and understood as UTF-8 Unicode and the opening of tabs is more reliable. (On my machine, the JavaScript doesn’t work with tabs which haven’t been focused before, such as when “Open in Tabs” has been selected in a bookmark menu.)

Hi, folks! I’ve just updated Safari to 6.1.1 and now I observe my TabsWindow is no longer able to link back to the tab I want when I click. Has anyone studied the documentation updates to learn some new behavior?

Has anyone else using custom protocols like Nigel described noticed that they stop working in Mavericks? My AppleScript applet has handled the protocol ‘htclink’ without trouble for several years now, but my system is now reporting:

Not sure if this is true for everyone, or just some. At least one other person has had this problem: http://veritrope.com/code/outlook-2011-to-evernote/

I’m going to ask him if he found a fix/workaround.

I’m having the same problem, but I have had to stall it at the moment.

I am going to have a serious look into the lauchservices file, and see what is there, or not. This was allways rather clunky, when it got to register the applet, so I deem it possible that it still may work. :slight_smile:

Edit

I’m not working on this right now, but I have figured out, that the app must have the role of browser specified in the property list file.

It also helps to increase the build version number (short bundle version string), when you reregister the app.

And, it beats me, that maybe they prohibit it, as a security measure along the lines of sandboxing, and like redirecting to other sites for “cross browser attack”. But, at least I’ll try when I find the time, to make this work again, because it was very useful, and cool.