Sort Pages

Script for Adobe InDesign

The script sorts document pages based on text on each page assigned a selected paragraph or character style.

  • Select paragraph or character style to find
  • Pages are sorted by text assigned the style
  • Adapt open source to customize or create other scripts
Download
Sort Pages
Help me keep making new scripts by supporting my work. Click the PayPal button to contribute any amount you choose. Thank you. William Campbell

How to use the script

The interface is a single section Sort pages by. Select the desired paragraph or character style then click the OK button to begin. The pages are sorted based on the first instance of text on each page assigned the selected style. Any pages lacking text assigned the selected style are ignored.

Source code

(download button below)

/*

Sort Pages
Copyright 2024 William Campbell
All Rights Reserved
https://www.marspremedia.com/contact

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.

*/

(function () {

    var title = "Sort Pages";

    if (!/indesign/i.test(app.name)) {
        alert("Script for InDesign", title, false);
        return;
    }

    // Script variables.
    var characterStyleNames;
    var doc;
    var doneMessage;
    var error;
    var paragraphStyleNames;
    var working;

    // Reusable UI variables.
    var g; // group
    var gc1; // group (column)
    var gc2; // group (column)
    var p; // panel
    var w; // window

    // Permanent UI variables.
    var btnCancel;
    var btnOk;
    var listCharacterStyle;
    var listParagraphStyle;
    var rbCharacterStyle;
    var rbParagraphStyle;

    // LANGUAGE EXTENSIONS

    // SETUP

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

    // Load styles.
    characterStyleNames = getStyleNames(doc.allCharacterStyles);
    paragraphStyleNames = getStyleNames(doc.allParagraphStyles);

    // CREATE WORKING WINDOW

    working = new Window("palette", undefined, undefined, {
        closeButton: false
    });
    working.preferredSize = [300, 80];
    working.add("statictext");
    working.t = working.add("statictext");
    working.add("statictext");
    working.display = function (message) {
        this.t.text = message || "Working... Please wait...";
        this.show();
        this.update();
    };

    // CREATE USER INTERFACE

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

    // Panel 'Sort by'
    p = w.add("panel", undefined, "Sort pages by");
    p.alignChildren = "left";
    p.margins = [24, 24, 24, 18];
    // Group of 2 columns.
    g = p.add("group");
    // Groups, columns 1 and 2.
    gc1 = g.add("group");
    gc1.orientation = "column";
    gc1.alignChildren = "left";
    gc2 = g.add("group");
    gc2.margins = [0, 3, 0, 14];
    gc2.orientation = "column";
    gc2.alignChildren = "left";
    // Rows.
    rbParagraphStyle = gc1.add("radiobutton", undefined, "Paragraph style:");
    rbParagraphStyle.preferredSize.height = 25;
    listParagraphStyle = gc2.add("dropdownlist", undefined, paragraphStyleNames);
    listParagraphStyle.preferredSize = [150, 25];
    // Add empty items so list is minimum two items.
    listParagraphStyle.add("item", " ");
    listParagraphStyle.add("item", " ");
    rbCharacterStyle = gc1.add("radiobutton", undefined, "Character style:");
    rbCharacterStyle.preferredSize.height = 25;
    listCharacterStyle = gc2.add("dropdownlist", undefined, characterStyleNames);
    listCharacterStyle.preferredSize = [150, 25];
    // Add empty items so list is minimum two items.
    listCharacterStyle.add("item", " ");
    listCharacterStyle.add("item", " ");

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

    // Panel Copyright
    p = w.add("panel");
    p.add("statictext", undefined, "Copyright 2024 William Campbell");

    // SET UI VALUES

    rbParagraphStyle.value = true;
    configureUi();

    // UI ELEMENT EVENT HANDLERS

    rbParagraphStyle.onClick = function () {
        rbCharacterStyle.value = false;
        configureUi();
    };
    listParagraphStyle.onChange = function () {
        if (this.selection.text === " ") {
            this.selection = null;
        }
    };
    rbCharacterStyle.onClick = function () {
        rbParagraphStyle.value = false;
        configureUi();
    };
    listCharacterStyle.onChange = function () {
        if (this.selection.text === " ") {
            this.selection = null;
        }
    };

    // Action Buttons
    btnOk.onClick = function () {
        if (rbParagraphStyle.value && !listParagraphStyle.selection) {
            alert("Select a paragraph style", " ", false);
            return;
        }
        if (rbCharacterStyle.value && !listCharacterStyle.selection) {
            alert("Select a character style", " ", false);
            return;
        }
        w.close(1);
    };
    btnCancel.onClick = function () {
        w.close(0);
    };

    // DISPLAY THE DIALOG

    if (w.show() == 1) {
        doneMessage = "";
        try {
            app.doScript(process, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, title);
            doneMessage = doneMessage || "Done";
        } catch (e) {
            error = error || e;
            doneMessage = "An error has occurred.\nLine " + error.line + ": " + error.message;
        }
        working.close();
        doneMessage && alert(doneMessage, title, error);
    }

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

    function configureUi() {
        listCharacterStyle.enabled = rbCharacterStyle.value;
        listParagraphStyle.enabled = rbParagraphStyle.value;
    }

    function getStyleNames(o) {
        var a = [];
        var i;
        var name;
        for (i = 0; i < o.length; i++) {
            name = o[i].name;
            // Ignore names that begin with bracket.
            if (/^\[/.test(name)) continue;
            a.push(name);
        }
        a.sort(function (a, b) {
            // Case insensitive.
            var aLow = a.toLowerCase();
            var bLow = b.toLowerCase();
            if (aLow < bLow) return -1;
            if (aLow > bLow) return 1;
            return 0;
        });
        return a;
    }

    function itemByName(o, name) {
        var i;
        for (i = 0; i < o.length; i++) {
            if (name == o[i].name) {
                return o[i];
            }
        }
        return null;
    }

    function process() {
        var i;
        var page;
        var pages;
        var style;
        var text;
        // Preserve preferences.
        var preserve = {
            findChangeTextOptions: app.findChangeTextOptions.properties,
            findTextPreferences: app.findTextPreferences.properties
        };
        // Set find change text options.
        app.findChangeTextOptions.includeFootnotes = false;
        app.findChangeTextOptions.includeHiddenLayers = true;
        app.findChangeTextOptions.includeLockedLayersForFind = true;
        app.findChangeTextOptions.includeLockedStoriesForFind = true;
        app.findChangeTextOptions.includeMasterPages = false;
        // Get style to find.
        if (rbParagraphStyle.value) {
            style = itemByName(doc.allParagraphStyles, listParagraphStyle.selection.text);
        } else {
            style = itemByName(doc.allCharacterStyles, listCharacterStyle.selection.text);
        }
        working.display();
        try {
            pages = [];
            for (i = 0; i < doc.pages.length; i++) {
                page = doc.pages[i];
                text = textAssignedStyle(page, style);
                if (text) {
                    pages.push({
                        id: page.id,
                        text: text
                    });
                }
            }
            if (pages.length == 0) {
                doneMessage = "Did not find text matching style";
                return;
            }
            // Sort pages array.
            pages.sort(function (a, b) {
                // Case insensitive.
                var aLow = a.text.toLowerCase();
                var bLow = b.text.toLowerCase();
                if (aLow < bLow) return -1;
                if (aLow > bLow) return 1;
                return 0;
            });
            // Sort document pages.
            for (i = 0; i < pages.length; i++) {
                page = doc.pages.itemByID(pages[i].id);
                page.move(LocationOptions.AT_END);
            }
        } catch (e) {
            error = e;
            throw e;
        } finally {
            // Restore preferences.
            app.findChangeTextOptions.properties = preserve.findChangeTextOptions;
            app.findTextPreferences.properties = preserve.findTextPreferences;
        }
    }

    function textAssignedStyle(page, style) {
        var i;
        var matches;
        var textFrames;
        textFrames = page.textFrames;
        app.findTextPreferences = NothingEnum.nothing;
        app.findTextPreferences.findWhat = "";
        if (rbParagraphStyle.value) {
            app.findTextPreferences.appliedParagraphStyle = style;
        } else {
            app.findTextPreferences.appliedCharacterStyle = style;
        }
        for (i = 0; i < textFrames.length; i++) {
            if (textFrames[i].contents.length) {
                matches = textFrames[i].findText();
                if (matches[0]) {
                    return matches[0].contents;
                }
            }
        }
        // Didn't find text assigned the style.
        return null;
    }

})();
Help me keep making new scripts by supporting my work. Click the PayPal button to contribute any amount you choose. Thank you. William Campbell
Download
Sort Pages

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

IMPORTANT: scripts are developed for the latest Adobe Creative Cloud applications. Many scripts work in CC 2018 and later, even some as far back as CS6, but may not perform as expected, or run at all, when used in versions prior to 2018. Photoshop features Select Subject and Preserve Details 2.0 definitely fail prior to CC 2018 (version 19) as the features do not exist in earlier versions. For best results use the latest versions of Adobe Creative Cloud applications.

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

IMPORTANT: fees paid for software products are the purchase of a non-exclusive license to use the software product and do not grant the purchaser any degree of ownership of the software code. Author of the intellectual property and copyright holder William Campbell retains 100% ownership of all code used in all software products regardless of the inspiration for the software product design or functionality.