Writing an InDesign UXP plugin I want to perform a file-related action and wrap that in one undo step. Unfortunately, as soon as I create the file object, the undo recording stops. The function continues to run and works fine, but all steps in the layout after the creation of the file object get their own undo step, which is annoying for the user (and possibly impacting performance).
Simplified version of my code:
const indesign = require("indesign"),
app = indesign.app,
uxpStorage = require('uxp').storage,
fs = uxpStorage.localFileSystem;
app.doScript(placeImage.bind(this, imgSrcUrl, page), indesign.ScriptLanguage.UXPSCRIPT,
undefined, indesign.UndoModes.ENTIRE_SCRIPT, "place an image");
async function placeImage(imgSrcUrl, page) {
const frame = page.rectangles.add( ... ); // Rectangle constructor
frame.applyObjectStyle(obStyle, true); // obStyle: my preferred ObjectStyle
const resp = await fetch(imgSrcUrl);
const buffer = await resp.arrayBuffer();
const tmpFile = await tmpFolder.createEntry(fileName, {overwrite: true});
// from now on, all layout-related actions get their own undo step
const bytesWritten = await tmpFile.write(buffer, {format: uxpStorage.formats.binary});
frame.place(tmpFile);
frame.fit(indesign.FitOptions.PROPORTIONALLY)
frame.fit(indesign.FitOptions.FRAME_TO_CONTENT)
}
Using the fs module to write the file, this does not occur, InDesign keeps recording the undo action. But for frame.place I need a File object.
For me, this looks like a bug. Any ideas or workarounds?
Never used bind, but looked it up as @medium_jon just bumped this thread.
The result of placeImage.bind is a function, lets call it bound.
When invoked by doScript, bound will call your placeImage with the given this and additional parameters.
As your placeImage() is async, its execution will be deferred and the call immediately returns to bound, which then is done. As is your call to doScript.
Actual execution of your async placeImage then continues whenever async handling feels like that, outside the ENTIRE_SCRIPT wrapper as you found out.
Not sure why you need to make placeImage async - is it the inside async file operations? Maybe. I’d use Sync functions for your I/O – if those are available in UXP, or await until everything async is settled, and only then wrap all the InDesign steps for your frame into a separate, following function. Invoke only that new function with doScript. You can’t undo the fetch or file write anyway.
Turns out pretty similar to the order suggested by Jon.
Thank you @Dirk for your suggestions! Makes sense… I haven’t found sync file i/o functions in UXP, so probably I’ll have to go the other way, but that should be possible.