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

Find chars/strings with a certain condition applied

Participant ,
May 30, 2015 May 30, 2015

Copy link to clipboard

Copied

Hello fellows,

I am writing an extendscript that is supposed to loop through all pgfs and find all characters/strings with a certain condition applied (let's say, Comment).

The problem is that in the scripting guide, I could not find a function that retrieves the condition property of a character. I tried using the JS "charAt(i)" function, but it does not seem to work in ES. Any idea how to implement such a function?

Below is the 1st draft of the script.

var doc = app.ActiveDoc;

if doc.ObjectValid() {

    checkCondFMt(doc);

}

else{

  Alert("No section open");

}

function checkCondFMt(doc) {

    var pgf = doc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;

    var CondObj=doc.GetNamedObject("Comment");

     while (pgf.ObjectValid()){

                     

               var textItems =pgf.GetText(Constants.FTI_String | Constants.FTI_LineEnd);

                var tr = new TextRange();            

                tr.beg.obj = tr.end.obj = textItems;

                tr.beg.offset = 0;

                 for (var i = 0; i < tr.len; i++ ) {

                  var c = tr.charAt(i);             

                  var PgfProps =doc.GetTextVal(c, Constants.FO_CondFmt);

                  alert (PgfProps.Name);

           }

                

        pgf=pgf.NextPgfInFlow;

    }

}

Thank you for your input in advance!

TOPICS
Scripting

Views

1.3K

Translate

Translate

Report

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 1 Correct answer

Community Expert , Jun 16, 2015 Jun 16, 2015

OK, I see the problem now. JavaScript does not have "block-scope" for its variables. It has function scope, so your "i" variable is being used in more than one loop. You should use a different variable for the inner loop:

for (var j = 0; j < oCond.length; j += 1) {

    if (oCond.Name == CondObj.Name) {

        applyCharFmt(textRange, doc);

    }                    

}

In the code sample above, I am using "j" for a counter for the inner loop.

In general, you can avoid problems like this by declari

...

Votes

Translate

Translate
Community Expert ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Roman, I have a 4-part post on my blog about removing conditions from text and table rows. Here is a link to the first one:

Removing Conditions From Text and Table Rows | FrameAutomation.com

-Rick

Votes

Translate

Translate

Report

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
Participant ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Hi Rick,

Thank you for your response and for a very useful and informative post!

In my specific case, I need to loop through all Pgfs and find all strings/characters to which the Comment condition is applied. My next step will be applying a char tag to those conditionalized strings/chars.

What I am trying to figure out is how to isolate the condtionalized strings and single characters in a Pgf. I found a JS function called "substr" or "substring" for isolating a range of chars and looping through them. Is this the one you would use?

Thanks again,

Roman

Votes

Translate

Translate

Report

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 ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

This is the part of the series I never got to :-). The following function will loop through all of the text in the selected paragraph and find each text range that has one or more conditions applied. You should be able to combine this with some of the code in my blog to test for a specific condition. Once you have the appropriate textRange, you should be able to apply a character format. Please let me know if you have any questions or comments.

#target framemaker

var doc = app.ActiveDoc;
var pgf = doc.TextSelection.beg.obj;

processConditions (pgf, doc);

function processConditions (pgf, doc) {

    var end = Constants.FV_OBJ_END_OFFSET, begin = 0, textRange = 0, prop;
   
    var textList = pgf.GetText(Constants.FTI_CharPropsChange);
    for (var i = textList.length - 1; i >= 0; i -= 1) {
       if (Constants.FTF_CONDITIONTAG & textList.idata) {
           begin = textList.offset;
            if (begin !== end) {
                textRange = new TextRange (new TextLoc (pgf, begin), new TextLoc (pgf, end));
                prop = doc.GetTextPropVal (textRange.beg, Constants.FP_InCond);
                if ((prop.propIdent.num) && (prop.propVal.osval.length !== 0)) {
                    alert (getText (textRange, doc));
                }
            }
            end = begin;
        }
    }
    if ((end < Constants.FV_OBJ_END_OFFSET) && (end > 0)) {
        textRange = new TextRange (new TextLoc (pgf, 0), new TextLoc (pgf, end));
        prop = doc.GetTextPropVal (textRange.beg, Constants.FP_InCond);
        if ((prop.propIdent.num) && (prop.propVal.osval.length !== 0)) {
            alert (getText (textRange, doc));
        }
    }   
}

function getText (textObj, doc) {
    // Gets the text from the text object.

    var text = "";
    // Get a list of the strings in the text object or text range.
    if (textObj.constructor.name !== "TextRange") {
        var textItems = textObj.GetText (Constants.FTI_String);
    } else {
         var textItems = doc.GetTextForRange (textObj, Constants.FTI_String);
    }
    // Concatenate the strings.
    for (var i = 0; i < textItems.len; i += 1) {
        text += (textItems.sdata);
    }
    return text; // Return the text
}

