Hi Selim,
I don't know why it's triggering an alert as a virus. If anyone knows a better way I could save the file so that doesn't happen, please let me know. Currently I just compress the text file with a .js suffix inside a zip archive - there should only be one file "find replace annot tx.js" in there.
The file makes no permanent changes to either PDFX-Change or your computer. If you make the JavaScripts folder, and put the javascript file (extracted from the zip) in there, it will run when PDFX-Change starts up to create the menu item.
If you just want to test it, you can copy and paste from below into the Javascript console on PDFX-Change (CTRL-J) and run it from there: In that case you should run it
without any document open or it will add the menu item, but it will only work with the current open document (you'll have to quit and restart to do the same on a different document).
Once the v1.2 tool has been run, PDFX-Change will save the last used search terms to a file GlobData, so if you want to remove absolutely everything, you'd also delete that file too.
- Mathew.
This is the entire script:
Code: Select all
app.addMenuItem( {
cName: "findReplaceAnnTx",
cUser: "Find/Replace…",
cParent: "Edit",
nPos: 21,
cExec: 'replaceAnnotTx.run(this)'}
);
var replaceAnnotTx = {
SAVE_LENGTH : 10,
dialog: {
data:{},
initialize: function (dialog) {
let def = this.data;
if ( !Object.keys(def).length ) {
def = { "ftxt": "", "rtxt": "", "usRE": false, "casS": false };
} else {
["ftxt","rtxt"].forEach( i => def[i] = this.dd( def[i] ));
}
dialog.load( def );
},
commit:function (dialog) {
this.data = dialog.store();
},
dd:function(arr) {
let ob = { "":1 };
if (! Array.isArray(arr))
arr = [arr];
for (let i in arr) {
ob[arr[i]] = -2-i;
}
return ob;
},
description: {
name: "Find & Replace",
align_children: "align_left",
elements:
[
{
type: "cluster",
name: "Search and Replace expressions",
align_children: "align_left",
elements:
[
{
type: "view",
align_children: "align_row",
elements:
[
{
type: "static_text",
name: "Find:",
alignment: "align_right",
width:50
},
{
item_id: "ftxt",
type: "edit_text",
PopupEdit: true,
alignment: "align_left",
width:300
}
]
},
{
type: "view",
align_children: "align_row",
elements:
[
{
type: "static_text",
name: "Replace:",
alignment: "align_right",
width:50
},
{
item_id: "rtxt",
type: "edit_text",
PopupEdit: true,
alignment: "align_left",
width:300
}
]
},
{
type: "check_box",
name: "Regular Expression",
item_id: "usRE"
},
{
type: "check_box",
name: "Case Sensitive",
item_id: "casS"
},
]
},
{
alignment: "align_right",
type: "ok_cancel",
ok_name: "Ok",
cancel_name: "Cancel"
}
]
}
},
run: function(t) {
let globals = this.global.get();
Object.assign(this.dialog.data, globals);
if ("ok" == app.execDialog(this.dialog)) {
console.println( this.doReplace( t, this.dialog.data ));
this.global.set( this.mkArrays( globals ) );
} else {
return "User Cancelled";
}
},
mkArrays: function ( gData ) {
let setObs = ["ftxt","rtxt"];
let newData = this.dialog.data;
if (gData) {
for (let i of setObs) {
let arr = gData[i];
if (arr) {
if ( !Array.isArray(arr) )
arr = [ arr ];
if ( -1 == arr.indexOf( newData[i] ) ) {
newData[i] = [newData[i]].concat( arr );
} else {
newData[i] = arr;
}
if ( newData[i].length > this.SAVE_LENGTH )
newData[i] = newData[i].slice(0,this.SAVE_LENGTH);
}
}
}
return newData;
},
doReplace: function( t, results ) {
let fSrc = results["ftxt"];
if ( "" == fSrc) return "Nothing to change";
let useRex = results["usRE"];
fSrc = useRex ? fSrc : fSrc.replace(/([\.\(\)\\\|\[\]\{\}\+\-\*\$\^\,\?])/g,"\\$1");
let caseSens = results["casS"] ? "":"i";
let fRE = new RegExp(fSrc,"g" + caseSens );
let reTx = results["rtxt"];
let anns = t.selectedAnnots;
if (0==anns.length)
anns = t.getAnnots();
let replacements = 0;
for (let ann of anns){
let aProps = ann.richContents;
if (aProps.length>0) {
let changed = false;
for (let i=0; i<aProps.length; i++) {
if (aProps[i] && fRE.test(aProps[i].text)) {
aProps[i].text = aProps[i].text.replace(fRE,reTx);
changed = true;
replacements++;
}
}
if (changed) ann.richContents = aProps;
} else {
aProps = ann.contents;
if (aProps && fRE.test(aProps)){
aProps=aProps.replace(fRE,reTx);
ann.contents = aProps;
replacements++;
}
}
}
return "Replaced in "+replacements+" locations.";
}
}
replaceAnnotTx.global = new class {
constructor(name) {
this.get = app.trustedFunction(() => {
app.beginPriv();
try{
if ( global[name] )
return JSON.parse( global[name] );
}catch{
console.println("Error accessing global variable '"+name+"'. Try:\n either uncheck 'Enable global object security policy',\n or (preferably) edit the file 'GlobData': Delete the line that begins with /D after the line \n/"+name+" <<");
}});
this.set = app.trustedFunction( value => {
app.beginPriv();
try{
global[name] = JSON.stringify( value );
global.setPersistent( name, true);
}catch{}});
}
}("FindReplaceGlobalVals")