5 Replies Latest reply on Apr 22, 2016 3:01 AM by K.Daube

    Find next marker

    K.Daube Level 1

      Dear friends,

      While it is quite simple to find the next marker with oDoc.NextMarkerInDoc the sequence of the found markers is not that what the user sees in the document: you get the markers in the sequence they were inserted into the document (which may be quite random). To get the same sequence as using the Find dialogue, I need ...

      But again my knowledge is to low - see lines 91 or 92:

      #target framemaker  
      /*  Navigate markers and get them
      Document in charge is E:\_DDDprojects\FM-calc\FM-testfiles\NavigateMarkers.fm 
      Which contains both #calc and Author markers
      
      It turns out that the sequence of marker.NextMarkerInDoc is that of creating the markers.
      For the first and last marker the simple method is OK (since absolute postions).
      For next and previous the find method must be used.
      */
      var oDoc = app.ActiveDoc, oCurrentMarker;
      if (!oDoc.ObjectValid ()) {
        alert ("There is no active document.");
      } else {
      oCurrentMarker =  GetMarker (oDoc, "#calc", "first");                 // OK
        Alert ("marker found = " + oCurrentMarker.MarkerText);
      oCurrentMarker =  GetMarker (oDoc, "#calc", "next", oCurrentMarker);  // undefined
        Alert ("marker found = " + oCurrentMarker.MarkerText);
      } 
        
      function GetMarker (oDoc, sMarkerName, sAdverb, oCurrentMarker) { // =============================
      // sAdverb may be first, last, previous, next
      // returns undefined if sMarkerName not defined in oDoc 
      // argument oCurrentMarker unused for "first"   
      // unfortunately there are no such methods as LastMarkerInDoc or PreviousMarkerInDoc
        var marker, nextMarker, exit, currenMarker; 
          markerType = oDoc.GetNamedMarkerType (sMarkerName); // Get the specified marker type.    
          if (!markerType.ObjectValid ()) { return undefined;} 
        
        switch (sAdverb) {
          case "first":  
            oCurrentMarker = GetFirstMarker (oDoc, sMarkerName);
            break;
          case "previous":  
            oCurrentMarker = FindNextPrevMarker (oDoc, sMarkerName, "previous", oCurrentMarker);
            break;
          case "next":  
            oCurrentMarker = FindNextPrevMarker (oDoc, sMarkerName, "next", oCurrentMarker);
            break;
          case "last":  
            oCurrentMarker = GetLastMarker (oDoc, sMarkerName);
            break;
          default:
            Alert ("Error in routine NavigateMarker\nUndefined sAdverb = " + sAdverb);
            break;
        }
        return oCurrentMarker;
      } 
      
      function GetFirstMarker (oDoc, sMarkerName) { // get first marker of type sMarkerName =============
      // function returns the current marker, null if it does not exist
      // parameter oCurrentMarker is not used
        var marker = null, nextMarker, oCurrentMarker; 
        marker = oDoc.FirstMarkerInDoc;  
        while (marker.ObjectValid ()) {  
          nextMarker = marker.NextMarkerInDoc;  
          if (marker.MarkerTypeId.Name === sMarkerName) { 
            return marker;
          }
          marker = nextMarker;  
        }
      } 
      
      function GetLastMarker (oDoc, sMarkerName) { // get last marker of type sMarkerName ===============
      // function returns the last marker of type sMarkerName, null if it does not exist
      // parameter oCurrentMarker is not used
        var marker, nextMarker, lastMarker; 
        marker = oDoc.FirstMarkerInDoc;
        marker = marker.NextMarkerInDoc;  
        while (marker.ObjectValid ()) {  
          if (marker.MarkerTypeId.Name === sMarkerName) { 
            lastMarker = marker;
          }
          marker = marker.NextMarkerInDoc;  
        }
        return lastMarker;
      } 
      
      function FindNextPrevMarker (oDoc, sMarkerName, sAdverb, oCurrentMarker) { // get next/previous ===
      // function returns the current marker, null if it does not exist
      // Base: Russ Ward in https://forums.adobe.com/message/3888653#3888653
        var marker;
        var tr = new TextRange();
        var findParams = new PropVals();
        
        tr.beg.obj = tr.end.obj = oCurrentMarker;       // Starting tr is the current marker
        tr.beg.offset = tr.end.offset = 0;              // 
                                                        // Wrapping not wanted.
        findParams = GetFindParamsMarker (sMarkerName, sAdverb); // Find parameters for marker
      
        InitFA_errno ();                                // reset - it is write protected
      //marker = oDoc.Find(tr.beg, findParams);         // => undefined
        marker = oDoc.Find(oCurrentMarker, findParams); // => undefined
          
        if (FA_errno !== Constants.FE_Success) {
          return undefined;                             // no next/previvious marker present
        }
        return marker;                                  // we have found a next/prev marker
      } 
      
      function GetFindParamsMarker (sMarkerName, direction) { //=========================================
      // Get/set the find parameters: find marker of type sMarkerName, consider direction, no wrapping around
      // Returns find parameters in the function
      
        var findParams;
        if (direction = "next") {
          findParams = AllocatePropVals (1);  
          findParams[0].propIdent.num = Constants.FS_FindMarkerOfType;  
          findParams[0].propVal.valType = Constants.FT_String;  
          findParams[0].propVal.sval = sMarkerName;  
        } else {                                        // previous
          findParams = AllocatePropVals (2);  
          findParams[0].propIdent.num = Constants.FS_FindMarkerOfType;  
          findParams[0].propVal.valType = Constants.FT_String;  
          findParams[0].propVal.sval = sMarkerName;  
          findParams[1].propIdent.num = Constants.FS_FindCustomizationFlags;
          findParams[1].propVal.valType = Constants.FT_Integer;
          findParams[1].propVal.ival = Constants.FF_FIND_BACKWARDS;
        }
        return findParams;  
      } // --- end GetFindParams
      
      function InitFA_errno() { //========================================================================
      // Reset FA_errno as it is write protected. See https://forums.adobe.com/thread/962910
        app.GetNamedMenu("!MakerMainMenu");             //If this fails, you've got bigger problems
        return;
      }
      

      How to specify the (most likely needed) text range?

      Thank You

      Klaus Daube

        • 1. Re: Find next marker
          Klaus Göbel Level 3

          Hi Klaus,

           

          there are some contstants that are undefined

           

          Constants.FF_FIND_CONSIDER_CASE (0x01)

          Constants.FF_FIND_WHOLE_WORD (0x02)

          Constants.FF_FIND_USE_WILDCARDS (0x04)

          Constants.FF_FIND_BACKWARDS (0x08)

           

          They all return "undefined".

           

          Maybe there are more constants undefined ( I didn't test it yet).

           

          But in FM2015 there was an update this week and since then it works in 2015.

           

          I didn't test it yet with FM 12/11/10.

           

          If you are using FM12 better don't use "Constants.FF_FIND_BACKWARDS" but just type "8" (no quotes).

          • 2. Re: Find next marker
            K.Daube Level 1

            Thanks to Klaus Gobel's answer to my other post I'm very close to a solution: The script finds the next marker of defined type.

            But I do not know how to get the new object - as a starting point for the next call of the function:

            function FindNextPrevMarker (oDoc, oCurrentMarker) { // 
            // function returns the nextmarker, null if it does not exist
              var tRange, fRange, marker;
              var tLoc1 = oCurrentMarker.TextLoc;
              var tLoc2 = tLoc1;
              tLoc1.offset = tLoc1.offset+1;                  // Just behind the marker 
              tLoc2.offset = tLoc1.offset;
              tRange  = new TextRange(tLoc1,tLoc2);          // TextRange after current marker
            
              var findParams = new PropVals();                // Get the find parameters for finding marker
                findParams = AllocatePropVals (1);  
                findParams[0].propIdent.num = Constants.FS_FindMarkerOfType;  
                findParams[0].propVal.valType = Constants.FT_String;  
                findParams[0].propVal.sval = "#calc";        // How to find ANY marker ?
            // findParams = GetFindParamsMarker (sMarkerName, sAdverb);
            
              InitFA_errno ();                                // reset - it is write protected
            
              fRange = oDoc.Find(tRange.beg, findParams);    // finds text range
              oDoc.TextSelection = fRange;                    //?  What is selected? 
              oDoc.ScrollToText(fRange);                      //? show it to me  
              marker = fRange.beg.obj;                        // is object Pgf!
            
              if (FA_errno !== Constants.FE_Success) {
                return undefined;                            // no next/previvious marker present
              }
              return marker;                                  // we have found a next/prev marker
            }
            

            Stopping the script at line 22 see that the possible next marker has been selected (item after the 2 -> indicator):

            SelectedMarker.png

            But the result of my search (line 19) is a paragraph object. How do I get from this the marker object (for the next call of this function)?

            Line 21 obviously is wrong.

             

            And BTW would it be correct to start a backwards search with replacing line 06 by:

            tLoc1.offset = tLoc1.offset-1;                  // just before the marker
            

            and of course the extended set of the find-paramters as listed in my initial post (function GetFindParamsMarker)

             

            And - what to put in line 14 to find any type of marker, just the next one in sequence?

            • 3. Re: Find next marker
              Klaus Göbel Level 3

              If you have found the range, where the marker resides, you need to get the texitem(s):

               

              var FoundMarker = [];
              
               var MarkerRange = oDoc.GetTextForRange (locTrefferListe[i], Constants.FTI_MarkerAnchor);
                             
               for (var i = 0; i < MarkerRange.length; i++)//maybe you'll find more markers
                   {
                   var oTextItem = MarkerRange[i];
                     
                   FoundMarker.push(oTextItem.obj)//gather all markers
                   }
              
              

               

              You're done (with the marker).

               

              To find any marker:

              findParams[0].propIdent.num = Constants.FS_FindObject;   

              findParams[0].propVal.valType = Constants.FT_Integer;

              findParams[0].propVal.ival = Constants.FV_FindAnyMarker;

               

              To ease jumping backward and forward I would suggest to fill an array with the markers.

              I will code it in a while, but it will take some time.

              Then I'll be back (hasta la vista).

              • 4. Re: Find next marker
                Klaus Göbel Level 3

                I'm back ;-))

                Just try this one.

                 

                 var oDoc = app.ActiveDoc
                 var oCurrentMarker;  
                 var docStart = oDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf; 
                 var MarkerList = [];   
                 var tloc = new TextLoc (docStart, 0); 
                 var locTextRange = new TextRange (tloc, tloc);
                
                 oDoc.TextSelection = locTextRange;
                
                  if (!oDoc.ObjectValid ()) {  
                      alert ("There is no active document.");  
                        } 
                    else
                        {  // gather all markers-locations(objects) and store them in an array (MarkerList)
                         var FindParams = GetFindParams()
                        
                        var foundTextRange = oDoc.Find(tloc, FindParams);
                
                        while (foundTextRange.beg.obj.ObjectValid()) 
                            {
                                MarkerList.push(foundTextRange);
                                tloc = foundTextRange.end;
                                foundTextRange = oDoc.Find(tloc, FindParams);
                            }
                
                 var FoundMarker = [];
                
                    for (var i = 0; i < MarkerList.length; i++)
                        {
                        var MarkerTI = oDoc.GetTextForRange (MarkerList[i], Constants.FTI_MarkerAnchor);
                      
                        oDoc.TextSelection = MarkerList[i];
                        oDoc.ScrollToText (MarkerList[i]);
                        alert("MARKER");
                
                          for (var x = 0; x < MarkerTI.length; x++)
                           {
                            var oTextItem = MarkerTI[x];
                            FoundMarker.push(oTextItem.obj)//store the marker objects
                            }
                        }
                    }  
                
                
                function GetFindParams()
                {
                    var FindParams = new PropVals() ;
                
                    var propVal = new PropVal() ;
                    propVal.propIdent.num = Constants.FS_FindWrap ;
                    propVal.propVal.valType = Constants.FT_Integer;
                    propVal.propVal.ival = 0 ;// don't start at the beginning
                    FindParams.push(propVal);
                    
                    propVal = new PropVal() ;
                    propVal.propIdent.num = Constants.FS_FindObject;
                    propVal.propVal.valType = Constants.FT_Integer;
                    propVal.propVal.ival = Constants.FV_FindAnyMarker ;
                    FindParams.push(propVal);
                
                    return FindParams
                }
                
                
                
                
                
                • 5. Re: Find next marker
                  K.Daube Level 1

                  Thank You Klaus for your response as of

                  function FindNextPrevMarker (oDoc, sMarkerName, sAdverb, oCurrentMarker) { // get next/previous ===
                  // function returns the next/prev marker, null if it does not exist
                    var tRange, fRange, oTextItem, oMarker, aoMarkerRange, foundMarkers = [];
                    var tLoc1 = oCurrentMarker.TextLoc;
                    var tLoc2 = tLoc1;
                    if (sAdverb === "next") {
                      tLoc1.offset = tLoc1.offset+1;                // Just behind the marker 
                    } else {
                      tLoc1.offset = tLoc1.offset-1;                // Just before the marker 
                    }  
                    tLoc2.offset = tLoc1.offset;
                    tRange  = new TextRange(tLoc1,tLoc2);          // TextRange after/before current marker
                  
                    var findParams = new PropVals();                // Get the find parameters for finding marker
                    findParams = GetFindParamsMarker (sMarkerName, sAdverb); 
                  
                    InitFA_errno ();                                // reset - it is write protected
                  // this finds a text range (object pgf) of length 1, even if another marker precedes or succeds the #calc marker
                    fRange = oDoc.Find(tRange.beg, findParams);    // finds text range (object pgf), lenght 1
                    aoMarkerRange = oDoc.GetTextForRange (fRange, Constants.FTI_MarkerAnchor);  // this is an array
                    for (var j = 0; j < aoMarkerRange.length; j++) {  //maybe you'll find more markers  
                      var oTextItem = aoMarkerRange[j];  
                      foundMarkers.push(oTextItem.obj)              //gather all markers  
                      }
                    oMarker = foundMarkers[0];                      // always only 1 is found
                    
                    if (FA_errno !== Constants.FE_Success) {        // is this canged after the find?
                      return undefined;                            // no next/previvious marker present
                    }
                    return oMarker;                                // we have found a next/prev marker
                  }