Skip to content

Editor embedding

Events

The seven O3O.Editor events: onReady, onDocumentLoaded, onModified, onSaved, onError, onClose, onLimitReached, each with fields and an example.

On this page

Declared in config.events. Each function receives ONE argument, the event object; missing functions are skipped. Exceptions thrown by your functions are caught and printed to the console; they never break the editor.

EventWhenObject
onReadySession created, iframe attached, editor frame ready.{sessionId, mode}
onDocumentLoadedThe document is visible.{sessionId, mode, loadTimeMs}
onModifiedThe “unsaved changes” state flips.{modified}
onSavedThe gate received a new version; exactly once per version number.{key, version, url, size, sha256, savedAt}
onErrorAny error.{code, message, detail}
onCloseThe user clicks close, or the page calls close().{sessionId, modified}
onLimitReachededit requested but the cap is reached; the editor still opens read-only.{limit, current, edition, message, mode}

Usual order: onReadyonDocumentLoaded → (onModified, onSaved)* → onClose.

onReady#

onReady

  • sessionIdstringrequired
    Session id, ses_ + 24 hex.
  • mode"edit" | "view"required
    Actual session mode (may be view if the cap was reached).
JavaScriptonReady
const events = {
  onReady(e) {
    // The editor frame is ready; the document is still loading
    document.getElementById("status").textContent = "Opening document…";
    console.log(e.sessionId, e.mode);   // "ses_…", "edit" | "view"
  }
};

onDocumentLoaded#

onDocumentLoaded

  • sessionIdstringrequired
    Session id.
  • mode"edit" | "view"required
    Session mode.
  • loadTimeMsnumberrequired
    Milliseconds from creating the editor to the document showing, measured on the user's machine.

Right after this event, api.js applies the message-based ui options (status bar, menu bar).

JavaScriptonDocumentLoaded
const events = {
  onDocumentLoaded(e) {
    document.getElementById("status").textContent = "";
    console.log("opened in", e.loadTimeMs, "ms, mode =", e.mode);
  }
};

onModified#

onModified

  • modifiedbooleanrequired
    true when there are unsaved changes.
JavaScriptonModified
let dirty = false;
const events = {
  onModified(e) {
    dirty = e.modified;
    document.title = (dirty ? "● " : "") + "Contract";
  }
};
// Warn users who leave while changes are unsaved
window.addEventListener("beforeunload", (ev) => { if (dirty) ev.preventDefault(); });

onSaved#

onSaved

  • keystringrequired
    The document's document.key.
  • versionintegerrequired
    New version number, increasing from 1.
  • urlstringrequired
    Signed download URL for this version, valid for the retention time (O3O_EMBED_RETAIN_HOURS, 24 hours by default).
  • sizeintegerrequired
    Size in bytes.
  • sha256stringrequired
    Hex SHA-256 of the file.
  • savedAtstringrequired
    Save time, ISO 8601 UTC.
JSONExample onSaved object
{
  "key": "contract-42-v7",
  "version": 3,
  "url": "http://localhost:8080/o3o/embed/files/doc_9835f61009fc659dfedab8696f2d2665?v=3&exp=1790086400&sig=5f1c…",
  "size": 48890,
  "sha256": "b1946ac92492d2347c6235b4d2611184…",
  "savedAt": "2026-09-21T10:05:00Z"
}
JavaScriptonSaved
const events = {
  onSaved(e) {
    // e.url is a signed download URL, valid for the server retention time (24 hours by default)
    console.log(e.key, "v" + e.version, e.size, "bytes", e.sha256, e.savedAt);
    document.getElementById("download").href = e.url;
  }
};

How api.js detects a save: when the editor frame reports a successful save, or when the “modified” state goes from true to false, it polls GET /o3o/embed/session/{id} once a second, up to 10 times, until version exceeds the last known one, and only then fires onSaved.

onError#

onError

  • codestringrequired
    Stable error code; see the code table.
  • messagestringrequired
    A Vietnamese sentence you can show to users.
  • detailobjectoptionalDefault: {}
    Extra details, e.g. errors for invalid_config.
JSONExample onError object
{
  "code": "download_failed",
  "message": "Không tải được tài liệu từ địa chỉ đã cho.",
  "detail": {}
}
JavaScriptonError
const events = {
  onError(e) {
    // e.message is a Vietnamese sentence you can show; branch on e.code
    console.error(e.code, e.message, e.detail);
    if (e.code === "network_error") setTimeout(() => location.reload(), 5000);
  }
};

onClose#

onClose

  • sessionIdstringrequired
    Session id.
  • modifiedbooleanrequired
    Unsaved changes remained when closing.
JavaScriptonClose
const events = {
  onClose(e) {
    // the iframe has already been removed when this fires
    if (e.modified) console.warn("closed with unsaved changes");
    location.href = "/documents";
  }
};

onLimitReached#

onLimitReached

  • limitintegerrequired
    Effective connection cap.
  • currentintegerrequired
    Editing sessions currently counted.
  • edition"community" | "enterprise"required
    Running edition.
  • messagestringrequired
    The server's Vietnamese sentence; api.js shows it verbatim in the banner.
  • mode"view"required
    Always view.
JSONExample onLimitReached object
{
  "limit": 50,
  "current": 50,
  "edition": "community",
  "message": "Hệ thống đã đạt giới hạn 50 phiên soạn thảo đồng thời của bản cộng đồng. Tài liệu của bạn vẫn an toàn. Bạn có thể mở ở chế độ chỉ đọc hoặc thử lại sau ít phút.",
  "mode": "view"
}
JavaScriptonLimitReached
const events = {
  onLimitReached(e) {
    // The editor IS still open, read-only (e.mode === "view")
    console.warn(e.limit, e.current, e.edition, e.message);
  }
};

Full example: log every event#

HTMLevents.html
<!doctype html>
<meta charset="utf-8">
<div id="o3o-editor" style="height: 70vh"></div>
<pre id="log" style="height: 25vh; overflow: auto; background: #f4f4f4"></pre>
<script src="http://localhost:8080/o3o/api.js"></script>
<script>
  const log = (name) => (e) => {
    document.getElementById("log").textContent += new Date().toISOString() + " " + name + " " + JSON.stringify(e) + "\n";
  };
  new O3O.Editor("o3o-editor", {
    document: { url: "http://localhost:8080/o3o/demo/sample.docx", title: "sample.docx", fileType: "docx", key: "events-demo-1" },
    editor: { mode: "edit", lang: "en-US", user: { id: "dev-1", name: "Dev" } },
    ui: { closeButton: true },
    events: {
      onReady: log("onReady"),
      onDocumentLoaded: log("onDocumentLoaded"),
      onModified: log("onModified"),
      onSaved: log("onSaved"),
      onError: log("onError"),
      onClose: log("onClose"),
      onLimitReached: log("onLimitReached")
    }
  });
</script>
Coming soon

Events for save-as and for version history.