Script needs to work across unconnected pages
Copy link to clipboard
Copied
Hello, I have a swap script which works. But if a user selects two objects on unconnected pages it fails to work. Any hints would be great.
(Also any hints of how to swap the object layer positions too, as currently if something is index x and the other is index y it doesnt swap)
Best,
Smyth
//AutoSwap
app.doScript(function () {
if (app.selection.length !== 2) {
alert("Please select exactly two objects.");
} else {
var firstObject = app.selection[0];
var secondObject = app.selection[1];
// Check if either object is a GraphicLine
if (firstObject.constructor.name === "GraphicLine" || secondObject.constructor.name === "GraphicLine") {
alert("Cannot swap selection with a rule.");
return; // Exit the script if a GraphicLine is detected
}
// Ensure both objects are valid
if (!firstObject.isValid || !secondObject.isValid) {
alert("Invalid selection. Please select two valid objects.");
} else {
// Function to remember text frame settings
function rememberTextFrameSettings(object) {
if (object.constructor.name === "TextFrame") {
return {
verticalJustification: object.textFramePreferences.verticalJustification,
columnCount: object.textFramePreferences.textColumnCount,
isMultiColumn: object.textFramePreferences.textColumnCount > 1
};
}
return null;
}
// Function to apply text frame settings
function applyTextFrameSettings(object, settings) {
if (settings !== null) {
object.textFramePreferences.verticalJustification = settings.verticalJustification;
object.textFramePreferences.textColumnCount = settings.columnCount;
}
}
// Remember text frame settings
var firstSettings = rememberTextFrameSettings(firstObject);
var secondSettings = rememberTextFrameSettings(secondObject);
// Get the geometric bounds of both objects
var firstBounds = firstObject.geometricBounds;
var secondBounds = secondObject.geometricBounds;
// Calculate width and height from geometric bounds
var firstWidth = firstBounds[3] - firstBounds[1];
var firstHeight = firstBounds[2] - firstBounds[0];
var secondWidth = secondBounds[3] - secondBounds[1];
var secondHeight = secondBounds[2] - secondBounds[0];
// Function to compare width and height
function areDimensionsEqual(width1, height1, width2, height2) {
return Math.abs(width1 - width2) < 6 && Math.abs(height1 - height2) < 6; // Tolerance for floating-point precision
}
// Check if either object is a multi-column text frame
var isFirstMultiColumn = firstSettings && firstSettings.isMultiColumn;
var isSecondMultiColumn = secondSettings && secondSettings.isMultiColumn;
// Handle swapping based on the type of objects
if ((isFirstMultiColumn && !isSecondMultiColumn && secondObject.constructor.name === "Rectangle") ||
(!isFirstMultiColumn && isSecondMultiColumn && firstObject.constructor.name === "Rectangle")) {
// Swap geometric bounds only for multi-column text frame with picture
firstObject.geometricBounds = secondBounds;
secondObject.geometricBounds = firstBounds;
} else {
// Swap geometric bounds and apply text frame settings
firstObject.geometricBounds = secondBounds;
secondObject.geometricBounds = firstBounds;
// Apply text frame settings only if both are text frames
if (firstSettings && secondSettings) {
applyTextFrameSettings(firstObject, secondSettings);
applyTextFrameSettings(secondObject, firstSettings);
}
}
// Handle grouped objects specifically
function adjustGroupImagesPosition(group, offsetX, offsetY) {
if (group.constructor.name === "Group") {
for (var i = 0; i < group.allPageItems.length; i++) {
adjustMediaPosition(group.allPageItems[i], offsetX, offsetY);
}
}
}
// Function to adjust media position (images and graphics) within the new frame
function adjustMediaPosition(object, offsetX, offsetY) {
if ((object.constructor.name === "Rectangle" ||
object.constructor.name === "Oval" ||
object.constructor.name === "Polygon") &&
(object.images.length > 0 || object.graphics.length > 0)) {
// Handle both images and graphics (including .eps)
var media = object.images.length > 0 ? object.images[0] : object.graphics[0];
// Adjust geometric bounds for all shapes
media.geometricBounds = [
media.geometricBounds[0] + offsetY,
media.geometricBounds[1] + offsetX,
media.geometricBounds[2] + offsetY,
media.geometricBounds[3] + offsetX
];
}
}
// Function to fit content in images/graphics with proportional adjustment for all shapes
function fitContentInMediaProportionally(object, fitOption) {
if ((object.constructor.name === "Rectangle" ||
object.constructor.name === "Oval" ||
object.constructor.name === "Polygon") &&
(object.images.length > 0 || object.graphics.length > 0)) {
object.fit(fitOption); // Use proportional fitting
} else if (object.constructor.name === "Group") {
for (var i = 0; i < object.allPageItems.length; i++) {
fitContentInMediaProportionally(object.allPageItems[i], fitOption);
}
}
}
// Check if the dimensions (width and height) are equal
if (areDimensionsEqual(firstWidth, firstHeight, secondWidth, secondHeight)) {
// Calculate the offset between the first and second object
var offsetX = secondBounds[1] - firstBounds[1];
var offsetY = secondBounds[0] - firstBounds[0];
// Adjust the image/graphic position for both objects
adjustMediaPosition(firstObject, offsetX, offsetY);
adjustMediaPosition(secondObject, -offsetX, -offsetY);
// Adjust media positions within groups if necessary
adjustGroupImagesPosition(firstObject, offsetX, offsetY);
adjustGroupImagesPosition(secondObject, -offsetX, -offsetY);
} else {
// Use FILL_PROPORTIONALLY option for fitting media without stretching
var fitOptions = FitOptions.FILL_PROPORTIONALLY;
// Fit content in media in both objects using proportional fitting for all shapes
fitContentInMediaProportionally(firstObject, fitOptions);
fitContentInMediaProportionally(secondObject, fitOptions);
// Adjust media positions within groups if necessary
adjustGroupImagesPosition(firstObject, 0, 0);
adjustGroupImagesPosition(secondObject, 0, 0);
}
}
}
}, ScriptLanguage.JAVASCRIPT, null, UndoModes.ENTIRE_SCRIPT, "Swap Object Sizes and Positions");
Copy link to clipboard
Copied
Hi @SmythWharf, just for starters, are *you* able to select items on different pages (edit: I was thinking spreads) at the same time? I don't know how to do that. - Mark
Edit: Ah I think I understand now... you mean two items on unconnected pages in the same spread. Of course. Sorry.
Copy link to clipboard
Copied
As in, two items from pages which have no connections. The quickest way to think about it is the pages panels, if there is a gap from one page to another or spread to a spread, I am unable to recognise both of these things as a selection in the script. It believes only one thing is being selected.
Hope this helps.
Copy link to clipboard
Copied
It's not possible to select items on two separate SPREADS.
Can you post some screenshots showing what you're trying to select?
Copy link to clipboard
Copied
What error do you get?
If by "swap" you mean "change location" - why not just move the selected objects?
Copy link to clipboard
Copied
I can't check your code right now, but it's possible that your script is going high-wire, if you've "ruler origin" set to "per page" - and not "per Spread".
https://www.indesignjs.de/extendscriptAPI/indesign-latest/#RulerOrigin.html
Copy link to clipboard
Copied
Hello,
The script fails to run when two items are selected on unconnected pages. It flags this the built in error claiming there needs to be two things selected. in short, it cant read one of the selections. (I never tested this as I could maybe add a debug at the start to print out all selections), but this is my hunch.
It seems to only be able to pick up selections from any connect page(s), i.e. page single or spread
Copy link to clipboard
Copied
Hello,
Silly me, it's an InDesign limitation, you simply cannot make selections of items which span across unconnected pages.
For example I can only select one image at a time.
Copy link to clipboard
Copied
Yes, you can select objects only on the same Spread - unfortunately, it was always like that.
But you can modify your script to ask for selecting first object, save reference, then display second dialog - asking user to select another object.
Copy link to clipboard
Copied
Alas, it was a slip of the mind, revisiting this script after about 6 or so months.
Shame InDesign doesn't support such selections. Oh well.
Best,
Smyth

