14 Replies Latest reply on Aug 7, 2017 1:19 PM by Peacock

    Select pathitem by name and remove it.

    Peacock

      So I have a script that will calculate the distance between print impressions when something is printed using whichever cylinder I choose. If I move the repeat line to a different cylinder marker, the script will copy the first impression and create a duplicate and place it exactly where that impression would start printing again depending on where the repeat line is placed. Also, it calculates the distance between prints and writes it on the artboard. If I am changing a proof and there is already measurements it will delete the existing measurements and create new ones. That all works fine.

       

      What I've yet to get it to do is to delete the copied impression called "repeat impression" so that the new altered artwork can take it's place. Currently I just click and delete the repeat impression before I run the script, but I figure since it is always named "repeat impression" I could just have the script check and see if that object exists and delete it first before running. Not sure what I'm missing...

       

       

      //Delete existing Measurements layer and repeat impression to make way for new ones in cases when proof had to be adjusted/changed.

       

      function mLayerCreate() {

       

                var mLayerNotExists = true;

       

      try {

          app.activeDocument.layers.getByName("Measurements").remove();

      } catch (e) {};

       

       

      try {

          app.activeDocument.pathitem.getByName("repeat impression").remove();

      } catch (e) {};

       

       

      // Create Measurements Layer

      if(mLayerNotExists){

      mLayer = myDocument.layers.add(); // not using var to declare makes it global

      mLayer.name = "Measurements";

      }

      }

       

      function releaseLayer(){

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

                          if(activeDocument.layers[i].name == "plate") {

                                    activeDocument.layers[i].locked= false;

                                    activeDocument.activeLayer = activeDocument.layers[i];

      }

      }

       

      }

        • 1. Re: Select pathitem by name and remove it.
          williamadowling Level 4

          Ok, you've got a few issues along the way here.

           

          number one, you should definitely do SOMETHING in your catch blocks.. It's never really a good idea to have a try statement with an empty catch block. It can create nearly impossible debugging situations.

           

          number two, the reason your pathItem is not being deleted is because you have a syntax error. pathItem is an object that is virtually always accessed as one element of an array of pathItem objects. This array is referenced by app.activeDocument.pathItems

           

          *edit* i realized i never explicitly shared the correction necessary, so here goes.

           

          change this:

          app.activeDocument.pathitem.getByName("repeat impression").remove();

           

          to this:

          app.activeDocument.pathItems.getByName("repeat impression").remove();

           

          *edit*

           

          This is a perfect illustration of why you want to add logic to your catch block. Your script is simply failing because you're missing the "s" in app.activeDocument.pathItems.getByName("repeat impression");

          Normally you would be getting an error: "undefined is not an object". But since the error occurs in a try block, the script simply moves on to the blank catch block and proceeds without letting you know anything went wrong.

           

          (potentially) number 3, I'm assuming that this is just a snippet of a larger script. At different times, you're using different ways of referring to the active document. sometimes you're using

          app.activeDocument

          whereas other times you're using

          myDocument

          in this snippet it does not appear that myDocument was ever declared, so you should probably be getting an error for this unless it is declared somewhere else in your script that you didn't share.

           

          And lastly, in your releaseLayer function you're simply using

          activeDocument

          which is another instance of an undefined variable. Try to keep all references to the active document using the same variable name. It will make your life much easier.

           

          Hope this helps.

          • 2. Re: Select pathitem by name and remove it.
            Peacock Level 1

            It does help. The script in full was created over quite a few years, mostly as a result of me inquiring at this forum. I'm by no means a coder, but I do enjoy playing in the sandbox. I did correct pathitem to pathitems, but it's still not deleting the existing "repeat impression". I do define myDocument as app.activeDocument, but I get your point about sticking to one term. Is there really a need to even create "myDocument" in the first place if app.activeDocument is the same thing?

             

            Also, I don't quite get what you mean about having a try statement with an empty catch block. I mean, I know what the catch block is, but I don't get what the alternative is.

             

            Here it is in full, and yes, it's probably looks quite messy an experienced eye:

             

             

             

            // http://forums.adobe.com/thread/1333774?tstart=0 

            // copy, move and paste into different layer 

             

            // required: an open document and a selected path item 

             

             

            var myDocument = app.activeDocument; 

            var selectedObject = myDocument.selection; 

             

            //Identify left edge of repeat 

            var repeatBounds = app.activeDocument.groupItems['repeat'].geometricBounds; 

            var r1 = repeatBounds[0]; 

             

            // Get position of selection bounds 

            var myBounds = selectedObject[0].geometricBounds; 

            var x1 = myBounds[0]; 

            var rawRepeat = (r1 - x1);

            var x2 = myBounds[2];

             

            var myDocument = app.activeDocument;

            var selectedObject = myDocument.selection;

            var activeLayer = app.activeDocument.activeLayer;

            var layerName = activeLayer.name;

            activeLayer.name = "plate";

            var dest = myDocument.layers["text fields"];

            var theCopy = selectedObject[0].duplicate(dest, ElementPlacement.PLACEATEND);

            theCopy.name = "repeat impression"; 

            selectedObject[0].selected = true;

            var theCopyBds = theCopy.visibleBounds;

             

             

            theCopy.position = new Array( theCopyBds[0]+rawRepeat, theCopyBds[1]);

             

             

             

            // Set up vars for the Measurements

             

             

            var rawPrintWidth = myBounds[2] - myBounds[0];

            var tmpPrintWidth = (rawPrintWidth / 72);

            var finalPrintWidth = tmpPrintWidth.toFixed(2);

            var rawGap = (r1 - x2);

            var rawRepeat = (r1 - x1);

            var Repeat = (rawRepeat / 72);

            var Gap = (rawGap / rawRepeat) * Repeat;

             

             

            //set up fraction calculations for Repeat interval

            var Factor = 16;

            var repeatFraction = Math.round(Factor*Repeat) % Factor;

            if (repeatFraction)

            {

                while (~(repeatFraction | Factor) & 1)

                    repeatFraction >>= 1, Factor >>= 1;

                if (Math.floor(Repeat) == 0)

                    Repeat = String(repeatFraction)+'/'+String(Factor);

                else

                    Repeat = String(Math.floor(Repeat))+' '+String(repeatFraction)+'/'+String(Factor);

            } else

            {

                Repeat = String(Math.round(Repeat));

            }

             

             

            //set up fraction calculations for Gap

            var gapFactor = 8

            var gapFraction = Math.round(gapFactor*Gap) % gapFactor;

            if (gapFraction)

            {

                while (~(gapFraction | gapFactor) & 1)

                    gapFraction >>= 1, gapFactor >>= 1;

                if (Math.floor(Gap) == 0)

                    Gap = String(gapFraction)+'/'+String(gapFactor);

                else

                    Gap = String(Math.floor(Gap))+' '+String(gapFraction)+'/'+String(gapFactor);

            } else

            {

                Gap = String(Math.round(Gap));

            }

             

             

            // Find specs swatch

            var origSwatches = myDocument.swatches;

            var swatchesLength = origSwatches.length;

            for (i=0;i<swatchesLength;i++) {

                      if (origSwatches[i].name == "specs" || origSwatches[i].name == "Specs") {

                                var specsSwatch = origSwatches[i];

                                }

                      }

             

             

            // Check if specs swatch is defined

            if (specsSwatch == undefined) {

                      alert("Please create a specs swatch");

                      }

            else {

                      makeDimensions();

                      releaseLayer();

            }

             

             

             

            function makeDimensions() {

             

             

            // Lock the active layer to prevent color change

            activeLayer.locked = true;

            dest.locked = true;

             

             

            // Create Measurements Layer

            mLayerCreate();

             

             

            // Set Document colors to specs

            myDocument.defaultFillColor = specsSwatch.color;

            myDocument.defaultStrokeColor = specsSwatch.color;

             

            // Create groups for measurements

            var xMeasure = mLayer.groupItems.add();

            xMeasure.name = "repeat & gap measurements";

             

             

            // Create Text for Repeat Measurement

            var repeatText = xMeasure.textFrames.add();

            repeatText.contents = "Will print every "+Repeat+"\" " + "with approx. "+Gap+"\" between prints";

            repeatText.bottomLeft = 0;

            repeatText.paragraphs[0].paragraphAttributes.justification = Justification.LEFT;

            for (i=0;i<repeatText.textRange.characters.length;i++) {

                      repeatText.characters[i].characterAttributes.fillColor = specsSwatch.color;

            }

            }

            // Create Text for Ink Colors (still in it's "thinkin' about it" phase)

             

             

            var inkList = [];

             

             

             

             

            //Delete existing Measurements layer and repeat impression to make way for new in cases when proof had to be adjusted/changed.

             

            function mLayerCreate() {

             

             

                      var mLayerNotExists = true;

             

             

            try {

                app.activeDocument.layers.getByName("Measurements").remove();

            } catch (e) {};

             

             

            try {

                app.activeDocument.pathitems.getByName("repeat impression").remove();

            } catch (e) {};

             

             

            // Create Measurements Layer

            if(mLayerNotExists){

            mLayer = myDocument.layers.add(); // not using var to declare makes it global

            mLayer.name = "Measurements";

            }

            }

             

            function releaseLayer(){

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

                                if(activeDocument.layers[i].name == "plate") {

                                          activeDocument.layers[i].locked = false;

                                          activeDocument.activeLayer = activeDocument.layers[i];

            }

            }

            }

             

              

            dest.locked = false;

            • 3. Re: Select pathitem by name and remove it.
              williamadowling Level 4

              Sorry in advance for this huge wall of text. I hope it is helpful and informative.

               

              Believe me, i know all about piecing together a script from input from lots of users on this forum. That's exactly how i got started. Now when i go back and look at my own code it makes me sick. haha.

               

              To your question of whether or not it's necessary to create a variable for app.activeDocument, no it's not necessary at all. It's a matter of reducing the amount of typing necessary and eliminating confusion in the future. For something like app.activeDocument, it's not as big of a deal, but let's take a look at a sample case for why it's better to use variables.

               

              function test()
              {
                   app.activeDocument.pathItems[0].left += 50;
                   app.activeDocument.pathItems[1].left += 50;
                   app.activeDocument.pathItems[2].left += 50;
                   app.activeDocument.pathItems[3].left += 50;
                   app.activeDocument.pathItems[4].left += 50;
              }
              test();
              

               

               

              in this example, i'm increasing the 'left' property of the first 5 pathItems in the document by 50pt. But what if i changed my mind and I wanted to move the paths 75pt instead. as it's written, i would have to change each instance. But if i use a variable called "inc" or something, then all i have to do is change the value of the variable, instead of having to find every instance in the script (which could be in tons of different locations). like this:

               

              function test()
              {
                   var myDoc= app.activeDocument;
                   var moveIncrement = 50;
                   var paths = myDoc.pathItems;
              
                   paths[0].left += inc;
                   paths[1].left += inc;
                   paths[2].left += inc;
                   paths[3].left += inc;
                   paths[4].left += inc;
              }
              test();
              

               

              let's look at an example of how not using variables can result in some really long, cumbersome lines of code. Let's say we wanted to make several changes to a given groupItem on a given layer. We'll change the name, the position, and then scale it up to 200%.

               

              app.activeDocument.layers.getByName("My Layer").groupItems.getByName("My Group").name = "New Name";
              app.activeDocument.layers.getByName("My Layer").groupItems.getByName("My Group").left = 500;
              app.activeDocument.layers.getByName("My Layer").groupItems.getByName("My Group").top = 100;
              app.activeDocument.layers.getByName("My Layer").groupItems.getByName("My Group").resize(200,200);
              

               

              Now let's have a look at what that would look like with some variables.

               

              var myDoc = app.activeDocument;
              var layers = myDoc.layers;
              var myLayer = layers["My Layer"];
              var myGroup = myLayer.groupItems["My Group"];
              
              myGroup.name = "New Name";
              myGroup.left = 500;
              myGroup.top = 100;
              myGroup.resize(200,200);
              

               

              anyway, that's the end of a largely irrelevant tangent. haha. main takeaway, the code looks much cleaner, requires far less typing and it's easier to edit, etc.

               

              back to your other question about the try/catch. a try/catch basically precludes the normal system error. You can test this out by running the following two scripts, back to back, from ESTK. I'll be attempting to alert the name of the first layer in the document, but i've intentionally put a syntax error, just like the error in the snippet you shared in your initial post. i left out the 's' at the end of 'layers'.

               

              function test()
              {
                  //this function should give you the error "undefined is not an object"
                  alert(app.activeDocument.layer[0].name);
              }
              test();
              

               

              function test()
              {
                  //this function should finish executing without giving you any errors
                  //and without giving you the desired alert message
                  try
                  {
                      alert(app.activeDocument.layer[0].name);
                  }
                  catch(e){}
              }
              test();
              

               

              now let's look at one possible way (though not a very realistic example) of handling the error just to show you what the catch block does.

               

              function test()
              {
                  //this try block should fail because app.activeDocument.layer is undefined, therefore we cannot get the first element of it
                  try
                  {
                      alert(app.activeDocument.layer[0].name);
                  }
                  catch(e)
                  {
                      alert("The try statement failed, and the script has now entered the catch block.");
                      alert("All of the code inside the catch block will be executed.");
                      alert("The name of the first layer in the document is: " + app.activeDocument.layers[0].name);
                  }
              }
              test();
              

               

               

               

              Hopefully this helps illustrate why it's good to have some code in the catch block. Typically you'll put some kind of message into the catch block so that the script either alerts the user that something went wrong, or there may be some logic that writes the error to a log file. Either way, the catch block should at the very least let you know that something went wrong, otherwise you simply have errors that occur silently and then it can be impossible to know why something else down the line did not work as expected.

               

              and finally, the reason that your 'repeat impression' pathItem is not being deleted is that your syntax is still wrong. you added the s to the end, which is good, but the property name is camelCase. the 'i' in the middle needs to be capital. replace that entire try/catch block with this:

               

              try {

                  myDocument.pathItems.getByName("repeat impression").remove();

              } catch (e)

              {

                   alert("failed to remove the repeat impression pathItem.");

              };

               

              this way, if that try statement fails, you'll get an alert message letting you know that it failed.

              2 people found this helpful
              • 4. Re: Select pathitem by name and remove it.
                Peacock Level 1

                No need to apologize for the wall of text. It was very helpful. I should be apologizing for having you spend all this time explaining stuff.

                 

                Well I added in the alert to the catch, and the alert works! Unfortunately it's working because the remove didn't work, so I got the error message. I replaced pathitems with pathItems (actually I pasted your whole snippet). I thought maybe it was connected to the fact that the repeat impressions is not part of the Measurements layer, and tried specifying the layer, but no luck there either.

                 

                try {

                    myDocument.layers["text fields"].pathItems.getByName("repeat impression").remove();

                } catch (e)

                {

                     alert("failed to remove the repeat impression pathItem");

                };

                 

                try {

                    myDocument.layers.getByName("Measurements").remove();

                } catch (e)

                {   

                    alert("failed to remove previous measurements")

                };

                 

                The remove for the old measurements layer works fine, and new measurements replace the old ones fine. That's exactly what I'm aiming for with the repeat impression. Remove the old one and update with a new one with the same name.

                • 5. Re: Select pathitem by name and remove it.
                  williamadowling Level 4

                  Are you able to share the file that you're working with so I can do some digging and find exactly what the bug may be? It's difficult to identify an issue when I can't see all the parts.

                   

                  Try adding this line to your catch statement and let me know what the alert says:

                   

                  alert("system error: " + e);

                  • 6. Re: Select pathitem by name and remove it.
                    Peacock Level 1

                    system error: Error: No such element

                    • 7. Re: Select pathitem by name and remove it.
                      williamadowling Level 4

                      Ok. good news and bad news.

                       

                      The bad news is you're trying to delete something that doesn't exist.

                      The good news is, that error is common and we can totally do something about it.

                       

                      Can you select the item that you want to delete, then take a screengrab of the layers panel so we can trace the DOM tree and make sure we are correctly identifying the pathItem's location in the DOM.

                       

                      Then attach the screenshot to your response and we can go from there.

                      • 8. Re: Select pathitem by name and remove it.
                        williamadowling Level 4

                        So I responded already in a DM, but for posterity's sake, i'll describe the issue here as well. Hopefully it will help someone else down the line when they have a similar issue.

                         

                        The issue is that you are attempting to find and remove a pathItem named "repeat impression", but the error message is telling you there is no such pathItem with that name. After you sent me the file, I identified the object you want to delete as a groupItem, not a pathItem.

                         

                        so if you change your statement to this, it should work:

                         

                        try {

                            myDocument.layers["text fields"].groupItems.getByName("repeat impression").remove();

                        } catch (e)

                        {

                             alert("failed to remove the repeat impression pathItem");

                        }

                         

                        additionally, you can make your code a little bit more flexible (but potentially more dangerous depending on the circumstances) by using pageItems instead of pathItems or groupItems. pageItems is an array that holds all of the following objects for a given scope:

                        pathItems, groupItems, compoundPathItems, placedItems and textFrames

                         

                        the dangerous bit may come into play if you have a groupItem called "My Item" and a pathItem called "My Item". If you have both of those items with the same name, you could get unexpected results by using pageItems["My Item"].remove(); Depending upon the order of the objects in the hierarchy, you could end up deleting the wrong object, because only the first item in the list will be removed. Just be careful.

                        1 person found this helpful
                        • 9. Re: Select pathitem by name and remove it.
                          Peacock Level 1

                          Well, I know I'm pretty close here, but I'm still getting the error message within the catch, and no removing of the existing repeat impression. I've tried tinkering around a bit because it just feels like I'm oh so close, but it's just not happening.

                           

                          Incidentally, pageItems really is the way to go for this, because there is no risk that there would be other items with that name within the document, and also sometimes the repeat impression would be a text box, other times a simple path, and sometimes a group.

                          • 10. Re: Select pathitem by name and remove it.
                            williamadowling Level 4

                            So, it's difficult for me to know exactly what you're running, but i'm noticing some inconsistency in the snippets you're sending me. Sometimes it appears you're targeting the pageItem in the document scope, and other times you're targeting it in the scope of a layer called "text fields". Now since there's only one thing in the document called "repeat impression" you shouldn't have a problem, but because of this inconsistency it's hard for me to put my finger on the cause of your issue.

                             

                            At this point, i'm attempting to run the entire script that you sent over before, but i gather i just don't know how to use it, so I'm getting errors long before the error you're reporting. There's a note at the top that says: "Required: an open document and a selected path item"

                             

                            i don't know what that pathItem should be or whether it's placment/shape etc are important to the rest of the script. I'll keep testing things out, but the more info you can give me, the better prepared i will be to adequately debug this.

                            • 11. Re: Select pathitem by name and remove it.
                              williamadowling Level 4

                              Aha! Got it.

                               

                              inside the makeDimensions function, you set the 'locked' property of 'dest'  to true. dest was previously defined as the layer called "text fields" which is the parent layer of the object you're trying to remove.

                               

                              So you're attempting to delete something form a locked layer, but Illustrator is (correctly) saying "no no no. you can't do that". You're not supposed to be able to modify locked layers, otherwise it would be pointless to allow the locking of a layer.

                               

                              It looks like there are only 3 things that you ever actually do with the variable "dest". you duplicate some artwork to the layer, then you lock the layer, then you unlock it later.

                               

                              You can leave these two lines of code alone, since it appears this is the only time you ever really do something useful with this variable:

                              var dest = myDocument.layers["text fields"];

                              var theCopy = selectedObject[0].duplicate(dest, ElementPlacement.PLACEATEND);

                              but you should get rid of the other two references to the variable dest, one of which is inside makeDimensions, and the other is at the very end of the script.

                               

                              After getting rid of those lines, the script worked properly for me.

                              1 person found this helpful
                              • 12. Re: Select pathitem by name and remove it.
                                Peacock Level 1

                                Thanks! I'll get right on it. I was busily typing an explanation of how I use the script and all that jazz and accidentally deleted the whole thing.

                                • 14. Re: Select pathitem by name and remove it.
                                  Peacock Level 1

                                  Not quite... Sorry for the delay, but this had to go on back burner for a little while.

                                   

                                  Here's the thing though. The layer gets locked so that when the script writes the measurements, it doesn't change the color of my artwork to the color of the specs swatch. So what I did was move the dest.locked = false; statement from the very end of the script to the beginning of

                                  function mLayerCreate() {

                                  so that when it begins the process of writing the measurements it unlocks the layer.

                                   

                                  So that part works now. If there is a repeat impression already there, it deletes it and places the new one in place of it.

                                   

                                  Now I'm trying to figure out how to construct the if statement so that if there is no repeat impression there (when I am using the template for the first time for an order), it behaves the same way as it would otherwise, except it doesn't have to delete an existing repeat impression because it isn't there. I think what it's doing now is creating a repeat impression placing it behind the repeat line, and then deleting it because it is called "repeat impression".