# Undo/Redo

# 简介

Foxit PDF SDK for Web 提供了一个名为 "undo-redo" 的插件,它可以为 PDF 文档添加撤销和重做功能。用户可以通过 Ctrl+ZCtrl+Y 组合键来撤销和重做以下操作:

  • 添加注释
  • 删除注释
  • 修改注释
  • 等等

此外,该插件还提供了编程接口,允许开发者在自定义应用中实现撤销和重做功能。

# 加载插件

请参考 Addons 简介 章节中的方法。插件加载后, undo-redo 功能便会自动生效。用户可以通过 Ctrl+ZCtrl+Y (Mac 中为 Cmd+ZCmd+Y)来撤销和重做上一步操作。

# 编程接口

除了提供快捷键之外,undo-redo 插件还提供了一系列编程接口帮助开发者实现自定义功能。在调用接口之前,需要先获取 undo-redo 插件的对象实例:

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.");
    }
}

关于 UndoRedoAddon 详细的接口描述,可以参考 API Reference (opens new window)

获取到 UndoRedoAddon 实例后,接下来开始使用它。

# 撤销操作

undoRedoAddon.undo() 接口用于撤销操作,它可以撤销用户的最后一次操作。示例如下:

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

# 重做操作

undoRedoAddon.redo() 接口用于重做操作,它可以重新执行最后一次被撤销的用户操作。示例如下:

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

# 撤销所有操作

undoRedoAddon.undoAll() 接口用于撤销所有操作,它可以撤销用户所有的操作,将文档还原到最初状态。示例如下:

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

虽然所有操作被撤销,但是也依然可以一步一步地重做。

# 记录操作

UndoRedoAddon 还提供了一个 invoke 方法,可以通过该方法传递回调函数。该函数接受一个 PDFDoc (opens new window) 对象,该对象是一个被包装过的对象。相对于未包装过的 PDFDoc ,其不同之处在于可以记录操作,这些被记录的操作可以被撤销和重做。

下面是一个简单的示例,在回调函数中记录了创建注释和修改注释的操作。这些操作被记录后,可以通过 undo/redo 接口来撤销和重做:

function wait() {
    // 这个函数的作用是让下面的每个步骤执行完后停顿一定时间,方便查看效果。
    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, // 初始化外边框颜色为:红色
            });
            await wait();
            // 创建完成后,将外边框颜色设置为紫色
            await square.setBorderColor(0xff00ff);
        });

        await wait();

        // 撤销后,颜色变回红色
        await undoRedoAddon.undo();

        await wait();

        // 重做后,颜色变为紫色
        await undoRedoAddon.redo();

        await wait();

        // 撤销所有,square Annotation 将被删除
        await undoRedoAddon.undoAll();
    } else {
        console.error("UndoRedo Addon instance not found.");
    }
}

# 支持 Undo/Redo 的 API 列表

下面列举了 Foxit PDF SDK for Web 当前支持撤销和重做操作的 API。

# 支持的对象获取接口

这里列举了一系列接口,当在 UIXAddon.invoke 回调函数中被调用时,会返回一个被包装过的对象。开发者可以调用这个被包装过的对象的方法来记录操作:

  1. PDFDoc (opens new window) 接口

    • PDFDoc.getPageByIndex(index): 通过索引获取文档中的页面。
    • PDFDoc.getPageById(id): 通过页面的唯一标识符获取页面。
    • PDFDoc.getAnnots(): 获取文档中的所有注释。
  2. PDFPage (opens new window) 接口

    • PDFPage.getAnnots(): 获取页面上的所有注释。
    • PDFPage.getAnnotsByObjectNumArray(objectNums): 通过对象编号数组获取页面上的注释。
    • PDFPage.getAnnotsByIdArray(annotIds): 通过注释标识符数组获取页面上的注释。
    • PDFPage.getMarkupAnnots(): 获取页面上的标记注释。
    • PDFPage.getAnnotTree(): 获取页面上注释的树状结构。

示例:

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.");
    }
}

# 支持的操作接口

这些接口被调用后,其操作将会被自动记录,记录后的操作可以被撤销和重做。要注意的是,这些接口必须在上一段中列举的 对象获取接口 返回的对象上调用。

  1. PDFDoc (opens new window) 接口
    • PDFDoc.addAnnot
  2. PDFPage (opens new window) 接口
    • PDFPage.addAnnot
    • PDFPage.removeAnnotById
    • PDFPage.removeAnnotByObjectNumber
  3. Annot (opens new window) 接口 (所有注释类的超类):
    • Annot.setContent
    • Annot.setRect
    • Annot.setBorderColor
    • Annot.setBorderInfo
    • Annot.setFlags
  4. Markup (opens new window) 接口 (所有 Markup 注释的超类, 包括: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. 特定的注释类型: