6 Replies Latest reply on May 11, 2010 8:05 AM by srakete

    Script Optimization (JS CS4)

    TᴀW Adobe Community Professional & MVP

      I've written a script, and it's running so slowly I could almost do it myself at that speed. It's a script to convert text to a table in a special way based on the way the author has typed his document in Word (basically, the author typed a bunch of sentences in Hebrew, followed by a bunch of sentences in English. The script puts these into a side-by-side table).

       

      The script just creates a table (adding rows as it goes along), and copies the text from the paragraph to the appropriate cell. It can take it about 30 second to convert 16 lines into a table, really slow.

       

      I've run a debug with timing, and the worst offending lines are these:

       

      myChars.duplicate (LocationOptions.AT_BEGINNING, myCell); //myChars is the characters to be copied, and myCell the cell to coy them to.

       

      (clocks in at over  9,000,000 [what is that, millionths of a second?])

       

      and

       

      myChars.duplicate (LocationOptions.AT_BEGINNING, myCell);

       

      (clocks in at over 22,000,000!!)

       

      Is there anything I can do to improve this?

       

      If it helps, here is the complete script:

       

      //BSD 9May10
      //Turn Following Text into Table: An InDesign CS4 Javascript by Ariel Walden
      //This script will run through the text following the current cursor location, and turn it into a two column table as follows:
      //First it will expect to find a run of paragraph styles called "AWFaceToFaceTableHebrew"
      //These will become the rightmost column of the new table
      //Then it will expect to find a run of paragraph styles called "AWFaceToFaceTableEnglish"
      //These will become the leftmost column of the new table
      //The script will also add a blank line above and below the table, with paragraph style "AWSpace7pt"
      //No error checking takes place in this script
      //To run, place the cursor in a blank line (that you have probably added) directly before the run of paragraphs. Double-click the script.

      myIP = app.selection[0]; //get the current insertion point
      myIP.contents += "\r"; //add blank line
      myParas = myIP.paragraphs;
      myPara = myParas[0];
      myPara.appliedParagraphStyle = app.activeDocument.paragraphStyles.itemByName ("AWSpacer7pt"); //set style of blank line
      myPara = myParas.nextItem(myPara);
      myTablePara = myPara; //get reference to paragraph in which table will be
      myTable = myPara.tables.add(LocationOptions.AT_BEGINNING, undefined, {columnCount:2, bodyRowCount:1});
      myTable.appliedTableStyle = app.activeDocument.tableStyles.itemByName ("AWFaceToFaceTranslation");
      //myTable.bodyRowCount = 1;
      myRow = myTable.rows[0];
      //myTable.columnCount = 2;
      myTable.columns[0].width = "220pt";
      myTable.columns[1].width = "122.992pt";
      myPara = myParas.nextItem(myPara);
      while (myPara.appliedParagraphStyle.name == "AWFaceToFaceTableHebrew"){
      myCell = myRow.cells[1];
      myCell.appliedCellStyle = app.activeDocument.cellStyles.itemByName ("AWFaceToFaceHebrew");
      myChars = myPara.characters.itemByRange(0, myPara.characters.length-2); //remove the hard return at end of paragraph
      myChars.duplicate (LocationOptions.AT_BEGINNING, myCell);
      myPara = myParas.nextItem(myPara);
      myRow = myTable.rows.add();
      }

      myRow = myTable.rows[0];
      while (myPara.appliedParagraphStyle.name == "AWFaceToFaceTableEnglish"){
      myCell = myRow.cells[0];
      myCell.appliedCellStyle = app.activeDocument.cellStyles.itemByName ("AWFaceToFaceEnglish");
      myChars = myPara.characters.itemByRange(0, myPara.characters.length-2);
      myChars.duplicate (LocationOptions.AT_BEGINNING, myCell);
      myPara = myParas.nextItem(myPara);
      myRow = myTable.rows.nextItem(myRow);
      }

      myTable.rows[-1].remove(); //there will always be a blank line at the end of the table. Remove
      myIP = myTablePara.paragraphs.nextItem(myTablePara).insertionPoints[0];
      myIP.contents = "\r"; //add blank line after table
      myIP.paragraphs[0].appliedParagraphStyle = app.activeDocument.paragraphStyles.itemByName ("AWSpacer7pt");

      Thanks,

      Ariel

        • 1. Re: Script Optimization (JS CS4)
          [Jongware] Most Valuable Participant

          Hi Arïel,

           

          It's always hard to debug other's scripts, so I wrote one myself  It's a bit rough around the edges but it seems to do the job per request, and in a reasonable time.

          I have no idea why a simple "duplicate" command would take 9 million ticks -- no matter how small one single tick is! 30 seconds to create and fill a 16-line table is way, way too long.

           

          This script works different from yours. Have the cursor on a blank line before your text runs -- this is where it will put the table. It first counts down for the first style, then for the second style. While counting down, it stores the start of each paragraph in an array; then, it creates a table of the correct dimensions (yup, one single command ). Final step is to move the paragraphs straight into their cells.

           

          Because the push/pop mechanism reverses the order of paragraphs, these are reversed back before pop'ing them into the cells. I actually thought that wouldn't work, because, well, you know by now you should "change" a document from back to front, to prevent earlier changes messing up the character count. For some reason that does not apply here ... -- so I took out a lot of reverse-counting-into-table-rows stuff ... It seems to work, miraculously.

           

          I didn't include all your stuff about paragraph and cell styles, but I managed to stuff in a small bonus: if the cell ends with a hard return, that gets clipped off in the process.

           

          Do try on a copy of your data first, or change the "move" stuff back to "duplicate' (although I would think you'd like to move it, move it, Move It).

           

          Hope it's of some use to you, even though I couldn't answer your question!

           

          count1 = 0;
          
          list1 = [];
          
          // start on paragraph below the cursor
          scandown1 = app.selection[0].parentStory.paragraphs.nextItem(app.selection[0].paragraphs[0]);
          while (scandown1.appliedParagraphStyle.name == "text")
          {
               list1.push (scandown1);
               count1++;
               scandown1 = scandown1.parentStory.paragraphs.nextItem(scandown1);
               // Stop on blank line ...
               if (scandown1.contents.length < 2)
                    break;
          }
          alert (count1);
          
          count2 = 0;
          list2 = [];
          scandown2 = scandown1;
          // Skip blank lines ..
          while (scandown2.contents.length < 2)
               scandown2 = scandown2.parentStory.paragraphs.nextItem(scandown2);
          
          // Gather more paragraphs
          while (scandown2.appliedParagraphStyle.name == "text too")
          {
               list2.push (scandown2);
               count2++;
               scandown2 = scandown2.parentStory.paragraphs.nextItem(scandown2);
               // Stop on end of story or blank line ...
               if (scandown2 == null || scandown2.contents.length < 2)
                    break;
          }
          alert (count2);
          
          if (count1 > count2)
               count1 = count2;
          
          list1.reverse();
          list2.reverse();
          table = app.selection[0].tables.add(LocationOptions.AFTER, app.selection[0].insertionPoints[0], {columnCount:2, headerRowCount:0, bodyRowCount:count1, footerRowCount:0});
          
          for (i=0; i<count1; i++)
          {
               p = list2.pop();
               p.move (LocationOptions.UNKNOWN, table.rows[i].cells[0]);
               if (table.rows[i].cells[0].characters[-1].contents == '\r')
                    table.rows[i].cells[0].characters[-1].contents = "";
               p = list1.pop();
               p.move (LocationOptions.UNKNOWN, table.rows[i].cells[1]);
               if (table.rows[i].cells[1].characters[-1].contents == '\r')
                    table.rows[i].cells[1].characters[-1].contents = "";
          }
           
          

          1 person found this helpful
          • 2. Re: Script Optimization (JS CS4)
            [Jongware] Most Valuable Participant

            Another idea seems to work as well.

             

            After collecting the right paragraphs, you can immediately use 'convertToTable' on a selected range of paragraphs -- this works, because you 'know' the first and last paragraph at this point. But if you use "paragraphs", this includes the final hard return, and you'll get an empty row at the end! Fortunately, if you have the paragraphs, you also have access to their characters, so you can use list[0].characters up to list[last].characters[up-to-last-minus 1] as input for convertToTable. (I don't feel like experimenting why it actually needs minus 2 right now...)

             

            So, 'select' the first set of paragraphs, convert to table -- which, oddly, returns a Table Array, rather than what it says in the Help! --, add a column before the first one, move the other stuff into it. Piece of cake:

             

            // list1.reverse();
            list2.reverse();
            // table = app.selection[0].tables.add(LocationOptions.AFTER, app.selection[0].insertionPoints[0], {columnCount:2, headerRowCount:0, bodyRowCount:count1, footerRowCount:0});
            table = app.selection[0].parentStory.characters.itemByRange (list1[0].characters[0], list1[list1.length-1].characters[list1[list1.length-1].characters.length-2]).convertToTable();
            table = table[0];  // !!!! NOT IN DOCUMENTATION !!!!
            table.columns.add (LocationOptions.BEFORE, table.columns[0]);
            
            for (i=0; i<count1; i++)
            {
                 p = list2.pop();
                 p.move (LocationOptions.UNKNOWN, table.rows[i].cells[0]);
                 if (table.rows[i].cells[0].characters[-1].contents == '\r')
                      table.rows[i].cells[0].characters[-1].contents = "";
            /*     p = list1.pop();
                 p.move (LocationOptions.UNKNOWN, table.rows[i].cells[1]);
                 if (table.rows[i].cells[1].characters[-1].contents == '\r')
                      table.rows[i].cells[1].characters[-1].contents = ""; */
            }
            

            • 3. Re: Script Optimization (JS CS4)
              TᴀW Adobe Community Professional & MVP

              Jongware, thanks very much for taking the trouble to do this.

               

              I'm referring to your first script (haven't looked at the second one yet). I haven't tried it, but I did go over it and it makes sense and is much less anarchic than mine.

               

              Only one question: Your code is:

               

              scandown1 = app.selection[0].parentStory.paragraphs.nextItem(app.selection[0].paragraphs[0]);

              Why not:

               

              scandown1 = app.selection[0].paragraphs[0].nextItem(app.selection[0].paragraphs[0]);

               

              ?

               

              After experimenting, I saw that my script was much much faster if the story was shorter. The story I was running it in had 2500 lines.

              • 4. Re: Script Optimization (JS CS4)
                TᴀW Adobe Community Professional & MVP

                The second script is probably more efficient.

                 

                I've spent time working on my own script (while you were writing yours), and have to stick with that because it's got more "features" that I need.

                I made it go much faster. Instead of beginning with the user placing the cursor in the text (like your script presumes), it requires the user to manually select all the necessary paragraphs. Then it works with the selection. For some reason this is much faster.

                 

                It also takes care of the necessary specific styles I need. Plus, one thing which is a real pain, is footnotes. What happens if you script  a "convert text to table"? In UI, you get a dialog warning that you'll lose the footnotes. I haven't tried it in a script. Maybe it's worth experimenting later.

                 

                Anyway, my script makes an effort to add "fake" footnote indicators inside the table. I would post it, but I don't know how to get that mono-width text frame thing that you post your scripts in. :-(

                 

                By the way, I wrote a script that converts ALL character overrides in a document to character styles (any combination of fonts, fonts weights, point size, language, etc. etc.) I can send it to you if you're interested. It's fairly quick.

                 

                Ariel

                 

                PS (I hate this forum interface. It's almost as slow as my script.)

                • 5. Re: Script Optimization (JS CS4)
                  [Jongware] Most Valuable Participant
                  Only one question: Your code is [...]

                   

                  Yeah, well ...  For some reason that stuck in my mind as the 'proper' way. In

                   

                  scandown1 = app.selection[0].paragraphs[0].[etc..]

                   

                  you cannot refer to app.selection[0].paragraphs[1] -- only when that's inside your selection. So I go up one level, to the parent story, and pick up the next item from there. So -- that's not necessary?

                   

                  After experimenting, I saw that my script was much much faster if the story was shorter. The story I was running it in had 2500 lines.

                   

                  I agree. My test text was only 32 paragraphs. Walking over the first 16 was a breeze; the next 16 already took way, way longer. A while ago I examined the code for the XHTML export script -- that was a great learning experience, because it uses *all* possible tricks to speed up walking over text.

                   

                  (Addendum 1) Blatner Tools ...

                  (Addendum 2) In the Forum editor: >> Syntax highlighting > Java (actually, it should be called "Javascript")

                  • 6. Re: Script Optimization (JS CS4)
                    srakete Level 1

                    Hi,

                     

                    try to avoid nextItem(myPara) and work with paras.item(nextParagraphIndex)

                     

                    Stefan