Skip to content

Undo and redo ​

Introduction ​

Foxit PDF SDK for Web provides an undo-redo add-on that adds undo and redo for PDF documents. Users can press Ctrl+Z and Ctrl+Y to undo and redo:

  • Add annotation
  • Delete annotation
  • Modify annotation

The add-on also exposes programming APIs so you can implement undo and redo in custom applications.

Load the add-on ​

See Add-ons overview for loading instructions. After the add-on loads, undo/redo is active automatically. Users can press Ctrl+Z and Ctrl+Y (on Mac: Cmd+Z and Cmd+Y) to undo and redo the last operation.

Programming API ​

In addition to keyboard shortcuts, the undo-redo add-on provides APIs for custom workflows. Obtain the add-on instance before calling its methods:

javascript
async function obtainAddonInstanceExample() {
    const undoRedoAddon = await pdfui.getAddonInstance("UndoRedoAddon");
    if (undoRedoAddon) {
        / Here you can begin to use the methods of undoRedoAddon object.
    } else {
        console.error("UndoRedo Addon instance not found.");
    }
}

For full API details, see UndoRedoAddon in the API Reference.

After you obtain the UndoRedoAddon instance, you can call its methods.

Undo ​

undoRedoAddon.undo() undoes the user's last operation:

javascript
async function undoExample() {
    const undoRedoAddon = await pdfui.getAddonInstance("UndoRedoAddon");
    if (undoRedoAddon) {
        undoRedoAddon.undo();
    } else {
        console.error("UndoRedo Addon instance not found.");
    }
}

Redo ​

undoRedoAddon.redo() re-applies the last undone operation:

javascript
async function redoExample() {
    const undoRedoAddon = await pdfui.getAddonInstance("UndoRedoAddon");
    if (undoRedoAddon) {
        undoRedoAddon.redo();
    } else {
        console.error("UndoRedo Addon instance not found.");
    }
}

Undo all ​

undoRedoAddon.undoAll() undoes every recorded operation and restores the document to its initial state:

javascript
async function undoAllExample() {
    const undoRedoAddon = await pdfui.getAddonInstance("UndoRedoAddon");
    if (undoRedoAddon) {
        undoRedoAddon.undoAll();
    } else {
        console.error("UndoRedo Addon instance not found.");
    }
}

After undoing all operations, you can still redo step by step.

Record operations ​

UndoRedoAddon provides an invoke method that accepts a callback. The callback receives a wrapped PDFDoc object. Unlike the unwrapped PDFDoc, the wrapped instance records operations that can be undone and redone.

The example below records creating and modifying an annotation; those steps can then be undone and redone with undo / redo:

javascript
function wait() {
    // Pause briefly after each step so you can observe the effect.
    return new Promise((resolve) => setTimeout(resolve, 2000));
}

async function invokeExample() {
    const undoRedoAddon = await pdfui.getAddonInstance("UndoRedoAddon");
    if (undoRedoAddon) {
        await undoRedoAddon.invoke(async (pdfDoc) => {
            const pdfPage = await pdfDoc.getPageByIndex(0);
            const [square, popup] = await pdfPage.addAnnot({
                type: "square",
                rect: {
                    left: 0,
                    right: 100,
                    bottom: 500,
                    top: 550,
                },
                color: 0xff0000, / Initial border color: red
            });
            await wait();
            // After creation, set the border color to purple
            await square.setBorderColor(0xff00ff);
        });

        await wait();

        // After undo, the color returns to red
        await undoRedoAddon.undo();

        await wait();

        // After redo, the color becomes purple again
        await undoRedoAddon.redo();

        await wait();

        // Undo all — the square annotation is removed
        await undoRedoAddon.undoAll();
    } else {
        console.error("UndoRedo Addon instance not found.");
    }
}

APIs that support undo/redo ​

The following SDK APIs support undo and redo when used inside UIXAddon.invoke.

Object accessor APIs ​

