Lloyd Smith Lloyd Smith - 5 days ago 3
Javascript Question

Checking for Locked/Hidden Layers in Adobe Illustrator

I am working on a script in Adobe Illustrator (AI), and I am running into an issue that I am unable to understand. This maybe be due to the underlying way AI works, but I would like to know if there is a way to work around this. Ok, so my question is this:

How to check if a sublayer in AI is locked/hidden while not directly locked (top most layer is locked/hidden while sublayers 'inherit the status').

I currently have a script which does a process (looping over layers) and does so as long as the layer is not Locked/Hidden. The problem is when a top layer (parent layer) is set to locked or hidden, all of its sublayer/objects inherit that trait (locked or hidden). The problem I am having with my script is these locked/hidden sublayers are being classified as visible and unlocked (or visible is undefined). Is there another way to determine this?

Script:

// JavaScript Document
if (app.documents.length > 0) {
var docRef = app.activeDocument;
var docLayers = docRef.layers;
var searchText = "";
var replaceText = "";
var found = false;

function recurseLayers(currLayers) {
var length = currLayers.length;
var currentLayer = null;
var searchtext = searchText;
var replacetext = replaceText;

try {
for (var i = length; i--;) {
currentLayer = currLayers[i];

replaceName(currentLayer, searchText, replaceText);

if (currentLayer.layers) {
recurseLayers(currentLayer.layers);
}
}
} catch (e) {
logger (e);
}
}

function replaceName(objArray, searchText, replaceText) {
try {
var visible = objArray.visible;
var locked = objArray.locked;
var typeName = objArray.typename;
if (visible && !locked) {
//var searchtext = "/\s*" + searchText + "\s*\d*/";
objArray.name = objArray.name.replace(searchText, replaceText);
}
} catch (e) {
logger(e);
}
}


startGUI();

function startGUI() {

var win = new Window("dialog", "Replace Layer name", undefined);

win.orientation = "column";
win.alignChildren = ["fill", "fill"];

// Search
var searchGrp = win.add("panel", undefined, "Search and Replace");
searchGrp.orientation = "column";
searchGrp.alignChildren = ["fill", "fill"];

var titleMsgS = searchGrp.add("statictext", undefined, "Layer name to search:");
var txt_searchText = searchGrp.add("edittext { characters: 1, justify: 'center', active: true }");

txt_searchText.helpTip = "Input layer name to replace";

var titleMsgR = searchGrp.add("statictext", undefined, "Layer name to replace with:");
var txt_replaceText = searchGrp.add("edittext { characters: 1, justify: 'center', active: true }");
txt_replaceText.helpTip = "Input layer name to replace with";

// Set first text box to active
txt_searchText.active = true;

win.addEventListener ("keydown", function(kd) {enter(kd) });

// Replace button
var replaceBtn = searchGrp.add("button", undefined, "Replace");
replaceBtn.helpTip = "Replace layer name";
replaceBtn.onClick = function() {
searchText = txt_searchText.text;
replaceText = txt_replaceText.text;

recurseLayers(docLayers);
app.redraw();
}

function enter(k) {
if (k.keyName == "Enter") {
recurseLayers(searchText.text, replaceText.text);
app.redraw();
}
}

// Close button
var quitBtn = win.add("button", undefined, "Close");
quitBtn.helpTip = "Press Esc to Close";

// Event listener for the quit button
quitBtn.onClick = function() {
win.close();
}

// Centering & Show Window
win.center();
win.show();
}


// Prints stack trace
function logger(e) {
var errorMsg = "";

errorMsg = errorMsg.concat("An error has occured:\n", e.line, "\n", e.message, "\n", e.stack);
//$.writeln(errorMsg);
}

} else {
alert("You do not have any document opened!");
}


Example:
The top layer (Blue Square) was set to locked (light lock symbol). While the sublayers are inheriting the locked status (grayed out locked symbol). In AI, these sublayers are considered locked, however, to my script they are labeled at unlocked (using layer.locked).

enter image description here
Update: Working code, thanks to @ermax.

function recurseLayers(currLayers) {
var length = currLayers.length;
var currentLayer = null;
var searchtext = searchText;
var replacetext = replaceText;

try {
for (var i = length; i--;) {
currentLayer = currLayers[i];
replaceName(currentLayer, searchText, replaceText);

if (currentLayer.layers) {
recurseLayers(currentLayer.layers);
}
}
} catch (e) {
logger (e);
}
}

function replaceName(currLayer, searchText, replaceText) {
try {
var visible = currLayer.visible;
var locked = currLayer.locked;
var typeName = currLayer.typename;
if (checkLayerVisibility(currLayer) && !checkLayerLocked(currLayer)) {
currLayer.name = currLayer.name.replace(searchText, replaceText);
}
} catch (e) {
logger(e);
}
}

function checkLayerLocked(layer) {
if(!layer.locked)
for(var parent = layer.parent; parent.typename=='Layer'; parent = parent.parent) {
if(parent.locked)
return true;
}
return layer.locked;
}

function checkLayerVisibility(layer) {
if(layer.visible)
for(var parent = layer.parent; parent.typename=='Layer'; parent = parent.parent) {
if(!parent.visible)
return false;
}
return layer.visible;
}

Answer

You can check sublayer visible status by checking this status in parent layers, if one of them is hidden, hence this sublayer also hidden:

function checkLayerVisibility(layer)
{
    if(layer.visible) 
    for(var parent = layer.parent; parent.typename=='Layer'; parent = parent.parent)
    {
         if(!parent.visible)
            return false;
     }
    return layer.visible;
 } 

For locked/unlocked status the same way:

function checkLayerLockedStatus(layer)
{
    if(!layer.locked) 
    for(var parent = layer.parent; parent.typename=='Layer'; parent = parent.parent)
    {
         if(parent.locked)
            return true;
    }
    return layer.locked;
 }