Execute a script via a button

I know its possible to convert an action to a uxp script but is it possible to execute a script from a uxp button? At times its more usful to be able to edit the action rather than remake the script everytime.

Thanks

Do you mean to play an action, or run a JSX script? Yes, either can be done.

I have a UXP plugin that plays actions and there have been no issues at all with that.

You can also play JSX extendscript through UXP. I don’t use this in my plugins but I did do some testing. It works fine but for some reason runs at about 1/2 the speed that my JSX extendscripts run when ran natively, not through UXP.

Here is the documentation for playing actions.

https://www.adobe.io/photoshop/uxp/ps_reference/classes/action/
https://www.adobe.io/photoshop/uxp/ps_reference/classes/actionset/

I currently play actions using batchPlay and have a report that if the action contains a script (.jsx), then it won’t play from the plugin. So using APIs to play actions instead of batchPlay may be preferable.

I found this code in the tutorials

  const app = require('photoshop').app;
  const allActionSets = app.actionTree;
  const firstActionSet = allActionSets[0];
  let actions = new Map(); // a JS Map allows easy "find by name" operations
  firstActionSet.actions.forEach((action) => { actions.set(action.name, action)});
  const myAction = actions.get("Wood Frame - 50 pixel");
  if (myAction) { // user may have deleted this action
    await myAction.play();
  }

I assume if i change “Wood Frame - 50 pixels” to my action name it should then point to my action. I have 2 questions though.

  1. How do i set the actionset folder name?
  2. how do i bind this to a buttonid?

Can anyone help me with this please, i still can’t figure out how to play an action from a UXP button.

I’m sure this isn’t the most efficient use of javascript and forgive the longhand… but it works.

//Use same ID in HTML doc
document.getElementById("yourButtonID").addEventListener("click", async function (){
await playAction("Your Action Set","Your Action");
});

async function playAction(setName,actionName){

let setFound=false;    
let actionFound=false;    
 
  const actionSets = require('photoshop').app.actionTree;
    
 // check for action set name to exist    
  for (let i=0; i<actionSets.length; i++){
      if (actionSets[i].name==setName){var setToPlay=actionSets[i]; setFound=true;}
  }
  
 //check for action name to exist    
 if(setFound==true){
    for (let i=0; i<setToPlay.actions.length; i++){
    if (setToPlay.actions[i].name==actionName){var actionToPlay=setToPlay.actions[i]; actionFound=true;}
    }
}    

 //play if action set/action both exist    
  if(setFound==true&&actionFound==true){await actionToPlay.play();}    
    
}
    

