Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Script check each page

Community Expert ,
Oct 30, 2025 Oct 30, 2025

I'm working on a script to compare the text on a page with the filename of a specific layer. Here's the issue I'm running into:

  • For example, I have a text frame on a layer named Code.

  • The script can find it if it's present on Page 1 or Page 2—that part works fine.

  • However, it doesn't report when the text frame is missing from Page 1 or Page 2.

It seems to handle Parent Pages correctly. For instance, if the Code layer contains the text in the same position on each page via the Parent Page, the script detects it and doesn’t need to take any action.

The problem arises when the text frame is not on parent pages. For example:

  • On Page 1, the text frame is in the top right.

  • On Page 2, it’s in the bottom left.


Then it's detecting text on the layer, so it stops as it's found. 
So page 1 might have the text for the code
and page 2 doesn't have text for the code - but the script is not finding it. 

Does this make sense?

TOPICS
Scripting
192
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2025 Oct 30, 2025

Hi @Eugene Tyson , Could you post a sample doc with the text frames and layers?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2025 Oct 30, 2025

Sure 

 

1. Trying to check the parent page for a text variable or text that matches the filename

2. Trying to check the page 1 for a variable, or for text matches the filename
3. When on page 1 and not page 2 (or vice versa) it doesn't recognise as it finds it on one of the pages

Something like the attached. 

For example, the text variable isn't always on the parent page. But it picks up the filename. 

So I'm trying to catch on all pages where the code is not the filename either by text or by text variable. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2025 Oct 30, 2025

This is as far as I got with the code - when i got into trouble I tried flushing it through ChatGPT and Gemini - but neither could resolve the issue or figure out why it's not working. 

This is literally where I have left off. 

#targetengine "textVariableCheckEngine"

(function () {
    var enableEventListener = false; // Set true later if you want automatic check on save

    if (enableEventListener) {
        var handlerAlreadyAdded = true;
        for (var i = 0; i < app.eventListeners.length; i++) {
            if (app.eventListeners[i].name === "textVariableCheckHandler") {
                handlerAlreadyAdded = true;
                break;
            }
        }
        if (!handlerAlreadyAdded) {
            var el = app.addEventListener("beforeSave", textVariableCheck, false);
            el.name = "textVariableCheckHandler";
        }
    }

    textVariableCheck(); // Run immediately for manual test

    function textVariableCheck() {
        try {
            if (app.documents.length === 0) return;

            var doc = app.activeDocument;
            var usedVariables = [];

            // --- Scan pages and master spreads ---
            function scanContainer(container) {
                for (var p = 0; p < container.length; p++) {
                    var page = container[p];
                    var pageItems = page.allPageItems;
                    for (var i = 0; i < pageItems.length; i++) {
                        var item = pageItems[i];
                        if (item.hasOwnProperty("textVariableInstances")) {
                            var instances = item.textVariableInstances;
                            for (var j = 0; j < instances.length; j++) {
                                var v = instances[j];
                                if (v && v.associatedTextVariable && v.associatedTextVariable.name != null) {
                                    var nameStr = String(v.associatedTextVariable.name);
                                    // Classic loop duplicate check
                                    var alreadyAdded = false;
                                    for (var k = 0; k < usedVariables.length; k++) {
                                        if (usedVariables[k] === nameStr) {
                                            alreadyAdded = true;
                                            break;
                                        }
                                    }
                                    if (!alreadyAdded) usedVariables.push(nameStr);
                                }
                            }
                        }
                    }
                }
            }

            scanContainer(doc.pages);
            scanContainer(doc.masterSpreads);

            if (usedVariables.length === 0) {
                alert("⚠ No text variables found in pages or master pages.");
            }

            // --- Code Layer check ---
            var fileName = doc.name.replace(/\.[^\.]+$/, "");
            var techMismatch = false;
            var techFound = false;

            for (var t = 0; t < doc.textFrames.length; t++) {
                var tf = doc.textFrames[t];
                if (tf.itemLayer && /Code/i.test(tf.itemLayer.name)) {
                    techFound = true;

                    // Ignore frames that have text variables
                    if (tf.textVariableInstances.length > 0) continue;

                    // Clean content for comparison
                    var content = String(tf.contents)
                        .replace(/[\s\u00A0\u200B-\u200D\uFEFF]/g, "")
                        .replace(/[^\x20-\x7E]/g, "")
                        .toLowerCase();
                    var cleanFile = String(fileName)
                        .replace(/[\s\u00A0\u200B-\u200D\uFEFF]/g, "")
                        .replace(/[^\x20-\x7E]/g, "")
                        .toLowerCase();

                    if (content.indexOf(cleanFile) === -1) {
                        techMismatch = true;
                        break;
                    }
                }
            }

            if (!techFound) {
                alert("⚠ No text found on the Code layer.");
            } else if (techMismatch) {
                alert("⚠ Code layer text does NOT match the filename: " + fileName);
            }

            // Silent if all is okay

        } catch (e) {
            alert("Error in textVariableCheck: " + e);
        }
    }
})();

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2025 Oct 30, 2025

