# # Bookmark API Migration Guide

This guide is intended to help developers upgrade from an older version of the Bookmark APIs to the newest version. Starting from version 10.0.0, we have refactored the Bookmark APIs, which provides more powerful features and performance improvements. Next, we will further discuss which old Bookmark APIs are being deprecated and how to migrate to the new APIs.

## # Confirm the current version of the API in use

If your application was developed based on versions prior to 10.0.0, when upgrading to versions after 10.0.0, please note that you will need to search for relevant API calls in your code, or check if the old bookmark component has been used in your component templates. The names of the old APIs and components will be listed subsequently.

## # Deprecated APIs

The table below lists the deprecated bookmark APIs and alternative solutions.

Old API | Description | Alternative API
--- | --- | ---
PDFDoc.getRootBookmark | Get the root bookmark of the document, this method will load all bookmarks in the document at once | BookmarkDataService.getFirstLevelBookmarks (opens new window)
PDFDoc.createRootBookmark | Create the root bookmark of the document. The new version will automatically create the root bookmark, making it unnecessary to create via an interface | none
PDFBookmark.insertBookmark | Insert a new bookmark at the specified location | BookmarkDataService.addBookmark (opens new window), BookmarkUIService.addBookmark (opens new window)
PDFBookmark.setProperty | Set the properties of the bookmark | BookmarkDataService.renameBookmark (opens new window), BookmarkDataService.setColor (opens new window), BookmarkDataService.setFontStyle (opens new window), BookmarkDataService.setDestination (opens new window), BookmarkUIService.renameBookmark (opens new window), BookmarkUIService.setColor (opens new window), BookmarkUIService.setFontStyle (opens new window), BookmarkUIService.setDestination (opens new window)
PDFBookmark.remove | Remove a specified bookmark | BookmarkDataService.deleteBookmark (opens new window), BookmarkUIService.deleteBookmark (opens new window)
PDF.constant.DataEvents.bookmarkAdded | Triggered when bookmark has been added | BookmarkDataService.onBookmarkAdded (opens new window)
PDF.constant.DataEvents.bookmarkUpdated | Triggered when bookmark has been updated | BookmarkDataService.onBookmarkPropertiesUpdated (opens new window)
PDF.constant.DataEvents.bookmarkRemoved | Triggered when bookmark has been removed | BookmarkDataService.onBookmarkDeleted (opens new window)

Below are the deprecated bookmark UIExtension components and their alternatives:

Old Component | Description | Alternative Component
--- | --- | ---
`<bookmark-sidebar-panel>` | Sidebar bookmark panel component | `<bookmark-v2:sidebar-panel>`
`<bookmark-contextmenu>` | Bookmark contextmenu component | `<bookmark-v2:bookmark-contextmenu>`

When these old components are replaced with new ones, the previously registered bookmark events will not be triggered. At this time, it is necessary to replace the registration method of these events. Examples will be provided later to illustrate.

If your application requires a custom bookmark UI, please refer to Customize bookmark.

## # Example

The following will provide examples to demonstrate how to use the new bookmark APIs to replace the old ones, as well as compare the differences between the two versions.

### # Example 1 - Listen to the event of adding a bookmark

This example demonstrates how to listen to the event of adding a bookmark, and modify the properties of the bookmark through the instance of BookmarkDataService
(opens new window).

    <html>
        <div id="pdf-ui"></div>
    </html>
    <style>
    html{
            overflow:hidden;
        }
        body {
            height: 100vh;
        }
        #pdf-ui {
            position: relative;
            top: 50px;
        }
    </style>

    <script>
    const libPath = window.top.location.origin + '/lib';
    const pdfui = new UIExtension.PDFUI({
        viewerOptions: {
            libPath: libPath,
            jr: {
                licenseSN: licenseSN,
                licenseKey: licenseKey
            }
        },
        renderTo: '#pdf-ui',
        appearance: UIExtension.appearances.adaptive,
        addons: []
    });

    pdfui.getBookmarkDataService().then(bookmarkDataService => {
        bookmarkDataService.onBookmarkAdded((event) => {
            bookmarkDataService.setColor(event.bookmarkId, '#FF0000');
            bookmarkDataService.setFontStyle(event.bookmarkId, {
                bold: true,
                italic: true
            });
        })
    })
    </script>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

After running the above example and opening a document, then adding a new bookmark through the bookmark panel, you will find that the font color of the new bookmark is set to red, and the font style is set to bold and italic.

For versions `9.*` and earlier, bookmark events are registered in the following way:

    pdfui.addViewerEventListener(PDFViewCtrl.ViewerEvents.bookmarkAdded, bookmark => {
        // Here operates the bookmark object
    })