Votes

Translate

Translate

Report

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
Participant ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Hi Rick,

Thank you for your prompt response and for your help!

I wasn't even aware of the FTI_CharPropsChange constant existence. 🙂 This is an elegant solution for finding distinctive Pgf pieces.

I have a couple of questions regarding the code:

Line 6, 8 -- Novice's question: Why do you need to specify the pgf, doc variables in the processConditions() function? These are not the only vars used in it.

Line 13 -- Why do you decrement 1 here instead of incrementing by 1?

Lion 14 -- What does this line exactly say?

Line 23 -- Why is end equal to begin?

Line 26 -- What does this line exactly say?


General: it's not clear to me how you detect a single char with this code. AFAIK, FTI_String cannot include a single char, right?


Thank you for your explanations in advance!

Votes

Translate

Translate

Report

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 ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Hi Roman,

Lines 6, 8: These are the parameters required by the function that have to be "passed in" from the outside.

Line 13: When you get the list of text items on line 12, it is a fixed list at the time you query the paragraph. If the script ends up changing the list somehow, you want to make sure that the loop doesn't get messed up by the changes. By working from the end of the paragraph to the beginning, you make sure that any changes you make to the paragraph doesn't affect the list of text items.

Line 14: When you get a list of FTI_CharPropsChange items, there is an internal list of exactly which properties have changed at that point. Since we are only interested in Condition Format changes, this line tests for that. Any other property change would be ignored.

Line 23: The variable end starts at the end of the paragraph. When a property change is detected, begin will be less than end. The script will then make a TextRange variable between begin and end (line 17), which will be a range of text containing a unique set of conditions (or no conditions at all). After all the tests are made, the script will start over at begin so you have end = begin.

Line 26: Actually, in this particular script, lines 26-33 aren't necessary.

I am not sure why you want to test a single character. This script will test one or more consecutive characters with exactly the same conditions applied. That means if there is a single character by itself, the script will detect it, or if there are multiple consecutive characters, the script will detect them. You could write a script to test a single character at a time, but I am not sure why you would want to. Maybe I am not understanding what you want to do.

Votes

Translate

Translate

Report

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
Participant ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Hi Rick,

Thank you for the explanations! The script logic is not trivial, I should say.

I'd like to test a single character just because in some cases, the condition is applied to a letter/number only. According to the FDK guide, FTI_String can only represent a string of characters and not a single character, so it's not clear to me how the script detects a single char.

Thanks again for your explanations!

My best wishes,

Roman

Votes

Translate

Translate

Report

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 ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

The script will find consecutively applied character formats, whether it is just a single character or a whole paragraph. Test it on some content and you will see. You'll have to trust me on this one :-).

Votes

Translate

Translate

Report

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
Participant ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Hi Rick,

Did you mean "consecutively applied condition formats"?

Trust has been established. I'm just trying to understand the internals of ES.

Thanks again,

Roman

Votes

Translate

Translate

Report

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 ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Yes, sorry I meant Condition Formats.

Votes

Translate

Translate

Report

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
Participant ,
Jun 01, 2015 Jun 01, 2015

Copy link to clipboard

Copied

Thanks a lot, Rick!

Votes

Translate

Translate

Report

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
Participant ,
Jun 13, 2015 Jun 13, 2015

Copy link to clipboard

Copied

Hello fellows,

I've made some progress with the script. I've added a function that creates a Char format and a function that applies this format to the text that was conditionalized with a specific condition. I've also modified the script that Rick came up with so that it will search for strings with a specific condition applied. However, for some reason, the script gets stuck at some point, after applying the Char format to several strings it found in a document. I don't understand why the script enters some kind of a loop. Below is the code. Please, advise! Thanks!

#target framemaker

var doc = app.ActiveDoc;

var pgf = doc.FirstPgfInDoc;

Add_Char();

while (pgf.ObjectValid())

{

    processConditions (pgf, doc);

    pgf = pgf.NextPgfInDoc;

}

//Functions go here:

function Add_Char ()

{

    var CharAdded = doc.NewNamedObject (Constants.FO_CharFmt, "Txt_Char");

    var NSpellCheck = doc.GetNamedObject(Constants.FO_CharFmt, "NoSpellCheck");

    var charprops = NSpellCheck.GetProps();

    var bk_color = doc.GetNamedColor("Green");

    var font_color = doc.GetNamedColor("Black");

    var Bcolor_en = GetPropIndex(charprops, Constants.FP_UseBkColor);

    var index = GetPropIndex(charprops, Constants.FP_BkColor);

    CharAdded.UseBkColor = 1;

    CharAdded.BkColor = bk_color;

    CharAdded.SepOverride = font_color;

    return(1);

}

