@stevekwak
Just an update on this. The code in my previous post does in fact seem to work well at avoiding edit context errors.
Additionally, knowing at times there are going to be items that are outside of edit context, I figured out a way to select the artboards where there are nodes that the plugin was unable to update.
Basically, while we’re walking down the tree of children, once it encounters a node/container that will be out of context, it will continue on crawling, but pass an argument to the command so that we know not to perform unsafe actions.
In my plugin I also store the unsafe nodes in an array, then once I’m done walking the tree, I loop through all the nodes where I was not able to make any changes, and use a getAncestors
function to find which artboard it’s on. Because the artboard is within edit context, I can add it to selection.items
safely thereby giving some visual indication where the unaffected items are located.
Its not the prettiest, but it will have to do for now.
const { Artboard} = require("scenegraph");
var commands = require("commands");
let application = require("application");
let panel;
let actionData;
function replaceArialWithHelvetica(){
walkDownTree(root, onReplaceArialWithHelveticaNode, selection);
}
function onReplaceArialWithHelveticaNode(node, value, safe=true) {
if (node.constructor.name == "Text") {
if (node.fontFamily == "Arial") {
if (safe) {
node.fontFamily = "Helvetica";
} else {
actionData.push(node);
}
}
}
}
function walkDownTree(node, command, value = null) {
command(node, value);
if (
(!node.mask) &&
(node.constructor.name != "RepeatGrid") &&
(node.constructor.name != "BooleanGroup") &&
(node.constructor.name != "LinkedGraphic")
) {
node.children.forEach(childNode => {
walkDownTree(childNode, command, value);
});
}else{
node.children.forEach(childNode => {
unsafeWalkDownTree(childNode, command, value);
});
}
}
function unsafeWalkDownTree(node, command, value = null) {
command(node, value, false); //Pass false to the command, so we can store the nodes that are out of edit context
node.children.forEach(childNode => {
unsafeWalkDownTree(childNode, command, value);
});
}
function getNodeAncestry(node){
let ancestors = [];
let currentNode = node;
while (currentNode.parent!=null) {
ancestors.push(currentNode.parent);
currentNode = currentNode.parent;
}
return ancestors;
}
function create() {
const HTML =
`<style>
.break {
flex-wrap: wrap;
}
.show {
display: block;
}
.hide {
display: none;
}
</style>
<form method="dialog" id="main">
<div class="row break">
<button id="replaceArialWithHelvetica">Global Replace Arial with Helvetica</button>
</div>
</form>
`
panel = document.createElement("div");
panel.innerHTML = HTML;
panel.querySelector("#replaceArialWithHelvetica").addEventListener("click", event => {
application.editDocument( function(selection, root){
actionData = [];
replaceArialWithHelvetica(selection, root);
let unaffectedArtboards = [];
actionData.forEach(actionDataNode => {
const unaffectedNodeAncestry = getNodeAncestry(actionDataNode);
const unaffectedNodeArtboard = unaffectedNodeAncestry[unaffectedNodeAncestry.length - 2]
if (unaffectedArtboards.indexOf(unaffectedNodeArtboard) === -1) {
unaffectedArtboards.push(unaffectedNodeArtboard);
}
});
selection.items = unaffectedArtboards;
});
});
return panel;
}
function show(event) {
if (!panel) event.node.appendChild(create());
}
module.exports = {
panels: {
pluginPanel: {
show,
hide,
update
}
}
};