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).
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;
}
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;
}
Related
I am writing a tinymce custom plugin called Mergetable. which will merger two user selected table.
Problem statement:
TinyMce is not allowing to select two table , by using shift and mouse I can select content of the table. So I can't use tinmce.activeeditor.selection.getNode() method instead using tinmce.activeeditor.selection.getContent().
Form getcontent() method I am getting proper html of both table. After do some operation while setting content using tinmce.activeeditor.selection.setContent() both table merged properly but two more table with empty td created one in top and one in bottom . Please see below plugin code.
code:
(function () {
var mergeTable = (function () {
'use strict';
tinymce.PluginManager.add("mergeTable", function (editor, url) {
function Merge(){
var selectedhtml=editor.selection.getContent();
//using getContent() as getnode returning body node
var dv=document.createElement('div');
dv.innerHTML= selectedhtml;
var tableElements = dv.getElementsByTagName('TABLE');
if (tableElements.length == 2) {
var tableOne = tableElements[0];
var tableTwo = tableElements[1];
var tempTable = null;
var offsetLeft = tableOne.offsetLeft;
var offsetTop = tableOne.offsetTop;
var elem = tableElements[0];
if (tableOne.nodeName == "TABLE" && tableTwo.nodeName == "TABLE") {
for (var r = 0; r < tableTwo.rows.length; r++) {
var newTR = tableOne.insertRow(tableOne.rows.length);
for (var i = 0; i < tableTwo.rows[r].cells.length; i++) {
var newTD = newTR.insertCell()
newTD.innerHTML = tableTwo.rows[r].cells[i].innerHTML;
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan;
newTD.rowSpan = tableTwo.rows[r].cells[i].rowSpan;
newTD.style.cssText = tableTwo.rows[r].cells[i].style.cssText;
if (tableOne.style.border != "") {
newTD.style.border = "1px dotted #BFBFBF"
}
}
}
tableTwo.remove();
console.log(dv.innerHTML);
editor.selection.setContent(dv.innerHTML);
editor.nodeChanged();
}
else {
alert("Please select two tables");
}
}
}
editor.ui.registry.addButton('mergeTable', {
text: "Merge Table",
onAction: function(){ Merge();}
});
});
}());
}());
I am able to fix my problem by using some work around . Instead use setContent() method. I have remove selected content and use insertContent().
Please find working code below.
(function () {
var mergeTable = (function () {
'use strict';
tinymce.PluginManager.add("mergeTable", function (editor, url) {
var cmd = function (command) {
return function () {
return editor.execCommand(command);
};
};
function Merge(){
var selectedhtml=editor.selection.getContent();
var dv=document.createElement('div');
dv.innerHTML= selectedhtml;
var tableElements = dv.getElementsByTagName('TABLE');
if (tableElements.length == 2) {
var tableOne = tableElements[0];
var tableTwo = tableElements[1];
var tempTable = null;
var tableOneMaxCell=0
var tabletwoMaxCell=0
var tempCellcount=0
var tableOneRowcount=tableOne.rows.length;
tableOne.querySelectorAll("tr").forEach(function(e){
tempCellcount= e.querySelectorAll("td").length ;
if(tempCellcount>tableOneMaxCell)
{
tableOneMaxCell=tempCellcount;
}
});
tableTwo.querySelectorAll("tr").forEach(function(e){
tempCellcount= e.querySelectorAll("td").length ;
if(tempCellcount>tabletwoMaxCell)
{
tabletwoMaxCell=tempCellcount;
}
});
if (tableOne.nodeName == "TABLE" && tableTwo.nodeName == "TABLE") {
for (var r = 0; r < tableTwo.rows.length; r++) {
var newTR = tableOne.insertRow(tableOne.rows.length);
for (var i = 0; i < tableTwo.rows[r].cells.length; i++) {
var newTD = newTR.insertCell()
newTD.innerHTML = tableTwo.rows[r].cells[i].innerHTML;
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan;
newTD.rowSpan = tableTwo.rows[r].cells[i].rowSpan;
newTD.style.cssText = tableTwo.rows[r].cells[i].style.cssText;
if (tableOne.style.border != "") {
newTD.style.border = "1px dotted #BFBFBF"
}
if(i==tableTwo.rows[r].cells.length-1 && tableOneMaxCell>tabletwoMaxCell){
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan + (tableOneMaxCell-tabletwoMaxCell);
}
}
}
for( var t1=0; t1<tableOneRowcount; t1++ ){
var celllen=tableOne.rows[t1].cells.length;
tableOne.rows[t1].cells[celllen-1].colSpan=tableOne.rows[t1].cells[celllen-1].colSpan+(tabletwoMaxCell-tableOneMaxCell)
}
tableTwo.remove();
// cmd('mceTableDelete');
// var selObj = editor.selection;
// var selstartRange = selObj.getStart();
// var selectendRange= selObj.getEnd();
// var selrng=selObj.getRng();
// console.log(selstartRange);
// console.log(selectendRange);
// editor.execCommand('mceTableDelete');
// selObj.removeAllRanges();
editor.selection.getSelectedBlocks().forEach(function(elm){
elm.remove();
});
// selObj.setRng(selrng,true);
editor.insertContent(dv.innerHTML);
editor.nodeChanged();
}
else {
editor.notificationManager.open({
text: 'Please select two table.',
type: 'error'
});
}
}
else {
editor.notificationManager.open({
text: 'Please select two table.',
type: 'error'
});
}
}
editor.ui.registry.addButton('mergeTable', {
text: "MergeTable",
onAction: function(){ Merge();}
});
});
}());
}());
So for some reason, the JavaScript that I'm using is not working on IE - There are errors which I will point out below. If someone knows anything else that I can try or knows how I can manipulate the code to make it more IE friendly, I'd really appreciate it.
Here are the steps that I've taken:
- Use https://babeljs.io/ to convert the whole page to ES2015.
- Added a polyfill script tag from https://polyfill.io/
Lots of code below (Whole general.js file which I've already converted using Babel (Please let me know if you want me to upload the original general.js file)):
Everything below rtd3Confirmation function is supposed to be:
for (var inputElement of rtd3ChangeClass) {
inputElement.addEventListener('change', rtd3Confirmation);
}
but that was before babel converted it.
"use strict";
// Form wrapper variables
var contactFormID = document.getElementById('contactForm');
var formWrapperSpecific = document.getElementById('form-wrapper-specific');
var formWrapperCertainSelection = document.getElementById('form-wrapper-certain-selection');
var formWrapperCertain = document.getElementById('form-wrapper-certain');
var formWrapperConfirm = document.getElementById('rtd3Confirm'); // Alert variables
var stateAlertID = document.getElementById('stateWarning');
var stateQuery = document.querySelector('#stateWarning b#stateName');
var resident = document.getElementById('resident');
var is_submitted = document.getElementsByClassName('is-submitted'); // Right to Know variables
var rtk5_selection = document.getElementById('rtk5');
var rtk5declaration = document.getElementById('rtk5Declaration'); // Right to Delete variables
var rtdChange = document.getElementById('rtd3');
var rtd3ChangeClass = document.querySelectorAll(".rtd3_change"); // Array for states
var states = []; // Once the DOM has loaded, call functions
document.addEventListener('DOMContentLoaded', function () {
formHandler();
residentAlert();
rtdCheckboxSelection();
rtd3Confirmation();
rtk5Declaration();
get_states();
}); // Show/hide form depending if state is included in array on dropdown selection
function formHandler() {
contactFormID.style.display = 'block';
if (resident == null) return;
if (!states.includes(resident.value)) contactFormID.style.display = 'none';
resident.addEventListener('change', formHandler);
} // Show/hide state alert for non-residents
function residentAlert() {
if (resident !== null) {
resident.addEventListener('change', function () {
// If value in states array is true, show the form
if (!states.includes(resident.value)) {
stateAlertID.style.display = 'block';
stateQuery.textContent = resident.options[resident.selectedIndex].text;
} else {
stateAlertID.style.display = 'none';
}
});
}
} // Show states dropdown depending on PHP variables
function get_states() {
var data_states = contactFormID.getAttribute('data-states').match(/\w{1,}/g);
data_states.forEach(function (state, i) {
return states[i] = state;
});
} // If RTK5 is selected, show declaration field and set required tag
function rtk5Declaration() {
if (!rtk5_selection.checked) {
formWrapperSpecific.style.display = 'none';
rtk5declaration.removeAttribute('required');
} else {
formWrapperSpecific.style.display = '';
rtk5declaration.setAttribute('required', 'required');
}
}
rtk5_selection.addEventListener('change', rtk5Declaration); // If RTD3 is selected, show/hide more checkboxes
function rtdCheckboxSelection() {
formWrapperCertain.style.display = rtdChange.checked ? '' : 'none';
document.querySelectorAll('[name="rtd[checked]"]').forEach(function (r) {
return r.addEventListener('change', rtdCheckboxSelection);
});
} // If at least one checkbox inside rtd3 is checked, show confirmation and make required
function rtd3Confirmation() {
if (document.querySelectorAll('.rtd3_change:checked').length) {
formWrapperCertainSelection.style.display = '';
formWrapperConfirm.required = true;
} else {
formWrapperCertainSelection.style.display = 'none';
formWrapperConfirm.required = false;
}
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = rtd3ChangeClass[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var inputElement = _step.value;
inputElement.addEventListener('change', rtd3Confirmation);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
I'm working on a simon game and is doing a sequence of 3 at level 2 instead of doing just 2 at level 2. I've looked all over. and I've trying output to console, but I guess I've been staring at this for too long. If someone can find the bug, please share. thanks for the help.
here's the pen
https://codepen.io/zentech/pen/XaYygR
//variables
userSeq = [];
simonSeq = [];
const NUM_OF_LEVELS = 5;
var id, color, level = 0;
var strict = false;
var error = false;
var boardSound = [
"http://www.soundjay.com/button/sounds/button-4.mp3", //green
"http://www.soundjay.com/button/sounds/button-09.mp3", //red
"http://www.soundjay.com/button/sounds/button-10.mp3", //yellow
"http://www.soundjay.com/button/sounds/button-7.mp3" //blue
];
//1- start board sequence
$(document).ready(function() {
$(".start").click(function() {
strict = false;
error = false;
level++;
simonSeq = userSeq = [];
simonSequence();
})
//user pad listener
$(".pad").click(function() {
id = $(this).attr("id");
color = $(this).attr("class").split(" ")[1];
userSequence();
});
//strict mode listener
$(".strict").click(function() {
level = 0;
level++;
simonSeq = userSeq = [];
strict = true;
simonSequence();
})
})
//user sequence
function userSequence() {
userSeq.push(id);
console.log(id+" "+color);
addClassSound(id, color);
//check user sequence
if(!checkUserSeq()) {
//if playing strict mode reset everything lol
if(strict) {
console.log("strict");
simonSeq = [];
level = 1;
}
displayError();
userSeq = [];
error = true;
console.log("start simon error")
simonSequence();
}
//checking end of sequence
else if(userSeq.length == simonSeq.length && userSeq.length < NUM_OF_LEVELS) {
level++;
userSeq = [];
error = false;
console.log("start simon")
simonSequence();
}
//checking for winners
if(userSeq.length == NUM_OF_LEVELS) {
displayWinner();
resetGame();
}
}
/* simon sequence */
function simonSequence() {
console.log("level "+level);
$(".display").text(level);
if(!error) {
getRandomNum();
}
var i = 0;
var myInterval = setInterval(function() {
id = simonSeq[i];
color = $("#"+id).attr("class");
color = color.split(" ")[1];
console.log(id+" "+color);
addClassSound(id, color);
i++;
if(i == simonSeq.length) {
clearInterval(myInterval);
}
}, 1000);
}
//generate random number
function getRandomNum() {
var random = Math.floor(Math.random() * 4);
simonSeq.push(random);
}
/* add temporary class and sound */
function addClassSound(id, color) {
$("#"+id).addClass(color+"-active");
playSound(id)
setTimeout(function(){
$("#"+id).removeClass(color+"-active");
}, 500);
}
/* checking user seq against simon's */
function checkUserSeq() {
for(var i = 0; i < userSeq.length; i++) {
if(userSeq[i] != simonSeq[i]) {
return false;
}
}
return true;
}
/* display error */
function displayError() {
console.log("error");
var counter = 0;
var myError = setInterval(function() {
$(".display").text("Err");
counter++;
if(counter == 3) {
$(".display").text(level);
clearInterval(myError);
userSeq = [];
counter = 0;
}
}, 500);
}
//display winner
function displayWinner() {
var count = 0;
var winInterval = setInterval(function() {
count++;
$(".display").text("Win");
if(count == 5) {
clearInterval(winInterval);
$(".display").text("00");
count = 0;
}
}, 500);
}
/* play board sound */
function playSound(id) {
var sound = new Audio(boardSound[id]);
sound.play();
}
/* reset game */
function resetGame() {
userSeq = [];
simonSeq = [];
level = 0;
strict = false;
$(".display").text("00");
}
PROBLEM
You have a reference vs copy problem in your initialization code.
$(document).ready(function() {
$(".start").click(function() {
strict = false;
error = false;
level++;
simonSeq = userSeq = []; //PROBLEM !!!!
simonSequence();
})
Arrays are passed by reference, not value.
simonSeq = userSeq = [];
/* Any changes to 'userSeq' will affect 'simonSeq'.
'simonSeq' is referencing 'userSeq' */
SOLUTION
Change all instances of
simonSeq = userSeq = [];
To
simonSeq = [];
userSeq = [];
EXPLINATION
Values in JavaScript can be referred to in 2 ways; by reference and by value.
When you refer to something by value, you are copying it.
var numA = 5;
var numB = numA; //COPY numA over to numB
numA = 12; // Changes to numA will not affect numB because it was copied
console.log(numA); // 12
console.log(numB); // 5
When you refer to something by reference, your are referring/referencing it, not copying it. Any changes made to the original will affect everything that is referencing it.
var original = [1,2,3];
var ref = original; //Any changes made to 'original' will affect 'ref'
original.push('APPLES');
console.log(original); // [1,2,3,'APPLES']
console.log(ref); // [1,2,3,'APPLES']
In the above code ref does not actually contain any values. ref contains the memory location of original.
ref is referencing original.
Arrays and Objects are always passed/refereed to by reference.
Everything else is passed/refereed to by value (they are copied).
Is it possible to edit the static text in adobe illustrator UI? For example, I have a number at the bottom that displays the progress of something. I want to update that in a loop to show the progress (X item out of X total items).
I tried creating the text with the UI and updating the variables later, however that didn't work because the GUI code doesn't run again (unless via event listeners).
I also tried to edit the text in the loop, but there is no built-in method for that (like there is in Java).
I just want to know if this is possible in any way (still learning AI scripting). If it's not possible, that's fine, it's not vital, just a neat feature to show the progress of a long/slow loop.
function startGUI() {
var inputText, inputNum;
// Create Main Window
win = new Window( "dialog", "title", undefined );
// Enable use of 'Enter' key
win.addEventListener ("keydown", function(kd) {enter(kd) });
// Style for Main Window
win.orientation = "column";
win.alignChildren = ["fill", "fill"];
win.preferredSize = [250, 150];
// Style for group
var objGrp = win.add("panel", undefined, "group");
objGrp.orientation = "column";
objGrp.alignChildren = ["fill", "fill"];
var titleMsg = objGrp.add ("statictext", undefined, "name:");
var txt_Input = objGrp.add("edittext { characters: 1, justify: 'center', active: true }");
txt_Input.helpTip = "";
var titleMsg = objGrp.add ("statictext", undefined, "Number to start from:");
var txt_Num = objGrp.add("edittext { characters: 1, justify: 'center' }");
txt_Num.helpTip = "Object number to start from, other than 1";
var txt_Count = win.add("statictext", undefined, "Current object: ".concat (itemCount).concat(" out of: ").concat(countTotal));
// Button
var objBtn = objGrp.add("button", undefined, "Start");
objGrp.helpTip = "";
objGrp.onClick = function() {
inputText = txt_Input.text;
inputNum = txt_Num.text;
start(inputText, inputNum);
app.redraw();
}
// Use Enter key
function enter(k) {
if (k.keyName == "Enter") {
inputText = txt_Input.text;
inputNum = txt_Num.text;
start(inputText, inputNum);
app.redraw();
}
}
// Listener for the input
txt_Input.onChanging = function() {
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();
}// end startGUI
Update:
#target illustrator
if (app.documents.length > 0) {
// Update with new script versions
var alphaLayersFile = "/AlphabatizeLayers-v1.03.jsx";
var deleteLayersFile = "/DeleteEmptyLayers-v1.00.jsx";
var dialogName = "Layer Search Selection"
var doc = app.activeDocument;
var docLayers = doc.layers;
var inputText;
var caseSense = false;
var exactWord = false;
var match = false;
var textSearch = false;
var itemCount = 0, countTotal;
// Display GUI
startGUI();
// Main Search function
function searchAll(layers, txt_Count, win) {
match = false;
searchLayers(layers, txt_Count, win);
// When match is found, show dialog
if (match) {
alert("Found match!");
match = false;
} else {
alert("No match found.");
match = false;
}
}
// Recursive loop to search all layers in active document
function searchLayers ( layers, txt_Count, win ) {
var input = inputText;
var length = layers.length;
var currentLayer ;
try {
countTotal = length;
for (var i = length; i--;) { //var i = length; i--; //var i = 0; i <= length; i++
currentLayer = layers[i];
itemCount++;
txt_Count.text = "Current object: ".concat(itemCount).concat(" out of: ").concat(countTotal);
win.update();
$.sleep(1000);
var locked = currentLayer.locked;
var visible = currentLayer.visible;
if (visible == true || locked == false) {
searchLayerName(input, currentLayer);
// Search for sublayers, page items or group items
if (currentLayer.layers) {
searchLayers(currentLayer.layers);
searchLayers(currentLayer.groupItems);
searchLayers(currentLayer.pathItems);
searchLayers(currentLayer.compoundPathItems);
searchLayers(currentLayer.symbolItems);
searchLayers(currentLayer.textFrames);
}
}
}
} catch (error) {
logger (error);
}
}// end SearchLayers
// Search for match between input and layer name
function searchLayerName( inputText, currentLayer ) {
try {
if (inputText) {
var layerName = "";
var layerType = currentLayer.typename;
var searchIndex = -1;
var exact = false;
switch (layerType) {
default:
layerName = currentLayer.name;
searchIndex = searchLayer(inputText, layerName);
selectLayer(searchIndex, currentLayer, layerType)
break;
case "SymbolItem":
layerName = currentLayer.symbol.name;
searchIndex = searchLayer(inputText, layerName);
selectLayer(searchIndex, currentLayer, layerType)
break;
case "TextFrame":
layerName = currentLayer.contents;
searchIndex = searchLayer(inputText, layerName);
selectLayer(searchIndex, currentLayer, layerType)
break;
case "Layer":
layerName = currentLayer.name;
searchIndex = searchLayer(inputText, layerName);
selectLayer(searchIndex, currentLayer, layerType)
break;
} // end Switch
} // end inputText
} catch (error) {
logger(error);
}
} // end Search
function searchLayer(inputText, layerName) {
var searchIndex = -1;
var caseSensitive = caseSense;
var exact = exactWord;
//inputText = fixString(inputText);
if (caseSensitive) {
searchIndex = layerName.indexOf(inputText) ;
} else if (exact) {
if (layerName === inputText) {
searchIndex = 0;
}
} else {
searchIndex = layerName.toLowerCase().indexOf(inputText.toLowerCase());
}
return searchIndex;
}
function selectLayer(searchIndex, currentLayer, layerType) {
if ( searchIndex != -1 ) {
if (layerType != "Layer") {
currentLayer.selected = true;
match = true;
} else if (layerType == "Layer") {
currentLayer.hasSelectedArtwork = true;
//layer.selected = true;
match = true;
}
}
} // end selectLayer
// Display GUI
function startGUI() {
// Create Main Window
var win = new Window( "dialog", dialogName );
// Style for Main Window
win.orientation = "column";
win.alignChildren = ["fill", "fill"];
//win.preferredSize = [150, 350];
// Style for Search group
var searchGrp = win.add("panel", undefined, "Search Layers");
searchGrp.orientation = "column";
searchGrp.alignChildren = ["fill", "fill"];
var titleMsg = searchGrp.add ("statictext", undefined, "Layer name to search:");
var txt_Input = searchGrp.add("edittext { characters: 1, justify: 'center', active: true }");
txt_Input.helpTip = "Input letters to search";
countTotal = docLayers.length;
txt_Count = win.add("statictext", undefined, "Current object ".concat(itemCount).concat(" out of: ").concat(countTotal));
// Search Button
var searchBtn = searchGrp.add("button", undefined, "Search");
searchBtn.helpTip = "Search from text items";
searchBtn.onClick = function() {
inputText = txt_Input.text;
searchAll(docLayers, txt_Count, win);
app.redraw();
}
// Listener for the input
txt_Input.onChanging = function() {
app.redraw();
}
// Options
var optionsGrp = win.add("panel", undefined, "Options");
optionsGrp.orientation = "row";
optionsGrp.margins = [10, 15, 10, 6];
optionsGrp.alignChildren = ["fill", "fill"];
// Radio button: Case Sensitive
var rdb_caseSensitive = optionsGrp.add ("radiobutton", undefined, "Match Case");
rdb_caseSensitive.helpTip = "Case sensitive search";
rdb_caseSensitive.value = false;
// Listener: Case Sensitive
rdb_caseSensitive.onClick = function() {
caseSense = rdb_caseSensitive.value;
app.redraw();
}
// Radio button: Exact Word
var rdb_exactWord = optionsGrp.add ("radiobutton", undefined, "Match Exact Word");
rdb_exactWord.helpTip = "Search exact word";
rdb_exactWord.value = false;
// Listener: Exact Word
rdb_exactWord.onClick = function() {
exactWord = rdb_exactWord.value;
app.redraw();
}
// Radio button: None
var chk_none = optionsGrp.add ("radiobutton", undefined, "None");
chk_none.helpTip = "Use no extra option";
chk_none.value = false;
// Radio button: None
chk_none.onClick = function() {
exactWord = false;
caseSense = false;
//textSearch = chk_textSearch.value;
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();
}// end startGUI
// Check to see if parent layer is visible
// Sometimes child layers that inheirit locked/hidden
// status from parent will return 'undefined' for visibility
function checkParentVisibility(layer) {
for(var parent = layer.parent; parent.typename=='Layer'; parent = parent.parent) {
var pvis = parent.visible;
if(!pvis) {
return false;
} else {
return true;
}
}
}
}
function fixString(str) {
str = str.split("_").join(" ");
return str;
}
// Prints stack trace
// Note: Don't print error message unless debugging
function logger(e) {
var errorMsg = "";
errorMsg = errorMsg.concat(e.line, "\n", e.message, "\n", e.stack);
$.writeln(errorMsg);
}
} else {
alert("You do not have any document opened!");
}
I second the recommendation to use a progress bar. I have created a demo for progress bars in Illustrator using JSX (as well as some other demos) here: https://github.com/iconifyit/illustrator-jsx-demos
Let me know if you have any trouble with the demos and I will clarify whatever I can.
Here is the one script, that will update static text
var countTotal = 10;
var itemCount = 0;
function startGUI() {
var inputText, inputNum;
// Create Main Window
win = new Window("dialog", "title", undefined);
// Enable use of 'Enter' key
win.addEventListener("keydown", function(kd) {
enter(kd)
});
// Style for Main Window
win.orientation = "column";
win.alignChildren = ["fill", "fill"];
win.preferredSize = [250, 150];
// Style for group
var objGrp = win.add("panel", undefined, "Panel");
objGrp.orientation = "column";
objGrp.alignChildren = ["fill", "fill"];
var titleMsg = objGrp.add("statictext", undefined, "Number to start from:");
var txt_Num = objGrp.add("edittext { characters: 1, justify: 'center' }");
txt_Num.helpTip = "Object number to start from, other than 1";
txt_Count = win.add("statictext", undefined, "Current object: ".concat(itemCount).concat(" out of: ").concat(countTotal));
// Button
var btn = objGrp.add("button", undefined, "Start");
btn.onClick = function() {
inputText = txt_Num.text;
itemCount = inputText
inputNum = txt_Num.text;
for (var i = 0; i < 10; i++) {
itemCount++;
txt_Count.text = "Current object: ".concat(itemCount).concat(" out of: ").concat(countTotal);
win.update();
$.sleep(1000);
}
win.close();
}
// Use Enter key
function enter(k) {
if (k.keyName == "Enter") {
inputText = txt_Num.text;
inputNum = txt_Num.text;
inputNum = txt_Num.text;
for (var i = 0; i < 10; i++) {
itemCount++;
txt_Count.text = "Current object: ".concat(itemCount).concat(" out of: ").concat(countTotal);
win.update();
$.sleep(1000);
}
win.close();
}
}
// Close button
var quitBtn = win.add("button", undefined, "Close");
// Event listener for the quit button
quitBtn.onClick = function() {
win.close();
}
// Centering & Show Window
win.center();
win.show();
} // end startGUI
startGUI();
You can change the script as per requirement. I have just removed some fields from your code. I have used for loop just to update the value of itemCount in static text and used $.sleep(1000) so that change should be visible otherwise in for loop you will not able to see the change.
Hope this will help you. Also, you can use progressbar if you want to show progress
I have a script that searches for layer names and replaces them, so far it works fine. However I have run across a problem and I don't understand what is happening. I have altered the script to include certain objects (pathItems, etc), in addition to layers. However when it finds and replaces the object name (which it does find them), it does not update in the layers pane. I debugged the program and it does indeed find and replace it, but does not update the names in the layers pane of Adobe Illustrator.
#target illustrator
#targetengine main
// JavaScript Document
if (app.documents.length > 0) {
var doc = app.activeDocument;
var docLayers = doc.layers;
var searchText = "";
var replaceText = "";
var found = false;
var match = false;
function replace(layers) {
match = false;
recurseLayers(layers);
app.redraw();
// When match is found, show dialog
if (match) {
alert("Found match!");
match = false;
} else {
alert("No match found.");
match = false;
}
}
function recurseLayers(layers) {
var length = layers.length;
var currentLayer = null;
var searchtext = searchText;
var replacetext = replaceText;
try {
for (var i = length; i--;) {
currentLayer = layers[i];
var visible = checkLayerVisibility(currentLayer);
var locked = checkLayerLocked(currentLayer);
if (visible == true || locked == false) {
replaceName(currentLayer, searchText, replaceText);
if (currentLayer.layers) {
recurseLayers(currentLayer.layers);
recurseLayers(currentLayer.groupItems);
recurseLayers(currentLayer.pathItems);
recurseLayers(currentLayer.compoundPathItems);
recurseLayers(currentLayer.symbolItems);
recurseLayers(currentLayer.textFrames);
}
}
}
} catch (e) {
logger (e);
}
}
function replaceName(currentLayer, searchText, replaceText) {
try {
currentLayer.name = currentLayer.name.replace(searchText, replaceText);
match = true;
} 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;
}
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;
replace(docLayers);
app.redraw();
}
function enter(k) {
if (k.keyName == "Enter") {
searchText = txt_searchText.text;
replaceText = txt_replaceText.text;
replace(docLayers);
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!");
}
These are the layers I am using, the lines are what I need to replace, just their display name (either full name or part of the name).
As you can see in the second picture, the name has indeed been changed (changed the 'A8900' to '1'), but only shows in when I double click the name, or hide and unhide the layers (then it updates). I can't figure out why this is happening, maybe something to do with how the objects work in AI? There doesn't seem to be any way to debug this either, since in my code it working fine, but its not updating correctly in AI. I also used an 'app.redraw()' in the hopes that it will refresh it, but it does not. Any help is appreciated
I managed to get it working, I added a line of code to select the layer and it updates the name in the layers panel.
If anyone know why this happens, I would still like to know.
#target illustrator
#targetengine main
// JavaScript Document
if (app.documents.length > 0) {
var doc = app.activeDocument;
var docLayers = doc.layers;
var searchText = "";
var replaceText = "";
var found = false;
var match = false;
function replace(layers) {
match = false;
recurseLayers(layers);
// When match is found, show dialog
if (match) {
alert("Found match!");
match = false;
} else {
alert("No match found.");
match = false;
}
}
function recurseLayers(layers) {
var length = layers.length;
var currentLayer = null;
var searchtext = searchText;
var replacetext = replaceText;
try {
for (var i = length; i--;) {
currentLayer = layers[i];
var visible = checkLayerVisibility(currentLayer);
var locked = checkLayerLocked(currentLayer);
if (visible == true || locked == false) {
replaceName(currentLayer, searchText, replaceText);
if (currentLayer.layers) {
recurseLayers(currentLayer.layers);
recurseLayers(currentLayer.groupItems);
recurseLayers(currentLayer.pathItems);
recurseLayers(currentLayer.compoundPathItems);
recurseLayers(currentLayer.symbolItems);
recurseLayers(currentLayer.textFrames);
}
}
}
} catch (e) {
logger (e);
}
}
function replaceName(currentLayer, searchText, replaceText) {
try {
var name = currentLayer.name;
var searchIndex = name.toLowerCase().indexOf(searchText.toLowerCase());
if( searchIndex != -1 ) {
currentLayer.name = currentLayer.name.replace(searchText, replaceText);
currentLayer.selected = true;
match = true;
}
} 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;
}
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;
replace(docLayers);
app.redraw();
}
function enter(k) {
if (k.keyName == "Enter") {
searchText = txt_searchText.text;
replaceText = txt_replaceText.text;
replace(docLayers);
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!");
}