7 Replies Latest reply on Nov 13, 2013 3:03 PM by Xarquol

    [JS][CS5.5] Interrupting a script via ScriptUI

    Xarquol

      I have a script that automates the placement of PDFs onto pages based on an input XML file. It works splendidly, but I would like users to be able to interrupt the placement, particularly if they have accidentally passed the wrong XML file to the script!

       

      Since the total time taken for the PDF placements can be a while, I put up a simple palette window containing a progress bar to give an idea of progress. I also added a cancel button, but although the window appears to have focus at least some of the time during the placements, it never becomes possible to press the cancel button, nor to close the window. The mouse pointer is an hourglass the whole time.

       

      Below is a simplified test script that demonstrates the problem. I've only run it on CS5.5 on Windows XP, but I believe it should work at least as far back as CS4 on Mac and Windows. It asks for a PDF file and then places it in a new document 16 times. My PC is slow enough that it takes enough time overall to give me plenty of time to hit the cancel button, if it were possible to do so. If your machine is really fast, you might want to increase gridSize so that the script has more to do.

       

      Is there anything I can do such that my cancel button can be pressed? I don't need to see the PDF import window, so if that can and needs to be turned off, that's fine. I dabbled with chains of IdleTasks, and was able to press my cancel button, but the chain didn't always end, and I ended up locking things up nastily. I probably need to read up more on IdleTasks. There may be potential there, but I would like to support earlier than CS5 if possible, and IdleTasks were introduced in CS5.

       

      #target indesign
      
      (function() {
          var gridSize = 4;
      
          // Ask user for a PDF
          var pdfFilter =($.os.toLowerCase().indexOf("macintosh") != -1) ?
              (function(file) { return file.name.match(/\.pdf$/); }) : '*.pdf';
          var pdfFile = File.openDialog("Choose a small PDF to place...", pdfFilter);
          if (!pdfFile) { return; }
      
          // Show a simple progress bar
          var active = true;
          var win = new Window('palette', 'Placing ' + pdfFile.name);
          var label = win.add('statictext', undefined, '');
          label.preferredSize.width = 300;
          label.justify = 'left';
          var progressBar = win.add('progressbar', undefined, 0, gridSize * gridSize);
          progressBar.preferredSize = [ 300, 12 ];
          var cancelButton = win.add('button', undefined, 'Cancel');
          cancelButton.onClick = function() { win.close(); };
          win.onClose = function() { active = false; };
          win.show();
      
          // Make a grid of rectangles and place the PDF in each rectangle,
          // advancing the progress bar as we go
          var doc = app.documents.add();
          var page = doc.pages[0];
          var mp = page.marginPreferences;
          var originX = page.bounds[1] + mp.left;
          var originY = page.bounds[0] + mp.top;
          var rectWidth = (page.bounds[3] - mp.right - originX) / gridSize;
          var rectDepth = (page.bounds[2] - mp.bottom - originY) / gridSize;
          var placePDF = function(n) {
              var y = Math.floor(n / gridSize);
              var x = n % gridSize;
              label.text = 'Placing PDF in [ ' + x + ', ' + y + ' ]';
              var rect = page.rectangles.add();
              rect.geometricBounds = [
                  originY + y * rectDepth,
                  originX + x * rectWidth,
                  originY + (y + 1) * rectDepth,
                  originX + (x + 1) * rectWidth
              ];
              rect.strokeWeight = 0;
              var pdfList = rect.place(pdfFile);
              pdfList[0].fit(FitOptions.PROPORTIONALLY);
              (progressBar.value)++;
              // Even this sleep doesn't let me press the cancel button!
              //$.sleep(1000);
          }
          for (var i = 0; active && i < gridSize*gridSize; i++) {
              placePDF(i);
          }
          win.close();
      })();
      
        • 1. Re: [JS][CS5.5] Interrupting a script via ScriptUI
          TᴀW Adobe Community Professional & MVP

          Have you tried:

           

          (a) using addEventListener() instead of the built-in onClick to the

          button? Perhaps addEventListener is more sensitive?

           

          (b) perhaps try using addEventListener to the Window object instead of

          the button and seeing if that is more "sensitive" to events. (You could

          then of course test to see if it was the button that was clicked.)

           

          ?

           

          Just suggestions... haven't tried them myself.

           

          Ariel

          • 2. Re: [JS][CS5.5] Interrupting a script via ScriptUI
            TᴀW Adobe Community Professional & MVP

            Also, this business of stopping the script by setting active to false --

            I guess there's no reason that shouldn't work in theory, but I wonder if

            for some reason it just doesn't. Have you tried a simple alert() in the

            onClick function, just to see if maybe the onClick is registering, but

            the active=false business isn't?

            • 3. Re: [JS][CS5.5] Interrupting a script via ScriptUI
              Xarquol Level 1

              Sadly, neither of your suggestions in reply 1 appear to make any difference.

               

              Out of interest though, how would I additionally test that the button had been clicked if the Window held the event listener, rather than the button?

               

              In regards to reply 2, an extra alert does not show itself either. If the onClick was being acted upon, my window would close. It is only when the window closes that the "active" boolean is set to false to terminate the placement loop, but my window remains open no matter how often I click.

               

              I think the trouble is really that I'm expecting multi-threaded behaviour (one thread for the placement loop, one to look after the gui and process clicks) when in reality there is only one thread, and it's busy placing PDFs. I wonder though if there is some pseudo-way to carve up the single thread and get it to check GUI state often enough to get what I want. As I said earlier, using IdleTasks sort of works in principle, but can get a little out of control!

              • 4. Re: [JS][CS5.5] Interrupting a script via ScriptUI
                TᴀW Adobe Community Professional & MVP

                Like this:

                 

                w = new Window("dialog");

                b = w.add("button", undefined, "Hello");

                w.addEventListener("mouseup", myEvent);

                w.show();

                 

                function myEvent(e){

                     alert(e.target);

                }

                 

                Ariel

                 

                PS Sorry that it's not all carefully wrapped up in anonymous functions

                and local variables like yours

                1 person found this helpful
                • 5. Re: [JS][CS5.5] Interrupting a script via ScriptUI
                  Trevorׅ Adobe Community Professional

                  Hi Ariel,

                   

                  Yet another example of SUI that doesn't work on CC

                  Can't use w.addEventListener

                  As far as I know the only thing on CC one can add an eventListener on the SUI is an Image.

                  On everything else it's all onClick etc.

                   

                  Pathetic to say the least (CC not your script!)

                   

                  Trevor

                  • 6. Re: [JS][CS5.5] Interrupting a script via ScriptUI
                    Marc Autret Level 4

                    Hi all,

                     

                    To my knowledge ScriptUI can only process 'update' events while your heavy routine is running. As a workaround Roey Horns from Adobe suggested in the past that we "rely on InDesign's support for canceling scripts with the Esc key or Cmd-Period".

                     

                    Anyway, IdleTasks is definitely the way to go in CS5 and later.

                     

                    @+

                    Marc

                    • 7. Re: [JS][CS5.5] Interrupting a script via ScriptUI
                      Xarquol Level 1

                      Ah! I didn't know about Esc (and Cmd-.). That will do for my purposes I think. I only really need users to be able to abort after an "oops". Fortunately, the script interruption raises a ReferenceError, which I can catch and deal with tidily.

                       

                      Interestingly, Esc didn't seem to do anything when I ran my test script from the ExtendScript Toolkit, but worked fine when I ran it from the Scripts Panel.

                       

                      I might play some more with IdleTasks sometime, but given that I managed to completely lock up my session and prevent any more scripts from running while testing, I think I'll settle for the Esc key. I'm not sure, but I think at least of my users may be on CS4 anyway.

                       

                      It might not be the fabulous solution I was hoping for, but I'd count Marc's answer as "correct" :-)