Search code examples
applescriptfoundation

How can I avoid hard coding the handlers for each menu item?


I have a stay open AppleScript app that creates a menu with many menu items. The handlers that is mapped are repetitive and only differs in its index. How can I refactor this code to dry it up?

on makeMenus(selectedIndex as integer)
    newMenu's removeAllItems() -- remove existing menu items

    set menuItems to {"POC1", "POC2"}

    repeat with i from 1 to number of items in menuItems
        set this_item to item i of menuItems
        if i is equal to selectedIndex then set this_item to this_item & " " & (emoji's CHECK)
        set thisMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:this_item action:("someAction" & (i as text) & ":") keyEquivalent:"")
        (newMenu's addItem:thisMenuItem)
        (thisMenuItem's setTarget:me)
    end repeat

    -- Create the Quit menu item separately
    set thisMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:"Quit" action:("quitAction:") keyEquivalent:"")
    (newMenu's addItem:thisMenuItem)
    (thisMenuItem's setTarget:me)
end makeMenus

The repetitive handler is:

on someAction1:sender
    updateStatus(1)
end someAction1:

on someAction2:sender
    updateStatus(2)
end someAction2:

If I can derive the menu item name or index from a parameter in the someAction handler, that would let me have a single handler to take care of all the menu items.


Solution

  • The sender argument of an action handler will be the object that called the action. In this case the sender will be the particular menuItem, so a common action handler can use a property such as the sender's title.

    Note that since it will be a Cocoa object, you will need to coerce the title to an AppleScript string, for example:

    on doAction:sender
        set menuTitle to (sender's title) as text
        if menuTitle is "this" then
            doThis()
        else if menuTitle is "that" then
            doThat()
        else
            doOther()
        end if
    end doAction: