executeAsModal isCanceled does not work

I want to perform some action on progress bar button “Cancel” click. But below code does not work. Can you please help?


async function batchProcess(executionContext) {
  for (const file of files) {
    await app.open(file);
    await checkDocSize();
    if (executionContext.isCancelled) {
      await app.activeDocument.closeWithoutSaving();
      throw "user cancelled";
    }
  }
}

With your code, if you manage to click Cancel after exeModal and before the batchProcess is called, then it should work, because execution context then would have isCanceled as true. If you want to perform something whenever Cancel is clicked, use onCancel (again, please check the docs)

And use it before the loop:

async function batchProcess(executionContext) {
  executionContext.onCancel(() => {
      await app.activeDocument.closeWithoutSaving();
      throw "user cancelled";
  }
  
  <...>
}

Hi @Karmalakas I tried below code but It does not work.
I debugged also and saw that It is returning from 2nd line only.

> async function batchProcess(executionContext) {
>   executionContext.onCancel(async () => {
>     await app.activeDocument.closeWithoutSaving();
>   });
>   for (const file of files) {
>     await app.open(file);
>     await checkDocSize();
>   }
> }

Sorry, I don’t understand what you mean

@Karmalakas The below code is not working, to perform some action on progress bar “Cancel” button clicked.

> async function batchProcess(executionContext) {
>   executionContext.onCancel(async () => {
>     await app.activeDocument.closeWithoutSaving();
>   });
>   for (const file of files) {
>     await app.open(file);
>     await checkDocSize();
>   }
> }

Blockquote

Could you elaborate the “not working” part? What happens? What do you get in console if you break on different lines? What does “returning from 2nd line only” mean? Do you get into the callback at all when you click “Cancel”?

@Karmalakas code did not execute. It just return from 2nd line only.

OK, my bad. Now that I’m at my PC, I could test it. You could also, by checking console output and docs - it’s all there

async function batchProcess(ctx) {
    ctx.onCancel = () => {
        console.log('CANCEL')
    }

    let now = new Date()
    
    for (const file of files) {
        if (ctx.isCancelled) {
            return
        }

        console.log(`Seconds passed: ${((new Date()) - now) / 1000}`)
        await wait(1000)
    }
}

P. S. I still don’t understand what you meant by “return from 2nd line” :confused:

@Karmalakas can you please test with below code:

async function batchProcess(ctx) {
  ctx.onCancel = async() => {
    await app.activeDocument.closeWithoutSaving();
    console.log("done");
}

let now = new Date()

for (const file of files) {
    if (ctx.isCancelled) {
        return
    }

    console.log(`Seconds passed: ${((new Date()) - now) / 1000}`)
    await wait(1000)
}
}

Test what exactly? There’s nothing to close, because none of the files are opened. What do you expect from this piece of script and what do you actually get?

@Karmalakas Suppose plugin has opened one document and doing some process on it, in the meanwhile user clicked on progress bar “Cancel” button to stop the process. So, on click “Cancel” button I want to close the current active document in photoshop and stop the current plugin execution process. I tried with below code but It is not working. Unable to close the active doc and process.

async function batchProcess(ctx) {
  ctx.onCancel = async() => {
    await app.activeDocument.closeWithoutSaving();
    console.log("done");
}

  for (const file of files) {
    if (ctx.isCancelled) {
      return
  }
    await app.open(file);
    await checkDocSize();
  }
}

Once again - if you have checked the console output, you would’ve seen what’s the issue right away…

I’d say it’s a Ps limitation or a bug, that active doc cannot be accessed inside onCancel() while Ps is still in modal state. It shows the error:

Unhandled exception in JavaScript function called by host: TypeError: Cannot read properties of undefined (reading 'documentID')

Although with the delay it works:

var exeModal = require('photoshop').core.executeAsModal;
var app = require('photoshop').app;
var fs = require("uxp").storage.localFileSystem;

let folder = await fs.getFolder()
let entries = await folder.getEntries()
let files = entries.filter(entry => entry.isFile)

function wait(milliseconds) {
    return new Promise(resolve => setTimeout(resolve, milliseconds));
}

exeModal(batchProcess);
async function batchProcess(ctx) {
    ctx.onCancel = () => {
        console.log('CANCEL')
        setTimeout(() => exeModal(() => app.activeDocument.closeWithoutSaving()), 3000);
    }

    let now = new Date()
    
    for (const file of files) {
        if (ctx.isCancelled) {
            return
        }

        console.log(`Seconds passed: ${((new Date()) - now) / 1000}`)
        await wait(1000)
    }
}

Maybe @Jarda might have some insight