Copy link to clipboard
Copied
I found this great script where you pick an assigned 'object style' and it will move all items of that style to the layer you pick. I'm trying to tweak it so it will instead change any text frames with a specified paragraph style and assign it with an object style.
I got the first part changed, but I need help with:
Any help would be great! Thank you!
//This script moves paragraphs with selected paragraph style to selected layer
var myDoc = app.activeDocument;
var w = new Window ("dialog", "Choose paragraph Style and Layer", undefined, {closeButton: true});
w.orientation = "row";
w.alignChildren = ["right", "center"];
w.add("statictext", undefined, "Assign all frames with");
var paragraphStyle = w.add("dropdownlist", undefined, myDoc.paragraphStyles.everyItem().name); // paragraph style list -- what do i adjust to include items within folders too?
paragraphStyle.selection = 0;
w.add("statictext", undefined, "style as");
var applyObjStyle = w.add("dropdownlist", undefined, myDoc.objectStyles.everyItem().name); // objectStyles list -- what do i adjust to include items within folders too?
applyObjStyle.selection = 0;
var button = w.add ("button", [0,0,96,20], "OK", {name: "Ok"});
var paraStyleName, objStyleName;
button.onClick = function(){
paraStyleName = paragraphStyle.selection.text;
objStyleName = applyObjStyle.selection.text;
w.close();
}
w.show();
//NEED HELP WITH CODE BELOW TO assign paraStyleName with objStyle Name
var pageItems = myDoc.pageItems;
if (parseFloat(app.version) < 6) // "app.version < 6" if it's running under an earlier version than CS4, as earlier versions don't support "Undo" in scripts
doUndoWrapper();
else
app.doScript(doUndoWrapper, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Move to layer");
//< END OF doUndoWraper
function doUndoWrapper(){
// unlock locked objectStyles
var lockedobjectStyles = {};
for(var layer = 0; layer < myDoc.objectStyles.length; layer++){
lockedobjectStyles[myDoc.objectStyles[layer].name] = myDoc.objectStyles[layer].locked;
myDoc.objectStyles[layer].locked = false;
}
if(paraStyleName && objStyleName){
//for(var i = 0; i < pageItems.length; i++){
for(var i = --pageItems.length; i >= 0; i--){
if(pageItems[i].appliedparagraphStyle.name === paraStyleName && pageItems[i].itemLayer.name != objStyleName){
try{
// unlock locked paragraphs
var paragraphWasLocked = false;
if(pageItems[i].locked){
paragraphWasLocked = true;
pageItems[i].locked = false;
}
// move paragraphs to layer
pageItems[i].itemLayer = myDoc.objectStyles.item(objStyleName);
// proceed until you bleed, lol!
var iterator = 0;
while(iterator < 1000 && pageItems[i].itemLayer.name != objStyleName){
pageItems[i].itemLayer = myDoc.objectStyles.item(objStyleName);
iterator++;
}
// locking back locked paragraphs
if(paragraphWasLocked){
pageItems[i].locked = true;
}
}catch(e){
alert(e, "Script Error", true);
}
}
}
}
}
Hi @LynxKx , here’s a version that uses the InDesign dialog class to return the selected styles—osSel & psSel return the dialog’s selected Object and Paragraph styles
makeDialog();
var osSel, psSel;
function makeDialog(){
var theDialog = app.dialogs.add({name:"Dialog Components", canCancel:true});
with(theDialog){
with(dialogColumns.add()){
with(dialogColumns.add()){
staticTexts.add({staticLabel:"Object Styles:"});
st
...
Copy link to clipboard
Copied
Hi @LynxKx,
I've written a bare bones script to do what (I think) you want. I haven't modified your existing script though, so you might need to meld them together. For example my script uses a hard-coded lookup array of paragraph style to object style pairs, so you may want to incorporate your existing UI for that part. See how you go with that—it will be a great exercise I hope, but let me know if you get stuck. I have written the getByName function to handle object styles in folders.
- Mark
/*
Set Object Style by Paragraph Style
for Indesign 2022
by m1b
here: https://community.adobe.com/t5/indesign-discussions/help-adjusting-a-script-i-found-to-change-text-frame-object-style-based-on-paragraph-style/m-p/12903549
*/
// array of paragraph-style-to-object-style lookups
// note: if two lookups match the same text frame
// only the first will be applied
var lookups = [
{ paragraphStyleName: 'Green', objectStyleName: 'Blue' },
{ paragraphStyleName: 'Blue', objectStyleName: 'Green' }
]
function main() {
var doc = app.activeDocument,
textFrames = doc.textFrames;
// resolve the objectStyle for each lookup
for (var i = 0; i < lookups.length; i++) {
var objectStyle = getByName(doc.allObjectStyles, lookups[i].objectStyleName);
if (objectStyle != undefined && objectStyle.isValid) {
lookups[i].objectStyle = objectStyle;
}
else {
alert('Could not find object style "' + lookups[i].objectStyleName + '" in document.');
return;
}
}
// look through each text frame for paragraphs with style
var counter = 0;
textFrameLoop:
for (var i = 0; i < textFrames.length; i++) {
for (var j = 0; j < lookups.length; j++) {
var lookup = lookups[j];
if (hasAppliedParagraphStyle(textFrames[i], lookup.paragraphStyleName)) {
// found a match, so apply the object style
textFrames[i].appliedObjectStyle = lookup.objectStyle;
counter++;
continue textFrameLoop;
}
}
}
// finished
alert("Changed " + counter + " text frame's object styles.");
function hasAppliedParagraphStyle(textFrame, paragraphStyleName) {
// returns true if any paragraph of textFrame
// has paragraphStyle paragraphStyleName applied
var paras = textFrame.paragraphs;
for (var i = 0; i < paras.length; i++) {
if (paragraphStyleName == paras[i].appliedParagraphStyle.name)
return true;
}
return false;
}
function getByName(styles, name) {
for (var i = 0; i < styles.length; i++)
if (styles[i].name == name)
return styles[i];
}
} // end main
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Set Object Style by Paragraph Style');
Copy link to clipboard
Copied
maybe if i break it down a little further, i could probably figure it out if someone can help with the dropdown list. I need to have all my ObjectStyles pulled into a dropdownlist where it also references the folder name they live in.
var applyObjStyle = w.add("dropdownlist", undefined, myDoc.objectStyles.everyItem().name); // how do I adjust this language to include all styles in folder and preferrably show the folder name with the style as well
applyObjStyle.selection = 0;
Copy link to clipboard
Copied
this code does work great to get the what I need done for right now, I just dont want to have to make a new script for every occurance that comes up. Thank you! I'm going to try and take pieces and see if I can get my original concept to work with how you set this up!
Copy link to clipboard
Copied
in case anyone wants it ... i jsut figured out the object list part
myObjStyles = myDoc.allObjectStyles;
var myObjStylesList = [];
for (i = 0; i < myObjStyles.length; i ++){
myObjStylesList[i] = myObjStyles[i].name;
if (myObjStyles[i].parent.constructor.name == "ObjectStyleGroup") myObjStylesList[i]+=" ["+myObjStyles[i].parent.name+"]";
}
w.add("statictext", undefined, "Move all objects with");
var list1 = w.add("dropdownlist", undefined, myObjStylesList); // Object style list
list1.selection = 0;
Copy link to clipboard
Copied
REALLY WISH I could edit my posts! ... my code is pulling in the styles now but the action in the code isnt working when I select one thats in a folder.
Copy link to clipboard
Copied
Hi @LynxKx, you are making progress! By the way, you should be able to edit your posts here. Click on the "More" button under your post and "Edit Reply".
If you want to show the style folders, perhaps you could make an array myStylesArray of objects that are something like this:
{
styleName: "myObjectStyle", // just the style name
folderName: "myStyleFolder" // this could be left undefined
style: myObjectStyle // the actual style
}
Then make the drop down menu by iterating over this array and adding either just the styleName property, or prefixing with the folderName, eg.
myStylesArray[i].folderName == undefined ? '' : myStylesArray[i].folderName + '/' + myStylesArray[i].styleName;
- Mark
Copy link to clipboard
Copied
I'm not sure if its because I'm just a 'participant' ... but I dont have those edit options for my posts 😕
I'd like to be able to use the script for mutliple things, and some files may or may not have the same folders and styles, so listing out any specific ones wont work ... i've got the code to pull in all the styles ... but the final script doesnt work if I select a style that is in a folder.
Copy link to clipboard
Copied
@LynxKx wrote:
I'm not sure if its because I'm just a 'participant' ... but I dont have those edit options for my posts 😕
That's weird. I've always been able to edit my posts. Have you tried a different browser? See my screenshot.
@LynxKx wrote:
... but the final script doesnt work if I select a style that is in a folder.
That's why you need something like my getByName function. It works even if the style is in a folder.
- Mark
Copy link to clipboard
Copied
Hi @LynxKx , here’s a version that uses the InDesign dialog class to return the selected styles—osSel & psSel return the dialog’s selected Object and Paragraph styles
makeDialog();
var osSel, psSel;
function makeDialog(){
var theDialog = app.dialogs.add({name:"Dialog Components", canCancel:true});
with(theDialog){
with(dialogColumns.add()){
with(dialogColumns.add()){
staticTexts.add({staticLabel:"Object Styles:"});
staticTexts.add({staticLabel:"Paragraph Styles:"});
}
with(dialogColumns.add()){
osSel = dropdowns.add({stringList:getStyles(app.activeDocument.allObjectStyles), selectedIndex:0, minWidth:80});
psSel = dropdowns.add({stringList:getStyles(app.activeDocument.allParagraphStyles), selectedIndex:0, minWidth:80});
}
}
if(theDialog.show() == true){
osSel = app.activeDocument.allObjectStyles[osSel.selectedIndex];
psSel = app.activeDocument.allParagraphStyles[psSel.selectedIndex];
main();
theDialog.destroy();
}
}
}
function main(){
alert("\rChosen Object Style: " + osSel.name + "\rChosen Paragraph Style: " + psSel.name);
return
}
/**
* Returns a list of style names from the provided array of styles
* @ param the object array
* @ return array of names
*/
function getStyles(p){
var a = new Array;
for(var i = 0; i < p.length; i++){
a.push(p[i].name);
}
return a
}
Copy link to clipboard
Copied
thank you! this has worked so nice and has been really helpful to learn from!
Copy link to clipboard
Copied
I won't tackle the entire script, but I will offer my functions for gathering styles, which might help that part anyway. Or help anyone else who happens upon this discussion looking for a solution to gathering styles. Character, Object, and Paragraph styles all have the same problem that "sub-styles" (items inside subfolders in the list) are not included in the top level style array. Here are my three functions that each get the root sytles plus all in style groups too. The functions return an array of the style objects. To use, call any of them and pass the active document.
// To use call and pass active document.
// For example...
var characterStyles = getCharacterStyles(app.activeDocument);
// etc.
function getCharacterStyles(o) {
var a = [];
var i;
// Root styles.
for (i = 0; i < o.characterStyles.length; i++) {
a.push(o.characterStyles[i]);
}
// Style groups.
for (i = 0; i < o.characterStyleGroups.length; i++) {
// Recursive; calls itself.
a = a.concat(getCharacterStyles(o.characterStyleGroups[i]));
}
return a;
}
function getObjectStyles(o) {
var a = [];
var i;
// Root styles.
for (i = 0; i < o.objectStyles.length; i++) {
a.push(o.objectStyles[i]);
}
// Style groups.
for (i = 0; i < o.objectStyleGroups.length; i++) {
// Recursive; calls itself.
a = a.concat(getObjectStyles(o.objectStyleGroups[i]));
}
return a;
}
function getParagraphStyles(o) {
var a = [];
var i;
// Root styles.
for (i = 0; i < o.paragraphStyles.length; i++) {
a.push(o.paragraphStyles[i]);
}
// Style groups.
for (i = 0; i < o.paragraphStyleGroups.length; i++) {
// Recursive; calls itself.
a = a.concat(getParagraphStyles(o.paragraphStyleGroups[i]));
}
return a;
}
Copy link to clipboard
Copied
Hi William, the API also has allParagraphStyles, allCharacterStyles, and allObjectStyles which return arrays (not collections) of all the document’s styles. Try this which gets all paragraph styles including styles in folders:
var aps = app.activeDocument.allParagraphStyles
var i = aps.length;
while (i--) $.writeln(aps[i].name);
Copy link to clipboard
Copied
Nice. Missed that one. I will definitely put that to use. Thank you.
Copy link to clipboard
Copied
@LynxKx is using the Javascript window class, but for some dialogs I find the built-in dialog class is easier to code. Here’s the template I use for dropdowns, which includes functions for arrays (allParagraphStyles) and collections (PDFpresets) to get the dropdown lists.
makeDialog();
var psSel, pdfPreset;
function makeDialog(){
var theDialog = app.dialogs.add({name:"Dialog Components", canCancel:true});
with(theDialog){
with(dialogColumns.add()){
with(dialogColumns.add()){
staticTexts.add({staticLabel:"Paragraph Styles:"});
staticTexts.add({staticLabel:"PDF Presets:"});
}
with(dialogColumns.add()){
//array
psSel = dropdowns.add({stringList:getArrayNames(app.activeDocument.allParagraphStyles), selectedIndex:0, minWidth:80});
//Collection
pdfPreset = dropdowns.add({stringList:getCollection(app.pdfExportPresets), selectedIndex:3, minWidth:80});
}
}
if(theDialog.show() == true){
psSel = app.activeDocument.allParagraphStyles[psSel.selectedIndex];
pdfPreset = app.pdfExportPresets[pdfPreset.selectedIndex];
main();
theDialog.destroy();
}
}
}
function main(){
alert("\rChosen Paragraph Style: " + psSel.name+ "\rChosen PDF Preset: " + pdfPreset.name);
return
}
/**
* Returns a list of style names from the provided array of styles.
* Note does not work with a collection allParagraphStyles is an array paragraphStyles is a collection
* @ param the object array
* @ return array of names
*/
function getArrayNames(arr){
var a = new Array;
for(var i = 0; i < arr.length; i++){
a.push(arr[i].name);
}
return a
}
/**
* Returns a list of item names from the provided collection.
* @param the collection
* @return array of names
*/
function getCollection(o){
var a = new Array;
for(var i = 0; i < o.length; i++){
a.push(o.item(i).name);
}
return a
}
Copy link to clipboard
Copied
Hi William,
and the best thing about allParagraphStyles, allCharacterStyles and allObjectStyles is:
The array's order of styles is the order of styles you see in the panel from top to bottom.
If the parent of a given style is the document the style is in the "root" of the style's panel.
If not, the parent of a style is a style group.
Regards,
Uwe Laubender
( ACP )
Copy link to clipboard
Copied
Is there any way to have the parent group name show up or show a hierachy breakdown in the dropdown for better organizing?
Copy link to clipboard
Copied
Hi @LynxKx, here's one way:
/**
* Returns list of names, optionally including parent collection name
* @param {Document} doc - the document containing the styles
* @param {String} docProperty - allParagraphStyles|allCharacterStyles|allObjectStyles|allTableStyles|allCellStyles
* @param {Boolean} showParent - whether to prepend parent collection name
* @param {Boolean} includeBracketedStyles - whether to show [Bracketed] styles
* @return {Array}
*/
function getStyleNames(doc, docProperty, showParent, includeBracketedStyles) {
var names = [],
styles = doc[docProperty],
prefix,
delimiter = '/';
if (styles == undefined) return [];
for (var i = 0; i < styles.length; i++) {
prefix = '';
if (
!includeBracketedStyles
&& styles[i].name[0] == '['
) {
continue;
}
if (
showParent
&& styles[i].parent.constructor.name !== 'Document'
) {
prefix = styles[i].parent.name + delimiter;
}
names.push(prefix + styles[i].name);
}
return names;
};
Then you must maintain both a "styles" array (of allParagraphStyles for example) and a "names" array (the result of the above function) so when user selects a name via the dropdown you can reference the actual style in the "styles" array by the same index as the dropdown.
- Mark
Copy link to clipboard
Copied
I've been searching all over for a script for when I use a specific object style, it automatically places it on a specific layer. It sounds like the original script you found does what I'm looking for. Any chance you still have the original one? Also, I'm a script newbie so hopefully it's something straightforward I can copy and paste into my scripts panel. Thank you!
Copy link to clipboard
Copied
I do! here you go
var myDoc = app.activeDocument;
function getStyles(p){
var a = new Array;
for(var i = 0; i < p.length; i++){
a.push(p[i].name);
}
return a
}
makeDialog();
var objSel, layerSel;
function makeDialog(){
var theDialog = app.dialogs.add({name:"Objects to Layer Script Magic", canCancel:true});
with(theDialog){
with(dialogColumns.add()){
with(dialogColumns.add()){
staticTexts.add({staticLabel:"Move objects with:"});
staticTexts.add({staticLabel:"to layer:"});
}
with(dialogColumns.add()){
objSel = dropdowns.add({stringList:getStyles(myDoc.allObjectStyles), selectedIndex:0, minWidth:80});
layerSel = dropdowns.add({stringList:(myDoc.layers.everyItem().name)}); // Layers list
}
}
if(theDialog.show() == true){
objSel = myDoc.allObjectStyles[objSel.selectedIndex];
layerSel = myDoc.layers[layerSel.selectedIndex];
theDialog.destroy();
}
}
}
var pageItems = myDoc.pageItems;
if (parseFloat(app.version) < 6) // "app.version < 6" if it's running under an earlier version than CS4, as earlier versions don't support "Undo" in scripts
objLayerMove();
else
app.doScript(objLayerMove, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Move to layer");
//< END OF doUndoWraper
function objLayerMove(){
// unlock locked layers
var lockedLayers = {};
for(var layer = 0; layer < myDoc.layers.length; layer++){
lockedLayers[myDoc.layers[layer].name] = myDoc.layers[layer].locked;
myDoc.layers[layer].locked = false;
}
if(objSel && layerSel){
//for(var i = 0; i < pageItems.length; i++){
for(var i = --pageItems.length; i >= 0; i--){
if(pageItems[i].appliedObjectStyle.name === objSel.name && pageItems[i].itemLayer.name != layerSel.name){
try{
// unlock locked objects
var objectWasLocked = false;
if(pageItems[i].locked){
objectWasLocked = true;
pageItems[i].locked = false;
}
// move objects to layer
pageItems[i].itemLayer = myDoc.layers.item(layerSel.name);
// proceed until you bleed, lol!
var iterator = 0;
while(iterator < 1000 && pageItems[i].itemLayer.name != layerSel.name){
pageItems[i].itemLayer = myDoc.layers.item(layerSel.name);
iterator++;
}
// locking back locked objects
if(objectWasLocked){
pageItems[i].locked = true;
}
}catch(e){
alert(e, "Script Error", true);
}
}
}
}
}