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 am trying to fix this script to automatically connect people you may know on Linkedin based on User roles (CEO e.t.c), Can someone help me fix this, Below is my code; I have tried the script on almost all browsers, Somebody help fix this.
var userRole = [
"CEO",
"CIO"
];
var inviter = {} || inviter;
inviter.userList = [];
inviter.className = 'button-secondary-small';
inviter.refresh = function () {
window.scrollTo(0, document.body.scrollHeight);
window.scrollTo(document.body.scrollHeight, 0);
window.scrollTo(0, document.body.scrollHeight);
};
inviter.initiate = function()
{
inviter.refresh();
var connectBtns = $(".button-secondary-small:visible");
//
if (connectBtns == null) {var connectBtns = inviter.initiate();}
return connectBtns;
};
inviter.invite = function () {
var connectBtns = inviter.initiate();
var buttonLength = connectBtns.length;
for (var i = 0; i < buttonLength; i++) {
if (connectBtns != null && connectBtns[i] != null) {inviter.handleRepeat(connectBtns[i]);}
//if there is a connect button and there is at least one that has not been pushed, repeat
if (i == buttonLength - 1) {
console.log("done: " + i);
inviter.refresh();
}
}
};
inviter.handleRepeat = function(button)
{
var nameValue = button.children[1].textContent
var name = nameValue.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
function hasRole(role){
for(var i = 0; i < role.length; i++) {
// cannot read children of undefined
var position = button.parentNode.parentNode.children[1].children[1].children[0].children[3].textContent;
var formatedPosition = position.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
var hasRole = formatedPosition.indexOf(role[i]) == -1 ? false : true;
console.log('Has role: ' + role[i] + ' -> ' + hasRole);
if (hasRole) {
return hasRole;
}
}
return false;
}
if(inviter.arrayContains(name))
{
console.log("canceled");
var cancel = button.parentNode.parentNode.children[0];
cancel.click();
}
else if (hasRole(userRole) == false) {
console.log("cancel");
var cancel = button.parentNode.parentNode.children[0];
cancel.click();
}
else if (button.textContent.indexOf("Connect")<0){
console.log("skipped");
inviter.userList.push(name); // it's likely that this person didn't join linkedin in the meantime, so we'll ignore them
var cancel = button.parentNode.parentNode.children[0];
cancel.click();
}
else {
console.log("added");
inviter.userList.push(name);
button.click();
}
};
inviter.arrayContains = function(item)
{
return (inviter.userList.indexOf(item) > -1);
};
inviter.usersJson = {};
inviter.loadResult = function()
{
var retrievedObject = localStorage.getItem('inviterList');
var temp = JSON.stringify(retrievedObject);
inviter.userList = JSON.parse(temp);
};
inviter.saveResult = function()
{
inviter.usersJson = JSON.stringify(inviter.userList);
localStorage.setItem('inviterList', inviter.usersJson);
};
setInterval(function () { inviter.invite(); }, 5000);
`
When I try executing this, I get the following error:
VM288:49 Uncaught TypeError: Cannot read property 'children' of undefined
at hasRole (<anonymous>:49:71)
at Object.inviter.handleRepeat (<anonymous>:66:11)
at Object.inviter.invite (<anonymous>:30:69)
at <anonymous>:108:35
Any ideas as to how to fix it?
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 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;
}