function processConditions (pgf, doc) {

    var end = Constants.FV_OBJ_END_OFFSET, begin = 0, textRange = 0, prop;

    var CondObj=doc.GetNamedCondFmt("Comment");

    //alert (CondObj.Name);

    var textList = pgf.GetText(Constants.FTI_CharPropsChange);

    for (var i = textList.length - 1; i >= 0; i -= 1) {

       if (Constants.FTF_CONDITIONTAG & textList.idata) {

           begin = textList.offset;

            if (begin !== end) {

                textRange = new TextRange (new TextLoc (pgf, begin), new TextLoc (pgf, end));

                prop = doc.GetTextPropVal (textRange.beg, Constants.FP_InCond);

                var oCond = prop.propVal.osval;

                if ((prop.propIdent.num) && (oCond.length !== 0)) {

                    for (var i = 0; i < oCond.length; i += 1) {

                       if (oCond.Name == CondObj.Name) {

                      applyCharFmt(textRange, doc);

                    

                        }

                

                    }

                  

                }

            }

            end = begin;

        }

    }

}

function applyCharFmt(textRange, doc)

{

           var newCharFmt =doc.GetNamedCharFmt ("Txt_Char");

                 

           if(newCharFmt.ObjectValid() == true)

          {

           //Get the character format properties

           var props = newCharFmt.GetProps();

           doc.SetTextProps (textRange, props);

          }

    

          else alert("Could not find the character format!");

       

}

}

Votes

Translate

Translate

Report

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 ,
Jun 14, 2015 Jun 14, 2015

Copy link to clipboard

Copied

Hi Roman. Make sure you show all the conditions at the beginning of the script. This may be what is causing problems. -Rick

doc.ShowAll = 1;

Votes

Translate

Translate

Report

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
Participant ,
Jun 14, 2015 Jun 14, 2015

Copy link to clipboard

Copied

Hi Rick,

I appreciate your response!

All conditions are exposed in the test document.

The status bar in ESTK shows "No errors" but there is a rolling indicator in the bottom right corner, as if the script execution has not ended.

In FM12, the char tag is applied to several strings with the specified condition. In FM10, nothing happens at all.

I am about to give up and port the script to Framescript, which seems to be a more stable scripting environment than Extendscript.

Best regards,

Roman

Votes

Translate

Translate

Report

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 ,
Jun 14, 2015 Jun 14, 2015

Copy link to clipboard

Copied

I haven't had a chance to actually test this, but one suggestion is to comment out some of the code and see if you can find out where it is getting stuck. For example, if you comment out the call to ApplyCharFmt does it still hang up?

Votes

Translate

Translate

Report

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
Participant ,
Jun 15, 2015 Jun 15, 2015

Copy link to clipboard

Copied

Hi Rick,

Commenting out ApplyCharFmt and calling alert (GetText...) just for the sake of a test leads to the same behavior. Framemaker 10, for example, becomes completely irresponsive.

Code-wise, I don't understand what is wrong. The script execution result is "No Errors" but it does nothing except for making Framemaker faint.

Best regards,

Roman

Votes

Translate

Translate

Report

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
Participant ,
Jun 16, 2015 Jun 16, 2015

Copy link to clipboard

Copied

Hi Rick,

I think I found what drives FM crazy when running the script.

FM gets stuck when the string(s) with the condition we are searching for have additional conditions applied.

If only the condition specified in the script is applied to the string (in this case, Comment), then the script works OK.

I guess, this issue has something to do with Constants.FTI_CharPropsChange, but I am not sure.


Thanks again,

Roman

Votes

Translate

Translate

Report

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 ,
Jun 16, 2015 Jun 16, 2015

Copy link to clipboard

Copied

OK, I see the problem now. JavaScript does not have "block-scope" for its variables. It has function scope, so your "i" variable is being used in more than one loop. You should use a different variable for the inner loop:

for (var j = 0; j < oCond.length; j += 1) {

    if (oCond.Name == CondObj.Name) {

        applyCharFmt(textRange, doc);

    }                    

}

In the code sample above, I am using "j" for a counter for the inner loop.

In general, you can avoid problems like this by declaring all of your variables at the top of the function:

function functionName (param1, param2) {

    var i, j, textlist; // etc.

    // function code...

}

That makes it easier to "keep track" of the variables and make sure you are not using any more than once.

-Rick

Votes

Translate

Translate

Report

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
Participant ,
Jun 16, 2015 Jun 16, 2015

Copy link to clipboard

Copied

LATEST

Hi Rick,

Good catch! Thank you very much!

As usually, the devil is in the details.

I'd better start defining variables at the top of the function, as you kindly suggested.

My best regards,

Roman

Votes

Translate

Translate

Report

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