I think you need to get the stories parentTextFrames, which is an array of textFrames containing the story.

 

Here I have some text or an insertionpoint  selected:

 

var sel = app.documents[0].selection[0].parent
var fa = sel.texts[0].parentTextFrames;
var l = makeLayer(app.activeDocument, "Code")

$.writeln(sel+ "  "+fa)
//sel is the selected text’s story
//fa are all of the stories TextFrames

for (var i = 0; i < fa.length; i++){
    fa[i].itemLayer = l
    $.writeln(fa[i].itemLayer.name)
};   


/**
* Makes a new named Layer or return a layer with n name
* @ param the document to add the layer 
* @ param layer name 
* @ param layer color 
* @ return the new layer 
*/
function makeLayer(d, n){
    if (d.layers.itemByName(n).isValid) {
        return d.layers.itemByName(n);
    } else {
        return d.layers.add({name:n});
    }
}

 

Before and after

 

Screen Shot 3.png

 

 

 

Screen Shot 4.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2025 Oct 30, 2025

It's kinda working - it reads the text frame and says it has the variable data in it - but when I remove the text and input garbage text it says it's still variable data

I still can't work out the logic to only flag an alert if it's not an all pages so it's fine if it's on the parent page and that it shows on all pages 

But would need to know if it's not on all pages (if absent from parent page), or if the text is manually typed in (not variable data). 

Practically, it should just flag if the Code layer is missing text frame containing either a text variable or text that matches the filename. 

 

But I'm not sure it can read the text on pages where it's applied via the parent page. Probably way overthinking it.


My head hurts.

#targetengine "textVariableCheckEngine"
code
(function() {

    var TECH_LAYER_REGEX = /technical|codes|code/i;

    // --- Normalize string for comparison ---
    function normalizeSafe(input) {
        try { return String(input).replace(/[^a-z0-9]/gi, "").toLowerCase().trim(); }
        catch (e) { return ""; }
    }

    // --- Safely extract variable text only if it exists ---
    function extractVariableText(tvi) {
        if (!tvi) return "";
        try {
            if (tvi.resultText && tvi.resultText.contents) {
                var text = String(tvi.resultText.contents);
                if (normalizeSafe(text).length > 0) return text;
            }
        } catch(e){}
        return "";
    }

    // --- Get all text from a frame: contents + valid text variables ---
    function getFrameText(frame) {
        var txt = "";
        try { if (frame.contents) txt += frame.contents; } catch(e){}
        try {
            if (frame.textVariableInstances && frame.textVariableInstances.length > 0) {
                for (var i=0;i<frame.textVariableInstances.length;i++){
                    txt += extractVariableText(frame.textVariableInstances[i]);
                }
            }
        } catch(e){}
        return normalizeSafe(txt);
    }

    // --- No open document ---
    if (app.documents.length === 0) { alert("No open document"); return; }

    var doc = app.activeDocument;
    var fileToken = normalizeSafe(doc.name.replace(/\.[^\.]+$/, ""));
    var masterHasToken = {};

    // --- Check parent/master spreads ---
    for (var m=0; m<doc.masterSpreads.length; m++){
        var master = doc.masterSpreads[m];
        var frames = [];
        try { frames = master.pageItems.everyItem().getElements(); } catch(e){}
        var found = false;
        for (var f=0; f<frames.length; f++){
            var frame = frames[f];
            try {
                if (frame.constructor.name !== "TextFrame") continue;
                if (!frame.itemLayer || !TECH_LAYER_REGEX.test(frame.itemLayer.name)) continue;
                var text = normalizeSafe(frame.contents);
                var variableText = getFrameText(frame);
                if (text.indexOf(fileToken) !== -1 || variableText.indexOf(fileToken) !== -1){
                    found = true;
                    break;
                }
            } catch(e){ continue; }
        }
        masterHasToken[master.name] = found;
    }

    // --- Check document pages ---
    var missingPages = [];
    for (var p=0; p<doc.pages.length; p++){
        var page = doc.pages[p];
        var pageFound = false;

        // 1) Check if applied master already contains token
        try {
            if (page.appliedMaster && page.appliedMaster.isValid){
                if (masterHasToken[page.appliedMaster.name]) pageFound = true;
            }
        } catch(e){}

        // 2) Check frames on the page
        if (!pageFound){
            var frames = [];
            try { frames = page.pageItems.everyItem().getElements(); } catch(e){}
            for (var f=0; f<frames.length; f++){
                var frame = frames[f];
                try {
                    if (frame.constructor.name !== "TextFrame") continue;
                    if (!frame.itemLayer || !TECH_LAYER_REGEX.test(frame.itemLayer.name)) continue;
                    var text = normalizeSafe(frame.contents);
                    var variableText = getFrameText(frame);
                    if (text.indexOf(fileToken) !== -1 || variableText.indexOf(fileToken) !== -1){
                        pageFound = true;
                        break;
                    }
                } catch(e){ continue; }
            }
        }

        if (!pageFound) missingPages.push(page.name);
    }

    // --- Output ---
    var masterWarning = "";
    var anyMasterHas = false;
    for (var key in masterHasToken) {
        if (masterHasToken.hasOwnProperty(key) && masterHasToken[key]) {
            anyMasterHas = true;
            break;
        }
    }
    if (!anyMasterHas) masterWarning = "WARNING: No parent/master spread contains filename/variable on Technical layer.\n\n";

    if (missingPages.length === 0) {
        alert(masterWarning + "All pages contain filename/variable on Technical layer.\nFilename: " + doc.name);
    } else {
        alert(masterWarning + "⚠ Filename/variable missing on Technical layer for pages:\n" +
              missingPages.join(", ") + "\nExpected: " + doc.name);
    }

})();



Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2025 Oct 30, 2025

