Copy link to clipboard
Copied
Dear all - I'm back to my beloved project...
I want to replace a found string by a TextSelction (formatted text) and started with Jang’s famous function FindAndReplaceString.
Since my replacement comes from a different document (sourceDoc) I edited activeDoc to targetDoc and introduced a second document (sourceDoc).
Actually the replacePara comes from an arry where it had been placed to avoid switching back and forth between the documents of a book (where to find and replace) and the source documents. I have learnt in another function that the information on the array requires that the sourceDoc must stay open.
Obviously there is some fog around me ... and I need some sunshine.
function FindAndReplacePara (targetDoc, findString, sourceDoc, replacePara, loopMax) {
var tr = new TextRange();
var restoreTR, frame = 0, loopCounter = 0, replacementCounter = 0;
var findParams = new PropVals();
var firstPgf = targetDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;
tr.beg.obj = tr.end.obj = firstPgf; // 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
findParams = AllocatePropVals(2);
findParams[0].propIdent.num = Constants.FS_FindText;
findParams[0].propVal.valType = Constants.FT_String;
findParams[0].propVal.sval = findString;
findParams[1].propIdent.num = Constants.FS_FindCustomizationFlags;
findParams[1].propVal.valType = Constants.FT_Integer;
findParams[1].propVal.ival = Constants.FF_FIND_CONSIDER_CASE;
FA_errno = Constants.FE_Success; // errno global, to be used to track the progress of the find and replace
tr = targetDoc.Find(tr.beg, findParams); // and do an initial find to get started.
while(FA_errno === Constants.FE_Success && loopCounter++ < 2*loopMax) { //find and replace loop as long as we keep finding
targetDoc.TextSelection = tr; // set up the text range to clear the original text
targetDoc.Clear(0); // clear it
// targetDoc.AddText(tr.beg, replacePara); // insert the new text at the original beginning of the text range
// tr.beg.offset += replacePara.length; // lets jimmy the text range in memory to place it directly after
targetDoc.TextSelection = sourceDoc.replacePara; // paste the whole replacement paragraph
targetDoc.Paste (0); // <-- Current contents of clipboard is pasted !!!!
if(FA_errno === Constants.FE_Success) { // increment our return counter
replacementCounter++;
}
FA_errno = Constants.FE_Success; // ... find the next instance. We'll reset FA_errno again just in case
tr = targetDoc.Find(tr.beg, findParams); // something screwy happened while we were replacing text.
}
targetDoc.ScrollToText(trSaved); // we're done. Restore the document to it's original area of display
return replacementCounter;
} // --- end FindAndReplacePara
Hi Klaus,
Thanks for the explanation. I remember that GetTabRange stuff from way back. You have been quite patient and persistent with this project, indeed.
So, given that we are dealing with text ranges here, I think that the only simple approach is to perform a copy/paste. There is no way to save a "formatted string" in a variable. The only super-precise way would be to get a TextItems data structure from each text range in the sourceDoc, then meticulously recreate each item in the targetDoc. Th
...Copy link to clipboard
Copied
Hi Klaus,
I see dense fog around line 30 As best I can tell, this is a completely invalid statement:
targetDoc.TextSelection = sourceDoc.replacePara;
A text selection is a data structure that consists of a start point and an end point, where each point consists of a paragraph object and an offset. These objects must be members of the parent document itself. It doesn't make any sense to assign paragraph objects from another document to a text range. It would be like me giving out directions to the US White House, using a map of Moscow. No logical correlation anywhere in that. Furthermore, like I mentioned, a text range is a data structure with multiple objects. So it doesn't make sense to assign a single paragraph object to it. Furtherfurthermore, "sourceDoc.replacePara" is an invalid expression by itself, because there is no "replacePara" property of a document object. These are two separate variables passed in the function arguments.
You did mention that "replacePara" is a "TextSelection" object, so maybe my second point is invalid. But I'm not sure... your variable name suggests that it is a paragraph object. Also, there is no such thing as a TextSelection object, perhaps you meant a TextRange object? In any case, I am sure that points 1 and 3 are correct.
Anyway, now that I've sufficiently trashed line 30, perhaps you could elaborate on what you really want to do. Are you simply trying to copy a paragraph (or part of a paragraph) from sourceDoc into the Find locations in targetDoc? And could you clarify what kind of variable "replacePara" really is?
I think we can get this to work with minimal effort... I just see some need for clarification.
Russ
Copy link to clipboard
Copied
Thanks Russ for the answer - so I stepped back and first tried to just paste the data as string. This works perfectly thanks the function GetText (by Rick) which I use frequently in my script.
The relevant part in the script now is this:
targetDoc.TextSelection = tr; // set up the text range to clear the original text
targetDoc.Clear(0); // clear it
replaceString = GetText (replacePara, sourceDoc); // expects TextObject, Doc
targetDoc.AddText(tr.beg, replaceString); // insert the new text at the original beginning of the text range
tr.beg.offset += replaceString.length; // lets jimmy the text range in memory to place it directly after
But how can I insert the formatted text which is in the variable replacePara? replacePara is (watch the italic portion):
Müller, P. D. H. (1925). De viris illustribus, Carl Meyer (Gustav Prior), Hannover.
BTW: know what 'to jimmy' is: apply some brute force. IMHO special words protect against plagiarism...
I always keep the sources mentioned. In this functions it is
// Source: script by Russ Ward in https://forums.adobe.com/message/3888653#3888653
Copy link to clipboard
Copied
Klaus, I got an email from the forum with a post from you, but I don't see it here on the web page. I'll answer it anyway.
I can't figure out what you mean by "formatted text which is in the variable replacePara". What is "formatted text"? A variable cannot contain formatted text, at least the way you seem to be thinking. I need to know how you are setting replacePara and what type of variable it is.
My suspicion is that you just want to copy from the source document and paste to the target document. In that case, you need to set the text selection in the source doc, call sourceDoc.Copy() (with the source doc active, probably), activate the target doc, then targetDoc.Paste().
And by the way, "jimmy" is an excellent plagiarism detector. That's how I know the source code was originally from me. If Jang tried to swipe it, well, that dirty rat, totally busted.
Russ
Copy link to clipboard
Copied
Russ, the explanation of variable replacePara is somewhat lenghty:
«My suspicion is that you just want to copy from the source document and paste to the target document. In that case, you need to set the text selection in the source doc, call sourceDoc.Copy() (with the source doc active, probably), activate the target doc, then targetDoc.Paste().» is correct in principle, but...
The pupose of the discussed part of the script is to replace placeholders (such as {Barnes-Ellerbe, 2004 #48}) in targetDoc with complete references (such as Barnes-Ellerbe, S., Knudsen, K. E., and Puga, A. (2004). "2,3,7,8-Tetrachlorodibenzo-p-dioxin blocks androgen-dependent cell proliferation of LNCaP cells through modulation of pRB phosphorylation." Mol Pharmacol, 66(3), 502-11.) from a sourceDoc (note the italic part in this text - this i call formatted text, ince the whole thing can not be treated just as string).
Since the placeholders are located in various documents of a book, the information from the document with the replacement texts (sourceDoc ) is filled into arrays. Otherwise I would need to switch between the targetDoc/oDoc2 and sourceDoc/oDoc1 for each reference in the sourceDoc. BTW this sourceDoc is an RTF created by a bibliographic application (EndNote or Citavi) and opened in FM, hence a standard fm document.
I have 3 global arrays:
var gasFmtCitsRaw = []; // left column in processed RTF
var gasFmtCitsFmt = []; // right column in processed RTF
var gaoBibliography = []; // bibliography paragraphs from processed RTF
They are filled in function GetBiblioFromRTF with the following statements relevant for replacePara:
// --- read the bibliography paragraphs
while (pgf.ObjectValid()) { // until end of doc
tabRange = GetTabRange (pgf, goRtfDoc); // Get the text range starting after the TAB to the end of the paragraph.
if (tabRange) {
gaoBibliography.push(tabRange); // store the paragraph-part in the array
pgf = pgf.NextPgfInFlow;
} else { break } // We are out of the bibliography range
}
Then in a loop the find/replace operation is performed:
function ExpandInDoc (oDoc2, oDoc1) {
// oDoc2 target document where to replace
// oDoc1 source document of the replacements in the array
var j, jBiblio, nBiblio, nCitations, findString, replacePara, loopMax, overallCounter = 0;
var nCitations = gasFmtCitsRaw.length;
var loopMax = nCitations;
for (j = 0; j < nCitations; j += 1) {
findString = gasFmtCitsRaw;
jBiblio = gasFmtCitsFmt; // number of biblio-paragraph
replacePara = gaoBibliography[jBiblio-1]; // is object TextRange
replacementCounter = FindAndReplacePara (oDoc2, findString, oDoc1, replacePara, loopMax);
}
} // --- end ExpandInDoc
IMHO replacePara is a TextRange which contains formatted text (string pieces with character formats forming part of a paragraph).
Then function FindAndReplacePara comes into play.
I hope this will explain the nature of replacePara.
Copy link to clipboard
Copied
Hi Klaus,
Thanks for the explanation. I remember that GetTabRange stuff from way back. You have been quite patient and persistent with this project, indeed.
So, given that we are dealing with text ranges here, I think that the only simple approach is to perform a copy/paste. There is no way to save a "formatted string" in a variable. The only super-precise way would be to get a TextItems data structure from each text range in the sourceDoc, then meticulously recreate each item in the targetDoc. This would be wildly complicated, I think, so a copy/paste seems the most logical. I'm wondering, though, if I'm missing something, because I think maybe you would have tried it already if so (?)
Anyway, I would do something like this, starting at line 30 of your original code sample (untested code here):
app.ActiveDoc = sourceDoc;
sourceDoc.TextSelection = replacePara;
sourceDoc.Copy(0);
app.ActiveDoc = targetDoc;
targetDoc.Paste(0);
... etc.
Does this make sense, or am I barking up the wrong tree, as they say?
Russ
Copy link to clipboard
Copied
Wow! Russ, that's a real break-trhough!
This does exactly what I want to achieve!
Now I see the end of the tunnel for my project.
I had experimented with copy and paste but obviously did not get it right - my knowledge of the object model still is in anfant state...
Copy link to clipboard
Copied
Klaus, I'm happy to hear that. Regarding the copy/paste, it is my assumption that you have to make the source and target documents active before you do the copy and paste, respectively. Even though the Copy() and Paste() methods are assigned to the document object, I don't believe that they will just work independently. In the FDK, they were "global" functions that didn't need any document object... it was up to you to make whichever document active, just like working in the GUI. Anyway, the documentation doesn't say this anywhere, just my guess. I'd be interested to know if you could validate that.
Russ
Copy link to clipboard
Copied
Russ, it works perfectly, as you can see from this Captivate Flash.
What I have noted after that captureing is this: Although the ¶ format of the Footnote in the target file has no * in the information area, the format is not correct. Re-applying format Footnote lets the size shrink. Only the 'not expanded' footnotes starting with a { keep their format.
But this can be fixed by re-applying the format of the footnote.
The reason propably is that in the sourceDoc (coming from an RTF generated by the biblogrphic app) uses a format named HeadingRunIn with different properties. The effect will be even more visible, if I have a targetDoc with sans-serif styles...
Copy link to clipboard
Copied
FA_errno = Constants.FE_Success; // errno global, to be used to track the progress of the find and rep
Hi Klaus,
FA_errno is write-protected. This should result in an error message.
Copy link to clipboard
Copied
Hi Klaus and Klaus,
It is true (and unfortunate) that FA_errno is write-protected. With the FDK, it was common practice to reset it in certain circumstances. Nonetheless, there are tricks to do the same thing with ExtendScript. Here is a thread that shows one:
Are there situations where you can NOT override the FA_errno's code?
Russ
Copy link to clipboard
Copied
Hi Russ,
thanks for this link.
This is exactly what I am doing. I use :
var openParams = GetOpenDefaultParams();
It results in FA_errno = 0 and works fine.