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:1073)
at internalReportPluginError (plugins/PluginErrorUtil.js:1:1180)
at Object.reportPluginError (plugins/PluginErrorUtil.js:1:1612)
at Object.checkAllowedToEdit (plugins/ScenegraphGuard.js:1:1577)
at Object.<anonymous> (plugins/ClipboardWrapper.js:1:194)
at VueComponent.copySCSSVariablesToClipboard (C:\...\main.js:1344:23)
my code
copySCSSVariablesToClipboard() {
clipboard.copyText(this.scssVariables); // CRUSH HERE
this.showNotification({
text: 'Colors for SCSS is now available on the clipboard',
color: 'green'
});
},
One possibility is that Vue is delaying the handler a tick after the actual event. XD only holds the scenegraph open for a single tick. So things like wrapping editDocument with a setTimeout wonāt work, because by the time the timeout happens, XD has already closed the scenegraph.
Unfortunately, Iām not familiar enough with Vue to know if thatās whatās going on here ā just bringing it up as a possibility.
@LeXX Does this also happen when you have a simple button with a @click event (and nothing more) and only happens in more ācomplexā scenarios or if it already happens in a minimal reproducable example? (if the latter, could you possibly create some sort of repo with this minimal example?)
Iām no expert in Vue myself, but to my knowledge, there is some sort of ātickā system (possibly deferring some events to the next document.requestAnimationFrame() or something like that) that could interfere here (again: Iām far from being versed in Vue, thatās just something Iāve heard of), especially if some event gets āpassed upā the component chain.
I deleted my previous post because I realized it still doesnāt resolve the issue upon further testing.
I replicated the issue and found a solution on my end.
Issue: Error: Panel plugin edits must be initiated from a supported UI event Reason: The reason for this is you are calling editDocument() on a child component which isnāt wrapped with an edit batch. Plugin edits must be initiated on a panel UI or on a menu item.
Solution: My workaround on this is, I created a Vue Event Bus. I can now pass the data from the dialog to my main file and initiate the clipboard.copyText() since I am now at the plugin menu item commands scope.
Steps:
Create a event-bus.js file
Import vue import Vue from 'vue';
Create a vue instance called EventBus const EventBus = new Vue();
On your hello.vue component require the EventBus const EventBus = require("./event-bus.js").default;
On your copy method use the EventBus copy() { EventBus.$emit('copy', this.message); }
This line will emit a custom event called copy with the message as the payload.
On your main.js file, require the EventBus const EventBus = require("./event-bus.js").default;
Then add a mounted method on your Vue instance. mounted() { EventBus.$on('copy', (message) => { clipboard.copyText(message); }); },
This will create an event listener to copy, receive the message and initiate clipboard.copyText(message);
I made the menuCommandasync and awaitgetDialog().showModal(); to ensure that further actions cant still be initiated.
I apologize if my post is a bit long. Iām still new at creating XD plugins and Iām still not an expert on VueJS.
I also created a pull request on your repo to see how I fixed the issue.
OK, but where does the application.editDocument() call go?
Seems like an awful lot of machinery for such a simple thing. Youād think the Vue click handler would be in a direct call path to the eventual .editDocument() call.
@elmer I checked your version, you are so right! I donāt know how you found a solution, but it solves the problem.
I make solution more simple, without event bus.
In main.js:
...
const copyToClipboard = string => {
clipboard.copyText(string);
};
const getDialog = (selection, documentRoot) => {
if (!dialog) {
...
new Vue({
...
render(h) {
return h(app, {
props: {
...
copyToClipboard, // now this.copyToClipboard('hello world') available on app.vue
},
});
}
});
}
return dialog;
};
module.exports = {
commands: {
exportToVue: async (selection, documentRoot) => {
await getDialog(selection, documentRoot).showModal(); // async await very important
}
}
};
@cpryland@kerrishottsapplication.editDocument() is no longer needed, because showModal() return Promise and we are write async/await-operation for waiting execution of this Promise. This means that any code inside main.js and getDialog() automatically wrapped as editDocument(). Now we should not use application.editDocument(), and we can write clipboard.copyText without editDocument(). Otherwise it will be a mistake, like this:
I think any operations inside the application no longer need application.editDocument(). But I can be wrong because didnāt check the idea. I also didnāt check event type dependency as āclickā or āinputā and other types something else, but I guess the āmouseenterā will work too.