Local Safari URL to Finder file

Hello all,

I’m looking to use applescript to grab a url of a page in safari parse the string and have the finder show and select the current file if it’s on the local machine. A nice little time saver and fairly straightforward? I’ve spent a good couple of hours trying to work it out, even finding documentation seems to be difficult. Every language has some sort of string manipulation capabilities, applescript must have but finding any info seems incredibly difficult… how on earth do you manage?!

I got this far by hacking a few of the examples I came across:


tell application "Safari"
	-- Find out if Safari has a window open
	if not (exists (front window)) then
		activate
		set dialogText to "No windows are open in Safari."
		display dialog dialogText buttons {"OK"} default button 1
		return
	else
		-- Get the  URL of the page currently displayed in Safari's front window
		set current_URL to URL of document of front window
	end if
	
end tell

-- watch out for server Aliases... check httpd.conf for details
set current_URL to SaR(current_URL, "simon.local/books", "simon.local/httpdocs/books")

set current_URL to SaR(current_URL, "simon.local/php", "simon.local/dynamic/php")
set current_URL to SaR(current_URL, "http://simon.local", "Users/simon/Sites")
set current_URL to SaR(current_URL, "/", ":")

set current_URL to path to startup disk & current_URL

tell application "Finder"
	activate
	open folder current_URL of the startup disk
end tell

on SaR(aText, asearch, areplace)
	try
		set oldAstid to AppleScript's text item delimiters
		set AppleScript's text item delimiters to asearch
		set a_text to every text item of aText
		set AppleScript's text item delimiters to areplace
		set a_text to (every text item of a_text) as string
		set AppleScript's text item delimiters to oldAstid
		return a_text
	on error
		return ""
	end try
end SaR

However when I couldn’t find a way of getting a “last Index of”, and the finder kept telling me that it wasn’t happy with the object I was trying to set it to select, I finally gave up and wrote a javascript bookmarklet. Here’s the code for anyone who might find it useful, it get’s close but doesn’t select the file (just opens the folder the files in), and I can’t control the finder window size and loc in a way I’d be able to do with applescript:


javascript:
/* web domain*/
var wd="simon.local";
/* file directory */
var fd="/Users/simon/Sites";
if(document.domain==wd){
	var w_loc=document.URL;
	/* check for any aliases - see httpd.conf */
	w_loc=w_loc.replace(wd+"/books",wd+"/httpdocs/books");
	w_loc=w_loc.replace(wd+"/php",wd+"/dynamic/php");
	w_loc=w_loc.replace(wd+"/photos",wd+"/httpdocs/photo");
	/* there might be a query string with a / in it so cut everything after the ? */
	var q=w_loc.lastIndexOf("?");
	if(q>0){
		w_loc = w_loc.substring(0,q);
	}
	var f_loc=w_loc.replace("http://"+wd,"file://"+fd);
	/* finally remove the doc so only a directory is left */
	var trim_point=f_loc.lastIndexOf("/");
	f_loc = f_loc.substring(0,trim_point+1);
	/* send safari there and it'll open the folder with the finder */
	window.location=f_loc;
} else {
	alert("Sorry this URL isn't the local domain I'm looking for.nnthis domain: "+document.domain+"nmy domain: "+wd);
};

so… what would I like to know?

  1. Where’s all the documentation on core applescript?
  2. What’s applescripts equivalent of lastIndexOf() ?
  3. What object is the finder after when telling it set a selection?

Here’s me hoping it isn’t always this frustrating.

Thanks,
Simon

