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
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
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
![]()
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more