Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Autoclose Alert Message and Custom Confirm Message

Engaged ,
Apr 07, 2025 Apr 07, 2025

I found this thread: https://community.adobe.com/t5/illustrator-discussions/auto-close-alert-message/td-p/9398258

Images here: https://github.com/Marshall-Brooks/Sandbox/issues/2

 

See also:

https://community.adobe.com/t5/photoshop-ecosystem-discussions/simulate-button-press-in-script-ui/m-...

 

I'm somewhat spoiled by the Enhanced Message Box add-on for Microsoft Access which shows a standard Msgbox with a countdown of seconds until the box closes.

 

I used @Peter Kahrel's Scipt UI guide to modify the first linked script as follows:

function AutocloseAlert(message, delaySeconds, title){
    title = title || 'Alert';
    var alertWindow = new Window('palette', title);
//    var control_text = alertWindow.add('edittext', [0, 0, 500, 200], message, {multiline: true});
//  var control_text = alertWindow.add('edittext', , message, {multiline: true});   
    var control_text = alertWindow.add('edittext', undefined, message, {multline:true})
//    if(delaySeconds === 0){
        var control_close = alertWindow.add('button', undefined, 'OK');       
        control_close.onClick = function(){
            if(alertWindow){
                alertWindow.hide();
                alertWindow = null;
            }
        };
 // }

    alertWindow.show();
    alertWindow.update();
   
    if(delaySeconds > 0){
        $.sleep(delaySeconds * 1000);
        alertWindow.hide();
        alertWindow = null;
    }  
}

I'm having the following issues:

  • I don't like that the window shows grayed out (disabled) - presumably b/c of the sleep function. I'd prefer it to look like the zero second but disappear when I clicked OK or when the timer expired. I tried commenting out the line "$.Sleep(DelaySeconds * 1000) and replacing it with: 
        var startTime = new Date().getTime();
        while ( new Date().getTime() - startTime < delaySeconds * 1000 ) {alertWindow.update()} ​

But it didn't change how it worked - i.e. the window was still grayed out, and clicking the OK button did not close the window, but it did disappear after the delaySeconds interval.

  • I would prefer to have the OK button show the seconds remaining, but I think I need two timers for this and I'm not sure how to implement them.
  • Probably easiest - I'd prefer to have a minimum size for the window and a maximum before it wraps to two lines, but I can basically set my "message" text to achieve this. (An alert that is more than one line is probably too long anyway).

Thank you in advance!!!

TOPICS
Scripting
564
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 2 Correct answers

Community Expert , Apr 07, 2025 Apr 07, 2025

Eh that didn't work - is this what you're thinking of ?

This works for me 

