6 Replies Latest reply on Feb 28, 2013 7:33 AM by Marc Autret

    Implementing 'whose' in Javascript

    [Jongware] Most Valuable Participant

      AppleScript has a 'whose' function, which allows you to quickly select specific items out of an array -- much to the envy of Javascripters! Would this function be a good idea? Any drawbacks, or possibly enhancements?

       

      Array.prototype.whose = function(propertiesObjectOrFunction)
      {
       var i, l;
       if (propertiesObjectOrFunction instanceof Object)
       {
        l = this.length;
        while (l--)
        {
         for (i in propertiesObjectOrFunction)
         {
          if (this[l][i] != propertiesObjectOrFunction[i])
          {
           this.splice(l,1);
           break;
          }
         }
        }
        return this;
       }
       if (propertiesObjectOrFunction instanceof Function)
       {
        l = this.length;
        while (l--)
        {
         for (i in propertiesObjectOrFunction)
         {
          if (!propertiesObjectOrFunction(this[l]))
          {
           this.splice(l,1);
           break;
          }
         }
        }
        return this;
       }
       return null;
      }
      
      // sample usage:
      x = app.activeDocument.textFrames.everyItem().getElements().whose({label:"MyLabel"});
      alert (x.length);
      x = app.activeDocument.textFrames.everyItem().getElements().whose(function(x) { return x.tables.length > 0; } );
      alert (x.length);
      
        • 1. Re: Implementing 'whose' in Javascript
          Peter Kahrel Adobe Community Professional & MVP

          Nice idea. Small problem: this line:

           

          if (this[l][i] != propertiesObjectOrFunction[i])

           

          produces an error ('Object doesn't support the property or method "prototype"') on this call:

           

          x = app.activeDocument.textFrames.everyItem().getElements().whose(function(x) { return x.tables.length > 0; } );

           

          The one-page document has a frame with two tables.

           

          A restriction is that the function doesn't return text frames in groups. Is that deliberate?

           

          Peter

          • 2. Re: Implementing 'whose' in Javascript
            Marc Autret Level 4

            Hi Theunis,

             

            A function is an object too!

            Place the function test before the object test.

             

             

            PS: Also, I strongly suggest you use this pattern:

             

            ( ('function'==typeof x) || (x instanceof Function) )

             

            @+

            Marc

            • 3. Re: Implementing 'whose' in Javascript
              Vamitul Level 4

              i think i seen something similar in the expandebles framework:

               

              http://extendables.org/docs/patches/array.html#array-methods

               

              the filter and reject methods.

              • 4. Re: Implementing 'whose' in Javascript
                Marc Autret Level 4

                My two pennies:

                 

                Array.prototype.whose = function F(/*obj|fct*/condition)
                //--------------------------------------
                // Note: support nested objs (see Example 1 below)
                {
                    // Default test function (cached)
                    // ---
                    F.OBJ_TEST || (F.OBJ_TEST = function T(t,o)
                        {
                        var r = 1,
                            k;
                
                        for( k in o )
                            {
                            if( !o.hasOwnProperty(k) ) continue;
                            r = ( 'object' == typeof o[k] ) ?
                                T(t[k],o[k]) :
                                +(t[k] == o[k]);
                            if( !r ) break;
                            }
                        return r;
                        });
                
                    // Vars
                    // ---
                    var fCond = 'function'==typeof condition || (condition instanceof Function),
                        oCond = fCond ? undefined : condition,
                        n = this.length,
                        z = 0,
                        i;
                
                    // Do we use the default function?
                    // ---
                    fCond = fCond ? condition : F.OBJ_TEST;
                
                    // Processing...
                    // ---
                    for( i=0 ; i < n ; ++i )
                        fCond(this[i],oCond) && (this[z++] = this[i]);
                
                    this.length = z;
                    fCond = oCond = null;
                
                    // Will allow compound calls :-)
                    // ---
                    return this;
                };
                
                
                
                // ---
                // Example 1 (based on obj)
                // ---
                a = app.activeDocument.textFrames.everyItem().getElements().
                    whose({ contents:"foobar", fillColor:{name:"None"} });
                app.select(a);
                
                
                // ---
                // Example 2 (based on a custom function)
                // ---
                a = app.activeDocument.textFrames.everyItem().getElements().
                    whose(function(tf){ return tf.texts[0].characters.length > 10; });
                app.select(a);
                

                 

                @+

                Marc

                • 5. Re: Implementing 'whose' in Javascript
                  [Jongware] Most Valuable Participant

                  Ow Marc, your sense of style is showing! Yes, that's what I had in mind, more or less

                   

                  Vamitul: you are correct, this is exactly what Expendables describes for 'filter'.

                   

                  Peter:

                  A restriction is that the function doesn't return text frames in groups. Is that deliberate?

                   

                  I'd rather consider that a side effect of 'document.textFrames'. Do you know what caused the error you reported? The only use of 'prototype' is on Array, and -- for once -- that should be safe to build upon.

                  • 6. Re: Implementing 'whose' in Javascript
                    Marc Autret Level 4

                    > Do you know what caused the error you reported? The only use of 'prototype' is on

                    > Array, and -- for once -- that should be safe to build upon.

                     

                    The error in your original code results from two combined facts:

                     

                    1) The supplied function will successfully pass the test (propertiesObjectOrFunction instanceof Object) because a function is an Object.

                     

                    2) Then, while traversing the properties of the function with  for (i in propertiesObjectOrFunction)  we meet the prototype property, which is unkknow from TextFrame instances. Therefore:

                     

                    this[l][i] != propertiesObjectOrFunction[i]

                     

                    causes an error, provided that i=='prototype'.

                     

                    @+

                    Marc