I'm trying to enable the NSMenuItems that I have but it doesn't seem to be working. I'm not sure what I'm doing wrong and I'm fairly new at AppleScript. When the menu items are clicked they need to call the functions as kind of shown in the code.
use scripting additions
use framework "Foundation"
use framework "AppKit"
set bar to current application's NSStatusBar's systemStatusBar
set StatusItem to bar's statusItemWithLength:-1.0
StatusItem's setTitle:"menu"
set newMenu to current application's NSMenu's alloc()'s initWithTitle:"Custom"
set menuItem1 to current application's NSMenuItem's alloc()'s initWithTitle:"item 1" action:"action1:" keyEquivalent:""
set menuItem2 to current application's NSMenuItem's alloc()'s initWithTitle:"item 2" action:"action2:" keyEquivalent:""
StatusItem's setMenu:newMenu
newMenu's addItem:menuItem1
newMenu's addItem:(current application's NSMenuItem's separatorItem())
newMenu's addItem:menuItem2
on action1()
log "this works"
end action1
on action2()
log "this works 2"
end action2
The main issue is your action handler declarations don't match the selectors when creating the menu items, and you need to specify the target that contains the action methods.
The system typically passes the sender (the menu item) to the action, so they need to be declared with a single parameter, with the selector ending with a colon - for example:
on action1:sender --> matches the selector "action1:"
If you aren't passing anything to your own methods, they wouldn't have a parameter or the ending colon:
on anotherAction() --> matches the selector "anotherAction"
The following script matches the method declarations and sets the targets - note that when running from the Script Editor, the script will normally end before using any menu items, so you won't get log statements when the action methods are called - I've used alerts instead. I've also added a termination handler (without a parameter) to remove the status menu, so that when testing from the Script Editor you don't wind up with a menu bar full of them (theoretically):
use framework "Foundation"
use scripting additions
property statusItem : missing value
on run -- example
set my statusItem to current application's NSStatusBar's systemStatusBar's statusItemWithLength:(current application's NSVariableStatusItemLength)
statusItem's setTitle:"menu"
set newMenu to current application's NSMenu's alloc()'s initWithTitle:""
(newMenu's addItemWithTitle:"item 1" action:"action1:" keyEquivalent:"")'s setTarget:me
(newMenu's addItemWithTitle:"item 2" action:"action2:" keyEquivalent:"")'s setTarget:me
newMenu's addItem:(current application's NSMenuItem's separatorItem)
(newMenu's addItemWithTitle:"Quit" action:"terminate" keyEquivalent:"")'s setTarget:me
statusItem's setMenu:newMenu
end run
on action1:sender
display alert "Menu " & quoted form of (sender's title() as text) & " works"
end action1:
on action2:sender
display alert "Menu " & quoted form of (sender's title() as text) & " also works"
end action2:
to terminate() -- quit handler is not called from normal NSApplication terminate:
current application's NSStatusBar's systemStatusBar's removeStatusItem:statusItem
if name of current application does not start with "Script" then tell me to quit
end terminate
Related
So I've been trying to write an AppleScript script that would create a folder with an input of user, but unfortunately I can't get it working. Any help is appreciated.
set theResponse to display dialog "Enter the name of folder" default answer "" with icon note buttons {"Cancel", "Continue"} default button "Continue"
display dialog "Name of the folder: " & (text returned of theResponse) & "."
tell application "Finder"
make new folder at desktop with properties {name:"theResponse"}
end tell
Here's a modified version of your code that will work:
set theResponse to text returned of (display dialog "Enter the name of folder" default answer "" with icon note buttons {"Cancel", "Continue"} default button "Continue")
display dialog "Name of the folder: " & theResponse & "."
tell application "Finder"
make new folder at desktop with properties {name:theResponse}
end tell
In your original code, {name:"theResponse"}, with "theResponse" in quotes, it's literally theResponse not the text returned.
So, In the first line of code, I started off with setting the theResponse variable to the text returned, so it need not be referenced as such later in the script.
Thus (text returned of theResponse) in the second line of code is now set to just theResponse, which contains the value of that variable.
Now when it comes time to make new folder the name property is the value of theResponse, without quotes, and it already contains the text returned from the first line of code.
I want to quickly create a list of all of the names of every menu item in the menu bar tree for an app.
tell application "System Events"
tell first process where name is "Script Editor"
set menuContents to entire contents of menu bar 1
return name of menuContents
end tell
end tell
This code throws error number -1728, which means the following according to documentation.
The referenced object doesn’t exist. This is a run-time resolution error,
such as when attempting to reference a third object when only two
objects exist.
EDIT:
I'm not completely sure, but it seems that the problem arises because entire contents dereferences the UIElements from their source. Properties of UIElements might be referenced by pointer, which means that the UIElements don't have access to them once dereferenced.
You cannot use return name of menuContents because menuContents, in the context of your code, is a list and a list object does not have a name property.
The properties of a list object are: class, length, rest and reverse
So, any of the following are valid commands:
return class of menuContents
return length of menuContents
return rest of menuContents
return reverse of menuContents
The elements of list objects are: item
To get the name property of each item in the list, use the following example:
set menuNames to {}
tell application "System Events"
tell application process "Script Editor"
set menuContents to entire contents of menu bar 1
repeat with thisItem in menuContents
set end of menuNames to name of thisItem
end repeat
end tell
end tell
return menuNames
See the list class reference it the AppleScript Language Guide.
Is there a way to create a script that will change the preferences of iChat to run the script when a message is received?
In other words, I want to make a script to change the iChat preferences to enable the "Message Received.applescript" i have created. Wow, this is confusing. Let me simply this.
I want a script that does this:
Activate iChat
Open iChat Preferences
Move to "Alerts" tab
select event "Message Received"
turn on "Run applescript"
select a certain script from the script folder called "Message Receive.applescript"
please help?
You just need to edit iChat's plist file. defaults is a bit awkward for nested values so use System Events instead:
tell application "System Events"
set EventActions to property list item "EventActions" of property list file ((path to preferences folder from user domain as text) & "com.apple.iChat.plist")
repeat with e in {property list item "MessageNotification" of EventActions, property list item "SubsequentMessage" of EventActions}
make new property list item at end of e with properties {name:"RunAppleScript", value:true}
make new property list item at end of e with properties {name:"iChatAppleScriptsKey", value:{"~/Library/Scripts/iChat/Message Received.scpt"}}
end repeat
end tell
This will attach "Message Received.scpt" to both initial text invitations and subsequent messages - you could simplify it if you only wanted it for subsequent messages. Also note you may need to relaunch iChat for the change to take effect.
While trying to make an automator action that opens multiple tabs from selected text as input I ran into an applescript issue I wasn't able to solve for awhile. This includes the answer and I'm posting this here because I just wasn't able to find documentation on how to handle data in "input" for a receives selected "text" in "any application" automator action, everything is for files which comes in as a list already.
When putting an applescript action in, you get:
on run {input, parameters}
the problem here is that input isn't in a list format and trying to do anything with it breaks the script or throws an error. ie I can't do:
repeat with URL in input
set this_URL to URL
So how can I treat a list of selected text as a list of items?
the solution is first treat input as a string then break apart every paragraph.
on run {input, parameters}
set inputText to input as string
set URL_list to every paragraph of inputText
Without treating input "as string" first before doing "every paragraph of" it won't work.
Here's the end working script, replace the "some_url" with your own. You'll be able to select several lines of text in an editor and treat each one as a parameter to your fixed url opening each in a new safari tab. This could be expanded upon by having each line be delimited for multiple params on the url.
on run {input, parameters}
set inputText to input as string
set URL_list to every paragraph of inputText
tell application "Safari"
activate
repeat with URL in URL_list
set this_URL to URL
# extra processing of URL could be done here for multiple params
my new_tab()
set tab_URL to "http://some_url.com?data=" & this_URL
set the URL of document 1 to tab_URL
end repeat
end tell
return input
end run
on new_tab()
tell application "Safari" to activate
tell application "System Events"
tell process "Safari"
click menu item "New Tab" of ¬
menu "File" of menu bar 1
end tell
end tell
end new_tab
As an example say you had the list and had a service of the above using "http://stackoverflow.com/posts/" & this_URL
6318162
6318163
6318164
you could now select them click services and choose your "StackOverflow - view questions" service and it'll append and open each one in a new safari tab. In my case I needed to verify multiple dns entries in our server as still valid and do a bunch of whois lookups.
I was looking for the same thing, just for files as input from Automator to AppleScript.
ddowns's trick didn't work for that, but ended up using this, hope it's helpful for someone looking for solving the same issue I ran into:
on run {input, parameters}
-- create empty list
set selectedFiles to {}
-- add each list item to the empty list
repeat with i in input
copy (POSIX path of i) to end of selectedFiles
end repeat
-- show each item (just for testing purposes of course)
repeat with currentFile in selectedFiles
display dialog currentFile as text
end repeat
end run
As Hanzaplastique says, for AppleScript within Automator, you don't need the Safari AppleScript because there's an Action for that. I use the following Actions:
Extract URLs from Text (actually the 'Extract Data from Text' Action)
Run AppleScript
Display Webpages
I use it as a Workflow added to the Services menu so that I can right-click on selected text in an email and open multiple URLs in Safari tabs.
In particular, I get Server / WordPress updates in an email but the URLs are just the top level of the domains and I want to jump to the plugins page of WordPress. So, my AppleScript (with thanks to Hanzaplastique) is:
on run {input, parameters}
set AppleScript's text item delimiters to {return & linefeed, return, linefeed, character id 8233, character id 8232}
-- create empty list
set selectedFiles to {}
-- add each list item to the empty list
repeat with i in input
set AppleScript's text item delimiters to {" "}
set i to i & "/wp-admin/plugins.php"
copy i to end of selectedFiles
end repeat
return selectedFiles
end run
I found I needed the 'return selectedFiles'. The always mysterious (to me) text delimiters may not be necessary and come from the previous version which only pulled out a single URL.
this script works fine until the commands of the buttons, can someone tell my why i doesent work?
it says "button_pressed is not definded"
display dialog "bla" with icon alias ((path to me) & "Contents:Resources:my.icns" as string) buttons {"blu", "bli", "blaa"} default button 3
if the button_pressed is "blu" then
-- action for 1st button goes here
say "blu"
else if the button_pressed is "bli" then
-- action for 2nd button goes here
say "bli"
else
-- action for 3rd button goes here
say "bla"
end if
The appropriate way to do this is to use button returned:
display dialog "bla" with icon alias ((path to me) & "Contents:Resources:my.icns" as string) buttons {"blu", "bli", "blaa"} default button 3
set theResponse to button returned of the result
if theResponse is "blu" then
-- action for 1st button goes here
say "blu"
else ...
The error occurs because the variable button_pressed is NOT defined. All you have to do is add this line of code before the if block and it should work!
set the button_pressed to the button returned of the result
Variables (i.e. button_pressed) must ALWAYS be defined before they can be uesd. For example, this code will not function...
display dialog greeting --> ERROR
...while this one will:
set greeting to "Hello! I am now a defined variable!"
display dialog greeting