Answered
Search and replace a text, only in visible layers
Hello,
Please I need a script to search for a textA in visible layers only and replace it by textB. Could you help.
Thanks in advance.
Hello,
Please I need a script to search for a textA in visible layers only and replace it by textB. Could you help.
Thanks in advance.
Here's my attempt. Recursive lookup of ancestors and sublayers, supports any amount of find/replace options, also has options for enabling whether to affect locked or hidden layers:
var config = {
// Support for any amount of find/replace parameters here
targets: [
{
find: "foo",
replace: "bar",
},
{
find: /(locked|hidden)/i, // including support for Regex patterns
replace: "Success",
},
],
affects: {
// names: false, // Whether it changes names, not implemented but possible
content: true, // Must be true at this basic state of the script
},
searchIn: {
hidden: false, // Whether it changes hidden layer contents
locked: false, // Whether it changes locked layer contents
},
};
//
// Don't alter the below unless you know what you're doing.
//
// Very simple ES6 polyfills for Array methods to make code more concise:
Array.prototype.filter = function (callback) {
var filtered = [];
for (var i = 0; i < this.length; i++)
if (callback(this[i], i, this)) filtered.push(this[i]);
return filtered;
};
Array.prototype.forEach = function (callback) {
for (var i = 0; i < this.length; i++) callback(this[i], i, this);
};
// This is a bit too verbose for what we need here, but as-is can recurse to find sublayers no matter the depth if we use:
// var list = get("layers"); <-- This is *all* layers and sublayers, not just the root-level / depth 0 ones from doc.layers.
function get(type, parent, deep) {
if (arguments.length == 1 || !parent) {
parent = app.activeDocument;
deep = true;
}
var result = [];
if (!parent[type]) return [];
for (var i = 0; i < parent[type].length; i++) {
result.push(parent[type][i]);
if (parent[type][i][type] && deep)
result = [].concat(result, get(type, parent[type][i], deep));
}
return result;
}
// The main obstacle is getting a recursive parent chain, then determining if any part of this chain doesn't meet requirements:
function checkAncestry(frame) {
// So we'll split the logic into just constructing a recursive Array containing data about parents when applicable:
function getAncestry(frame) {
// And have a dedicated recursive function to look into the parent then recurse and concat an Array when needed:
function getParentChain(item, data) {
if (item.parent && /layer/i.test(item.parent.typename))
data = getParentChain(
item.parent,
[].concat(
{ hidden: !item.parent.visible, locked: item.parent.locked },
data
)
);
return data;
}
// For ease, we start the chain with the textFrame's hidden/locked data:
return getParentChain(frame, [
{ hidden: frame.hidden, locked: frame.locked },
]);
}
// Now that we have a list like [ { locked: true, hidden: false }, {locked: false, hidden: false }, ... ]
// We can filter it to see if there are any hidden/lockeds present:
var chain = getAncestry(frame),
hiddenStatus =
chain.filter(function (i) {
return i.hidden;
}).length > 0,
lockedStatus =
chain.filter(function (i) {
return i.locked;
}).length > 0;
// AI doesn't handle short circuiting well, so if no locked/hiddens exist, we'll explicitly return:
if (!lockedStatus && !hiddenStatus) return true;
// Otherwise we need to ensure the chain contents either match the queries or returned empty:
else
return (
(hiddenStatus == config.searchIn.hidden || !hiddenStatus) &&
(lockedStatus == config.searchIn.locked || !lockedStatus)
);
}
// Our main function can now be very concise, we get all text frames:
get("textFrames")
// But remove any that don't match our search queries for hidden/locked
.filter(function (i) {
return checkAncestry(i);
// Then for every remaining textFrame:
})
.forEach(function (frame) {
// And for every find/replace option:
config.targets.forEach(function (target) {
// Replace the text content of the frame:
frame.contents = frame.contents.replace(target.find, target.replace);
});
});Already have an account? Login
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.