Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Script to change red text to black?

Enthusiast ,
Apr 28, 2025 Apr 28, 2025

Background: We use red font to indicate changes in the draft document. Then we change the red text back to black before issuing the final version of the document. We sometimes have master page borders and artwork that we use red text with that we do NOT want to change.

 

Four questions:

 

  • Is there a way to manually search for red text and find it? I didn't see it in the find and replace options? (If I could find it manually, I would be better able to find a way to script it.)

 

  • Is there a way to script this? I found a script on here to find and replace text, but I don't think this would be the same thing. I know tables present some difficulty, in that if press Ctrl-A to select all and change the font, I usually have to change the tables.

 

  • My lead would prefer for the script to find the red text and prompt if you want to change it or not? (He's worried about the automated script changing the artwork and/or occasional (rare) times that we actually want red text in the document). Can this be done?

 

  • Finally (easier, but I'm not sure how) - could a script be written that would change the active selection to red text? (Basically, the same thing as selecting red from the color portion of the graphics toolbar, but from a button on a script window and without having to go through the drop-down.)

 

Thanks in advance!

 

-

TOPICS
Scripting
2.2K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 2 Correct answers

Community Expert , May 02, 2025 May 02, 2025
var doc, textRange;

doc = app.ActiveDoc;
textRange = doc.TextSelection;

applyTextColor (textRange, "Black", doc);

function applyTextColor (textRange, colorName, doc) {
    
    var color, prop;
    
    // Get the color object.
    color = doc.GetNamedColor (colorName);
    // Make sure the color exists in the document.
    if (color.ObjectValid () === 1) {
        // Make a property list containing the color.
        prop = new PropVal ();
        prop.propIdent.num = Constants.FP_Color;
   
...
Translate
Enthusiast , May 05, 2025 May 05, 2025

@frameexpert - THANK YOU!!!!

 

I got the script working. Seems to do fine. Here is the full find and replace script in case anyone searches this thread:

main();

function main(){  
  var doc = app.ActiveDoc;
  if(!doc.ObjectValid())
  {
    alert("No active document. Cannot continue.");
    return;   
  }
FindAndReplaceColor(doc, doc.MainFlowInDoc, 'Red', 'Black') ;
}

function FindAndReplaceColor(doc, flow, findString, replaceString) {
// https://community.adobe.com/t5/framemaker-discussions/find-
...
Translate
Community Expert ,
Apr 28, 2025 Apr 28, 2025

Changing text properties is always tricky because it can be difficult to revert to the default settings. The best way to do this in FrameMaker is to use Conditional Text because, while you can show the condition indicator (red text, etc.), it doesn't affect the underlying text properties. Plus, you can temporarily hide the condition indicator for printing, etc.

 

All of what you asked about is scriptable, although it's complex enough where it will likely require some cost. I would be glad to discuss the project with you off list. Alternatively, you could break these down into multiple tasks and post them as individual questions here on the forum. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 28, 2025 Apr 28, 2025

@frameexpert - Thank you. I appreciate the offer. I did some experimenting and discovered I can manually change it by searching for Character Formats. Let me do some more experimenting and I'll let you know how it goes.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 28, 2025 Apr 28, 2025

Even if you decide to do it manually, I would still suggest you try Condition Formats instead of just changing font colors. You can search for Condition Formats too.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 28, 2025 Apr 28, 2025

We use Conditional Formats a LOT also, but it seems like it it would be more difficult for this particular instance.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 29, 2025 Apr 29, 2025

Another approach would be to have multiple red colors of different names. You'll of course have the default “Red” in FM, but you could define a “Red.Change” of the same or similar color values.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 29, 2025 Apr 29, 2025

@Bob_Niland - We're still somewhat skipping the point of how to change the value with a script, but I'll look into that.

Your idea brings up a good suggestion, however. 

 

"Red.change" would work if I were building new templates, but we have a lot of existing documents using prior templates.

 

However, if I had text that I wanted to stay red (not revised text) - rarely happens, I could define a color like "Red.Static" or similar and use that for that text.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 29, 2025 Apr 29, 2025
main ();

function main () {

    var doc;
    
    doc = app.ActiveDoc;
    if (doc.ObjectValid () === 1) {
        processDoc (doc);
    }
}

function processDoc (doc) {

    var color, pgf;
    
    // Get the color object.
    color = doc.GetNamedColor ("Red");
    if (color.ObjectValid () === 1) {
        // Get the paragraph where the cursor is.
        pgf = doc.TextSelection.beg.obj;
        if (pgf.ObjectValid () === 1) {
            // Color the paragraph.
            pgf.Color = color;
        }
    }
}
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 30, 2025 Apr 30, 2025

@frameexpert - Thanks, but your script changes the color of the entire paragraph. I only want to change the color of the selection.

 

I'm looking for two scripts.

 

First script changes the selection to red. For example, if my document had "This is sentence 1." and "sentence 1" was selected, "sentence 1" should be turned red.

 

Second script should loop through the document and change any "Red" characters to "Black". I tried to write that using this, but it fails (I don't think it is finding the red text, and while I found the "find" command in the scritping guide, I didn't see any mention of "change" or something similar to Change and FInd):

main();

function main(){  
  var doc = app.ActiveDoc;
  if(!doc.ObjectValid())
  {
    alert("No active document. Cannot continue.");
    return;   
  }
FindAndReplaceColor(app.ActiveDoc, app.ActiveDoc.MainFlowInDoc, 'Red', 'Black') ;
}

function FindAndReplaceColor(activeDoc, flow, findString, replaceString) {
// https://community.adobe.com/t5/framemaker-discussions/find-replace/td-p/3581679#4032650
// https://community.adobe.com/t5/framemaker-discussions/find-and-replace-text/td-p/14438481#M82917
var tr = new TextRange();
var restoreTR, frame = 0;
var loopCounter = 0, replacementCounter = 0;
var findParams = new PropVals();

//if the flow object is not valid, assume the main flow
if(activeDoc.ObjectValid() && !flow.ObjectValid()){
flow = activeDoc.MainFlowInDoc;
}

//get the first text frame in the flow, a starting point to
//find the first paragraph
if(flow.ObjectValid()){
frame = flow.FirstTextFrameInFlow;
}

//At this point, if we don't have a frame object, might as well abort.
if(!frame.ObjectValid()){
Alert("Could not find a starting point for the search. Cannot continue." , Constants.FF_ALERT_CONTINUE_WARN);
return replacementCounter;
}

//store the original text selection as an amenity to restore after the action.
restoreTR = activeDoc.TextSelection;

//now, set up the starting text range as the very beginning
//of the flow. We'll move straight from beginning to end.
tr.beg.obj = tr.end.obj = frame.FirstPgf;
tr.beg.offset = tr.end.offset = 0;

//set up our find parameters. We want to configure it to look
//for a string and perhaps be case sensitive. We don't need
//the find to wrap because we are controlling the flow from
//beginning to end.
findParams = AllocatePropVals(2);

findParams[0].propIdent.num = Constants.FS_FindCharFmt.Color=findString;
//findParams[0].propVal.valType = Constants.Color;
//findParams[0].propVal.sval = findString;

//findParams[1].propIdent.num = Constants.FS_FindCustomizationFlags;
//findParams[1].propVal.valType = Constants.FT_Integer;
//if(considerCase){
//findParams[1].propVal.ival = Constants.FF_FIND_CONSIDER_CASE;
//}
//else{
//findParams[1].propVal.ival = 0;
//}

//initialize the errno global, which will be used to
//track the progress of the find and replace
FA_errno = Constants.FE_Success;

//and do an initial find to get started.
tr = activeDoc.Find(tr.beg, findParams);

//now, run the find and replace loop as long as we keep finding things.
//The loop counter is just an emergency back door in case something
//goes critically wrong and causes an endless loop.
while(FA_errno === Constants.FE_Success && loopCounter++ < 1000){

//set up the text range to clear the original text
activeDoc.TextSelection = tr;

//clear it
//activeDoc.Clear(0);

//insert the new text. We should be able to use the
//original beginning of the text range where the old text was
//found.
activeDoc.Change(tr.beg, replaceString);

//now, lets jimmy the text range in memory to place it directly
//after the string we just inserted, so the find picks back up after that.
tr.beg.offset += replaceString.length;

//increment our return counter
if(FA_errno === Constants.FE_Success){
replacementCounter++;
}

//...and find the next instance. We'll reset FA_errno again just in case
//something screwy happened while we were replacing text.
FA_errno = Constants.FE_Success;
tr = activeDoc.Find(tr.beg, findParams);
}

//we're done. Restore the document to it's original area of display
activeDoc.TextSelection = restoreTR;
activeDoc.ScrollToText(restoreTR);

return replacementCounter;
} // End FindAndReplaceString

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 01, 2025 May 01, 2025

Right. I was just giving you a head start on some of the concepts. You could use my code to change your text back to black as long as all paragraphs should be black by default.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 01, 2025 May 01, 2025

Makes sense, but I can't quite do that. We only use red for changes, but we use blue for E-mail addresses. So if I'm understanding correctly, I would have to run your script and then change the e-mail addresses back from black to blue, which is more work than manually running the find and replace.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 01, 2025 May 01, 2025

I'm going to give up on this for now. I'll try to come back to it later. I made some limited progress with some of Klaus Daube's scripts (which are really collections of @frameexpert and @Russ Ward 's scripts): This is what I have so far (edited out a lot of non-applicable code like searching for anchored frames, etc.):  (And, yes, I did notice Msg02 ...)

main();

function main(){  
  var oDoc = app.ActiveDoc;
  if(!oDoc.ObjectValid())
  {
    alert("No active document. Cannot continue.");
    return;   
  }
FindAndReplaceString (oDoc, "Red", "Black", 5);
}

function FindAndReplaceString(oDoc, sFind, sReplace, loopMax) { //========================
/*            In the active document replace a string by another one (all occurrences)
Arguments     oDoc            Document to be handled, not necessarily the current document
              sFind           String to be found and replaced
              sReplace        String for replacement
              loopMax         emergency back door - number of maximum expected finds (will be doubled here)
Returns       Count of replacements
Calling       GetFindParameters, InitFA_errno
Comment       Function operates only on MainFlowInDoc. There is no initial TextSelection,
              hence start directly at the first paragraph.
Reference     Russ Ward in https://forums.adobe.com/thread/895626 and Rick Quatro
Used in       FMbiblio
History       2021-07-15
              2022-06-02 Update for mnemonic Find Type
*/
var oFindParms, oFirstPgf, lC = 0, nReplCount, restoreTR, tr;

  tr = new TextRange();
  nReplCount = 0;
  oFindParms = new PropVals();
  oFirstPgf = oDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;

  tr.beg.obj = tr.end.obj = oFirstPgf;            // set up the starting text range as the very beginning
  tr.beg.offset = tr.end.offset = 0;              // of the flow. We'll move straight from beginning to end.
  trSaved = tr                                    // to come back after work
//We don't need the find to wrap because we are controlling the flow from beginning to end.

// WAS GetFindParmeters ("TXTTXT" ...
  oFindParms = GetFindParameters ("CHRFMT", sFind, 0, false, false, false);
//                                     (sType, sSearch, iMode, bWord, bCase, bBack)

  InitFA_errno ();                          // reset - it is write protected
  tr = oDoc.Find(tr.beg, oFindParms);             // and do an initial find to get started.

  while(FA_errno === Constants.FE_Success && lC++ < 2*loopMax) { //find and replace loop as long as we keep finding
    oDoc.TextSelection = tr;                      // set up the text range to clear the original text
    oDoc.Clear(0);                                // clear it
    return; // Return added. I figured if it deleted the red text, at least I knew it found it.
    oDoc.AddText(tr.beg, sReplace);               // insert the new text at the original beginning of the text range
    tr.beg.offset += sReplace.length;             // lets jimmy the text range in memory to place it directly after
                                                  // the string we just inserted, so the find picks back up after that.
    if(FA_errno === Constants.FE_Success) {       // increment our return counter - does not work
      nReplCount++;
    }
    InitFA_errno ();                        // to be used to track the progress of the find and replace
    tr = oDoc.Find(tr.beg, oFindParms);           // something screwy happened while we were replacing text.
  }
  oDoc.ScrollToText(trSaved);                     // we're done. Restore the document to it's original area of display
  giFMbib_LvlTrace -= 1;
  return nReplCount;
} // --- end FindAndReplaceString -----------------------------------------------------------------


function GetFindParameters (sFType, sSearch, iMode, bWord, bCase, bBack) { //==============
/*            Set up search parameters accordingly
Argument      sFType          Textual ID of Find Type. See Table asFindType
              sSearch         what to search for - used only for certain types
              iMode           0 Simple search
                              1 Wildcard search; excludes RegEx and simple Search
                              2 Regex search; excludes bWord and bBack; RegexFlavour is set to Perl
              bWord           true to constrain search to whole word
              bCase           true to consider case in search
              bBack           true to search backwards
Returns       Parameters for the find method
Comment       FS_FindWrap: A flag that determines whether the find operation wraps when it
              reaches the location where the search began. Default is True; the find operations wraps.
              If False, after reaching the location where the search began, the find operation
              returns an empty TextRange and  FA_errno is set to FE_NotFound (-95).
              → This flag can not be used to stop search at end of document ...
              The following Constants.FS_xx are not handled in this routine:
               2 FS_FindElementTag
               7 not defined
              14 FS_FindCondTextNotInCondTags
Calling       Message
Called by     FindSomething
Reference     FDK Function Reference, F_ApiFind(), https://forums.adobe.com/thread/961616
Used in       FMfindRepl
History       2020-12-01
*/
var bWild, bRegEx, findParms, jj, qFlags, oPropVal1, oPropVal2, oPropVal3, oPropVal4,
    msg_01, msg_02, msg_03;

  msg_01 = "Can not handle sFType «%01». Probably program error.";
  msg_02 = "«Find Character Format» is awfully complicated. Hence not implemented.";
  msg_03 = "«Find Selection» is not explained at all in the FDK/Scripting Guide. It is not known what it really means. Hence not implemented.";

  if (iMode == undefined) {iMode = 0;}
  if (bWord == undefined) {bWord = false;}
  if (bCase == undefined) {bCase = false;}
  if (bBack == undefined) {bBack = false;}  bWild  = iMode == 1;
  bRegEx = iMode == 2;

  findParms = new PropVals();

  oPropVal1 = new PropVal() ; // --- NoWrap stops at the iniital find start ----- Const.FS_FindWrap ???
  oPropVal1.propIdent.num = Constants.FS_FindWrap ;
  oPropVal1.propVal.valType = Constants.FT_Integer;
  oPropVal1.propVal.ival = 0 ;                    // no wrap
  findParms.push(oPropVal1);

  oPropVal2 = new PropVal() ;
  if     (sFType == "CHRFMT") { // ------------------------------------ Constants.FS_FindCharFmt
    // this should not appear in the call
    oPropVal2.propIdent.num = Constants.FS_FindChrFmt;
    oPropVal2.propVal.valType = Constants.Color;
    oPropVal2.propVal.sval = sSearch;
    //KLD_Z.Message ("E", msg_02, "GetFindParameters");
 //   return null;
  }  else if (sFType == "TXTTXT") { // --------------------------------------- Constants.FS_FindText
    oPropVal2.propIdent.num = Constants.FS_FindText;
    oPropVal2.propVal.valType = Constants.FT_String;
    oPropVal2.propVal.sval = sSearch;
  } else {
    KLD_Z.Message ("E", msg_01, "GetFindParameters", [sFType]);
    return null;
  }
  findParms.push(oPropVal2);

  if (bWord || bCase || bBack || bRegEx || bWild) {                 // customisation flags are ORED
    oPropVal3 = new PropVal() ;
    oPropVal3.propIdent.num = Constants.FS_FindCustomizationFlags ;
    oPropVal3.propVal.valType = Constants.FT_Integer;
    qFlags = 0;
    if (bCase)  { qFlags = qFlags   | Constants.FF_FIND_CONSIDER_CASE;}                     // 0x01
    if (bRegEx) { qFlags = qFlags   | Constants.FF_FIND_USE_REGEX;                          // 0x10
        oPropVal4 = new PropVal ();
        oPropVal4.propIdent.num = Constants.FS_RegexFlavour;                                // 17
        oPropVal4.propVal.valType = Constants.FT_Integer;
        oPropVal4.propVal.ival = Constants.FR_USE_PERL;                                     // 1
        findParms.push(oPropVal4);
    } else {
      if (bWild)  { qFlags = qFlags | Constants.FF_FIND_USE_WILDCARDS;}                     // 0x04
      if (bWord)  { qFlags = qFlags | Constants.FF_FIND_WHOLE_WORD;}                        // 0x02
      if (bBack)  { qFlags = qFlags | Constants.FF_FIND_BACKWARDS;}                         // 0x08
    }
    oPropVal3.propVal.ival = qFlags;              // qFlags OK; ...ival reports error in ESTK
    findParms.push(oPropVal3);
  }
return findParms;
} //---  end GetFindParameters --------------------------------------------------------------------

function InitFA_errno () { //==============================================================
/*            Reset FA_errno
Arguments     oDoc            Current document
              asNames         Array of xy-names
Returns       Function value is Modified constant
Called by     CollectVarsInDoc
Calling       -
Comment       FA_errno is write protected and hence can not be set to 0 programmatically
Usage         ...
              findParams = GetFindParameters (2, null);     // finding any variable, no wrap
              InitFA_errno ();                              // reset - it is write protected
              oTR = oDoc.Find(oTR.beg, findParams);         // and do an initial find to get started.
              while(FA_errno === Constants.FE_Success) {
                ...
Reference     https://forums.adobe.com/thread/962910
History       2020-12-29
*/
  app.GetNamedMenu("!MakerMainMenu");             //If this fails, you've got a bigger problem
  return;
} //--- end InitFA_errno --------------------------------------------------------------------------

To do:

The script isn't finding anything. I suspect:

    oPropVal2.propIdent.num = Constants.FS_FindChrFmt;
    oPropVal2.propVal.valType = Constants.Color;
    oPropVal2.propVal.sval = sSearch;

is incorrect. Page 849 (780 printed) of FrameMaker_Scripting.pdf (Doc>Find) says "FS_FindCharFmt No associated property. One of more of the following additional properties should be specifed to tailor the search ... color."  But it doesn't tell you HOW to specify any of the additional properties.

 

With that figured out, the script should locate the red text. Then the original script deleted the text and replaced it with the sReplace text. I would need to figure out how to leave the text but change the color (by applying the Character Format).

 

(Actually, if the script only found the text, that would somewhat be helpful as the author could at least manually change the text to black and would at least know it was there.)

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 01, 2025 May 01, 2025

https://community.adobe.com/t5/framemaker-discussions/find-chars-strings-with-a-certain-condition-ap... - Not sure if this helps or not. Initial question was about condiitonal formats, but later discussion mentions character formats and when they change.  And the link is applying a NAMED character format, not just changing a font color, so probably not exactly what I am looking for ...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2025 May 02, 2025

You need to create a property list, add the color to the property list, and then use SetProps to apply the color to the text range. Although this example, is applying a character format name, not a color, the premise is the same.

prop = new PropVal ();
prop.propIdent.num = Constants.FP_CharTag;
prop.propVal.valType = Constants.FT_String;
prop.propVal.sval = name;
doc.SetTextPropVal (textRange, prop);
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2025 May 02, 2025

Here is what you need to apply a color to the selected text. I suggest putting this in a function so that it's easy to call on a particular text range.

var doc, textRange, color, prop;

doc = app.ActiveDoc;

color = doc.GetNamedColor ("Black");

prop = new PropVal ();
prop.propIdent.num = Constants.FP_Color;
prop.propVal.valType = Constants.FT_Id;
prop.propVal.obj = color;

textRange = doc.TextSelection;
doc.SetTextPropVal (textRange, prop);
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2025 May 02, 2025
var doc, textRange;

doc = app.ActiveDoc;
textRange = doc.TextSelection;

applyTextColor (textRange, "Black", doc);

function applyTextColor (textRange, colorName, doc) {
    
    var color, prop;
    
    // Get the color object.
    color = doc.GetNamedColor (colorName);
    // Make sure the color exists in the document.
    if (color.ObjectValid () === 1) {
        // Make a property list containing the color.
        prop = new PropVal ();
        prop.propIdent.num = Constants.FP_Color;
        prop.propVal.valType = Constants.FT_Id;
        prop.propVal.obj = color;
        // Apply the color to the text.
        doc.SetTextPropVal (textRange, prop);    
    }
}
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 05, 2025 May 05, 2025

@frameexpert - THANK YOU!!!!

 

I got the script working. Seems to do fine. Here is the full find and replace script in case anyone searches this thread:

main();

function main(){  
  var doc = app.ActiveDoc;
  if(!doc.ObjectValid())
  {
    alert("No active document. Cannot continue.");
    return;   
  }
FindAndReplaceColor(doc, doc.MainFlowInDoc, 'Red', 'Black') ;
}

function FindAndReplaceColor(doc, flow, findString, replaceString) {
// https://community.adobe.com/t5/framemaker-discussions/find-replace/td-p/3581679#4032650
// https://community.adobe.com/t5/framemaker-discussions/find-and-replace-text/td-p/14438481#M82917
//  https://community.adobe.com/t5/framemaker-discussions/script-to-change-red-text-to-black/m-p/15293234
var tr = new TextRange();
var restoreTR, frame = 0;
var loopCounter = 0, replacementCounter = 0;
var findParams = new PropVals();
//if the flow object is not valid, assume the main flow
if(doc.ObjectValid() && !flow.ObjectValid()){
flow = doc.MainFlowInDoc;
}

//get the first text frame in the flow, a starting point to
//find the first paragraph
if(flow.ObjectValid()){
frame = flow.FirstTextFrameInFlow;
}

//At this point, if we don't have a frame object, might as well abort.
if(!frame.ObjectValid()){
Alert("Could not find a starting point for the search. Cannot continue." , Constants.FF_ALERT_CONTINUE_WARN);
return replacementCounter;
}

//store the original text selection as an amenity to restore after the action.
restoreTR = doc.TextSelection;

//now, set up the starting text range as the very beginning
//of the flow. We'll move straight from beginning to end.
tr.beg.obj = tr.end.obj = frame.FirstPgf;
tr.beg.offset = tr.end.offset = 0;

//set up our find parameters. We want to configure it to look
//for the color format. We don't need
//the find to wrap because we are controlling the flow from
//beginning to end.
findParams = AllocatePropVals(1);
 var color = doc.GetNamedColor (findString);
findParams[0].propIdent.num = Constants.FP_Color;
findParams[0].propVal.valType = Constants.FT_Id;
findParams[0].propVal.obj = color;

//initialize the errno global, which will be used to
//track the progress of the find and replace
FA_errno = Constants.FE_Success;

//and do an initial find to get started.
tr = doc.Find(tr.beg, findParams);

//now, run the find and replace loop as long as we keep finding things.
//The loop counter is just an emergency back door in case something
//goes critically wrong and causes an endless loop.
while(FA_errno === Constants.FE_Success && loopCounter++ < 1000){

//set up the text range to change the color
doc.TextSelection = tr;

//clear it - Uncomment this line to test if the search is finding the correct items.
//activeDoc.Clear(0);

// Change the color:
applyTextColor (tr, replaceString, doc);

//increment our return counter
if(FA_errno === Constants.FE_Success){
replacementCounter++;
}

//...and find the next instance. We'll reset FA_errno again just in case
//something screwy happened while we were replacing text.
FA_errno = Constants.FE_Success;
tr = doc.Find(tr.beg, findParams);
}

//we're done. Restore the document to it's original area of display
doc.TextSelection = restoreTR;
doc.ScrollToText(restoreTR);

return replacementCounter;
} // End FindAndReplaceString

function applyTextColor (textRange, colorName, doc) {
    
    var color, prop;
    
    // Get the color object.
    color = doc.GetNamedColor (colorName);
    // Make sure the color exists in the document.
    if (color.ObjectValid () === 1) {
        // Make a property list containing the color.
        prop = new PropVal ();
        prop.propIdent.num = Constants.FP_Color;
        prop.propVal.valType = Constants.FT_Id;
        prop.propVal.obj = color;
        // Apply the color to the text.
        doc.SetTextPropVal (textRange, prop);    
    }
} // End applyTextColor
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 05, 2025 May 05, 2025

Good job! Thank you for the feedback.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 05, 2025 May 05, 2025

Grrr - New issue. (I thought I knew how to handle this one.)

The script does great at changing the red text to black.

 

If a certain conditional format is applied, the first paragraph in the document will be red and we want that paragraph to STAY red. So, if that conditional format is applied, I want the search to start at the Second paragraph in the document.

 

I know how to check if the format is applied.

 

I thought I could just change:

tr.beg.obj = tr.end.obj = frame.FirstPgf;

to:

tr.beg.obj = tr.end.obj = frame.FirstPgf.NextPgfInFlow;

but it doesn't seem to work ...

 

More confusing - I used your getPgfText function and frame.FirstPgf.NextPgfInFlow matches the second paragraph, so I don't know why the search is not starting from that point.

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 05, 2025 May 05, 2025

It may be starting with the second paragraph, but if it is probably catching the first paragraph as it loops around. This is one of the pitfalls of using text colors to mark text instead of Conditional Text.

 

One thing to try: turn off the Condition Indicators before running the script so that it doesn't find red conditional text.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 05, 2025 May 05, 2025

Found the error, but haven't fixed it. The script IS starting at the second paragraph, but then it is looping back to the first paragraph, so I need to avoid the loop. I'm going to look at the other code and see what I can come up with ...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 05, 2025 May 05, 2025

There's supposed to be a way to keep the script from wrapping. Since I am starting at the beginning of the doc, it should complete and not need to wrap back. I looked at the longer script I posted earlier and the FrameMaker Scripting .pdf and tried changing my code to this:

findParams = AllocatePropVals(2);
 var color = doc.GetNamedColor (findString);
findParams[0].propIdent.num = Constants.FP_Color;
findParams[0].propVal.valType = Constants.FT_Id;
findParams[0].propVal.obj = color;
findParams[1].propIdent.num = Constants.FS_FindWrap ;
findParams[1].propVal.valType = Constants.FT_Integer;
findParams[1].propVal.ival = 0 ;                    // no wrap

but it didn't work.

Actually, looking at the comments for the Find and Replace Script I used, there is a comment about not needing the script to wrap and two lines I commented out (and deleted):

findParams[1].propIdent.num = Constants.FS_FindCustomizationFlags;
findParams[1].propVal.valType = Constants.FT_Integer;

but that didn't work either.

Your idea about turning off the conditional formatting would probably work, but that means I would need to check in the CF is shown, store that in a variable, hide the CF, run the search, check the variable and undhide the CF. Not difficult, but would be easier if the script just did not wrap.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 05, 2025 May 05, 2025
var showCondIndicators;

// Store the current condition indicator settings.
showCondIndicators = doc.ShowCondIndicators;

// ... do your thing

// Restore the original condition indicator settings.
doc.ShowCondIndicators = showCondIndicators;
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 05, 2025 May 05, 2025

I don't think it's that simple. We have about 25 conditional text formats. About 18 of them COULD have red text that we would want to change to black. One of them has red text that we don't want to change to black.

 

So I think I need to check for that one, hide it, search, and then restore it. Not the end of the world, but it would be simpler and easier to follow if the find didn't wrap, which is supposed to be controllable, but ...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 05, 2025 May 05, 2025

I was whining a little bit. I got it working!!

var CondFmt = doc.GetNamedObject (Constants.FO_CondFmt, "ThisStaysRed");
if (CondFmt.ObjectValid){
    var IsRed = CondFmt.CondFmtIsShown;
     if (IsRed) {
            CondFmt.CondFmtIsShown = 0;
    }   
}
tr.beg.obj = tr.end.obj = frame.FirstPgf;

// ... seach continues

if (CondFmt.ObjectValid){
    CondFmt.CondFmtIsShown = IsRed; 
}
//we're done. Restore the document to it's original area of display

 Thank you again!!!!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines