Copy link to clipboard
Copied
Hi,
I'm writing my very first script, so this is probably a very basic question, but please bear with me. I am trying to change the color of all objects with the name 'Rood' in a specific layer. Now I was thinking to use an if statement to look for items called Rood, if it finds any, change their name and color and check again. When it doesn't find any Rood layers it should break out of the loop.
This is the snippet I wrote:
if (myEDlayer.pageItems.itemByName ("Rood").isValid) { //if there is an item called 'rood'
myEDlayer.pageItems.itemByName ("Rood").name = "Blauw"; //make the name 'blauw'
myEDlayer.pageItems.itemByName ("Blauw").fillColor = "Blauw (C=100, M=66, Y=0, K=0)"; //and change the color to blue
}
The problem is it only works for the first item called Rood and leaves the others alone. This makes me think I haven't wrote the .isValid part correctly. Could someone help me understand where I'm going wrong?
Thanks!
Actually this is a complicated issue, and feels like multiple InDesign bugs to me.
When you use ...item... functions on collections, in principle you can target multiple objects. A prominent example is the xmlElements collection with itemByName("myTag"), another more obvious example is the everyItem() function.
So I checked whether this also works for page items with the same name, but it doesn't.
$.writeln(myEDlayer.pageItems.itemByName ("Rood").getElements().length);
=> 1
getElements() should yield
...Copy link to clipboard
Copied
Hi,
Lets try and understand your code, now you queried the pageItems collection of the layer for an object with name "Rood" and then changed its name fillColor. So far so good, once this is done then we still need to add instructions in the code to keep looking for the next object in the layers pageItems collection with the name "Rood", this part of code is missing in your existing code.
Now this new thing can be done in two ways
Try any one of these two approaches and let us know if it worked.
-Manan
Copy link to clipboard
Copied
Actually this is a complicated issue, and feels like multiple InDesign bugs to me.
When you use ...item... functions on collections, in principle you can target multiple objects. A prominent example is the xmlElements collection with itemByName("myTag"), another more obvious example is the everyItem() function.
So I checked whether this also works for page items with the same name, but it doesn't.
$.writeln(myEDlayer.pageItems.itemByName ("Rood").getElements().length);
=> 1
getElements() should yield an array with all your candidate page items for the specifier expression itemByName() ....
When you run your script for the first time, select the renamed page item - in my case the other one with the original name was colorized. I'm not sure why, but smells like a caching problem, definitely another bug. It should have changed the color for the renamed item.
Another variant of the script that ran thru for me without the crash in the second run:
var rect = myEDlayer.pageItems.itemByName ("Rood").getElements()[0];
if (myEDlayer.pageItems.itemByName ("Rood").isValid) { //if there is an item called 'rood'
myEDlayer.pageItems.itemByName ("Rood").name = "Blauw"; //make the name 'blauw'
myEDlayer.pageItems.itemByName ("Blauw").fillColor = app.activeDocument.swatches.lastItem(); // my blue
}
the added first line var rect ... getElements() somehow changed the situation - but the color still modifies the wrong item.
One contributing factor could be that "pageitem" is a base class - your page items are actually rectangle or text frame or ...
if (myEDlayer.rectangles.itemByName ("Rood").isValid) { //if there is an item called 'rood'
myEDlayer.rectangles.itemByName ("Rood").name = "Blauw"; //make the name 'blauw'
myEDlayer.rectangles.itemByName ("Blauw").fillColor = app.activeDocument.swatches.lastItem();
}
Worked for me without exception, but still with the color at the wrong item.
In the short run you can work around the problem by modifying multiple properties with one assignment:
while(myEDlayer.pageItems.itemByName ("Rood").isValid)
myEDlayer.pageItems.itemByName("Rood").properties = {
name : "Blauw",
fillColor: app.activeDocument.swatches.lastItem()
};
Copy link to clipboard
Copied
Interesting observations Dirk Becker, i investigated a bit myself and found the following
var myEDlayer = app.activeDocument.layers[0]
if (myEDlayer.pageItems.itemByName ("Rood").isValid)
{ //if there is an item called 'rood'
var a = myEDlayer.pageItems.itemByName ("Rood")
a.name = "Blauw"; //make the name 'blauw'
a.fillColor = app.activeDocument.swatches.lastItem(); //and change the color to blue
}
However if the initial state of the document would have been such that the object Rood was upper in order than object Blauw, then the coloring works fine
So finally the solution would be to put the code in loop and either set the properties in one shot as suggested by Dirk, or hold the object in a variable and use that to set the properties.
-Manan
Copy link to clipboard
Copied
I hope Jeroen won't mind if we carry on the discussion.
Manan, the properties of those plural specifiers from the XML elements don't just return arrays, they are also writable. Same with methods. This works the same way as with everyItem(), or itemByRange.
var blue = app.activeDocument.swatches.lastItem();
app.activeDocument.pageItems.everyItem().fillColor = blue;
You can even work across multiple such expressions:
app.activeDocument.stories.everyItem().textFrames.everyItem().characters.firstItem().contents = "x";
Copy link to clipboard
Copied
Dirk, you are right about that, i did try and change the content of multiple objects using the content property and it worked just fine. I have used everyItem this way quite a bit but this xmlElement object was something new that i discovered today from your comment. However do you concur on my finding regarding the object order causing the problem of color being applied to the wrong object? Also any thoughts on why saving the object in a variable worked fine, isn't it supposed to resolve the object again even in this case.
Copy link to clipboard
Copied
https://forums.adobe.com/people/Dirk+Becker schreef
I hope Jeroen won't mind if we carry on the discussion.
Not al all. This is all going way over my head, but carry on!
Copy link to clipboard
Copied
Hi together,
see also into this old thread where huge changes in DOM between CS4 and CS5 were discussed.
The behavior of pageItem.itemByName("Name") or pageItem.item("Name") had changed dramatically with CS5:
Re: With CS5, some things have changed
See also what Dave Saunders is doing there with app.scriptPreferences.version !
So, if you create an object reference while working within the CS4 versioning engine it won't work when you move back into the CS5 engine. So, by converting to an array--by using getElements()--which is a core feature, you can pass objects effectively from one engine to the other.
Just to increase your confusion, jeroenh14992699 …
Regards,
Uwe
Copy link to clipboard
Copied
Thanks both, very helpful. I first tried a do-while loop as Manan suggested, but that only changed the name, not the color. Which is weird, cause it does mean the loop is working. Might be a bug as Dirk said. Anyways, tried Dirk's solution and that worked perfectly. Final snippet is this:
while (myEDlayer.pageItems.itemByName ("Rood").isValid) { //if there is an item called 'rood'
myEDlayer.pageItems.itemByName("Rood").properties = {
name : "Blauw",
fillColor: "Blauw (C=100, M=66, Y=0, K=0)"
};
}