Skip to main content
michaels64592398
Participant
January 18, 2020
Question

Get object of items by script label

  • January 18, 2020
  • 4 replies
  • 5469 views

InDesign 2018, javascript

Proprietary Proofing Script supporting Client facing Storefront

 

I've come to conclude the only way to obtain an Object of items with a specified Script Label is to iterate

allPageItems. The issue is iterating allPageItems is time costly when there are a lot, over 500. We have legacy applescript code (CS 5.5) that allowed to create an Object of items by a specific Script Label. Wondering if javascript simpy never supported previous mentioned?

This topic has been closed for replies.

4 replies

Community Expert
January 20, 2020

Hi Rob,

I could be wrong on this, but my explanation why allPageItems is very fast would be:
allPageItems is not created by the ExtendScript architecture that is on top of everything else but allPageItems is directly done and exposed to the scripting layer with CC++ code.

 

Regards,
Uwe Laubender

( ACP )

rob day
Community Expert
Community Expert
January 20, 2020

Thanks Uwe, Coming from AppleScript I can see why Michael would assume getting all the page items would be the slowest option. At first I thought my Date() timers were wrong—even at 10000 items it’s under 5 sec on an oldish iMac.

Community Expert
January 19, 2020

Michael said:

We have legacy applescript code (CS 5.5) that allowed to create an Object of items by a specific Script Label.

 

Can you share that code?

Maybe we can then see if it is possible or efficient to port it to ExtendScript.

 

Hm. That said: Does your legacy code use the allPageItems array?

And you are lookin for a faster way to do things?

 

Regards,
Uwe Laubender

( ACP )

rob day
Community Expert
Community Expert
January 19, 2020

I tested the two Applescripts, all page items vs. every page item, on a doc with 2000 page items, and there was no significant performance difference—took around 7 secs to change the fill on 700 labeled items, so my AS example will not help.

 

This all page items JS was faster at 3 sec

 

 

var pi = app.documents[0].allPageItems

var redarray = []

for(i = 0; i < pi.length; i++){
    if (pi[i].label == "red") {
        pi[i].fillColor = "gray"
        redarray.push(pi[i])
    }
}
$.writeln(redarray)

 

 

 

 

michaels64592398
Participant
January 20, 2020

Okay, first I thank you all for the quick replies. Amazing. We will review the option of getting a collection of items using earlier scripting environment. It is very quick so I assume some sort of indexing is used.

The root cause to our issue is design. We were looking for a seemless way to correct the issue.

We ran into with a Postcard Calander Template. A Designer outlined all the fonts therefore creating over 500 items. Our Proofing Engine provides methods to colorize 1-bit tiff's and text. Spec's allow 3 different colors for each. Proofing sepc's also indicate any item subject to color change must be a top level page item, no exceptions. As previously mentioned iterating 500 Items is time consuming. As it relates to returing proofs as quickly as possible. The legacy as code I mentioned earlier as follows,

<<

tell application "Adobe InDesign CC 2018"
set doc to document 1
set iName to "Image3"

tell doc
-- our applescript script actually used "page item" which only returns the top level page items
--set itemsOBJ to every page item whose label is iName

-- contains will get items based on a subset of a string e.g. If iName was "Image" all items whom's label contained Image would be part of the collection
set itemCollection to every item of all page items whose label is iName
log ("Count of Item Collection: " & (count of itemCollection))

repeat with collectionItem in itemCollection
set collectionItemType to class of collectionItem
set collectionItemLabel to label of collectionItem
log ("Collection Item Type: " & collectionItemType)
log ("Collection Item Label: " & collectionItemLabel)

end repeat
end tell
end tell

>>

 

The issue occurs when looking for items that require color change. We are searching for an items label matching a given critera e.g. Image1, Image2 etc. Since we allow 3 color value sets we have to search document page 3 times. So 3 x 500 at about 5.5 seconds per loop to a total (Jeopardy theme plays here) of 17 seconds.

Long story short, I did not write this code but in my opinion we certainly can review ways to optimize.

 

For now I'm going to recommend Templates that may create many items are optimized by exporting all static items to a PDF and then placing that PDF into the Template. This will signifantly reduce page items and makes sense.

rob day
Community Expert
Community Expert
January 19, 2020

Are you trying to move the Applescript to Javascript, or just get the AS to run faster?

 

In AppleScript I can’t use a whose qualifier on all page items to get a limited list—it returns an error and I’m forced to loop thru the entire list:

 

 

 

tell application id "com.adobe.indesign"
	set api to all page items of active document whose label is "red"
	--returns "Can’t get all page items of active document of application \"Adobe InDesign CC 2018\" whose label = \"red\". Access not allowed." number -1723
end tell

 

 

 

I can use whose with every page item, but that only gets the top items and skips things like nested groups and anchors. So this only returns 2 of the 6 items with a "red" label because I’ve buried 4 of them in nested groups and text frames.

 

 

 

What might help would be to get an initial list via every page item whose label is..., and the concentate the list by looking inside of groups and text frames, which all page items will get. So this gets a list that includes all 6 of the frames labeled "red"—I think this could be easily translated into JS:

 

 

 

tell application id "com.adobe.indesign"
	
	--gets the top level page items
	set r to every page item of active document whose label is "red"
	
	--all apge items and check by class where we can use every page item of x whose...
	set api to all page items of active document
	
	repeat with x in api
		if class of x is group or class of x is text frame then
			set nr to (every page item of x whose label is "red")
			
			--add the found objects to the list
			set r to r & nr
		end if
	end repeat
	
	get count of r
	--returns 6
end tell

 

 

 

 

Community Expert
January 18, 2020

Hi Michael,

the best strategy to reduce the numbers of page items you like to visit depends on where you like to look into objects. Do you like to look inside nested structures like groups or anchored objects as well? Also buttons and multistate objects? Note objects perhaps? Then even allPageItems will not get them all.

 

If you want to gather only "first class" items of the document without nested structures and check for a specific label you could do two things:

 

1. Option: Create an array with:

app.documents[0].pageItems.everyItem().getElements();

and loop that array. It's length should be shorter than app.documents[0].allPageItems if your document contains nested structures. However it will also take its time to create it vs. allPageItems that is "already" available.

 

2. Option: Set back the scripting environment temporarily to the one of InDesign CS4 and get all the objects with:

app.documents[0].pageItems.item( "labelvalue");

 

Sample code for option 2:

var labelContents = "FindMe" ;

// Store the version of the current scripting environment:
var currentScriptingEnvironment = app.scriptPreferences.version ;

// Set the scripting environment to the version of InDesign CS4:
app.scriptPreferences.version = "6.0";

// Do something in the old CS4 environment
// Something that can only be done in the old environment like this:

var foundByLabelArray = 
app.documents[0].pageItems.item( labelContents ).getElements();

// IMPORTANT: Set the scripting environment back:
app.scriptPreferences.version = currentScriptingEnvironment;

// Loop through the foundByLabelArray and do something to the found elements:

for( var n=0; n<foundByLabelArray.length; n++ )
{
	foundByLabelArray[n].fillColor = "Magenta";
};

 

If you need all nested stuff as well I fear you'd need either loop the allPageItems array ( that does not cover all elements ) or you have to loop through all pageItems by ID until really all page items are visited.

 

Regards,
Uwe Laubender

( ACP )