Перейти к содержимому
FastOffice

Embedding API: структура, события, меню

Модель доступа без DOM, структурные проекции книги, события клика и выбора, вклад в контекстное меню и команды вместо прямой записи.

Внутри F1 уже есть структурные проекции книги и обработка кликов, двойных кликов, выбора объектов и контекстных меню. Сегодня это внутренние интерфейсы продукта — для внешнего приложения они оформляются как отдельный стабильный Embedding API.

Руководство для команды, встраивающей редактор в документарную систему

Прямой ответ Внутри F1 уже есть структурные проекции книги и событийная обработка кликов, двойных кликов, выбора объектов и контекстных меню. Но сегодня это внутренние интерфейсы продукта. Для внешнего приложения необходимо оформить отдельный стабильный Embedding API; использовать DOM-селекторы, внутренние CustomEvent и глобальные __f1… hooks напрямую нельзя.
Статус Объект Что это означает
Существует Rust compute contract Чтение структуры, ячеек, объектов и типизированные операции изменения.
Существует Web interaction runtime Hit testing, click/double-click/contextmenu, selection и внутренние semantic events.
Требует упаковки Public Embedding SDK Стабильные методы, события, menu contributions, permissions и versioning.
Read API узнать книгу, выбор, ячейку, объект Event API реагировать на действия пользователя Command API безопасно изменять документ UI Extension API добавлять команды и меню

1 · МОДЕЛЬ ДОСТУПА

Не DOM документа, а структурные проекции и команды

Заголовок раздела «Не DOM документа, а структурные проекции и команды»

Электронная таблица в F1 не представлена публичным деревом HTML-элементов. Canvas, виртуализация и sparse viewport означают, что нужной ячейки или объекта может вообще не быть в DOM. Поэтому интеграция должна обращаться к логической структуре через SDK.

Объект SDK Что предоставляет Источник истины
WorkbookSession documentId, subsetId, revision, dirty, active sheet, format capabilities. Rust session.
WorkbookInfo Листы, стабильные identity, имена, видимость и активный лист. Rust projection.
Selection Sheet, range/address, active cell, selected object IDs. Web hit test + Rust identity.
CellDetails Raw value, display value, formula, type, format, validation, comment/hyperlink. read_cell_details.
RangeSnapshot Ограниченная матрица значений/formulas/styles и metadata. Bounded compute request.
ObjectInventory Shapes, charts, images, controls, anchors, z-order, capabilities. Rust/OOXML inventory.
ContextTarget Что находится под указателем: cell, table, chart, shape, header и т. д. Semantic hit testing.
Не хранить живые ссылки внешнее приложение получает snapshot с stableId и revision. Нельзя хранить DOM node или изменяемый JS-объект книги и затем писать в него напрямую. Перед действием SDK заново проверяет identity, revision, права и capability.

Предлагаемый публичный API (не внутреннее имя текущего контракта)

const session = await F1.open({
mount, documentId, bytes, mode: "edit"
});
const workbook = await session.getWorkbookInfo();
const selection = await session.getSelection();
const cell = await session.getCellDetails(selection.activeCell);

2 · ЧТЕНИЕ СТРУКТУРЫ

Как получить листы, диапазон, таблицу и графический объект

Заголовок раздела «Как получить листы, диапазон, таблицу и графический объект»
Задача Метод публичного SDK Что возвращается
Получить листы session.getWorkbookInfo() SheetInfo[] со stableId, name, visibility, order.
Прочитать ячейку session.getCellDetails(ref) CellDetails: raw/display/formula/type/style/metadata.
Прочитать диапазон session.getRangeSnapshot(range, options) Bounded values/formulas/styles; без всей книги.
Узнать таблицу session.getTableAt(ref) Table identity, range, columns, filters, totals, capabilities.
Получить объекты session.getObjects({sheetId}) Inventory с stableId, type, anchor, zOrder, editable.
Узнать объект под точкой session.hitTest({x,y}) ContextTarget с semantic kind и stable identity.

Пример: найти диаграмму и переименовать через команду

const objects = await session.getObjects({ sheetId });
const chart = objects.find(x => x.type === "chart");
if (chart?.capabilities.rename) {
await session.execute({
operation: "renameObject",
objectId: chart.stableId,
name: "План перевозок",
expectedRevision: session.revision
});
}

Открытие книги возвращает activeSheet, workbookSheets, viewport, previewCells, table metadata, surfaceObjects и objectInventory. Для объектов доступны stableId, sheet, type, name, anchor, relationships, z-order, visibility, lock state и mutationCapabilities. Для конкретной ячейки существует операция read_cell_details.

Ограничение Генерального запроса «вернуть всё дерево документа» быть не должно: он разрушит sparse-модель и создаст риск утечки больших или закрытых частей книги. Чтение должно быть адресным и ограниченным.

