How to output an Array in elements' type inside batchPlay?

I’m coding in batchPlay, and here’s the basic format goes:

var batchPlay = require("photoshop").action.batchPlay;
var result = await batchPlay([

//Here lies the actions code(in actual object type), if more than one action: plus an ","

],{"synchronousExecution": false,"modalBehavior": "fail"});

So if I do a Select Layer Action it will be coded as :

{"_obj":"select","_target":[{"_name":"Layer 2","_ref":"layer"}],"layerID":[4],"makeVisible":false}

which contains absolute layer.name and layer._id, and I want to make this substituted with app.activeDocument.activeLayers. So the final code should be like this:

var batchPlay = require("photoshop").action.batchPlay;
var SelectedLayers = [ //Assume this is the array of app.activeDocument.activeLayers
{"_obj":"select","_target":[{"_name":"Layer 2","_ref":"layer"}],"layerID":[4],"makeVisible":false}, 
{"_obj":"select","_target":[{"_name":"Layer 3","_ref":"layer"}],"layerID":[5],"makeVisible":false},
{"_obj":"select","_target":[{"_name":"Layer 4","_ref":"layer"}],"layerID":[6],"makeVisible":false}
]
var result = await batchPlay([
SelectedLayers[0],
SelectedLayers[1],
SelectedLayers[2]
],{"synchronousExecution": false,"modalBehavior": "fail"});

This works well but I just can’t find the way to nicely output the array elements in this format, and in actual object type (debugger told me it not gonna happen with string type)
SelectedLayers[0],
SelectedLayers[1],
SelectedLayers[2]
I guess this question is more like a javaScript one even with Adobe stuffs.

If I’m understanding it correctly:

await batchPlay(SelectedLayers, {"synchronousExecution": false,"modalBehavior": "fail"});

SelectedLayers is already an array so you don’t need to create an array again.

I tried but debugger said that is not a accepable type, it printed “expected: actual object type: array”
The type after second “:” would be my input type, I tried.

Are you trying to use app.activeDocument.activeLayers inside batchPlay?
That will not work. You can only use batchPlay objects.

But this works in this form:

var batchPlay = require("photoshop").action.batchPlay;
var SelectedLayers = [ //Assume this is the array of app.activeDocument.activeLayers
{"_obj":"select","_target":[{"_name":"Layer 2","_ref":"layer"}],"layerID":[4],"makeVisible":false}, 
{"_obj":"select","_target":[{"_name":"Layer 3","_ref":"layer"}],"layerID":[5],"makeVisible":false},
{"_obj":"select","_target":[{"_name":"Layer 4","_ref":"layer"}],"layerID":[6],"makeVisible":false}
]
var result = await batchPlay([
SelectedLayers[0],
SelectedLayers[1],
SelectedLayers[2]
],{"synchronousExecution": false,"modalBehavior": "fail"});

Could you maybe describe what’s your intention to do with the code?
{"_obj":"select", ...} is the descriptor for selecting a layer, however you’re writing to

Assume this is the array of app.activeDocument.activeLayers

So I’m wondering why you want to select the already selected layers?

If you want to map an array of layers (DOM layer objects) to batchPlay descriptors, you could do so via
const descriptorArray = someLayers.map(layer => (descriptor))
e.g

const descriptorArray = someLayers.map(layer => 
    ({"_obj":"select","_target":[{"_name":layer.name,"_ref":"layer"}]})
)

Oh, I guess I did bad at giving example.
I was going to do command like “Disable Layer Mask”, “Delete Layer Mask” while more than one layer are selected, because these commands seem to accept only one layer in selection.
So I thought that could be done through batchPlay in scripting:

