I believe the issue to be the selection event itself. In order to do a rename or change the color, Ps needs to select the layer that you’re targeting, apply the change, and then reset the original selection. Turns out there’s a flag on the select
command called makeVisible
. If it’s not specified, the default action is to… select the layer and make it visible.
As far as I can tell, the JS DOM API isn’t taking this into account, and so changing a layer’s name
can affect layer visibility when it tries to put things back to how they were before the call. If the layer that is to be changed was already selected, then there’s no need to change the selection in the first place, and so the issue never occurs.
Until the bug itself is fixed, as a workaround, you can use batchPlay
with makeVisible
(or you will have the exact same issue).
I’ve been able to change layer names & colors without impacting visibility or the current selection using the following code. Feel free to use it as you like. Hopefully it helps.
async function layerMagic() {
const app = require("photoshop").app
// get a layer's ID
const toLayerId = (layer => layer._id);
// get all layers in the current document
const allLayerIds = app.activeDocument.layers.map(toLayerId);
// actions required to select one or more layers. Note makeVisible here defaults to "false"
// so that the selection doesn't impact layer visibility! If this were omitted from the
// actions, changing the selection would also change the selected layers' visibility.
// Also note that to select multiple layers, one must use "addToSelection" for further
// selections, otherwise you'd only end up with the last layer as the selected layer.
const selectLayers = (ids, makeVisible = false) => ([
{_obj: "select", _target: [{ _ref: "layer", _id: ids[0]}], makeVisible},
...ids.slice(1).map(id => ({_obj: "select", _target: [{ _ref: "layer", _id: id}], makeVisible, selectionModifier: {_enum: "selectionModifierType", _value: "addToSelection"}}))
]);
// Sets all selected layer colors to the specified color value. Doesn't bother to validate
// that your color is valid.
const setSelectedLayerColor = color => [{_obj:"set", _target:[{_ref:"layer", _enum:"ordinal", _value:"targetEnum"}],to:{_obj:"layer",color:{_enum:"color", _value: color}}}];
// Sets the first selected layer's name to the specified value. If multiple layers are selected,
// then only the first layer in the selection is modified.
const setSelectedLayerName = name => [{_obj:"set", _target:[{_ref:"layer", _enum:"ordinal", _value:"targetEnum"}],to:{_obj:"layer",name}}];
const colorChoices = ["red", "green", "yellowColor", "blue", "violet", "gray", "orange"];
// create a list of random colors so that it's obvious the UI what's happening
const colors = allLayerIds.map(() => colorChoices[Math.floor(Math.random()*colorChoices.length)]);
// save the currently selected layer IDs. We need this to _restore_ the user's selection
// after we change all the layer colors and names.
const allSelectedLayerIds = app.activeDocument.activeLayers.map(toLayerId);
const actions = [
// for every layer in the document...
...allLayerIds.map((id, idx) => [
// select it...
...selectLayers([id]),
// set its color to the random value we've determined earlier
...setSelectedLayerColor(colors[idx]),
// change the name to include the id and a random number
...setSelectedLayerName(`Layer ID: ${id} - ${Math.floor(Math.random()*1000)}`)
]).flat(),
// and when done, re-select the originally selected layers
...selectLayers(allSelectedLayerIds)
];
// ... and go!
await app.batchPlay(actions, {modalBehavior: "wait"});
}
layerMagic();