function CountdownAlert(message, delaySeconds, title) {
    title = title || "Countdown Alert";

    var win = new Window("palette", title);
    win.orientation = "column";
    win.alignChildren = "center";

    var msg = win.add("statictext", undefined, message);
    var btn = win.add("button", undefined, "OK (" + delaySeconds + ")");

    var cancelled = false;

    // Function for button click
    btn.onClick = functio
...
Translate
Engaged , Apr 23, 2025 Apr 23, 2025

Updated the scripts to auto-size and or wrap correctly with the help of this thread: https://community.adobe.com/t5/indesign-discussions/script-ui-dynamically-autosizing-statictext/td-p/15275567#M621971 

 

EDIT: Had to make a minor change to the "if" statement in AutocloseAlert(). The previous version would fail (only display the first line) if message length was < 80 and you have manual line feeds, e.g.:

AutocloseAlert("Line 1\rLine2");

EDIT2: Had to correct the "if" statement, not found returns -1

...
Translate
Community Expert ,
Apr 07, 2025 Apr 07, 2025

Try using Idle Task instead of sleep 

 

function AutocloseAlert(message, delaySeconds, title) {
    title = title || 'Alert';
    delaySeconds = delaySeconds || 5;

    var alertWindow = new Window('palette', title);
    alertWindow.orientation = 'column';
    alertWindow.alignChildren = 'fill';

    var textBox = alertWindow.add('statictext', undefined, message, { multiline: true });
    textBox.characters = 50;

    var button = alertWindow.add('button', undefined, 'OK (' + delaySeconds + ')');

    var countdown = delaySeconds;
    var idleTask;

    // Button closes early
    button.onClick = function () {
        if (idleTask && idleTask.isValid) {
            idleTask.remove();
        }
        alertWindow.close();
    };

    // This function will be called repeatedly by IdleTask
    function onIdleEvent() {
        countdown--;

        if (!button || !button.text) return;

        if (countdown <= 0) {
            if (idleTask && idleTask.isValid) {
                idleTask.remove();
            }
            alertWindow.close();
        } else {
            button.text = 'OK (' + countdown + ')';
        }
    }

    // Create IdleTask
    idleTask = app.idleTasks.add({ name: "AutocloseAlertTimer", sleep: 1000 });

    // Attach event listener
    idleTask.addEventListener(IdleEvent.ON_IDLE, function () {
        onIdleEvent();
    });

    alertWindow.show();
}
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 07, 2025 Apr 07, 2025

Eh that didn't work - is this what you're thinking of ?

This works for me 

function CountdownAlert(message, delaySeconds, title) {
    title = title || "Countdown Alert";

    var win = new Window("palette", title);
    win.orientation = "column";
    win.alignChildren = "center";

    var msg = win.add("statictext", undefined, message);
    var btn = win.add("button", undefined, "OK (" + delaySeconds + ")");

    var cancelled = false;

    // Function for button click
    btn.onClick = function () {
        cancelled = true;
        win.close();
        $.writeln("User clicked OK");
    };

    // Show the window
    win.show();

    // Countdown loop
    while (delaySeconds > 0 && !cancelled) {
        $.sleep(1000); // wait 1 second
        delaySeconds--;
        try {
            btn.text = "OK (" + delaySeconds + ")";
            win.update();  // Force the window to update
        } catch (e) {
            break; // window might be closed already
        }
    }

    // Close window after countdown, unless user clicked OK
    if (!cancelled) {
        win.close();
        $.writeln("Auto-closed after timeout");
    }
}

// Example usage: countdown from 5 seconds
CountdownAlert("This message will close in 5 seconds.", 5, "Autoclose Alert");

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 07, 2025 Apr 07, 2025

@Eugene Tyson - I didn't understand your code, although it looks really good, but I am getting an error "Undefined is not an object" on the line idleTask = app.itleTasks.add({name:"AutocloseAlertTimer", sleep: 1000})

I should have added - my script is being run in FrameMaker, but I was told the InDesign forum had better ScriptUI support.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 07, 2025 Apr 07, 2025

@Eugene Tyson Second script is almost perfect. Only issue is I can't click on the OK button - well I can, but nothing happens. I would like the alert to count down the time remaining, but be able to close early if desired.

Much better than what I started with, though!!!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 07, 2025 Apr 07, 2025

I'm only learning scripting so this is cobbled together from bits of other scripts I have. 

 

I think I'd need a broader context to what you're doing to fully do what you want. 

 

Let me see if I can fix the OK button. 

 

But more details on your overall goal will help me greatly understand.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 07, 2025 Apr 07, 2025

@Eugene Tyson - What you have is great!  I made two minor changes. I changed:

            btn.text = "OK (" + delaySeconds + ")";
            win.update();  // Force the window to update

To:

            if(delaySeconds > 0){    
                btn.text = "OK (" + delaySeconds + ")";
            }
            else {
                btn.text = "OK";   
            }
            //win.update();  // Force the window to update

It looked odd having the countdown show "OK (0)" and the window still displayed, and the text would flicker once a second with win.update(), and the script works with it commented out.

Just need the OK button to work.

Broader context: I have a larger script that takes about 1-2 seconds to run in the office, but 6-7 seconds to run at home over VPN. 6-7 seconds is long enough that you aren't certain if the script has completeted or not, but 1-2 seconds is annoying to have to mouse over and click OK before you can continue. So I want to pop-up a msg for a couple of seconds that the script is complete, but then you don't have to click OK to close the message.

UPDATE: I was originally using something similar in an MS Access Database with VBA where I have a long script that runs in the background and I wanted a pop-up to show that the script was complete, but if the script were run unattended, it wouldn't wait for two hours until the user returned from lunch. There would be similar use cases for ScriptUI, but that isn't personally what I need it for (yet ...)

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 07, 2025 Apr 07, 2025

@Eugene Tyson - Found another really minor error with your script. It doesn't work with delaySeconds = 0.

Normally, I wouldn't care, but I figured out I could use SetFont (Page 79 of @Peter Kahrel 's guide: https://creativepro.com/files/kahrel/indesign/scriptui.html) with your script and have the script readable. I was going to replace all my alert functions with yours, but I can use the earlier script I posted if I don't need a delay.

Disregard above: I can put an "If" (if(delaySeconds)>0){ } around the countdown loop portion of your code and it works fine (And change the button text code).

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 07, 2025 Apr 07, 2025

No prob glad its a starting point. Will jump back in tomorrow if you still need help

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 07, 2025 Apr 07, 2025

Thanks again. I still need to have the OK button functional if there is a delaySeconds value. For present use, I don't HAVE to have it, but I don't think I'll figure it out on my own.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 07, 2025 Apr 07, 2025

Yeh so can't get the button to work - but can press ESC on the keyboard not sure if that's quitting the dialog  only or ending the script ... 

 

But if that works then you don't need a button. 

 

$.sleep()  freezes the UI, so the button never gets a chance to register clicks during that time.

 

I'm trying with idletask - but can't get anywhere - seems like it's single threaded so when it's doing the countdown it can't do anything else like click a button. 

 

 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 08, 2025 Apr 08, 2025

@Eugene Tyson  - Stand down, please (and tremendous thanks!!!)!

The okay button is working for me today. Not sure why - it wasn't yesterday and it didn't seem to be for you.

Your comments got my curious, so I did some testing with this:

AutocloseAlert("This message will close in 10 seconds. Checking for a really long message. Not that it matters.", 10, "Autoclose Alert");
alert("done");

Keyboard Esc did NOT do anything for the script, however, clicking the red X closed the window, but left the script running and didn't display the "done" alert until the timer expired. (Keyboard Enter didn't work either, which is the default for clicking OK in Access VBA, but I'm not going to worry about that.)

And I need the button to display the countdown timer.

If it couldn't be fixed, I might take OK off the button, but my team is used to seeing it from Access. More likely I would just set the timer to a really low value like two seconds, and if someone happened to be quick enough to get the mouse over to it, they would just think they had to click it twice for some reason.

Latest version of the code in following reply, in case something I added fixed the issue.

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 08, 2025 Apr 08, 2025

Full Script:

function set_font (control, font) {
    for (var i = 0; i < control.children.length; i++) {
    if ("GroupPanel".indexOf (control.children[i].constructor.name) > -1)
    set_font (control.children[i], font);
    else
    control.children[i].graphics.font = font;
    }
}//--end set_font;

function AutocloseAlert(message, delaySeconds, title) {
    title = title || "Script Alert";

    var win = new Window("palette", title, undefined, {closeButton:false});
    win.orientation = "column";
    win.alignChildren = "center";
 //   win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    var msg = win.add("statictext", undefined, message);
//    msg.graphics.backgroundColor = msg.graphics.newBrush (msg.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    if (delaySeconds>0){
        var btn = win.add("button", undefined, "OK (" + delaySeconds + ")");
    }
    else{
        var btn = win.add("button", undefined, "OK");      
    }

    var cancelled = false;

    // Function for button click
    btn.onClick = function () {
        cancelled = true;
        win.close();
        $.writeln("User clicked OK");
    };

    // Show the window
    set_font (win, "Tahoma:14");
    win.show();

    if (delaySeconds>0){
        // Countdown loop
        while (delaySeconds > 0 && !cancelled) {
            $.sleep(1000); // wait 1 second
            delaySeconds--;
            try {
                if(delaySeconds > 0){    
                    btn.text = "OK (" + delaySeconds + ")";
                }
                else {
                    btn.text = "OK";   
                }
                //win.update();  // Force the window to update
            } catch (e) {
                break; // window might be closed already
            }
        }

        // Close window after countdown, unless user clicked OK
        if (!cancelled) {
            win.close();
            $.writeln("Auto-closed after timeout");
        }
    }
} // End AutocloseAlert
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 08, 2025 Apr 08, 2025