I’m getting an error, i think its because of a ‘{’ at the end of the line ‘async function playAction(setName,actionName){’

It doesn’t seem to be closed again. Where should the ‘}’ go?

I tried it at the end but the action wouldn’t play from the button

What is the exact error?

I must have missed the closing bracket when I copied it from my plusing. I updated the post. It is the exact function I use for multiple plugins and I’ve never had it give an error.

OK, I just updated it again. I missed the last line and the closing bracket when I copied it last time… oops.

//Use same ID in HTML doc
document.getElementById("yourButtonID").addEventListener("click", async function (){
await playAction("Your Action Set","Your Action");
});

async function playAction(setName,actionName){

let setFound=false;    
let actionFound=false;    
 
  const actionSets = require('photoshop').app.actionTree;
    
 // check for action set name to exist    
  for (let i=0; i<actionSets.length; i++){
      if (actionSets[i].name==setName){var setToPlay=actionSets[i]; setFound=true;}
  }
  
 //check for action name to exist    
 if(setFound==true){
    for (let i=0; i<setToPlay.actions.length; i++){
    if (setToPlay.actions[i].name==actionName){var actionToPlay=setToPlay.actions[i]; actionFound=true;}
    }
}    

 //play if action set/action both exist    
  if(setFound==true&&actionFound==true){await actionToPlay.play();}    
    
}

Thank you very much, that worked perfectly.

Are all the checks needed? I didn’t see any errors or pop ups when i tried to assign an action that didn’t exist. I have 50+ actions so less code would be more benficial to me

That is your decision. You can put an else statement in there to prompt an error. In my case, I didn’t want it to throw an error and just move on if the action doesn’t exist.

Dies this still work in PS 23?
I use the exact code but my action is not played.
The action has no extendedscript adn when I debug it both setFound & actionFound are true before it tries to play it.

I don’t think it works in recent Photoshop versions. I’m pretty sure that UXP scripting is replacing extendscript. So maybe it doesn’t work anymore by design… not sure.

UXP scripting is still missing many methods which exist in extendedacript but are still missing in UXP.
Even if I wanted to convert my existing CEP plugin to UXP it would be impossible at this stage.

I’m not sure why it doesn’t work anymore. It could be a bug. You would have to ask Adobe on that. I just know it stopped working at least 6 months ago, maybe longer. You can’t play an action through UXP containing an extendscript either. One of my plugins plays actions from a Hot Folder. Several of my users were running actions that played scripts. It stopped working for all of them. I don’t know if there is anyway to play a script through UXP at all right now. Again, Adobe would have to give an official answer about if it is possible, or if it is a bug or by design.

Interesting! @ddbell Your code actually works well for me. for either run normal actions or a JSX script.

const app = require("photoshop").app;
const batchPlay = require("photoshop").action.batchPlay;
const ExecuteAsModal = require("photoshop").core.executeAsModal;

async function playAction(setName, actionName) {
  let setFound = false;
  let actionFound = false;

  const actionSets = require("photoshop").app.actionTree;

  // check for action set name to exist
  for (let i = 0; i < actionSets.length; i++) {
    if (actionSets[i].name == setName) {
      var setToPlay = actionSets[i];
      setFound = true;
    }
  }

  //check for action name to exist
  if (setFound == true) {
    for (let i = 0; i < setToPlay.actions.length; i++) {
      if (setToPlay.actions[i].name == actionName) {
        var actionToPlay = setToPlay.actions[i];
        actionFound = true;
      }
    }
  }

  //play if action set/action both exist
  if (setFound == true && actionFound == true) {
    await actionToPlay.play();
  }
}


document
  .getElementById("action1")
  .addEventListener("click", async function () {
    await ExecuteAsModal(() => playAction("Actions set Name", "Action 1"));
  });

but I have notice different behaviour based on how I run the JSX.
if I have the JSX play like this

It won’t work And I get this error:

but if I set it to play an action from another set that contain JSX file it works

btw: I am in Photoshop 23.4.1 api 2 manifest 5

1 Like

That is interesting. However, I don’t know if I would trust that workaround to be future-proof. I think JSX is on it’s way out. I have seen things in my JSX scripts stop working on newer PS releases. So even if you get it to play, the doesn’t guarantee that the script will work correctly in future PS releases. For myself, I have 1 last JSX program that I am trying to convert to UXP so my collection of plugins will all be JSX-free.

Don’t rely on it. This one might require your intervention in the future.

I am doing the same converting all my jsx files. but I still use some of my jsx script because they rely on keyboard shortcuts, I hope we get support for shortcuts soon in UXP.

Hello, I have here a script to run a pre-recorded photoshop action: I use this “RunAction.js” script, in combination with another “buttonConfig.json” file. Here is the RunAction.js script :

const { core, action } = require(“photoshop”);

async function actionCommands(actionName, actionSet) {
console.log(Executing actionCommands with actionName: ${actionName}, actionSet: ${actionSet});
try {
const result = await core.executeAsModal(async () => {

  return await action.batchPlay(
    [
      {
        _obj: "play",
        _target: [
          { _ref: "action", _name: actionName },
          { _ref: "actionSet", _name: actionSet }
        ],
        _options: { dialogOptions: "dontDisplay" }
      }
    ],
    {}
  );
}, { commandName: `Executing ${actionName}` });

console.log("Action executed successfully:", result);
return result;

} catch (err) {
console.error(“Error in batchPlay:”, err);
throw err;
}
}

module.exports = { actionCommands };

and here is the buttonConfig.json file :

{
“Name_of_Button”: {
“action”: “Name_of_Action”,
“actionSet”: “Name_of_Set”
}
}