These methods return wrapped objects when called inside an invoke callback. Methods on those wrapped objects record undoable operations:

  1. PDFDoc

    • PDFDoc.getPageByIndex(index): Get a page by index.
    • PDFDoc.getPageById(id): Get a page by unique ID.
    • PDFDoc.getAnnots(): Get all annotations in the document.
  2. PDFPage

    • PDFPage.getAnnots(): Get all annotations on the page.
    • PDFPage.getAnnotsByObjectNumArray(objectNums): Get annotations by object number array.
    • PDFPage.getAnnotsByIdArray(annotIds): Get annotations by ID array.
    • PDFPage.getMarkupAnnots(): Get markup annotations on the page.
    • PDFPage.getAnnotTree(): Get the annotation tree on the page.

Example:

javascript
async function getAnnotsExample() {
    const undoRedoAddon = await pdfui.getAddonInstance("UndoRedoAddon");
    if (undoRedoAddon) {
        await undoRedoAddon.invoke(async (pdfDoc) => {
            const pdfPage = await pdfDoc.getPageByIndex(0);
            const [square] = await pdfPage.getAnnotsByObjectNumArray([12002]);
            square.setBorderColor(0xFF0000);
        });
        await undoRedoAddon.undo();
    } else {
        console.error("UndoRedo Addon instance not found.");
    }
}

Operation APIs ​

Calls to these methods are recorded automatically and can be undone and redone. They must be invoked on objects returned by the accessor APIs above.

  1. PDFDoc
    • PDFDoc.addAnnot
  2. PDFPage
    • PDFPage.addAnnot
    • PDFPage.removeAnnotById
    • PDFPage.removeAnnotByObjectNumber
  3. Annot (base class for all annotation types):
    • Annot.setContent
    • Annot.setRect
    • Annot.setBorderColor
    • Annot.setBorderInfo
    • Annot.setFlags
  4. Markup (base class for markup annotations, including FreeText (callout, textbox, typewriter), ink, line, note, polygon, polyline, redact, sound, square, stamp, and TextMarkup (highlight, squiggly, strikeout, underline)):
    • Markup.setOpacity
    • Markup.setSubject
    • Markup.setTitle
    • Markup.addReply
    • Markup.addReviewState
    • Markup.addMarkedState
    • Markup.setFillColor
  5. Specific annotation types:
    • Circle
      • Circle.setMeasureRatio
      • Circle.setMeasureUnit
      • Circle.setMeasureConversionFactor
      • Circle.enableCaption
      • Circle.setCaptionColor
    • Line
      • Line.setMeasureRatio
      • Line.setMeasureUnit
      • Line.enableCaption
      • Line.setCaptionColor
      • Line.setEndPoint
      • Line.setStartPoint
      • Line.setEndingStyle
      • Line.setStyleFillColor
      • Line.setLeaderLineExtend
      • Line.setLeaderLineOffset
      • Line.setLeaderLineLength
      • Line.setCaptionOffset
    • Polygon
      • Polygon.enableCaption
      • Polygon.setCaptionColor
      • Polygon.updateVertexes
      • Polygon.setVertexes
    • Polyline
      • Polyline.setMeasureRatio
      • Polyline.enableCaption
      • Polyline.setCaptionColor
      • Polyline.setEndingStyle
      • Polyline.setStyleFillColor
      • Polyline.updateVertexes
      • Polyline.setVertexes
    • Square
      • Square.setMeasureRatio
      • Square.setMeasureUnit
      • Square.setMeasureConversionFactor
    • FreeText (typewriter, textbox, callout)
      • FreeText.setAlignment
      • FreeText.setInnerRect
      • FreeText.setCalloutLinePoints
      • FreeText.setCalloutLineEndingStyle
      • FreeText.setDefaultAppearance
      • FreeText.setRotation
    • Screen
      • Screen.setRotation
    • Stamp
      • Stamp.setRotation
    • Redact
      • Redact.setDefaultAppearance
      • Redact.setOverlayText
      • Redact.removeOvelayText
      • Redact.setOverlayTextAlignment
      • Redact.setRepeat
      • Redact.setAutoFontSize
      • Redact.setRedactApplyFillColor
    • Ink
      • Ink.setInkList
    • Link
      • Link.setHighlightingMode
      • Link.setAction
    • FileAttachment
      • FileAttachment.setIconName
    • Note
      • Note.setIconName