@Eugene Tyson - Just so you know I'm not going crazy and in case it is helpful to you:

If I launch the script from ESTK and target ExtendScript Toolkit CC, the OK button works flawlessly. If I target FrameMaker 2022, the OK button cannot be clicked.

Not sure if that helps you or not, but I'm not going to worry too much over it. I'll just set the delay to something short like two seconds.

(Some of the team interpret it as they can't do anythiing until the timer runs down, so that works just as well anyway ...)

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 08, 2025 Apr 08, 2025

Not sure if this helps: https://stackoverflow.com/questions/31439286/does-javascript-have-anything-similar-to-vbas-doevents Your mention of single-threaded made me think of DoEvents in VBA, so I was wondering if there was something similar, but the SO page is pure javascript and mentions web browsers, so might not work with ExtendScript/ScriptUI.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 08, 2025 Apr 08, 2025

EDIT: Removed the second commented graphics line.

Another minor update - the script was not pausing if DelaySeconds was zero. I needed to change it from a pallette to a dialog:

function set_font (control, font) {
    for (var i = 0; i < control.children.length; i++) {
    if ("GroupPanel".indexOf (control.children[i].constructor.name) > -1)
    set_font (control.children[i], font);
    else
    control.children[i].graphics.font = font;
    }
}//--end set_font;

function AutocloseAlert(message, delaySeconds, title) {
    title = title || "Script Alert";

     if(delaySeconds===0){
            var win = new Window("dialog", title, undefined, {closeButton:false});
    }
    else{
        var win = new Window("palette", title, undefined, {closeButton:false});
    }
    win.orientation = "column";
    win.alignChildren = "center";
 //   win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    var msg = win.add("statictext", undefined, message);
    if (delaySeconds>0){
        var btn = win.add("button", undefined, "OK (" + delaySeconds + ")");
    }
    else{
        var btn = win.add("button", undefined, "OK",{name: "ok"});      
    }

    var cancelled = false;

    // Function for button click
    btn.onClick = function () {
        cancelled = true;
        win.close();
        $.writeln("User clicked OK");
    };

    // Show the window
    set_font (win, "Tahoma:14");
    win.show();

    if (delaySeconds>0){
        // Countdown loop
        while (delaySeconds > 0 && !cancelled) {
            $.sleep(1000); // wait 1 second
            delaySeconds--;
            try {
                if(delaySeconds > 0){    
                    btn.text = "OK (" + delaySeconds + ")";
                }
                else {
                    btn.text = "OK";   
                }
                //win.update();  // Force the window to update
            } catch (e) {
                break; // window might be closed already
            }
        }

        // Close window after countdown, unless user clicked OK
        if (!cancelled) {
            win.close();
            $.writeln("Auto-closed after timeout");
        }
    }
} // End AutocloseAlert

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 09, 2025 Apr 09, 2025

Wanted to clarify also - the commented line beginning win.graphics.background color changes the background of the pop-up from gray to white.

 

Our team (mainly myself) debated this a bit.

 

  • White matches ScriptUI defaults and tends to get the users attention. It is useful for messages like "Could not find all required master pages, the script must exit!!!"
  • Gray matches the other pop-up windows (if you didn't modify them), looks a bit more consistent, and is useful for messages like "Script complete. You may resume work."

 

Ultimately we (I) decided to leave it with gray, but it would also be simple to pass an additional parameter to the script (Like is done with the title) and have it selectable based on the intent of the message.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 09, 2025 Apr 09, 2025

Minor change to the script above.

 

If delaySeconds = 0, I added {name: "ok"} to the line that adds the OK button. This allows you to press the Kbd Enter key to close the message. (Even though since the button's text is "OK" that should work anyway, but it doesn't seem to.)

 

I intentionally did NOT add it if delaySeconds > 0 b/c it seems to work like the red X did, i.e. if you press the Kbd enter, the pop-up closes after a few seconds, but the script still doesn't continue until the delay expires.

 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 14, 2025 Apr 14, 2025

Back again - minor changes to the script. I made delaySeconds default to 0. This way you can use the script exactly the same as the alert() function, except the text will use the custom font. And a added a parameter for the bgcolor, but if you don't pass it a color, it uses gray:

function AutocloseAlert(message, delaySeconds, title, bgcolor) {
    title = title || "Script Alert";
    delaySeconds = delaySeconds || 0
    bgcolor = bgcolor || "gray";

     if(delaySeconds===0){
            var win = new Window("dialog", title, undefined, {closeButton:false});
    }
    else{
        var win = new Window("palette", title, undefined, {closeButton:false});
    }
    win.orientation = "column";
    win.alignChildren = "center";
    if(bgcolor==="white"){
        win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    }
    var msg = win.add("statictext", undefined, message);
    if (delaySeconds>0){
        var btn = win.add("button", undefined, "OK (" + delaySeconds + ")");
    }
    else{
        var btn = win.add("button", undefined, "OK",{name: "ok"});      
    }

    var cancelled = false;

    // Function for button click
    btn.onClick = function () {
        cancelled = true;
        win.close();
        $.writeln("User clicked OK");
    };

    // Show the window
    set_font (win, "Tahoma:14");
    win.show();

    if (delaySeconds>0){
        // Countdown loop
        while (delaySeconds > 0 && !cancelled) {
            $.sleep(1000); // wait 1 second
            delaySeconds--;
            try {
                if(delaySeconds > 0){    
                    btn.text = "OK (" + delaySeconds + ")";
                }
                else {
                    btn.text = "OK";   
                }
                //win.update();  // Force the window to update
            } catch (e) {
                break; // window might be closed already
            }
        }

        // Close window after countdown, unless user clicked OK
        if (!cancelled) {
            win.close();
            $.writeln("Auto-closed after timeout");
        }
    }
} // End AutocloseAlert

@Eugene Tyson New issue: I wanted something like the Enhanced Message Box for Access (but not quite as fancy (without custom button colors, delay before buttons are enabled, etc.): https://datenbank-projekt.de/projekte/improved-enhanced-message-box-ms-access

Script UI has the Confirm() function (which uses Yes/No, even though Javascript Confirm uses OK/Cancel), but this doesn't work if, for example, you wanted Abort/Retry/Ignore. I came up with the following with 4 possible buttons:

function CustomConfirm(message, title, DefaultBtn, Btn1Text, Btn2Text, Btn3Text, Btn4Text, bgcolor) {
    // Yes/No, OKOnly, OK/Cancel, Abort/Retry/Ignore, Yes/No/Cancel, Retry/Ignore, 
    title = title || "Script Alert";
    Btn1Text = Btn1Text || "OK";
    Btn2Text = Btn2Text || "";
    Btn3Text = Btn3Text || "";
    Btn4Text = Btn4Text || "";
    DefaulBtn = DefaultBtn || 0;
    bgcolor = bgcolor || "gray";
    var result = "";
    var win = new Window("dialog", title, undefined, {closeButton:false});
    win.orientation = "column";
    win.alignChildren = "left";
    if(bgcolor==="white"){
        win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    }
    var msg = win.add("statictext", undefined, message);
    var myButtonGroup = win.add ("group");
    myButtonGroup.alignment = "center";
    var Btn1 = myButtonGroup.add ("button", undefined, Btn1Text);
    if(Btn2Text!==""){
        var Btn2 = myButtonGroup.add ("button", undefined, Btn2Text);
    }
    if(Btn3Text!==""){
        var Btn3 = myButtonGroup.add ("button", undefined, Btn3Text);
    }
    if(Btn4Text!==""){
        var Btn4 = myButtonGroup.add ("button", undefined, Btn4Text);
    }
    switch(DefaultBtn){
        case 1:
            win.defaultElement=Btn1;
            break;
        case 2:
            win.defaultElement=Btn2;
            break;            
        case 3:
            win.defaultElement=Btn3;
            break;            
        case 4:
            win.defaultElement=Btn4;
            break;            
    }
// Event Listeners
    Btn1.onClick=function(){
//        alert(Btn1Text);
        result = Btn1Text;
//alert(result);
//        return result;
        win.close();
         $.writeln("User clicked Abort");
         $.writeln(Btn1Text);
      return result;
    };   
    Btn2.onClick=function(){
        result = Btn2Text;
        win.close();
         $.writeln("User clicked Retry");
         $.writeln(Btn2Text);
        return result;
    };
    Btn3.onClick=function(){
        result = Btn3Text;
        win.close();
         $.writeln("User clicked Ignore");
         $.writeln(Btn3Text);
        return result;
    };
    Btn4.onClick=function(){
        result = Btn4Text;
        win.close();
         $.writeln("User clicked Retry");
         $.writeln(Btn4Text);
        return result;
    };
    // Show the window
    set_font (win, "Tahoma:14");
    win.show();

} // End  CustomConfirm

// Usage
switch(CustomConfirm("Select A Button", undefined, 2, "Abort", "Retry", "Ignore")){
    Case "Abort"
        alert("You selected Abort")
        break;
     Case "Retry"
        alert("You selected Retry")
        break;
      Case "Ignore"
        alert("You selected Ignore")
        break;
    }

The script sets up the window properly and looks fine, but it returns "undefined" instead of the button text, and I don't know why - which makes it pretty much useless. The commented out alert buttons work and display the correct results, so I'm not sure why the return statement is not working.

 

(I'm also open to suggestions on the position of the title statement. You can't specify a title for the confirm statement. The way I have it, you have to specify "undefined" for the second position. If I move it to the end, you could ignore it, but then for a simple Yes/No pop-up with a custom button, you would have to specify "CustomConfirm("Select a button", 2, "Yes", "No", undefined, undefined, "Button Selection:")"

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 14, 2025 Apr 14, 2025

New problems:

  • I'm getting an error on the Btn4.OnClick line if I don't specify a value for Btn4Text. Previously, it was working. I tried surrounding the code with if(Btn4.ObjectValid()){ ...}, but then I get the same error "Undefined is not an object" on that line.
  • I thought I figured out the script returning undefined I was returning the button text as the result of the .onCLick function and not the result of the CustomConfirm function, but I tried passing the Btn1.onclick result to the main function return and it didn't work, and I don't know how to pass it the "selected" button.
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 15, 2025 Apr 15, 2025

Have the script working, the problem was in the calling procedure. Here's the sloppy script with commented lines still included:

function CustomConfirm(message, title, DefaultBtn, Btn1Text, Btn2Text, Btn3Text, Btn4Text, bgcolor) {
    // Yes/No, OKOnly, OK/Cancel, Abort/Retry/Ignore, Yes/No/Cancel, Retry/Ignore, 
    title = title || "Script Alert";
    Btn1Text = Btn1Text || "";
    Btn2Text = Btn2Text || "";
    Btn3Text = Btn3Text || "";
    Btn4Text = Btn4Text || "";
    DefaulBtn = DefaultBtn || 0;
    bgcolor = bgcolor || "gray";
    var mainresult = "";
    var win = new Window("dialog", title, undefined, {closeButton:false});
    win.orientation = "column";
    win.alignChildren = "left";
    if(bgcolor==="white"){
        win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    }
    var msg = win.add("statictext", undefined, message);
    var myButtonGroup = win.add ("group");
    myButtonGroup.alignment = "center";
    var Btn1 = myButtonGroup.add ("button", undefined, Btn1Text);
            if(Btn1Text===""){
            Btn1.visible=false;
        }
//    if(Btn2Text!==""){
        var Btn2 = myButtonGroup.add ("button", undefined, Btn2Text);
        if(Btn2Text===""){
            Btn2.visible=false;
        }        
//    }
 //   if(Btn3Text!==""){
        var Btn3 = myButtonGroup.add ("button", undefined, Btn3Text);
        if(Btn3Text===""){
            Btn3.visible=false;
        }        
//    }
//    if(Btn4Text!==""){
        var Btn4 = myButtonGroup.add ("button", undefined, Btn4Text);
        if(Btn4Text===""){
            Btn4.visible=false;
        }
 //   }
    switch(DefaultBtn){
        case 1:
            win.defaultElement=Btn1;
            break;
        case 2:
            win.defaultElement=Btn2;
            break;            
        case 3:
            win.defaultElement=Btn3;
            break;            
        case 4:
            win.defaultElement=Btn4;
            break;            
    }
//alert(Btn4.ObjectValid())
// Event Listeners
    Btn1.onClick=function(){
//        alert(Btn1Text);
        result = Btn1Text;
//alert(result);
//        return result;
        win.close();
         $.writeln("User clicked Abort");
         $.writeln(Btn1Text);
      return result;
    };   
    Btn2.onClick=function(){
        result = Btn2Text;
        win.close();
         $.writeln("User clicked Retry");
         $.writeln(Btn2Text);
        return result;
    };
    Btn3.onClick=function(){
        result = Btn3Text;
        win.close();
         $.writeln("User clicked Ignore");
         $.writeln(Btn3Text);
        return result;
    };


        Btn4.onClick=function(){
            result = Btn4Text;
            win.close();
 //            $.writeln("User clicked Retry");
 //            $.writeln(Btn4Text);
            return result;
        }


    // Show the window
    set_font (win, "Tahoma:14");
    win.show();
 //   alert(Btn1.onClick())
    mainresult = result
//    alert (mainresult)
 $.writeln(mainresult);    
    return mainresult;

} // End  CustomConfirm

Calling functions:

//alert(CustomConfirm("Select A Button:", undefined, 2, undefined, "Abort", "Retry", "Ignore"))

Returns what was selected ...

var answer = CustomConfirm("Select A Button:", undefined, 2, undefined, "Abort", "Retry", "Ignore");
//alert(answer);
if(answer==="Abort"){
    alert("You selected Abort");
    }
else if(answer==="Retry"){
    alert("You selected Retry");
    }
else if(answer==="Ignore"){
    alert("You selected Ignore");
    }

Above works perfectly:

var answer = CustomConfirm("Select A Button:", undefined, 2, undefined, "Abort", "Retry", "Ignore");
switch(answer){
    Case "Abort"
        alert("You selected Abort")
        break;
     Case "Retry"
        alert("You selected Retry")
        break;
      Case "Ignore"
        alert("You selected Ignore")
        break;
    }

Above does nothing, not sure why ...

if(CustomConfirm("Select A Button:", undefined, 2, undefined, "Abort", "Retry", "Ignore")==="Abort"){
    alert("You selected Abort");
    }
else if(CustomConfirm("Select A Button:", undefined, 2, undefined, "Abort", "Retry", "Ignore")==="Retry"){
    alert("You selected Retry");
    }
else if(CustomConfirm("Select A Button:", undefined, 2, undefined, "Abort", "Retry", "Ignore")==="Ignore"){
    alert("You selected Ignore");
    }

Above is awkward. If you are clicking Button 3, you have to click it three times (the pop-up reappears) and then it works.
To Do:

  • The buttons should be right aligned. The script still creates 4 buttons, but the buttons are hidden if they don't have text. So if you have only an OK button, the text will show up on button 1, which is to the left. I need to shift the buttons over. I'll post updated code soon.
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 15, 2025 Apr 15, 2025

Fixed it. Final code (it could be prettier/more efficient, but it works):

function CustomConfirm(message, title, DefaultBtn, Btn1Text, Btn2Text, Btn3Text, Btn4Text, bgcolor) {
    // Yes/No, OKOnly, OK/Cancel, Abort/Retry/Ignore, Yes/No/Cancel, Retry/Ignore, 
    title = title || "Script Alert";
    Btn1Text = Btn1Text || "";
    Btn2Text = Btn2Text || "";
    Btn3Text = Btn3Text || "";
    Btn4Text = Btn4Text || "";  
    DefaulBtn = DefaultBtn || 0;
    // Shift the buttons:
    if (Btn1Text===""){
        // Show at least one button
        Btn4Text="OK";
    }
    else if (Btn2Text===""){
        // Only one button
        Btn4Text=Btn1Text;
        Btn1Text = "";
        if (DefaultBtn===1){
            DefaultBtn=4;
        }
    }
    else if (Btn3Text===""){
        // Two Buttons
        Btn4Text=Btn2Text;
        Btn3Text=Btn1Text;
        Btn2Text = "";
        Btn1Text = "";
        if (DefaultBtn===1){
            DefaultBtn=3;
        }
        else if (DefaultBtn===2){
            DefaultBtn=4
        }
     }
    else if (Btn4Text===""){
        // Three Buttons
        Btn4Text=Btn3Text;
        Btn3Text=Btn2Text;
        Btn2Text = Btn1Text;
        Btn1Text = "";
        if (DefaultBtn===1){
            DefaultBtn=2;
        }
        else if (DefaultBtn===2){
            DefaultBtn=3;
        }
        else if (DefaultBtn===3){
            DefaultBtn=4;
        }            
    }
    bgcolor = bgcolor || "gray";
    var result = "";
    var win = new Window("dialog", title, undefined, {closeButton:false});
    win.orientation = "column";
    win.alignChildren = "left";
    if(bgcolor==="white"){
        win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    }
    var msg = win.add("statictext", undefined, message);
    var myButtonGroup = win.add ("group");
    myButtonGroup.alignment = "right";
    var Btn1 = myButtonGroup.add ("button", undefined, Btn1Text);
    if(Btn1Text===""){
        Btn1.visible=false;
    }
    var Btn2 = myButtonGroup.add ("button", undefined, Btn2Text);
    if(Btn2Text===""){
        Btn2.visible=false;
    }        
    var Btn3 = myButtonGroup.add ("button", undefined, Btn3Text);
    if(Btn3Text===""){
        Btn3.visible=false;
    }        
    var Btn4 = myButtonGroup.add ("button", undefined, Btn4Text);
    if(Btn4Text===""){
        Btn4.visible=false;
    }
    switch(DefaultBtn){
        case 1:
            win.defaultElement=Btn1;
            break;
        case 2:
            win.defaultElement=Btn2;
            break;            
        case 3:
            win.defaultElement=Btn3;
            break;            
        case 4:
            win.defaultElement=Btn4;           
    }
// Event Listeners
    Btn1.onClick=function(){
        result = Btn1Text;
        win.close();
      return result;
    };   
    Btn2.onClick=function(){
        result = Btn2Text;
        win.close();
        return result;
    };
    Btn3.onClick=function(){
        result = Btn3Text;
        win.close();
        return result;
    };
    Btn4.onClick=function(){
        result = Btn4Text;
        win.close();
        return result;
    }
    // Show the window
    set_font (win, "Tahoma:14");
    win.show();
    return result;
} // End  CustomConfirm

Calling Code (I'm not sure why switch doesn't work, but ...):

var answer = CustomConfirm("Select A Button:", undefined, 2, "Retry", "Ignore");
// Include up to 4 buttons in the order you want them to appear. Set Default Button to 0 if you don't want a default.
if(answer==="Retry"){
    alert("You selected Retry");
}
else if(answer==="Ignore"){
    alert("You selected Ignore");
}

Alernative (simpler) calling statement:

switch(CustomConfirm("Select A Button:", undefined, 2, "Abort", "Retry", "Ignore")){
// Include up to 4 buttons in the order you want them to appear. Set Default Button to 0 if you don't want a default.
    case "Abort":
        alert("You selected Abort")
        break;
     case "Retry":
        alert("You selected Retry")
        break;
      case "Ignore":
        alert("You selected Ignore")
}

 

Advantages over standard Confirm dialog (or even VBA Enhanced Message Box):

  • You can have up to 4 buttons. Probably overkill, but there are times I would have liked it with VBA. At least 3 (Yes/No/Cancel,  Abort/Retry/Ignore) is handy.
  • You can specify ANY name for the buttons.
  • Result matches the BTN name. (If you use custom button names with EMB, it returns vbBt3 and you have to figure out which button that is.)
  • Can specify any button as the default button - or no default button.

Disadvantage:

  • Kbd Enter and Kbd Esc don't seem to do anything in FrameMaker. I think they do work in ExtendScriptToolKit. (There seem to be a lot of things that don't work in FrameMaker but do work in ScriptUI, for whatever reason.)
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 16, 2025 Apr 16, 2025

Minor edits above. "case 4" didn't need a break statement since it was the last statement, but it didn't hurt anything. In the calling statement, "case" needed to be lower-case instead of initial caps, and I was missing the ":" at the end of the statement.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 23, 2025 Apr 23, 2025
LATEST

Updated the scripts to auto-size and or wrap correctly with the help of this thread: https://community.adobe.com/t5/indesign-discussions/script-ui-dynamically-autosizing-statictext/td-p... 

 

EDIT: Had to make a minor change to the "if" statement in AutocloseAlert(). The previous version would fail (only display the first line) if message length was < 80 and you have manual line feeds, e.g.:

AutocloseAlert("Line 1\rLine2");

EDIT2: Had to correct the "if" statement, not found returns -1, not 0.

 

Here are the final (I hope) versions:

function AutocloseAlert(message, delaySeconds, title, bgcolor) {
    title = title || "Script Alert";
    delaySeconds = delaySeconds || 0
    bgcolor = bgcolor || "gray";

     if(delaySeconds===0){
            var win = new Window("dialog", title, undefined, {closeButton:false});
    }
    else{
        var win = new Window("palette", title, undefined, {closeButton:false});
    }
    win.margins = 10;
    win.orientation = "column";
    win.alignChildren = "center";
    if(bgcolor==="white"){
        win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    }
    // Dialog Width To Be Defined:
    var w_width = 450;  

    //  80 below is somewhat arbitrary. Run the script and see where the first line ends. Adjust w_static text to a bit longer than that. Uncomment the line below to get the text length, Use that in the "if" statement.
    //alert (message.length)
    if (message.length < 80 && message.indexOf("\r")===-1 && message.indexOf("\n")===-1) {
    // single line
         var msg = win.add('statictext', undefined, message);
    }
    else{
    // multiline    
        var msg = win.add('statictext', undefined, 'X', {multiline: true});
        // if not using standard font size, Font must be defined below, even if using set_font, or the message will truncate unpredictably.
        msg.graphics.font="Tahoma:14";        
        
        var X_width = msg.preferredSize[0];
        with(msg){preferredSize = [-1,-1]; characters = ~~(w_width/X_width); preferredSize[1] = -1;};
        msg.text = message;
    }

    if (delaySeconds>0){
        var btn = win.add("button", undefined, "OK (" + delaySeconds + ")");
    }
    else{
        var btn = win.add("button", undefined, "OK",{name: "ok"});      
    }

    var cancelled = false;

    // Function for button click
    btn.onClick = function () {
        cancelled = true;
        win.close();
        $.writeln("User clicked OK");
    };

    // Show the window
    set_font (win, "Tahoma:14");
    win.show();

    if (delaySeconds>0){
        // Countdown loop
        while (delaySeconds > 0 && !cancelled) {
            $.sleep(1000); // wait 1 second
            delaySeconds--;
            try {
                if(delaySeconds > 0){    
                    btn.text = "OK (" + delaySeconds + ")";
                }
                else {
                    btn.text = "OK";   
                }
                //win.update();  // Force the window to update
            } catch (e) {
                break; // window might be closed already
            }
        }

        // Close window after countdown, unless user clicked OK
        if (!cancelled) {
            win.close();
            $.writeln("Auto-closed after timeout");
        }
    }
} // End AutocloseAlert

function set_font (control, font) {
    for (var i = 0; i < control.children.length; i++) {
    if ("GroupPanel".indexOf (control.children[i].constructor.name) > -1)
    set_font (control.children[i], font);
    else
    control.children[i].graphics.font = font;
    }
}//--end set_font;


function CustomConfirm(message, title, DefaultBtn, Btn1Text, Btn2Text, Btn3Text, Btn4Text, bgcolor) {
    // Yes/No, OKOnly, OK/Cancel, Abort/Retry/Ignore, Yes/No/Cancel, Retry/Ignore, 
    title = title || "Script Alert";
    Btn1Text = Btn1Text || "";
    Btn2Text = Btn2Text || "";
    Btn3Text = Btn3Text || "";
    Btn4Text = Btn4Text || "";  
    DefaulBtn = DefaultBtn || 0;
    // Shift the buttons:
    if (Btn1Text===""){
        // Show at least one button
        Btn4Text="OK";
    }
    else if (Btn2Text===""){
        // Only one button
        Btn4Text=Btn1Text;
        Btn1Text = "";
        if (DefaultBtn===1){
            DefaultBtn=4;
        }
    }
    else if (Btn3Text===""){
        // Two Buttons
        Btn4Text=Btn2Text;
        Btn3Text=Btn1Text;
        Btn2Text = "";
        Btn1Text = "";
        if (DefaultBtn===1){
            DefaultBtn=3;
        }
        else if (DefaultBtn===2){
            DefaultBtn=4
        }
     }
    else if (Btn4Text===""){
        // Three Buttons
        Btn4Text=Btn3Text;
        Btn3Text=Btn2Text;
        Btn2Text = Btn1Text;
        Btn1Text = "";
        if (DefaultBtn===1){
            DefaultBtn=2;
        }
        else if (DefaultBtn===2){
            DefaultBtn=3;
        }
        else if (DefaultBtn===3){
            DefaultBtn=4;
        }            
    }
    bgcolor = bgcolor || "gray";
    var result = "";
    var win = new Window("dialog", title, undefined, {closeButton:false});
    win.margins = 10;
    win.orientation = "column";
    win.alignChildren = "left";
    if(bgcolor==="white"){
        win.graphics.backgroundColor = win.graphics.newBrush (win.graphics.BrushType.SOLID_COLOR, [1.0, 1.0, 1.0]);
    }
    // Dialog Width to be defined:
    // If using Tahoma:14, there is no reason to set w_width below 350. Min Width is determined by the 4 buttons, even if some are not visible. Values over 350 make the window wider. I like 450.
    var w_width = 450;
    var msg = win.add("statictext",  undefined, 'X', {multiline: true});
    // Must be set here or some of the message gets chopped off.
    msg.graphics.font="Tahoma:14";
    var X_width = msg.preferredSize[0];
    with (msg){preferredSize = [-1,-1]; characters = ~~(w_width/X_width); preferredSize[1] = -1;};
    msg.text=message
    var myButtonGroup = win.add ("group");
    myButtonGroup.alignment = "right";
    var Btn1 = myButtonGroup.add ("button", undefined, Btn1Text);
    if(Btn1Text===""){
        Btn1.visible=false;
    }
    var Btn2 = myButtonGroup.add ("button", undefined, Btn2Text);
    if(Btn2Text===""){
        Btn2.visible=false;
    }        
    var Btn3 = myButtonGroup.add ("button", undefined, Btn3Text);
    if(Btn3Text===""){
        Btn3.visible=false;
    }        
    var Btn4 = myButtonGroup.add ("button", undefined, Btn4Text);
    if(Btn4Text===""){
        Btn4.visible=false;
    }
    switch(DefaultBtn){
        case 1:
            win.defaultElement=Btn1;
            break;
        case 2:
            win.defaultElement=Btn2;
            break;            
        case 3:
            win.defaultElement=Btn3;
            break;            
        case 4:
            win.defaultElement=Btn4;                       
    }
// Event Listeners
    Btn1.onClick=function(){
        result = Btn1Text;
        win.close();
      return result;
    };   
    Btn2.onClick=function(){
        result = Btn2Text;
        win.close();
        return result;
    };
    Btn3.onClick=function(){
        result = Btn3Text;
        win.close();
        return result;
    };
    Btn4.onClick=function(){
        result = Btn4Text;
        win.close();
        return result;
    }
    // Show the window
    set_font (win, "Tahoma:14");
    win.show();
    return result;
} // End  CustomConfirm

// Calling functions:
AutocloseAlert("This short message will close in 5 seconds.", 5, "Autoclose Alert");

AutocloseAlert("This much longer message will wrap nicely and will stay open until you click the OK button");

switch(CustomConfirm("Super long text, just a test, FWIW. No need to panic. Just see what happens. Go with the flow ... \r\rThis is Line2", undefined, 2, "Abort", "Retry", "Ignore")){
    case "Abort":
        alert("You selected Abort")
        break;
     case "Retry":
        alert("You selected Retry")
        break;
      case "Ignore":
        alert("You selected Ignore")
}

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines