Copy link to clipboard
Copied
Hello,
I have done a ton of search, trail / error, and finally need to reach out for assistance.
I am attempting to create a PS script that toggles visibility of layers AND groups based on a regular expression in a PS document.
EXAMPLE STRUCTURE OF PS GROUPS & LAYERS
=======================================
• // example
• header
- some-layer
- // test
• footer
- another-layer
- // content-area
Bullet = Group
Hyphen = Layer
This script should hide both "// example", "// test", and "// content-area" on run. Running the script again would ideally reveal these layer(s) and group(s).
I have managed to located two scripts that do each half of the desired outcome below.
Part 1: Use Regular expression to locate each layer and group (I have modified the reg exp to use case):
Re: Script to search layer names
by: Michael L Hale
var re = /\/\/\ .*/; // a reg exp
var matches = collectNamesAM(re); // get array of matching layer indexes
for( var l = 0; l < matches.length; l++ ){
makeActiveByIndex( matches
, false ); // do something with layer
alert(app.activeDocument.activeLayer.name);
} // next match if any
function collectNamesAM(re){
var allLayers = new Array();
var startLoop = Number( !hasBackground() );
var endLoop = getNumberOfLayer();
for( var l = startLoop;l < endLoop; l++){
while( !isValidActiveLayer( l ) ) {
l++;
}
if( getLayerNameByIndex( l ).match(re) != null){
allLayers.push( l );
}
}
return allLayers;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: getActiveLayerIndex
// Description: Gets gets the Action Manager API index
// of activeLayer corrected for Background Layer
// Usage: var idx = getActiveLayerIndex();
// Input: None
// Return: Number - correct AM itemIndex
// Dependices: hasBackground
//////////////////////////////////////////////////////////////////////////////*/
function getActiveLayerIndex() {
var ref = new ActionReference();
ref.putProperty( 1349677170 , 1232366921 );
ref.putEnumerated( 1283027488, 1332896878, 1416783732 );
var res = executeActionGet(ref).getInteger( 1232366921 )
- Number( hasBackground() );
res == 4 ? res++:res // why the skip in this doc?
return res;
}
/*//////////////////////////////////////////////////////////////////////////////
// Function: isValidActiveLayer( )
// Description: Checks LayerSection for 'real' layers
// Usage: if( isValidActiveLayer() )
// Input: None
// Return: Boolean - True if not the end of a Set
// Notes: Needed only if the layer was made active
// using Action Manager API
//////////////////////////////////////////////////////////////////////////////*/
function isValidActiveLayer( idx ) {
var propName = stringIDToTypeID( 'layerSection' ); // can't replace
var ref = new ActionReference();
ref.putProperty( 1349677170 , propName); // TypeID for "Prpr"
// 'Lyr ", idx
ref.putIndex( 1283027488, idx );
var desc = executeActionGet( ref );
var type = desc.getEnumerationValue( propName );
var res = typeIDToStringID( type );
return res == 'layerSectionEnd' ? false:true;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: hasBackground
// Description: Test for background layer using AM API
// Usage: if( hasBackground() );
// Input: None
// Return: Boolean - true if doc has background layer
// Notes: Requires the document to be active
// DOM: App.Document.backgroundLayer
//////////////////////////////////////////////////////////////////////////////*/
function hasBackground(){
var res = undefined;
try{
var ref = new ActionReference();
ref.putProperty( 1349677170 , 1315774496);
ref.putIndex( 1283027488, 0 );
executeActionGet(ref).getString(1315774496 );;
res = true;
}catch(e){ res = false}
return res;
};
function makeActiveByIndex( idx, forceVisible ){
try{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID( "Lyr " ), idx)
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), forceVisible );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
}catch(e){ return -1;}
};
function getNumberOfLayer(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
var numberOfLayer = desc.getInteger(charIDToTypeID("NmbL"));
return numberOfLayer;
};
function getLayerNameByIndex( idx ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "Nm " ));
ref.putIndex( charIDToTypeID( "Lyr " ), idx );
return executeActionGet(ref).getString(charIDToTypeID( "Nm " ));;
};
This script shows an alert for each layer / group name that matches - It is locating the layers / groups!
Now I need these layers / groups to simultaneously hide or appear depending on their status.
I located a script that toggles visibility for a specific name (in this case 'GRID') here:
photoshop-grid-toggle/Toggle Grid.jsx at master · squarefrog/photoshop-grid-toggle · GitHub
var gridName = "GRID"; // Change to whatever you call your grid layer set.
function toggleGridLayer() {
if (app.documents.length > 0) {
var gridLayer = app.activeDocument.layerSets.getByName(gridName);
gridLayer.visible = !gridLayer.visible;
}
}
toggleGridLayer();
Essentially, I would like to fuse the toggling visibility script into the regular expression script. Any and all help would be awesome. Thanks in advance!
Note: Using PS CC 2015
1 Correct answer
That script is all on one line and is difficult to see where separate lines are. If you want code to turn on or off a layer you can use:
var docLayer = app.activeDocument.activeLayer;
docLayer.visible=docLayer.visible==false;
Explore related tutorials & articles
Copy link to clipboard
Copied
That script is all on one line and is difficult to see where separate lines are. If you want code to turn on or off a layer you can use:
var docLayer = app.activeDocument.activeLayer;
docLayer.visible=docLayer.visible==false;
Copy link to clipboard
Copied
Your solution worked! I added the two lines you provided into the script at line 6 & 7 (after "// do something with layer") and it its toggling the visibility perfectly. The only thing to note for others that may come across this, is that the script does not find a match on the top most layer / group of the stack. The elements that I am toggling are nested, so this is not a concern for me. Just making a note.
P.S. - Sorry about not inserting the JS into the code formatting as pasting would wrap after I posted. It looked fine while editing in the reply field. Hm.
var re = /\/\/\ .*/; // a reg exp
var matches = collectNamesAM(re); // get array of matching layer indexes
for( var l = 0; l < matches.length; l++ ){
makeActiveByIndex( matches
// do something with layer
var docLayer = app.activeDocument.activeLayer;
docLayer.visible=docLayer.visible==false;
// test matches with alert
// alert(app.activeDocument.activeLayer.name);
} // next match if any
function collectNamesAM(re){
var allLayers = new Array();
var startLoop = Number( !hasBackground() );
var endLoop = getNumberOfLayer();
for( var l = startLoop;l < endLoop; l++){
while( !isValidActiveLayer( l ) ) {
l++;
}
if( getLayerNameByIndex( l ).match(re) != null){
allLayers.push( l );
}
}
return allLayers;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: getActiveLayerIndex
// Description: Gets gets the Action Manager API index
// of activeLayer corrected for Background Layer
// Usage: var idx = getActiveLayerIndex();
// Input: None
// Return: Number - correct AM itemIndex
// Dependices: hasBackground
//////////////////////////////////////////////////////////////////////////////*/
function getActiveLayerIndex() {
var ref = new ActionReference();
ref.putProperty( 1349677170 , 1232366921 );
ref.putEnumerated( 1283027488, 1332896878, 1416783732 );
var res = executeActionGet(ref).getInteger( 1232366921 )
- Number( hasBackground() );
res == 4 ? res++:res // why the skip in this doc?
return res;
}
/*//////////////////////////////////////////////////////////////////////////////
// Function: isValidActiveLayer( )
// Description: Checks LayerSection for 'real' layers
// Usage: if( isValidActiveLayer() )
// Input: None
// Return: Boolean - True if not the end of a Set
// Notes: Needed only if the layer was made active
// using Action Manager API
//////////////////////////////////////////////////////////////////////////////*/
function isValidActiveLayer( idx ) {
var propName = stringIDToTypeID( 'layerSection' ); // can't replace
var ref = new ActionReference();
ref.putProperty( 1349677170 , propName); // TypeID for "Prpr"
// 'Lyr ", idx
ref.putIndex( 1283027488, idx );
var desc = executeActionGet( ref );
var type = desc.getEnumerationValue( propName );
var res = typeIDToStringID( type );
return res == 'layerSectionEnd' ? false:true;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: hasBackground
// Description: Test for background layer using AM API
// Usage: if( hasBackground() );
// Input: None
// Return: Boolean - true if doc has background layer
// Notes: Requires the document to be active
// DOM: App.Document.backgroundLayer
//////////////////////////////////////////////////////////////////////////////*/
function hasBackground(){
var res = undefined;
try{
var ref = new ActionReference();
ref.putProperty( 1349677170 , 1315774496);
ref.putIndex( 1283027488, 0 );
executeActionGet(ref).getString(1315774496 );;
res = true;
}catch(e){ res = false}
return res;
};
function makeActiveByIndex( idx, forceVisible ){
try{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID( "Lyr " ), idx)
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), forceVisible );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
}catch(e){ return -1;}
};
function getNumberOfLayer(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
var numberOfLayer = desc.getInteger(charIDToTypeID("NmbL"));
return numberOfLayer;
};
function getLayerNameByIndex( idx ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "Nm " ));
ref.putIndex( charIDToTypeID( "Lyr " ), idx );
return executeActionGet(ref).getString(charIDToTypeID( "Nm " ));;
};
Copy link to clipboard
Copied
Glad it's working for you!
Copy link to clipboard
Copied
Hi Chuck Uebele,
since a long time I missed the possibility to mark an answer as helpful. How did you mark my answer as helpful?
Best regards
Copy link to clipboard
Copied
pixxxel schubser I'm a mod, so I can mark answers as helpful. It's been removed for regular users for some odd reason.
Copy link to clipboard
Copied
What a shame. I guessed it.
But thank you for your answer.
Copy link to clipboard
Copied
Hope it helps, MSpangenberg.
I have no CC2015 to test. Only CC2014
// string for regexp verification
var myRegexp = "example_test_content-area";
//
var wasHere = app.activeDocument.activeLayer;
var onOff = false;
// The group "example" visibility will dictate the other artlayers visibility
for (var a=0; a<app.activeDocument.layers.length ; a++) {
//
if (myRegexp.match(new RegExp(app.activeDocument.layers.name)) != null) {
app.activeDocument.layers.visible = (String(app.activeDocument.layers.visible) == 'true') ? false : true;
onOff = app.activeDocument.layers.visible;
} else {
// to activate a artlayer or group, will also put its visibility on at the same time (important):
app.activeDocument.activeLayer = app.activeDocument.layers;
for (var b=0; b<app.activeDocument.layers.artLayers.length ; b++) {
if (myRegexp.match(new RegExp(app.activeDocument.layers.artLayers.name)) != null) {
app.activeDocument.layers.artLayers.visible = onOff;
}
}
}
}
// go back to the initial active layer
app.activeDocument.activeLayer = wasHere;
Copy link to clipboard
Copied
Thanks for the reply!
I added my regular expression into the variable:
var myRegexp = /\/\/\ .*/;
Running the script, I receive the following error:
Error 24: myRegexp.match is not a function.
Line: 9
-> if (myRegexp.match(new RegExp(app.activeDocument.layers.name)) != null) {
Any ideas?
Copy link to clipboard
Copied
Hi MSpangenberg‌,
you should use something like this (standalone "three-liner") in your script:
if (app.activeDocument.activeLayer.name.match(/\/\/\ .*/) != null) {
alert("found: " + app.activeDocument.activeLayer.name.match(/\/\/\ .*/));
}
Have fun

