[javascript FR] Add a bookmark/link through javascript that updates with inserted pages

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

Mathew
User
Posts: 606
Joined: Thu Jun 19, 2014 7:30 pm

[javascript FR] Add a bookmark/link through javascript that updates with inserted pages

Post by Mathew »

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:

Code: Select all

To pg 5; goto:{4; Fit; 15}
SSK-03; goto:{2; XYZ; 12; 792.000; 612.000}
Added by javaScript
Last edited by Mathew on Fri Mar 22, 2024 8:28 pm, edited 1 time in total.
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 11345
Joined: Wed Jan 03, 2018 6:52 pm

Re: [javascript] Add a bookmark through javascript that updates with inserted pages

Post by Daniel - PDF-XChange »

Hello, Mathew

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
Mathew
User
Posts: 606
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Add a bookmark through javascript that updates with inserted pages

Post by Mathew »

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.
Mathew
User
Posts: 606
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Add a bookmark through javascript that updates with inserted pages

Post by Mathew »

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.
User avatar
Stefan - PDF-XChange
Site Admin
Posts: 19913
Joined: Mon Jan 12, 2009 8:07 am

Re: [javascript] Add a bookmark through javascript that updates with inserted pages

Post by Stefan - PDF-XChange »

Hello Mathew,

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.
Mathew
User
Posts: 606
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Add a bookmark through javascript that updates with inserted pages

Post by Mathew »

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).
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 11345
Joined: Wed Jan 03, 2018 6:52 pm

Re: [javascript] Add a bookmark through javascript that updates with inserted pages

Post by Daniel - PDF-XChange »

Hello, Mathew

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
Mathew
User
Posts: 606
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Add a bookmark through javascript that updates with inserted pages

Post by Mathew »

Thank you!

It's a similar situation for Links - but there's no workaround I know to even find their destination:
image.png
:D

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.
User avatar
Stefan - PDF-XChange
Site Admin
Posts: 19913
Joined: Mon Jan 12, 2009 8:07 am

Re: [javascript FR] Add a bookmark/link through javascript that updates with inserted pages

Post by Stefan - PDF-XChange »

Hello Mathew,

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

Kind regards,
Stefan
Mathew
User
Posts: 606
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript FR] Add a bookmark/link through javascript that updates with inserted pages

Post by Mathew »

:wink: thank you.
User avatar
Stefan - PDF-XChange
Site Admin
Posts: 19913
Joined: Mon Jan 12, 2009 8:07 am

[javascript FR] Add a bookmark/link through javascript that updates with inserted pages

Post by Stefan - PDF-XChange »

:)
JohnWMitchell
User
Posts: 1
Joined: Tue Mar 04, 2025 8:43 pm

Re: [javascript FR] Add a bookmark/link through javascript that updates with inserted pages

Post by JohnWMitchell »

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

here is my javascript:

Code: Select all

// 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;
}
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 11345
Joined: Wed Jan 03, 2018 6:52 pm

[javascript FR] Add a bookmark/link through javascript that updates with inserted pages

Post by Daniel - PDF-XChange »

:)
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
Mathew
User
Posts: 606
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript FR] Add a bookmark/link through javascript that updates with inserted pages

Post by Mathew »

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.

Code: Select all

/** 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.