Skip navigation
Currently Being Moderated

Can you search an Indesign document for all Specified Script Labels?

Aug 20, 2010 8:22 AM

Better yet, is it possible to get a listing of all the objects; then pass through and retrieve thier respective attributes?  For example, the document has 2 objects one script label of "header image" image 20 by 200 starting as position 50 and one text block with label of "description" 100 by 200 at position 70.

 

I've been looking for some more detailed documentation around scripting, however I just cannot find the ultimate comprehensive guide.

 

Thanks in advance.

 
Replies
  • Currently Being Moderated
    Aug 20, 2010 1:26 PM   in reply to dmarma

    > is it possible to get a listing of all the objects?

     

    If by "all the objects" you mean all the page items objects of your document, then myDocument.allPageItems is probably the property you're looking for. It returns an Array of PageItem objects whatever their level in the Document hierarchy.

     

    However, there are many ways to retrieve a set of filtered objects from your document. As explained by Loic Aigon (http://www.loicaigon.com/blog/?p=337) AppleScript offers a whose command which is very helpful to do this kind of job. It's also possible to mimic whose in JavaScript: see the main code in Loic's article; or another suggestion here: http://www.loicaigon.com/blog/?p=337#comment-40 (in French).

     

    For English readers, a different approach is detailed at the end of the following article: http://www.indiscripts.com/post/2010/07/on-everyitem-part-2

    (see the code of Object.prototype.findItems).

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 20, 2010 1:36 PM   in reply to Marc Autret

    For the clarity of my answer, here are the two generic methods I suggest in the above comment:

     

     

    //--------------------------------------
    // Emulates 'whose' in JavaScript
    //--------------------------------------
    Object.prototype.whose = function(/*str*/filter)
    { // E.g.: 'this.contents == "foo" && this.geometricBounds[0]>20'
     
         if( !this.isValid ) return false;
     
         var filterFct = new Function('return (' + filter + ');'),
              objs = this.getElements(),
              i = objs.length;
     
         while( i-- )
         {
         if( !filterFct.call(objs[i]) ) objs.splice(i,1);
         }
     
    return objs;
    }
     
    //--------------------------------------
    // Sample code
    //--------------------------------------
     
    var doc = app.activeDocument;
    var tfs = doc.textFrames.everyItem();
    var arr = tfs.whose('this.contents=="foo" && this.geometricBounds[0]>20′);
     
    alert( arr.length );
    

     

     

     

    //--------------------------------------
    // Add a generic 'findItems' method
    // callable from any collection
    //--------------------------------------
    Object.prototype.findItems = function(/*obj*/props)
    {
        if( !('everyItem' in this) )
            {
            throw new Error("Error: " + this + " is not a collection.");
            }
     
        var ret = this.everyItem().getElements(),
            i = ret.length,
            e, p;
     
        while( i-- && e=ret[i] )
            {
            for( p in props )
                {
                if( (p in e) && e[p]===props[p] ) continue;
                ret.splice(i,1);
                }
            }
        return ret;
    };
     
    //--------------------------------------
    // Sample code
    //--------------------------------------
     
    // Find all text frames having the
    // label 'foo' AND overflows==true
    var tfs = app.activeDocument.
        textFrames.findItems(
        {
        label: 'foo',
        overflows:true,
        });
     
    alert(tfs.length);
    

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 21, 2010 1:30 AM   in reply to Marc Autret

    Marc, as a convert from AppleScript I will be giving those a try thank you… I do miss them old friends…

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 24, 2010 5:13 AM   in reply to Muppet Mark-QAl63s

    Just a word of warning:

     

    There's a general convention which believes it's wrong to Prototype "Object".

     

    Prototpying Object can have unexpected side-effects in unrelated functions which assume empty objects have no properties. I learned the validity of this optiono the hard way...

     

     

    Harbs

    http://www.in-tools.com

    Innovations in Automation

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 24, 2010 5:57 AM   in reply to Harbs.

    You're absolutely right. My code is unsafe and is not a good model. In real life projects we should create and prototype specific sub-objects, and not taint the primitive Object entity. The fact is that I don't know how to specifically target DOM objects together. . . OK, I know your advice in this particular case: Don't use OOP, use global functions! ;-)

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 24, 2010 7:19 AM   in reply to Marc Autret

    AFAIK, the only way to protype collections is to prototype each one individually. I don't think there's a parent "collection" object.

     

    Additionally, Collection objects are actually undefined in the DOM until you access them at least once.

     

    For example:

    PageItems.prototype.itemWhose = function(what){
      //function body
    }
     
    

    This will fail unless you first access PageItems

     

    A simple statement:

    app.documents.item(0).pageItems
     
    

    will "wake InDesign" to the fact that there is actually an Object "PageItems".

     

    Once a particular scripting engine "knows" about a particular collection, you can prototype it like any object, but you need to access every collection you'd like to prototype.

     

    You can define one function and chain assign it to all collection prototypes.

     

    itemWhose = function(what){
    //function body
    return retVal;
    }
    app.paragraphStyles;
    app.characterStyles;
    app.objectStyles;
    var doc = app.documents.item(0);
    doc.pageItems;
    doc.textFrames;
    //Add in every collection in the DOM...
     
    ParagraphStyles.prototype.itemWhose = 
    CharacterStyles.prototype.itemWhose = 
    ObjectStyles.prototype.itemWhose = 
    PageItems.prototype.itemWhose = 
    TextFrames.prototype.itemWhose = itemWhose;
    //Add in every collection in the DOM...
     
    

     

    There's nothing wrong with this approach, but you can decide for yourself if this is too much trouble!

     

    My opinion is that in this case forsaking OOP for a simple global function is way simpler...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 24, 2010 8:12 AM   in reply to Harbs.

    Yeh, I noticed in another topic the way you wake collections. Honestly, I don't like that solution. It sounds like a hack. A third party developer might think that such a statement is incomplete or removable: app.paragraphStyles;

     

    Moreover, when you need to target collections which are not visible from app —like PageItems, TextFrames— you must assume that some DOM objects are actually available, as you do in:

     

    // Need a Document to wake PageItems...
    // ...But is there any Document available now?
    var doc = app.documents.item(0);
    doc.pageItems;
    // etc.
    

     

    It's a serious problem if we work on reusable snippets or libraries, isn't it?

     

    To conclude, I do not like my solution, nor yours. IMHO, Adobe should provide a better interface to safely handle and extend DOM objects and collections. In CS5 the object event model have been notably extended, that's great. Now we want to implement a whose method or whatever, what's the big deal? Why offering an object-oriented architecture to scripters if they should be so wary of extending prototypes? That is my question.

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 24, 2010 12:00 PM   in reply to Marc Autret

    Yes. I agree with you.

     

    It would be nice if the DOM was more extendable without going through these ridiculous hoops.

     

    And yes, the fact that some of those collections are only children of Documents is a major problem with this approach.

     

    FWIW, you can extend any non-collection prototypes. My guess is that the fact that you need to "wake" collection objects is simply a bug which was never addressed.

     

    I'll try to get this some more attention from the engineers so that we have a chance it will eventually get fixed...

     

    On the other hand, it's possible that the collcetion limitation is by design for performance reasons. If that's the case, I'm not sure I want this to be fixed. I'll try to clarify either way.

     

    Harbs

     
    |
    Mark as:
  • JulienFR
    13 posts
    Nov 30, 2009
    Currently Being Moderated
    Apr 10, 2012 3:06 AM   in reply to dmarma

    hi,

    great script in Applescript.

    I seash to group items in document with the same script_label.

    So in my document there are many itmes with the same script_label. (just a part of the label) and i want to group there items with the same.

    it's begin to "kkk22_33_xxxx" and after there different. so it's possible. i try in javascript but there are problem to select it and put diffrent label in the list to use it before to group items (text and pictures).

    i do after a script to cut and paste an other document and there stay group...

    thanks indesigners !!!!

     

    (update : i open discussion about this)

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points