I am trying to format a text in InDesign that was originally written in LaTex, so I have all the footnotes in the main text surrounded by \footnote{} tags:
This is my main text\footnote{with foonotes and sometimes with other braces inside footnotes such as\ref{section2}}, and I want to format it properly.
I have hundreds of notes so I would like to write a script that can format them automatically. I am using the one below (found here https://gist.github.com/welblaud/c21a96f2f23db58b4011726cf21addb8) but so far I’m unable to adapt it to match my pattern.
What am I missing?
Application.prototype.main = function(){
if (this.documents.length <= 0) return;
var tg = this.selection[0] || this.activeDocument;
if ('appliedFont' in tg) tg = tg.parent;
if (tg.constructor == TextFrame) { tg = tg.parentStory; }
if (!('findGrep' in tg)) return;
/* Here it is neecessary to choose a pattern for wrapping the note, we are not parsing
here, hence the rough technique! */
var fnPatterns = ["(\\footnote\{)([^\}]+)(\})"];
var count = 0;
for(patterCounter = 0; patterCounter < fnPatterns.length; patterCounter++){
fnPattern = fnPatterns[patterCounter];
var fnFinds = (function(){
this.findGrepPreferences = this.changeGrepPreferences = null;
this.findGrepPreferences.findWhat = fnPattern;
var ret = tg.findGrep();
this.findGrepPreferences = this.changeGrepPreferences = null;
return ret;
}).call(this);
var fnFind, fnPrefix,fnSuffix, rg = new RegExp(fnPattern), ip, fnParent, fn, count;
while (fnFind = fnFinds.pop()){
fnPrefix = fnFind.contents.match(/^@[^@]+@/)[0];
fnSuffix = fnFind.contents.match(/@[^@]+@/)[0];
try {
// add footnote
fn = fnFind.footnotes.add(LocationOptions.AFTER, fnFind.insertionPoints[-1]);
// duplicate the text
fnFind.texts[0].characters.itemByRange(fnPrefix.length,fnFind.texts[0].characters.length-fnSuffix.length-1).duplicate(LocationOptions.AT_END, fn.texts[0]);
// remove the original
fnFind.characters.itemByRange(0,fnFind.characters.length-2).remove();
++count;
}
catch(_){}
}
}
alert((count)? (count+" footnote(s) successfully added."): "No footnote added. Make sure you use the relevant pattern.");
}
app.doScript('app.main();', ScriptLanguage.javascript, undefined, UndoModes.entireScript, app.activeScript.displayName);
Try to replace:
var fnPatterns = ["(\\footnote\{)([^\}]+)(\})"];
with:
var fnPatterns = ["\\\\footnote\\{.+?\\}"];
And:
fnPrefix = fnFind.contents.match(/^@[^@]+@/)[0];
fnSuffix = fnFind.contents.match(/@[^@]+@/)[0];
with:
fnPrefix = '\\footnote{';
fnSuffix = '}';
It should handle all footnotes without the nested \ref{...}
tags.
To handle the nested tags I'd propose to replace their {}
with something else. With @
for example. And change them back to {}
after the main code is done. It can be done if you add the several lines before and after the app.doScript()
:
// change '\ref{...}' --> '\ref@...@'
app.findGrepPreferences = app.changeGrepPreferences = null;
app.findGrepPreferences.findWhat = "\(\\\\ref\)\\{\(.+?\)\\}";
app.changeGrepPreferences.changeTo = "$1@$2@";
app.activeDocument.changeGrep();
// run the script
app.doScript('app.main();', ScriptLanguage.javascript, undefined, UndoModes.entireScript, app.activeScript.displayName);
// change '\ref@...@' --> '\ref{...}'
app.findGrepPreferences = app.changeGrepPreferences = null;
app.findGrepPreferences.findWhat = "\(\\\\ref\)@\(.+?\)@";
app.changeGrepPreferences.changeTo = "$1\{$2\}";
app.activeDocument.changeGrep();
If you have another nested tags you can toggle them about the same way.
But if you have nested tags inside nested tags \ref{...\subref{...}...}
it may require a more complicated recursive solution or a particular sequence of substitutions (frist from inner tags to outer tags and then in reverse order, probably).
This is why, by the way, the start and end tags <a>...<b>...</b>...</a>
work better than brackets {...{...}...}
.