Jump to content

Apple script and browser tabs

Recommended Posts

Hi everyone,


I would like to make a script that does the following:



IF current tab of Safari is not tab 1, bring Safari to forefront and switch to tab 1.

IF (Safari is currently in focus) AND (tab 1 is the current tab) THEN hide window


Also to start Safari if it is not running at all.


I would then also make a similar script for tab 2 and tab 3. The idea is that I can make a webapp "feel" almost as a desktop app by opening op when I press hotkey, hiding when I press hotkey again (Like Alfred's "Toggle visibility for app"), BUT if I already have Safari in focus but I just want to switch from tab A to tab B, not hide Safari.


What I got so far form various googling:

on alfred_script(q)
set appName to "Safari"
set startIt to false
tell application "System Events"
tell window 1 of application "Safari" to set current tab to tab 1
    if not (exists process appName) then
        set startIt to true
    else if frontmost of process appName then
        set visible of process appName to false
        set frontmost of process appName to true
    end if
end tell
if startIt then
    tell application appName to activate
end if
end alfred_script

It works. All I'm missing is to change this line:

else if frontmost of process appName then

Into something like this:

else if frontmost of process appName AND if current tab is 1 then

How do I do this? So close now!  :)


Link to comment

I think what you were missing is index of current tab. That's how you get a number, not a tab object.


If I've understood you correctly, this should do what you want. I've rewritten the script extensively because the behaviour you want is a little complicated, and it's easier to reason about if you separate the "business logic" from the actual actions. This way, my toggleActiveTab() function, which is the bit that implements the behaviour you want, is fairly simple.

This function is called when you run the script from the command line, e.g.:
	osascript "Safari Tabs.scpt" 2
will activate tab 2 of the frontmost Safari window.
on run (argv)
	set tabIndex to item 1 of argv as integer
	my toggleActiveTab(tabIndex)
end run

This function is called when the script is run from within an
Alfred Run NSAppleScript Action.

q is the query you entered in Alred's query box. It is a string.
Convert it to a number and run the script.
on alfred_script(q)
	set tabIndex to q as integer
	my toggleActiveTab(tabIndex)
end alfred_script

If Safari is the active application and the specified tab is the current one,
hide Safari.

Otherwise, activate Safari and make the specified tab the current one.
on toggleActiveTab(tabIndex)
	set activeAppName to my getActiveApp()
	log activeAppName & " is the active application"
	-- First we want to hide Safari if it is currently active and current tab is tabIndex
	if activeAppName = "Safari" then
		set activeTab to my getActiveSafariTab()
		if activeTab = tabIndex then
			my hideApplication("Safari")
			-- Our job is done; exit script
		end if
	end if
	-- Safari isn't active and/or tabIndex isn't the current tab, so
	-- activate Safari (if necessary) and set current tab to tabIndex
	activate application "Safari"
	my setActiveSafariTab(tabIndex)
end toggleActiveTab

-- Return the name of the active application
on getActiveApp()
	tell application "System Events" to set activeApp to first process where it is frontmost
	return name of activeApp
end getActiveApp

-- Return the index of the current tab in Safari's frontmost window
on getActiveSafariTab()
	tell application "Safari" to return index of current tab of front window
end getActiveSafariTab

-- Set the active tab of Safari's frontmost window
on setActiveSafariTab(tabIndex)
	tell front window of application "Safari" to set current tab to tab tabIndex
end setActiveSafariTab

-- Hide the specified application
on hideApplication(appName)
	tell application "Finder" to set visible of process appName to false
end hideApplication

Edited by deanishe
Link to comment

deanishe, thanks for all the work you put into it! I'm going to use the script together with a hotkey trigger - not a keyword input (perhaps I should've been more clear about that. How do I use the script with a hotkey and just hardcoding q as e.g. 1?


I tried putting q = 1 at the top of the script and running it, but that didn't do it. So how?


Sorry I'm not so familiar with AppleScript :)

Link to comment

AppleScript sucks, tbh. Really sucks.
The way Alfred runs NSAppleScripts is that it calls the alfred_script(q) function, passing in its query as q.
So if you're running it from within Alfred, change the line within alfred_script(q) from: 

set tabIndex to q as integer


set tabIndex to 1

Similarly, if you're running it from the command line, change the corresponding line in run(argv) (which is the normal entry point when you run a script) from:

set tabIndex to item 1 of argv as integer


set tabIndex to 1

Or in either cases, just use: my toggleActiveTab(1)
That said, I deliberately wrote it so it takes an argument because you said you were planning to do the same for tabs 2 and 3.

It's rather bad form to create multiple copies of a script if you can avoid it: if you find a bug or want to change/improve something, you have to edit multiple, effectively identical scripts.

A better idea would be to open your workflow in Finder and save this script in there as, say, safari_tabs.scpt. Then in Alfred, instead of a Run NSAppleScript Action, create a Run Script Action with Language = /bin/bash. Then you can use a super simple script, which can't really go wrong: 

osascript safari_tabs.scpt 1

Then just make a copy of that and change the number to activate tab 2 or 3.
You can connect Hotkey triggers to each of these.

Edited by deanishe
Link to comment

Thanks! it's working just as I wanted to perfectly as far as I can tell! At least the dummy way :)


I completely got what you're saying about bad form, I was just thinking there would be the risk of either a very small delay or perhaps a terminal window poping up briefly if I didn't invoke everything from Alfred using NSAppleScript. But perhaps that is not the case?



EDIT: And yeah I find Apple Script a mix of really nice, almost Pythonic, notation that's almost as intuitive as python list comprehension, but then when I need to write something up myself I'm completely lost  :mellow: It'd be nice to be good at though.

Edited by Fnantier
Link to comment

Python, you say? Now we're talking :D


Anything you put in a Run Script action should be run silently in the background. Sometimes weird things happen on OS X if you try to run, say, git, but it isn't installed (instead of your script silently failing, you'll get a pop-up asking you to install Xcode).


There is a small delay when you start running extra processes, but running a bash process takes a few hundredths of a second. That can really add up if you're writing a complex script in bash (which is largely based on running other processes), but when you're combining it with AppleScript calls to applications (which are insanely slow), bash will never be the problem. Getting data from an application via AppleScript is often many thousands of times slower than accessing the datastore directly (if that's possible).


Don't break your head over AppleScript. It's a truly demented language. It's simple to the point of broken, but the first-class option for interacting with very complicated application object models. It's two kinds of bad rolled in to one…

Link to comment
  • 2 weeks later...

deanishe I have a favor to ask. I think you know enough Apple Script to be able to help me out one more time, and I would be very grateful!


The problem:

Chrome apps such as Google Keep mapped to a global hotkey with Alfred opens just fine, but "Toggle visibility for apps" does not work. I.e. it's not possible to hide the app by pressing the hotkey again. What's worse is that pressing Cmd+H to hide the window again hides it, but then also switches focus to Google Chrome, which is a very big annoyance. However Chrome is not put into focus if minimizing Google Keep (Cmd+M) instead of hiding it (Cmd+H).


My proposed solution:

An Applescript that does the following when hotkey is pressed:

if (app is in focus):

    then minimize app


    focus on app



Can you do this?  :) Anyone else is also more than welcome to pitch in of course. As a bonus you'd also be solving a general problem of Chrome apps on Mac.


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...