Copy link to clipboard
Copied
I've this script that links all Document textFrame with specific frame name.
It works well, only if I've one box per page.
When I've two textFrames in one page, it links only one.
var ps = app.activeDocument.pages;
var ct, nt;
for (var i = 0; i < ps.length - 1; i++) {
ct = ps[i].textFrames.itemByName("<Numbers>");
secondTextFrame = ct.nextTextFrame
nt = ps[i+1].textFrames.itemByName("<Numbers>");
ct.nextTextFrame = nt;
}
Thanks
Hi @lux65, here's some code that might help you with your project. It will thread any text frame that has the script label "NUMBERS". If you prefer using the name you can change that—either is fine. Text frames will be sorted by page order, then Y coordinate, then X coordinate.
- Mark
/**
* Thread text frames labelled "NUMBERS"
* @author m1b
* @discussion https://community.adobe.com/t5/indesign-discussions/threading-all-textframe-in-document-skips-second-frame-in-page/m-p/13842736
*
...
Copy link to clipboard
Copied
If you have two text frames named <Numbers> on a page, then yes, this would not work. ItemByName only returns the first item it finds. You would need to either change how you name your frames and adjust the script to account for that, or loop through ps[i].allPageItems, and find all text frames named <Numbers>. Of course, in that case, how would the script know which is the first and which is the second? Alternatively, you could link the frames on the page before executing the script.
Copy link to clipboard
Copied
I changed second frame name, it works but only if all frames are unthreaded.
var ps = app.activeDocument.pages;
var ct, nt, ct2;
for (var i = 0; i < ps.length - 1; i++) {
ct = ps[i].textFrames.itemByName("<Number>");
ct2 = ps[i].textFrames.itemByName("Number2");
nt = ps[i+1].textFrames.itemByName("<Number>");
// ct.nextTextFrame = nt;
if(ct2.isValid ){
ct.nextTextFrame = ct2;
ct2.nextTextFrame = nt;
}
else{
ct.nextTextFrame = nt
}
}
Copy link to clipboard
Copied
Hi @lux65, here's some code that might help you with your project. It will thread any text frame that has the script label "NUMBERS". If you prefer using the name you can change that—either is fine. Text frames will be sorted by page order, then Y coordinate, then X coordinate.
- Mark
/**
* Thread text frames labelled "NUMBERS"
* @author m1b
* @discussion https://community.adobe.com/t5/indesign-discussions/threading-all-textframe-in-document-skips-second-frame-in-page/m-p/13842736
*/
var targetScriptLabel = "NUMBERS";
function main() {
var doc = app.activeDocument,
allTextFrames = doc.textFrames,
targetFrames = [];
// we only want the text frames
// with target script label
for (var i = 0; i < allTextFrames.length; i++)
if (allTextFrames[i].label == targetScriptLabel)
targetFrames.push(allTextFrames[i]);
//sort in page order
targetFrames.sort(sortFrames);
// now we thread the frames, by only if
// they aren't already threaded properly
for (var i = 0; i < targetFrames.length - 1; i++)
if (targetFrames[i].nextTextFrame != targetFrames[i + 1])
targetFrames[i].nextTextFrame = targetFrames[i + 1];
}
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Thread "' + targetScriptLabel + '" Frames');
/**
* Sorts text frames based on page, then left position, then top position.
* @param {TextFrame} a - the TextFrame to sort.
* @param {TextFrame} b - the TextFrame to sort.
*/
function sortFrames(a, b) {
// by page number
if (a.parentPage.documentOffset < b.parentPage.documentOffset) return -1;
else if (a.parentPage.documentOffset > b.parentPage.documentOffset) return 1;
// by top-bottom
else if (round(a.geometricBounds[0]) < round(b.geometricBounds[0])) return -1;
else if (round(a.geometricBounds[0]) > round(b.geometricBounds[0])) return 1;
// by left-right
else if (round(a.geometricBounds[1]) < round(b.geometricBounds[1])) return -1;
else if (round(a.geometricBounds[1]) > round(b.geometricBounds[1])) return 1;
// same
else return 0;
function round(a) { return (Math.round(a * 1000) / 1000) };
};
Edit 2023-06-07: added sorting function so the layer order doesn't matter.
Edit 2023-06-17: changed sorting order to prefer left-right.
Edit 2023-06-18: changed sorting order to prefer top-bottom.
Edit 2023-06-18: improved sorting so that tiny Extendscript rounding errors are ignored.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Interesting! Can you check if the frames are in the correct order on the spread? Maybe the page 3 frame is above the page 2 frame?
Copy link to clipboard
Copied
Seems it links Frames randomly
Copy link to clipboard
Copied
Hi @lux65, the way the script works currently is to link them in page order, and then layer order. So which ever text frame is topmost in the Layers Panel will be first. It isn't random.
However, it isn't hard for me to put some useful logic in the script so I will update the above code with a sorting function that sorts each text frame by page, then by Y location, then by X location. That should make it simpler.
- Mark
Copy link to clipboard
Copied
Thank you m1b, I didn't see you added sort code.
I just need a little change to get left-right priority then top down.
Copy link to clipboard
Copied
Hi @lux65, I changed the sorting function above to do left-right before top-bottom. That should do it.
- Mark
Copy link to clipboard
Copied
Maybe the flow I need is too complicated.
Copy link to clipboard
Copied
It looks fine to me. (But I have to revert the last change I made to the script—must be top-bottom first then left-right.) When I test it threads in the correct order. Remember that it sorts top to bottom first, so even though the frames look like they are lining up to our eye, check the numbers! Even if a right-ward frame is 0.001 higher than the other, it will be threaded first. - Mark
Copy link to clipboard
Copied
Thank you m1b,
Perfect!
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Hi @lux65, thanks for the sample document—that helped a lot! The problem was because even though in Indesign two frames say the same top value, eg. 36, the actual number of some of them is 35.9999999. The UI shows 36 for both. I easily fixed this problem by changing the sorting function to round the numbers off to 3 decimal places. Try the updated script.
- Mark