SmythWharf
Contributor
SmythWharf
Contributor
Activity
‎Mar 01, 2025
12:46 PM
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
... View more
‎Mar 01, 2025
12:18 PM
1 Upvote
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.
... View more
‎Mar 01, 2025
05:47 AM
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.
... View more
‎Mar 01, 2025
05:32 AM
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
... View more
‎Feb 28, 2025
05:14 PM
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");
... View more
‎Feb 27, 2025
12:07 PM
Hello, This is excellent starter information. Very curious indeed. Best, Smyth
... View more
‎Feb 27, 2025
03:19 AM
Hello, Thank you for your reply, so in theory a library which sits on my desktop I could access via a script? My thinking is, if you can access libary items, would there be a way to make a script to do things to particular library items via the name of those items? For example if you really wanted to, can you do a paste in place via the script looking for say library item called 'template'... this is just https://www.indesignjs.de/extendscriptAPI/indesign-latest/#Library.html Best, Smyth.
... View more
‎Feb 26, 2025
03:57 PM
Hello, Is it possible to access library items from scripts? Really hope there is a way! Many thanks Smyth
... View more
‎Dec 04, 2024
02:44 PM
1 Upvote
Thats the one Re: I wonder if you're referring to this ScriptUI builder: https://scriptui.joonas.me/
... View more
‎Nov 04, 2024
11:53 AM
Umm, I will have a look. The html part should be fine. Additionally, I also believe there is a UI builder for a range of Adobe applications, however I have forgotten the website, unless you had knowledge of it. It was a case of drag on drop from one side, and then you can export the html/css etc
... View more
‎Nov 04, 2024
11:45 AM
Hello, yup UXP. I have had a go at downloading even the basic starter samples, e.g. hello world button dockable panel. But I run into issues even on basic stuff such as this, e.g. no hello world pop up etc. I would be interested in collaborating, or finding a good example of a working set up so I can further understand. Any thing that I have found has been quite primilimary. Best, Smyth
... View more
‎Nov 04, 2024
08:41 AM
Hello, I have looked arround for information regarding making an InDesign plugin which comprises of a user interface panel and some buttons to run scripts. (Yes, the scripts could be run via shortcut, however a formalised pannel would be a nice goal). I have looked at the documentation and there is and there is a query close to mine here https://forums.creativeclouddeveloper.com/t/what-to-create-a-plugin-panel-that-has-multiple-buttons-to-run-scripts-i-have-developed/8014 However it was not much help to me. Any suggestions would be ace. Best, Smyth
... View more
‎Sep 30, 2024
02:13 PM
Quick script below will print out yes or no if there is paragaph style overrides // Check if there is a selection
if (app.selection.length === 0 || !(app.selection[0] instanceof Text)) {
alert("Please select some text.");
} else {
var selectedText = app.selection[0];
// Check if the selected text has paragraphs
if (selectedText.paragraphs.length > 0) {
var paragraph = selectedText.paragraphs[0];
var paragraphStyle = paragraph.appliedParagraphStyle.name;
var hasOverrides = paragraph.styleOverridden; // Corrected property name
// Create a message to display
var message = "The applied paragraph style is: " + paragraphStyle + "\n";
message += "Overrides: " + (hasOverrides ? "Yes" : "No");
alert(message);
} else {
alert("The selected text does not contain any paragraphs.");
}
}
... View more
‎Sep 30, 2024
12:07 PM
Hello, Oh aces, will check it out shortly, Best
... View more
‎Sep 30, 2024
09:57 AM
Hello is there method or something alreay within indesign API to check if there are paragraph style overrides which can product a boole result? I have the following: // Function to check if the paragraph style has been overridden
function isParagraphStyleOverridden(paragraph) {
return paragraph.styleOverrides.length > 0; // Returns true if there are overrides
} The reason being I had this stupid bit of code from a few months ago which really is terrible and would prefer a dynamic approach // Function to check if the paragraph matches its base paragraph style
function isStyleUnmodified(paragraph) {
// Get the paragraph style applied to the paragraph
var paragraphStyle = paragraph.appliedParagraphStyle;
// If there's no style applied, return false
if (!paragraphStyle) {
return false;
}
// Get the properties to check
var styleProperties = ['appliedFont', 'pointSize', 'fillColor', 'fillTint', 'justification',
'leading', 'firstLineIndent', 'baselineShift', 'tracking',
'capitalization', 'alignToBaseline', 'ruleAbove', 'ruleBelow',
'spaceBefore', 'spaceAfter'];
// Check each property against the paragraph style
for (var i = 0; i < styleProperties.length; i++) {
var prop = styleProperties[i];
if (paragraph[prop] !== paragraphStyle[prop]) {
return false; // If any property is different, return false
}
}
// If all properties match, return true
return true;
} But not sure if there are other ways of doing this? Thank you, Smyth
... View more
‎Sep 14, 2024
04:22 PM
Had a little look into it thank you all for the advice below is some updated code which from what I could test seems to swap the .eps files well 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");
... View more
‎Sep 14, 2024
09:58 AM
Hello, Below is a script indended to swap two selected items. Should a user have a graphic the script portionally centres the images in their new frames. However EPS do not behave in such a away, but jpgs pdfs and psds all seems okay. Any hints would be most welcome, 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++) {
adjustImagePosition(group.allPageItems[i], offsetX, offsetY);
}
}
}
// Function to adjust image position within the new frame
function adjustImagePosition(object, offsetX, offsetY) {
if ((object.constructor.name === "Rectangle" ||
object.constructor.name === "Oval" ||
object.constructor.name === "Polygon") && object.images.length > 0) {
var image = object.images[0];
// Adjust geometric bounds for all shapes
image.geometricBounds = [
image.geometricBounds[0] + offsetY,
image.geometricBounds[1] + offsetX,
image.geometricBounds[2] + offsetY,
image.geometricBounds[3] + offsetX
];
}
}
// Function to fit content in images with proportional adjustment for all shapes
function fitContentInImagesProportionally(object, fitOption) {
if ((object.constructor.name === "Rectangle" ||
object.constructor.name === "Oval" ||
object.constructor.name === "Polygon") && object.images.length > 0) {
object.fit(fitOption); // Use proportional fitting
} else if (object.constructor.name === "Group") {
for (var i = 0; i < object.allPageItems.length; i++) {
fitContentInImagesProportionally(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 position for both objects
adjustImagePosition(firstObject, offsetX, offsetY);
adjustImagePosition(secondObject, -offsetX, -offsetY);
// Adjust image positions within groups if necessary
adjustGroupImagesPosition(firstObject, offsetX, offsetY);
adjustGroupImagesPosition(secondObject, -offsetX, -offsetY);
} else {
// Use FILL_PROPORTIONALLY option for fitting images without stretching
var fitOptions = FitOptions.FILL_PROPORTIONALLY;
// Fit content in images in both objects using proportional fitting for all shapes
fitContentInImagesProportionally(firstObject, fitOptions);
fitContentInImagesProportionally(secondObject, fitOptions);
// Adjust image positions within groups if necessary
adjustGroupImagesPosition(firstObject, 0, 0);
adjustGroupImagesPosition(secondObject, 0, 0);
}
}
}
}, ScriptLanguage.JAVASCRIPT, null, UndoModes.ENTIRE_SCRIPT, "Swap Object Sizes and Positions");
... View more
‎Sep 12, 2024
11:49 AM
1 Upvote
Thank you both for your insight. @Robert at ID-Tasker Yes I had a quick look at the ID Tasker... curious thing. @rob day I will look into this Regarding the above I have adjusted the processItem and the findSmallerGroupItem functions and up pageItems has done it - a good thing to learn! Thank you very much! Best, Smyth
... View more
‎Sep 12, 2024
04:06 AM
Hello, Nice bit of software to show that - Thats interesting becuase I did also have a script to show me the bounds of all objects which gave me four results which took me back as I had precived image plus item groups as three things - but complete oversight as the group of course has its own bounds... of which your page items demo shows four parts three parent to the group Aces Can't wait to update the code later! Thank you Smyth
... View more
‎Sep 12, 2024
03:23 AM
Hello, Thank you for the advice, this was distroying my soul. I will give it a shot tonight when I am back home. I know the script and this function is very daft on appearance but it's a workarround for a content management system running through InDesign. Ill update later, Best, Smyth
... View more
‎Sep 11, 2024
04:22 PM
Hello, I have a script which counts how many things are in a group. Is it becuase indesign is reading a parent bound plus the image inside the rectangle, PLUS the blue box, so there is three things? I have the following code and am struggling to know how to intergrate a group which has an image and another thing My thought was to adjust this part if (item instanceof Group && item.allPageItems.length === 2) to have OR group selection of image, bounding rectangle, and other thing then ... but I'm just not getting anywhere Any advice would be great Thanks Smyth app.doScript(function() {
// Get the active document
var doc = app.activeDocument;
// Get document grid preferences
var gridPreferences = doc.gridPreferences;
var baselineIncrement = gridPreferences.baselineDivision;
// Add a precision threshold to handle floating-point precision issues
var precisionThreshold = 0.1; // This helps to avoid errors when height is close to baselineIncrement
// Function to adjust height
function adjustHeight(item) {
var currentHeight = item.geometricBounds[2] - item.geometricBounds[0];
if (currentHeight > baselineIncrement + precisionThreshold) {
// Reduce the bottom edge to shrink the height
if (item instanceof Image && item.parent instanceof Rectangle) {
adjustHeight(item.parent); // Adjust the height of the parent frame, not the image itself
} else {
item.geometricBounds = [
item.geometricBounds[0],
item.geometricBounds[1],
item.geometricBounds[2] - baselineIncrement,
item.geometricBounds[3]
];
}
} else {
// Move the item upwards if its height is equal to or less than one baseline (within threshold)
var moveAmount = Math.abs(baselineIncrement); // Ensure positive value
item.geometricBounds = [
item.geometricBounds[0] - moveAmount,
item.geometricBounds[1],
item.geometricBounds[2] - moveAmount,
item.geometricBounds[3]
];
}
}
// Function to find and assign smaller and larger items in a group of two
function findSmallerGroupItem(group) {
var groupItem1 = group.allPageItems[0];
var groupItem2 = group.allPageItems[1];
var heightItem1 = groupItem1.geometricBounds[2] - groupItem1.geometricBounds[0];
var heightItem2 = groupItem2.geometricBounds[2] - groupItem2.geometricBounds[0];
var smallGroupItem, largeGroupItem;
// Compare heights and assign smaller and larger
if (heightItem1 < heightItem2) {
smallGroupItem = groupItem1;
largeGroupItem = groupItem2;
} else {
smallGroupItem = groupItem2;
largeGroupItem = groupItem1;
}
return {
smallGroupItem: smallGroupItem,
largeGroupItem: largeGroupItem
};
}
// Function to resize and center the smaller group item
function resizeAndCenterSmallerGroupItem(smallGroupItem, largeGroupItem) {
var largeTop = largeGroupItem.geometricBounds[0];
var largeBottom = largeGroupItem.geometricBounds[2];
var largeCenter = (largeTop + largeBottom) / 2;
// Calculate the new height and top position for the smaller item
var smallWidth = smallGroupItem.geometricBounds[3] - smallGroupItem.geometricBounds[1];
var smallNewTop = largeCenter - (baselineIncrement / 2);
// Resize the smaller item to match baseline increment
smallGroupItem.geometricBounds = [
smallNewTop,
smallGroupItem.geometricBounds[1],
smallNewTop + baselineIncrement,
smallGroupItem.geometricBounds[3]
];
// Adjust the smaller item’s horizontal position if necessary
var currentBounds = smallGroupItem.geometricBounds;
smallGroupItem.geometricBounds = [
currentBounds[0],
currentBounds[1],
currentBounds[2],
currentBounds[3] // No horizontal adjustment needed in this case
];
}
// Function to process each item or group recursively
function processItem(item) {
if (item instanceof Group && item.allPageItems.length === 2) {
// If the item is a group with exactly two items, find smaller and larger items
var groupItems = findSmallerGroupItem(item);
// Resize and center the smaller item within the larger item
resizeAndCenterSmallerGroupItem(groupItems.smallGroupItem, groupItems.largeGroupItem);
// Now adjust the height of the larger item as well
adjustHeight(groupItems.largeGroupItem);
} else if (item instanceof GraphicLine || item instanceof TextFrame || item instanceof Rectangle) {
adjustHeight(item);
} else if (item instanceof Group) {
for (var j = 0; j < item.allPageItems.length; j++) {
processItem(item.allPageItems[j]);
}
} else if (item instanceof Image) {
// Check if the image is inside a rectangle (frame)
var parent = item.parent;
if (parent instanceof Rectangle) {
adjustHeight(parent);
} else {
adjustHeight(item);
}
} else {
alert("Selection contains unsupported items. Please select only vertical rules, text frames, picture boxes, or groups.");
}
}
// Check if there are any selected objects
if (app.selection.length === 0) {
alert("Please select one or more vertical rules, text frames, picture boxes, or groups.");
} else {
// Iterate over all selected objects
for (var i = 0; i < app.selection.length; i++) {
processItem(app.selection[i]);
}
}
}, ScriptLanguage.JAVASCRIPT, null, UndoModes.ENTIRE_SCRIPT, "Adjust Item Height Based on Baseline Increment");
... View more
‎Sep 10, 2024
05:22 PM
Hello, Please may I get some help regarding a script aimed at moving selections up by a baseline height - its part of a larger array of movement scripts. Anyhow... There is logic to centre a the smaller item in a group of two things. // Function to ensure smaller item is centered within the larger item So the script when run is making the box smaller with each time it is run, it makes the smaller object a baseline in height and keeps it centre - Dont worry about the offseting being slightly wrong I am aware of it as if i reverse the shrinking origin that then offset is fine... anyhow -- // Function to offset the position of the smaller group item -- is why is it not quite centre This works fine for graphic to graphic but if i try image to text where the text is smaller than the image then it doesnt work. Do not question why I am trying to make such a stupid script, it is the fault of a daft content management system which deals with indesign. Im guessing it is something to do with telling the smaller object to read the parent frame for the image... not sure Any heko on this would be ace, Best, Smyth Code is below app.doScript(function() {
// Get the active document
var doc = app.activeDocument;
// Get document grid preferences
var gridPreferences = doc.gridPreferences;
var baselineIncrement = gridPreferences.baselineDivision;
// Add a precision threshold to handle floating-point precision issues
var precisionThreshold = 0.1; // This helps to avoid errors when height is close to baselineIncrement
// Function to adjust height
function adjustHeight(item) {
var currentHeight = item.geometricBounds[2] - item.geometricBounds[0];
if (currentHeight > baselineIncrement + precisionThreshold) {
// Reduce the bottom edge to shrink the height
if (item instanceof Image && item.parent instanceof Rectangle) {
adjustHeight(item.parent); // Adjust the height of the parent frame, not the image itself
} else {
item.geometricBounds = [
item.geometricBounds[0],
item.geometricBounds[1],
item.geometricBounds[2] - baselineIncrement,
item.geometricBounds[3]
];
}
} else {
// Move the item upwards if its height is equal to or less than one baseline (within threshold)
var moveAmount = Math.abs(baselineIncrement); // Ensure positive value
item.geometricBounds = [
item.geometricBounds[0] - moveAmount,
item.geometricBounds[1],
item.geometricBounds[2] - moveAmount,
item.geometricBounds[3]
];
}
}
// Function to find and assign smaller and larger items in a group of two
function findSmallerGroupItem(group) {
var groupItem1 = group.allPageItems[0];
var groupItem2 = group.allPageItems[1];
var heightItem1 = groupItem1.geometricBounds[2] - groupItem1.geometricBounds[0];
var heightItem2 = groupItem2.geometricBounds[2] - groupItem2.geometricBounds[0];
var smallGroupItem, largeGroupItem;
// Compare heights and assign smaller and larger
if (heightItem1 < heightItem2) {
smallGroupItem = groupItem1;
largeGroupItem = groupItem2;
} else {
smallGroupItem = groupItem2;
largeGroupItem = groupItem1;
}
return {
smallGroupItem: smallGroupItem,
largeGroupItem: largeGroupItem
};
}
// Function to ensure smaller item is centered within the larger item
function ensureSmallerGroupItemIsCentre(smallGroupItem, largeGroupItem) {
var largeTop = largeGroupItem.geometricBounds[0];
var largeBottom = largeGroupItem.geometricBounds[2];
var largeCenter = (largeTop + largeBottom) / 2;
var smallHeight = smallGroupItem.geometricBounds[2] - smallGroupItem.geometricBounds[0];
var smallTop = largeCenter - (smallHeight / 2);
// Adjust the smaller item’s vertical position to be centered within the larger one
smallGroupItem.geometricBounds = [
smallTop,
smallGroupItem.geometricBounds[1],
smallTop + smallHeight,
smallGroupItem.geometricBounds[3]
];
}
// Function to resize the smaller group item to match baseline increment
function smallerGroupItemSize(smallGroupItem) {
smallGroupItem.geometricBounds = [
smallGroupItem.geometricBounds[0] + baselineIncrement ,
smallGroupItem.geometricBounds[1],
smallGroupItem.geometricBounds[0],
smallGroupItem.geometricBounds[3]
];
}
// Function to offset the position of the smaller group item
function offsetSmallGroupItem(smallGroupItem) {
var offsetAmount = baselineIncrement / 2;
var currentBounds = smallGroupItem.geometricBounds;
smallGroupItem.geometricBounds = [
currentBounds[0] + offsetAmount,
currentBounds[1],
currentBounds[2] + offsetAmount,
currentBounds[3]
];
}
// Function to process each item or group recursively
function processItem(item) {
if (item instanceof Group && item.allPageItems.length === 2) {
// If the item is a group with exactly two items, find smaller and larger items
var groupItems = findSmallerGroupItem(item);
// Ensure the smaller item is centered within the larger item
ensureSmallerGroupItemIsCentre(groupItems.smallGroupItem, groupItems.largeGroupItem);
// Resize the smaller group item
smallerGroupItemSize(groupItems.smallGroupItem);
// Offset the smaller group item
offsetSmallGroupItem(groupItems.smallGroupItem);
// Now adjust the height of the larger item as well
adjustHeight(groupItems.largeGroupItem);
} else if (item instanceof GraphicLine || item instanceof TextFrame || item instanceof Rectangle) {
adjustHeight(item);
} else if (item instanceof Group) {
for (var j = 0; j < item.allPageItems.length; j++) {
processItem(item.allPageItems[j]);
}
} else if (item instanceof Image) {
// Check if the image is inside a rectangle (frame)
var parent = item.parent;
if (parent instanceof Rectangle) {
adjustHeight(parent); // Adjust the frame's height, not the image itself
} else {
adjustHeight(item);
}
} else {
alert("Selection contains unsupported items. Please select only vertical rules, text frames, picture boxes, or groups.");
}
}
// Check if there are any selected objects
if (app.selection.length === 0) {
alert("Please select one or more vertical rules, text frames, picture boxes, or groups.");
} else {
// Iterate over all selected objects
for (var i = 0; i < app.selection.length; i++) {
processItem(app.selection[i]);
}
}
}, ScriptLanguage.JAVASCRIPT, null, UndoModes.ENTIRE_SCRIPT, "Adjust Item Height Based on Baseline Increment");
... View more
‎Sep 09, 2024
03:15 PM
Okay this time the following script should allow for a user to select any combination of frames of unthreaded and either/or previosuly or next threaded text boxes //AutoThread
var gScriptName = "Advanced Thread Text Frames (Bidirectional with Improved Error Handling)";
try {
app.doScript(main, undefined, undefined, UndoModes.ENTIRE_SCRIPT, gScriptName);
app.menuActions.itemByName("$ID/Force Redraw").invoke();
} catch (e) {
alert(e + ". An error has occurred, try again.", gScriptName);
}
function main() {
var selectedFrames = app.selection;
// Check if user has selected text frames
if (selectedFrames.length < 2) {
alert("Select at least two text frames to thread.", gScriptName);
return;
}
// Validate that all selected items are text frames
var textFrames = [];
for (var i = 0; i < selectedFrames.length; i++) {
if (selectedFrames[i] instanceof TextFrame) {
textFrames.push(selectedFrames[i]);
}
}
if (textFrames.length < 2) {
alert("Please select at least two valid text frames.", gScriptName);
return;
}
// Sort frames by horizontal position
textFrames.sort(compareFramesByPosition);
// Determine the starting frame of the thread
var startingFrame = findStartingFrame(textFrames);
// Determine the threading direction
var threadingDirection = determineDirection(textFrames);
// Re-threading logic
try {
rethreadFrames(textFrames, startingFrame, threadingDirection);
} catch (e) {
alert("Error during rethreading: " + e.message, gScriptName);
}
}
function compareFramesByPosition(frameA, frameB) {
// Sort by x-position (geometricBounds[1] is the x-coordinate)
return frameA.geometricBounds[1] - frameB.geometricBounds[1];
}
function determineDirection(frames) {
// Compare positions of the first and last frame
var firstX = frames[0].geometricBounds[1];
var lastX = frames[frames.length - 1].geometricBounds[1];
return firstX < lastX ? "leftToRight" : "rightToLeft";
}
function findStartingFrame(frames) {
// Check if any frame is a part of a thread
var threadedFrames = [];
// Helper function to check if an array contains an element
function arrayContains(array, element) {
for (var i = 0; i < array.length; i++) {
if (array[i] === element) {
return true;
}
}
return false;
}
for (var i = 0; i < frames.length; i++) {
var frame = frames[i];
if (frame.previousTextFrame && !arrayContains(frames, frame.previousTextFrame)) {
threadedFrames.push(frame.previousTextFrame);
}
if (frame.nextTextFrame && !arrayContains(frames, frame.nextTextFrame)) {
threadedFrames.push(frame.nextTextFrame);
}
}
if (threadedFrames.length > 0) {
// Determine the farthest left (or right) frame
var sortedThreadedFrames = threadedFrames.concat(frames).sort(compareFramesByPosition);
return sortedThreadedFrames[0];
}
// If no threaded frames are found, return the first frame in the selection
return frames[0];
}
function rethreadFrames(frames, startingFrame, direction) {
var currentFrame = startingFrame;
// Thread the frames based on the direction
for (var i = 0; i < frames.length; i++) {
if (direction === "leftToRight") {
if (currentFrame.nextTextFrame !== frames[i] && currentFrame != frames[i]) {
currentFrame.nextTextFrame = frames[i];
}
currentFrame = frames[i];
} else if (direction === "rightToLeft") {
if (currentFrame.previousTextFrame !== frames[i] && currentFrame != frames[i]) {
currentFrame.previousTextFrame = frames[i];
}
currentFrame = frames[i];
}
}
}
... View more
‎Sep 08, 2024
02:54 PM
Ah ha! - well yup it broke, sigh.
... View more
‎Sep 08, 2024
02:28 PM
I unthreaded them to ensure that if I had an array of some threaded some not, that it would be easier to unthread the lot and thread left to right. Perhaps I am taking too long a step?
... View more
‎Sep 08, 2024
02:27 PM
And finally one more thing regarding the numbers hitting up against each other after being threaded... this was no more than there not being an enter after the last number - see screenshot Full code below var gScriptName = "Thread Text Frames (Left to Right)";
try {
app.doScript(main, undefined, undefined, UndoModes.ENTIRE_SCRIPT, gScriptName);
app.menuActions.itemByName("$ID/Force Redraw").invoke(); // Refresh the screen
} catch (e) {
alert(e + ". An error has occurred, try again.", gScriptName);
}
function main() {
var selectedFrames = app.selection;
// Ensure there are at least two frames selected
if (selectedFrames.length < 2) {
alert("Please select at least two text frames.", gScriptName);
return;
}
// Filter to only include text frames
var textFrames = [];
for (var i = 0; i < selectedFrames.length; i++) {
if (selectedFrames[i] instanceof TextFrame) {
textFrames.push(selectedFrames[i]);
}
}
if (textFrames.length < 2) {
alert("Please select at least two text frames.", gScriptName);
return;
}
// Sort the frames by their x-coordinate (left to right)
textFrames.sort(function(a, b) {
return a.geometricBounds[1] - b.geometricBounds[1];
});
// Unthread all frames but the frist before re-threading
for (var i = 1; i < textFrames.length; i++) {
unthreadFrame(textFrames[i]);
}
// Thread the frames from left to right
for (var i = 0; i < textFrames.length - 1; i++) {
textFrames[i].nextTextFrame = textFrames[i + 1];
}
}
function unthreadFrame(frame) {
// Unthread the current frame from both its previous and next frames
if (frame.previousTextFrame != null) {
frame.previousTextFrame.nextTextFrame = null;
frame.previousTextFrame = null;
}
if (frame.nextTextFrame != null) {
frame.nextTextFrame.previousTextFrame = null;
frame.nextTextFrame = null;
}
} Thank you for the help on this one. Two very daft oversights on this! But I think this is working at this moment. best, Smyth
... View more
‎Sep 08, 2024
02:22 PM
Hello // Unthread all frames before re-threading for (var i = 1; i < textFrames.length; i++) { unthreadFrame(textFrames[i]); } Seems if you dont unthread the first one everything stays okay....
... View more
‎Sep 08, 2024
05:10 AM
Acutally its awful! Hastily done to be fair. In my testing I had always selected the first box from which all threading spawned from, and it works but instances where you do not select the first text frame from which threading was dervied the script could not account for it. The breaking of threads doesnt help. Finding this quite difficult to solve. At least in the ealier ones the restrictions aided in the script. Regarding the /r i noticed that screenshot error I got happens on occasion and usally with the list is it evident. For body copy it does not behave the same way, and I cannot precisly pinpoint to what is going on. I tried to replicate the problem yesterday and I couldn't but then this morning with a list it occured. But trying out real copy and it works... so very much not sure why such occurs. Not great all round.
... View more
‎Sep 08, 2024
04:15 AM
Hello, Thank you for the feedback, this is an older script from about a year ago and I am coming back to it. I remember having a lot of difficulties ensuring which order the frames are in and keeping a left to right flow of selection and what not. Anyhow in light of your comments, perhaps it is easier to start clean and just have a script that threads any combination of text frames together. Perhaps below is better. This time it looks for two text frames, giving us an array of the selection. Cheaking the order via the geometry bounds. Then break any previous threading as to ensure the new threading is left to right. It seems better this time as there are less restrictions for the user when it comes to selections. var gScriptName = "Thread Text Frames (Left to Right)";
try {
app.doScript(main, undefined, undefined, UndoModes.ENTIRE_SCRIPT, gScriptName);
app.menuActions.itemByName("$ID/Force Redraw").invoke(); // Refresh the screen
} catch (e) {
alert(e + ". An error has occurred, try again.", gScriptName);
}
function main() {
var selectedFrames = app.selection;
// Ensure there are at least two frames selected
if (selectedFrames.length < 2) {
alert("Please select at least two text frames.", gScriptName);
return;
}
// Filter to only include text frames
var textFrames = [];
for (var i = 0; i < selectedFrames.length; i++) {
if (selectedFrames[i] instanceof TextFrame) {
textFrames.push(selectedFrames[i]);
}
}
if (textFrames.length < 2) {
alert("Please select at least two text frames.", gScriptName);
return;
}
// Sort the frames by their x-coordinate (left to right)
textFrames.sort(function(a, b) {
return a.geometricBounds[1] - b.geometricBounds[1];
});
// Unthread all frames before re-threading
for (var i = 0; i < textFrames.length; i++) {
unthreadFrame(textFrames[i]);
}
// Thread the frames from left to right
for (var i = 0; i < textFrames.length - 1; i++) {
textFrames[i].nextTextFrame = textFrames[i + 1];
}
}
function unthreadFrame(frame) {
// Unthread the current frame from both its previous and next frames
if (frame.previousTextFrame != null) {
frame.previousTextFrame.nextTextFrame = null;
frame.previousTextFrame = null;
}
if (frame.nextTextFrame != null) {
frame.nextTextFrame.previousTextFrame = null;
frame.nextTextFrame = null;
}
}
... View more
‎Sep 07, 2024
03:36 PM
Ah okay - sure perhaps something like the below might be closer to your suggestion. Best, Smyth var gScriptName = "Thread Text Frames (Left to Right)";
try {
app.doScript(main, undefined, undefined, UndoModes.ENTIRE_SCRIPT, gScriptName);
// Force a screen refresh to update the threading display (if necessary).
app.menuActions.itemByName("$ID/Force Redraw").invoke();
} catch (e) {
alert(e + ". An error has occurred, try again.", gScriptName);
}
function main() {
var selectedFrames = app.selection;
if (selectedFrames.length < 2) {
alert("Select at least two text frames to thread.", gScriptName);
return;
}
var allThreaded = true;
var threadedCount = 0;
var firstFrameThreaded = false;
// Determine if all selected frames are threaded
for (var i = 0; i < selectedFrames.length; i++) {
if (selectedFrames[i] instanceof TextFrame) {
// Check if the frame has a previousTextFrame
if (selectedFrames[i].previousTextFrame != null) {
threadedCount++;
} else if (selectedFrames[i].nextTextFrame != null) {
// If it has a nextTextFrame, it is the first frame in a threading chain
firstFrameThreaded = true;
threadedCount++;
} else {
allThreaded = false;
}
}
}
// If all frames are threaded (including the first in a chain), show the appropriate message
if (allThreaded && (threadedCount === selectedFrames.length)) {
alert("All selected frames are already threaded. Please select frames that are not yet threaded.", gScriptName);
return;
}
// Show error if more than one previously threaded frame is selected
if (threadedCount > 1) {
alert("Please ensure no more than one previously threaded text frame is part of your selection, then try again.", gScriptName);
return;
}
// Sort the selected frames by their position
selectedFrames.sort(compareFramesByPosition);
// Thread the frames, starting from the leftmost one
threadFrames(selectedFrames);
}
function compareFramesByPosition(frameA, frameB) {
// Sort by x-position (geometricBounds[1] is the x-coordinate)
return frameA.geometricBounds[1] - frameB.geometricBounds[1];
}
function threadFrames(frames) {
var previousFrame = frames[0]; // Extract the starting point here
for (var i = 1; i < frames.length; i++) {
var currentFrame = frames[i];
// Thread the current frame to the previous one
currentFrame.previousTextFrame = previousFrame;
previousFrame = currentFrame;
}
}
... View more