use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
property theView : missing value
global listOfLabels
-- check we are running in foreground
if not (current application's NSThread's isMainThread()) as boolean then
display alert "This script must be run from the main thread." buttons {"Cancel"} as critical
error number -128
end if
-- for styleNum, 0 = warning, 1 = informational, 2 = critical; for givingUpAfter, 0 means never; accessoryView of missing value means none
on display alert message mainText with description theExplanaton as style styleNum and buttons buttonsList suppression showSuppression giving up after giveUp accessoryView theView
set styleNum to styleNum as string
set buttonsList to reverse of buttonsList -- because they get added in reverse order cf AS
-- create an alert
set theAlert to current application's NSAlert's alloc()'s init()
-- set up alert
set validQStyleType to {"warning", "0", "informational", "1", "critical", "2"}
if styleNum is in validQStyleType then
-- apply the indicated transformation to the Cocoa string
if the styleNum is "warning" or styleNum is "0" then
set the styleNum to current application's NSNumber's numberWithInt:0
else if the styleNum is "informational" or styleNum is "1" then
set the styleNum to current application's NSNumber's numberWithInt:1
else if the styleNum is "critical" or styleNum is "2" then
set the styleNum to current application's NSNumber's numberWithInt:2
end if
else
set errStr to styleNum & " is not valid style " as text
error errStr
end if
tell theAlert
its setAlertStyle:styleNum
its setMessageText:mainText
its setInformativeText:theExplanaton
repeat with anEntry in buttonsList
(its addButtonWithTitle:anEntry)
end repeat
its setShowsSuppressionButton:showSuppression
if theView is not missing value then its setAccessoryView:theView
end tell
-- if giveUp value > 0, tell the app to abort any modal event loop after that time, and thus close the panel
if giveUp > 0 then current application's NSApp's performSelector:"abortModal" withObject:(missing value) afterDelay:giveUp inModes:{current application's NSModalPanelRunLoopMode}
-- show alert in modal loop
set returnCode to theAlert's runModal()
-- if a giveUp time was specified and the alert didn't timeout, cancel the pending abort request
if giveUp > 0 and returnCode is not current application's NSModalResponseAbort then current application's NSObject's cancelPreviousPerformRequestsWithTarget:(current application's NSApp) selector:"abortModal" object:(missing value)
-- get values after alert is closed
set suppressedState to theAlert's suppressionButton()'s state() as boolean
set buttonNumber to returnCode mod 1000 + 1 -- where 1 = right-most button
if buttonNumber = 0 then
set buttonName to "Gave Up"
else
set buttonName to item buttonNumber of buttonsList
end if
set theAnswers to {}
repeat with i from 1 to count of listOfLabels
set end of theAnswers to ((theView's viewWithTag:i)'s stringValue() as text)
end repeat
return {buttonName, suppressedState, theAnswers}
end display alert message
on View with labels listOfLabels and placeholders listOfPlaceholders
set labelCount to count of listOfLabels
set totalDepth to labelCount * 55 -- each label plus entry field needs 55pts
set viewList to {} -- list of controls to add to accessory view
repeat with i from 1 to labelCount
set theLabel to (current application's NSTextField's alloc()'s initWithFrame:(current application's NSMakeRect(0, totalDepth - 30 - (i - 1) * 55, 400, 17)))
tell theLabel
(its setStringValue:(item i of listOfLabels))
(its setEditable:false)
(its setBordered:false)
(its setDrawsBackground:false)
end tell
copy theLabel to end of viewList
-- now text entry field
set theInput to (current application's NSTextField's alloc()'s initWithFrame:(current application's NSMakeRect(0, totalDepth - 55 - (i - 1) * 55, 400, 22)))
tell theInput
(its setEditable:true)
(its setBordered:true)
(its setPlaceholderString:(item i of listOfPlaceholders))
(its setTag:i)
end tell
copy theInput to end of viewList
end repeat
-- create a view and add items
set theView to current application's NSView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, 400, totalDepth))
theView's setSubviews:viewList
return theView
end View with labels