Copy link to clipboard
Copied
Hi,
I'm building a script for InDesign to check if any non-brand colours are used in the document. The script displays a palette/dialog and fetches all the swatches. The user then selects the required Brand colours and clicks the button to check any inconsistencies.
The current script prompts the correct number of inconsistencies. The quick navigation dialog box perfectly shows the next object on clicking the 'Next' button. However, the script is not selecting any object. I want the script to find the culprit object and select it, so that the user does not have to find it manually.
Can anyone fix it please.
Thanks.
#target indesign
// --- Global Variables ---
var doc;
// --- Main Execution ---
if (app.documents.length > 0) {
doc = app.activeDocument;
createAndRunChecker();
} else {
alert("Please open an InDesign document before running this script.");
}
// =============================================================================
// Helper: indexOf replacement (ExtendScript safe)
// =============================================================================
function inArray(arr, val) {
if (!arr) return -1;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === val) return i;
}
return -1;
}
// =============================================================================
// Main UI
// =============================================================================
function createAndRunChecker() {
var dialog = new Window("dialog", "Brand Colour Checker v8.0");
dialog.orientation = "column";
dialog.alignChildren = ["fill", "top"];
dialog.spacing = 10;
dialog.margins = 16;
dialog.add("statictext", undefined, "Select Brand Colours from the Swatches:");
var swatchPanel = dialog.add("panel", undefined, "Document Swatches");
swatchPanel.orientation = "column";
swatchPanel.alignChildren = "left";
swatchPanel.margins = 10;
var allSwatches = doc.swatches;
var defaultNames = ["None", "Paper", "Black", "Registration"];
for (var i = 0; i < allSwatches.length; i++) {
var currentSwatch = allSwatches[i];
try {
if (currentSwatch && currentSwatch.isValid && inArray(defaultNames, currentSwatch.name) === -1) {
var cb = swatchPanel.add("checkbox", undefined, currentSwatch.name);
cb.swatchObject = currentSwatch;
cb.value = false;
}
} catch (e) {
$.writeln("Skipped swatch due to error: " + e);
}
}
var btnGroup = dialog.add("group");
btnGroup.alignment = "right";
var cancelButton = btnGroup.add("button", undefined, "Cancel", { name: "cancel" });
var checkButton = btnGroup.add("button", undefined, "Check Inconsistent Brand Colours", { name: "ok" });
checkButton.onClick = function () {
var brandSwatches = [];
for (var i = 0; i < swatchPanel.children.length; i++) {
var checkbox = swatchPanel.children[i];
try {
if (checkbox && checkbox.value === true && checkbox.swatchObject) {
brandSwatches.push(checkbox.swatchObject);
}
} catch (e) {
$.writeln("Checkbox read error: " + e);
}
}
if (brandSwatches.length === 0) {
alert("Please select at least one brand colour to check against.");
return;
}
dialog.close();
try {
var inconsistentItems = findInconsistentItems(brandSwatches);
if (inconsistentItems.length > 0) {
navigateThroughItems(inconsistentItems);
} else {
alert("✅ All Clear! No inconsistent brand colours were found.");
}
} catch (err) {
alert("Error during check:\n" + (err && err.message ? err.message : err));
}
};
cancelButton.onClick = function () {
dialog.close();
};
dialog.center();
dialog.show();
}
// =============================================================================
// Find Inconsistent Items
// =============================================================================
function findInconsistentItems(brandSwatches) {
var foundItems = [];
var allItems = doc.allPageItems;
var defaultNames = ["None", "Paper", "Black", "Registration"];
function isAllowedSwatch(swatch) {
if (!swatch) return true;
for (var i = 0; i < brandSwatches.length; i++) {
try {
var b = brandSwatches[i];
if (b && swatch && b.id !== undefined && swatch.id !== undefined && b.id === swatch.id) return true;
if (b && swatch && b.name && swatch.name && b.name === swatch.name) return true;
} catch (e) {}
}
try {
if (swatch && typeof swatch.name === "string" && inArray(defaultNames, swatch.name) !== -1) return true;
} catch (e) {}
return false;
}
for (var j = 0; j < allItems.length; j++) {
var item = allItems[j];
if (!item) continue;
var reason = "";
try {
var fill = undefined;
try { fill = item.fillColor; } catch (e) { fill = undefined; }
if (fill && typeof fill.name === "string" && fill.name !== "None") {
var fillName = fill.name || "";
if (fillName === "") {
reason = "Unnamed fill colour used.";
} else if (!isAllowedSwatch(fill)) {
reason = "Non-brand fill colour ('" + fillName + "') used.";
} else {
var ft = undefined;
try { ft = item.fillTint; } catch (e) { ft = undefined; }
if (typeof ft === "number" && ft !== -1 && ft !== 100) {
reason = "Fill tint of " + ft + "% applied.";
}
}
}
} catch (e) {}
try {
var stroke = undefined;
try { stroke = item.strokeColor; } catch (e) { stroke = undefined; }
if (!reason && stroke && typeof stroke.name === "string" && stroke.name !== "None") {
var strokeName = stroke.name || "";
if (strokeName === "") {
reason = "Unnamed stroke colour used.";
} else if (!isAllowedSwatch(stroke)) {
reason = "Non-brand stroke colour ('" + strokeName + "') used.";
} else {
var st = undefined;
try { st = item.strokeTint; } catch (e) { st = undefined; }
if (typeof st === "number" && st !== -1 && st !== 100) {
reason = "Stroke tint of " + st + "% applied.";
}
}
}
} catch (e) {}
try {
var op = undefined;
try { op = item.opacity; } catch (e) { op = undefined; }
if (!reason && typeof op === "number" && op !== 100) {
reason = "Opacity of " + op + "% applied.";
}
} catch (e) {}
if (reason !== "") {
foundItems.push({ item: item, reason: reason });
continue;
}
// Check text characters inside TextFrames
try {
if (item.constructor && item.constructor.name === "TextFrame") {
var chars = undefined;
try { chars = item.characters; } catch (e) { chars = undefined; }
if (chars && chars.length > 0) {
for (var k = 0; k < chars.length; k++) {
try {
var myChar = chars[k];
if (!myChar) continue;
var charFill = undefined;
try { charFill = myChar.fillColor; } catch (e) { charFill = undefined; }
if (charFill && typeof charFill.name === "string" && charFill.name !== "None" && !isAllowedSwatch(charFill)) {
var cname = charFill.name || "";
foundItems.push({ item: myChar, reason: "Inconsistent character colour ('" + cname + "') used." });
break;
}
} catch (innerE) {}
}
}
}
} catch (e) {}
}
return foundItems;
}
// =============================================================================
// Navigation & Selection
// =============================================================================
function navigateThroughItems(items) {
for (var i = 0; i < items.length; i++) {
var obj = items[i].item;
var reason = items[i].reason;
if (!obj) continue;
// --- If it's a Character, select parent TextFrame ---
if (obj.constructor && obj.constructor.name === "Character") {
if (obj.parentTextFrames && obj.parentTextFrames.length > 0) {
obj = obj.parentTextFrames[0];
}
}
// --- Unlock / unhide ---
try { if (obj.locked) obj.locked = false; } catch(e) {}
try { if (obj.hidden) obj.hidden = false; } catch(e) {}
// --- Activate page ---
try { if (obj.parentPage) app.activeWindow.activePage = obj.parentPage; } catch(e) {}
// --- Select & zoom before dialog ---
try { app.select(obj); } catch(e) {}
try { app.activeWindow.zoomPercentage = 100; } catch(e) {}
// --- Show dialog after selection ---
var navDialog = new Window("dialog", "Quick Navigation");
navDialog.orientation = "column";
navDialog.alignChildren = ["fill", "top"];
navDialog.spacing = 10;
navDialog.add("statictext", undefined, "Inconsistency Found:");
navDialog.add("statictext", [0,0,420,60], reason, {multiline:true});
navDialog.add("statictext", undefined, (i + 1) + " of " + items.length);
var navButtonGroup = navDialog.add("group");
navButtonGroup.alignment = "center";
var stopButton = navButtonGroup.add("button", undefined, "Stop");
var nextButton = navButtonGroup.add("button", undefined, "Next");
stopButton.onClick = function() { navDialog.close(0); };
nextButton.onClick = function() { navDialog.close(1); };
var res = navDialog.show();
if (res === 0) break;
}
}
Copy link to clipboard
Copied
I'm looking at your post history and wondering if you're a human or a bot. The fact that some brand-new account posted your post a 100% match, at the exact same time, inclines me to believe that you're a bot - or., perhaps, a person not accustomed to running a botswarm.
Copy link to clipboard
Copied
Hi Joel,
No, I'm not a bot. I'm a human and this is my personal account to get support from experts like you on the Adobe Community. I know what you're talking about. Actually, I was working on two different browsers and mistakenly, I posted my request on the other browser. I didn't find an option to delete that post, so if anyone has permissions to delete a post, please remove it from the link.
here's the link of the mistake I have done:
https://community.adobe.com/t5/indesign-discussions/check-brand-colour-inconsistencies/m-p/15512187#...
I would appreciate, if I could get some support on my initial request.
Thanks,
Masood
Copy link to clipboard
Copied
I locked the other thread and left a trail to here - so all good no worries.
app.select(obj) isn’t always reliable, depending on the object type (characters, groups, nested items, etc.).
From my notes and what you have I think this might work
try {
app.select(NothingEnum.NOTHING); // clear previous selection
app.select(obj, SelectionOptions.REPLACE);
app.activeWindow.activePage = obj.parentPage; // ensure page is visible
} catch(e) {
$.writeln("Selection failed: " + e);
}
or you could try this
if (obj.constructor && obj.constructor.name === "Character") {
try {
app.select(NothingEnum.NOTHING);
app.select(obj, SelectionOptions.REPLACE); // highlight text
} catch(e) {}
} else {
app.select(NothingEnum.NOTHING);
app.select(obj, SelectionOptions.REPLACE);
}
Zooming I've had luck with something similar
// --- Unlock / unhide ---
try { if (obj.locked) obj.locked = false; } catch(e) {}
try { if (obj.hidden) obj.hidden = false; } catch(e) {}
// --- Activate page ---
try { if (obj.parentPage) app.activeWindow.activePage = obj.parentPage; } catch(e) {}
// --- Select & zoom before dialog ---
try {
app.select(NothingEnum.NOTHING);
app.select(obj, SelectionOptions.REPLACE);
app.activeWindow.zoom(ZoomOptions.FIT_SELECTION);
} catch(e) {
$.writeln("Selection/zoom failed: " + e);
}
I'm not the best scripter just trying to help, have a bunch of scripts and broke them into usable blocks for different uses, so it might seem cobbled together, because it is.
Copy link to clipboard
Copied
Hi Eugene,
I tried your suggestions, but didn't get the results. I think the problem is with the Screen Redraw. I found another script in my drive, and remember that I was facing the same issue with that one too. Here's the code from that script.
Please see, if this could help fix my code. I'm not a coder, but I try my hands to create stuff like this for my personal use.
PS: What if we simplify the script only to find page items like all type of frames, rectangles, the parent text frame containing an inconsistent character, rather than the character itself?
#targetengine 'customChecksAndFixes'
// Create the panel window
var myWindow = new Window('palette', "Checks & Fixes - InDesign, v10.0", undefined, { resizeable: true });
// Add a message "Please Save Your File Before Running a Script!"
var messageText = myWindow.add('statictext', undefined, "Save Your File Before Clicking a Button...");
messageText.alignment = 'center';
// messageText.graphics.font = ScriptUI.newFont("dialog", "bold", 29); // Reduced font size
// buttonFontSize = 9;
// Create a scrollable panel for buttons
var buttonPanel = myWindow.add('panel', undefined, undefined, { scrolling: true });
// var buttonPanel = myWindow.add('panel', undefined, undefined, { scrolling: true, multiselect: false });
buttonPanel.orientation = 'column';
buttonPanel.alignChildren = 'left';
buttonPanel.margins = [5, 2, 1, 2];
// buttonPanel.maximumSize.height = 500; // Limit height to enable vertical scrolling
// ************************************************ CUSTOM C H E C K S – B U T T O N S
var checkRGB = buttonPanel.add('button', undefined, 'CHECK - RGB Image(s)');
var checkResolution = buttonPanel.add('button', undefined, 'CHECK - Images Below Minimum Resolution');
// ************************************************ F U N C T I O N S
// Check if the effective resolution of an image is below 300 dpi
checkResolution.onClick = function () {
// Prompt the user for a DPI threshold
var desiredValue = parseInt(prompt("Enter the Minimum DPI Required:", "300"), 10);
// Check if the user entered a valid number
if (isNaN(desiredValue) || desiredValue <= 0) {
alert("Invalid DPI value. Please enter a positive number.");
} else {
var qualityCheck = 0;
var foundArray = [];
// Iterate through all graphics in the document
for (var i = 0; i < app.documents[0].allGraphics.length; i++) {
try {
var img = app.documents[0].allGraphics[i];
if (img.effectivePpi[0] < desiredValue || img.effectivePpi[1] < desiredValue) {
qualityCheck++;
foundArray.push(img); // Add image to the array
}
} catch (e) { }
}
if (qualityCheck === 0) {
alert("No Image(s) Found Below: " + desiredValue + " DPI");
} else {
// alert("Image(s) Found Below: " + qualityCheck);
// Navigate through the images
for (var j = 0; j < foundArray.length; j++) {
try {
app.select(foundArray[j]); // Select the image
// app.activeWindow.zoom(ZoomOptions.FIT_PAGE); // Set zoom level to fit the page
app.activeWindow.zoomPercentage = 100; // Set zoom level to 100%
// Create a custom dialog for navigation
var dialog = new Window("dialog", "Quick Navigation");
dialog.add("statictext", undefined, "Image(s) Found Below: " + desiredValue + " DPI");
dialog.add("statictext", undefined, (j + 1) + " of " + qualityCheck);
var buttonGroup = dialog.add("group");
buttonGroup.alignment = "center";
var cancelButton = buttonGroup.add("button", undefined, "Stop");
var nextButton = buttonGroup.add("button", undefined, "Next Image");
// Set button actions
nextButton.onClick = function () {
dialog.close(1); // Continue to next image
};
cancelButton.onClick = function () {
dialog.close(0); // Exit loop
};
// ************************************************ D I S C L A I M E R
var blankLine = dialog.add('statictext', undefined);
var copyrightText = dialog.add('statictext', undefined, 'ⓒ Masood Ahmad - 2024');
// copyrightText.alignment = 'center';
// Show the dialog
if (dialog.show() === 0) {
break; // Exit the loop if "Cancel" is clicked
}
} catch (e) {
alert("Unable to locate one of the image(s).");
}
}
}
}
};
// Check for RGB Image(s)
checkRGB.onClick = function () {
// Alert to ensure user is aware of image linking status
// alert("Make sure all the images are linked properly if possible, but missing links will also be checked!");
alert("Make sure all the images are Linked properly!")
var myLinks = app.documents[0].links;
var rgbCheck = 0;
var foundArray = [];
for (var i = 0; i < myLinks.length; i++) {
try {
var link = myLinks[i];
if (link.status == LinkStatus.NORMAL || link.status == LinkStatus.LINK_MISSING) {
var image = link.parent;
if (image.space == "RGB") {
// alert("RGB image(s) Found. Please Convert to CMYK!");
rgbCheck++;
foundArray.push(image); // Add image to the array
// break;
}
}
} catch (e) { }
}
if (rgbCheck === 0) {
alert("RGB Image(s) Not-Found!");
} else {
// alert("RGB image(s) Found: " + rgbCheck + "\n Convert to CMYK!");
// Navigate through the images
for (var j = 0; j < foundArray.length; j++) {
try {
app.select(foundArray[j]); // Select the image
// app.activeWindow.zoom(ZoomOptions.FIT_PAGE); // Set zoom level to fit the page
app.activeWindow.zoomPercentage = 100; // Set zoom level to 100%
// Create a custom dialog for navigation
var dialog = new Window("dialog", "Quick Navigation");
dialog.add("statictext", undefined, "RGB image(s) Found. Convert to CMYK");
dialog.add("statictext", undefined, (j + 1) + " of " + rgbCheck);
var buttonGroup = dialog.add("group");
buttonGroup.alignment = "center";
var cancelButton = buttonGroup.add("button", undefined, "Stop");
var nextButton = buttonGroup.add("button", undefined, "Next Image");
// Set button actions
nextButton.onClick = function () {
dialog.close(1); // Continue to next image
};
cancelButton.onClick = function () {
dialog.close(0); // Exit loop
};
// ************************************************ D I S C L A I M E R
var blankLine = dialog.add('statictext', undefined);
var copyrightText = dialog.add('statictext', undefined, 'ⓒ Masood Ahmad - 2024');
// copyrightText.alignment = 'center';
// Show the dialog
if (dialog.show() === 0) {
break; // Exit the loop if "Cancel" is clicked
}
} catch (e) {
alert("Unable to locate one of the image(s).");
}
}
}
};
// Show the panel
myWindow.show();
Copy link to clipboard
Copied
Let me know how this goes - hopefully something here either works directly for you or gives you a clue somewhere...
In your navigateThroughItems(items) loop, replace the selection/zoom block with:
// --- Unlock / unhide ---
try { if (obj.locked) obj.locked = false; } catch(e) {}
try { if (obj.hidden) obj.hidden = false; } catch(e) {}
// --- If it's a Character, use its parent TextFrame ---
if (obj.constructor && obj.constructor.name === "Character") {
try {
if (obj.parentTextFrames && obj.parentTextFrames.length > 0) {
obj = obj.parentTextFrames[0];
}
} catch(e) {}
}
// --- Activate page ---
try { if (obj.parentPage) app.activeWindow.activePage = obj.parentPage; } catch(e) {}
// --- Select & zoom ---
try {
app.select(NothingEnum.NOTHING);
app.select(obj, SelectionOptions.REPLACE);
// Force screen redraw
app.activeWindow.zoom(ZoomOptions.FIT_SELECTION);
// OR: app.activeWindow.zoomPercentage = app.activeWindow.zoomPercentage;
app.redraw();
} catch(e) {
$.writeln("Selection/zoom failed: " + e);
}
If you want only frames/rectangles/text frames (ignoring characters directly)
Change your findInconsistentItems() so that whenever you detect an inconsistent Character, you push its parent frame instead:
if (myChar.parentTextFrames && myChar.parentTextFrames.length > 0) {
foundItems.push({ item: myChar.parentTextFrames[0], reason: "Inconsistent character colour ('" + cname + "') used." });
}
What I'm trying to.... hmmm I'm not sure ha ha
Trying the “parent frame” approach and use zoom(FIT_SELECTION) to guarantee the object comes into view.
So something else comes to mind too
// ==================================
// Navigation & Selection (rewritten)
// ==================================
function navigateThroughItems(items) {
for (var i = 0; i < items.length; i++) {
var obj = items[i].item;
var reason = items[i].reason;
if (!obj) continue;
// --- If it's a Character, select the parent TextFrame ---
if (obj.constructor && obj.constructor.name === "Character") {
try {
if (obj.parentTextFrames && obj.parentTextFrames.length > 0) {
obj = obj.parentTextFrames[0];
}
} catch (e) {}
}
// --- Unlock / unhide if needed ---
try { if (obj.locked) obj.locked = false; } catch (e) {}
try { if (obj.hidden) obj.hidden = false; } catch (e) {}
// --- Activate page containing the object ---
try { if (obj.parentPage) app.activeWindow.activePage = obj.parentPage; } catch (e) {}
// --- Select & zoom to object ---
try {
app.select(NothingEnum.NOTHING); // clear selection
app.select(obj, SelectionOptions.REPLACE); // select the object
app.activeWindow.zoom(ZoomOptions.FIT_SELECTION); // zoom to fit
app.redraw(); // force screen refresh
} catch (e) {
$.writeln("Selection/zoom failed: " + e);
}
// --- Show navigation dialog ---
var navDialog = new Window("dialog", "Quick Navigation");
navDialog.orientation = "column";
navDialog.alignChildren = ["fill", "top"];
navDialog.spacing = 10;
navDialog.add("statictext", undefined, "Inconsistency Found:");
navDialog.add("statictext", [0,0,420,60], reason, { multiline:true });
navDialog.add("statictext", undefined, (i + 1) + " of " + items.length);
var navButtonGroup = navDialog.add("group");
navButtonGroup.alignment = "center";
var stopButton = navButtonGroup.add("button", undefined, "Stop");
var nextButton = navButtonGroup.add("button", undefined, "Next");
stopButton.onClick = function() { navDialog.close(0); };
nextButton.onClick = function() { navDialog.close(1); };
var res = navDialog.show();
if (res === 0) break; // Stop button clicked, exit loop
}
}
Copy link to clipboard
Copied
Hi @code_seeeeeker , Unless I’m misunderstanding the problem, it seems like an easier approach would be to delete the non brand swatches and when you are prompted for a replacment choose a brand color. It’s easy to do that via the UI and you should be able to do it via a script also— the swatch object has a remove() method which has a replaceWith parameter.
Trash the swatch named Non Brand Blue and replace with Brand 1:
Repeat for other non brand swatches:
Copy link to clipboard
Copied
Thanks, @rob day, I am awar of this and several other tricks, but sometimes I cannot delete the unused swatches as they are needed later. Second, the process is time-taking, so, I'm trying some magic with a script.
Hi, @Eugene Tyson , thanks for sharing the revised code, but it still not working.
Copy link to clipboard
Copied
What happens
Copy link to clipboard
Copied
Nothing!
just on hold, trying to take a different approach.
THINKING...................
Find more inspiration, events, and resources on the new Adobe Community
Explore Now