http://developer.apple.com/documentation/AppleScript/AppleScript-date.html
(specially the AppleScript Language Guide, a bit outdated, but still useful on its basics.

Does not exist, but you can use something as:

lastIndexOf("cakes", "I like cakes and cakes") --> -5

item result of "I like cakes and cakes" --> "c"

to lastIndexOf(str, longstr)
	set lof to (offset of ("" & reverse of str's items) in ("" & reverse of longstr's items))
	if lof is 0 then return 0 --> not found
	-(count str) + 1 - lof
end lastIndexOf

I’m not sure what are you asking here… Do you need something similar to this?

set itemToShow to alias ((path to home folder as text) & "Public")
tell application "Finder" to reveal itemToShow

Thanks JJ.

Hard to see how I managed to miss the button on the homepage with the link to the documentation… I also hadn’t realised that there’s a libary window in the script editor. I am suprised that there’s no equivalent string manipulation functions, that’ll be why they were so difficult to find.

My Q no 3 should have read: What type of object (string, array etc) can the finder use when you script the equivalent of selecting an item in a finder window.

I’ve been playing around and come up with this:

--alter for local variables
set local_domain to "simon.local"
set site_directory to "Simons HD:Users:simon:Sites"

tell application "System Events"
	-- Find out if Safari is running
	if not (exists (application process "Safari")) then
		activate
		set dialogText to "Safari is not running."
		display dialog dialogText buttons {"OK"} default button 1
		return
	end if
end tell

tell application "Safari"
	-- Find out if Safari has a window open
	if not (exists (front window)) then
		activate
		set dialogText to "No windows are open in Safari."
		display dialog dialogText buttons {"OK"} default button 1
		return
	else
		-- Get the  URL of the page currently displayed in Safari's front window
		set current_URL to URL of document of front window
	end if
end tell

--things could get messy with escaped chars... catch an obvious one..
set current_URL to SaR(current_URL, "%20", " ")

--check to see if the url is alread a file:///
set file_check to subString(current_URL, 1, 8)
if (file_check is equal to "file:///") then
	-- thing just got a little simpler
	set current_URL to SaR(current_URL, "file:///", "")
	set volume_check to subString(current_URL, 1, 8)
	if (volume_check is equal to "Volumes/") then
		-- the file is on a mounted volume
		set current_URL to SaR(current_URL, "Volumes/", "")
	else
		-- the file should be on the startup disk
		set current_URL to ((path to startup disk as text) & current_URL)
	end if
else
	set check_local to SaR(current_URL, local_domain, "iama.localurlsonoworries")
	-- check_local WON'T be equal to current_URL if it is a local domain
	if (check_local is equal to current_URL) then
		display dialog "This isn't the local domain I'm looking for:" & local_domain buttons {"OK"} default button 1
		return
	end if
	-- convert server Aliases... check httpd.conf for details
	set current_URL to SaR(current_URL, local_domain & "/books", local_domain & "/misc/books")
	set current_URL to SaR(current_URL, local_domain & "/php", local_domain & "/dynamic/php")
	
	-- check for querystrings and remove
	set current_URL to removeTrailing("?", current_URL)
	-- check for page anchors and remove
	set current_URL to removeTrailing("#", current_URL)
	
	-- replace the http://domain with the site_directory
	set current_URL to SaR(current_URL, "http://" & local_domain, site_directory)
end if

-- convert all slashes to colons and isolate the parent (remember fileToShow could actually be a Directory)
set current_URL to SaR(current_URL, "/", ":")
set current_DIR to removeTrailing(":", current_URL)

-- store the file and directory for use by 
--display dialog fileToShow
set fileToShow to alias (current_URL)
set dirToShow to alias (current_DIR)

-- Use the file with an app of your choice....
--(* 
tell application "Finder"
	-- comment 'activate' in/out if you want the window to appear in the foreground/background
	--activate
	-- if you're happy with no window control then just use the following line
	--reveal fileToShow
	-- want to see the parent directory instead?
	--reveal dirToShow
	-- otherwise config your window settings here...
	--(*
	-- window will be 550 wide by 755 high, x at 6 and y at 82 in (column, icon or list) column view
	tell (open container window of dirToShow) to ¬
		set {bounds, current view} to {{6, 82, 650, 750}, column view}
	reveal fileToShow
	--*)
end tell
--*)

(*
tell application "TextMate"
	open fileToShow
end tell
*)

on SaR(aText, asearch, areplace)
	try
		set oldAstid to AppleScript's text item delimiters
		set AppleScript's text item delimiters to asearch
		set a_text to every text item of aText
		set AppleScript's text item delimiters to areplace
		set a_text to (every text item of a_text) as string
		set AppleScript's text item delimiters to oldAstid
		return a_text
	on error
		return false
	end try
end SaR

on lastIndexOf(str, longstr)
	set lof to (offset of ("" & reverse of str's items) in ("" & reverse of longstr's items))
	if lof is 0 then return 0 --> not found 
	return -(count str) + 1 - lof
end lastIndexOf

on subString(the_string, start_index, end_index)
	return "" & (get characters 1 thru end_index of the_string)
end subString

on removeTrailing(last_instance_of, the_URL)
	set qs to lastIndexOf(last_instance_of, the_URL)
	if (qs is not 0) then
		return subString(the_URL, 1, qs - 1)
	else
		return the_URL
	end if
end removeTrailing

It should be pretty to useful to web developers who test on their local machines, and with a couple of tweaks it’s easy to extend the functionality to different browsers and applications. However there’s a couple of gaps which I’d appreciate help with:

  1. Is there a way to use a path with slashes (unix style) instead of colons?

  2. Safari encodes certain characters ie space to %20 is there a decode function?

  3. Ideally i’d like to add this script as a button in the browser toolbar - where should I start looking for info on this? Or can I call an applescript from a bookmark?

  4. Are multidimensional arrays possilbe in applescript?

Suggestions on code improvements are most welcome.

Yes, lack of certain functions in AS is an old problem, specially basic text manipulation routines, such as lastIndexOf, search-replace, the equivalent to split() and join() in other languages, etc.

Finder is very polivalent. Some examples:

tell application "Finder"
	select alias "path:to:file.txt"
	select "path:to:file.txt"
	select {alias "path:to:file.txt", alias "path:to:file2.txt"}
	select item "file.txt" of front window
	select file "file.txt" of front window
	select document file "file.txt" of front window
	select (items whose name contains "file") of window 1
end tell

Only internally or in “do shell script” calls. Eg:

set appsFolder to "/Applications"

tell application "Finder" to reveal (appsFolder as POSIX file)
--> appsFolder as POSIX file = file "diskname:Applications"

There are several routines available (handlers), but since you use Safari, I would use something as:

tell application "Safari"
	set current_URL to do JavaScript "document.location.href" in document 1
end tell

This should return the url decoded (or you can use javascript’s “unescape”).

This is a long long way if you plan it using only AppleScript. I would run it from Apple’s Script Menu. Otherwise, keep asking :wink:

In AppleScript there are only lists and records, which can contain other lists and records (and also, of course, strings, numbers, etc.). Eg:

--> LISTS
item 1 of {1} --> 1
item 1 of {1, 2, 3} --> 1
item 1 of {{1}, {1, 2, 3}} --> {1}

--> RECORDS
a of {a:1} --> 1
a of {a:1, b:2} --> 1
a of {a:{a:1, b:2}} --> {a:1, b:2}

There are some strong libraries to manipulate lists and records, and you can create magical stuff such as fake “associative arrays”, fake “tables”, etc. You can find them surfing this site’s sections Code Exchange and ScriptBuilders. The “official” place is AppleMods, but the new site is in construction (though you can browse still the old one, find the link in the propper place).