Resolve Overset Text
Script for Adobe InDesign
Fix overset text in InDesign documents. Script detects overset text, creates a text frame off-page, and links to the frame so the hidden content is revealed. Once confident all content to keep is showing, and the revealed overset text is excess, the script can then delete the unwanted content and added frames.
Overset text is visible in Story Editor, but having to open Story Editor to resolve each instance of overset text takes time. The purpose of the script is to help speed up the process.
- Make visible all overset text in a document
- Delete all overset text
- Adapt open source to customize or create other scripts
How-to Video
How to use the script
The interface is a single section with two choices: Reveal overset text, and Delete revealed text. Select one and click the OK button to begin.
Reveal overset text — document stories are scanned for overset text, and when found, the ending text frame is located and linked to a new text frame created on the pasteboard next to the page. Before linking the new frame, the script inserts a paragraph end after the last character showing in the ending frame, to prevent reflow that can occur when overset text is revealed. The new frame on the pasteboard is given a magenta, dashed stroke so it stands out. In cases of multiple instances of overset text on the same page, the added frames are stacked, but each is offset over and down so they are not directly atop each other.
Before inspecting the results, enable Show Hidden Characters (Type menu), and enable Show Text Threads (View menu, Extras). Then whitespace is visible, in some cases all the overset text contains, and selecting the frame of revealed text shows the connection to the story ending frame on the page, to which the new frame is linked.
Once overset text is revealed, the user should inspect the content to determine whether the excess is a mistake and is not needed, or wanted content has moved into the overset portion. In that case, adjust the layout to get the desired content to appear in the frame on the page. Be aware of the paragraph end added after the last character showing in the ending frame, which must be removed if overset text needs to flow back into the text frame on the page.
Delete revealed text — after inspecting overset text and adjusting the layout, the excess content and text frames may be deleted if desired. This can be done manually, one-by-one, but to help, the script can remove all revealed text and frames at once using this option.
It’ s possible to make the script take both steps in one operation, but I feel it’s better to split the process into two steps, so the user can confirm the text revealed before deleting it, and hopefully avoid a costly mistake.
Source code
(download button below)
/*
Resolve Overset Text
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 = "Resolve Overset Text";
if (!/indesign/i.test(app.name)) {
alert("Script for InDesign", title, false);
return;
}
// Script variables.
var count;
var doc;
var doneMessage;
var error;
var working;
// Reusable UI variables.
var g; // group
var p; // panel
var w; // window
// Permanent UI variables.
var btnCancel;
var btnOk;
var rbDelete;
var rbReveal;
// SETUP
// Script requires open document.
if (!app.documents.length) {
alert("Open a document", title, false);
return;
}
doc = app.activeDocument;
// 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
p = w.add("panel");
p.alignChildren = "left";
g = p.add("group");
g.orientation = "column";
g.alignChildren = "left";
rbReveal = g.add("radiobutton", undefined, "Reveal overset text");
rbDelete = g.add("radiobutton", undefined, "Delete revealed text");
// 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");
// DEFAULTS
rbReveal.value = true;
// UI ELEMENT EVENT HANDLERS
// Action Buttons
btnOk.onClick = function () {
w.close(1);
};
btnCancel.onClick = function () {
w.close(0);
};
// DISPLAY THE DIALOG
if (w.show() == 1) {
doneMessage = "";
try {
process();
} 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 process() {
app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;
count = 0;
working.display();
if (rbReveal.value) {
app.doScript(processReveal, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Reveal overset text");
if (count) {
doneMessage =
"Revealed " + count + " cases of overset text.\n" +
"Inspect revealed text, resolve problems, then use 'Delete revealed text' to finish.";
} else {
doneMessage = "No overset text found.";
}
}
if (rbDelete.value) {
app.doScript(processDelete, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Delete revealed text");
if (count) {
doneMessage = "Deleted " + count + " cases of revealed text.";
} else {
doneMessage = "No revealed text found.";
}
}
}
function processDelete() {
var cb; // content begin
var ce; // content end
var i;
var textFrame;
try {
// Loop through all text frames.
// Loop backwards because removing items.
for (i = doc.textFrames.length - 1; i > -1; i--) {
textFrame = doc.textFrames[i];
if (textFrame.label == "oversettext") {
if (textFrame.contents) {
// Delete content from begin of frame to end of story.
cb = textFrame.texts[0].insertionPoints.firstItem();
ce = textFrame.parentStory.texts[0].insertionPoints.lastItem();
textFrame.parentStory.texts.itemByRange(cb, ce).remove();
}
// Delete frame.
textFrame.remove();
// Increment count.
count++;
}
}
} catch (e) {
error = e;
throw e;
}
}
function processReveal() {
var endFrame; // last frame of story
var h = doc.documentPreferences.pageHeight;
var i;
var lastXY;
var osFrames = []; // collection of overset frames
var page;
var reFrame; // revealing frame
var reFrames = []; // collection of revealing frames
var w = doc.documentPreferences.pageWidth;
var x;
var y;
osFrames.pushUnique = function (x) {
for (var i = 0; i < this.length; i++) {
if (this[i].id == x.id) {
return;
}
}
this.push(x);
};
reFrames.position = function (pageId) {
// Loop backwards to match last added.
for (var i = this.length - 1; i > -1; i--) {
if (this[i].id == pageId) {
return [this[i].x, this[i].y];
}
}
return null;
};
try {
// Loop through doc stories to collect overset frames.
for (i = 0; i < doc.stories.length; i++) {
if (doc.stories[i].overflows) {
// Add end frame to overset frames array.
osFrames.pushUnique(doc.stories[i].textContainers[0].endTextFrame);
}
}
// Loop through overset frames.
for (i = 0; i < osFrames.length; i++) {
endFrame = osFrames[i];
// Get frame's page.
page = endFrame.parentPage;
if (!page) {
// Ignore frames on pasteboard.
continue;
}
// Add paragraph end so text doesn't flow into new frame adding next.
endFrame.texts[0].insertionPoints.lastItem().contents = "\r";
// Add new frame and link end frame to it.
reFrame = page.textFrames.add();
endFrame.nextTextFrame = reFrame;
// Position new frame off page.
if (page.index == 1) {
// Right-hand page.
if (doc.viewPreferences.rulerOrigin == RulerOrigin.SPREAD_ORIGIN) {
// Rulers using spread origin.
x = w * 2 + 18;
} else {
// Rulers using page or spine origin.
x = w + 18;
}
} else {
// Left-hand page.
if (doc.viewPreferences.rulerOrigin == RulerOrigin.SPINE_ORIGIN) {
// Rulers using spine origin.
x = -(w + w / 2) - 18;
} else {
// Rulers using page or spread origin.
x = -(w / 2) - 18;
}
}
y = 0;
lastXY = reFrames.position(page.id);
if (lastXY) {
// A revealing frame next to this page has already been added.
// Shift new frame so not on top of last.
if (page.index == 1) {
// Right-hand page.
x = lastXY[0] += 24;
} else {
// Left-hand page.
x = lastXY[0] -= 24;
}
y = lastXY[1] += 24;
}
// Set frame position and size.
reFrame.geometricBounds = [y, x, y + h / 2, x + w / 2];
// Mark frame to identify it as holding overset text so can
// clear its content when calling 'Delete revealed text.'
reFrame.label = "oversettext";
// Stroke frame so it stands out.
reFrame.strokeColor = "Magenta";
reFrame.strokeTint = 100;
reFrame.strokeWeight = 4;
reFrame.strokeType = "Dashed";
// Remember revealing frame.
reFrames.push({
id: page.id,
x: x,
y: y
});
// Increment count.
count++;
}
} catch (e) {
error = e;
throw e;
}
}
})();
Resolve Overset Text
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.