12 Replies Latest reply on Dec 23, 2016 1:40 PM by Marc Autret

    pause javascript until display updates

    MilesBC Level 1

      My script works properly, but on occasion (depending on size of objects and what else my computer is doing at the time), the script crashes with an "Object not valid" error because the referenced object was not available yet.

      I have tried myDoc.recompose(), but this does not seem to affect it.

      I have used $.sleep(n milliseconds) but most of the time that adds unnecessary delays.

      Is there a way to get the script to wait until the targeted object has "arrived"?

      Thanks.

        • 1. Re: pause javascript until display updates
          Loic.Aigon Adobe Community Professional

          What does your script exactly ?

          • 2. Re: pause javascript until display updates
            MilesBC Level 1

            I have tried to simplify the code to make it clear. I hope I didn't make it worse.

            Task: Duplicateg a number of lines from the middle of a story in one document to a location at the end of a story in another document.

             

            . . . . .

            //make a reference (foundLines) to a range of lines from sourceStory (in doc1)

            var foundLines = sourceStory.lines.itemByRange(startLineNumber, endLineNumber);

            //duplicate foundlines at the end of myStory (in doc2)

            var mySnippet = foundLines.texts[0].duplicate(LocationOptions.AT_END, myStory);

            //the lines of mySnippet are now a single text in myStory  referenced by myStory.mySnippet[0].texts[0]

            //[I wish I understood better why the above is the case.]

            var snippetParagraph0 = myStory.mySnippet[0].texts[0].paragraphs[0];

            alert(snippetParagraph0.contents)

             

            Using the exact same doc1 and doc2 and the same startLineNumber and endLineNumber,

            sometimes this completes correctly and sometimes the last line generates an Object Not Valid error.

            If I put $.sleep(10000) before the last line, then it works all the time.

            Smaller sleep values work with other files. But the files are long and complex,

            and the lines take a long time (or so it seems) to "arrive safely" at myStory.

            But it is waiting 10 seconds dozens of times whether it needs to or not.

            And perhaps I'll encounter an instance where 10 seconds is not enough.

             

            After my original post today, I tried using a while loop containing a try {} catch () {} to repeated test the contents of the ending line of mySnippet against the original ending line in sourceStory until they match. This seems to be working.

            But it is rather clumsy, I think.

             

            I don't know anything about javascript events yet.

            Is there some "display finished updating" event that could announce that it is safe for the program to continue?

             

            From what I read, I thought myStory.recompose() would accomplish this. But it does not seem to have any effect.

             

            Thanks for your interest in helping,

            Miles

            • 3. Re: pause javascript until display updates
              Loic.Aigon Adobe Community Professional

              Hello,

               

              What is myStory.mySnippet[0] exactly. Given that myStory is a Story object, I can't find any property of type mySnippet.

               

              Loic

              • 4. Re: pause javascript until display updates
                Laubender Adobe Community Professional & MVP

                MilesBC wrote:

                //the lines of mySnippet are now a single text in myStory referenced by myStory.mySnippet[0].texts[0]

                //[I wish I understood better why the above is the case.]

                var snippetParagraph0 = myStory.mySnippet[0].texts[0].paragraphs[0];

                alert(snippetParagraph0.contents)

                 

                Hi Miles,

                 

                myStory.mySnippet[0] is indeed a problem.

                It should be:

                 

                var snippetParagraph0 = mySnippet[0].paragraphs[0];
                

                 

                To get that straight I would first test in a minimized controllable environment like that:

                 

                Docs-1-and-2-side-by-side.png

                Supposed the task is:

                1. To duplicate the lines colored cyan to the end of the story of that other document.

                ( Only the two documents are open, "Doc-1.indd" is the active document. )

                2. Do something with the first paragraph of the duplicated text. Be caucious what you want here!

                E.g. color that paragraph magenta.

                 

                Note: The black text above the cyan one does not end with a paragraph sign.

                 

                Here a snippet, that is not using your variable names, but the one of "mySnippet":

                 

                var source = app.documents[0]
                var target = app.documents[1];
                
                var sourceStory = source.stories[0];
                var targetStory = target.stories[0];
                
                // The text to duplicate:
                var foundLines = sourceStory.lines.itemByRange(2,5);
                
                var mySnippet = foundLines.texts[0].duplicate(LocationOptions.AT_END, targetStory);
                var mySnippetFirstParagraph = mySnippet[0].paragraphs[0];
                
                mySnippetFirstParagraph.fillColor = target.colors.itemByName("Magenta");
                

                 

                After running the snippet:

                 

                Docs-1-and-2-side-by-side-AFTER-running-snippet.png

                 

                 

                As you can see it worked.

                 

                Note: That paragraphs[0] of mySnippet will contain also some text that is not in mySnippet because the text in the target did not end with a paragraph sign.

                 

                If you wanted to change something with the text in mySnippet down to the first paragraph sign in mySnippet one has to do more calculations to get the right range of characters. A workaround would be to duplicate to a new text frame first, do the changes on the first paragraph and then move the text on to the intended story.

                 

                Will you add different text snippets to the same target story?

                That could be the culprit of your problems. InDesign's composition engine may be not ready before the next snippet comes in.

                 

                To recompose a story or at least a text frame one could move the anchor of a pathPoint back and forth.

                 

                var textFrame = app.selection[0];
                var plusX = 10;
                var plusY = 10;
                
                var posX = textFrame.paths[0].pathPoints[0].anchor[0];
                var posY = textFrame.paths[0].pathPoints[0].anchor[1];
                
                textFrame.paths[0].pathPoints[0].anchor = [ posX+plusX , posY+plusY ];
                textFrame.paths[0].pathPoints[0].anchor = [ posX , posY ];
                

                 

                 

                Regards,
                Uwe

                • 5. Re: pause javascript until display updates
                  MilesBC Level 1

                  Regarding

                  var snippetParagraph0 = myStory.mySnippet[0].texts[0].paragraphs[0];

                  Of course, that was not correct. Just a mistake I made as I attempted to present a simpler version. It should have been:

                  var snippetParagraph0 = mySnippet[0].texts[0].paragraphs[0];

                   

                  I am only duplicating full paragraphs so I won't have that problem you describe.

                  But I do need to edit the actual text of the duplicated lines, and that is where the javascript gets ahead of the composition engine.

                  Then I do copy more lines to the target document. But the problem occurs when I edit, before additional lines are duplicated.

                  Also, whether the problem happens depends on the length and complexity of the of the story. The longer the story, the more likely it is to occur.

                  So the composition engine is clearly falling behind as there is more recomposing to accomplish.

                   

                  Are you recommending that If I move that anchor back and forth, the script won't proceed until the story is recomposed?

                   

                  Also, perhaps you can clarify this for me:

                  var foundLines = sourceStory.lines.itemByRange(startLineNumber, endLineNumber);

                  So foundLines is an array containing 1 item (a text of several lines), and that item has constructor name Line! Why isn't it Text?

                  So foundLines[0] is a Line.

                  Next, foundLines[0].lines.length is actually the number of lines duplicated.

                  YetI can't reference it with foundLines[0].lines[0, 1, 2, etc.].

                  I can only reference it with foundLines[0].texts[0].lines[0, 1, 2, etc.].

                  I stumble on this too often.

                   

                  Thank you for enlightening help and for pointing me in the right direction.

                  Miles

                  • 6. Re: pause javascript until display updates
                    Laubender Adobe Community Professional & MVP

                    Hi Miles,

                    as I already suggested to get rid of the composition problem:

                     

                    1. Duplicate the text to a new temporary text frame in the target document.

                    2. Do your editing within that little story.

                    3. Then move the story to its intended insertion point.

                    4. Remove the temporary text frame.

                     

                    And again (I'm not sure at all):

                    Will you add different text snippets to the same target story?

                    If so move the texts in reverse order to the complex story.
                    Use the highest index numbers of the target insertion points first so that the new composition of text will work always after the inserted text.

                     

                    Regards,
                    Uwe

                    • 7. Re: pause javascript until display updates
                      Jump_Over Level 5

                      Hi Miles,

                       

                      MilesBC napisał(-a):

                       

                      ...

                      var foundLines = sourceStory.lines.itemByRange(startLineNumber, endLineNumber);

                      So foundLines is an array containing 1 item (a text of several lines), and that item has constructor name Line! Why isn't it Text?

                      ....

                      Similar to result of story.lines.everyItem() ==> your foundLines is not an array but some kind of "naive collection"

                      See a great explanation here

                      http://www.indiscripts.com/post/2010/06/on-everyitem-part-1

                       

                      Short answer - if your goal is to output as an array - use:

                      var foundLines = sourceStory.lines.itemByRange(startLineNumber, endLineNumber).lines.everyItem().getElements()

                       

                      Jarek

                      • 8. Re: pause javascript until display updates
                        MilesBC Level 1

                        Some of the sections to be duplicated are lengthy. So I had to open them in a temporary file instead of a temporary frame. (Perhaps that eliminated the benefit.) I edit the temporary file and then duplicate the text.

                        The completed file is composed of dozens of duplicated texts, some long and some short, as well as many single-line paragraphs produced directly from the script.

                        Regarding your recommendation:

                        <<Use the highest index numbers of the target insertion points first so that the new composition of text will work always after the inserted text.>>

                        I am not sure I understand what you say here. But composing the entire project from end to start would require a complete revision of the script, which I cannot attempt at this time. I could try rewriting before I begin the next edition. Is that what you are suggesting -- entering all the lines in reverse order?

                        • 9. Re: pause javascript until display updates
                          MilesBC Level 1

                          Thanks for the reference to the article. Actually, I recognized it as something I read a few years ago when I was just starting to write scripts. It made my head swim, and I forgot about it. Now that I understand the object model much better, rereading it was quite helpful. Still, in practice I have questions.

                          My end goal is not an Array, but a Text that I can duplicate.

                          Is there any difference between:

                          var dupLines = sourceStory.lines.itemByRange(startLine, endLine).everyItem().duplicate(LocationOptions.AT_END, myStory);

                          and

                          var dupLines = sourceStory.lines.itemByRange(startLine, endLine).duplicate(LocationOptions.AT_END, myStory);

                          It appears to me I get the same result.

                          Thanks.

                          • 10. Re: pause javascript until display updates
                            Marc Autret Level 4

                            Is there any difference between:

                            var dupLines = sourceStory.lines.itemByRange(startLine, endLine).everyItem().duplicate(LocationOptions.AT_END, myStory);

                            and

                            var dupLines = sourceStory.lines.itemByRange(startLine, endLine).duplicate(LocationOptions.AT_END, myStory);

                            The first line should cause an error, since sourceStory.lines.itemByRange(startLine, endLine) is a Line specifier and everyItem() is not a method available from a specifier—it is only available from a collection. So you probably meant

                             

                            (1) sourceStory.lines.itemByRange(startLine, endLine).lines.everyItem()

                              vs.

                            (2) sourceStory.lines.itemByRange(startLine, endLine)

                             

                            didn't you?

                             

                            What is sure is that syntax (1) is not a good idea at all, even if the duplicate() command leads to the same result in both cases. Indeed (1) will resolve to an Array of Line instances (which finally coerces into an Array of text ranges) while (2) directly resolves to a Text instance, that is, a text range. Therefore, there are serious (if not obvious) reasons to suppose that syntax (2) is faster and might even be dramatically faster in high volume contexts.

                             

                            So I strongly suggest you keep going with the simplest command,

                            sourceStory.lines.itemByRange(startLine, endLine).duplicate(LocationOptions.AT_END, targetStory);

                             

                            I also suggest that you save the number +LocationOptions.AT_END in a constant (const LO_END=+LocationOptions.AT_END) so that you can use

                            sourceStory.lines.itemByRange(startLine, endLine).duplicate(LO_END, targetStory);

                            in your loop process. (Thus, you won't endlessly invoke unnecessary DOM commands.)

                             

                            However, you still seem to have a runtime performance issue, maybe related to unresolved specifiers (?) and/or recomposition delay (?) I'm surprised, though, that duplicating Text instances into a Story might cause such problems, since Stories are nonvisual entities (by contrast with TextFrames) that usually work fine and fast even in overset (=hidden) areas. By the way, a trick I often use when dealing with just feeding a story (disregarding layout and composition questions) is deliberately using a small frame (overflows==true) during the text process, then adjusting, chaining and so on at the very end. This way InDesign is not made too busy at performing background refreshes etc.

                             

                            But this implies that you don't need to keep track of those dupLines within the target story. Why do you need them? Remember that lines require an up-to-date layout while insertion points or characters do not. If the source story is stable, you can safely resolve input lines into basic text ranges (as done in syntax 2) then duplicate those guys at the end of the target story—or maybe into targetStory.insertionPoints[-1] if really there seems to be Text resolution issues—but anyway I don't figure out why that should be so long, even in huge documents.

                             

                            So there is probably something else that we aren't aware of. Without seeing your code it's hard to conclude.

                             

                            @+

                            Marc

                            2 people found this helpful
                            • 11. Re: pause javascript until display updates
                              MilesBC Level 1

                              That is a lot to digest. It will take me a while to understand all the subtle (to me, at least) distinctions in these syntax constructions. Thanks in advance for your teaching.

                               

                              However, late last night I figured out a fix for the errors caused by apparent occasional slowness of the composition engine, which was my original problem. After repeated testing, it turns out that these problems occur only at the end of the current last page of the document. With Smart Text Flow selected, the last textFrame is overset for a short interval while a new page is created. I think that during that interval, if the script continues to run and accesses the temporarily overset text, the invalid object error is generated.

                              I turned off Smart Text Flow, made a file of many, many pages with threaded textFrames. Magically, all these errors disappeared.

                              Now I imagine if I checked for an overset frame before trying to access the newly duplicated text, then perhaps I could reenable Smart Text Flow. (But it runs much faster with Smart Text Flow off.)

                              I learned a lot from everyone. Thanks for your teaching. When my head stops swimming, I am going to work on getting very clear on the differences between arrays of line instances, text ranges, specifiers, collections, and all these concepts I have so far gotten away with only a fuzzy understanding of.

                              Miles

                              1 person found this helpful
                              • 12. Re: pause javascript until display updates
                                Marc Autret Level 4
                                (…) With Smart Text Flow selected, the last textFrame is overset for a short interval while a new page is created. I think that during that interval, if the script continues to run and accesses the temporarily overset text, the invalid object error is generated.

                                I turned off Smart Text Flow, made a file of many, many pages with threaded textFrames. Magically, all these errors disappeared. (…)

                                Miles

                                Yes, and you can be 99% sure that Smart Text Reflow is at the root of your problem. (That was the missing piece.)

                                Indeed—among others tricks—do always deactivate TextPreference.smartTextReflow before processing a story from a huge loop.

                                 

                                @+

                                Marc

                                1 person found this helpful