26 Replies Latest reply on Sep 5, 2013 10:16 AM by Rocky Berlier

    Decrementing a date

    Rocky Berlier

      I do a monthly newsletter for a small business that hosts about 30 classes each month and they require the customers to prepay by the day before the class to get a discounted price, otherwise the price increases if you pay on the day of the class. For example:

       

      Sunday, Oct 6, 1:00 - 3:00 PM

      Instructor: Professor Smith

      1 Class - $30 by Oct 5 or $45 at the door.

       

      What I'd like to do (via a script) is to find and copy the "6" (from Oct 6) then decrement it by 1 and place it in the "by Oct 5" day place.

       

      Is there a way to do this? It would save a HUGE amount of time each month.

       

      Any help is appreciated.

       

      ⁓Rocky

        • 1. Re: Decrementing a date
          DaveSofTypefi Level 2

          This can be done by script fairly easily if your document is set-up with paragraph styles to make it easy to find the text in question.

           

          Dave

          • 2. Re: Decrementing a date
            Rocky Berlier Level 1

            Hello Dave,

             

            Thanks for responding.

             

            The three lines of the class info (Date/time, Instructor, and Price) are assigned a different style each (named "classInfo1, classInfo2, and classInfo3"). What I want to do is to grab the date number of "classInfo1",  decrement it then place it in the proper date place of "classInfo3".

             

            Where I need help is in the scripting part. The month is actually a defined Text Variable that changes with each month for the newletter. Using a newsletter  template with the variables defined and placed, I simply redefine the month Text Variable each time I create a new newsletter. Then all classes that have the month defined (as well as elsewhere in the newsletter) are changed. This works great and is a real time saver.

             

            However, regarding setting the day-before-date, I've tried doing a search and replace but this doesn't help with decrementing. It's the decrementing part that I am really struggling with. I can copy the day to the clipboard but getting it out of the clipboard and decremented is where I am having problems.

             

            If you have some practical scripting ideas, Dave, I'd greatly appreciate the assistance.

             

            Warmest regards,

            ⁓Rocky

            • 3. Re: Decrementing a date
              DaveSofTypefi Level 2

              Decrementing a number is easy, assuming you've found it in text:

               

              myNumber = Number(myFoundText);

              myDecNum = myNumber - 1;

              myFoundText.contents = myDecNum;

               

              But what if the number is 1? You don't want zero? So extra logic is needed to handle month boundaries.

               

              Dave

              • 4. Re: Decrementing a date
                [Jongware] Most Valuable Participant

                Last month's discussion on "grep search result + 1 HELP PLEASE!" turned out to be about incrementing a date. I devised a way to do this, using the JS Date object (see msg #7) but unfortunately the OP decided not to use it, so I don't know if it actually works.

                 

                (The script works of course, but I don't know if it did or did not do what the OP wanted.)

                • 5. Re: Decrementing a date
                  Rocky Berlier Level 1

                  Thanks again Dave for responding. You bring up a good point about needing to create a month/day boundary handler.

                   

                  I have been playing with your scripting suggestions and I think the biggest problem I'm facing now is with finding the number and isolating it from the month variable. If I use a Grep find of:

                   

                  var myString = "~v \d"

                  app.findGrepPreferences.findWhat = myString;

                   

                  It does find the first instance of the month variable and the day. However, I don't know how to get the second instance and then change ONLY the number. As I showed above, the lines for the class info is like so:

                   

                  Sunday, Oct 6, 1:00 - 3:00 PM

                  Instructor: Professor Smith

                  1 Class - $30 by Oct 5 or $45 at the door.

                   

                  You see that there are Time numbers as well as Class numbers to consider. So, just a general search for numbers isn't going to work. What I need to do is isolate the month from the day  because the month is a variable (I can definitely find it by using the Grep "~v \d").

                   

                  Unfortunately, because the month is a variable it isn't recognized by javascript as a date (I'm not even sure it's recognized as a string)  therefore I need to somehow separate these, turn the day into an integer var, decrement it then find the next instance of the month variable then change it to the month variable PLUS the decremented day. The additional hurdle here is that the Grep won't let you change your find to an InDesign Text Vriable. It will only let you search for one. I don't know how to get past this hurdle either.

                   

                  You mentioned earlier that having these defined in styles might help. Could you elborate on that? Can I limit a search to a style in the javascript? I know I can do this in a manual search but don't know how it's done in javascript.

                   

                  You help is greatly appreciated and I am learning a lot from it.

                  Warmest regards,

                  ⁓Rocky

                  • 6. Re: Decrementing a date
                    Rocky Berlier Level 1

                    Thanks Jongware. This was very helpful. I got errors with your scripting solution from that thread but it gave me the basic structure for the script that I was looking for.

                     

                    I've done a lot of scripting in Photoshop but scripting in InDesign is still new for me. I think with a little grateful assistance I can grow quickly with scripting here.

                    Thanks again.

                    Warmest regards,

                    ⁓Rocky

                    • 7. Re: Decrementing a date
                      DaveSofTypefi Level 2

                      Here's some code that shows one way to do it:

                       

                      var myDoc = app.documents[0];
                      var myStyle = myDoc.paragraphStyles.item("StyleName");
                      setupFindGrep("~v \\d+","");
                      app.findGrepPreferences.appliedParagraphStyle = myStyle;
                      var myFinds = myDoc.findGrep();
                      for (var j = myFinds.length - 1; j >= 0; j--) {
                                var numString = myFinds[j].contents.slice(2);
                                var decString = decrementDateNum(numString);
                                var startIndex = myFinds[j].index + 2;
                                var endIndex = myFinds[j].characters[-1].index;
                                myFinds[j].characters.itemByRange(startIndex, endIndex).texts[0].contents = decString;
                      }
                      
                      function decrementDateNum(aString) {
                                return String(Number(aString) - 1);
                      }
                      
                      function setupFindGrep(find, change, foots, hidLayers, lockedLayers, lockedStories, masters) {
                                app.findGrepPreferences = null;
                                app.changeGrepPreferences = null;
                                try { app.findGrepPreferences.findWhat = find } catch(e) {};
                                try {app.changeGrepPreferences.changeTo = change } catch(e) {};
                                app.findChangeGrepOptions.properties = {
                                          includeFootnotes:(foots == null ? false : foots),
                                          includeHiddenLayers:(hidLayers == null ? false : hidLayers),
                                          includeLockedLayersForFind:(lockedLayers == null ? false : lockedLayers),
                                          includeLockedStoriesForFind:(lockedStories == null ? false : lockedStories),
                                          includeMasterPages:(masters == null ? false : masters)
                                }
                      } // end setupFindGrep
                      

                       

                      Obviously, you need to substitute your style name.

                       

                      Note the double backslash in the setupFindGrep call: that's because backslash is an escape character in both JavaScript and Grep.

                       

                      I was surprised that I couldn't simplify things by using positive lookbehind so that the variable was not part of the found string, but I couldn't make that work. It doesn't work in the UI, either.

                       

                      As we discussed, you'll need a more sophisticated decrement function and that might include the need to pass in the text value of the variable -- off the top of my head, I'm not sure how to do that.

                       

                      Dave

                      • 8. Re: Decrementing a date
                        Rocky Berlier Level 1

                        Thanks very much for this Dave. I’m learning a lot with this.

                         

                        Unfortunately, it gave me an error with this at line 12:

                        Source:     myFind[j].characters.itemByRange(startIndex,endIndex).texts[0].contents - decString;

                         

                        I think your script is searching for an actual date (month & day) to decrement (no?) and that is probably where it is hanging up.

                        The Loop is where it seems to get caught.

                         

                        I’m not exactly sure why but I think it has to do with the InDesign Text Variable for the month. Like I mentioned, the month is an InDesign Text Varibable that I set when I first create a newsletter from a template. All the month call-outs throughout the newsletter are set to this variable so I can just change it once and it changes them globally in the new newsletter. A tremendous time saver. The problem is, Javascript isn’t recognizing these as a month (or even a string). I’m not sure how to deal with the whole Text Variable assignment issue since I absolutely need to keep them in the Template. I’ve looked through the Scripting Guides and can’t find anything referencing them but maybe I’m looking in the wrong place.

                         

                        I’ve been trying (unsuccessfully) to do some simple scripts like just Find the day number (in the 3rd class-info line) and change it to a different number.

                         

                        Here’s what I’ve been manually doing with a Find to select the date I want to change:

                         

                        1) I set the:

                             Find What: “~v \d”,

                             Change to: blank,

                             Search: “Story”,

                             Find Format: Paragraph Style: "Class Info3”

                             (all this criteria is actually saved as a Query preset).

                        2) I click Find and it goes immediately to the instance that I want to change (line three of my class info paragraph).

                        3) I click Done

                        4) I press the Right Arrow to deselect the selection and jump to the end of the day number

                            (this is because both the Text Variable and the date are selected together).

                        5) I press shift+Left Arrow once (or twice depending on whether it’s a one or two digit number) to select the day number.

                        6) Type the new day number (1 day less than the class day).

                         

                        Doing all this automatically in a script, of course, is what my hope is. At this point, I’m just having difficulty getting the Find criteria right in a script.

                         

                        Thanks again for all your help. It has really taught me a lot.

                        Warmest regards,

                        ⁓Rocky

                        • 9. Re: Decrementing a date
                          DaveSofTypefi Level 2

                          No, my script (which works, I tested it) is searching for a text variable followed by a number.

                           

                          It looks like you retyped the script because the line quoted in the error message is not right. You have a minus sign where there should be an equals.

                           

                          Dave

                          • 10. Re: Decrementing a date
                            Rocky Berlier Level 1

                            Yeah, that was just a typo I made in the Error message when trying to transcribe it. It wasn’t in the script I ran.

                             

                            Here’s the actual error (copied & pasted):

                            -----------------------------------------------

                            JavaScript Error!

                            Error Number: 45

                            Error String: Object is invalid

                            Engine: main

                            File: /Applications/Adobe InDesign CC/Scripts/Scripts Panel/Samples/JavaScript/DecrementDate2.jsx

                            Line: 11

                            Source:           myFinds[j].characters.itemByRange(startIndex, endIndex).texts[0].contents = decString;

                            -----------------------------------------------

                             

                            I copied and pasted your script as written.

                             

                            Ah yes, I do see that your script is searching for the Text Variable & number via the setupFindGrep ("~v \\d+",""); but perhaps something is going wrong with the Loop?

                             

                            Another issue (I think) is that this needs to be applied to the active story and NOT the entire document. Each class offered is written up as a separate text box and story. It could cause some problems being applied to the entire document.

                             

                            Thanks again. This has been quite a learning experience for me.

                            Warmest regards,

                            ⁓Rocky

                            • 11. Re: Decrementing a date
                              DaveSofTypefi Level 2

                              Ah, I realized that I had tested it with only one instance. Putting a second instance in the story gives me the same error. I'll look deeper.

                               

                              Dave

                              • 12. Re: Decrementing a date
                                DaveSofTypefi Level 2

                                I've found the bug. That line should read:

                                 

                                myFinds[j].parentStory.characters.itemByRange(startIndex, endIndex).texts[0].contents = decString;
                                

                                 

                                That's the danger of working with minimal test documents. In my original test documents the indexes were the same.

                                 

                                Dave

                                • 13. Re: Decrementing a date
                                  Rocky Berlier Level 1

                                  Now I get:

                                  -----------------------------------------------

                                  JavaScript Error!

                                  Error Number: 45

                                  Error String: Object is invalid

                                  Engine: main

                                  File: /Applications/Adobe InDesign CC/Scripts/Scripts Panel/Samples/JavaScript/DecrementDate2.jsx

                                  Line: 11

                                  Source:           myFinds[j].parentStory.characters.itemByRange(startIndex, endIndex).texts[0].contents = decString;

                                  -----------------------------------------------

                                   

                                  Hmmm... I thought that would fix it too...

                                  • 14. Re: Decrementing a date
                                    DaveSofTypefi Level 2

                                    Do you have any instances inside tables?

                                     

                                    Dave

                                    • 15. Re: Decrementing a date
                                      DaveSofTypefi Level 2

                                      While temptation to use "parentStory" in that statement causing us the problem is almost irresistible, it is actually better to use just "parent". If the found text is in a story then the two are synonymous but if the text is in a cell then the latter works and the former doesn't. So, try changing that line to:

                                       

                                      myFinds[j].parent.characters.itemByRange(startIndex, endIndex).texts[0].contents = decString;
                                      

                                       

                                      The only thing I'm not sure about is if a text cell is overset. I guess I can try that easily enough ... ah, yes it does. So this change should fix your problem.

                                       

                                      If it doesn't and you can't work it out, I might need to see a document to help you further.

                                       

                                      Dave

                                      1 person found this helpful
                                      • 16. Re: Decrementing a date
                                        Rocky Berlier Level 1

                                        No errors, Yay! However, it definitely applies the change to the whole document. I’m very excited about this as it works rather quickly at updating  the whole newsletter (even though I only want it to perform the change on the current story). Love the speed of this.

                                        So, how can I limit this to only affect the active story. You are right, the text is in a cell. Is there an "activeCell" call that can be used here?

                                         

                                        I am SO grateful for your help with this, Dave. I am learning so much through this exchange.

                                         

                                        ⁓Rocky

                                        • 17. Re: Decrementing a date
                                          DaveSofTypefi Level 2

                                          Have you discovered ESTK's Object Model Viewer (under the Help menu)? It has the answer to most questions, but it often takes dogged persistence to interpret its "wisdom".

                                           

                                          Here's a script that focuses on the text associated with the selection (although I don't think it catches all possibilities -- for example, if you have a table selected it won't process the table, but maybe you can adapt the code for that if you need it):

                                           

                                          //DESCRIPTION: Processing the text of the selection or of the selection's parent
                                          
                                          
                                          (function() { // use anonymous function to avoid namespace leakage
                                                    if (app.documents.length > 0) { // must be a document before there can be a selection
                                                              if (app.selection.length > 0) { //selection is always an array
                                                                        var myText = getTextFromSelection(app.selection[0]);
                                                                        if (myText != null) {
                                                                                  var myStyle = app.activeDocument.paragraphStyles.item("StyleName");
                                                                                  decrementDates(myStyle, myText)
                                                                        }
                                                              }
                                                    }
                                          
                                          
                                                    function decrementDates(myStyle, myText) {
                                                              setupFindGrep("~v \\d+","");
                                                              app.findGrepPreferences.appliedParagraphStyle = myStyle;
                                                              var myFinds = myText.findGrep();
                                                              for (var j = myFinds.length - 1; j >= 0; j--) {
                                                                        var numString = myFinds[j].contents.slice(2);
                                                                        var decString = decrementDateNum(numString);
                                                                        var startIndex = myFinds[j].index + 2;
                                                                        var endIndex = myFinds[j].characters[-1].index;
                                                                        myFinds[j].parent.characters.itemByRange(startIndex, endIndex).texts[0].contents = decString;
                                                              }
                                                    }
                                          
                                          
                                                    function getTextFromSelection(sel) {
                                                              if (sel.hasOwnProperty("baseline")) {// sel is text
                                                                        return sel.parent.texts[0];
                                                              } else if (sel.hasOwnProperty("texts")) { // sel owns a text object
                                                                        return sel.texts[0];
                                                              }
                                                              return null;
                                                    }
                                          
                                          
                                                    function decrementDateNum(aString) {
                                                              return String(Number(aString) - 1);
                                                    }
                                          
                                          
                                                    function setupFindGrep(find, change, foots, hidLayers, lockedLayers, lockedStories, masters) {
                                                              app.findGrepPreferences = null;
                                                              app.changeGrepPreferences = null;
                                                              try { app.findGrepPreferences.findWhat = find } catch(e) {};
                                                              try {app.changeGrepPreferences.changeTo = change } catch(e) {};
                                                              app.findChangeGrepOptions.properties = {
                                                                        includeFootnotes:(foots == null ? false : foots),
                                                                        includeHiddenLayers:(hidLayers == null ? false : hidLayers),
                                                                        includeLockedLayersForFind:(lockedLayers == null ? false : lockedLayers),
                                                                        includeLockedStoriesForFind:(lockedStories == null ? false : lockedStories),
                                                                        includeMasterPages:(masters == null ? false : masters)
                                                              }
                                                    } // end setupFindGrep
                                          }())
                                          

                                           

                                          Be warned that I haven't actually tested this. I'm doing this on a break and need to get back to my own work.

                                           

                                          Dave

                                           

                                          Message was edited by: DaveSofTypefi: fixed two instances of missing parentheses in the getTextFromSelection function.

                                          1 person found this helpful
                                          • 18. Re: Decrementing a date
                                            DaveSofTypefi Level 2

                                            Ah, I didn't even syntax check it. I see I left out a closing parenthesis -- I do that all the time.

                                             

                                            Dave

                                            1 person found this helpful
                                            • 19. Re: Decrementing a date
                                              Rocky Berlier Level 1

                                              Thanks again, Dave for nudging me in the right direction.

                                               

                                              NO! I haven’t discovered ESTK's Object Model Viewer (under the Help menu). WOW! Thanks! I can see I will be exploring this a lot in the near future.

                                              Thanks again for all your very illuminating help.

                                               

                                              Warmest regards,

                                              ⁓Rocky

                                              • 20. Re: Decrementing a date
                                                Rocky Berlier Level 1

                                                Hi Dave,

                                                I understand now what you meant by dogged determination to interpret the wisdom in the Object Model Viewer. Whew! It isn’t telling me much. There is a similar lack of information provided for scripting in Photoshop as well. Truly informative and educational resources are hard to find.

                                                 

                                                I still haven’t discovered a way to limit your Decrementing script to the current selection. It is applying it to the whole document and I have to hit Revert to undo the changes it makes. I’m reading everything I can and experimenting with what I learn. Unfortunately, every object I try fails in one way or another. I must say, Javascript for InDesign is twice as difficult as it is for Photoshop (and that’s saying a lot).

                                                 

                                                If you are inclined to put me out of my misery, I’d really appreciate knowing how to limit the script to the current selection. I’m sure it’s probably something really simple and I will smack myself in the head when I find out.

                                                 

                                                ⁓Rocky

                                                • 21. Re: Decrementing a date
                                                  DaveSofTypefi Level 2

                                                  Did you see message 17? it either does what you want or ought to show you the way. Note the caveat in message 18.

                                                   

                                                  Dave

                                                  1 person found this helpful
                                                  • 22. Re: Decrementing a date
                                                    Rocky Berlier Level 1

                                                    Hi Dave,

                                                    Yes, message 17 is the script I am using and it works but doesn’t limit itself to the current selection. I have been looking for the syntax error you mentioned (closing parenthesis) but haven’t found it (nor has ESTK).

                                                    ⁓Rocky

                                                    • 23. Re: Decrementing a date
                                                      Rocky Berlier Level 1

                                                      By the way, all the classes are in separate tables (text frames). I don’t know if this makes a difference but you mentioned in message 17 that it wouldn’t process selected tables but it processes ALL the tables selected or not. The date info is in a cell. Ugh! Maybe there just isn’t a way to do this?

                                                      • 24. Re: Decrementing a date
                                                        Rocky Berlier Level 1

                                                        Okay, so I made a serious mistake. I kept running an older script. DOH! I hate when that happens!! My script file is very full of experiments for this and it can get a little confusing sometimes.

                                                         

                                                        OMG! This script does exactly what I was trying to do all along!!!! You are a GENIUS!!! This is brilliant! WOW!

                                                         

                                                        Thank you a million times!

                                                        Warmest regards,

                                                        ⁓Rocky

                                                        • 25. Re: Decrementing a date
                                                          DaveSofTypefi Level 2

                                                          In your original request, you had a source and a target, so the question is how to change the script to handle that?

                                                           

                                                          Off the top of my head, the easy way to do this is use two different searches. Assuming both source and target are in range of the original selection, this should work (You'll need to change the paragraph style names.)

                                                           

                                                          //DESCRIPTION: Processing the text of the selection or of the selection's parent
                                                          
                                                          
                                                          (function() { // use anonymous function to avoid namespace leakage
                                                                    if (app.documents.length > 0) { // must be a document before there can be a selection
                                                                              if (app.selection.length > 0) { //selection is always an array
                                                                                        var myText = getTextFromSelection(app.selection[0]);
                                                                                        if (myText != null) {
                                                                                                  var mySourceStyle = app.activeDocument.paragraphStyles.item("SourceStyleName");
                                                                                                  var myTargetStyle = app.activeDocument.paragraphStyles.item("TargetStyleName");
                                                                                                  decrementDates(mySourceStyle, myTargetStyle, myText)
                                                                                        }
                                                                              }
                                                                    }
                                                          
                                                          
                                                                    function decrementDates(sourceStyle, targetStyle, myText) {
                                                                              setupFindGrep("~v \\d+","");
                                                                              app.findGrepPreferences.appliedParagraphStyle = sourceStyle;
                                                                              var myFinds = myText.findGrep();
                                                                              if (myFinds.length > 1) {
                                                                                        alert("More than one source found; ignoring all but first");
                                                                              }
                                                                              var source = myFinds[0];
                                                                              var numString = source.contents.slice(2);
                                                                              var decString = decrementDateNum(numString);
                                                                              app.findGrepPreferences.appliedParagraphStyle = targetStyle;
                                                                              var myFinds = myText.findGrep();
                                                                              for (var j = myFinds.length - 1; j >= 0; j--) {
                                                                                        var startIndex = myFinds[j].index + 2;
                                                                                        var endIndex = myFinds[j].characters[-1].index;
                                                                                        myFinds[j].parent.characters.itemByRange(startIndex, endIndex).texts[0].contents = decString;
                                                                              }
                                                                    }
                                                          
                                                          
                                                                    function getTextFromSelection(sel) {
                                                                              if (sel.hasOwnProperty("baseline")) {// sel is text
                                                                                        return sel.parent.texts[0];
                                                                              } else if (sel.hasOwnProperty("texts")) { // sel owns a text object
                                                                                        return sel.texts[0];
                                                                              }
                                                                              return null;
                                                                    }
                                                          
                                                          
                                                                    function decrementDateNum(aString) {
                                                                              return String(Number(aString) - 1);
                                                                    }
                                                          
                                                          
                                                                    function setupFindGrep(find, change, foots, hidLayers, lockedLayers, lockedStories, masters) {
                                                                              app.findGrepPreferences = null;
                                                                              app.changeGrepPreferences = null;
                                                                              try { app.findGrepPreferences.findWhat = find } catch(e) {};
                                                                              try {app.changeGrepPreferences.changeTo = change } catch(e) {};
                                                                              app.findChangeGrepOptions.properties = {
                                                                                        includeFootnotes:(foots == null ? false : foots),
                                                                                        includeHiddenLayers:(hidLayers == null ? false : hidLayers),
                                                                                        includeLockedLayersForFind:(lockedLayers == null ? false : lockedLayers),
                                                                                        includeLockedStoriesForFind:(lockedStories == null ? false : lockedStories),
                                                                                        includeMasterPages:(masters == null ? false : masters)
                                                                              }
                                                                    } // end setupFindGrep
                                                          }())
                                                          

                                                           

                                                          I think that does the job. It allows for multiple targets but processes only the first source in the selection.

                                                           

                                                          One way of extending it to handle multiple sources (for example, each in its own cell of a table with all the associated targets in the same cell) would be to use the (badly named) getTextFromSelection function to get the associated text for each source and then use that as the range for the corresponding targets.

                                                           

                                                          Dave

                                                          • 26. Re: Decrementing a date
                                                            Rocky Berlier Level 1

                                                            This is amazing! That does it perfectly!!!!

                                                            Even if I have my cursor on the second instance, it still grabs the first instance, decrements it and changes the target. Bravo!!!! That’s exactly what I wanted to do! I now have it as a shorcut keypress that I can use on a template file to change the target day for each class. OMG! This is fantastic.

                                                             

                                                            You are BRILLIANT!!!

                                                            Thank you again Dave for the generous sharing of your wisdom and intellect. It is greatly appreciated.

                                                            Warmest regards,

                                                            ⁓Rocky