3 · СОБЫТИЯ

Событие SDK Когда возникает Основные поля
selectionChanged После подтверждённого изменения выбора. selection, previousSelection, source, revision.
cellActivated Одиночный click/tap активировал ячейку. cellRef, range, modifiers, source.
cellDoubleClicked Double-click по ячейке после semantic hit test. cellRef, editIntent, modifiers.
objectSelected Выбрана shape/chart/image/control. stableId, objectType, anchor, capabilities.
objectDoubleClicked Double-click по графическому объекту. target, defaultAction, modifiers.
contextMenuOpening Right-click или mobile long-press. target, selection, builtInItems, capabilities.
workbookChanged Rust успешно применил mutation. revision, operation, changedKeys, dirty.
operationRefused Rust отказал до изменения. code, message, target, currentRevision.

Подписка на семантические события

const unsubscribe = session.on("cellDoubleClicked", async event => {
const details = await session.getCellDetails(event.cellRef);
hostPanel.open({ documentId, cell: details });
});
session.on("objectSelected", event => {
propertiesPanel.show(event.target);
});
// При закрытии интеграции:
unsubscribe();

pointer/touch → hit test → selection commit → semantic event → default action

Почему не raw DOM event Canvas node может быть пересоздан, а два клика могут попасть в разные DOM-узлы. SDK должен гарантировать semantic double-click по одному stable target, а не заставлять внешнее приложение самостоятельно угадывать это по браузерным событиям.

4 · КОНТЕКСТНОЕ МЕНЮ

Как менять меню в зависимости от выбранного элемента

Заголовок раздела «Как менять меню в зависимости от выбранного элемента»

внешнее приложение не должен искать внутренний HTML-элемент меню и вставлять туда кнопку. Вместо этого он регистрирует menu provider. Перед показом F1 формирует ContextTarget и запрашивает у provider дополнительные пункты.

ContextTarget.kind Примеры данных контекста
cell / range sheetId, address, valueType, formula, validation, comment, hyperlink, protected.
table tableId, name, range, columnId, totals/filter state, mutation capabilities.
chart objectId, chartType, source range, anchor, editable capabilities.
shape / image objectId, anchor, zOrder, groupId, metadata, supported mutations.
rowHeader / columnHeader track index, hidden state, size, protection.
sheetTab sheetId, name, visibility, active/grouped state.
canvas sheetId, pointer coordinates, no semantic object.

Пример menu contribution для строки таблицы

session.contextMenu.registerProvider(async context => {
if (context.target.kind !== "table") return [];
return [{
id: "partner.open-shipment-card",
label: "Открыть карточку перевозки",
icon: "external-link",
enabled: Boolean(context.target.rowKey),
group: "partner",
order: 20,
run: () => host.openCard(context.target.rowKey)
}];
});
  • Пункт имеет уникальный namespace ID, локализуемый label, optional icon, group, order и enabled/visible predicate.

  • Provider получает безопасный snapshot контекста, а не внутренний DOM и не весь workbook.

  • Built-in команды остаются под контролем F1; внешнее приложение добавляет или ограниченно заменяет разрешённые slots.

  • Долгий provider имеет timeout; меню не должно зависнуть из-за backend внешнее приложение.

5 · ИЗМЕНЕНИЕ ДОКУМЕНТА

Любая операция, меняющая документ, должна пройти через Rust compute contract. Это сохраняет одинаковое поведение в браузере, desktop и server и обеспечивает atomic history.

Шаг Что делает SDK
1. Сформировать intent Operation name, target stableId/range, параметры и expectedRevision.
2. Проверить доступ Read-only, protection, capability, source format и session policy.
3. Передать Rust Тот же contract через WASM/native/service adapter.
4. Применить атомарно Успех меняет revision/history; refusal оставляет документ без partial delta.
5. Опубликовать результат Новая projection, workbookChanged либо operationRefused.

Пример изменения с optimistic concurrency

const result = await session.execute({
operation: "setCellValue",
target: { sheetId, row: 12, col: 4 },
value: { kind: "string", value: "Доставлено" },
expectedRevision: session.revision
});
if (!result.ok && result.code === "stale-revision") {
await session.refreshProjection();
}
// НЕЛЬЗЯ: это обходит Rust, историю и сохранение.
document.querySelector("[data-cell='E13']").textContent = "Доставлено";
session.workbook.sheets[0].cells[12][4].value = "Доставлено";
Undo/Redo Если операция относится к редактированию книги, Rust создаёт одну central-history entry. внешний команда не должна вести отдельный стек Undo в Web.

6 · WEB, MOBILE И SERVER

Ассистент документации

Ответ собран из документации и может быть неточным — сверяйтесь с источниками.