Links GREP Relink

JavaScript for Adobe InDesign

Use GREP (regular expressions) to match file names of existing links, change to new file names, then search a specified folder and relink each replacement file name found.

To rename links, use the script Links GREP Rename.

  • Replace links using GREP pattern replacement
  • Option to ignore letter case
  • Specify folder to search for links
  • Adapt open source to create other scripts
Links GREP Relink screen
Download
Links GREP Relink

You decide. Reward the author an
amount the solution is worth to you.

How-to Video

How to use the script

The interface has two sections: Link file name and Search for links in folder. Set the GREP pattern and replacement, choose the Links folder, then click the OK button to begin. A progress bar is displayed as links are processed.

Section 1: Link file name

Find what — the GREP pattern to match. Works the same as when using the InDesign Find/Change dialog. For each link in the document, the full file name, including extension, is tested against the pattern. By including extension, GREP patterns may change the file type to which a graphic is linked. This could be desired behavior, or possibly not. Just be aware that patterns are tested against the full file name including extension.

Change to — the GREP replacement to use when the pattern above is matched. Works the same as when using the InDesign Find/Change dialog. For each link that matches the find pattern, a new file name is computed using the change value, the script searches the specified Links folder for a file that matches, and then the file is relinked.

Ignore case — adds the “i” switch to the regular expression, making it case-insensivive.

Section 2: Search for links in folder

Click the Folder... button to select the folder where replacement links are located. Note this path defaults to the current location of the document’s links by examining the first link for its current path, and assumes the rest are in the same folder. Click the button to choose any other location.

Source code

(download button below)

/*

Links GREP Relink
Copyright 2021 William Campbell
All Rights Reserved
https://www.marspremedia.com/contact

Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

*/

//@target indesign

(function () {

    var title = "Links GREP Relink";

    var doc; // Document
    var error; // Error
    var folderLinks; // Folder

    // Reusable UI variables.
    var g1; // group
    var g2; // group
    var p; // panel
    var w; // window

    // Permanent UI variables.
    // Prefixes:
    //   btn  = "button"
    //   cb   = "checkbox"
    //   txt  = "statictext"
    //   inp  = "edittext"
    //   list = "dropdownlist"
    //   rb   = "radiobutton"
    var btnCancel;
    var btnFolderLinks;
    var btnOk;
    var cbIgnoreCase;
    var inpChange;
    var inpFind;
    var txtFolderLinks;

    // SETUP

    // Check for valid doc.
    if (!app.documents.length) {
        alert("Open a document.", title, false);
        return;
    }
    doc = app.activeDocument;

    // CREATE USER INTERFACE

    w = new Window("dialog", title);
    w.alignChildren = "fill";

    // Search/Replace.
    p = w.add("panel", undefined, "Link file name");
    p.alignChildren = "left";
    p.margins = [24, 24, 24, 18];
    p.spacing = 24;

    g1 = p.add("group");
    g2 = g1.add("group");
    g2.alignChildren = "left";
    g2.orientation = "column";
    // Preferred size set on next two to match height of inputs in next column.
    g2.add("statictext", undefined, "Find what:").preferredSize = [-1, 23];
    g2.add("statictext", undefined, "Change to:").preferredSize = [-1, 23];
    g2 = g1.add("group");
    g2.alignChildren = "left";
    g2.orientation = "column";
    inpFind = g2.add("edittext");
    inpFind.characters = 38;
    inpChange = g2.add("edittext");
    inpChange.characters = 38;

    cbIgnoreCase = p.add("checkbox", undefined, "Ignore case");

    p = w.add("panel", undefined, "Search for links in folder");
    p.alignChildren = "left";
    p.margins = [24, 24, 24, 18];
    p.spacing = 24;
    g1 = p.add("group");
    btnFolderLinks = g1.add("button", undefined, "Folder...");
    txtFolderLinks = g1.add("statictext", undefined, "", {
        truncate: "middle"
    });
    txtFolderLinks.characters = 40;

    // Action Buttons
    g1 = w.add("group");
    g1.alignment = "center";
    btnOk = g1.add("button", undefined, "OK");
    btnCancel = g1.add("button", undefined, "Cancel");

    // SET DEFAULT VALUES

    // Links folder set to location of first document link (if any).
    if (doc.links.length) {
        txtFolderLinks.text = Folder.decode(new File(doc.links[0].filePath).path);
        folderLinks = new Folder(txtFolderLinks.text);
    }

    // UI ELEMENT EVENT HANDLERS

    btnFolderLinks.onClick = function () {
        var f = Folder.selectDialog("Select Links folder", txtFolderLinks.text);
        if (f) {
            folderLinks = f;
            txtFolderLinks.text = Folder.decode(folderLinks.fsName);
        }
    };

    btnOk.onClick = function () {
        if (!inpFind.text) {
            alert("Enter a value for 'Find what'");
            return;
        }
        if (!folderLinks.exists) {
            alert("Select Links folder", " ", false);
            return;
        }
        w.close(1);
    };

    btnCancel.onClick = function () {
        w.close(0);
    };

    // DISPLAY THE DIALOG

    if (w.show() == 1) {
        try {
            app.doScript(process, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, title);
            alert("Processing complete.", title, false);
        } catch (_) {
            alert("An error has occurred.\nLine " + error.line + ": " + error.message, title, true);
        }
    }

    //====================================================================
    //               END PROGRAM EXECUTION, BEGIN FUNCTIONS
    //====================================================================

    function process() {
        var file;
        var i;
        var link;
        var name;
        var newName;
        var pattern;

        try {
            pattern = new RegExp(inpFind.text, "g" + (cbIgnoreCase.value ? "i" : ""));
            progress(doc.links.length);
            for (i = 0; i < doc.links.length; i++) {
                link = doc.links[i];
                name = link.name;
                if (inpFind.text) {
                    newName = name.replace(pattern, inpChange.text);
                    progress.message(name + " -> " + newName);
                    file = new File(folderLinks.fsName + "/" + newName);
                } else {
                    // 'Find what' is empty.
                    // Relink same name in specified folder.
                    progress.message(name);
                    file = new File(folderLinks.fsName + "/" + name);
                }
                if (file.exists) {
                    link.relink(file);
                    link.update();
                }
                progress.increment();
            }
        } catch (e) {
            error = e;
            throw e;
        } finally {
            progress.close();
        }
    }

    function progress(steps) {
        var b;
        var t;
        var w;
        w = new Window("palette", "Progress", undefined, {
            closeButton: false
        });
        t = w.add("statictext");
        t.preferredSize = [450, -1]; // 450 pixels wide, default height.
        if (steps) {
            b = w.add("progressbar", undefined, 0, steps);
            b.preferredSize = [450, -1]; // 450 pixels wide, default height.
        }
        progress.close = function () {
            w.close();
        };
        progress.increment = function () {
            b.value++;
        };
        progress.message = function (message) {
            t.text = message;
            w.update();
        };
        w.show();
    }

})();
Download
Links GREP Relink

License details included in download

For help installing scripts, see How to Install and Use Scripts in Adobe Creative Cloud Applications.

IMPORTANT: by downloading the script you agree that the software is provided without any warranty, express or implied. USE AT YOUR OWN RISK. Always make backups of important data.