Search code examples
javascriptadobe-indesign

How to autofit table rows to text box height after deleting a row in InDesign


Is there a way to autofit an InDesign table to the size of the text box bounding frame by adjusting row height and/or column width? I am using the script below to delete empty rows from tables, but after deleting the row, the table no longer fills the space it is designed for.

Any suggestions or resources that may be helpful would be very much appreciated!

Thank you!

var rows = app.activeDocument.textFrames.everyItem().tables.everyItem().rows.everyItem().getElements()
for (var i = rows.length - 1; i >= 0; i--) {
    if (rows[i].cells.everyItem().contents.toString().replace(/,/g, "") == "")
        rows[i].remove()
}

var columns = app.activeDocument.textFrames.everyItem().tables.everyItem().columns.everyItem().getElements()
for (var i = columns.length - 1; i >= 0; i--) {
    if (columns[i].cells.everyItem().contents.toString().replace(/,/g, "") == "")
        columns[i].remove()
}

Solution

  • Here is the simple solution:

    try { var cells = app.selection[0].cells } catch(e) { exit() }
    
    app.doScript(main, ScriptLanguage.JAVASCRIPT, [], UndoModes.ENTIRE_SCRIPT, 'Fit table')
    
    function main() {
    
        // change the units to Points
        var old_h_units = app.activeDocument.viewPreferences.horizontalMeasurementUnits;
        app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS
        var old_v_units = app.activeDocument.viewPreferences.verticalMeasurementUnits;
        app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS
    
        var first_cell = cells.firstItem().texts[0];
        var last_cell = cells.lastItem().texts[0];
        var id = first_cell.parentTextFrames[0].id;
    
        // change heights
        while (last_cell.parentTextFrames.length > 0
            && last_cell.parentTextFrames[0].id == id) {
            change_heights(cells, +.1);
        }
        change_heights(cells, -.1); // one step back
    
        // change widths
        var row = cells[0].parentRow;
        var borders = row.rightEdgeStrokeWeight/2 + row.leftEdgeStrokeWeight/2;
        var frame_width = get_width(first_cell.parentTextFrames[0]) - borders;
        while (cells[0].parentRow.width < frame_width) {
            change_widths(cells, +.1);
        }
    
        // restore the old units
        app.activeDocument.viewPreferences.horizontalMeasurementUnits = old_h_units;
        app.activeDocument.viewPreferences.verticalMeasurementUnits = old_v_units;
    
    }
    
    // functions ------------------------------------------------------------------
    
    function change_heights(cells, value) {
        for (var i=0; i<cells.length; i++) cells[i].height += value;
    }
    
    function change_widths(cells, value) {
        for (var i=0; i<cells.length; i++) cells[i].width += value;
    }
    
    function get_width(obj) {
        return obj.geometricBounds[3] - obj.geometricBounds[1];
    }
    

    Select the cells you want to resize and run the script. It increases height and width of the selected cells until the cells are fit in the parent text frame.

    enter image description here

    But it suggests to run the script manually for every problem table. If you mean to change all the tables in the document at once automatically there should be more complicated solution. Let me know if you need it. And it wouldn't hurt if you provide a sample of your document with the tables — there can be details that affect the algorithm.


    Update

    Here is the 'full-automatic' variant of the script:

    app.doScript(main, ScriptLanguage.JAVASCRIPT, [], UndoModes.ENTIRE_SCRIPT, 'Fit table')
    
    function main() {
    
        // change the units to Points
        var old_h_units = app.activeDocument.viewPreferences.horizontalMeasurementUnits;
        app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS;
        var old_v_units = app.activeDocument.viewPreferences.verticalMeasurementUnits;
        app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS;
    
        var doc = app.activeDocument;
        var all_tables = [];
    
        // get all the tables
        var stories = doc.stories.everyItem().getElements();
        while(s = stories.pop()) {
            if (!s.textContainers[0].itemLayer.visible) continue; // exclude stories on hidden layers
            var tables = s.tables.everyItem().getElements();
            while(t = tables.pop()) all_tables.push(t);
        }
    
        // resize cells of all tables
        while (t = all_tables.pop()) resize_cells(t.cells);
    
        // restore the old units
        app.activeDocument.viewPreferences.horizontalMeasurementUnits = old_h_units;
        app.activeDocument.viewPreferences.verticalMeasurementUnits = old_v_units;
    
    }
    
    // functions ------------------------------------------------------------------
    
    function resize_cells(cells) {
        var first_cell = cells.firstItem().texts[0];
        var last_cell = cells.lastItem().texts[0];
        var id = first_cell.parentTextFrames[0].id;
    
        // chahge heights
        while (last_cell.parentTextFrames.length
            && last_cell.parentTextFrames[0].id === id) {
            change_heights(cells, +.1);
        }
        change_heights(cells, -.1); // one step back
    
        // change widths
        var row = cells[0].parentRow;
        var borders = row.rightEdgeStrokeWeight/2 + row.leftEdgeStrokeWeight/2;
        var frame_width = get_width(first_cell.parentTextFrames[0]) - borders;
        while (cells[0].parentRow.width < frame_width) {
            change_widths(cells, +.1);
        }
    }
    
    function change_heights(cells, value) {
        for (var i=0; i<cells.length; i++) cells[i].height += value;
    }
    
    function change_widths(cells, value) {
        for (var i=0; i<cells.length; i++) cells[i].width += value;
    }
    
    function get_width(obj) {
        return obj.geometricBounds[3] - obj.geometricBounds[1];
    }
    

    It gets all the tables of current document (except hidden layers), select all cells of each table and resize the cells to fit them in their parent text frame.

    Not sure, is it okay to change highs of first and second row? Let me know if you don't want change highs of the first two rows.