async function RemoveMask_func(){
    var batchPlay = require("photoshop").action.batchPlay;
    var SlcLyrs = app.activeDocument.activeLayers
    var SlcLyrsNames = SlcLyrs.map(layer => layer.name)// return a list 
    var SlcLyrsId = SlcLyrs.map(layer => layer._id) // return a list 
                        var result = await batchPlay([
        /*Deselect*/            {"_obj":"selectNoLayers","_target":[{"_enum":"ordinal","_ref":"layer"}]},
        /*TargetLayers*/        {"_obj":"select","_target":[{"_name":`${SlcLyrsNames[0]}`,"_ref":"layer"}],"layerID":[`${SlcLyrsId[0]}`],"makeVisible":false}, 
        /*DeleteMask*/          {"_obj":"delete","_target":[{"_enum":"channel","_ref":"channel","_value":"mask"}]},
        /*TargetLayers*/        {"_obj":"select","_target":[{"_name":`${SlcLyrsNames[1]}`,"_ref":"layer"}],"layerID":[`${SlcLyrsId[1]}`],"makeVisible":false}, 
        /*DeleteMask*/          {"_obj":"delete","_target":[{"_enum":"channel","_ref":"channel","_value":"mask"}]},
        /*TargetLayers*/        {"_obj":"select","_target":[{"_name":`${SlcLyrsNames[2]}`,"_ref":"layer"}],"layerID":[`${SlcLyrsId[2]}`],"makeVisible":false}, 
        /*DeleteMask*/          {"_obj":"delete","_target":[{"_enum":"channel","_ref":"channel","_value":"mask"}]},
        /*TargetLayers*/        {"_obj":"select","_target":[{"_name":`${SlcLyrsNames[3]}`,"_ref":"layer"}],"layerID":[`${SlcLyrsId[3]}`],"makeVisible":false}, 
        /*DeleteMask*/          {"_obj":"delete","_target":[{"_enum":"channel","_ref":"channel","_value":"mask"}]},
        /*TargetLayers*/        {"_obj":"select","_target":[{"_name":`${SlcLyrsNames[4]}`,"_ref":"layer"}],"layerID":[`${SlcLyrsId[4]}`],"makeVisible":false}, 
        /*DeleteMask*/          {"_obj":"delete","_target":[{"_enum":"channel","_ref":"channel","_value":"mask"}]},
        /*TargetLayers*/        {"_obj":"select","_target":[{"_name":`${SlcLyrsNames[5]}`,"_ref":"layer"}],"layerID":[`${SlcLyrsId[5]}`],"makeVisible":false}, 
        /*DeleteMask*/          {"_obj":"delete","_target":[{"_enum":"channel","_ref":"channel","_value":"mask"}]},
                                .............
        /*Deselect*/            {"_obj":"selectNoLayers","_target":[{"_enum":"ordinal","_ref":"layer"}]}
                        ],{"synchronousExecution": false,"modalBehavior": "fail"});
}}

And I tried this…
image

If you want to (directly) return an object inside the map function, you have to wrap it in brackets.
So either write
array.map(() => { return {...}})
or
array.map(() => ({...}))
This will solve the unexpected token error.

I just saw that I did that wrong myself in the previous post, I’ve edited it there to be correct now.


You actually don’t need to select a layer in order to delete its layer mask. Since the target property is an array, you can specify multiple references, for example one for the mask and one for the layer.
I’d write it like that:

 photoshop.action.batchPlay(
      photoshop.app.activeDocument.activeLayers.map(layer => (
        {
          _obj: 'delete',
          _target: [
            {
              _ref: 'channel',
              _enum: 'channel',
              _value: 'mask',
            },
            {_ref: "layer", _id: layer._id}
          ],
        }
      )
), {})

This will delete all the masks of the selected layers.

How does this work? Doesn’t it target both layer and it’s mask? Or does this mean only the mask of that specific layer? Batch play is so confusing. For me here it looks like two targets to delete and I’d expect layer to be deleted also :confused:

It’s giving the target more specificity, just like in

 {
      _obj: 'get',
      _target: [{ _property: prop }, { _ref: 'layer', _id: id }],
},

for example

But in delete case, how does it know there’s no need to delete the second target, which is layer by ID, but delete only first one, which is mask? Does it have something to do with _enum and _value?

I do agree though, that it’s not really 100% consistent. For example you can add multiple layer references to a select descriptor to select multiple layers at once. In this case it behaves more like you’ve anticipated it. I assume it’s some kind of hierarchy thing or it’s somehow hardcoded which events can process which kind of target(s).

In case of property + layer reference, the internal code might see that property adds specificity to the layer reference. Same for mask + layer. If you were deleting the layer, the mask would be deleted anyways. So it wouldn’t make sense to interpret both target references on the same “hierarchy level” and perform a delete on both.

Just speculating here, unfortunately we can’t look into Photoshop’s code :smiley:

1 Like

Nope. The enums are just predefined values, such as next, previous, target, first, last etc.

Thanks! This works well!
And if I have some other alone actions to do before the Selection.map(layer => (Action_X)) like this:

batchPlay([
Action_1,
Action_2,
Selection.map(layer => (Action_X))
],{ })

How to run this, because the batchPlay Argument 1 stays in array-like type, if .map is inside it won’t run.(It seems to be having an array, in an array)

With spreading:

[
...array
]

A great thing about spreading is that it resolves empty arrays by not adding them to the outside array.
This can be used to conditionally spread the array (inline):

[
...(condition ? [lorem, ipsum, dolor] : []
]

for example

const selectLayers = true
batchPlay([
Action_1,
Action_2,
...(selectLayers ? Selection.map(layer => (Action_X)) : [])
],{ })