Sorry, I read too fast and missed the text varible condition.

 

This gets the document’s allPageItems array and checks for textVariables—if there’s 1 or more, moves the frame to the Code layer. This should also get textFrames with textVariables on parent pages:

 

var d = app.documents[0]
//all of the document’s page items as an array—includes items inside of groups ect.
var api = d.allPageItems;
//the layer named "Code"
var l = makeLayer(app.activeDocument, "Code")


for (var i = 0; i < api.length; i++){
    //get all textFrames with textVariableInstances
    if (api[i].constructor.name == "TextFrame" && api[i].textVariableInstances.length > 0) {
        //if the frame includes a textVariable, set its Layer to Code
        api[i].itemLayer = l
    } 
};   


/**
* Makes a new named Layer or return a layer with n name
* @ param the document to add the layer 
* @ param layer name 
* @ param layer color 
* @ return the new layer 
*/
function makeLayer(d, n){
    if (d.layers.itemByName(n).isValid) {
        return d.layers.itemByName(n);
    } else {
        return d.layers.add({name:n});
    }
} 
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2025 Oct 30, 2025

My apologies if I wasn't clear. I don't need to make a layer or move items onto a layer - although it's not a bad idea... 

Many thanks for helping out with the script it is giving me some ideas to try. 

 

I just want to check that there's a text frame on that layer on each page - parent page or not. 
The text frame either has to have the Text Variable or the text equal to the file name. 

 

If it's on the Parent Page it's fine don't need an alert

----------------------->unless it's not a text variable or the text in it doesn't match the file name. 

If it's on Page 1 - same criteria as above

--------->and subsequent pages.

 

But I think I can try something with this. 

The layer move is a good idea, sometimes the Code is not on the right layer. This makes sense to check that it's on the right layer and move it if it's not.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 31, 2025 Oct 31, 2025

This is a case where allPageItems, which is an array vs. pageItems, which is a collection is useful. The d.allPageItems variable gets all the document’s page items—items on masterpages, inside of groups, etc. The array could be quite large, so you have to consider whether it would have a noticeable performance hit, but it’s easy to get.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 31, 2025 Oct 31, 2025
LATEST

I'll have to think about it some more. 

 

Had different head hurt day with different problem today than yesterday.

Time for the weekend anyway - thanks for the help and tips.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines