15 Replies Latest reply on Oct 20, 2009 8:01 AM by AdobeScripts

    Scripting object position

    MrZaneE

      Hi All.

          I'm not new to scripting, however I've never scripted in InDesign. I need to work out an easy way to position an object (page number in a black box) on the edge of the page so that they are evenly distributed from the top to the bottom through a book (you've no doubt seen this as the bleed looks like a stripe running diagonally along the edge of the book). In other words;

       

      vertical position =  total height * (page number /total number of pages)

       

      To add to that it needs to run properly on multiple documents in the same book (ie run smoothly from page 1 to the last page and not reset for each document) using macs with CS4. Is it possible to attach a script to an object or does it require selecting each object and running the script, as that could be painful when adding / removing pages. Cheers,

      Z.

       

      PS kinda funny that the spell checker in here doesn't recognize "InDesign".

        • 1. Re: Scripting object position
          Kasyan Servetsky Level 5

          Hi,

           

          Here is my idea how to implement your task:

           

          var myDoc = app.documents.add();
          myDoc.viewPreferences.horizontalMeasurementUnits = myDoc.viewPreferences.verticalMeasurementUnits = MeasurementUnits.MILLIMETERS;
          myDoc.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
          for (p = 0; p < 22; p++) {
              myDoc.pages.add();
          }

           

          var myPages = myDoc.pages;
          var mySpreads = myDoc.spreads;
          var myRecHeight = myDoc.documentPreferences.pageHeight/mySpreads.length;

           

          var myY1position = 0;

           

          for (i = 0; i < mySpreads.length; i++) {
              var mySpread = mySpreads[i];
              var myY2position = myY1position + myRecHeight;
             
              for (j = 0; j < mySpread.pages.length; j++) {
                  var myPage = mySpread.pages[j];
             
                  if (myPage.side == PageSideOptions.RIGHT_HAND) {
                      var myX1position = 195; 
                      var myX2position = 215;
                  }
                  else {
                      var myX1position = 0;
                      var myX2position = 20;
                  }

           

                  var myTextFrame = myPage.textFrames.add();
                  myTextFrame.fillColor = myDoc.swatches.item(6);
                  myTextFrame.strokeColor = myDoc.swatches.item(0);
                  myTextFrame.geometricBounds = [myY1position, myX1position, myY2position, myX2position];
                  myTextFrame.contents = myPage.name;
              }
              myY1position = myY1position + myRecHeight;
          }

          1 person found this helpful
          • 2. /
            MrZaneE Level 1

            Thats a really good start! Fantastic. However that works if its a new document and I already know how many pages I will be using, which isn't the case, It'll be one of those things that'll need to change right up to the last minute (eg adding/removing/rearranging pages). Also could it have a paragraph/character style for the page number (i realize you can change the font if you edit the InDesign defaults but would be great if it could be adjusted via a style. Also an object style for the box would be cool. Thanks for the speedy response, really awesome,

            Z.

            • 3. Re: Scripting object position
              Kasyan Servetsky Level 5

              This script was written just to show you approach I would use to solve your task. I made it to create a new document for demonstration purposes — since I don't know the page size, number of pages in your document, units you work in, etc. Obviously that the real script should work with the active document. And of course all formatting should be done by applying styles.

              Since you change your files up to the last minute, I offer to label the text frames, e.g:

               

              var myTextFrame = myPage.textFrames.add();

              myTextFrame.label = "MyBlackBox";

               

              Then you will be able to easily remove all of them:

              myDoc.textFrames.item("MyBlackBox").remove();

              and rerun the script again.

               

              I think it's a good idea to create a dialog at start for a user to choose options — e.g. page range, add or remove boxes, etc.

               

              Are you going to start learning InDesign scripting and finishing the script yourself?

               

              Kasyan

              • 4. Re: Scripting object position
                MrZaneE Level 1

                I was hoping to learn InDesign Scripting however its a bit of a handfull. I have some students (Architecture and Landscape Architecture) who are working on the anual publication (a book) of student work. and they wanted to do this, thats when I thought I'd try to figure out a way to script it. I'm assuming theres no way for a script to identify the number of pages in the current book? Where a good place to start if I want to learn InDesign scripting (esp what can and can't be achieved)? By the way I didn't want to sound ungratefull in my previous post, very impressed so far. Got'a run, till later,

                Zane.

                • 5. Re: Scripting object position
                  [Jongware] Most Valuable Participant
                  I'm assuming theres no way for a script to identify the number of pages in the current book?

                   

                  Sure there is.

                  The Bookcontents array in a Book (a description of a single file) has a 'documentPageRange' property, but it's a string, rather than a number -- I didn't check, but I'm assuming it could be to allow for roman numbered pages and the like: "vii-xiv". Theoretically you can still parse this with Javascript, but it could also be something like "Section1:456-Section2:123". (I might want to confirm this some time ...)

                   

                  It's far easier to just open each document and count the pages immediately. That way, you don't have to worry about weird numbering schemes, section prefixes, or whatever. This (untested!) script opens all documents belonging to one single Book and displays the number of pages.

                   

                  if (app.books.length != 1)
                  {
                    alert ("Slow Reader Alert!\nI can only work on one book at a time.");
                    exit(0);
                  }
                  numberOfPages = 0;
                  for (doc=0; doc<app.books[0].bookContents.length; doc++)
                  {
                    a_document = app.open (app.books[0].bookContents[doc].fullName);
                    numberOfPages += a_document.pages.length;
                    a_document.close(SaveOptions.NO);
                  }
                  alert ("This book seems to contain "+numberOfPages+" pages, including any blanks");
                  


                  To calculate the position of a thumb tack for any page in any document, all you need to know are two three things:

                  1. The total number of pages (which requires you to open all documents);
                  2. The position of your current document in the book list (so you know its first page number);
                  3. The current page number ([Rereading:] I meant the current index of the page in the current document, starting at zero)

                   

                  By the way, the InDesign Scripting Tutorial PDF contains lots of little snippets that walk you through standard stuff. From that, you'll be able to build more complicated scripts. The Tutorial PDF can be found on Adobe's home site, InDesign, Scripting stuff (sorry -- slow connection, don't want to locate it for you!).

                  The ESTK built-in Help has a full reference on all supported Javascript objects. If you happen to be on Windows, you might want to check my rewrite of it in Windows CHM format (http://www.jongware.com/idjshelp.html), which has lots of hyperlinks and is fully indexed.

                  • 6. Re: Scripting object position
                    Kasyan Servetsky Level 5

                    Where a good place to start if I want to learn InDesign scripting (esp what can and can't be achieved)?

                             

                    First of all, check out this page on Adobe site (Scripting resources section) http://www.adobe.com/products/indesign/scripting/index.html and start from Adobe Introduction to Scripting and Adobe InDesign CS3 Scripting Tutorial

                     

                    Make sure to download the supporting Scripting Guide scripts http://wwwimages.adobe.com/www.adobe.com/products/indesign/scripting/downloads/indesign_cs 3_guide_scripts.zip It contains examples of scripts, covering majority of aspects of ID scripting. In my opinion the best way to study scripting is to take an example and examine it.

                     

                     

                    Here is a JavaScript Reference I use every day:

                    http://www.w3schools.com/jsref/

                    and also this

                    http://www.devguru.com/technologies/javascript/home.asp

                     

                     

                    I also strongly recommend you to read Dave Saunders blog:

                    http://www.jsid.blogspot.com/ and browse this site: http://www.pdsassoc.com/

                     

                    And be sure to visit Bob Stuckys site http://www.creativescripting.net/ Id like to draw your attention to his terrific script library.

                     

                    Here is Kris Coppieters's blog — very interesting — complex things explained in simple terms:

                    http://rorohiko.blogspot.com/

                     

                     

                    Whenever you start writing a script, take a look at what other scripters did; its quite possible that somebody has already done something similar and you can use it as a basis for your own script.

                    So take a look at these sites:

                     

                     

                    Adobe Exchange:

                    http://www.adobe.com/cfusion/exchange/index.cfm?event=productHome&exc=19&loc=en_us

                     

                     

                    Peter Kahrels site:

                    http://www.kahrel.plus.com/indesignscripts.html

                     

                     

                    Here you can download a compendium of interesting scripts (chm-file for windows)

                    http://www.box.net/shared/pdkkcopmk4

                     

                     

                    Kasyan

                    • 7. Re: Scripting object position
                      [Jongware] Most Valuable Participant

                      Hi Kasyan! Good list of links (you seemed to have missed one )

                      I already worked out a full script in my head; it shouldn't take more than 10 minutes to write & test. But I'm going to hold back until I see what Zane comes up with by himself

                      • 8. Re: Scripting object position
                        [Jongware] Most Valuable Participant

                        Zane, even going over it mentally I already spotted a slight mistake:

                         

                        vertical position =  total height * (page number /total number of pages)

                         

                        No -- it should be

                         

                        vertical position =  (total height - height of page number box) * (page number /total number of pages)

                        • 9. Re: Scripting object position
                          Kasyan Servetsky Level 5

                           

                          you seemed to have missed one

                          Ouch! Of course! How could I forget about your references?! I can't live even a day without them!

                           

                          An addition to my previous post:

                          Zane, make sure to download Jonware's InDesign CS3 or 4 reference, JavaScript Core Classes, and also ScriptUI if you want to create interfaces for your scripts.

                           

                          Kasyan

                          • 10. Re: Scripting object position
                            MrZaneE Level 1

                            Argggg, this is doing my head in. How do you people do it? I think I've dived head first into the deep end, and now I'm drowning. All I seem to be able to do is break things. I'll try again tommorrow.

                            Z.

                            • 11. Re: Scripting object position
                              MrZaneE Level 1

                              well this is far as I got (works with a 20 page a4 facing page doc);

                               

                              var myDoc = app.activeDocument

                              var myPages = myDoc.pages;

                              var mySpreads = myDoc.spreads;

                              var font = ScriptUI.newFont ("Helvetica", ScriptUI.FontStyle.BOLD)

                              var myPageHeight = 295;

                              var myRecHeight = myPageHeight / 11;

                              var myY1position = 0;

                               

                              for (i = 0; i < mySpreads.length; i++) {

                              var mySpread = mySpreads[i];

                              var myY2position = myY1position + myRecHeight;

                               

                              for (j = 0; j < mySpread.pages.length; j++) {

                              var myPage = mySpread.pages[j];

                               

                              if (myPage.side == PageSideOptions.RIGHT_HAND) {

                              var myX1position = 405; 

                              var myX2position = 425;

                              }

                              else {

                              var myX1position = -5;

                              var myX2position = 15;

                              }

                               

                              var myTextFrame = myPage.textFrames.add();

                              myTextFrame.fillColor = myDoc.swatches.item(8);

                              myTextFrame.strokeColor = myDoc.swatches.item(0);

                              myTextFrame.geometricBounds = [myY1position, myX1position, myY2position, myX2position];

                              myTextFrame.contents = myPage.name;

                              }

                              myY1position = myY1position + myRecHeight;

                              }

                               

                              Then I search for objects with a green fill and attach an object style. Yes it's insainly crude, but I tried far more complex techniques and all it did was crash indesign.

                               

                              how come if I change;

                              var myRecHeight = myPageHeight / 11;

                              to

                              var myRecHeight = myPageHeight / mySpreads;

                              it crashes inDesign?

                              • 12. Re: Scripting object position
                                [Jongware] Most Valuable Participant

                                Relax, you aren't doing too bad -- for a first time! It may be crude, but even I feel my scripts look haphazard when compared to the wonders of logic of Marc Autret.

                                 

                                how come if I change;

                                var myRecHeight = myPageHeight / 11;

                                to

                                var myRecHeight = myPageHeight / mySpreads;

                                it crashes inDesign?

                                 

                                You are mixing objects with object properties. myPageHeight resolves to a simple number (you could use myDoc.documentPreferences.pageHeight for that, but this will work as long as your document size doesn't change. OTOH, using this variable means you suddenly have to take your measurement units into account.).

                                 

                                mySpreads, on the other hand, is a composite object -- a class in Javascript parlance. It has a definition (class "Spread") and lots of properties and methods to 'act' on one or more spreads. What do you get if you divide a number by a spread? I would have guessed 'nothing', or perhaps a Javascript error, but you already found out: it crashes ID ... To get the number you want, you need to use mySpreads.length.

                                 

                                var font = ScriptUI.newFont ("Helvetica", ScriptUI.FontStyle.BOLD)

                                 

                                This is No Good. What you created here is a display font to use in the powerful ScriptUI interface programming sub-system. With this newly create font you can create wonderful dialogs -- but I imagine that was not what you were looking for

                                To change the font in your InDesign document, all you need to do is set it into the text frame you created:

                                 

                                myTextFrame.insertionPoints[-1].appliedFont = "Helvetica";

                                myTextFrame.insertionPoints[-1].fontStyle = "Bold";

                                 

                                I am using the "insertion point" to refer to something like the text insertion cursor -- any text you add as well in the insertion point will use the new font from that point on. The odd notation [-1] means "the very last item" (it's odd because most programming languages don't like negative array indices!) -- meaning, your new settings are 'appended' to what's already in the frame. Add any text you want in the 'contents' of an insertion point:

                                 

                                myTextFrame.insertionPoints[-1].contents = "Hello world!\r";

                                 

                                (Note the backslash r at the end -- it's to insert a hard return.) Since the 'last point' is updated after inserting this text, you can immediately follow it with

                                 

                                myTextFrame.insertionPoints[-1].appliedFont = "Times";

                                myTextFrame.insertionPoints[-1].fontStyle = "Italic";

                                myTextFrame.insertionPoints[-1].contents = "That's all folks\r";

                                • 13. Re: Scripting object position
                                  [Jongware] Most Valuable Participant

                                  (additional)

                                   

                                  myTextFrame.fillColor = myDoc.swatches.item(8);

                                  myTextFrame.strokeColor = myDoc.swatches.item(0);

                                   

                                  This is somewhat unreliable, as it depends on the exact order of items in your document. You can safely use the swatch names instead:

                                   

                                  myTextFrame.fillColor = myDoc.swatches.item("Green");
                                  myTextFrame.strokeColor = myDoc.swatches.item("C=85 M=14 Y=31 K=10");
                                  

                                   

                                  (the advantage of 'named' swatches is clear from that 2nd example!)

                                  • 14. Re: Scripting object position
                                    MrZaneE Level 1

                                    okay now I'm getting into this. I now have it controlled by an object style, which is great, next I'll try and get it to work within a book (made up of multiple documents). However I do have yet another question. How do I get the script to search the document for anything with the "pagenumber" object style and then delete it (ie so that the script can regenerate the page numbers if the document has changed).

                                    script so far.

                                     

                                     

                                    var myDoc = app.activeDocument

                                    var myPages = myDoc.pages;

                                    var mySpreads = myDoc.spreads;

                                    var myPageHeight = myDoc.documentPreferences.pageHeight;

                                    var myY1position = 10;

                                    var myRecHeight = (myPageHeight - myY1position) /mySpreads.length -1;

                                    var spaceVal = 2;

                                     

                                     

                                    try {

                                        var myOStyle = myDoc.objectStyles.item("PageNumber");

                                        myOStyle.name;

                                    } catch (e) {

                                        var myOStyle = myDoc.objectStyles.add({name: "PageNumber"});

                                    }

                                     

                                     

                                    for (i = 0; i < mySpreads.length; i++) {

                                    var mySpread = mySpreads[i];

                                    var myY2position = myY1position + myRecHeight;

                                     

                                    for (j = 0; j < mySpread.pages.length; j++) {

                                    var myPage = mySpread.pages[j];

                                     

                                    if (myPage.side == PageSideOptions.RIGHT_HAND) {

                                    var myX1position = 405; 

                                    var myX2position = 425;

                                    }

                                    else {

                                    var myX1position = -5;

                                    var myX2position = 15;

                                    }

                                     

                                    var myTextFrame = myPage.textFrames.add();

                                    myTextFrame.geometricBounds = [myY1position, myX1position, myY2position, myX2position];

                                    myTextFrame.contents = myPage.name;

                                    myTextFrame.applyObjectStyle(myOStyle);

                                    }

                                    myY1position = myY1position + myRecHeight;

                                    }

                                     

                                     

                                    • 15. Re: Scripting object position
                                      AdobeScripts Level 3

                                      MrZaneE wrote:

                                       

                                      okay now I'm getting into this. I now have it controlled by an object style, which is great, next I'll try and get it to work within a book (made up of multiple documents). However I do have yet another question. How do I get the script to search the document for anything with the "pagenumber" object style and then delete it (ie so that the script can regenerate the page numbers if the document has changed).

                                      script so far.

                                       

                                      I'm not JS man so I can't give you finall code, but maybe I can still help you

                                      you have two ways - you can iterate through Pages in Spreads (like you have now at end of your code) collections and then iterate through PageItems collection (in JS it will be "pageItems") and check for appliedObjectStyle.name

                                      or you can iterate through myDocument.pageItems collection directly

                                      and you don't need to delete and recreate - because you can UPDATE contents which will be a lot faster

                                       

                                      or maybe I'll try to post some JS code

                                       

                                      for (i = 0; i < mySpreads.length; i++) {

                                      var mySpread = mySpreads[i];

                                      var myY2position = myY1position + myRecHeight;

                                       

                                      for (j = 0; j < mySpread.pages.length; j++)

                                      {

                                      var myPage = mySpread.pages[j];

                                       

                                      if (myPage.side == PageSideOptions.RIGHT_HAND)

                                      {

                                      var myX1position = 405; 

                                      var myX2position = 425;

                                      }

                                      else

                                      {

                                      var myX1position = -5;

                                      var myX2position = 15;

                                      }

                                       

                                      for (k = 0; k< myPage.textFrames.length; k++

                                      {

                                      if (myPage.textFrames[k].appliedObjectStyle == myOStyle.name )

                                      {

                                      var myTextFrame = myPage.textFrames[k];

                                       

                                      myTextFrame.geometricBounds = [myY1position, myX1position, myY2position, myX2position];

                                      myTextFrame.contents = myPage.name;

                                      }

                                      }

                                      }

                                      myY1position = myY1position + myRecHeight;

                                      }

                                       

                                      robin

                                       

                                      www.adobescripts.co.uk