A Single Dialog to Handle Multiple Entries

A question that seems to crop up from time to time goes something like this: "Can I create a dialog to take more than one entry in the same panel?

Typical advice might range from building a custom dialog in AppleScript Studio/Xcode to using a third-party scripting addition (OSAX) - such as 24U Appearance. All worthy suggestions since, depending on exactly what’s required, most of the proposed solutions offer a variety of benefits. But they could also involve an additional learning curve, cost or complication that the enquirer may prefer to avoid - especially if the immediate aim is not overly ambitious.

Often, the purpose is merely to produce a dialog that takes a list as input. Ideally, this would allow the user to enter the list in a single panel, review it in context, edit items as required - and then, finally, confirm the result. Such a feature might be useful as a front end for entering data into some kind of database, or simply as a means of jotting down a general-purpose list. What a pity it can’t be achieved with vanilla AppleScript…

Or can it?

The script below shows a way to extend a regular dialog so that it accepts multiple line entries. It then goes on to output entries - formatted either as text or as a list. Of course, the trick here is not really in the script - but in Standard Additions, which accepts the insertion of return characters in a dialog’s default answer. However, the script demonstrates how the input and output could be formatted - and the multi_dialog handler might be handy for creating a series of multiple-entry dialogs more easily.

The following notes may help:

The script, which includes a few syntax examples, also demonstrates how the size of a dialog’s entry panel is defined by the prompt list:


on multi_dialog for q given listing:l
	tell q as list
		set {a, b, c} to {{}, beginning, count}
		set v to b's class is integer
		if v then set {c, v, q} to {b, b is 0, rest}
	end tell
	if v then set c to 30
	repeat c + 1 div (1 + (system attribute "sysv") div 4160) times
		set a's end to ""
	end repeat
	set {d, text item delimiters} to {text item delimiters, return}
	set {q, a, text item delimiters} to {q as string, a as string, d}
	set r to (display dialog q default answer a)'s text returned
	if not v then tell r & a
		if l then return items 1 thru c of paragraphs
		if c > 1 then return text 1 thru paragraph c
	end tell
	tell r to repeat with i from (count paragraphs) to 1 by -1
		if (count paragraph i) is not 0 then
			if l then return paragraphs 1 thru i
			return text 1 thru paragraph i
		end if
	end repeat
	if l then return {}
	""
end multi_dialog

------------------
-- demonstration --
------------------

property l : {"1]  Name: {items: 2, length: fixed, output: list}", 
	"2]  Address: {items: 3, length: fixed, output: list}", 
	"3]  Reasons: {items: 6, length: fixed, output: list}", 
	"4]  ToDo List: {items: ?, length: variable, output: text}", 
	"5]  Standard: {items: 1, length: variable, output: text}"}

property d : l's item 1

tell (choose from list l default items d with prompt "Choose a multi-dialog demonstration:")
	if it is false then error number -128
	set d to it
	set i to item 1's item 1 as integer
end tell

--------------------
-- syntax examples --
--------------------

if i is 1 then
	multi_dialog for {"... What is your first name?", "... And your last name?"} with listing
else if i is 2 then
	multi_dialog for {3, "Please enter your:", "", "1: house number & street name", "2: city/area", "3: zip code"} with listing
else if i is 3 then
	multi_dialog for {6, "List up to six reasons to be cheerful:"} with listing
else if i is 4 then
	multi_dialog for {0, "To Do list for " & (current date)'s weekday & ":"} with listing
else
	multi_dialog for "Did you *really* just want a standard dialog?" without listing
end if

I added the (option shift) line breaks mid-script to allow it to work…

Impressive script Kai!

on multi_dialog for q given listing:l
	tell q as list
		set {a, b, c} to {{}, beginning, count}
		set v to b's class is integer
		if v then set {c, v, q} to {b, b is 0, rest}
	end tell
	if v then set c to 30
	repeat c + 1 div (1 + (system attribute "sysv") div 4160) times
		set a's end to ""
	end repeat
	set {d, text item delimiters} to {text item delimiters, return}
	set {q, a, text item delimiters} to {q as string, a as string, d}
	set r to (display dialog q default answer a)'s text returned
	if not v then tell r & a
		if l then return items 1 thru c of paragraphs
		if c > 1 then return text 1 thru paragraph c
	end tell
	tell r to repeat with i from (count paragraphs) to 1 by -1
		if (count paragraph i) is not 0 then
			if l then return paragraphs 1 thru i
			return text 1 thru paragraph i
		end if
	end repeat
	if l then return {}
	""
end multi_dialog

------------------
-- demonstration --
------------------

property l : {"1]  Name: {items: 2, length: fixed, output: list}", ¬
	"2]  Address: {items: 3, length: fixed, output: list}", ¬
	"3]  Reasons: {items: 6, length: fixed, output: list}", ¬
	"4]  ToDo List: {items: ?, length: variable, output: text}", ¬
	"5]  Standard: {items: 1, length: variable, output: text}"} ¬
	
property d : l's item 1

tell (choose from list l default items d with prompt "Choose a multi-dialog demonstration:")
	if it is false then error number -128
	set d to it
	set i to item 1's item 1 as integer
end tell

--------------------
-- syntax examples --
--------------------

if i is 1 then
	multi_dialog for {"... What is your first name?", "... And your last name?"} with listing
else if i is 2 then
	multi_dialog for {3, "Please enter your:", "", "1: house number & street name", "2: city/area", "3: zip code"} with listing
else if i is 3 then
	multi_dialog for {6, "List up to six reasons to be cheerful:"} with listing
else if i is 4 then
	multi_dialog for {0, "To Do list for " & (current date)'s weekday & ":"} with listing
else
	multi_dialog for "Did you *really* just want a standard dialog?" without listing
end if

When trying to run this I get “Can’t get text item delimiters” with the second list in this line "set {d, text item delimiters} to {text item delimiters, return} highlighted. Suggestions?

Hello.

I think that somehow, an illegal character has been incorporated in your script, because MacAnswerMan’s script worked for me. I tried all options.

If the scipt compiles, then I’d try to

set AppleScript's text item delimiters to ""

at the top of the script. HTH

If any script requiring text item delimiters you are testing fails persistently, McUsrII’s solution should always be your first trial. It is easy to forget that text item delimiters are persistent which is why structures like this are always recommended:

set tid to AppleScript's text item delimiters
set applescript's text item delimiters to "search item here"
set tParts to text items of 'ref to text to be searched'
set AppleScript's text item delimiters to tid

Further when you’re testing a complex parsing operation and it fails, the TID’s are left where they were at the point of failure.

Thanks McUsril and Adam Bell for the tips. Turns out that wasn’t the problem though. I was trying to run this in Smile and it won’t run there without throwing that error about the text item delimiters. Copied the same script to the Script Editor and it runs fine there. No idea why Smile doesn’t like it.