Forum for the PDF-XChange Editor - Free and Licensed Versions
Moderators:PDF-XChange Support, Daniel - PDF-XChange, Chris - PDF-XChange, Sean - PDF-XChange, Paul - PDF-XChange, Vasyl - PDF-XChange, Ivan - Tracker Software, Stefan - PDF-XChange
When adding bookmarks though javascript, the only way I can see to make the bookmark do something is to add a javaScript to it with .createChild( cName, cScript, nIndex) or .setAction( cScript )
This works fine until a page is moved, inserted, or added - the bookmark then points to the wrong page. Is there a way to add a goto page action that PDF XChange will recognize and update as it does when you add a bookmark through the bookmarks pane?
Digging a bit deeper, when I export bookmarks to a text file (Bookmarks > Export Bookmarks to Text file...) the resulting text file shows nothing for the javascript action. What would be really fantastic would be a goto method on bookmarks that could get/set the goto parameters that show up when bookmarks are exported to text:
I have passed this along to the Dev team and am just awaiting a reply on how doable this is. Hopefully we can get a positive response and I can go make a ticket, I will keep you posted when they reply.
Kind regards,
Dan McIntyre - Support Technician
PDF-XChange Co. LTD
+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
Support@pdf-xchange.com
In the PDF Reference v1.7 it lists two options for bookmarks and links. Only A (action) is currently accessible by javascript. Actions are very hard (maybe impossible) to parse and update automatically.
This request is that Dest (destination) also be accessible by javascript (read and write).
image.png
Destination object/array should follow the PDF Reference:
image(1).png
image(2).png
This would open up the possibility of scripts that could add links or bookmarks within documents based on the contents of the document. These links/destinations wouldn't be fragile and break any time a page is added or removed because PDFXChange already updates destinations.
You do not have the required permissions to view the files attached to this post.
The specific use case I'm looking at right now is this (in the Architecture/Engineering field):
Permitting authorities in many jurisdictions in the USA are starting to require that pdf drawing sets submitted to them have both bookmarks for all the sheets, with the name and number of the drawing, and links from individual references within the drawings to the referenced sheet.
This is tedious to do by hand, but an automated tool can do it relatively easily. The problem is that if done in javascript that tool would have to add actions to the bookmarks and links. But when drawings from all sub-consultants are combined in a set, all those actions would break (they'd point to the wrong page). For a javascript tool to be able to do it, it would need to set the Dest property.
Unfortunately the JS Bookmark methods are quite limited:
image.png
You can not really access or modify the existing actions. You can overwrite them by setting new Action for a bookmark, however you can not read them first so that you can e.g. modify them before overwriting.
However - have you tried setting a "gotoNamedDest" as the action for your bookmarks? You will probably still need to create the named destinations manually, but then once a bookmark is set to point to a Named Destination - that destination moves with the page - so even if the order of pages changes - your bookmark link will still work?
Kind regards,
Stefan
You do not have the required permissions to view the files attached to this post.
Yes: I guess I should have titled it "javascript Feature Request": Add methods .getDestination() and .setDestination() to bookmark methods.
There have been a few other posts asking for similar functionality (find the destination of bookmarks in javascript - currently there's only a hack workaround that has a number of problems).
Thanks for clarifying, I spoke with the team and this one is a low priority request, so no timeline other than "unlikely to be soon": RT#6841: FR: add .getDestination() and .setDestination() JS methods for bookmarks
Kind regards,
Dan McIntyre - Support Technician
PDF-XChange Co. LTD
+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
Support@pdf-xchange.com
It's a similar situation for Links - but there's no workaround I know to even find their destination:
image.png
Bookmarks and Links are very similar, and would be ideal items for scripting because there are often so many of them and making changes is such a huge tedious task. Yet without this functionality, javascript is almost useless on them.
You do not have the required permissions to view the files attached to this post.
I've just updated the ticket to make the request to also work for Links - I can't tell you yet whether that is possible and whether it can be in the same ticket - but if it needs a separate one - I will create it. For now the ticket is: #6841: FR: add .getDestination() and .setDestination() JS methods for bookmarks and links
Matthew, I found your post trying to do a similar thing. To compile PDF with a bookmark for each file my workaround was:
1. Save every pdf file with the bookmark name as the file name
2. create a "first_page" bookmark in PDF-Exchange Editor
3. export the bookmark as *.xcbkm file
4. batch apply the bookmark file using PDF-Tools "Import Bookmarks" tool to every PDF
5. batch run javascript using PDF-Tools to rename the "first_page" bookmark to the file name
6. use PDF-Exchange file explorer context menu to compile all the PDFs together
// STEP 1: Import a first page bookmark using batch process and save with the inspection number in the file name
// STEP 2: Batch run this JavaScript to rename the bookmark
// SETP 3: Collate all PDFs into a single PDF file which now has a bookmark for each inspection.
function Tools_DoWork()
{
let str = this.documentFileName;
let numbers = str.match(/\d+/g);
let bookmark_title = "Inspection-" + numbers[0]
this.bookmarkRoot.children[0].name = bookmark_title;
return bookmark_title;
}
Dan McIntyre - Support Technician
PDF-XChange Co. LTD
+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
Support@pdf-xchange.com
JohnWMitchell wrote: ↑Tue Mar 04, 2025 8:59 pm
Matthew, I found your post trying to do a similar thing. To compile PDF with a bookmark for each file my workaround was:
1. Save every pdf file with the bookmark name as the file name
...
Sorry, I'm probably not understanding: I think you can do the above without javascript. After step 1, use "Combine Files into a Single PDF"
image.png
and set the option to add a root bookmark based on filename:
image(1).png
What I'm looking for in this feature request is the ability for javascript to create a new bookmark, and that bookmark can have the same properties as a bookmark created through the UI.
I have created a workaround. It's painful but works by using app.execMenuItem to run the built-in add bookmark, then it tries to find it and renames it. It's easily broken because different languages get different default bookmark names.
/** add a bookmark that uses built-in bookmark properties at current page/zoom/position (ie not bookmark.setAction())
* @returns the added bookmark or null
*
* @param {string} bkmName - name for the new bookmark
* @param {object Doc} doc - the document to add the bookmark
* @param {boolean} [reTry] - number of times to try to find the added bookmark (because app.execMenuItem happens asynchronously, the bookmark may not be added immediately)
*
* @todo: convert to async function
**/
function addBookmark( bkmName, doc, reTry=2 ) {
const realName = (bk) => 'Root' === bk.name ? '' : bk.name;
const untitledBkList = [];
const bkCrawl = (bks) => {
const bkN = [];
for (let b of bks) {
const name = realName(b);
// if a previous bookmark is named 'Untitled', then it will get mistakenly equated to a new bookmark.
if ('Untitled' === name) {
untitledBkList.push(b);
}
bkN.push( b.children?.length ? {name, children: bkCrawl(b.children)} : {name});
}
return bkN;
};
// go through current bookmarks and look for one that was added (start at the end)
function bkRename( bkmName, oldBks, bks) {
// if bookmark is added to this tree, will be 1
const offset = bks.length - oldBks.length;
for (let i = bks.length; i--; ) {
if (offset) {
if (oldBks[i - offset].name !== realName( bks[i]) || ('Untitled' === bks[i].name && !untitledBkList.includes( bks[i] ))) {
// found it, rename
bks[i].name = bkmName;
return bks[i];
}
} else if (bks[i].children?.length) {
// !offset: there isn't an added bookmark in this tree, but maybe in the children
const renamed = bkRename( bkmName, oldBks[i].children, bks[i].children);
if (renamed) return renamed; // jshint ignore: line
}
}
return;
}
// need to get list of current bookmarks
const bkList = bkCrawl( doc.bookmarkRoot.children);
app.execMenuItem('cmd.addBookmark', doc);
// the above happens asynchronously, so may need to wait to rename new bookmark?
// this won't return the bookmark though - need async
//xutil.setTimeout( bkRename, 100, bkmName, bkList);
let addedBk;
while (reTry-- && !addedBk) {
addedBk = bkRename( bkmName, bkList, doc.bookmarkRoot.children);
}
return addedBk;
}
// test
addBookmark( 'testName', this);
You do not have the required permissions to view the files attached to this post.