[javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Forum for the PDF-XChange Editor - Free and Licensed Versions

Moderators: PDF-XChange Support, Daniel - PDF-XChange, Chris - PDF-XChange, Sean - PDF-XChange, Paul - PDF-XChange, Vasyl - PDF-XChange, Ivan - Tracker Software, Stefan - PDF-XChange

User avatar
Mathew
User
Posts: 934
Joined: Thu Jun 19, 2014 7:30 pm

[javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Mathew »

When an async function runs from a custom dialog (app.execDialog) event, any application dialogs will show up as blank, so the user cannot choose whether to allow it.
image.png
To reproduce, use this dialog to select a file to open. PDF XChange must be set to Preferences > Security > "Use Trusted/Untrusted List" and the location must not be in the list. This shows a file permission dialog.

Code: Select all

{
  const dia = {
    open(dialog) {
      const path = app.browseForDoc();
      Promise.resolve(path)
      .then( p => {
        // put the file opening into async
        return app.openDoc({
          cPath: p.cPath,
          cFS: p.cFS,
        });
      })
      .catch( e =>  dialog.load({'fPth': e}));
      // do something with the dialog before the async
      dialog.load({'fPth': path.cPath});
    },
    description: {name: "Open file", elements: [
      { type: 'static_text', name: "Select a file to open", width: 300},
      { type: 'button', name: 'Browse…', item_id: 'open'},
      { type: 'static_text', name: "", item_id: 'fPth', alignment: 'align_fill'},
    ]}
  };
  
  app.execDialog(dia);
}
But similarly, if one were to trigger a dialog asking if the user wants to save:

Code: Select all

{
  const dia = {
    open(dialog) {
      const path = app.browseForDoc();
      const doc = app.openDoc({
          cPath: path.cPath,
          cFS: path.cFS,
        });
      Promise.resolve(doc)
      .then( p => {
        p.dirty = true;
        // "do you want to save?"
        return p.closeDoc(false)
      })
      .catch( e =>  dialog.load({'fPth': e}));
      // do something with the dialog before the async
      dialog.load({'fPth': path.cPath});
    },
    description: {name: "Open file", elements: [
      { type: 'static_text', name: "Select a file to open", width: 300},
      { type: 'button', name: 'Browse…', item_id: 'open'},
      { type: 'static_text', name: "", item_id: 'fPth', alignment: 'align_fill'},
    ]}
  };
  
  app.execDialog(dia);
}
You do not have the required permissions to view the files attached to this post.
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 13260
Joined: Wed Jan 03, 2018 6:52 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Daniel - PDF-XChange »

Hello, Mathew

thank you for the report - I have raised this to the Dev team fore review and action - if possible.

Kind regards,
Dan McIntyre - Support Technician
PDF-XChange Co. LTD

+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
[email protected]
User avatar
Mathew
User
Posts: 934
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Mathew »

Here's an even more nasty example: If there's no cancel option, then PDF XChange will need to be force-quit:

Code: Select all

{
  const dia = {
    open(dialog) {
      const path = app.browseForDoc();
      Promise.resolve(path)
      .then( p => {
        // a dialog without a cancel option will require a force quit of the program
        app.alert({
          cTitle: "Can't do anything",
          cMsg: "Select OK"});
      })
      .catch( e =>  dialog.load({'fPth': e}));
      // do something with the dialog before the async
      dialog.load({'fPth': path.cPath});
    },
    description: {name: "Open file", elements: [
      { type: 'static_text', name: "Select a file to open", width: 300},
      { type: 'button', name: 'Browse…', item_id: 'open'},
      { type: 'static_text', name: "", item_id: 'fPth', alignment: 'align_fill'},
    ]}
  };
  
  app.execDialog(dia);
}
I checked with PXCE v10.8.5 and all async functions get put off until app.execDialog() is finished; so basically you can't run async functions while a custom dialog is active: They all run immediately after the dialog is closed.

PXCE 10.3 has the same problem as 11.0.1 (blank dialog).
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 13260
Joined: Wed Jan 03, 2018 6:52 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Daniel - PDF-XChange »

Hello, Mathew

Oh, yes that certainly sounds like a.. "pleasant" bug. - forwarded with urgency.

Kind regards,
Dan McIntyre - Support Technician
PDF-XChange Co. LTD

+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
[email protected]
User avatar
Roman - Tracker Supp
Site Admin
Posts: 346
Joined: Sun Nov 21, 2004 3:19 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Roman - Tracker Supp »

Hi Mathew,
I cannot reproduce the described behaviour in the Editor 11.0.1. For me, the script first displays the custom dialog, the `Browse...` button handler settles a promise with the browsed path and the `app.openDoc` as a continuation. The `app.openDoc` is executed after I close the dialog (i.e. when the script execution is complete) and the permission dialog looks and works normally. The same is with the `app.alert` variant.
Mathew wrote: ↑Fri Aug 14, 2026 9:14 pm so basically you can't run async functions while a custom dialog is active: They all run immediately after the dialog is closed.
This is an expected behavior. According to the JS specification the tasks generated by resolved promises should be processed when the JS execution context is empty. So to be conformant we cannot drain the task queue while the script is executing `app.execDialog`.

May I know what you want to implement with that async code in the dialog handler function?
In principle, we could implement an async version of `app.execDialog` (say, `app.execDialogAsync`) that would allow execution of async tasks right after the execution of a dialog handler function.
User avatar
Mathew
User
Posts: 934
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Mathew »

Roman - Tracker Supp wrote: ↑Sun Aug 23, 2026 7:33 pm I cannot reproduce the described behaviour in the Editor 11.0.1. For me, the script first displays the custom dialog, the `Browse...` button handler settles a promise with the browsed path and the `app.openDoc` as a continuation. The `app.openDoc` is executed after I close the dialog (i.e. when the script execution is complete) and the permission dialog looks and works normally. The same is with the `app.alert` variant.
Hi Roman,
Thanks for looking into this.
Well, that's strange. Maybe because I'm on a Win 10 machine? I did notice that different versions of PXCE behaved differently, and v10.8.5 is the same for me as you describe above. For me, v11.0.1 does it every time. I've recorded a video:
blank dialog.gif
Roman - Tracker Supp wrote: ↑Sun Aug 23, 2026 7:33 pm This is an expected behavior. According to the JS specification the tasks generated by resolved promises should be processed when the JS execution context is empty. So to be conformant we cannot drain the task queue while the script is executing `app.execDialog`.

May I know what you want to implement with that async code in the dialog handler function?
I've noticed that app.execDialog does completely stop interval and timeouts until the dialog has closed. And if I use app.timeOut(1) instead of Promise.resolve(), it does wait until after the dialog.

My case is (as usual) a bit complex: I'd written a script to check if a file is locked by another user before opening the file. I ran into this problem when I rewrote the script asynchronously, so that it could try multiple times to open the file before giving up and showing a dialog. I was using that script to open a file from a button event in app.execDialog. It would not work to defer this until after the dialog, because the user is expecting a result from interacting with the dialog. My workaround is to create a separate modal version - for this case, it works fine.

What this tells me is that one should never try to run any async functions from events in app.execDialog.
Roman - Tracker Supp wrote: ↑Sun Aug 23, 2026 7:33 pm In principle, we could implement an async version of `app.execDialog` (say, `app.execDialogAsync`) that would allow execution of async tasks right after the execution of a dialog handler function.
Well that's on my wish list! Actually a bit more: I think we've already discussed a feature request for a non-modal async dialog. The concept makes a lot of sense to me because the dialog is already event-based. viewtopic.php?t=46657
You do not have the required permissions to view the files attached to this post.
User avatar
Mathew
User
Posts: 934
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Mathew »

Just tested on 11.1 preview portable version and it delays the async until after the dialog is closed, similar to v10.8.5, and as Roman described. Maybe the intended effect, and obviously not as painful as locking up the application, but it prevents any async function from being used during a dialog (ie from a button press, change in input, etc). Also quite unintuitive at first -- it's similar to the observation that app.execDialog doesn't show error output on the console until the dialog is ended...

The other use case I was noodling with was live previews (of the hatch pattern tool, for example) while the dialog is open. I can do it synchronously, but if the user accidentally enters a too dense pattern, the dialog will be held up until the pattern is done drawing.
Last edited by Mathew on Mon Aug 24, 2026 10:27 pm, edited 1 time in total.
User avatar
Roman - Tracker Supp
Site Admin
Posts: 346
Joined: Sun Nov 21, 2004 3:19 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Roman - Tracker Supp »

We need to think how to implement an async version of `app.execDialog`. A solution to keep the dialog modal, and just produce a Promise at the script level seems to be simple, but does not look idiomatically async — the events generated by the dialog are still to be handled via synchronous callbacks.

Perhaps, a better solution would be to make the dialog object an async generator, so that the use will look like:

Code: Select all

for await (const event of app.execDialogAsync({/* dialog template */})) {
  switch (event.item_id) {
    case 'open':
      //...
  }
}
User avatar
Mathew
User
Posts: 934
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Mathew »

Roman - Tracker Supp wrote: ↑Mon Aug 24, 2026 7:32 pm We need to think how to implement an async version of `app.execDialog`. A solution to keep the dialog modal, and just produce a Promise at the script level seems to be simple, but does not look idiomatically async — the events generated by the dialog are still to be handled via synchronous callbacks.

Perhaps, a better solution would be to make the dialog object an async generator, so that the use will look like:

Code: Select all

for await (const event of app.execDialogAsync({/* dialog template */})) {
  switch (event.item_id) {
    case 'open':
      //...
  }
}
I see the beauty in that: It effectively reduces the dialog template to just the description part; although I don't know how in this case the dialog would be communicated with: event.dialog.load() and event.dialog.end() so even initialize() becomes an event (the first one)?
User avatar
Roman - Tracker Supp
Site Admin
Posts: 346
Joined: Sun Nov 21, 2004 3:19 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Roman - Tracker Supp »

It effectively reduces the dialog template to just the description part
Yes!
how in this case the dialog would be communicated with: event.dialog.load() and event.dialog.end()
We could make the `dialog` a property of the `event` object (event.dialog.load(...)):

Code: Select all

for await (const {dialog, item_id} of app.execDialogAsync({/* dialog template */})) {
  switch (item_id) {
    case 'open':
       dialog.load(item_id, ...);
      //...
  }
}
Anyways, it is still a very vague idea...we are going way far from the traditional Adobe JS API design.
Definitely not for the upcoming release. :)
User avatar
Mathew
User
Posts: 934
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Mathew »

:) well it's enjoyable to imagine (for me): Someone's got to do the hard part still.

One day maybe we'll have something elegant as you describe - I see it opening up quite a few possibilities for scripts.
we are going way far from the traditional Adobe JS API design.
The Adobe API is quite old already and has weathered time quite well; I do think its boundaries do need stretching. In my mind there are some glaring omissions (no way to properly handle bookmarks or links, OCGs only partly supported, stamp annotations barely supported, all the menu improvements PDF-XChange added, no modules, etc), but this does remind me a little of the early web days when individual companies were adding to the web standards. I've been keeping tabs on PDF-XChange's additions and have in my todo list to make something that could be more widely shared, but haven't really come up with a way to do that yet.

Thanks again for looking at it.
User avatar
Roman - Tracker Supp
Site Admin
Posts: 346
Joined: Sun Nov 21, 2004 3:19 pm

Re: [javascript bug v11.0.1] async function during custom dialog results in blank application dialog boxes

Post by Roman - Tracker Supp »

I agree Mathew.
Thanks for pushing the boundaries for us. :)