I’m walking down the artboard and creating lines with the function below:
function createLine(item) {
const line = new Line();
line.setStartEnd(
item.start.x,
item.start.y,
item.end.x,
item.end.y
)
return line;
}
It works when I have the artboard selected but when the artboard is not selected (iterating through all artboards) an error is thrown at the setStartEnd() method.
Plugin Error: Plugin is not permitted to make changes from the background. Return a Promise to continue execution asynchronously.
at convertPluginErrorToString (plugins/PluginErrorUtil.js:1:198)
at internalFormatPluginError (plugins/PluginErrorUtil.js:1:503)
at internalReportPluginError (plugins/PluginErrorUtil.js:1:610)
at Object.reportPluginError (plugins/PluginErrorUtil.js:1:1015)
at Object.checkAllowedToEdit (plugins/ScenegraphGuard.js:1:1097)
at Line.<anonymous> (plugins/ScenegraphWrappers.js:1:2399)
at createLine (/Users/bob/Library/Application Support/Adobe/Adobe XD CC/develop/myplugin/main.js:100:7)
Iteration code:
async function run() {
createModel(artboard, 0, 0);
}
function createModel(item, nestLevel, index, skipExport = false) {
// do stuff
createLine();
if (item.isContainer && item.children.length && isBooleanGroup==false) {
item.children.forEach((item, i) => {
createModel(item, ++artboardModel.currentNestLevel, i);
--artboardModel.currentNestLevel;
})
}
}
How can creating a line not on any artboard be not allowed? I do add it to the artboard eventually but the focused artboard.
Is there any thing that will help debugging the promise chain? If I could get the name of the function that the promise chain is in that might be enough.
If XD throws an error and then “undoes” modifications to the scenegraph is it possible continue editing after an error and save the objects to add them after the promise? For me, in a few cases, the user is not in the edit context (they have one artboard selected) and the objects that they need to work with span multiple artboards. So I could work on the focused artboard and add the changes back in after if possible.
If the edit context permission is granted on what is selected is there a global selection option? I’ve tried selecting all artboards (to allow editing any object) and still get errors (I will double check on this).
In your original code snippet, why is the function “run” marked async at all? The only thing you show it doing is making a single synchronous function call to createModel(). If your real, full createModel() code is doing async stuff too, make sure it’s declared async function (which it’s not in your snippet here) and make sure you call it with await in your real run() function… Otherwise the Promise returned by run() will just resolve immediately without waiting for any of createModel()'s async stuff.
The async and await keywords in JavaScript look nice & clean but sometimes I fear they make it too easy to miss what actually is – or isn’t – happening with the Promises underneath. Maybe there are linting tools that help make mistakes with async way easier to catch… but if not, it may be worth considering just working with Promise chains directly so things are much more crystal-clear when reading the code.
To answer your questions at the bottom of this thread:
We’re working hard on support for debugging via the V8 Inspector (which is very similar to Chrome Dev Tools), and I think that should help a lot with debugging Promises.
After the plugin promise resolves, it can’t make any further edits to the user’s document – there’s no guarantee XD isn’t busy doing something else at that point. You’ll need the user to re-invoke the plugin to make more edits later. In the specific example you cited though, edit contexts shouldn’t be an issue: in the “root” edit context, you can add child nodes to any/all artboards in a single operation (and in fact the user’s selection can even span multiple artboards itself). See https://adobexdplatform.com/plugin-docs/reference/core/edit-context.html.
There’s no way currently to make edits all across the whole document in a single plugin operation. We’d love to hear more details about your use cases for doing this though!