Skip to main content
Inspiring
April 7, 2025
Answered

AutocloseAlert, CustomConfirm, and CustomPrompt Messages

  • April 7, 2025
  • 1 reply
  • 2217 views

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-p/7460138

 

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!!!

Correct answer Marshall_Brooks

I think I see the problem, but not the solution.

"answer" is being returned by the .onClick of either button, but nothing is being returned by CustomPrompt(), but I don't see how to pass "answer" to CustomPrompt() so that it can then be passed to the calling function.

 

Solved - I'll update the code above in a minute ...


CustomPrompt Code:

var result;
result = CustomPrompt("test","input","title");
alert (result);
result = prompt("test","input","title");
alert (result);

function CustomPrompt(message, defaultinput, title)
{
    var usercancelled = false;
    title = title || "Script Alert";
    defaultinput = defaultinput || "";
    var win = new Window("dialog", title, undefined, {closeButton:false});
    win.orientation = "row"; // not deprecated and required here, despite what VS Code says.
    win.alignChildren = "top";
    win.margins = 10;

    var myInputGroup = win.add ("group");
    myInputGroup.orientation = "column";
    myInputGroup.alignChildren = "left";
    // Dialog Width To Be Defined:
    var w_width = 275;

    //  150 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 < 150 && message.indexOf("\r")===-1 && message.indexOf("\n")===-1)
    {
    // single line
         var msg = myInputGroup.add('statictext', undefined, message);
    }
    else
    
    {
    // multiline
        var msg = myInputGroup.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];
        msg.preferredSize = [-1,-1];
        msg.characters = ~~(w_width/X_width);
        msg.preferredSize[1] = -1;
        msg.text = message;
    }
    var InputBox = myInputGroup.add ("edittext", undefined, defaultinput);
    InputBox.characters = 30;
    InputBox.active = true;
    var myButtonGroup = win.add ("group");
    myButtonGroup.orientation = "column";
    var btnOk = myButtonGroup.add ("button", undefined, "OK", {name: "ok"});
    var btnCancel = myButtonGroup.add ("button", undefined, "Cancel", {name: "cancel"});
    btnOk.onClick = function ()
    {
        win.close();
    }
    btnCancel.onClick = function ()
    {
        win.close();
        usercancelled = true;
    }
    set_font (win, "Tahoma:14");
    win.show ();
    if (usercancelled ===true)
    {
        return null;
    }
    else
    {
        return InputBox.text
    }
} // end CustomPrompt

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

Minor edits above. I had "if message.length < 15" instead of "if message.length < 150". Also I changed w_width to 275. Script was truncating after 6 lines of text with 250, but I don't know why and I am not sure why 275 works better.

1 reply

Community Expert
April 7, 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();
}
Community Expert
April 7, 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");