Skip to main content
Inspiring
April 18, 2024
Answered

Iterate through Stories in page order

  • April 18, 2024
  • 2 replies
  • 1599 views
I'm using var myStories = app.activeDocument.stories to get all the stories in a document. I want to loop through the stories, but in page order, which is not strictly how InDesign references them. Any advice on how to iterate through (or first *sort* before iterating through) myStories in page order? Thank you!
This topic has been closed for replies.
Correct answer brian_p_dts

Use getElements() to convert the collection into an array, then use this sort function, like so: 

var myStories = app.activeDocument.stories.everyItem().getElements();
myStories.sort(function(a,b) {
    return a.textContainers[0].parentPage.documentOffset < b.textContainers[0].parentPage.documentOffset;
});

2 replies

Community Expert
April 19, 2024

Alternatively you can iterate the pages collection and each page has a textframes collection so you can get the story from the textframes.

-Manan

-Manan
Robert at ID-Tasker
Legend
April 19, 2024
quote

Alternatively you can iterate the pages collection and each page has a textframes collection so you can get the story from the textframes.

-Manan


By @Manan Joshi

 

But OP wants order for the whole document - not for the current page?

 

brian_p_dts
Community Expert
Community Expert
April 20, 2024

Hi Robert, Manan was talking about iterating through the whole page collection. Probably is a faster approach than what I proposed in a longer doc too. 

brian_p_dts
Community Expert
brian_p_dtsCommunity ExpertCorrect answer
Community Expert
April 19, 2024

Use getElements() to convert the collection into an array, then use this sort function, like so: 

var myStories = app.activeDocument.stories.everyItem().getElements();
myStories.sort(function(a,b) {
    return a.textContainers[0].parentPage.documentOffset < b.textContainers[0].parentPage.documentOffset;
});
Inspiring
April 19, 2024

Thank you~  haven't had a chance to do much testing yet but that appears to do it. In limited testing, I changed to > rather than a < in the sort. Using <, the story on the last page came up first.

Marc Autret
Legend
April 20, 2024

@Andrew24943677v30i 

 

Without wanting to criticize my colleagues, I strongly discourage the proposed solution (which anyway seems problematic in other respects), simply because commands such that 

 

a.textContainers[0].parentPage.documentOffset

 

within a custom sort function will explode the Scripting DOM as soon as the document contains a huge number of stories. In ExtendScript, a custom sort involves on average 5×N×Log(N) internal calls of the function.

 

Note. - You should also take care of possible runtime errors (e.g. parentPage may be null, etc) and other issues (what about master pages?)

 

As usual, the solution I suggest is based on generating safe UTF16 sort keys through one linear loop, calling the native Array.prototype.sort() and building the desired array. Safer and probably much faster with long documents.

 

Here is a quick implementation [not tested in depth but you get the idea]

 

 

function sortedStories(/*Document*/doc,  K,ev,r,a,i,t)
{
  // Init.
  const CHR = String.fromCharCode;
  K=doc.stories, ev=K.everyItem(), r=ev.id, a=ev.textContainers;

  // Make sort keys  ->  r[i] :: <key> + storyId
  for
  (
    i=r.length ; i-- ;
    // ---
    (t=a[i]).length              // Have we a container?
    && (t=t[0].parentPage)           // Have we a parent page?
    && 'Spread'===t.parent.constructor.name  // Skip master pages!
    ? ( r[i]=CHR(1+t.documentOffset)+r[i] )  // Make 1st char sortable, add the ID.
    : r.splice(i,1)
  );

  // Instant sort.
  r.sort();

  // Build array of sorted stories and return.
  for( i=r.length ; i-- ; r[i]=K.itemByID(parseInt(r[i].slice(1),10)) );
  return r;
};

var myStories = sortedStories(app.activeDocument);
// etc

 

 

[EDIT] Still, this is certainly not the optimal way to reach the goal, but I wanted to illustrate my point while keeping the textContainers[0].parentPage.documentOffset approach proposed by @brian_p_dts 

 

Best,

Marc