### # Example 2 - Get the nodes of bookmark tree

In versions `9.*` and earlier, bookmarks were loaded into memory all at once and inserted into the DOM tree, loading speed could be slow, even to the point of lag, when there were many bookmarks. After refactoring, bookmarks are loaded and rendered based on the number of bookmarks visible to the user, which speeds up the loading process. Furthermore, bookmarks are rendered through the TreeComponent
(opens new window) component, reserving some space for user customization. The following example shows how to get the nodes of the bookmark tree and modify the node styles:

    <html>
        <div id="pdf-ui"></div>
    </html>
    <style>
    html{
            overflow:hidden;
        }
        body {
            height: 100vh;
        }
        #pdf-ui {
            position: relative;
            top: 50px;
        }
    </style>

    <script>
    const libPath = window.top.location.origin + '/lib';
    const pdfui = new UIExtension.PDFUI({
        viewerOptions: {
            libPath: libPath,
            jr: {
                licenseSN: licenseSN,
                licenseKey: licenseKey
            }
        },
        renderTo: '#pdf-ui',
        appearance: UIExtension.appearances.adaptive,
        addons: []
    });

    (async () => {
        const rootComponent = await pdfui.getRootComponent();
        const bookmarkTreeComponent = rootComponent.querySelector('@bookmark-v2:bookmark-tree');
        const treeComponent = bookmarkTreeComponent.getTree()
        treeComponent.on('create-tree-node', treeNode => {
            const titleElement = treeNode.element.querySelector('.fv__ui-tree-node-title');
            titleElement.style.cssText += 'font-family: system-ui, --apple-system, BlinkMacSystemFont;';
        })
    })()

    </script>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

Unlike the old version, all DOM nodes of the old bookmarks can be obtained through `querySelector` once the bookmarks were loaded. However, the new version requires listening to the `create-tree-node` event to get these nodes.

### # Example 3 - Support for undo/redo

In version 10.0.0, a BookmarkUIService
(opens new window) instance is provided, which is available only when the application layer is based on the implementation of UIExtension. It offers the same API as BookmarkDataService
(opens new window), but supports undo/redo operations.

    <html>
        <div id="pdf-ui"></div>
    </html>
    <style>
    html{
            overflow:hidden;
        }
        body {
            height: 100vh;
        }
        #pdf-ui {
            position: relative;
            top: 50px;
        }
    </style>

    <script>
    const libPath = window.top.location.origin + '/lib';
    const pdfui = new UIExtension.PDFUI({
        viewerOptions: {
            libPath: libPath,
            jr: {
                licenseSN: licenseSN,
                licenseKey: licenseKey
            }
        },
        renderTo: '#pdf-ui',
        appearance: UIExtension.appearances.adaptive,
        addons: [
            libPath + '/uix-addons/undo-redo'
        ]
    });

    (async () => {
        // Create a custom menu item component.
        class HighlightBookmarkContextMenuItem extends UIExtension.SeniorComponentFactory.createSuperClass({
            // Listen to the click event through the @on.click directive.
            template: `<contextmenu-item @on.click="$component.onClick()">Highlight it</contextmenu-item>`
        }) {
            static getName() {
                return 'highlight-bookmark-contextmenu-item';
            }
            async onClick() {
                const treeNode = this.parent.getCurrentTarget();
                const nodeData = treeNode.getData();
                const bookmarkData = nodeData.data;
                const bookmarkId = bookmarkData.id;
                const bookmarkUIService = pdfui.getBookmarkUIService();
                await bookmarkUIService.setColor(bookmarkId, '#FF0000', bookmarkData.color);
            }
        }
        const module = UIExtension.modular.module('custom', []);
        module.registerComponent(HighlightBookmarkContextMenuItem);
        const rootComponent = await pdfui.getRootComponent();
        // Get the bookmark contextmenu instance.
        const bookmarkContextMenu = rootComponent.querySelector('@bookmark-v2:bookmark-contextmenu');
        // Insert a custom menu item at the end of the bookmark contextmenu.
        bookmarkContextMenu.append('<custom:highlight-bookmark-contextmenu-item>');
    })()

    </script>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

This example inserts a custom menu item at the end of the bookmark contextmenu. Clicking this item allows you to set the currently selected bookmark to red. Moreover, this action can be undone or redone using `Ctrl+Z`/`Ctrl+Y`. Please note, to enable the undo/redo feature, you need to include `libPath + '/uix-addons/undo-redo'` in the `addons` configuration when initializing PDFUI, or you can simply configure `addons: libPath + '/uix-addons/allInOne.js'` to load all addons.