6 Replies Latest reply on Jan 11, 2017 9:42 AM by Marc Autret

    Find all pages that have marginPreferences overridden from masterSpread

    BRVDL

      Hello,

       

      In a script I'm making, I'm trying to adjust all margins on all pages and masterSpreads.

      This adjustment is a formula based on its current marginPreferences so the outcome differs for every page.

       

      The problem is that when I loop through all pages and adjust their marginPreferences, their margins get detached from their respective masterSpreads. This is something that I don't want to happen. However, when I only would loop through the masterSpreads, all pages that have margins that are overridden by the user wouldn't be adjusted.


      My solution would be to first loop through all masterSpreads and adjust the margins there. That way, all pages that are based on that masterSpread are updated. I then need to loop through the pages that have marginPreferences that are already overridden by the user and adjust those margins while leaving the other pages alone.

       

      However, I can't find a way to check if a page has its marginPreferences overridden. Can anyone point me in the right direction?

       

      My current code for looping through the masterSpreads is:

       

      for(i=0; i < myDoc.masterSpreads.length; i++){
        for(j=0; j < myDoc.masterSpreads.item(i).pages.length; j++){
          var myMargin = myDoc.masterSpreads.item(i).pages.item(j).marginPreferences;
          myMargin.top = doAdjustmentWith(myMargin.top)
          myMargin.bottom = doAdjustmentWith(myMargin.bottom)
          myMargin.left = doAdjustmentWith(myMargin.left)
          myMargin.right = doAdjustmentWith(myMargin.right)
        }
      }
      

       

      Thanks in advance!

        • 1. Re: Find all pages that have marginPreferences overridden from masterSpread
          Marc Autret Level 4

          Hi BRVDL,

           

          > I can't find a way to check if a page has its marginPreferences overridden.

          > Can anyone point me in the right direction?

           

          That's an interesting problem and I won't pretend to provide a full answer to it. As far as I know, the Scripting DOM does not directly tell us whether myPage's margin preferences actually override its master page settings. That's a missing tool in the box, I'm afraid. So you likely have to implement your own method.

           

          Here is my reasoning. First, if a page P and its master page M do not share the same margin preferences, then we can instantly conclude that P has its prefs overridden. Otherwise, we can't make the decision from just inspecting the prefs—they match!—so we have to check whether they are actually linked. To do so, I suggest we temporarily change a parameter, say columnGutter, at the master level and test if P's gutter undergoes the same change. (Of course one restores the original parameter before returning.)

           

          1. From this, we need a way to compare margin preferences, that is, to decide whether the relevant parameters match. The toSource() method is not a option, because it both adds irrelevant data for our purpose, and does not always reveal the relevant ones. So I've designed a custom marginPrefTrace() method which can be injected in Page.prototype. It returns a string that somehow reflects the margin prefs and can be compared against another trace.

           

          2. In addition—although this appears to be an ancillary issue—we need to get access to the master page of a page. I'm not sure this issue has been already discussed in this forum, but there is no masterPage property, only masterSpread (i.e appliedMaster.) So the problem is to find the corresponding index of P in the collection P.masterSpread.pages. SDK developers have a tool for that (IMasterPage::GetMasterSpreadPageIndex), and “the calculation depends on the index position (0, 1, 2, ...) of the page within its spread and the document set-up” (InDesign CC Programing Guide, Vol 1.) But a generic algorithm hasn't be made available to scripters, AFAIK. Below is an experimental one, Page.prototype.getMasterPage(), which I've not tested in every circumstance and should then be considered a starting point only.

           

          3. Putting all this together, I finally suggest a Page.prototype.overriddenMargins() method—returning either true, false, or undefined—which implements the approach discussed above.

           

          Page.prototype.marginPrefTrace = function F(  o,k,t,a)
          // -------------------------------------
          // Return a string that reflects the margin
          // preferences of this page.
          {
              o = F.Q||(F.Q={
                  bottom:           'toString',
                  left:             'toString',
                  right:            'toString',
                  top:              'toString',
                  columnGutter:     'toString',
                  // ---
                  columnCount:      'valueOf',
                  customColumns:    'valueOf',
                  columnDirection:  'valueOf',
                  // ---
                  columnsPositions: 'toSource',
                  });
          
              t = this.marginPreferences.properties;
              a = [];
              for( k in o )
                  o.hasOwnProperty(k) &&
                  a.push(t[k][o[k]]());
          
              return a.join(',');
          };
          
          Page.prototype.getMasterPage = function(  m,n,s)
          // -------------------------------------
          // Return the master page of this page,
          // or NULL if no master applied.
          {
              m = this.appliedMaster;
              if( !m || !m.isValid ) return null;
          
              n = (m=m.pages).length;
          
              return m[
                  2 < n || +PageSideOptions.SINGLE_SIDED==(s=+this.side) ?
                  ( this.index % n ) :
                  +(s==+PageSideOptions.RIGHT_HAND)
                  ];
          };
          
          Page.prototype.overriddenMargins = function(  r,m,t,v)
          // -------------------------------------
          // Tell whether this page has overridden
          // margin prefs relative to its master page.
          // => TRUE | FALSE | undefined
          {
              if( !(m=this.getMasterPage()) )
                  return;
          
              // 1. Simple case (distinct traces.)
              // ---
              if( m.marginPrefTrace() != this.marginPrefTrace() )
                  return true;
          
              // 2. Difficult case (matching traces.)
              // ---
              v = (t=m.marginPreferences).columnGutter;
              t.columnGutter = 1+v;  // change
              r = m.marginPrefTrace() != this.marginPrefTrace();
              t.columnGutter = v;    // restore
          
              return r;
          };
          
          
          // =====================================
          // Test
          // =====================================
          
          var doc = app.properties.activeDocument,
              pages = doc && doc.pages.everyItem().getElements(),
              r = [],
              t;
          
          for(
               i=pages.length ;
               i-- ;
               r[i] = (t=pages.pop()).name + ': ' + t.overriddenMargins()
             );
          
          if( r.length ) alert( r.join('\r') );
          

           

           

          Hope that helps.

           

          @+

          Marc

          1 person found this helpful
          • 2. Re: Find all pages that have marginPreferences overridden from masterSpread
            Trevorׅ Adobe Community Professional

            Nice one Marc,

            Not so sure that's it's a good idea to prototype the DOM but either way it's a nice one.

             

            Trevor

            • 3. Re: Find all pages that have marginPreferences overridden from masterSpread
              Marc Autret Level 4

              > Not so sure that's it's a good idea to prototype the DOM.

               

              Yeah I know that's still a huge controversy but from time to time I like to live dangerously ;-)

               

              @+

              Marc

              • 4. Re: Find all pages that have marginPreferences overridden from masterSpread
                BRVDL Level 1

                Hi Marc,

                 

                Thanks for your elaborate answer! I follow your reasoning but because I'm still a novice with Javascript, it will take some time for me to understand the code and implement it. I'll let you know how it goes!

                • 5. Re: Find all pages that have marginPreferences overridden from masterSpread
                  BRVDL Level 1

                  Hi Marc!

                   

                  I got it working, thanks again!

                  Although I don't understand why prototyping the DOM is considered dangerous in InDesign. Can this lead to conflicts with other scripts that are running? Or is the extended DOM reset once the script is run?

                  • 6. Re: Find all pages that have marginPreferences overridden from masterSpread
                    Marc Autret Level 4

                    > Can this lead to conflicts with other scripts that are running?

                    > Or is the extended DOM reset once the script is run?

                     

                    I don't think so, except maybe in (weird?) cases where a script would share its target engine with a foreign one

                     

                    However, what is unquestionable—and this is probably what Trevor was pointing out—is the fact that prototyping DOM related methods requires careful consideration of plural specifiers, should your script use them. Indeed, any of the custom methods I've injected in the above code (say Page.prototype.getMasterPage) will react unexpectedly if you call it from a Pages.everyItem() specifier. Thus, a fully designed prototype should take into account that this may refer to a plural object, which can be checked based on this.getElements().length, and then accordingly operate in returning an array instead of a single object. All this could be done, though. That depends on both your requirements and the recipients of your code. For example, if Page.prototype.getMasterPage() is supposed to work within a framework, my quick implementation obviously lacks robustness. But if you just want it to work in a narrow, fugacious and well defined context, well, it just does its job ;-)

                     

                    @+

                    Marc