Add a new element from panel

I’m getting an error when I attempt to add an element to the artboard from a panel.

async function addRectangle(event) {
	const {selection} = require("scenegraph");

	try {
	
		const newElement = new Rectangle();
		newElement.width = 100;
		newElement.height = 100;
		newElement.fill = new Color("Purple");

		editDocument( () => {
			selection.insertionParent.addChild(newElement);
			newElement.moveInParentCoordinates(100, 100);
		});
	}
	catch(error) {
		console.log(error);
	}
}

Plugin Error: Plugin is not permitted to make changes from the background. Use editDocument() for panel UI handlers, or return a Promise to extend an edit operation asynchronously.

I’m using editDocument. Is there something else I’m missing?

Don’t know if it could be helpful in your case but this is the code I use to add elements to artboards:

async function validateDialog(_e)
{
    editDocument({editLabel: "Your Label"}, async() =>
    {
    	// your code
    });
}
1 Like

Putting the new call inside of the editDocument() works.

1 Like

This really shouldn’t request the async document editing function, as it’s not doing anything asynchronous. (At least not the code you’re showing.)

2 Likes

I agree with @cpryland.

I would expect that the problem is that due to this being an async function, it returns a Promise. All code in it, therefore, gets run asynchronously, which means editDocument() probably doesn’t get called in the same tick as the UI-event, which then triggers the error.

Therefore, while you can put everything into the editDocument(), which apperently still works as the JS engine seems to run the code up to editDocument first (although that might not be consistent, so I wouldn’t count on that), but the “cleaner” way (that should deterministically work :wink:) would be to have a non-async function getting triggered by the UI-event, which then calls editDocument() (which, of course, is still in the same tick as nothing asynchronous is going on), in which you can do whatever you need to do (may that be creating elements, or even asynchronous stuff, in which case the function passed to editDocument() must return a Promise).

function addRectangle(event) {
	const {selection} = require("scenegraph");

	try {
		const newElement = new Rectangle();
		newElement.width = 100;
		newElement.height = 100;
		newElement.fill = new Color("Purple");

		editDocument( () => {
			selection.insertionParent.addChild(newElement);
			newElement.moveInParentCoordinates(100, 100);
		});
	}
	catch(error) {
		console.log(error);
	}
}

When I moved the new Rectangle() statement into the editDocument() call I also had to move it before the await calls that I removed from the code above.

You’re right that it wasn’t in the same tick. I had to break things into two different steps and I’m doing some magic to get it to work.

1 Like

Also (from the original code you posted), are you using

await addRectange(event)

?

There are several async functions inside:

async function validateDialog(_e)
{
	// console.log("validateDialog()");

	editDocument({editLabel: "Make Frame"}, async() =>
	{
		try
		{
			let s = await checkSelection();
			
			if(s == false)
			{
				return;
			}
			else
			{
				// switch(frameMode)
				switch(settingsO["frameMode"])
				{
					case "size":
						try
						{
							let s = await checkSize();
							if(s == false)
							{
								return;
							}
						}
						catch(_error)
						{
							console.log(_error);
						}
						break;

					case "padding":
						// switch(paddingMode)
						switch(settingsO["paddingMode"])
						{
							case "padding":
								try
								{
									let p = await checkPadding();
									if(p == false)
									{
										return;
									}
								}
								catch(_error)
								{
									console.log(_error);
								}
								break;
							case "paddings":
								try
								{
									let p = await checkPaddings();
									if(p == false)
									{
										return;
									}
								}
								catch(_error)
								{
									console.log(_error);
								}
								break;
						}
						break;
				}
			}
			makeFrameOK();
		}
		catch(_error)
		{
			console.log(_error);
		}
	});
}