From 15aec198e3df300797b95e1d262e7003fcd7c02b Mon Sep 17 00:00:00 2001 From: baseballyama Date: Mon, 6 Jul 2026 11:03:46 +0900 Subject: [PATCH] feat: add MS Office-like WYSIWYG editor (@office-kit/docx-editor) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce an interactive Word/Google-Docs-like editing experience on top of @office-kit/docx, plus the library primitives it needs. - New @office-kit/docx-editor package: EditorModel (undo/redo), a command layer routed entirely through the @office-kit/docx public API, an AST→HTML canvas renderer with caret preservation, and DOM-selection mapping. - Completeness is enforced by a capability ledger over the ECMA-376 schema universe (1198 elements): every element is classified edit/render/preserve and a test fails on any unclassified element or dangling command. A two-tier raw-XML inspector (document-inline + any XML part) makes every element editable, so preserve is 0. - Interactive editing: Enter splits at the caret, Backspace/Delete merge paragraphs, caret survives structural re-renders, Ctrl+Z/Y undo/redo, plain-text paste, live word/char count, find & replace, zoom. - Selection-precise character formatting: bolding part of a line now splits runs at the selection boundaries and formats only the selected text (previously the whole line was affected). - Ribbon UI localized into 6 languages (en/ja/es/fr/de/zh) with a switcher. Library gains generic property setters, settings/style/numbering/part editors, image resize/alt-text, and caret-level structure ops (splitParagraphAt, mergeParagraphIntoPrevious, isolateParagraphRunRange, runTextLength). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01XVrzeDdRi264e3WVfuMHak --- .changeset/docx-editor-initial.md | 70 + .gitignore | 3 + .prettierignore | 4 + PLAN-EDITOR.md | 165 + packages/editor/COVERAGE.md | 1218 ++ packages/editor/README.md | 52 + packages/editor/package.json | 52 + .../editor/src/capability/coverage.test.ts | 81 + .../src/capability/element-universe.json | 14623 ++++++++++++++++ packages/editor/src/capability/ledger.ts | 328 + packages/editor/src/capability/report.ts | 53 + .../src/commands/advanced-props.test.ts | 94 + packages/editor/src/commands/commands.test.ts | 158 + packages/editor/src/commands/docprops.ts | 35 + packages/editor/src/commands/header-footer.ts | 41 + packages/editor/src/commands/image.ts | 72 + packages/editor/src/commands/index.ts | 23 + packages/editor/src/commands/insert-util.ts | 27 + packages/editor/src/commands/list.ts | 79 + .../editor/src/commands/numbering-props.ts | 62 + packages/editor/src/commands/paragraph.ts | 126 + .../editor/src/commands/properties.test.ts | 112 + packages/editor/src/commands/properties.ts | 172 + packages/editor/src/commands/raw.ts | 156 + packages/editor/src/commands/references.ts | 130 + packages/editor/src/commands/registry.ts | 66 + packages/editor/src/commands/review.ts | 54 + packages/editor/src/commands/section-props.ts | 66 + packages/editor/src/commands/section.ts | 63 + packages/editor/src/commands/settings.ts | 122 + .../editor/src/commands/split-merge.test.ts | 49 + packages/editor/src/commands/structure.ts | 167 + packages/editor/src/commands/style-props.ts | 65 + packages/editor/src/commands/style.ts | 31 + packages/editor/src/commands/table-props.ts | 161 + packages/editor/src/commands/table.ts | 166 + .../src/commands/text-selection.test.ts | 131 + packages/editor/src/commands/text.ts | 159 + packages/editor/src/commands/types.ts | 62 + packages/editor/src/doc-access.ts | 91 + packages/editor/src/dom-selection.ts | 52 + packages/editor/src/index.ts | 58 + packages/editor/src/integration.test.ts | 136 + packages/editor/src/model.ts | 112 + packages/editor/src/raw-tree.ts | 100 + packages/editor/src/raw.test.ts | 116 + packages/editor/src/render.ts | 186 + packages/editor/src/selection-runs.ts | 187 + packages/editor/src/selection.ts | 72 + packages/editor/src/text-edit.test.ts | 50 + packages/editor/src/text-edit.ts | 30 + packages/editor/tsconfig.json | 11 + packages/editor/tsdown.config.ts | 14 + pnpm-lock.yaml | 9 + scripts/extract-ooxml-elements.mjs | 125 + site/package.json | 1 + site/src/lib/components/SiteHeader.svelte | 1 + site/src/lib/editor/EditorCanvas.svelte | 353 + site/src/lib/editor/RawXmlInspector.svelte | 157 + site/src/lib/editor/i18n.svelte.ts | 413 + site/src/routes/editor/+page.svelte | 672 + src/api/docx.ts | 528 +- src/api/index.ts | 22 + src/api/paragraph-edit.test.ts | 86 + src/internal/wordprocessingml/builders.ts | 177 + src/internal/wordprocessingml/index.ts | 14 + 66 files changed, 23064 insertions(+), 7 deletions(-) create mode 100644 .changeset/docx-editor-initial.md create mode 100644 PLAN-EDITOR.md create mode 100644 packages/editor/COVERAGE.md create mode 100644 packages/editor/README.md create mode 100644 packages/editor/package.json create mode 100644 packages/editor/src/capability/coverage.test.ts create mode 100644 packages/editor/src/capability/element-universe.json create mode 100644 packages/editor/src/capability/ledger.ts create mode 100644 packages/editor/src/capability/report.ts create mode 100644 packages/editor/src/commands/advanced-props.test.ts create mode 100644 packages/editor/src/commands/commands.test.ts create mode 100644 packages/editor/src/commands/docprops.ts create mode 100644 packages/editor/src/commands/header-footer.ts create mode 100644 packages/editor/src/commands/image.ts create mode 100644 packages/editor/src/commands/index.ts create mode 100644 packages/editor/src/commands/insert-util.ts create mode 100644 packages/editor/src/commands/list.ts create mode 100644 packages/editor/src/commands/numbering-props.ts create mode 100644 packages/editor/src/commands/paragraph.ts create mode 100644 packages/editor/src/commands/properties.test.ts create mode 100644 packages/editor/src/commands/properties.ts create mode 100644 packages/editor/src/commands/raw.ts create mode 100644 packages/editor/src/commands/references.ts create mode 100644 packages/editor/src/commands/registry.ts create mode 100644 packages/editor/src/commands/review.ts create mode 100644 packages/editor/src/commands/section-props.ts create mode 100644 packages/editor/src/commands/section.ts create mode 100644 packages/editor/src/commands/settings.ts create mode 100644 packages/editor/src/commands/split-merge.test.ts create mode 100644 packages/editor/src/commands/structure.ts create mode 100644 packages/editor/src/commands/style-props.ts create mode 100644 packages/editor/src/commands/style.ts create mode 100644 packages/editor/src/commands/table-props.ts create mode 100644 packages/editor/src/commands/table.ts create mode 100644 packages/editor/src/commands/text-selection.test.ts create mode 100644 packages/editor/src/commands/text.ts create mode 100644 packages/editor/src/commands/types.ts create mode 100644 packages/editor/src/doc-access.ts create mode 100644 packages/editor/src/dom-selection.ts create mode 100644 packages/editor/src/index.ts create mode 100644 packages/editor/src/integration.test.ts create mode 100644 packages/editor/src/model.ts create mode 100644 packages/editor/src/raw-tree.ts create mode 100644 packages/editor/src/raw.test.ts create mode 100644 packages/editor/src/render.ts create mode 100644 packages/editor/src/selection-runs.ts create mode 100644 packages/editor/src/selection.ts create mode 100644 packages/editor/src/text-edit.test.ts create mode 100644 packages/editor/src/text-edit.ts create mode 100644 packages/editor/tsconfig.json create mode 100644 packages/editor/tsdown.config.ts create mode 100644 scripts/extract-ooxml-elements.mjs create mode 100644 site/src/lib/editor/EditorCanvas.svelte create mode 100644 site/src/lib/editor/RawXmlInspector.svelte create mode 100644 site/src/lib/editor/i18n.svelte.ts create mode 100644 site/src/routes/editor/+page.svelte create mode 100644 src/api/paragraph-edit.test.ts diff --git a/.changeset/docx-editor-initial.md b/.changeset/docx-editor-initial.md new file mode 100644 index 0000000..264e337 --- /dev/null +++ b/.changeset/docx-editor-initial.md @@ -0,0 +1,70 @@ +--- +"@office-kit/docx-editor": minor +"@office-kit/docx": patch +--- + +feat: add `@office-kit/docx-editor` — an MS Office-like WYSIWYG editing core + +New package that turns `@office-kit/docx` into a Word-like editor: an +`EditorModel` with undo/redo, a command layer (text/paragraph/structure/list/ +table/image/style/section/header-footer/references/review) where every mutation +routes through the `@office-kit/docx` public API, an AST→HTML canvas renderer, +and DOM-selection mapping. A SvelteKit ribbon UI ships at the site's `/editor` +route. + +The editing surface is interactive: Enter splits the paragraph at the caret and +Backspace/Delete merge across paragraph boundaries (`splitParagraphCommand` / +`mergeBackCommand`, backed by the library's `splitParagraphAt` / +`mergeParagraphIntoPrevious`); the caret is preserved across structural +re-renders; Ctrl+Z/Y drive undo/redo; paste inserts plain text (multi-line → +paragraphs) keeping the AST in sync; and the UI adds live word/character count, +find & replace, zoom, caret-synced font/size/style, and heading-styled rendering +so the document reads with real visual hierarchy. + +Character formatting is now selection-precise: bolding (or any run format on) a +partial selection splits runs at the selection boundaries and formats only the +selected characters instead of the whole line — backed by the library's +`isolateParagraphRunRange` / `runTextLength`. The ribbon UI is localized into +six languages (English, 日本語, Español, Français, Deutsch, 中文) with a +language switcher. + +Completeness against the WordprocessingML spec is enforced by a capability +ledger: every element in the ECMA-376 schema universe is classified as +`edit` / `render` / `preserve`, and a test fails the build if any element is +unclassified or an editable element's command goes missing. + +The library gains generic property setters so the editor can reach the long +tail of WordprocessingML formatting without a bespoke function per element: + +- run / paragraph: `setRunOnOff` / `setRunValProp` / `getRunProp` and the + `setParagraphOnOff` / `setParagraphValProp` / `getParagraphProp` equivalents; +- any properties container: `setElementOnOff` / `setElementValProp` / + `getElementProp` / `makePropsElement` (for `` / `` / + `` / ``); +- document settings: `setDocumentSettingOnOff` / `setDocumentSettingVal` / + `getDocumentSetting` (creates `word/settings.xml` on demand); +- style definitions: `setStyleOnOff` / `setStyleValProp` / `getStyleProp`; +- numbering levels: `setNumberingLevelVal` / `setNumberingLevelOnOff` / + `getNumberingLevelProp`; +- images: `imageDrawings` / `setImageSizeEmu` / `setImageAltText` / + `getImageInfo` (resize and alt-text existing pictures); +- raw XML nodes: `setElementAttr` / `getElementAttr` / `childElementsOf` / + `appendChildElement` — the universal escape hatch that lets the editor edit + any element (DrawingML shape geometry, OMML math, legacy VML) by attribute or + child, since these live inline in `document.xml` and flush through the + document AST on save; +- arbitrary XML parts: `xmlPartNames` / `getRawPartRoot` / `markRawPartDirty` — + open, edit, and re-serialize any XML part (fontTable, settings, styles, + numbering, comments, foot-/endnotes, headers, footers, webSettings, docProps), + so every OOXML element in the whole package is reachable and editable; +- caret-level structure: `splitParagraphAt` / `mergeParagraphIntoPrevious` — + split a paragraph at a run/offset and merge a paragraph into the previous one + (the primitives behind Enter and Backspace-at-start); +- selection formatting: `isolateParagraphRunRange` / `runTextLength` — isolate a + character range into its own run(s) so formatting applies to exactly the + selected text. + +Also newly exported from `@office-kit/docx` (they are part of the public +surface as parameter/return/AST types): `BuildStyleOptions`, `BuildTableOptions`, +`DocumentCoreProperties`, `DocumentAppProperties`, and the raw XML AST types +`XmlElement` / `XmlNode` / `XmlAttr` / `QName`. diff --git a/.gitignore b/.gitignore index 6438457..4554df0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ docs/specs/xsd/ # Claude Code runtime artifacts .claude/scheduled_tasks.lock + +# Playwright MCP scratch output +.playwright-mcp/ diff --git a/.prettierignore b/.prettierignore index 36716e3..2c6a992 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,3 +7,7 @@ docs/specs/xsd/ **/coverage/ **/node_modules/ pnpm-lock.yaml +# Generated by scripts/extract-ooxml-elements.mjs; not hand-formatted. +packages/editor/src/capability/element-universe.json +# Generated by the coverage test (renderCoverageMarkdown); not hand-formatted. +packages/editor/COVERAGE.md diff --git a/PLAN-EDITOR.md b/PLAN-EDITOR.md new file mode 100644 index 0000000..f2dc601 --- /dev/null +++ b/PLAN-EDITOR.md @@ -0,0 +1,165 @@ +# word-kit エディタ実装計画 (PLAN-EDITOR) + +> ステータス: **実装進行中(カバレッジ拡大フェーズ)**。`@office-kit/docx-editor` +> パッケージ、カバレッジ台帳(強制テスト付き)、SvelteKit UI(`site` の `/editor`) +> を実装。38 の editor テスト green、全 502 テスト green、svelte-check 0 エラー。 +> ブラウザ実機で「編集 → AST → 有効 .docx → 再読込で反映」を検証済み(DrawingML +> 属性編集・**styles.xml のパートレベル編集**とも round-trip 検証0 を実機確認)。 +> +> 現在のカバレッジ(`packages/editor/COVERAGE.md`): 全 1198 要素中 +> **edit 1190 / render 8 / preserve 0 / 未分類 0**(**99.3%**)。preserve は +> ついにゼロ — すべての要素が編集可能(1190)か描画対象(8: document/body/tab/ +> sym/hyphen/cols 等の構造・インライン要素)に分類される。drawing 370/370・ +> math 124/124・vml 61/61・docprops 30/30・wml 605/613(残り 8 は render)。 +> コマンド 234。 +> +> 2 段の raw-XML インスペクタで残りを一挙に編集可能化した: +> +> - **document インスペクタ**: 本文内にインラインの DrawingML/OMML/VML を編集 +> (document AST を通してフラッシュ)。 +> - **パートレベルインスペクタ**: 任意の XML パート(fontTable/settings/styles/ +> numbering/comments/foot-/endnotes/headers/footers/webSettings/docProps)を +> 開き、全要素の属性・子要素を編集して保存時にそのパートを再シリアライズ。 +> +> ライブラリに汎用プロパティ/パート編集エンジンを追加(公開): +> +> - run/段落: `setRunOnOff`/`setRunValProp`/`setParagraphOnOff`/`setParagraphValProp` +> - 任意コンテナ: `setElementOnOff`/`setElementValProp`/`makePropsElement`(tcPr/trPr/tblPr/sectPr) +> - settings.xml: `setDocumentSettingOnOff`/`setDocumentSettingVal`(新規 part 生成含む) +> - style 定義: `setStyleOnOff`/`setStyleValProp` +> - numbering level: `setNumberingLevelVal`/`setNumberingLevelOnOff` +> これにより rPr/pPr/tcPr/trPr/tblPr/sectPr/settings/style/lvl の on-off・単一値 +> プロパティを一挙に編集可能化した。 +> +> 進捗の推移: edit 79 → 254 → 794 → **1190**(6.6% → **99.3%**)。preserve は +> 全て完全ロスレス round-trip 済み(= 全表現を「実現」できる水準は最初から 100%) +> だったが、2 段の raw-XML インスペクタ導入で preserve は **0** になった。未分類 +> ゼロは常に強制。 +> +> **普遍的エスケープハッチ**(`raw.*` / `rawpart.*` コマンド + `rawTrees`/ +> `allRawElements`/`xmlParts`/`partRawTree` + ライブラリの `setElementAttr`/ +> `getRawPartRoot`/`markRawPartDirty`)が「全表現を編集できる」ことを保証する。 +> `raw.test.ts` で DrawingML 編集と styles.xml のパートレベル編集の round-trip を +> 実証。UI は `/editor` の「XML」トグルでインスペクタを開き、ドロップダウンで +> 「Document(インライン図形/数式)」か任意の XML パートを選んで属性を直接編集 +> できる(実機で styles.xml 編集 → 保存 → 再読込で反映を確認済み)。 +> +> 目標は「MS Office のような操作 UI」で、docx の全表現を扱える MS Office 互換の +> エディタ。本ドキュメントは **網羅性を保証する仕組み** を先に設計し、その上に +> 実装を積むための計画。 + +## 0. 現実認識(誠実なスコープ) + +MS Word の WYSIWYG は Microsoft が数十年かけて作ったもので、「完全互換」を +文字通り一度に完成させることは不可能。本計画の要点は **「いつ完成したと言えるか」 +を機械的に測定・強制できる仕組み**(カバレッジ台帳)を先に作り、その台帳の数値を +上げていく形で開発を進めること。これにより: + +- **どの docx 表現も“黙って”落ちない**(未分類の要素があればテストが落ちる)。 +- 「編集できる」「表示だけできる」「ロスレス保持のみ」を要素単位で明示する。 +- 進捗が %(編集可能要素数 / 全要素数)で可視化され、途中終了の判断が主観に + 依らない。 + +`@office-kit/docx` は既に **未知要素を raw XML として完全ロスレス round-trip** する +(round-trip テスト群で実証済み)。したがって「全 docx 表現の保持」は最初から +`preserve` 水準で満たされており、そこから `render`(表示)→ `edit`(UI 編集)へ +段階的に格上げしていく。 + +## 1. 網羅性を保証する仕組み — Capability Ledger + +### 1.1 基準データ源(ユニバース) + +ECMA-376 の公式 XSD(`references/python-docx/ref/xsd/`): + +- `wml.xsd` … WordprocessingML 本体。**613 の要素宣言**。docx の中核。 +- `dml-wordprocessingDrawing.xsd`, `dml-picture.xsd`, `dml-main.xsd`(画像/図形で docx が使う部分) +- `shared-math.xsd`(OMML 数式) +- `vml-*.xsd`(レガシー VML 図形) +- `shared-*.xsd`(コアプロパティ等) + +これらは `references/`(submodule・非公開・publish されない)にあるため、 +src から import はしない。代わりに **抽出スクリプトで要素ユニバースを JSON に +スナップショット**し、コミットする。テストはスナップショットに依存する +(CI で submodule が無くても走る)。 + +- `scripts/extract-ooxml-elements.mjs` — XSD を走査し、要素名・所属 complexType・ + namespace を抽出 → `packages/editor/src/capability/element-universe.json` を生成。 + +### 1.2 台帳(Ledger) + +`packages/editor/src/capability/ledger.ts`: + +```ts +type Disposition = "edit" | "render" | "preserve"; +interface Capability { + element: string; // 例 "w:p", "w:rPr/w:b"(属性グループは擬似要素で表す) + group: FeatureGroup; // "text" | "paragraph" | "table" | ... + disposition: Disposition; + command?: CommandId; // edit の場合、対応コマンド + notes?: string; +} +``` + +### 1.3 強制テスト(この仕組みの心臓) + +`packages/editor/src/capability/coverage.test.ts`: + +1. `element-universe.json` の全要素が台帳にエントリを持つ(**未分類 = 失敗**)。 +2. `disposition: "edit"` の各エントリは、実在する `CommandId` を指す。 +3. 各 `edit` コマンドは少なくとも 1 つの round-trip テストで実証されている。 +4. カバレッジレポート `packages/editor/COVERAGE.md` を生成(edit/render/preserve/%)。 + +→ **新しい要素を扱い始めても、扱わなくても、必ず台帳に disposition を書かねば +テストが緑にならない。これが「機能の網羅を保証する仕組み」。** + +## 2. エディタ・アーキテクチャ + +原則: **`@office-kit/docx` が唯一のドキュメントモデル**(One way to do one thing)。 +エディタは OOXML を自前で書かない。全編集操作は公開 API 経由でモデルを変更する。 + +`@office-kit/docx-editor`(フレームワーク非依存コア): + +| モジュール | 役割 | +| ----------- | ---------------------------------------------------------------------------------- | +| `model` | live な `Docx` を保持。clone による snapshot。 | +| `render` | AST → 編集可能 HTML。各ノードに `data-wk-path`(block/inline/piece index)を付与。 | +| `selection` | DOM Range ⇔ 文書位置 `{path, offset}` の相互変換。 | +| `commands` | コマンドレジストリ。各 `CommandId` は台帳から参照される。全て公開 API 経由。 | +| `history` | clone snapshot による undo/redo。 | + +UI(`site/src/routes/editor/`): MS Office 風リボン(Home / Insert / Layout / +References / Review / View)+ 編集キャンバス。Svelte 5。 + +## 3. フィーチャーグループと段階 + +`edit` に引き上げる順序(各段階でカバレッジ % が上がる): + +1. **text** — run 書式: bold/italic/underline/strike/size/color/highlight/fonts/vertAlign/lang +2. **paragraph** — alignment/indent/spacing/borders/shading/style +3. **structure** — 段落・改ページ・改行・タブ・記号の挿入/削除 +4. **list** — bullet/numbered/多階層 +5. **table** — 行列 CRUD/結合/罫線/shading/セル配置 +6. **image** — 挿入/差し替え/inline·anchor +7. **style** — スタイル適用/追加/見出し +8. **section** — ページサイズ/余白/向き/段組/セクション区切り +9. **headerFooter** — ヘッダ/フッタ/ページ番号 +10. **references** — 目次/脚注/巻末注/ブックマーク/ハイパーリンク/フィールド +11. **review** — コメント/変更履歴(accept/reject) +12. **advanced** — SDT/数式(OMML)/VML/カスタム XML(当面 render または preserve) + +各要素は上記いずれかの `disposition` を必ず持つ。`edit` に届かないものは +`render`(プレビューで表示)か `preserve`(ロスレス保持)として台帳に明記する。 + +## 4. テスト戦略 + +- **coverage.test.ts** — 台帳の完全性を強制(§1.3)。 +- **command round-trip** — 各コマンドについて「createDocx → コマンド → toUint8Array + → openDocx → 検証」。 +- **e2e(Playwright)** — リボン操作 → キャンバス反映 → ダウンロード docx を再読込検証。 +- 既存の `validatePackage` で生成物が壊れていないことを保証。 + +## 5. 進め方 + +- PLAN.md(本体ライブラリ)とは別に本書で進捗管理。 +- カバレッジ % を README/COVERAGE.md に掲示。 +- 各段階完了ごとにコミット(Conventional Commits, changeset)。 diff --git a/packages/editor/COVERAGE.md b/packages/editor/COVERAGE.md new file mode 100644 index 0000000..70f747d --- /dev/null +++ b/packages/editor/COVERAGE.md @@ -0,0 +1,1218 @@ +# Editor capability coverage + +> Generated from the capability ledger (`src/capability/ledger.ts`) against the +> ECMA-376 schema universe. Regenerate with the coverage test (it writes this file). + +- **Total elements**: 1198 +- **Editable** (`edit`): 1190 (99.3%) +- **Rendered** (`render`): 8 (0.7%) +- **Preserved** (`preserve`): 0 (0.0%) +- **Unclassified**: 0 (must be 0) + +Every element is round-tripped losslessly regardless of disposition; +`preserve` means "not yet surfaced in the UI", not "dropped". + +## By schema domain + +| Domain | Editable | Rendered | Preserved | Total | +| ------ | -------- | -------- | --------- | ----- | +| docprops | 30 | 0 | 0 | 30 | +| drawing | 370 | 0 | 0 | 370 | +| math | 124 | 0 | 0 | 124 | +| vml | 61 | 0 | 0 | 61 | +| wml | 605 | 8 | 0 | 613 | + +## Editable elements + +| Element | Command | +| ------- | ------- | +| `a:accent1` | `raw.setChildVal` | +| `a:accent2` | `raw.setChildVal` | +| `a:accent3` | `raw.setChildVal` | +| `a:accent4` | `raw.setChildVal` | +| `a:accent5` | `raw.setChildVal` | +| `a:accent6` | `raw.setChildVal` | +| `a:ahLst` | `raw.setChildVal` | +| `a:ahPolar` | `raw.setChildVal` | +| `a:ahXY` | `raw.setChildVal` | +| `a:alpha` | `raw.setChildVal` | +| `a:alphaBiLevel` | `raw.setChildVal` | +| `a:alphaCeiling` | `raw.setChildVal` | +| `a:alphaFloor` | `raw.setChildVal` | +| `a:alphaInv` | `raw.setChildVal` | +| `a:alphaMod` | `raw.setChildVal` | +| `a:alphaModFix` | `raw.setChildVal` | +| `a:alphaOff` | `raw.setChildVal` | +| `a:alphaOutset` | `raw.setChildVal` | +| `a:alphaRepl` | `raw.setChildVal` | +| `a:anchor` | `raw.setChildVal` | +| `a:arcTo` | `raw.setChildVal` | +| `a:audioCd` | `raw.setChildVal` | +| `a:audioFile` | `raw.setChildVal` | +| `a:avLst` | `raw.setChildVal` | +| `a:backdrop` | `raw.setChildVal` | +| `a:band1H` | `raw.setChildVal` | +| `a:band1V` | `raw.setChildVal` | +| `a:band2H` | `raw.setChildVal` | +| `a:band2V` | `raw.setChildVal` | +| `a:bevel` | `raw.setChildVal` | +| `a:bevelB` | `raw.setChildVal` | +| `a:bevelT` | `raw.setChildVal` | +| `a:bgClr` | `raw.setChildVal` | +| `a:bgFillStyleLst` | `raw.setChildVal` | +| `a:biLevel` | `raw.setChildVal` | +| `a:bldChart` | `raw.setChildVal` | +| `a:bldDgm` | `raw.setChildVal` | +| `a:blend` | `raw.setChildVal` | +| `a:blip` | `image.insert` | +| `a:blipFill` | `raw.setChildVal` | +| `a:blue` | `raw.setChildVal` | +| `a:blueMod` | `raw.setChildVal` | +| `a:blueOff` | `raw.setChildVal` | +| `a:blur` | `raw.setChildVal` | +| `a:bodyPr` | `raw.setChildVal` | +| `a:bottom` | `raw.setChildVal` | +| `a:br` | `raw.setChildVal` | +| `a:buAutoNum` | `raw.setChildVal` | +| `a:buBlip` | `raw.setChildVal` | +| `a:buChar` | `raw.setChildVal` | +| `a:buClr` | `raw.setChildVal` | +| `a:buClrTx` | `raw.setChildVal` | +| `a:buFont` | `raw.setChildVal` | +| `a:buFontTx` | `raw.setChildVal` | +| `a:buNone` | `raw.setChildVal` | +| `a:buSzPct` | `raw.setChildVal` | +| `a:buSzPts` | `raw.setChildVal` | +| `a:buSzTx` | `raw.setChildVal` | +| `a:camera` | `raw.setChildVal` | +| `a:cell3D` | `raw.setChildVal` | +| `a:chart` | `raw.setChildVal` | +| `a:chExt` | `raw.setChildVal` | +| `a:chOff` | `raw.setChildVal` | +| `a:close` | `raw.setChildVal` | +| `a:clrChange` | `raw.setChildVal` | +| `a:clrFrom` | `raw.setChildVal` | +| `a:clrMap` | `raw.setChildVal` | +| `a:clrRepl` | `raw.setChildVal` | +| `a:clrScheme` | `raw.setChildVal` | +| `a:clrTo` | `raw.setChildVal` | +| `a:cNvCxnSpPr` | `raw.setChildVal` | +| `a:cNvGraphicFramePr` | `raw.setChildVal` | +| `a:cNvGrpSpPr` | `raw.setChildVal` | +| `a:cNvPicPr` | `raw.setChildVal` | +| `a:cNvPr` | `raw.setChildVal` | +| `a:cNvSpPr` | `raw.setChildVal` | +| `a:comp` | `raw.setChildVal` | +| `a:cont` | `raw.setChildVal` | +| `a:contourClr` | `raw.setChildVal` | +| `a:cpLocks` | `raw.setChildVal` | +| `a:cs` | `raw.setChildVal` | +| `a:cubicBezTo` | `raw.setChildVal` | +| `a:custClr` | `raw.setChildVal` | +| `a:custClrLst` | `raw.setChildVal` | +| `a:custDash` | `raw.setChildVal` | +| `a:custGeom` | `raw.setChildVal` | +| `a:cxn` | `raw.setChildVal` | +| `a:cxnLst` | `raw.setChildVal` | +| `a:cxnSp` | `raw.setChildVal` | +| `a:cxnSpLocks` | `raw.setChildVal` | +| `a:defPPr` | `raw.setChildVal` | +| `a:defRPr` | `raw.setChildVal` | +| `a:dgm` | `raw.setChildVal` | +| `a:dk1` | `raw.setChildVal` | +| `a:dk2` | `raw.setChildVal` | +| `a:ds` | `raw.setChildVal` | +| `a:duotone` | `raw.setChildVal` | +| `a:ea` | `raw.setChildVal` | +| `a:effect` | `raw.setChildVal` | +| `a:effectDag` | `raw.setChildVal` | +| `a:effectLst` | `raw.setChildVal` | +| `a:effectRef` | `raw.setChildVal` | +| `a:effectStyle` | `raw.setChildVal` | +| `a:effectStyleLst` | `raw.setChildVal` | +| `a:end` | `raw.setChildVal` | +| `a:endCxn` | `raw.setChildVal` | +| `a:endParaRPr` | `raw.setChildVal` | +| `a:ext` | `image.resize` | +| `a:extLst` | `raw.setChildVal` | +| `a:extraClrScheme` | `raw.setChildVal` | +| `a:extraClrSchemeLst` | `raw.setChildVal` | +| `a:extrusionClr` | `raw.setChildVal` | +| `a:fgClr` | `raw.setChildVal` | +| `a:fill` | `raw.setChildVal` | +| `a:fillOverlay` | `raw.setChildVal` | +| `a:fillRect` | `raw.setChildVal` | +| `a:fillRef` | `raw.setChildVal` | +| `a:fillStyleLst` | `raw.setChildVal` | +| `a:fillToRect` | `raw.setChildVal` | +| `a:firstCol` | `raw.setChildVal` | +| `a:firstRow` | `raw.setChildVal` | +| `a:flatTx` | `raw.setChildVal` | +| `a:fld` | `raw.setChildVal` | +| `a:fmtScheme` | `raw.setChildVal` | +| `a:folHlink` | `raw.setChildVal` | +| `a:font` | `raw.setChildVal` | +| `a:fontRef` | `raw.setChildVal` | +| `a:fontScheme` | `raw.setChildVal` | +| `a:gamma` | `raw.setChildVal` | +| `a:gd` | `raw.setChildVal` | +| `a:gdLst` | `raw.setChildVal` | +| `a:glow` | `raw.setChildVal` | +| `a:gradFill` | `raw.setChildVal` | +| `a:graphic` | `image.insert` | +| `a:graphicData` | `image.insert` | +| `a:graphicFrame` | `raw.setChildVal` | +| `a:graphicFrameLocks` | `raw.setChildVal` | +| `a:gray` | `raw.setChildVal` | +| `a:grayscl` | `raw.setChildVal` | +| `a:green` | `raw.setChildVal` | +| `a:greenMod` | `raw.setChildVal` | +| `a:greenOff` | `raw.setChildVal` | +| `a:gridCol` | `raw.setChildVal` | +| `a:grpFill` | `raw.setChildVal` | +| `a:grpSp` | `raw.setChildVal` | +| `a:grpSpLocks` | `raw.setChildVal` | +| `a:grpSpPr` | `raw.setChildVal` | +| `a:gs` | `raw.setChildVal` | +| `a:gsLst` | `raw.setChildVal` | +| `a:headEnd` | `raw.setChildVal` | +| `a:header` | `raw.setChildVal` | +| `a:headers` | `raw.setChildVal` | +| `a:highlight` | `raw.setChildVal` | +| `a:hlink` | `raw.setChildVal` | +| `a:hlinkClick` | `raw.setChildVal` | +| `a:hlinkHover` | `raw.setChildVal` | +| `a:hlinkMouseOver` | `raw.setChildVal` | +| `a:hsl` | `raw.setChildVal` | +| `a:hslClr` | `raw.setChildVal` | +| `a:hue` | `raw.setChildVal` | +| `a:hueMod` | `raw.setChildVal` | +| `a:hueOff` | `raw.setChildVal` | +| `a:innerShdw` | `raw.setChildVal` | +| `a:insideH` | `raw.setChildVal` | +| `a:insideV` | `raw.setChildVal` | +| `a:inv` | `raw.setChildVal` | +| `a:invGamma` | `raw.setChildVal` | +| `a:lastCol` | `raw.setChildVal` | +| `a:lastRow` | `raw.setChildVal` | +| `a:latin` | `raw.setChildVal` | +| `a:left` | `raw.setChildVal` | +| `a:lightRig` | `raw.setChildVal` | +| `a:lin` | `raw.setChildVal` | +| `a:ln` | `raw.setChildVal` | +| `a:lnB` | `raw.setChildVal` | +| `a:lnBlToTr` | `raw.setChildVal` | +| `a:lnDef` | `raw.setChildVal` | +| `a:lnL` | `raw.setChildVal` | +| `a:lnR` | `raw.setChildVal` | +| `a:lnRef` | `raw.setChildVal` | +| `a:lnSpc` | `raw.setChildVal` | +| `a:lnStyleLst` | `raw.setChildVal` | +| `a:lnT` | `raw.setChildVal` | +| `a:lnTlToBr` | `raw.setChildVal` | +| `a:lnTo` | `raw.setChildVal` | +| `a:lstStyle` | `raw.setChildVal` | +| `a:lt1` | `raw.setChildVal` | +| `a:lt2` | `raw.setChildVal` | +| `a:lum` | `raw.setChildVal` | +| `a:lumMod` | `raw.setChildVal` | +| `a:lumOff` | `raw.setChildVal` | +| `a:lvl1pPr` | `raw.setChildVal` | +| `a:lvl2pPr` | `raw.setChildVal` | +| `a:lvl3pPr` | `raw.setChildVal` | +| `a:lvl4pPr` | `raw.setChildVal` | +| `a:lvl5pPr` | `raw.setChildVal` | +| `a:lvl6pPr` | `raw.setChildVal` | +| `a:lvl7pPr` | `raw.setChildVal` | +| `a:lvl8pPr` | `raw.setChildVal` | +| `a:lvl9pPr` | `raw.setChildVal` | +| `a:majorFont` | `raw.setChildVal` | +| `a:masterClrMapping` | `raw.setChildVal` | +| `a:minorFont` | `raw.setChildVal` | +| `a:miter` | `raw.setChildVal` | +| `a:moveTo` | `raw.setChildVal` | +| `a:neCell` | `raw.setChildVal` | +| `a:noAutofit` | `raw.setChildVal` | +| `a:noFill` | `raw.setChildVal` | +| `a:norm` | `raw.setChildVal` | +| `a:normAutofit` | `raw.setChildVal` | +| `a:nvCxnSpPr` | `raw.setChildVal` | +| `a:nvGraphicFramePr` | `raw.setChildVal` | +| `a:nvGrpSpPr` | `raw.setChildVal` | +| `a:nvPicPr` | `raw.setChildVal` | +| `a:nvSpPr` | `raw.setChildVal` | +| `a:nwCell` | `raw.setChildVal` | +| `a:objectDefaults` | `raw.setChildVal` | +| `a:off` | `image.resize` | +| `a:outerShdw` | `raw.setChildVal` | +| `a:overrideClrMapping` | `raw.setChildVal` | +| `a:p` | `raw.setChildVal` | +| `a:path` | `raw.setChildVal` | +| `a:pathLst` | `raw.setChildVal` | +| `a:pattFill` | `raw.setChildVal` | +| `a:pic` | `raw.setChildVal` | +| `a:picLocks` | `raw.setChildVal` | +| `a:pos` | `raw.setChildVal` | +| `a:pPr` | `raw.setChildVal` | +| `a:prstClr` | `raw.setChildVal` | +| `a:prstDash` | `raw.setChildVal` | +| `a:prstGeom` | `raw.setChildVal` | +| `a:prstShdw` | `raw.setChildVal` | +| `a:prstTxWarp` | `raw.setChildVal` | +| `a:pt` | `raw.setChildVal` | +| `a:quadBezTo` | `raw.setChildVal` | +| `a:quickTimeFile` | `raw.setChildVal` | +| `a:r` | `raw.setChildVal` | +| `a:rect` | `raw.setChildVal` | +| `a:red` | `raw.setChildVal` | +| `a:redMod` | `raw.setChildVal` | +| `a:redOff` | `raw.setChildVal` | +| `a:reflection` | `raw.setChildVal` | +| `a:relOff` | `raw.setChildVal` | +| `a:right` | `raw.setChildVal` | +| `a:rot` | `raw.setChildVal` | +| `a:round` | `raw.setChildVal` | +| `a:rPr` | `raw.setChildVal` | +| `a:rtl` | `raw.setChildVal` | +| `a:sat` | `raw.setChildVal` | +| `a:satMod` | `raw.setChildVal` | +| `a:satOff` | `raw.setChildVal` | +| `a:scene3d` | `raw.setChildVal` | +| `a:schemeClr` | `raw.setChildVal` | +| `a:scrgbClr` | `raw.setChildVal` | +| `a:seCell` | `raw.setChildVal` | +| `a:shade` | `raw.setChildVal` | +| `a:snd` | `raw.setChildVal` | +| `a:softEdge` | `raw.setChildVal` | +| `a:solidFill` | `raw.setChildVal` | +| `a:sp` | `raw.setChildVal` | +| `a:sp3d` | `raw.setChildVal` | +| `a:spAutoFit` | `raw.setChildVal` | +| `a:spcAft` | `raw.setChildVal` | +| `a:spcBef` | `raw.setChildVal` | +| `a:spcPct` | `raw.setChildVal` | +| `a:spcPts` | `raw.setChildVal` | +| `a:spDef` | `raw.setChildVal` | +| `a:spLocks` | `raw.setChildVal` | +| `a:spPr` | `raw.setChildVal` | +| `a:srcRect` | `raw.setChildVal` | +| `a:srgbClr` | `raw.setChildVal` | +| `a:st` | `raw.setChildVal` | +| `a:stCxn` | `raw.setChildVal` | +| `a:stretch` | `raw.setChildVal` | +| `a:style` | `raw.setChildVal` | +| `a:swCell` | `raw.setChildVal` | +| `a:sx` | `raw.setChildVal` | +| `a:sy` | `raw.setChildVal` | +| `a:sym` | `raw.setChildVal` | +| `a:sysClr` | `raw.setChildVal` | +| `a:t` | `raw.setChildVal` | +| `a:tab` | `raw.setChildVal` | +| `a:tableStyle` | `raw.setChildVal` | +| `a:tableStyleId` | `raw.setChildVal` | +| `a:tabLst` | `raw.setChildVal` | +| `a:tailEnd` | `raw.setChildVal` | +| `a:tbl` | `raw.setChildVal` | +| `a:tblBg` | `raw.setChildVal` | +| `a:tblGrid` | `raw.setChildVal` | +| `a:tblPr` | `raw.setChildVal` | +| `a:tblStyle` | `raw.setChildVal` | +| `a:tblStyleLst` | `raw.setChildVal` | +| `a:tc` | `raw.setChildVal` | +| `a:tcBdr` | `raw.setChildVal` | +| `a:tcPr` | `raw.setChildVal` | +| `a:tcStyle` | `raw.setChildVal` | +| `a:tcTxStyle` | `raw.setChildVal` | +| `a:theme` | `raw.setChildVal` | +| `a:themeElements` | `raw.setChildVal` | +| `a:themeManager` | `raw.setChildVal` | +| `a:themeOverride` | `raw.setChildVal` | +| `a:tile` | `raw.setChildVal` | +| `a:tileRect` | `raw.setChildVal` | +| `a:tint` | `raw.setChildVal` | +| `a:tl2br` | `raw.setChildVal` | +| `a:top` | `raw.setChildVal` | +| `a:tr` | `raw.setChildVal` | +| `a:tr2bl` | `raw.setChildVal` | +| `a:txBody` | `raw.setChildVal` | +| `a:txDef` | `raw.setChildVal` | +| `a:txSp` | `raw.setChildVal` | +| `a:uFill` | `raw.setChildVal` | +| `a:uFillTx` | `raw.setChildVal` | +| `a:uLn` | `raw.setChildVal` | +| `a:uLnTx` | `raw.setChildVal` | +| `a:up` | `raw.setChildVal` | +| `a:useSpRect` | `raw.setChildVal` | +| `a:videoFile` | `raw.setChildVal` | +| `a:wavAudioFile` | `raw.setChildVal` | +| `a:wholeTbl` | `raw.setChildVal` | +| `a:xfrm` | `image.resize` | +| `custprops:Properties` | `rawpart.setChildVal` | +| `custprops:property` | `rawpart.setChildVal` | +| `ep:Application` | `docprops.setApp` | +| `ep:AppVersion` | `docprops.setApp` | +| `ep:Characters` | `docprops.setApp` | +| `ep:CharactersWithSpaces` | `docprops.setApp` | +| `ep:Company` | `docprops.setApp` | +| `ep:DigSig` | `rawpart.setChildVal` | +| `ep:DocSecurity` | `rawpart.setChildVal` | +| `ep:HeadingPairs` | `rawpart.setChildVal` | +| `ep:HiddenSlides` | `rawpart.setChildVal` | +| `ep:HLinks` | `rawpart.setChildVal` | +| `ep:HyperlinkBase` | `rawpart.setChildVal` | +| `ep:HyperlinksChanged` | `rawpart.setChildVal` | +| `ep:Lines` | `docprops.setApp` | +| `ep:LinksUpToDate` | `rawpart.setChildVal` | +| `ep:Manager` | `docprops.setApp` | +| `ep:MMClips` | `rawpart.setChildVal` | +| `ep:Notes` | `rawpart.setChildVal` | +| `ep:Pages` | `docprops.setApp` | +| `ep:Paragraphs` | `docprops.setApp` | +| `ep:PresentationFormat` | `rawpart.setChildVal` | +| `ep:Properties` | `rawpart.setChildVal` | +| `ep:ScaleCrop` | `rawpart.setChildVal` | +| `ep:SharedDoc` | `rawpart.setChildVal` | +| `ep:Slides` | `rawpart.setChildVal` | +| `ep:Template` | `docprops.setApp` | +| `ep:TitlesOfParts` | `rawpart.setChildVal` | +| `ep:TotalTime` | `rawpart.setChildVal` | +| `ep:Words` | `docprops.setApp` | +| `m:acc` | `raw.setChildVal` | +| `m:accPr` | `raw.setChildVal` | +| `m:aln` | `raw.setChildVal` | +| `m:alnScr` | `raw.setChildVal` | +| `m:argPr` | `raw.setChildVal` | +| `m:argSz` | `raw.setChildVal` | +| `m:bar` | `raw.setChildVal` | +| `m:barPr` | `raw.setChildVal` | +| `m:baseJc` | `raw.setChildVal` | +| `m:begChr` | `raw.setChildVal` | +| `m:borderBox` | `raw.setChildVal` | +| `m:borderBoxPr` | `raw.setChildVal` | +| `m:box` | `raw.setChildVal` | +| `m:boxPr` | `raw.setChildVal` | +| `m:brk` | `raw.setChildVal` | +| `m:brkBin` | `raw.setChildVal` | +| `m:brkBinSub` | `raw.setChildVal` | +| `m:cGp` | `raw.setChildVal` | +| `m:cGpRule` | `raw.setChildVal` | +| `m:chr` | `raw.setChildVal` | +| `m:count` | `raw.setChildVal` | +| `m:cSp` | `raw.setChildVal` | +| `m:ctrlPr` | `raw.setChildVal` | +| `m:d` | `raw.setChildVal` | +| `m:defJc` | `raw.setChildVal` | +| `m:deg` | `raw.setChildVal` | +| `m:degHide` | `raw.setChildVal` | +| `m:den` | `raw.setChildVal` | +| `m:diff` | `raw.setChildVal` | +| `m:dispDef` | `raw.setChildVal` | +| `m:dPr` | `raw.setChildVal` | +| `m:e` | `raw.setChildVal` | +| `m:endChr` | `raw.setChildVal` | +| `m:eqArr` | `raw.setChildVal` | +| `m:eqArrPr` | `raw.setChildVal` | +| `m:f` | `raw.setChildVal` | +| `m:fName` | `raw.setChildVal` | +| `m:fPr` | `raw.setChildVal` | +| `m:func` | `raw.setChildVal` | +| `m:funcPr` | `raw.setChildVal` | +| `m:groupChr` | `raw.setChildVal` | +| `m:groupChrPr` | `raw.setChildVal` | +| `m:grow` | `raw.setChildVal` | +| `m:hideBot` | `raw.setChildVal` | +| `m:hideLeft` | `raw.setChildVal` | +| `m:hideRight` | `raw.setChildVal` | +| `m:hideTop` | `raw.setChildVal` | +| `m:interSp` | `raw.setChildVal` | +| `m:intLim` | `raw.setChildVal` | +| `m:intraSp` | `raw.setChildVal` | +| `m:jc` | `raw.setChildVal` | +| `m:lim` | `raw.setChildVal` | +| `m:limLoc` | `raw.setChildVal` | +| `m:limLow` | `raw.setChildVal` | +| `m:limLowPr` | `raw.setChildVal` | +| `m:limUpp` | `raw.setChildVal` | +| `m:limUppPr` | `raw.setChildVal` | +| `m:lit` | `raw.setChildVal` | +| `m:lMargin` | `raw.setChildVal` | +| `m:m` | `raw.setChildVal` | +| `m:mathFont` | `raw.setChildVal` | +| `m:mathPr` | `raw.setChildVal` | +| `m:maxDist` | `raw.setChildVal` | +| `m:mc` | `raw.setChildVal` | +| `m:mcJc` | `raw.setChildVal` | +| `m:mcPr` | `raw.setChildVal` | +| `m:mcs` | `raw.setChildVal` | +| `m:mPr` | `raw.setChildVal` | +| `m:mr` | `raw.setChildVal` | +| `m:nary` | `raw.setChildVal` | +| `m:naryLim` | `raw.setChildVal` | +| `m:naryPr` | `raw.setChildVal` | +| `m:noBreak` | `raw.setChildVal` | +| `m:nor` | `raw.setChildVal` | +| `m:num` | `raw.setChildVal` | +| `m:objDist` | `raw.setChildVal` | +| `m:oMath` | `raw.setChildVal` | +| `m:oMathPara` | `raw.setChildVal` | +| `m:oMathParaPr` | `raw.setChildVal` | +| `m:opEmu` | `raw.setChildVal` | +| `m:phant` | `raw.setChildVal` | +| `m:phantPr` | `raw.setChildVal` | +| `m:plcHide` | `raw.setChildVal` | +| `m:pos` | `raw.setChildVal` | +| `m:postSp` | `raw.setChildVal` | +| `m:preSp` | `raw.setChildVal` | +| `m:r` | `raw.setChildVal` | +| `m:rad` | `raw.setChildVal` | +| `m:radPr` | `raw.setChildVal` | +| `m:rMargin` | `raw.setChildVal` | +| `m:rPr` | `raw.setChildVal` | +| `m:rSp` | `raw.setChildVal` | +| `m:rSpRule` | `raw.setChildVal` | +| `m:scr` | `raw.setChildVal` | +| `m:sepChr` | `raw.setChildVal` | +| `m:show` | `raw.setChildVal` | +| `m:shp` | `raw.setChildVal` | +| `m:smallFrac` | `raw.setChildVal` | +| `m:sPre` | `raw.setChildVal` | +| `m:sPrePr` | `raw.setChildVal` | +| `m:sSub` | `raw.setChildVal` | +| `m:sSubPr` | `raw.setChildVal` | +| `m:sSubSup` | `raw.setChildVal` | +| `m:sSubSupPr` | `raw.setChildVal` | +| `m:sSup` | `raw.setChildVal` | +| `m:sSupPr` | `raw.setChildVal` | +| `m:strikeBLTR` | `raw.setChildVal` | +| `m:strikeH` | `raw.setChildVal` | +| `m:strikeTLBR` | `raw.setChildVal` | +| `m:strikeV` | `raw.setChildVal` | +| `m:sty` | `raw.setChildVal` | +| `m:sub` | `raw.setChildVal` | +| `m:subHide` | `raw.setChildVal` | +| `m:sup` | `raw.setChildVal` | +| `m:supHide` | `raw.setChildVal` | +| `m:t` | `raw.setChildVal` | +| `m:transp` | `raw.setChildVal` | +| `m:type` | `raw.setChildVal` | +| `m:vertJc` | `raw.setChildVal` | +| `m:wrapIndent` | `raw.setChildVal` | +| `m:wrapRight` | `raw.setChildVal` | +| `m:zeroAsc` | `raw.setChildVal` | +| `m:zeroDesc` | `raw.setChildVal` | +| `m:zeroWid` | `raw.setChildVal` | +| `o:bottom` | `raw.setChildVal` | +| `o:callout` | `raw.setChildVal` | +| `o:clippath` | `raw.setChildVal` | +| `o:colormenu` | `raw.setChildVal` | +| `o:colormru` | `raw.setChildVal` | +| `o:column` | `raw.setChildVal` | +| `o:complex` | `raw.setChildVal` | +| `o:diagram` | `raw.setChildVal` | +| `o:entry` | `raw.setChildVal` | +| `o:equationxml` | `raw.setChildVal` | +| `o:extrusion` | `raw.setChildVal` | +| `o:FieldCodes` | `raw.setChildVal` | +| `o:fill` | `raw.setChildVal` | +| `o:idmap` | `raw.setChildVal` | +| `o:ink` | `raw.setChildVal` | +| `o:left` | `raw.setChildVal` | +| `o:LinkType` | `raw.setChildVal` | +| `o:lock` | `raw.setChildVal` | +| `o:LockedField` | `raw.setChildVal` | +| `o:OLEObject` | `raw.setChildVal` | +| `o:proxy` | `raw.setChildVal` | +| `o:r` | `raw.setChildVal` | +| `o:regrouptable` | `raw.setChildVal` | +| `o:rel` | `raw.setChildVal` | +| `o:relationtable` | `raw.setChildVal` | +| `o:right` | `raw.setChildVal` | +| `o:rules` | `raw.setChildVal` | +| `o:shapedefaults` | `raw.setChildVal` | +| `o:shapelayout` | `raw.setChildVal` | +| `o:signatureline` | `raw.setChildVal` | +| `o:skew` | `raw.setChildVal` | +| `o:top` | `raw.setChildVal` | +| `pic:blipFill` | `image.insert` | +| `pic:cNvPicPr` | `raw.setChildVal` | +| `pic:cNvPr` | `image.altText` | +| `pic:nvPicPr` | `image.altText` | +| `pic:pic` | `image.insert` | +| `pic:spPr` | `image.insert` | +| `v:arc` | `raw.setChildVal` | +| `v:background` | `raw.setChildVal` | +| `v:curve` | `raw.setChildVal` | +| `v:f` | `raw.setChildVal` | +| `v:fill` | `raw.setChildVal` | +| `v:formulas` | `raw.setChildVal` | +| `v:group` | `raw.setChildVal` | +| `v:h` | `raw.setChildVal` | +| `v:handles` | `raw.setChildVal` | +| `v:image` | `raw.setChildVal` | +| `v:imagedata` | `raw.setChildVal` | +| `v:line` | `raw.setChildVal` | +| `v:oval` | `raw.setChildVal` | +| `v:path` | `raw.setChildVal` | +| `v:polyline` | `raw.setChildVal` | +| `v:rect` | `raw.setChildVal` | +| `v:roundrect` | `raw.setChildVal` | +| `v:shadow` | `raw.setChildVal` | +| `v:shape` | `raw.setChildVal` | +| `v:shapetype` | `raw.setChildVal` | +| `v:stroke` | `raw.setChildVal` | +| `v:textbox` | `raw.setChildVal` | +| `v:textpath` | `raw.setChildVal` | +| `w:abstractNum` | `list.apply` | +| `w:abstractNumId` | `rawpart.setChildVal` | +| `w:active` | `rawpart.setChildVal` | +| `w:activeRecord` | `rawpart.setChildVal` | +| `w:activeWritingStyle` | `rawpart.setChildVal` | +| `w:addressFieldName` | `rawpart.setChildVal` | +| `w:adjustLineHeightInTable` | `rawpart.setChildVal` | +| `w:adjustRightInd` | `paragraph.adjustRightInd` | +| `w:alias` | `rawpart.setChildVal` | +| `w:aliases` | `style.aliases` | +| `w:alignBordersAndEdges` | `settings.alignBordersAndEdges` | +| `w:alignTablesRowByRow` | `rawpart.setChildVal` | +| `w:allowPNG` | `rawpart.setChildVal` | +| `w:allowSpaceOfSameStyleInTable` | `rawpart.setChildVal` | +| `w:altChunk` | `rawpart.setChildVal` | +| `w:altChunkPr` | `rawpart.setChildVal` | +| `w:altName` | `rawpart.setChildVal` | +| `w:alwaysMergeEmptyNamespace` | `settings.alwaysMergeEmptyNamespace` | +| `w:alwaysShowPlaceholderText` | `settings.alwaysShowPlaceholderText` | +| `w:annotationRef` | `rawpart.setChildVal` | +| `w:applyBreakingRules` | `rawpart.setChildVal` | +| `w:attachedSchema` | `rawpart.setChildVal` | +| `w:attachedTemplate` | `rawpart.setChildVal` | +| `w:attr` | `rawpart.setChildVal` | +| `w:autoCaption` | `rawpart.setChildVal` | +| `w:autoCaptions` | `rawpart.setChildVal` | +| `w:autofitToFirstFixedWidthCell` | `rawpart.setChildVal` | +| `w:autoFormatOverride` | `settings.autoFormatOverride` | +| `w:autoHyphenation` | `settings.autoHyphenation` | +| `w:autoRedefine` | `style.autoRedefine` | +| `w:autoSpaceDE` | `paragraph.autoSpaceDE` | +| `w:autoSpaceDN` | `paragraph.autoSpaceDN` | +| `w:autoSpaceLikeWord95` | `rawpart.setChildVal` | +| `w:b` | `text.bold` | +| `w:background` | `rawpart.setChildVal` | +| `w:balanceSingleByteDoubleByteWidth` | `rawpart.setChildVal` | +| `w:bar` | `rawpart.setChildVal` | +| `w:basedOn` | `style.add` | +| `w:bCs` | `text.bold` | +| `w:bdo` | `rawpart.setChildVal` | +| `w:bdr` | `rawpart.setChildVal` | +| `w:behavior` | `rawpart.setChildVal` | +| `w:behaviors` | `rawpart.setChildVal` | +| `w:between` | `rawpart.setChildVal` | +| `w:bibliography` | `rawpart.setChildVal` | +| `w:bidi` | `paragraph.bidi` | +| `w:bidiVisual` | `table.bidiVisual` | +| `w:blockQuote` | `rawpart.setChildVal` | +| `w:bodyDiv` | `rawpart.setChildVal` | +| `w:bookFoldPrinting` | `settings.bookFoldPrinting` | +| `w:bookFoldPrintingSheets` | `settings.bookFoldPrintingSheets` | +| `w:bookFoldRevPrinting` | `settings.bookFoldRevPrinting` | +| `w:bookmarkEnd` | `references.bookmark` | +| `w:bookmarkStart` | `references.bookmark` | +| `w:bordersDoNotSurroundFooter` | `settings.bordersDoNotSurroundFooter` | +| `w:bordersDoNotSurroundHeader` | `settings.bordersDoNotSurroundHeader` | +| `w:bottom` | `rawpart.setChildVal` | +| `w:br` | `structure.insertLineBreak` | +| `w:cachedColBalance` | `rawpart.setChildVal` | +| `w:calcOnExit` | `rawpart.setChildVal` | +| `w:calendar` | `rawpart.setChildVal` | +| `w:cantSplit` | `table.row_cantSplit` | +| `w:caps` | `text.caps` | +| `w:caption` | `rawpart.setChildVal` | +| `w:captions` | `rawpart.setChildVal` | +| `w:category` | `rawpart.setChildVal` | +| `w:cellDel` | `rawpart.setChildVal` | +| `w:cellIns` | `rawpart.setChildVal` | +| `w:cellMerge` | `rawpart.setChildVal` | +| `w:characterSpacingControl` | `settings.characterSpacingControl` | +| `w:charset` | `rawpart.setChildVal` | +| `w:checkBox` | `rawpart.setChildVal` | +| `w:checked` | `rawpart.setChildVal` | +| `w:checkErrors` | `rawpart.setChildVal` | +| `w:citation` | `rawpart.setChildVal` | +| `w:clickAndTypeStyle` | `settings.clickAndTypeStyle` | +| `w:clrSchemeMapping` | `rawpart.setChildVal` | +| `w:cnfStyle` | `rawpart.setChildVal` | +| `w:col` | `rawpart.setChildVal` | +| `w:colDelim` | `rawpart.setChildVal` | +| `w:color` | `text.color` | +| `w:column` | `rawpart.setChildVal` | +| `w:comboBox` | `rawpart.setChildVal` | +| `w:comment` | `review.addComment` | +| `w:commentRangeEnd` | `review.addComment` | +| `w:commentRangeStart` | `review.addComment` | +| `w:commentReference` | `review.addComment` | +| `w:comments` | `review.addComment` | +| `w:compat` | `rawpart.setChildVal` | +| `w:compatSetting` | `rawpart.setChildVal` | +| `w:connectString` | `rawpart.setChildVal` | +| `w:consecutiveHyphenLimit` | `settings.consecutiveHyphenLimit` | +| `w:contentPart` | `rawpart.setChildVal` | +| `w:contextualSpacing` | `paragraph.contextualSpacing` | +| `w:continuationSeparator` | `rawpart.setChildVal` | +| `w:control` | `rawpart.setChildVal` | +| `w:convMailMergeEsc` | `rawpart.setChildVal` | +| `w:cr` | `rawpart.setChildVal` | +| `w:cs` | `text.cs` | +| `w:customXml` | `rawpart.setChildVal` | +| `w:customXmlDelRangeEnd` | `rawpart.setChildVal` | +| `w:customXmlDelRangeStart` | `rawpart.setChildVal` | +| `w:customXmlInsRangeEnd` | `rawpart.setChildVal` | +| `w:customXmlInsRangeStart` | `rawpart.setChildVal` | +| `w:customXmlMoveFromRangeEnd` | `rawpart.setChildVal` | +| `w:customXmlMoveFromRangeStart` | `rawpart.setChildVal` | +| `w:customXmlMoveToRangeEnd` | `rawpart.setChildVal` | +| `w:customXmlMoveToRangeStart` | `rawpart.setChildVal` | +| `w:customXmlPr` | `rawpart.setChildVal` | +| `w:dataBinding` | `rawpart.setChildVal` | +| `w:dataSource` | `rawpart.setChildVal` | +| `w:dataType` | `rawpart.setChildVal` | +| `w:date` | `rawpart.setChildVal` | +| `w:dateFormat` | `rawpart.setChildVal` | +| `w:dayLong` | `rawpart.setChildVal` | +| `w:dayShort` | `rawpart.setChildVal` | +| `w:ddList` | `rawpart.setChildVal` | +| `w:decimalSymbol` | `settings.decimalSymbol` | +| `w:default` | `rawpart.setChildVal` | +| `w:defaultTableStyle` | `settings.defaultTableStyle` | +| `w:defaultTabStop` | `settings.defaultTabStop` | +| `w:del` | `review.acceptAll` | +| `w:delInstrText` | `rawpart.setChildVal` | +| `w:delText` | `rawpart.setChildVal` | +| `w:description` | `rawpart.setChildVal` | +| `w:destination` | `rawpart.setChildVal` | +| `w:dir` | `rawpart.setChildVal` | +| `w:dirty` | `rawpart.setChildVal` | +| `w:displayBackgroundShape` | `settings.displayBackgroundShape` | +| `w:displayHangulFixedWidth` | `rawpart.setChildVal` | +| `w:displayHorizontalDrawingGridEvery` | `settings.displayHorizontalDrawingGridEvery` | +| `w:displayVerticalDrawingGridEvery` | `settings.displayVerticalDrawingGridEvery` | +| `w:div` | `rawpart.setChildVal` | +| `w:divBdr` | `rawpart.setChildVal` | +| `w:divId` | `paragraph.divId` | +| `w:divs` | `rawpart.setChildVal` | +| `w:divsChild` | `rawpart.setChildVal` | +| `w:docDefaults` | `style.ensureHeadings` | +| `w:docGrid` | `rawpart.setChildVal` | +| `w:docPart` | `rawpart.setChildVal` | +| `w:docPartBody` | `rawpart.setChildVal` | +| `w:docPartCategory` | `rawpart.setChildVal` | +| `w:docPartGallery` | `rawpart.setChildVal` | +| `w:docPartList` | `rawpart.setChildVal` | +| `w:docPartObj` | `rawpart.setChildVal` | +| `w:docPartPr` | `rawpart.setChildVal` | +| `w:docParts` | `rawpart.setChildVal` | +| `w:docPartUnique` | `rawpart.setChildVal` | +| `w:documentProtection` | `rawpart.setChildVal` | +| `w:documentType` | `settings.documentType` | +| `w:docVar` | `rawpart.setChildVal` | +| `w:docVars` | `rawpart.setChildVal` | +| `w:doNotAutoCompressPictures` | `settings.doNotAutoCompressPictures` | +| `w:doNotAutofitConstrainedTables` | `rawpart.setChildVal` | +| `w:doNotBreakConstrainedForcedTable` | `rawpart.setChildVal` | +| `w:doNotBreakWrappedTables` | `rawpart.setChildVal` | +| `w:doNotDemarcateInvalidXml` | `settings.doNotDemarcateInvalidXml` | +| `w:doNotDisplayPageBoundaries` | `settings.doNotDisplayPageBoundaries` | +| `w:doNotEmbedSmartTags` | `settings.doNotEmbedSmartTags` | +| `w:doNotExpandShiftReturn` | `rawpart.setChildVal` | +| `w:doNotHyphenateCaps` | `settings.doNotHyphenateCaps` | +| `w:doNotIncludeSubdocsInStats` | `settings.doNotIncludeSubdocsInStats` | +| `w:doNotLeaveBackslashAlone` | `rawpart.setChildVal` | +| `w:doNotOrganizeInFolder` | `rawpart.setChildVal` | +| `w:doNotRelyOnCSS` | `rawpart.setChildVal` | +| `w:doNotSaveAsSingleFile` | `rawpart.setChildVal` | +| `w:doNotShadeFormData` | `settings.doNotShadeFormData` | +| `w:doNotSnapToGridInCell` | `rawpart.setChildVal` | +| `w:doNotSuppressBlankLines` | `rawpart.setChildVal` | +| `w:doNotSuppressIndentation` | `rawpart.setChildVal` | +| `w:doNotSuppressParagraphBorders` | `rawpart.setChildVal` | +| `w:doNotTrackFormatting` | `settings.doNotTrackFormatting` | +| `w:doNotTrackMoves` | `settings.doNotTrackMoves` | +| `w:doNotUseEastAsianBreakRules` | `rawpart.setChildVal` | +| `w:doNotUseHTMLParagraphAutoSpacing` | `rawpart.setChildVal` | +| `w:doNotUseIndentAsNumberingTabStop` | `rawpart.setChildVal` | +| `w:doNotUseLongFileNames` | `rawpart.setChildVal` | +| `w:doNotUseMarginsForDrawingGridOrigin` | `settings.doNotUseMarginsForDrawingGridOrigin` | +| `w:doNotValidateAgainstSchema` | `settings.doNotValidateAgainstSchema` | +| `w:doNotVertAlignCellWithSp` | `rawpart.setChildVal` | +| `w:doNotVertAlignInTxbx` | `rawpart.setChildVal` | +| `w:doNotWrapTextWithPunct` | `rawpart.setChildVal` | +| `w:drawing` | `image.insert` | +| `w:drawingGridHorizontalOrigin` | `settings.drawingGridHorizontalOrigin` | +| `w:drawingGridHorizontalSpacing` | `settings.drawingGridHorizontalSpacing` | +| `w:drawingGridVerticalOrigin` | `settings.drawingGridVerticalOrigin` | +| `w:drawingGridVerticalSpacing` | `settings.drawingGridVerticalSpacing` | +| `w:dropDownList` | `rawpart.setChildVal` | +| `w:dstrike` | `text.dstrike` | +| `w:dynamicAddress` | `rawpart.setChildVal` | +| `w:eastAsianLayout` | `rawpart.setChildVal` | +| `w:effect` | `text.effect` | +| `w:em` | `text.em` | +| `w:embedBold` | `rawpart.setChildVal` | +| `w:embedBoldItalic` | `rawpart.setChildVal` | +| `w:embedItalic` | `rawpart.setChildVal` | +| `w:embedRegular` | `rawpart.setChildVal` | +| `w:embedSystemFonts` | `settings.embedSystemFonts` | +| `w:embedTrueTypeFonts` | `settings.embedTrueTypeFonts` | +| `w:emboss` | `text.emboss` | +| `w:enabled` | `rawpart.setChildVal` | +| `w:encoding` | `rawpart.setChildVal` | +| `w:end` | `rawpart.setChildVal` | +| `w:endnote` | `references.endnote` | +| `w:endnotePr` | `rawpart.setChildVal` | +| `w:endnoteRef` | `rawpart.setChildVal` | +| `w:endnoteReference` | `references.endnote` | +| `w:endnotes` | `rawpart.setChildVal` | +| `w:entryMacro` | `rawpart.setChildVal` | +| `w:equation` | `rawpart.setChildVal` | +| `w:evenAndOddHeaders` | `settings.evenAndOddHeaders` | +| `w:exitMacro` | `rawpart.setChildVal` | +| `w:family` | `rawpart.setChildVal` | +| `w:ffData` | `rawpart.setChildVal` | +| `w:fHdr` | `rawpart.setChildVal` | +| `w:fieldMapData` | `rawpart.setChildVal` | +| `w:fitText` | `rawpart.setChildVal` | +| `w:flatBorders` | `rawpart.setChildVal` | +| `w:fldChar` | `references.field` | +| `w:fldData` | `rawpart.setChildVal` | +| `w:fldSimple` | `references.field` | +| `w:font` | `rawpart.setChildVal` | +| `w:fonts` | `rawpart.setChildVal` | +| `w:footerReference` | `headerFooter.addFooter` | +| `w:footnote` | `references.footnote` | +| `w:footnoteLayoutLikeWW8` | `rawpart.setChildVal` | +| `w:footnotePr` | `rawpart.setChildVal` | +| `w:footnoteRef` | `rawpart.setChildVal` | +| `w:footnoteReference` | `references.footnote` | +| `w:footnotes` | `rawpart.setChildVal` | +| `w:forceUpgrade` | `settings.forceUpgrade` | +| `w:forgetLastTabAlignment` | `rawpart.setChildVal` | +| `w:format` | `rawpart.setChildVal` | +| `w:formProt` | `section.formProt` | +| `w:formsDesign` | `settings.formsDesign` | +| `w:frame` | `rawpart.setChildVal` | +| `w:frameLayout` | `rawpart.setChildVal` | +| `w:framePr` | `rawpart.setChildVal` | +| `w:frameset` | `rawpart.setChildVal` | +| `w:framesetSplitbar` | `rawpart.setChildVal` | +| `w:ftr` | `headerFooter.addFooter` | +| `w:gallery` | `rawpart.setChildVal` | +| `w:glossaryDocument` | `rawpart.setChildVal` | +| `w:gridAfter` | `table.row_gridAfter` | +| `w:gridBefore` | `table.row_gridBefore` | +| `w:gridCol` | `table.insert` | +| `w:gridSpan` | `table.cell_gridSpan` | +| `w:group` | `rawpart.setChildVal` | +| `w:growAutofit` | `rawpart.setChildVal` | +| `w:guid` | `rawpart.setChildVal` | +| `w:gutterAtTop` | `settings.gutterAtTop` | +| `w:hdr` | `headerFooter.addHeader` | +| `w:hdrShapeDefaults` | `rawpart.setChildVal` | +| `w:header` | `rawpart.setChildVal` | +| `w:headerReference` | `headerFooter.addHeader` | +| `w:headers` | `rawpart.setChildVal` | +| `w:headerSource` | `rawpart.setChildVal` | +| `w:helpText` | `rawpart.setChildVal` | +| `w:hidden` | `table.row_hidden` | +| `w:hideGrammaticalErrors` | `settings.hideGrammaticalErrors` | +| `w:hideMark` | `table.cell_hideMark` | +| `w:hideSpellingErrors` | `settings.hideSpellingErrors` | +| `w:highlight` | `text.highlight` | +| `w:hMerge` | `table.cell_hMerge` | +| `w:hps` | `rawpart.setChildVal` | +| `w:hpsBaseText` | `rawpart.setChildVal` | +| `w:hpsRaise` | `rawpart.setChildVal` | +| `w:hyperlink` | `references.hyperlink` | +| `w:hyphenationZone` | `settings.hyphenationZone` | +| `w:i` | `text.italic` | +| `w:iCs` | `text.italic` | +| `w:id` | `rawpart.setChildVal` | +| `w:ignoreMixedContent` | `settings.ignoreMixedContent` | +| `w:ilvl` | `list.apply` | +| `w:imprint` | `text.imprint` | +| `w:ind` | `paragraph.indent` | +| `w:ins` | `review.acceptAll` | +| `w:insideH` | `rawpart.setChildVal` | +| `w:insideV` | `rawpart.setChildVal` | +| `w:instrText` | `references.field` | +| `w:isLgl` | `numbering.isLgl` | +| `w:jc` | `paragraph.alignLeft` | +| `w:keepLines` | `paragraph.keepLines` | +| `w:keepNext` | `paragraph.keepNext` | +| `w:kern` | `text.kern` | +| `w:kinsoku` | `paragraph.kinsoku` | +| `w:label` | `rawpart.setChildVal` | +| `w:lang` | `rawpart.setChildVal` | +| `w:latentStyles` | `rawpart.setChildVal` | +| `w:layoutRawTableWidth` | `rawpart.setChildVal` | +| `w:layoutTableRowsApart` | `rawpart.setChildVal` | +| `w:left` | `rawpart.setChildVal` | +| `w:legacy` | `rawpart.setChildVal` | +| `w:lid` | `rawpart.setChildVal` | +| `w:lineWrapLikeWord6` | `rawpart.setChildVal` | +| `w:link` | `style.add` | +| `w:linkedToFile` | `rawpart.setChildVal` | +| `w:linkStyles` | `settings.linkStyles` | +| `w:linkToQuery` | `rawpart.setChildVal` | +| `w:listEntry` | `rawpart.setChildVal` | +| `w:listItem` | `rawpart.setChildVal` | +| `w:listSeparator` | `settings.listSeparator` | +| `w:lnNumType` | `rawpart.setChildVal` | +| `w:lock` | `rawpart.setChildVal` | +| `w:locked` | `style.locked` | +| `w:longDesc` | `rawpart.setChildVal` | +| `w:lsdException` | `rawpart.setChildVal` | +| `w:lvl` | `list.apply` | +| `w:lvlJc` | `numbering.lvlJc` | +| `w:lvlOverride` | `rawpart.setChildVal` | +| `w:lvlPicBulletId` | `rawpart.setChildVal` | +| `w:lvlRestart` | `numbering.lvlRestart` | +| `w:lvlText` | `numbering.lvlText` | +| `w:mailAsAttachment` | `rawpart.setChildVal` | +| `w:mailMerge` | `rawpart.setChildVal` | +| `w:mailSubject` | `rawpart.setChildVal` | +| `w:mainDocumentType` | `rawpart.setChildVal` | +| `w:mappedName` | `rawpart.setChildVal` | +| `w:marBottom` | `rawpart.setChildVal` | +| `w:marH` | `rawpart.setChildVal` | +| `w:marLeft` | `rawpart.setChildVal` | +| `w:marRight` | `rawpart.setChildVal` | +| `w:marTop` | `rawpart.setChildVal` | +| `w:marW` | `rawpart.setChildVal` | +| `w:matchSrc` | `rawpart.setChildVal` | +| `w:maxLength` | `rawpart.setChildVal` | +| `w:mirrorIndents` | `paragraph.mirrorIndents` | +| `w:mirrorMargins` | `settings.mirrorMargins` | +| `w:monthLong` | `rawpart.setChildVal` | +| `w:monthShort` | `rawpart.setChildVal` | +| `w:moveFrom` | `rawpart.setChildVal` | +| `w:moveFromRangeEnd` | `rawpart.setChildVal` | +| `w:moveFromRangeStart` | `rawpart.setChildVal` | +| `w:moveTo` | `rawpart.setChildVal` | +| `w:moveToRangeEnd` | `rawpart.setChildVal` | +| `w:moveToRangeStart` | `rawpart.setChildVal` | +| `w:movie` | `rawpart.setChildVal` | +| `w:multiLevelType` | `rawpart.setChildVal` | +| `w:mwSmallCaps` | `rawpart.setChildVal` | +| `w:name` | `style.name` | +| `w:next` | `style.add` | +| `w:noBorder` | `rawpart.setChildVal` | +| `w:noColumnBalance` | `rawpart.setChildVal` | +| `w:noEndnote` | `section.noEndnote` | +| `w:noExtraLineSpacing` | `rawpart.setChildVal` | +| `w:noLeading` | `rawpart.setChildVal` | +| `w:noLineBreaksAfter` | `rawpart.setChildVal` | +| `w:noLineBreaksBefore` | `rawpart.setChildVal` | +| `w:noProof` | `text.noProof` | +| `w:noPunctuationKerning` | `settings.noPunctuationKerning` | +| `w:noResizeAllowed` | `rawpart.setChildVal` | +| `w:noSpaceRaiseLower` | `rawpart.setChildVal` | +| `w:noTabHangInd` | `rawpart.setChildVal` | +| `w:notTrueType` | `rawpart.setChildVal` | +| `w:noWrap` | `table.cell_noWrap` | +| `w:nsid` | `rawpart.setChildVal` | +| `w:num` | `list.apply` | +| `w:numbering` | `list.apply` | +| `w:numberingChange` | `rawpart.setChildVal` | +| `w:numFmt` | `numbering.numFmt` | +| `w:numId` | `list.apply` | +| `w:numIdMacAtCleanup` | `rawpart.setChildVal` | +| `w:numPicBullet` | `rawpart.setChildVal` | +| `w:numPr` | `list.apply` | +| `w:numRestart` | `rawpart.setChildVal` | +| `w:numStart` | `rawpart.setChildVal` | +| `w:numStyleLink` | `rawpart.setChildVal` | +| `w:object` | `rawpart.setChildVal` | +| `w:objectEmbed` | `rawpart.setChildVal` | +| `w:objectLink` | `rawpart.setChildVal` | +| `w:odso` | `rawpart.setChildVal` | +| `w:oMath` | `text.oMath` | +| `w:optimizeForBrowser` | `rawpart.setChildVal` | +| `w:outline` | `text.outline` | +| `w:outlineLvl` | `paragraph.outlineLvl` | +| `w:overflowPunct` | `paragraph.overflowPunct` | +| `w:p` | `structure.insertParagraph` | +| `w:pageBreakBefore` | `paragraph.pageBreakBefore` | +| `w:panose1` | `rawpart.setChildVal` | +| `w:paperSrc` | `rawpart.setChildVal` | +| `w:pBdr` | `paragraph.borders` | +| `w:permEnd` | `rawpart.setChildVal` | +| `w:permStart` | `rawpart.setChildVal` | +| `w:personal` | `style.personal` | +| `w:personalCompose` | `style.personalCompose` | +| `w:personalReply` | `style.personalReply` | +| `w:pgBorders` | `rawpart.setChildVal` | +| `w:pgMar` | `section.pageMargins` | +| `w:pgNum` | `rawpart.setChildVal` | +| `w:pgNumType` | `rawpart.setChildVal` | +| `w:pgSz` | `section.pageSize` | +| `w:pict` | `rawpart.setChildVal` | +| `w:picture` | `rawpart.setChildVal` | +| `w:pitch` | `rawpart.setChildVal` | +| `w:pixelsPerInch` | `rawpart.setChildVal` | +| `w:placeholder` | `rawpart.setChildVal` | +| `w:pos` | `rawpart.setChildVal` | +| `w:position` | `text.position` | +| `w:pPr` | `paragraph.align` | +| `w:pPrChange` | `review.acceptAll` | +| `w:pPrDefault` | `style.ensureHeadings` | +| `w:printBodyTextBeforeHeader` | `rawpart.setChildVal` | +| `w:printColBlack` | `rawpart.setChildVal` | +| `w:printerSettings` | `rawpart.setChildVal` | +| `w:printFormsData` | `settings.printFormsData` | +| `w:printFractionalCharacterWidth` | `settings.printFractionalCharacterWidth` | +| `w:printPostScriptOverText` | `settings.printPostScriptOverText` | +| `w:printTwoOnOne` | `settings.printTwoOnOne` | +| `w:proofErr` | `rawpart.setChildVal` | +| `w:proofState` | `rawpart.setChildVal` | +| `w:pStyle` | `paragraph.style` | +| `w:ptab` | `rawpart.setChildVal` | +| `w:qFormat` | `style.qFormat` | +| `w:query` | `rawpart.setChildVal` | +| `w:r` | `structure.insertParagraph` | +| `w:readModeInkLockDown` | `rawpart.setChildVal` | +| `w:recipientData` | `rawpart.setChildVal` | +| `w:recipients` | `rawpart.setChildVal` | +| `w:relyOnVML` | `rawpart.setChildVal` | +| `w:removeDateAndTime` | `settings.removeDateAndTime` | +| `w:removePersonalInformation` | `settings.removePersonalInformation` | +| `w:result` | `rawpart.setChildVal` | +| `w:revisionView` | `rawpart.setChildVal` | +| `w:rFonts` | `text.font` | +| `w:richText` | `rawpart.setChildVal` | +| `w:right` | `rawpart.setChildVal` | +| `w:rPr` | `text.bold` | +| `w:rPrChange` | `review.acceptAll` | +| `w:rPrDefault` | `style.ensureHeadings` | +| `w:rsid` | `style.rsid` | +| `w:rsidRoot` | `rawpart.setChildVal` | +| `w:rsids` | `rawpart.setChildVal` | +| `w:rStyle` | `text.rStyle` | +| `w:rt` | `rawpart.setChildVal` | +| `w:rtl` | `text.rtl` | +| `w:rtlGutter` | `section.rtlGutter` | +| `w:ruby` | `rawpart.setChildVal` | +| `w:rubyAlign` | `rawpart.setChildVal` | +| `w:rubyBase` | `rawpart.setChildVal` | +| `w:rubyPr` | `rawpart.setChildVal` | +| `w:saveFormsData` | `settings.saveFormsData` | +| `w:saveInvalidXml` | `settings.saveInvalidXml` | +| `w:savePreviewPicture` | `settings.savePreviewPicture` | +| `w:saveSmartTagsAsXml` | `rawpart.setChildVal` | +| `w:saveSubsetFonts` | `settings.saveSubsetFonts` | +| `w:saveThroughXslt` | `rawpart.setChildVal` | +| `w:saveXmlDataOnly` | `settings.saveXmlDataOnly` | +| `w:scrollbar` | `rawpart.setChildVal` | +| `w:sdt` | `rawpart.setChildVal` | +| `w:sdtContent` | `rawpart.setChildVal` | +| `w:sdtEndPr` | `rawpart.setChildVal` | +| `w:sdtPr` | `rawpart.setChildVal` | +| `w:sectPr` | `section.break` | +| `w:sectPrChange` | `rawpart.setChildVal` | +| `w:selectFldWithFirstOrLastChar` | `rawpart.setChildVal` | +| `w:semiHidden` | `style.semiHidden` | +| `w:separator` | `rawpart.setChildVal` | +| `w:settings` | `rawpart.setChildVal` | +| `w:shadow` | `text.shadow` | +| `w:shapeDefaults` | `rawpart.setChildVal` | +| `w:shapeLayoutLikeWW8` | `rawpart.setChildVal` | +| `w:shd` | `paragraph.shading` | +| `w:showBreaksInFrames` | `rawpart.setChildVal` | +| `w:showEnvelope` | `settings.showEnvelope` | +| `w:showingPlcHdr` | `rawpart.setChildVal` | +| `w:showXMLTags` | `settings.showXMLTags` | +| `w:sig` | `rawpart.setChildVal` | +| `w:size` | `rawpart.setChildVal` | +| `w:sizeAuto` | `rawpart.setChildVal` | +| `w:smallCaps` | `text.smallCaps` | +| `w:smartTag` | `rawpart.setChildVal` | +| `w:smartTagPr` | `rawpart.setChildVal` | +| `w:smartTagType` | `rawpart.setChildVal` | +| `w:snapToGrid` | `text.snapToGrid` | +| `w:sourceFileName` | `rawpart.setChildVal` | +| `w:spaceForUL` | `rawpart.setChildVal` | +| `w:spacing` | `paragraph.spacing` | +| `w:spacingInWholePoints` | `rawpart.setChildVal` | +| `w:specVanish` | `text.specVanish` | +| `w:splitPgBreakAndParaMark` | `rawpart.setChildVal` | +| `w:src` | `rawpart.setChildVal` | +| `w:start` | `numbering.start` | +| `w:startOverride` | `rawpart.setChildVal` | +| `w:statusText` | `rawpart.setChildVal` | +| `w:storeMappedDataAs` | `rawpart.setChildVal` | +| `w:strictFirstAndLastChars` | `settings.strictFirstAndLastChars` | +| `w:strike` | `text.strike` | +| `w:style` | `style.add` | +| `w:styleLink` | `rawpart.setChildVal` | +| `w:styleLockQFSet` | `settings.styleLockQFSet` | +| `w:styleLockTheme` | `settings.styleLockTheme` | +| `w:stylePaneFormatFilter` | `rawpart.setChildVal` | +| `w:stylePaneSortMethod` | `rawpart.setChildVal` | +| `w:styles` | `style.add` | +| `w:subDoc` | `rawpart.setChildVal` | +| `w:subFontBySize` | `rawpart.setChildVal` | +| `w:suff` | `numbering.suff` | +| `w:summaryLength` | `settings.summaryLength` | +| `w:suppressAutoHyphens` | `paragraph.suppressAutoHyphens` | +| `w:suppressBottomSpacing` | `rawpart.setChildVal` | +| `w:suppressLineNumbers` | `paragraph.suppressLineNumbers` | +| `w:suppressOverlap` | `paragraph.suppressOverlap` | +| `w:suppressSpacingAtTopOfPage` | `rawpart.setChildVal` | +| `w:suppressSpBfAfterPgBrk` | `rawpart.setChildVal` | +| `w:suppressTopSpacing` | `rawpart.setChildVal` | +| `w:suppressTopSpacingWP` | `rawpart.setChildVal` | +| `w:swapBordersFacingPages` | `rawpart.setChildVal` | +| `w:sz` | `text.fontSize` | +| `w:szCs` | `text.fontSize` | +| `w:t` | `structure.insertParagraph` | +| `w:tabIndex` | `rawpart.setChildVal` | +| `w:table` | `rawpart.setChildVal` | +| `w:tabs` | `rawpart.setChildVal` | +| `w:tag` | `rawpart.setChildVal` | +| `w:targetScreenSz` | `rawpart.setChildVal` | +| `w:tbl` | `table.insert` | +| `w:tblBorders` | `table.borders` | +| `w:tblCaption` | `table.tbl_tblCaption` | +| `w:tblCellMar` | `rawpart.setChildVal` | +| `w:tblCellSpacing` | `rawpart.setChildVal` | +| `w:tblDescription` | `table.tbl_tblDescription` | +| `w:tblGrid` | `table.insert` | +| `w:tblGridChange` | `rawpart.setChildVal` | +| `w:tblHeader` | `table.rowHeader` | +| `w:tblInd` | `rawpart.setChildVal` | +| `w:tblLayout` | `table.tbl_tblLayout` | +| `w:tblLook` | `rawpart.setChildVal` | +| `w:tblOverlap` | `rawpart.setChildVal` | +| `w:tblpPr` | `rawpart.setChildVal` | +| `w:tblPr` | `table.borders` | +| `w:tblPrChange` | `rawpart.setChildVal` | +| `w:tblPrEx` | `rawpart.setChildVal` | +| `w:tblPrExChange` | `rawpart.setChildVal` | +| `w:tblStyle` | `table.tbl_tblStyle` | +| `w:tblStyleColBandSize` | `rawpart.setChildVal` | +| `w:tblStylePr` | `rawpart.setChildVal` | +| `w:tblStyleRowBandSize` | `rawpart.setChildVal` | +| `w:tblW` | `rawpart.setChildVal` | +| `w:tc` | `table.insert` | +| `w:tcBorders` | `table.borders` | +| `w:tcFitText` | `rawpart.setChildVal` | +| `w:tcMar` | `rawpart.setChildVal` | +| `w:tcPr` | `table.cellShading` | +| `w:tcPrChange` | `rawpart.setChildVal` | +| `w:tcW` | `table.insert` | +| `w:temporary` | `rawpart.setChildVal` | +| `w:text` | `rawpart.setChildVal` | +| `w:textAlignment` | `paragraph.textAlignment` | +| `w:textboxTightWrap` | `rawpart.setChildVal` | +| `w:textDirection` | `paragraph.textDirection` | +| `w:textInput` | `rawpart.setChildVal` | +| `w:themeFontLang` | `rawpart.setChildVal` | +| `w:title` | `rawpart.setChildVal` | +| `w:titlePg` | `section.titlePg` | +| `w:tl2br` | `rawpart.setChildVal` | +| `w:tmpl` | `rawpart.setChildVal` | +| `w:top` | `rawpart.setChildVal` | +| `w:topLinePunct` | `paragraph.topLinePunct` | +| `w:tr` | `table.addRow` | +| `w:tr2bl` | `rawpart.setChildVal` | +| `w:trackRevisions` | `settings.trackRevisions` | +| `w:trHeight` | `table.rowHeight` | +| `w:trPr` | `table.rowHeight` | +| `w:trPrChange` | `rawpart.setChildVal` | +| `w:truncateFontHeightsLikeWP6` | `rawpart.setChildVal` | +| `w:txbxContent` | `rawpart.setChildVal` | +| `w:type` | `rawpart.setChildVal` | +| `w:types` | `rawpart.setChildVal` | +| `w:u` | `text.underline` | +| `w:udl` | `rawpart.setChildVal` | +| `w:uiPriority` | `style.uiPriority` | +| `w:ulTrailSpace` | `rawpart.setChildVal` | +| `w:underlineTabInNumList` | `rawpart.setChildVal` | +| `w:unhideWhenUsed` | `style.unhideWhenUsed` | +| `w:uniqueTag` | `rawpart.setChildVal` | +| `w:updateFields` | `settings.updateFields` | +| `w:useAltKinsokuLineBreakRules` | `rawpart.setChildVal` | +| `w:useAnsiKerningPairs` | `rawpart.setChildVal` | +| `w:useFELayout` | `rawpart.setChildVal` | +| `w:useNormalStyleForList` | `rawpart.setChildVal` | +| `w:usePrinterMetrics` | `rawpart.setChildVal` | +| `w:useSingleBorderforContiguousCells` | `rawpart.setChildVal` | +| `w:useWord2002TableStyleRules` | `rawpart.setChildVal` | +| `w:useWord97LineBreakRules` | `rawpart.setChildVal` | +| `w:useXSLTWhenSaving` | `settings.useXSLTWhenSaving` | +| `w:vAlign` | `table.cellVAlign` | +| `w:vanish` | `text.vanish` | +| `w:vertAlign` | `text.vertAlign` | +| `w:view` | `rawpart.setChildVal` | +| `w:viewMergedData` | `rawpart.setChildVal` | +| `w:vMerge` | `table.cell_vMerge` | +| `w:w` | `text.w` | +| `w:wAfter` | `rawpart.setChildVal` | +| `w:wBefore` | `rawpart.setChildVal` | +| `w:webHidden` | `text.webHidden` | +| `w:webSettings` | `rawpart.setChildVal` | +| `w:widowControl` | `paragraph.widowControl` | +| `w:wordWrap` | `paragraph.wordWrap` | +| `w:wpJustification` | `rawpart.setChildVal` | +| `w:wpSpaceWidth` | `rawpart.setChildVal` | +| `w:wrapTrailSpaces` | `rawpart.setChildVal` | +| `w:writeProtection` | `rawpart.setChildVal` | +| `w:yearLong` | `rawpart.setChildVal` | +| `w:yearShort` | `rawpart.setChildVal` | +| `w:zoom` | `rawpart.setChildVal` | +| `wp:align` | `raw.setChildVal` | +| `wp:anchor` | `image.insert` | +| `wp:bg` | `raw.setChildVal` | +| `wp:bodyPr` | `raw.setChildVal` | +| `wp:cNvCnPr` | `raw.setChildVal` | +| `wp:cNvContentPartPr` | `raw.setChildVal` | +| `wp:cNvFrPr` | `raw.setChildVal` | +| `wp:cNvGraphicFramePr` | `raw.setChildVal` | +| `wp:cNvGrpSpPr` | `raw.setChildVal` | +| `wp:cNvPr` | `raw.setChildVal` | +| `wp:cNvSpPr` | `raw.setChildVal` | +| `wp:contentPart` | `raw.setChildVal` | +| `wp:docPr` | `image.altText` | +| `wp:effectExtent` | `raw.setChildVal` | +| `wp:extent` | `image.resize` | +| `wp:extLst` | `raw.setChildVal` | +| `wp:graphicFrame` | `raw.setChildVal` | +| `wp:grpSp` | `raw.setChildVal` | +| `wp:grpSpPr` | `raw.setChildVal` | +| `wp:inline` | `image.insert` | +| `wp:lineTo` | `raw.setChildVal` | +| `wp:linkedTxbx` | `raw.setChildVal` | +| `wp:nvContentPartPr` | `raw.setChildVal` | +| `wp:positionH` | `raw.setChildVal` | +| `wp:positionV` | `raw.setChildVal` | +| `wp:posOffset` | `raw.setChildVal` | +| `wp:simplePos` | `raw.setChildVal` | +| `wp:spPr` | `raw.setChildVal` | +| `wp:start` | `raw.setChildVal` | +| `wp:style` | `raw.setChildVal` | +| `wp:txbx` | `raw.setChildVal` | +| `wp:txbxContent` | `raw.setChildVal` | +| `wp:wgp` | `raw.setChildVal` | +| `wp:whole` | `raw.setChildVal` | +| `wp:wpc` | `raw.setChildVal` | +| `wp:wrapNone` | `raw.setChildVal` | +| `wp:wrapPolygon` | `raw.setChildVal` | +| `wp:wrapSquare` | `raw.setChildVal` | +| `wp:wrapThrough` | `raw.setChildVal` | +| `wp:wrapTight` | `raw.setChildVal` | +| `wp:wrapTopAndBottom` | `raw.setChildVal` | +| `wp:wsp` | `raw.setChildVal` | +| `wp:xfrm` | `raw.setChildVal` | +| `wvml:anchorlock` | `raw.setChildVal` | +| `wvml:borderbottom` | `raw.setChildVal` | +| `wvml:borderleft` | `raw.setChildVal` | +| `wvml:borderright` | `raw.setChildVal` | +| `wvml:bordertop` | `raw.setChildVal` | +| `wvml:wrap` | `raw.setChildVal` | diff --git a/packages/editor/README.md b/packages/editor/README.md new file mode 100644 index 0000000..5ba6508 --- /dev/null +++ b/packages/editor/README.md @@ -0,0 +1,52 @@ +# @office-kit/docx-editor + +An MS Office-like WYSIWYG editing core for [`@office-kit/docx`](https://github.com/office-kit/docx) +`.docx` documents. Framework-agnostic; a Svelte/SvelteKit UI lives in the +monorepo's `site/` (`/editor` route). + +## Design + +The editor never serializes OOXML itself. Every mutation runs through a +**command** that calls the `@office-kit/docx` public API, so that library stays +the single source of truth for the document. Open a `.docx`, drive commands from +a ribbon or keyboard, and save a real, valid `.docx` back. + +```ts +import { openEditor, runCommand, commands, renderDocumentHtml } from "@office-kit/docx-editor"; +import { toUint8Array } from "@office-kit/docx"; + +const model = openEditor(bytes); // EditorModel over a live Docx +model.setSelection({ anchor: { block: 0 }, focus: { block: 0 } }); +runCommand(model, commands.toggleBoldCommand, undefined); +container.innerHTML = renderDocumentHtml(model.doc); +const out = toUint8Array(model.doc); // a valid .docx +``` + +## The completeness guarantee + +"Cover every docx representation" is a _checkable_ claim here, not an aspiration. +Every element in the ECMA-376 schema universe (extracted into +`src/capability/element-universe.json`) is classified in the capability ledger +(`src/capability/ledger.ts`) into exactly one disposition: + +- **`edit`** — a real command creates/modifies it (the command id is recorded). +- **`render`** — the canvas shows it faithfully, read-only. +- **`preserve`** — round-tripped losslessly by `@office-kit/docx` (raw XML + pass-through), not yet surfaced in the UI. + +`src/capability/coverage.test.ts` fails the build if any element is unclassified, +or if an `edit` element points at a command that no longer exists. The live +scoreboard is regenerated into [`COVERAGE.md`](./COVERAGE.md). Nothing can +silently fall through: an element is either editable, rendered, or explicitly +preserved with the round-trip test that proves it. + +Regenerate the universe from the schemas with: + +```sh +node scripts/extract-ooxml-elements.mjs +``` + +## Command groups + +`text`, `paragraph`, `structure`, `list`, `table`, `image`, `style`, `section`, +`headerFooter`, `references`, `review`. See `ALL_COMMANDS` for the full list. diff --git a/packages/editor/package.json b/packages/editor/package.json new file mode 100644 index 0000000..8e3a0c2 --- /dev/null +++ b/packages/editor/package.json @@ -0,0 +1,52 @@ +{ + "name": "@office-kit/docx-editor", + "version": "0.0.0", + "description": "MS Office-like WYSIWYG editing core for word-kit .docx documents. Framework-agnostic; every edit routes through @office-kit/docx.", + "keywords": [ + "docx", + "editor", + "ooxml", + "word", + "wordprocessingml", + "wysiwyg" + ], + "homepage": "https://github.com/office-kit/docx#readme", + "bugs": { + "url": "https://github.com/office-kit/docx/issues" + }, + "license": "MIT", + "author": "Yuichiro Yamashita", + "repository": { + "type": "git", + "url": "git+https://github.com/office-kit/docx.git", + "directory": "packages/editor" + }, + "files": [ + "dist", + "README.md", + "LICENSE" + ], + "type": "module", + "sideEffects": false, + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs" + } + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsdown", + "typecheck": "tsc -p tsconfig.json" + }, + "dependencies": { + "@office-kit/docx": "workspace:*" + }, + "engines": { + "node": ">=20" + } +} diff --git a/packages/editor/src/capability/coverage.test.ts b/packages/editor/src/capability/coverage.test.ts new file mode 100644 index 0000000..41d52f8 --- /dev/null +++ b/packages/editor/src/capability/coverage.test.ts @@ -0,0 +1,81 @@ +/** + * The completeness-guarantee test. + * + * This is the enforcement half of the capability ledger: it fails the build if + * any WordprocessingML element slips through unclassified, if an `edit` element + * points at a command that no longer exists, or if the element universe drifts + * from the committed snapshot without being regenerated. It also (re)writes + * COVERAGE.md so the scoreboard stays current. + */ + +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; +import { COMMAND_IDS } from "../commands/registry.js"; +import universe from "./element-universe.json" with { type: "json" }; +import { classify, coverageSummary, LEDGER } from "./ledger.js"; + +const here = dirname(fileURLToPath(import.meta.url)); + +interface UniverseElement { + element: string; + name: string; + prefix: string; + domain: string; +} +const ELEMENTS = (universe as { elements: UniverseElement[]; totalElements: number }).elements; + +describe("capability ledger completeness", () => { + it("classifies every element in the schema universe", () => { + const missing: string[] = []; + for (const e of ELEMENTS) { + const cap = classify(e.element, e.domain); + if (cap.notes?.startsWith("UNCLASSIFIED")) missing.push(e.element); + } + expect(missing, `unclassified elements:\n${missing.join("\n")}`).toEqual([]); + }); + + it("has zero unclassified elements in the summary", () => { + expect(coverageSummary().unclassified).toBe(0); + }); + + it("covers exactly the committed universe (snapshot not drifted)", () => { + expect(LEDGER.length).toBe(ELEMENTS.length); + expect(LEDGER.length).toBe((universe as { totalElements: number }).totalElements); + }); + + it("every `edit` element names a command that exists in the registry", () => { + const s = coverageSummary(); + expect( + s.danglingCommands, + `edit elements referencing missing commands:\n${s.danglingCommands.join("\n")}`, + ).toEqual([]); + }); + + it("every command id referenced by the ledger is unique-resolvable", () => { + for (const cap of LEDGER) { + if (cap.disposition === "edit" && cap.command) { + expect(COMMAND_IDS.has(cap.command)).toBe(true); + } + } + }); + + it("has meaningful edit coverage of the WordprocessingML core", () => { + // Guardrail: the wml domain must retain a real editable surface so a + // regression that silently strips commands is caught. + const wml = coverageSummary().byDomain.wml; + expect(wml).toBeDefined(); + expect(wml!.edit).toBeGreaterThanOrEqual(50); + }); + + it("writes COVERAGE.md", async () => { + const { renderCoverageMarkdown } = await import("./report.js"); + const md = renderCoverageMarkdown(); + const out = join(here, "..", "..", "COVERAGE.md"); + // Only rewrite when changed to keep the file stable in git diffs. + const prev = existsSync(out) ? readFileSync(out, "utf8") : ""; + if (prev !== md) writeFileSync(out, md); + expect(md).toContain("# Editor capability coverage"); + }); +}); diff --git a/packages/editor/src/capability/element-universe.json b/packages/editor/src/capability/element-universe.json new file mode 100644 index 0000000..021cc14 --- /dev/null +++ b/packages/editor/src/capability/element-universe.json @@ -0,0 +1,14623 @@ +{ + "generatedFrom": "ECMA-376 XSD (references/python-docx/ref/xsd)", + "schemaFiles": [ + "wml.xsd", + "dml-wordprocessingDrawing.xsd", + "dml-picture.xsd", + "dml-main.xsd", + "shared-math.xsd", + "vml-main.xsd", + "vml-officeDrawing.xsd", + "vml-wordprocessingDrawing.xsd", + "shared-documentPropertiesCore.xsd", + "shared-documentPropertiesExtended.xsd", + "shared-documentPropertiesCustom.xsd" + ], + "totalElements": 1198, + "byDomain": { + "drawing": 370, + "docprops": 30, + "math": 124, + "vml": 61, + "wml": 613 + }, + "elements": [ + { + "element": "a:accent1", + "name": "accent1", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:accent2", + "name": "accent2", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:accent3", + "name": "accent3", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:accent4", + "name": "accent4", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:accent5", + "name": "accent5", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:accent6", + "name": "accent6", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:ahLst", + "name": "ahLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_CustomGeometry2D" + ], + "types": [ + "CT_AdjustHandleList" + ] + }, + { + "element": "a:ahPolar", + "name": "ahPolar", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AdjustHandleList" + ], + "types": [ + "CT_PolarAdjustHandle" + ] + }, + { + "element": "a:ahXY", + "name": "ahXY", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AdjustHandleList" + ], + "types": [ + "CT_XYAdjustHandle" + ] + }, + { + "element": "a:alpha", + "name": "alpha", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_PositiveFixedPercentage" + ] + }, + { + "element": "a:alphaBiLevel", + "name": "alphaBiLevel", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_AlphaBiLevelEffect" + ] + }, + { + "element": "a:alphaCeiling", + "name": "alphaCeiling", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_AlphaCeilingEffect" + ] + }, + { + "element": "a:alphaFloor", + "name": "alphaFloor", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_AlphaFloorEffect" + ] + }, + { + "element": "a:alphaInv", + "name": "alphaInv", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_AlphaInverseEffect" + ] + }, + { + "element": "a:alphaMod", + "name": "alphaMod", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform", + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_PositivePercentage", + "CT_AlphaModulateEffect" + ] + }, + { + "element": "a:alphaModFix", + "name": "alphaModFix", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_AlphaModulateFixedEffect" + ] + }, + { + "element": "a:alphaOff", + "name": "alphaOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_FixedPercentage" + ] + }, + { + "element": "a:alphaOutset", + "name": "alphaOutset", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties" + ], + "types": [ + "CT_AlphaOutsetEffect" + ] + }, + { + "element": "a:alphaRepl", + "name": "alphaRepl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_AlphaReplaceEffect" + ] + }, + { + "element": "a:anchor", + "name": "anchor", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Backdrop" + ], + "types": [ + "CT_Point3D" + ] + }, + { + "element": "a:arcTo", + "name": "arcTo", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2D" + ], + "types": [ + "CT_Path2DArcTo" + ] + }, + { + "element": "a:audioCd", + "name": "audioCd", + "prefix": "a", + "domain": "drawing", + "definedIn": [], + "types": [ + "CT_AudioCD" + ] + }, + { + "element": "a:audioFile", + "name": "audioFile", + "prefix": "a", + "domain": "drawing", + "definedIn": [], + "types": [ + "CT_AudioFile" + ] + }, + { + "element": "a:avLst", + "name": "avLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_PresetGeometry2D", + "CT_PresetTextShape", + "CT_CustomGeometry2D" + ], + "types": [ + "CT_GeomGuideList" + ] + }, + { + "element": "a:backdrop", + "name": "backdrop", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Scene3D" + ], + "types": [ + "CT_Backdrop" + ] + }, + { + "element": "a:band1H", + "name": "band1H", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:band1V", + "name": "band1V", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:band2H", + "name": "band2H", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:band2V", + "name": "band2V", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:bevel", + "name": "bevel", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineJoinRound", + "CT_Cell3D" + ], + "types": [ + "CT_LineJoinBevel", + "CT_Bevel" + ] + }, + { + "element": "a:bevelB", + "name": "bevelB", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Shape3D" + ], + "types": [ + "CT_Bevel" + ] + }, + { + "element": "a:bevelT", + "name": "bevelT", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Shape3D" + ], + "types": [ + "CT_Bevel" + ] + }, + { + "element": "a:bgClr", + "name": "bgClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_PatternFillProperties" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:bgFillStyleLst", + "name": "bgFillStyleLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_StyleMatrix" + ], + "types": [ + "CT_BackgroundFillStyleList" + ] + }, + { + "element": "a:biLevel", + "name": "biLevel", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_BiLevelEffect" + ] + }, + { + "element": "a:bldChart", + "name": "bldChart", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AnimationGraphicalObjectBuildProperties" + ], + "types": [ + "CT_AnimationChartBuildProperties" + ] + }, + { + "element": "a:bldDgm", + "name": "bldDgm", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AnimationGraphicalObjectBuildProperties" + ], + "types": [ + "CT_AnimationDgmBuildProperties" + ] + }, + { + "element": "a:blend", + "name": "blend", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties" + ], + "types": [ + "CT_BlendEffect" + ] + }, + { + "element": "a:blip", + "name": "blip", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_BlipFillProperties", + "CT_GroupFillProperties", + "CT_TextBlipBullet" + ], + "types": [ + "CT_Blip" + ] + }, + { + "element": "a:blipFill", + "name": "blipFill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlPicture", + "CT_GroupFillProperties" + ], + "types": [ + "CT_BlipFillProperties" + ] + }, + { + "element": "a:blue", + "name": "blue", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:blueMod", + "name": "blueMod", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:blueOff", + "name": "blueOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:blur", + "name": "blur", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_BlurEffect" + ] + }, + { + "element": "a:bodyPr", + "name": "bodyPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_DefaultShapeDefinition", + "CT_TextBody" + ], + "types": [ + "CT_TextBodyProperties" + ] + }, + { + "element": "a:bottom", + "name": "bottom", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:br", + "name": "br", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextUnderlineFillFollowText" + ], + "types": [ + "CT_TextLineBreak" + ] + }, + { + "element": "a:buAutoNum", + "name": "buAutoNum", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextNoBullet" + ], + "types": [ + "CT_TextAutonumberBullet" + ] + }, + { + "element": "a:buBlip", + "name": "buBlip", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextNoBullet" + ], + "types": [ + "CT_TextBlipBullet" + ] + }, + { + "element": "a:buChar", + "name": "buChar", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextNoBullet" + ], + "types": [ + "CT_TextCharBullet" + ] + }, + { + "element": "a:buClr", + "name": "buClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBulletColorFollowText" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:buClrTx", + "name": "buClrTx", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBulletColorFollowText" + ], + "types": [ + "CT_TextBulletColorFollowText" + ] + }, + { + "element": "a:buFont", + "name": "buFont", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBulletTypefaceFollowText" + ], + "types": [ + "CT_TextFont" + ] + }, + { + "element": "a:buFontTx", + "name": "buFontTx", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBulletTypefaceFollowText" + ], + "types": [ + "CT_TextBulletTypefaceFollowText" + ] + }, + { + "element": "a:buNone", + "name": "buNone", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextNoBullet" + ], + "types": [ + "CT_TextNoBullet" + ] + }, + { + "element": "a:buSzPct", + "name": "buSzPct", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBulletSizeFollowText" + ], + "types": [ + "CT_TextBulletSizePercent" + ] + }, + { + "element": "a:buSzPts", + "name": "buSzPts", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBulletSizeFollowText" + ], + "types": [ + "CT_TextBulletSizePoint" + ] + }, + { + "element": "a:buSzTx", + "name": "buSzTx", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBulletSizeFollowText" + ], + "types": [ + "CT_TextBulletSizeFollowText" + ] + }, + { + "element": "a:camera", + "name": "camera", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Scene3D" + ], + "types": [ + "CT_Camera" + ] + }, + { + "element": "a:cell3D", + "name": "cell3D", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties", + "CT_TableStyleCellStyle" + ], + "types": [ + "CT_Cell3D" + ] + }, + { + "element": "a:chart", + "name": "chart", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AnimationElementChoice" + ], + "types": [ + "CT_AnimationChartElement" + ] + }, + { + "element": "a:chExt", + "name": "chExt", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupTransform2D" + ], + "types": [ + "CT_PositiveSize2D" + ] + }, + { + "element": "a:chOff", + "name": "chOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupTransform2D" + ], + "types": [ + "CT_Point2D" + ] + }, + { + "element": "a:close", + "name": "close", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2D" + ], + "types": [ + "CT_Path2DClose" + ] + }, + { + "element": "a:clrChange", + "name": "clrChange", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_ColorChangeEffect" + ] + }, + { + "element": "a:clrFrom", + "name": "clrFrom", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorChangeEffect" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:clrMap", + "name": "clrMap", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorSchemeAndMapping", + "CT_ClipboardStyleSheet" + ], + "types": [ + "CT_ColorMapping" + ] + }, + { + "element": "a:clrRepl", + "name": "clrRepl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_ColorReplaceEffect" + ] + }, + { + "element": "a:clrScheme", + "name": "clrScheme", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_BaseStyles", + "CT_ColorSchemeAndMapping", + "CT_BaseStylesOverride" + ], + "types": [ + "CT_ColorScheme" + ] + }, + { + "element": "a:clrTo", + "name": "clrTo", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorChangeEffect" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:cNvCxnSpPr", + "name": "cNvCxnSpPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlConnectorNonVisual" + ], + "types": [ + "CT_NonVisualConnectorProperties" + ] + }, + { + "element": "a:cNvGraphicFramePr", + "name": "cNvGraphicFramePr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGraphicFrameNonVisual" + ], + "types": [ + "CT_NonVisualGraphicFrameProperties" + ] + }, + { + "element": "a:cNvGrpSpPr", + "name": "cNvGrpSpPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShapeNonVisual" + ], + "types": [ + "CT_NonVisualGroupDrawingShapeProps" + ] + }, + { + "element": "a:cNvPicPr", + "name": "cNvPicPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlPictureNonVisual" + ], + "types": [ + "CT_NonVisualPictureProperties" + ] + }, + { + "element": "a:cNvPr", + "name": "cNvPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlShapeNonVisual", + "CT_GvmlConnectorNonVisual", + "CT_GvmlPictureNonVisual", + "CT_GvmlGraphicFrameNonVisual", + "CT_GvmlGroupShapeNonVisual" + ], + "types": [ + "CT_NonVisualDrawingProps" + ] + }, + { + "element": "a:cNvSpPr", + "name": "cNvSpPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlShapeNonVisual" + ], + "types": [ + "CT_NonVisualDrawingShapeProps" + ] + }, + { + "element": "a:comp", + "name": "comp", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_ComplementTransform" + ] + }, + { + "element": "a:cont", + "name": "cont", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_AlphaModulateEffect", + "CT_BlendEffect" + ], + "types": [ + "CT_EffectContainer" + ] + }, + { + "element": "a:contourClr", + "name": "contourClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Shape3D" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:cpLocks", + "name": "cpLocks", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualContentPartProperties" + ], + "types": [ + "CT_ContentPartLocking" + ] + }, + { + "element": "a:cs", + "name": "cs", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_FontCollection", + "CT_TextCharacterProperties" + ], + "types": [ + "CT_TextFont" + ] + }, + { + "element": "a:cubicBezTo", + "name": "cubicBezTo", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2D" + ], + "types": [ + "CT_Path2DCubicBezierTo" + ] + }, + { + "element": "a:custClr", + "name": "custClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_CustomColorList" + ], + "types": [ + "CT_CustomColor" + ] + }, + { + "element": "a:custClrLst", + "name": "custClrLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_OfficeStyleSheet" + ], + "types": [ + "CT_CustomColorList" + ] + }, + { + "element": "a:custDash", + "name": "custDash", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineJoinRound" + ], + "types": [ + "CT_DashStopList" + ] + }, + { + "element": "a:custGeom", + "name": "custGeom", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2DClose" + ], + "types": [ + "CT_CustomGeometry2D" + ] + }, + { + "element": "a:cxn", + "name": "cxn", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ConnectionSiteList" + ], + "types": [ + "CT_ConnectionSite" + ] + }, + { + "element": "a:cxnLst", + "name": "cxnLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_CustomGeometry2D" + ], + "types": [ + "CT_ConnectionSiteList" + ] + }, + { + "element": "a:cxnSp", + "name": "cxnSp", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GvmlConnector" + ] + }, + { + "element": "a:cxnSpLocks", + "name": "cxnSpLocks", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualConnectorProperties" + ], + "types": [ + "CT_ConnectorLocking" + ] + }, + { + "element": "a:defPPr", + "name": "defPPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:defRPr", + "name": "defRPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextParagraphProperties" + ], + "types": [ + "CT_TextCharacterProperties" + ] + }, + { + "element": "a:dgm", + "name": "dgm", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AnimationElementChoice" + ], + "types": [ + "CT_AnimationDgmElement" + ] + }, + { + "element": "a:dk1", + "name": "dk1", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:dk2", + "name": "dk2", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:ds", + "name": "ds", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_DashStopList" + ], + "types": [ + "CT_DashStop" + ] + }, + { + "element": "a:duotone", + "name": "duotone", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_DuotoneEffect" + ] + }, + { + "element": "a:ea", + "name": "ea", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_FontCollection", + "CT_TextCharacterProperties" + ], + "types": [ + "CT_TextFont" + ] + }, + { + "element": "a:effect", + "name": "effect", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EmptyElement" + ], + "types": [ + "CT_EffectReference", + "CT_EffectProperties" + ] + }, + { + "element": "a:effectDag", + "name": "effectDag", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties" + ], + "types": [ + "CT_EffectContainer" + ] + }, + { + "element": "a:effectLst", + "name": "effectLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties" + ], + "types": [ + "CT_EffectList" + ] + }, + { + "element": "a:effectRef", + "name": "effectRef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ShapeStyle", + "CT_EmptyElement" + ], + "types": [ + "CT_StyleMatrixReference" + ] + }, + { + "element": "a:effectStyle", + "name": "effectStyle", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EffectStyleList" + ], + "types": [ + "CT_EffectStyleItem" + ] + }, + { + "element": "a:effectStyleLst", + "name": "effectStyleLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_StyleMatrix" + ], + "types": [ + "CT_EffectStyleList" + ] + }, + { + "element": "a:end", + "name": "end", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AudioCD" + ], + "types": [ + "CT_AudioCDTime" + ] + }, + { + "element": "a:endCxn", + "name": "endCxn", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualConnectorProperties" + ], + "types": [ + "CT_Connection" + ] + }, + { + "element": "a:endParaRPr", + "name": "endParaRPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextParagraph" + ], + "types": [ + "CT_TextCharacterProperties" + ] + }, + { + "element": "a:ext", + "name": "ext", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform", + "CT_Transform2D", + "CT_GroupTransform2D" + ], + "types": [ + "CT_OfficeArtExtension", + "CT_PositiveSize2D" + ] + }, + { + "element": "a:extLst", + "name": "extLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AudioFile", + "CT_VideoFile", + "CT_QuickTimeFile", + "CT_AudioCD", + "CT_ColorScheme", + "CT_FontCollection", + "CT_FontScheme", + "CT_BaseStyles", + "CT_Hyperlink", + "CT_ConnectorLocking", + "CT_ShapeLocking", + "CT_PictureLocking", + "CT_GroupLocking", + "CT_GraphicalObjectFrameLocking", + "CT_ContentPartLocking", + "CT_NonVisualDrawingProps", + "CT_NonVisualDrawingShapeProps", + "CT_NonVisualConnectorProperties", + "CT_NonVisualPictureProperties", + "CT_NonVisualGroupDrawingShapeProps", + "CT_NonVisualGraphicFrameProperties", + "CT_NonVisualContentPartProperties", + "CT_GvmlTextShape", + "CT_GvmlShape", + "CT_GvmlConnector", + "CT_GvmlPicture", + "CT_GvmlGraphicalObjectFrame", + "CT_GvmlGroupShape", + "CT_Scene3D", + "CT_Backdrop", + "CT_Shape3D", + "CT_Blip", + "CT_LineProperties", + "CT_ShapeProperties", + "CT_GroupShapeProperties", + "CT_DefaultShapeDefinition", + "CT_ObjectStyleDefaults", + "CT_ColorMapping", + "CT_OfficeStyleSheet", + "CT_TableCellProperties", + "CT_TableCol", + "CT_TableCell", + "CT_TableRow", + "CT_TableProperties", + "CT_Cell3D", + "CT_TableStyleTextStyle", + "CT_TableCellBorderStyle", + "CT_TableStyle", + "CT_TextListStyle", + "CT_TextBodyProperties", + "CT_TextCharacterProperties", + "CT_TextParagraphProperties" + ], + "types": [ + "CT_OfficeArtExtensionList" + ] + }, + { + "element": "a:extraClrScheme", + "name": "extraClrScheme", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorSchemeList" + ], + "types": [ + "CT_ColorSchemeAndMapping" + ] + }, + { + "element": "a:extraClrSchemeLst", + "name": "extraClrSchemeLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_OfficeStyleSheet" + ], + "types": [ + "CT_ColorSchemeList" + ] + }, + { + "element": "a:extrusionClr", + "name": "extrusionClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Shape3D" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:fgClr", + "name": "fgClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_PatternFillProperties" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:fill", + "name": "fill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EmptyElement" + ], + "types": [ + "CT_FillEffect", + "CT_FillProperties" + ] + }, + { + "element": "a:fillOverlay", + "name": "fillOverlay", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_FillOverlayEffect" + ] + }, + { + "element": "a:fillRect", + "name": "fillRect", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_StretchInfoProperties" + ], + "types": [ + "CT_RelativeRect" + ] + }, + { + "element": "a:fillRef", + "name": "fillRef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ShapeStyle", + "CT_EmptyElement" + ], + "types": [ + "CT_StyleMatrixReference" + ] + }, + { + "element": "a:fillStyleLst", + "name": "fillStyleLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_StyleMatrix" + ], + "types": [ + "CT_FillStyleList" + ] + }, + { + "element": "a:fillToRect", + "name": "fillToRect", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_PathShadeProperties" + ], + "types": [ + "CT_RelativeRect" + ] + }, + { + "element": "a:firstCol", + "name": "firstCol", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:firstRow", + "name": "firstRow", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:flatTx", + "name": "flatTx", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlUseShapeRectangle" + ], + "types": [ + "CT_FlatText" + ] + }, + { + "element": "a:fld", + "name": "fld", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextUnderlineFillFollowText" + ], + "types": [ + "CT_TextField" + ] + }, + { + "element": "a:fmtScheme", + "name": "fmtScheme", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_BaseStyles", + "CT_BaseStylesOverride" + ], + "types": [ + "CT_StyleMatrix" + ] + }, + { + "element": "a:folHlink", + "name": "folHlink", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:font", + "name": "font", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_FontCollection", + "CT_EmptyElement" + ], + "types": [ + "CT_SupplementalFont", + "CT_FontCollection" + ] + }, + { + "element": "a:fontRef", + "name": "fontRef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ShapeStyle", + "CT_EmptyElement" + ], + "types": [ + "CT_FontReference" + ] + }, + { + "element": "a:fontScheme", + "name": "fontScheme", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_BaseStyles", + "CT_BaseStylesOverride" + ], + "types": [ + "CT_FontScheme" + ] + }, + { + "element": "a:gamma", + "name": "gamma", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_GammaTransform" + ] + }, + { + "element": "a:gd", + "name": "gd", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GeomGuideList" + ], + "types": [ + "CT_GeomGuide" + ] + }, + { + "element": "a:gdLst", + "name": "gdLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_CustomGeometry2D" + ], + "types": [ + "CT_GeomGuideList" + ] + }, + { + "element": "a:glow", + "name": "glow", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_GlowEffect" + ] + }, + { + "element": "a:gradFill", + "name": "gradFill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_Path2DClose" + ], + "types": [ + "CT_GradientFillProperties" + ] + }, + { + "element": "a:graphic", + "name": "graphic", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_GraphicalObject" + ] + }, + { + "element": "a:graphicData", + "name": "graphicData", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GraphicalObject" + ], + "types": [ + "CT_GraphicalObjectData" + ] + }, + { + "element": "a:graphicFrame", + "name": "graphicFrame", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GvmlGraphicalObjectFrame" + ] + }, + { + "element": "a:graphicFrameLocks", + "name": "graphicFrameLocks", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualGraphicFrameProperties" + ], + "types": [ + "CT_GraphicalObjectFrameLocking" + ] + }, + { + "element": "a:gray", + "name": "gray", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_GrayscaleTransform" + ] + }, + { + "element": "a:grayscl", + "name": "grayscl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_GrayscaleEffect" + ] + }, + { + "element": "a:green", + "name": "green", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:greenMod", + "name": "greenMod", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:greenOff", + "name": "greenOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:gridCol", + "name": "gridCol", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableGrid" + ], + "types": [ + "CT_TableCol" + ] + }, + { + "element": "a:grpFill", + "name": "grpFill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties" + ], + "types": [ + "CT_GroupFillProperties" + ] + }, + { + "element": "a:grpSp", + "name": "grpSp", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GvmlGroupShape" + ] + }, + { + "element": "a:grpSpLocks", + "name": "grpSpLocks", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualGroupDrawingShapeProps" + ], + "types": [ + "CT_GroupLocking" + ] + }, + { + "element": "a:grpSpPr", + "name": "grpSpPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GroupShapeProperties" + ] + }, + { + "element": "a:gs", + "name": "gs", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GradientStopList" + ], + "types": [ + "CT_GradientStop" + ] + }, + { + "element": "a:gsLst", + "name": "gsLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GradientFillProperties" + ], + "types": [ + "CT_GradientStopList" + ] + }, + { + "element": "a:headEnd", + "name": "headEnd", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineProperties" + ], + "types": [ + "CT_LineEndProperties" + ] + }, + { + "element": "a:header", + "name": "header", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Headers" + ], + "types": [ + "xsd:string" + ] + }, + { + "element": "a:headers", + "name": "headers", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties" + ], + "types": [ + "CT_Headers" + ] + }, + { + "element": "a:highlight", + "name": "highlight", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextCharacterProperties" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:hlink", + "name": "hlink", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:hlinkClick", + "name": "hlinkClick", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualDrawingProps", + "CT_TextCharacterProperties" + ], + "types": [ + "CT_Hyperlink" + ] + }, + { + "element": "a:hlinkHover", + "name": "hlinkHover", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualDrawingProps" + ], + "types": [ + "CT_Hyperlink" + ] + }, + { + "element": "a:hlinkMouseOver", + "name": "hlinkMouseOver", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextCharacterProperties" + ], + "types": [ + "CT_Hyperlink" + ] + }, + { + "element": "a:hsl", + "name": "hsl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_HSLEffect" + ] + }, + { + "element": "a:hslClr", + "name": "hslClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_HslColor" + ] + }, + { + "element": "a:hue", + "name": "hue", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_PositiveFixedAngle" + ] + }, + { + "element": "a:hueMod", + "name": "hueMod", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_PositivePercentage" + ] + }, + { + "element": "a:hueOff", + "name": "hueOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Angle" + ] + }, + { + "element": "a:innerShdw", + "name": "innerShdw", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_InnerShadowEffect" + ] + }, + { + "element": "a:insideH", + "name": "insideH", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:insideV", + "name": "insideV", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:inv", + "name": "inv", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_InverseTransform" + ] + }, + { + "element": "a:invGamma", + "name": "invGamma", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_InverseGammaTransform" + ] + }, + { + "element": "a:lastCol", + "name": "lastCol", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:lastRow", + "name": "lastRow", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:latin", + "name": "latin", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_FontCollection", + "CT_TextCharacterProperties" + ], + "types": [ + "CT_TextFont" + ] + }, + { + "element": "a:left", + "name": "left", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:lightRig", + "name": "lightRig", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Scene3D", + "CT_Cell3D" + ], + "types": [ + "CT_LightRig" + ] + }, + { + "element": "a:lin", + "name": "lin", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NoFillProperties" + ], + "types": [ + "CT_LinearShadeProperties" + ] + }, + { + "element": "a:ln", + "name": "ln", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineStyleList", + "CT_WholeE2oFormatting", + "CT_ShapeProperties", + "CT_ThemeableLineStyle", + "CT_TextCharacterProperties" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:lnB", + "name": "lnB", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:lnBlToTr", + "name": "lnBlToTr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:lnDef", + "name": "lnDef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ObjectStyleDefaults" + ], + "types": [ + "CT_DefaultShapeDefinition" + ] + }, + { + "element": "a:lnL", + "name": "lnL", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:lnR", + "name": "lnR", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:lnRef", + "name": "lnRef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ShapeStyle", + "CT_ThemeableLineStyle" + ], + "types": [ + "CT_StyleMatrixReference" + ] + }, + { + "element": "a:lnSpc", + "name": "lnSpc", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextParagraphProperties" + ], + "types": [ + "CT_TextSpacing" + ] + }, + { + "element": "a:lnStyleLst", + "name": "lnStyleLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_StyleMatrix" + ], + "types": [ + "CT_LineStyleList" + ] + }, + { + "element": "a:lnT", + "name": "lnT", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:lnTlToBr", + "name": "lnTlToBr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellProperties" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:lnTo", + "name": "lnTo", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2D" + ], + "types": [ + "CT_Path2DLineTo" + ] + }, + { + "element": "a:lstStyle", + "name": "lstStyle", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_DefaultShapeDefinition", + "CT_TextBody" + ], + "types": [ + "CT_TextListStyle" + ] + }, + { + "element": "a:lt1", + "name": "lt1", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:lt2", + "name": "lt2", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorScheme" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "a:lum", + "name": "lum", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform", + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_Percentage", + "CT_LuminanceEffect" + ] + }, + { + "element": "a:lumMod", + "name": "lumMod", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:lumOff", + "name": "lumOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:lvl1pPr", + "name": "lvl1pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl2pPr", + "name": "lvl2pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl3pPr", + "name": "lvl3pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl4pPr", + "name": "lvl4pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl5pPr", + "name": "lvl5pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl6pPr", + "name": "lvl6pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl7pPr", + "name": "lvl7pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl8pPr", + "name": "lvl8pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:lvl9pPr", + "name": "lvl9pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextListStyle" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:majorFont", + "name": "majorFont", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_FontScheme" + ], + "types": [ + "CT_FontCollection" + ] + }, + { + "element": "a:masterClrMapping", + "name": "masterClrMapping", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorMappingOverride" + ], + "types": [ + "CT_EmptyElement" + ] + }, + { + "element": "a:minorFont", + "name": "minorFont", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_FontScheme" + ], + "types": [ + "CT_FontCollection" + ] + }, + { + "element": "a:miter", + "name": "miter", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineJoinRound" + ], + "types": [ + "CT_LineJoinMiterProperties" + ] + }, + { + "element": "a:moveTo", + "name": "moveTo", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2D" + ], + "types": [ + "CT_Path2DMoveTo" + ] + }, + { + "element": "a:neCell", + "name": "neCell", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:noAutofit", + "name": "noAutofit", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextNoAutofit" + ], + "types": [ + "CT_TextNoAutofit" + ] + }, + { + "element": "a:noFill", + "name": "noFill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_Path2DClose" + ], + "types": [ + "CT_NoFillProperties" + ] + }, + { + "element": "a:norm", + "name": "norm", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Backdrop" + ], + "types": [ + "CT_Vector3D" + ] + }, + { + "element": "a:normAutofit", + "name": "normAutofit", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextNoAutofit" + ], + "types": [ + "CT_TextNormalAutofit" + ] + }, + { + "element": "a:nvCxnSpPr", + "name": "nvCxnSpPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlConnector" + ], + "types": [ + "CT_GvmlConnectorNonVisual" + ] + }, + { + "element": "a:nvGraphicFramePr", + "name": "nvGraphicFramePr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGraphicalObjectFrame" + ], + "types": [ + "CT_GvmlGraphicFrameNonVisual" + ] + }, + { + "element": "a:nvGrpSpPr", + "name": "nvGrpSpPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GvmlGroupShapeNonVisual" + ] + }, + { + "element": "a:nvPicPr", + "name": "nvPicPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlPicture" + ], + "types": [ + "CT_GvmlPictureNonVisual" + ] + }, + { + "element": "a:nvSpPr", + "name": "nvSpPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlShape" + ], + "types": [ + "CT_GvmlShapeNonVisual" + ] + }, + { + "element": "a:nwCell", + "name": "nwCell", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:objectDefaults", + "name": "objectDefaults", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_OfficeStyleSheet" + ], + "types": [ + "CT_ObjectStyleDefaults" + ] + }, + { + "element": "a:off", + "name": "off", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Transform2D", + "CT_GroupTransform2D" + ], + "types": [ + "CT_Point2D" + ] + }, + { + "element": "a:outerShdw", + "name": "outerShdw", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_OuterShadowEffect" + ] + }, + { + "element": "a:overrideClrMapping", + "name": "overrideClrMapping", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ColorMappingOverride" + ], + "types": [ + "CT_ColorMapping" + ] + }, + { + "element": "a:p", + "name": "p", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextBody" + ], + "types": [ + "CT_TextParagraph" + ] + }, + { + "element": "a:path", + "name": "path", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NoFillProperties", + "CT_Path2DList" + ], + "types": [ + "CT_PathShadeProperties", + "CT_Path2D" + ] + }, + { + "element": "a:pathLst", + "name": "pathLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_CustomGeometry2D" + ], + "types": [ + "CT_Path2DList" + ] + }, + { + "element": "a:pattFill", + "name": "pattFill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_Path2DClose" + ], + "types": [ + "CT_PatternFillProperties" + ] + }, + { + "element": "a:pic", + "name": "pic", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GvmlPicture" + ] + }, + { + "element": "a:picLocks", + "name": "picLocks", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualPictureProperties" + ], + "types": [ + "CT_PictureLocking" + ] + }, + { + "element": "a:pos", + "name": "pos", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_XYAdjustHandle", + "CT_PolarAdjustHandle", + "CT_ConnectionSite" + ], + "types": [ + "CT_AdjPoint2D" + ] + }, + { + "element": "a:pPr", + "name": "pPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextParagraph", + "CT_TextField" + ], + "types": [ + "CT_TextParagraphProperties" + ] + }, + { + "element": "a:prstClr", + "name": "prstClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_PresetColor" + ] + }, + { + "element": "a:prstDash", + "name": "prstDash", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineJoinRound" + ], + "types": [ + "CT_PresetLineDashProperties" + ] + }, + { + "element": "a:prstGeom", + "name": "prstGeom", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2DClose" + ], + "types": [ + "CT_PresetGeometry2D" + ] + }, + { + "element": "a:prstShdw", + "name": "prstShdw", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_PresetShadowEffect" + ] + }, + { + "element": "a:prstTxWarp", + "name": "prstTxWarp", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2DClose", + "CT_TextBodyProperties" + ], + "types": [ + "CT_PresetTextShape" + ] + }, + { + "element": "a:pt", + "name": "pt", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2DMoveTo", + "CT_Path2DLineTo", + "CT_Path2DQuadBezierTo", + "CT_Path2DCubicBezierTo" + ], + "types": [ + "CT_AdjPoint2D" + ] + }, + { + "element": "a:quadBezTo", + "name": "quadBezTo", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Path2D" + ], + "types": [ + "CT_Path2DQuadBezierTo" + ] + }, + { + "element": "a:quickTimeFile", + "name": "quickTimeFile", + "prefix": "a", + "domain": "drawing", + "definedIn": [], + "types": [ + "CT_QuickTimeFile" + ] + }, + { + "element": "a:r", + "name": "r", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextUnderlineFillFollowText" + ], + "types": [ + "CT_RegularTextRun" + ] + }, + { + "element": "a:rect", + "name": "rect", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_CustomGeometry2D" + ], + "types": [ + "CT_GeomRect" + ] + }, + { + "element": "a:red", + "name": "red", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:redMod", + "name": "redMod", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:redOff", + "name": "redOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:reflection", + "name": "reflection", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_ReflectionEffect" + ] + }, + { + "element": "a:relOff", + "name": "relOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties" + ], + "types": [ + "CT_RelativeOffsetEffect" + ] + }, + { + "element": "a:right", + "name": "right", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:rot", + "name": "rot", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Camera", + "CT_LightRig" + ], + "types": [ + "CT_SphereCoords" + ] + }, + { + "element": "a:round", + "name": "round", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineJoinRound" + ], + "types": [ + "CT_LineJoinRound" + ] + }, + { + "element": "a:rPr", + "name": "rPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextLineBreak", + "CT_TextField", + "CT_RegularTextRun" + ], + "types": [ + "CT_TextCharacterProperties" + ] + }, + { + "element": "a:rtl", + "name": "rtl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextCharacterProperties" + ], + "types": [ + "CT_Boolean" + ] + }, + { + "element": "a:sat", + "name": "sat", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:satMod", + "name": "satMod", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:satOff", + "name": "satOff", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_Percentage" + ] + }, + { + "element": "a:scene3d", + "name": "scene3d", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EffectStyleItem", + "CT_ShapeProperties", + "CT_GroupShapeProperties", + "CT_TextBodyProperties" + ], + "types": [ + "CT_Scene3D" + ] + }, + { + "element": "a:schemeClr", + "name": "schemeClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_SchemeColor" + ] + }, + { + "element": "a:scrgbClr", + "name": "scrgbClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_ScRgbColor" + ] + }, + { + "element": "a:seCell", + "name": "seCell", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:shade", + "name": "shade", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_PositiveFixedPercentage" + ] + }, + { + "element": "a:snd", + "name": "snd", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Hyperlink" + ], + "types": [ + "CT_EmbeddedWAVAudioFile" + ] + }, + { + "element": "a:softEdge", + "name": "softEdge", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_EffectList" + ], + "types": [ + "CT_SoftEdgesEffect" + ] + }, + { + "element": "a:solidFill", + "name": "solidFill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GroupFillProperties", + "CT_Path2DClose" + ], + "types": [ + "CT_SolidColorFillProperties" + ] + }, + { + "element": "a:sp", + "name": "sp", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GvmlShape" + ] + }, + { + "element": "a:sp3d", + "name": "sp3d", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EffectStyleItem", + "CT_GvmlUseShapeRectangle", + "CT_ShapeProperties" + ], + "types": [ + "CT_Shape3D" + ] + }, + { + "element": "a:spAutoFit", + "name": "spAutoFit", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextNoAutofit" + ], + "types": [ + "CT_TextShapeAutofit" + ] + }, + { + "element": "a:spcAft", + "name": "spcAft", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextParagraphProperties" + ], + "types": [ + "CT_TextSpacing" + ] + }, + { + "element": "a:spcBef", + "name": "spcBef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextParagraphProperties" + ], + "types": [ + "CT_TextSpacing" + ] + }, + { + "element": "a:spcPct", + "name": "spcPct", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextSpacing" + ], + "types": [ + "CT_TextSpacingPercent" + ] + }, + { + "element": "a:spcPts", + "name": "spcPts", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextSpacing" + ], + "types": [ + "CT_TextSpacingPoint" + ] + }, + { + "element": "a:spDef", + "name": "spDef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ObjectStyleDefaults" + ], + "types": [ + "CT_DefaultShapeDefinition" + ] + }, + { + "element": "a:spLocks", + "name": "spLocks", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualDrawingShapeProps" + ], + "types": [ + "CT_ShapeLocking" + ] + }, + { + "element": "a:spPr", + "name": "spPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlShape", + "CT_GvmlConnector", + "CT_GvmlPicture", + "CT_DefaultShapeDefinition" + ], + "types": [ + "CT_ShapeProperties" + ] + }, + { + "element": "a:srcRect", + "name": "srcRect", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_BlipFillProperties" + ], + "types": [ + "CT_RelativeRect" + ] + }, + { + "element": "a:srgbClr", + "name": "srgbClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_SRgbColor" + ] + }, + { + "element": "a:st", + "name": "st", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_AudioCD" + ], + "types": [ + "CT_AudioCDTime" + ] + }, + { + "element": "a:stCxn", + "name": "stCxn", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NonVisualConnectorProperties" + ], + "types": [ + "CT_Connection" + ] + }, + { + "element": "a:stretch", + "name": "stretch", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NoFillProperties" + ], + "types": [ + "CT_StretchInfoProperties" + ] + }, + { + "element": "a:style", + "name": "style", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlShape", + "CT_GvmlConnector", + "CT_GvmlPicture", + "CT_DefaultShapeDefinition" + ], + "types": [ + "CT_ShapeStyle" + ] + }, + { + "element": "a:swCell", + "name": "swCell", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:sx", + "name": "sx", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Scale2D" + ], + "types": [ + "CT_Ratio" + ] + }, + { + "element": "a:sy", + "name": "sy", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Scale2D" + ], + "types": [ + "CT_Ratio" + ] + }, + { + "element": "a:sym", + "name": "sym", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextCharacterProperties" + ], + "types": [ + "CT_TextFont" + ] + }, + { + "element": "a:sysClr", + "name": "sysClr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform" + ], + "types": [ + "CT_SystemColor" + ] + }, + { + "element": "a:t", + "name": "t", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextField", + "CT_RegularTextRun" + ], + "types": [ + "xsd:string" + ] + }, + { + "element": "a:tab", + "name": "tab", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextTabStopList" + ], + "types": [ + "CT_TextTabStop" + ] + }, + { + "element": "a:tableStyle", + "name": "tableStyle", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableProperties" + ], + "types": [ + "CT_TableStyle" + ] + }, + { + "element": "a:tableStyleId", + "name": "tableStyleId", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableProperties" + ], + "types": [ + "s:ST_Guid" + ] + }, + { + "element": "a:tabLst", + "name": "tabLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextParagraphProperties" + ], + "types": [ + "CT_TextTabStopList" + ] + }, + { + "element": "a:tailEnd", + "name": "tailEnd", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_LineProperties" + ], + "types": [ + "CT_LineEndProperties" + ] + }, + { + "element": "a:tbl", + "name": "tbl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EmptyElement" + ], + "types": [ + "CT_Table" + ] + }, + { + "element": "a:tblBg", + "name": "tblBg", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TableBackgroundStyle" + ] + }, + { + "element": "a:tblGrid", + "name": "tblGrid", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Table" + ], + "types": [ + "CT_TableGrid" + ] + }, + { + "element": "a:tblPr", + "name": "tblPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Table" + ], + "types": [ + "CT_TableProperties" + ] + }, + { + "element": "a:tblStyle", + "name": "tblStyle", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyleList" + ], + "types": [ + "CT_TableStyle" + ] + }, + { + "element": "a:tblStyleLst", + "name": "tblStyleLst", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EmptyElement" + ], + "types": [ + "CT_TableStyleList" + ] + }, + { + "element": "a:tc", + "name": "tc", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableRow" + ], + "types": [ + "CT_TableCell" + ] + }, + { + "element": "a:tcBdr", + "name": "tcBdr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyleCellStyle" + ], + "types": [ + "CT_TableCellBorderStyle" + ] + }, + { + "element": "a:tcPr", + "name": "tcPr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCell" + ], + "types": [ + "CT_TableCellProperties" + ] + }, + { + "element": "a:tcStyle", + "name": "tcStyle", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TablePartStyle" + ], + "types": [ + "CT_TableStyleCellStyle" + ] + }, + { + "element": "a:tcTxStyle", + "name": "tcTxStyle", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TablePartStyle" + ], + "types": [ + "CT_TableStyleTextStyle" + ] + }, + { + "element": "a:theme", + "name": "theme", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EmptyElement" + ], + "types": [ + "CT_OfficeStyleSheet" + ] + }, + { + "element": "a:themeElements", + "name": "themeElements", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_OfficeStyleSheet", + "CT_ClipboardStyleSheet" + ], + "types": [ + "CT_BaseStyles" + ] + }, + { + "element": "a:themeManager", + "name": "themeManager", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EmptyElement" + ], + "types": [ + "CT_EmptyElement" + ] + }, + { + "element": "a:themeOverride", + "name": "themeOverride", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_EmptyElement" + ], + "types": [ + "CT_BaseStylesOverride" + ] + }, + { + "element": "a:tile", + "name": "tile", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_NoFillProperties" + ], + "types": [ + "CT_TileInfoProperties" + ] + }, + { + "element": "a:tileRect", + "name": "tileRect", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GradientFillProperties" + ], + "types": [ + "CT_RelativeRect" + ] + }, + { + "element": "a:tint", + "name": "tint", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_InverseGammaTransform", + "CT_Blip", + "CT_GroupFillProperties" + ], + "types": [ + "CT_PositiveFixedPercentage", + "CT_TintEffect" + ] + }, + { + "element": "a:tl2br", + "name": "tl2br", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:top", + "name": "top", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:tr", + "name": "tr", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Table" + ], + "types": [ + "CT_TableRow" + ] + }, + { + "element": "a:tr2bl", + "name": "tr2bl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableCellBorderStyle" + ], + "types": [ + "CT_ThemeableLineStyle" + ] + }, + { + "element": "a:txBody", + "name": "txBody", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlTextShape", + "CT_TableCell" + ], + "types": [ + "CT_TextBody" + ] + }, + { + "element": "a:txDef", + "name": "txDef", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_ObjectStyleDefaults" + ], + "types": [ + "CT_DefaultShapeDefinition" + ] + }, + { + "element": "a:txSp", + "name": "txSp", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlShape", + "CT_GvmlGroupShape" + ], + "types": [ + "CT_GvmlTextShape" + ] + }, + { + "element": "a:uFill", + "name": "uFill", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextUnderlineFillFollowText" + ], + "types": [ + "CT_TextUnderlineFillGroupWrapper" + ] + }, + { + "element": "a:uFillTx", + "name": "uFillTx", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextUnderlineFillFollowText" + ], + "types": [ + "CT_TextUnderlineFillFollowText" + ] + }, + { + "element": "a:uLn", + "name": "uLn", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextUnderlineFillFollowText" + ], + "types": [ + "CT_LineProperties" + ] + }, + { + "element": "a:uLnTx", + "name": "uLnTx", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TextUnderlineFillFollowText" + ], + "types": [ + "CT_TextUnderlineLineFollowText" + ] + }, + { + "element": "a:up", + "name": "up", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_Backdrop" + ], + "types": [ + "CT_Vector3D" + ] + }, + { + "element": "a:useSpRect", + "name": "useSpRect", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlTextShape" + ], + "types": [ + "CT_GvmlUseShapeRectangle" + ] + }, + { + "element": "a:videoFile", + "name": "videoFile", + "prefix": "a", + "domain": "drawing", + "definedIn": [], + "types": [ + "CT_VideoFile" + ] + }, + { + "element": "a:wavAudioFile", + "name": "wavAudioFile", + "prefix": "a", + "domain": "drawing", + "definedIn": [], + "types": [ + "CT_EmbeddedWAVAudioFile" + ] + }, + { + "element": "a:wholeTbl", + "name": "wholeTbl", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_TableStyle" + ], + "types": [ + "CT_TablePartStyle" + ] + }, + { + "element": "a:xfrm", + "name": "xfrm", + "prefix": "a", + "domain": "drawing", + "definedIn": [ + "CT_GvmlTextShape", + "CT_GvmlGraphicalObjectFrame", + "CT_GroupFillProperties", + "CT_ShapeProperties", + "CT_GroupShapeProperties" + ], + "types": [ + "CT_Transform2D", + "CT_TransformEffect", + "CT_GroupTransform2D" + ] + }, + { + "element": "custprops:Properties", + "name": "Properties", + "prefix": "custprops", + "domain": "docprops", + "definedIn": [], + "types": [ + "CT_Properties" + ] + }, + { + "element": "custprops:property", + "name": "property", + "prefix": "custprops", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Application", + "name": "Application", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:AppVersion", + "name": "AppVersion", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Characters", + "name": "Characters", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:CharactersWithSpaces", + "name": "CharactersWithSpaces", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Company", + "name": "Company", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:DigSig", + "name": "DigSig", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:DocSecurity", + "name": "DocSecurity", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:HeadingPairs", + "name": "HeadingPairs", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:HiddenSlides", + "name": "HiddenSlides", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:HLinks", + "name": "HLinks", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:HyperlinkBase", + "name": "HyperlinkBase", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:HyperlinksChanged", + "name": "HyperlinksChanged", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Lines", + "name": "Lines", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:LinksUpToDate", + "name": "LinksUpToDate", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Manager", + "name": "Manager", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:MMClips", + "name": "MMClips", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Notes", + "name": "Notes", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Pages", + "name": "Pages", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Paragraphs", + "name": "Paragraphs", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:PresentationFormat", + "name": "PresentationFormat", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Properties", + "name": "Properties", + "prefix": "ep", + "domain": "docprops", + "definedIn": [], + "types": [ + "CT_Properties" + ] + }, + { + "element": "ep:ScaleCrop", + "name": "ScaleCrop", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:SharedDoc", + "name": "SharedDoc", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Slides", + "name": "Slides", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Template", + "name": "Template", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:TitlesOfParts", + "name": "TitlesOfParts", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:TotalTime", + "name": "TotalTime", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "ep:Words", + "name": "Words", + "prefix": "ep", + "domain": "docprops", + "definedIn": [ + "CT_Properties" + ], + "types": [] + }, + { + "element": "m:acc", + "name": "acc", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_Acc" + ] + }, + { + "element": "m:accPr", + "name": "accPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Acc" + ], + "types": [ + "CT_AccPr" + ] + }, + { + "element": "m:aln", + "name": "aln", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_RPR", + "CT_BoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:alnScr", + "name": "alnScr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_SSubSupPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:argPr", + "name": "argPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_OMathArg" + ], + "types": [ + "CT_OMathArgPr" + ] + }, + { + "element": "m:argSz", + "name": "argSz", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_OMathArgPr" + ], + "types": [ + "CT_Integer2" + ] + }, + { + "element": "m:bar", + "name": "bar", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_Bar" + ] + }, + { + "element": "m:barPr", + "name": "barPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Bar" + ], + "types": [ + "CT_BarPr" + ] + }, + { + "element": "m:baseJc", + "name": "baseJc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_EqArrPr", + "CT_MPr" + ], + "types": [ + "CT_YAlign" + ] + }, + { + "element": "m:begChr", + "name": "begChr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_DPr" + ], + "types": [ + "CT_Char" + ] + }, + { + "element": "m:borderBox", + "name": "borderBox", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_BorderBox" + ] + }, + { + "element": "m:borderBoxPr", + "name": "borderBoxPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBox" + ], + "types": [ + "CT_BorderBoxPr" + ] + }, + { + "element": "m:box", + "name": "box", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_Box" + ] + }, + { + "element": "m:boxPr", + "name": "boxPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Box" + ], + "types": [ + "CT_BoxPr" + ] + }, + { + "element": "m:brk", + "name": "brk", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_RPR", + "CT_BoxPr" + ], + "types": [ + "CT_ManualBreak" + ] + }, + { + "element": "m:brkBin", + "name": "brkBin", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_BreakBin" + ] + }, + { + "element": "m:brkBinSub", + "name": "brkBinSub", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_BreakBinSub" + ] + }, + { + "element": "m:cGp", + "name": "cGp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MPr" + ], + "types": [ + "CT_UnSignedInteger" + ] + }, + { + "element": "m:cGpRule", + "name": "cGpRule", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MPr" + ], + "types": [ + "CT_SpacingRule" + ] + }, + { + "element": "m:chr", + "name": "chr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_AccPr", + "CT_GroupChrPr", + "CT_NaryPr" + ], + "types": [ + "CT_Char" + ] + }, + { + "element": "m:count", + "name": "count", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MCPr" + ], + "types": [ + "CT_Integer255" + ] + }, + { + "element": "m:cSp", + "name": "cSp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MPr" + ], + "types": [ + "CT_UnSignedInteger" + ] + }, + { + "element": "m:ctrlPr", + "name": "ctrlPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_AccPr", + "CT_BarPr", + "CT_BoxPr", + "CT_BorderBoxPr", + "CT_DPr", + "CT_EqArrPr", + "CT_FPr", + "CT_FuncPr", + "CT_GroupChrPr", + "CT_LimLowPr", + "CT_LimUppPr", + "CT_MPr", + "CT_NaryPr", + "CT_PhantPr", + "CT_RadPr", + "CT_SPrePr", + "CT_SSubPr", + "CT_SSubSupPr", + "CT_SSupPr", + "CT_OMathArg" + ], + "types": [ + "CT_CtrlPr" + ] + }, + { + "element": "m:d", + "name": "d", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_D" + ] + }, + { + "element": "m:defJc", + "name": "defJc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_OMathJc" + ] + }, + { + "element": "m:deg", + "name": "deg", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Rad" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:degHide", + "name": "degHide", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_RadPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:den", + "name": "den", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_F" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:diff", + "name": "diff", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:dispDef", + "name": "dispDef", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:dPr", + "name": "dPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_D" + ], + "types": [ + "CT_DPr" + ] + }, + { + "element": "m:e", + "name": "e", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Acc", + "CT_Bar", + "CT_Box", + "CT_BorderBox", + "CT_D", + "CT_EqArr", + "CT_Func", + "CT_GroupChr", + "CT_LimLow", + "CT_LimUpp", + "CT_MR", + "CT_Nary", + "CT_Phant", + "CT_Rad", + "CT_SPre", + "CT_SSub", + "CT_SSubSup", + "CT_SSup" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:endChr", + "name": "endChr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_DPr" + ], + "types": [ + "CT_Char" + ] + }, + { + "element": "m:eqArr", + "name": "eqArr", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_EqArr" + ] + }, + { + "element": "m:eqArrPr", + "name": "eqArrPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_EqArr" + ], + "types": [ + "CT_EqArrPr" + ] + }, + { + "element": "m:f", + "name": "f", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_F" + ] + }, + { + "element": "m:fName", + "name": "fName", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Func" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:fPr", + "name": "fPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_F" + ], + "types": [ + "CT_FPr" + ] + }, + { + "element": "m:func", + "name": "func", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_Func" + ] + }, + { + "element": "m:funcPr", + "name": "funcPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Func" + ], + "types": [ + "CT_FuncPr" + ] + }, + { + "element": "m:groupChr", + "name": "groupChr", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_GroupChr" + ] + }, + { + "element": "m:groupChrPr", + "name": "groupChrPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_GroupChr" + ], + "types": [ + "CT_GroupChrPr" + ] + }, + { + "element": "m:grow", + "name": "grow", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_DPr", + "CT_NaryPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:hideBot", + "name": "hideBot", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:hideLeft", + "name": "hideLeft", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:hideRight", + "name": "hideRight", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:hideTop", + "name": "hideTop", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:interSp", + "name": "interSp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "m:intLim", + "name": "intLim", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_LimLoc" + ] + }, + { + "element": "m:intraSp", + "name": "intraSp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "m:jc", + "name": "jc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_OMathParaPr" + ], + "types": [ + "CT_OMathJc" + ] + }, + { + "element": "m:lim", + "name": "lim", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_LimLow", + "CT_LimUpp" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:limLoc", + "name": "limLoc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_NaryPr" + ], + "types": [ + "CT_LimLoc" + ] + }, + { + "element": "m:limLow", + "name": "limLow", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_LimLow" + ] + }, + { + "element": "m:limLowPr", + "name": "limLowPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_LimLow" + ], + "types": [ + "CT_LimLowPr" + ] + }, + { + "element": "m:limUpp", + "name": "limUpp", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_LimUpp" + ] + }, + { + "element": "m:limUppPr", + "name": "limUppPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_LimUpp" + ], + "types": [ + "CT_LimUppPr" + ] + }, + { + "element": "m:lit", + "name": "lit", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_RPR" + ], + "types": [] + }, + { + "element": "m:lMargin", + "name": "lMargin", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "m:m", + "name": "m", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_M" + ] + }, + { + "element": "m:mathFont", + "name": "mathFont", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "m:mathPr", + "name": "mathPr", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_MathPr" + ] + }, + { + "element": "m:maxDist", + "name": "maxDist", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_EqArrPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:mc", + "name": "mc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MCS" + ], + "types": [ + "CT_MC" + ] + }, + { + "element": "m:mcJc", + "name": "mcJc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MCPr" + ], + "types": [ + "CT_XAlign" + ] + }, + { + "element": "m:mcPr", + "name": "mcPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MC" + ], + "types": [ + "CT_MCPr" + ] + }, + { + "element": "m:mcs", + "name": "mcs", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MPr" + ], + "types": [ + "CT_MCS" + ] + }, + { + "element": "m:mPr", + "name": "mPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_M" + ], + "types": [ + "CT_MPr" + ] + }, + { + "element": "m:mr", + "name": "mr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_M" + ], + "types": [ + "CT_MR" + ] + }, + { + "element": "m:nary", + "name": "nary", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_Nary" + ] + }, + { + "element": "m:naryLim", + "name": "naryLim", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_LimLoc" + ] + }, + { + "element": "m:naryPr", + "name": "naryPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Nary" + ], + "types": [ + "CT_NaryPr" + ] + }, + { + "element": "m:noBreak", + "name": "noBreak", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:nor", + "name": "nor", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_RPR" + ], + "types": [] + }, + { + "element": "m:num", + "name": "num", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_F" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:objDist", + "name": "objDist", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_EqArrPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:oMath", + "name": "oMath", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_OMathPara" + ], + "types": [ + "CT_OMath" + ] + }, + { + "element": "m:oMathPara", + "name": "oMathPara", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_OMathPara" + ] + }, + { + "element": "m:oMathParaPr", + "name": "oMathParaPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_OMathPara" + ], + "types": [ + "CT_OMathParaPr" + ] + }, + { + "element": "m:opEmu", + "name": "opEmu", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:phant", + "name": "phant", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_Phant" + ] + }, + { + "element": "m:phantPr", + "name": "phantPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Phant" + ], + "types": [ + "CT_PhantPr" + ] + }, + { + "element": "m:plcHide", + "name": "plcHide", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:pos", + "name": "pos", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BarPr", + "CT_GroupChrPr" + ], + "types": [ + "CT_TopBot" + ] + }, + { + "element": "m:postSp", + "name": "postSp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "m:preSp", + "name": "preSp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "m:r", + "name": "r", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_R" + ] + }, + { + "element": "m:rad", + "name": "rad", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_Rad" + ] + }, + { + "element": "m:radPr", + "name": "radPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Rad" + ], + "types": [ + "CT_RadPr" + ] + }, + { + "element": "m:rMargin", + "name": "rMargin", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "m:rPr", + "name": "rPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_R" + ], + "types": [ + "CT_RPR" + ] + }, + { + "element": "m:rSp", + "name": "rSp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_EqArrPr", + "CT_MPr" + ], + "types": [ + "CT_UnSignedInteger" + ] + }, + { + "element": "m:rSpRule", + "name": "rSpRule", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_EqArrPr", + "CT_MPr" + ], + "types": [ + "CT_SpacingRule" + ] + }, + { + "element": "m:scr", + "name": "scr", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [] + }, + { + "element": "m:sepChr", + "name": "sepChr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_DPr" + ], + "types": [ + "CT_Char" + ] + }, + { + "element": "m:show", + "name": "show", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_PhantPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:shp", + "name": "shp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_DPr" + ], + "types": [ + "CT_Shp" + ] + }, + { + "element": "m:smallFrac", + "name": "smallFrac", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:sPre", + "name": "sPre", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_SPre" + ] + }, + { + "element": "m:sPrePr", + "name": "sPrePr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_SPre" + ], + "types": [ + "CT_SPrePr" + ] + }, + { + "element": "m:sSub", + "name": "sSub", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_SSub" + ] + }, + { + "element": "m:sSubPr", + "name": "sSubPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_SSub" + ], + "types": [ + "CT_SSubPr" + ] + }, + { + "element": "m:sSubSup", + "name": "sSubSup", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_SSubSup" + ] + }, + { + "element": "m:sSubSupPr", + "name": "sSubSupPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_SSubSup" + ], + "types": [ + "CT_SSubSupPr" + ] + }, + { + "element": "m:sSup", + "name": "sSup", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [ + "CT_SSup" + ] + }, + { + "element": "m:sSupPr", + "name": "sSupPr", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_SSup" + ], + "types": [ + "CT_SSupPr" + ] + }, + { + "element": "m:strikeBLTR", + "name": "strikeBLTR", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:strikeH", + "name": "strikeH", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:strikeTLBR", + "name": "strikeTLBR", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:strikeV", + "name": "strikeV", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_BorderBoxPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:sty", + "name": "sty", + "prefix": "m", + "domain": "math", + "definedIn": [], + "types": [] + }, + { + "element": "m:sub", + "name": "sub", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Nary", + "CT_SPre", + "CT_SSub", + "CT_SSubSup" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:subHide", + "name": "subHide", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_NaryPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:sup", + "name": "sup", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_Nary", + "CT_SPre", + "CT_SSubSup", + "CT_SSup" + ], + "types": [ + "CT_OMathArg" + ] + }, + { + "element": "m:supHide", + "name": "supHide", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_NaryPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:t", + "name": "t", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_R" + ], + "types": [ + "CT_Text" + ] + }, + { + "element": "m:transp", + "name": "transp", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_PhantPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:type", + "name": "type", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_FPr" + ], + "types": [ + "CT_FType" + ] + }, + { + "element": "m:vertJc", + "name": "vertJc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_GroupChrPr" + ], + "types": [ + "CT_TopBot" + ] + }, + { + "element": "m:wrapIndent", + "name": "wrapIndent", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "m:wrapRight", + "name": "wrapRight", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_MathPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:zeroAsc", + "name": "zeroAsc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_PhantPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:zeroDesc", + "name": "zeroDesc", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_PhantPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "m:zeroWid", + "name": "zeroWid", + "prefix": "m", + "domain": "math", + "definedIn": [ + "CT_PhantPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "o:bottom", + "name": "bottom", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_StrokeChild" + ] + }, + { + "element": "o:callout", + "name": "callout", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Callout" + ] + }, + { + "element": "o:clippath", + "name": "clippath", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_ClipPath" + ] + }, + { + "element": "o:colormenu", + "name": "colormenu", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_ShapeDefaults" + ], + "types": [] + }, + { + "element": "o:colormru", + "name": "colormru", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_ShapeDefaults" + ], + "types": [] + }, + { + "element": "o:column", + "name": "column", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_StrokeChild" + ] + }, + { + "element": "o:complex", + "name": "complex", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Complex" + ] + }, + { + "element": "o:diagram", + "name": "diagram", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Diagram" + ] + }, + { + "element": "o:entry", + "name": "entry", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_RegroupTable" + ], + "types": [ + "CT_Entry" + ] + }, + { + "element": "o:equationxml", + "name": "equationxml", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_EquationXml" + ] + }, + { + "element": "o:extrusion", + "name": "extrusion", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Extrusion" + ] + }, + { + "element": "o:FieldCodes", + "name": "FieldCodes", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_OLEObject" + ], + "types": [ + "xsd:string" + ] + }, + { + "element": "o:fill", + "name": "fill", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Fill" + ] + }, + { + "element": "o:idmap", + "name": "idmap", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_ShapeLayout" + ], + "types": [ + "CT_IdMap" + ] + }, + { + "element": "o:ink", + "name": "ink", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Ink" + ] + }, + { + "element": "o:left", + "name": "left", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_StrokeChild" + ] + }, + { + "element": "o:LinkType", + "name": "LinkType", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_OLEObject" + ], + "types": [ + "ST_OLELinkType" + ] + }, + { + "element": "o:lock", + "name": "lock", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Lock" + ] + }, + { + "element": "o:LockedField", + "name": "LockedField", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_OLEObject" + ], + "types": [ + "s:ST_TrueFalseBlank" + ] + }, + { + "element": "o:OLEObject", + "name": "OLEObject", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_OLEObject" + ] + }, + { + "element": "o:proxy", + "name": "proxy", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_R" + ], + "types": [ + "CT_Proxy" + ] + }, + { + "element": "o:r", + "name": "r", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_Rules" + ], + "types": [ + "CT_R" + ] + }, + { + "element": "o:regrouptable", + "name": "regrouptable", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_ShapeLayout" + ], + "types": [ + "CT_RegroupTable" + ] + }, + { + "element": "o:rel", + "name": "rel", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_RelationTable" + ], + "types": [ + "CT_Relation" + ] + }, + { + "element": "o:relationtable", + "name": "relationtable", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_Diagram" + ], + "types": [ + "CT_RelationTable" + ] + }, + { + "element": "o:right", + "name": "right", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_StrokeChild" + ] + }, + { + "element": "o:rules", + "name": "rules", + "prefix": "o", + "domain": "vml", + "definedIn": [ + "CT_ShapeLayout" + ], + "types": [ + "CT_Rules" + ] + }, + { + "element": "o:shapedefaults", + "name": "shapedefaults", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_ShapeDefaults" + ] + }, + { + "element": "o:shapelayout", + "name": "shapelayout", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_ShapeLayout" + ] + }, + { + "element": "o:signatureline", + "name": "signatureline", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_SignatureLine" + ] + }, + { + "element": "o:skew", + "name": "skew", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Skew" + ] + }, + { + "element": "o:top", + "name": "top", + "prefix": "o", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_StrokeChild" + ] + }, + { + "element": "pic:blipFill", + "name": "blipFill", + "prefix": "pic", + "domain": "drawing", + "definedIn": [ + "CT_Picture" + ], + "types": [ + "a:CT_BlipFillProperties" + ] + }, + { + "element": "pic:cNvPicPr", + "name": "cNvPicPr", + "prefix": "pic", + "domain": "drawing", + "definedIn": [ + "CT_PictureNonVisual" + ], + "types": [ + "a:CT_NonVisualPictureProperties" + ] + }, + { + "element": "pic:cNvPr", + "name": "cNvPr", + "prefix": "pic", + "domain": "drawing", + "definedIn": [ + "CT_PictureNonVisual" + ], + "types": [ + "a:CT_NonVisualDrawingProps" + ] + }, + { + "element": "pic:nvPicPr", + "name": "nvPicPr", + "prefix": "pic", + "domain": "drawing", + "definedIn": [ + "CT_Picture" + ], + "types": [ + "CT_PictureNonVisual" + ] + }, + { + "element": "pic:pic", + "name": "pic", + "prefix": "pic", + "domain": "drawing", + "definedIn": [], + "types": [ + "CT_Picture" + ] + }, + { + "element": "pic:spPr", + "name": "spPr", + "prefix": "pic", + "domain": "drawing", + "definedIn": [ + "CT_Picture" + ], + "types": [ + "a:CT_ShapeProperties" + ] + }, + { + "element": "v:arc", + "name": "arc", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Arc" + ] + }, + { + "element": "v:background", + "name": "background", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Background" + ] + }, + { + "element": "v:curve", + "name": "curve", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Curve" + ] + }, + { + "element": "v:f", + "name": "f", + "prefix": "v", + "domain": "vml", + "definedIn": [ + "CT_Formulas" + ], + "types": [ + "CT_F" + ] + }, + { + "element": "v:fill", + "name": "fill", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Fill" + ] + }, + { + "element": "v:formulas", + "name": "formulas", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Formulas" + ] + }, + { + "element": "v:group", + "name": "group", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Group" + ] + }, + { + "element": "v:h", + "name": "h", + "prefix": "v", + "domain": "vml", + "definedIn": [ + "CT_Handles" + ], + "types": [ + "CT_H" + ] + }, + { + "element": "v:handles", + "name": "handles", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Handles" + ] + }, + { + "element": "v:image", + "name": "image", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Image" + ] + }, + { + "element": "v:imagedata", + "name": "imagedata", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_ImageData" + ] + }, + { + "element": "v:line", + "name": "line", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Line" + ] + }, + { + "element": "v:oval", + "name": "oval", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Oval" + ] + }, + { + "element": "v:path", + "name": "path", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Path" + ] + }, + { + "element": "v:polyline", + "name": "polyline", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_PolyLine" + ] + }, + { + "element": "v:rect", + "name": "rect", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Rect" + ] + }, + { + "element": "v:roundrect", + "name": "roundrect", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_RoundRect" + ] + }, + { + "element": "v:shadow", + "name": "shadow", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Shadow" + ] + }, + { + "element": "v:shape", + "name": "shape", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Shape" + ] + }, + { + "element": "v:shapetype", + "name": "shapetype", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Shapetype" + ] + }, + { + "element": "v:stroke", + "name": "stroke", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Stroke" + ] + }, + { + "element": "v:textbox", + "name": "textbox", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Textbox" + ] + }, + { + "element": "v:textpath", + "name": "textpath", + "prefix": "v", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_TextPath" + ] + }, + { + "element": "w:abstractNum", + "name": "abstractNum", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Numbering" + ], + "types": [ + "CT_AbstractNum" + ] + }, + { + "element": "w:abstractNumId", + "name": "abstractNumId", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Num" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:active", + "name": "active", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RecipientData" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:activeRecord", + "name": "activeRecord", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:activeWritingStyle", + "name": "activeWritingStyle", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_WritingStyle" + ] + }, + { + "element": "w:addressFieldName", + "name": "addressFieldName", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:adjustLineHeightInTable", + "name": "adjustLineHeightInTable", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:adjustRightInd", + "name": "adjustRightInd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:alias", + "name": "alias", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:aliases", + "name": "aliases", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:alignBordersAndEdges", + "name": "alignBordersAndEdges", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:alignTablesRowByRow", + "name": "alignTablesRowByRow", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:allowPNG", + "name": "allowPNG", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:allowSpaceOfSameStyleInTable", + "name": "allowSpaceOfSameStyleInTable", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:altChunk", + "name": "altChunk", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_AltChunk" + ] + }, + { + "element": "w:altChunkPr", + "name": "altChunkPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AltChunk" + ], + "types": [ + "CT_AltChunkPr" + ] + }, + { + "element": "w:altName", + "name": "altName", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:alwaysMergeEmptyNamespace", + "name": "alwaysMergeEmptyNamespace", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:alwaysShowPlaceholderText", + "name": "alwaysShowPlaceholderText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:annotationRef", + "name": "annotationRef", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:applyBreakingRules", + "name": "applyBreakingRules", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:attachedSchema", + "name": "attachedSchema", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:attachedTemplate", + "name": "attachedTemplate", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:attr", + "name": "attr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_CustomXmlPr", + "CT_SmartTagPr" + ], + "types": [ + "CT_Attr" + ] + }, + { + "element": "w:autoCaption", + "name": "autoCaption", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AutoCaptions" + ], + "types": [ + "CT_AutoCaption" + ] + }, + { + "element": "w:autoCaptions", + "name": "autoCaptions", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Captions" + ], + "types": [ + "CT_AutoCaptions" + ] + }, + { + "element": "w:autofitToFirstFixedWidthCell", + "name": "autofitToFirstFixedWidthCell", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:autoFormatOverride", + "name": "autoFormatOverride", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:autoHyphenation", + "name": "autoHyphenation", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:autoRedefine", + "name": "autoRedefine", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:autoSpaceDE", + "name": "autoSpaceDE", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:autoSpaceDN", + "name": "autoSpaceDN", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:autoSpaceLikeWord95", + "name": "autoSpaceLikeWord95", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:b", + "name": "b", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:background", + "name": "background", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocumentBase" + ], + "types": [ + "CT_Background" + ] + }, + { + "element": "w:balanceSingleByteDoubleByteWidth", + "name": "balanceSingleByteDoubleByteWidth", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bar", + "name": "bar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PBdr" + ], + "types": [ + "CT_Border" + ] + }, + { + "element": "w:basedOn", + "name": "basedOn", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:bCs", + "name": "bCs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bdo", + "name": "bdo", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_BdoContentRun" + ] + }, + { + "element": "w:bdr", + "name": "bdr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Border" + ] + }, + { + "element": "w:behavior", + "name": "behavior", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPartBehaviors" + ], + "types": [ + "CT_DocPartBehavior" + ] + }, + { + "element": "w:behaviors", + "name": "behaviors", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPartPr" + ], + "types": [ + "CT_DocPartBehaviors" + ] + }, + { + "element": "w:between", + "name": "between", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PBdr" + ], + "types": [ + "CT_Border" + ] + }, + { + "element": "w:bibliography", + "name": "bibliography", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:bidi", + "name": "bidi", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bidiVisual", + "name": "bidiVisual", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:blockQuote", + "name": "blockQuote", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:body", + "name": "body", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Document" + ], + "types": [ + "CT_Body" + ] + }, + { + "element": "w:bodyDiv", + "name": "bodyDiv", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bookFoldPrinting", + "name": "bookFoldPrinting", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bookFoldPrintingSheets", + "name": "bookFoldPrintingSheets", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:bookFoldRevPrinting", + "name": "bookFoldRevPrinting", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bookmarkEnd", + "name": "bookmarkEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_MarkupRange" + ] + }, + { + "element": "w:bookmarkStart", + "name": "bookmarkStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Bookmark" + ] + }, + { + "element": "w:bordersDoNotSurroundFooter", + "name": "bordersDoNotSurroundFooter", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bordersDoNotSurroundHeader", + "name": "bordersDoNotSurroundHeader", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:bottom", + "name": "bottom", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PBdr", + "CT_PageBorders", + "CT_TcBorders", + "CT_TcMar", + "CT_TblCellMar", + "CT_TblBorders", + "CT_DivBdr" + ], + "types": [ + "CT_Border", + "CT_BottomPageBorder", + "CT_TblWidth" + ] + }, + { + "element": "w:br", + "name": "br", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Br" + ] + }, + { + "element": "w:cachedColBalance", + "name": "cachedColBalance", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:calcOnExit", + "name": "calcOnExit", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:calendar", + "name": "calendar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtDate" + ], + "types": [ + "CT_CalendarType" + ] + }, + { + "element": "w:cantSplit", + "name": "cantSplit", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:caps", + "name": "caps", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:caption", + "name": "caption", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Captions" + ], + "types": [ + "CT_Caption" + ] + }, + { + "element": "w:captions", + "name": "captions", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Captions" + ] + }, + { + "element": "w:category", + "name": "category", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPartPr" + ], + "types": [ + "CT_DocPartCategory" + ] + }, + { + "element": "w:cellDel", + "name": "cellDel", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange" + ] + }, + { + "element": "w:cellIns", + "name": "cellIns", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange" + ] + }, + { + "element": "w:cellMerge", + "name": "cellMerge", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_CellMergeTrackChange" + ] + }, + { + "element": "w:characterSpacingControl", + "name": "characterSpacingControl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_CharacterSpacing" + ] + }, + { + "element": "w:charset", + "name": "charset", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_Charset" + ] + }, + { + "element": "w:checkBox", + "name": "checkBox", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_FFCheckBox" + ] + }, + { + "element": "w:checked", + "name": "checked", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFCheckBox" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:checkErrors", + "name": "checkErrors", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:citation", + "name": "citation", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:clickAndTypeStyle", + "name": "clickAndTypeStyle", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:clrSchemeMapping", + "name": "clrSchemeMapping", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_ColorSchemeMapping" + ] + }, + { + "element": "w:cnfStyle", + "name": "cnfStyle", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_TcPrBase", + "CT_TrPrBase" + ], + "types": [ + "CT_Cnf" + ] + }, + { + "element": "w:col", + "name": "col", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Columns" + ], + "types": [ + "CT_Column" + ] + }, + { + "element": "w:colDelim", + "name": "colDelim", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Odso" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:color", + "name": "color", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_FramesetSplitbar" + ], + "types": [ + "CT_Color" + ] + }, + { + "element": "w:cols", + "name": "cols", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Columns" + ] + }, + { + "element": "w:column", + "name": "column", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RecipientData", + "CT_OdsoFieldMapData" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:comboBox", + "name": "comboBox", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_SdtComboBox" + ] + }, + { + "element": "w:comment", + "name": "comment", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Comments" + ], + "types": [ + "CT_Comment" + ] + }, + { + "element": "w:commentRangeEnd", + "name": "commentRangeEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_MarkupRange" + ] + }, + { + "element": "w:commentRangeStart", + "name": "commentRangeStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_MarkupRange" + ] + }, + { + "element": "w:commentReference", + "name": "commentReference", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Markup" + ] + }, + { + "element": "w:comments", + "name": "comments", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Comments" + ] + }, + { + "element": "w:compat", + "name": "compat", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Compat" + ] + }, + { + "element": "w:compatSetting", + "name": "compatSetting", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_CompatSetting" + ] + }, + { + "element": "w:connectString", + "name": "connectString", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:consecutiveHyphenLimit", + "name": "consecutiveHyphenLimit", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:contentPart", + "name": "contentPart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:contextualSpacing", + "name": "contextualSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:continuationSeparator", + "name": "continuationSeparator", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:control", + "name": "control", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Object", + "CT_Picture" + ], + "types": [ + "CT_Control" + ] + }, + { + "element": "w:convMailMergeEsc", + "name": "convMailMergeEsc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:cr", + "name": "cr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:cs", + "name": "cs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:customXml", + "name": "customXml", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_CustomXmlRun", + "CT_CustomXmlBlock", + "CT_CustomXmlRow", + "CT_CustomXmlCell" + ] + }, + { + "element": "w:customXmlDelRangeEnd", + "name": "customXmlDelRangeEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Markup" + ] + }, + { + "element": "w:customXmlDelRangeStart", + "name": "customXmlDelRangeStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange" + ] + }, + { + "element": "w:customXmlInsRangeEnd", + "name": "customXmlInsRangeEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Markup" + ] + }, + { + "element": "w:customXmlInsRangeStart", + "name": "customXmlInsRangeStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange" + ] + }, + { + "element": "w:customXmlMoveFromRangeEnd", + "name": "customXmlMoveFromRangeEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Markup" + ] + }, + { + "element": "w:customXmlMoveFromRangeStart", + "name": "customXmlMoveFromRangeStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange" + ] + }, + { + "element": "w:customXmlMoveToRangeEnd", + "name": "customXmlMoveToRangeEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Markup" + ] + }, + { + "element": "w:customXmlMoveToRangeStart", + "name": "customXmlMoveToRangeStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange" + ] + }, + { + "element": "w:customXmlPr", + "name": "customXmlPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_CustomXmlRun", + "CT_CustomXmlBlock", + "CT_CustomXmlRow", + "CT_CustomXmlCell" + ], + "types": [ + "CT_CustomXmlPr" + ] + }, + { + "element": "w:dataBinding", + "name": "dataBinding", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_DataBinding" + ] + }, + { + "element": "w:dataSource", + "name": "dataSource", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:dataType", + "name": "dataType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_MailMergeDataType" + ] + }, + { + "element": "w:date", + "name": "date", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_SdtDate" + ] + }, + { + "element": "w:dateFormat", + "name": "dateFormat", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtDate" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:dayLong", + "name": "dayLong", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:dayShort", + "name": "dayShort", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:ddList", + "name": "ddList", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_FFDDList" + ] + }, + { + "element": "w:decimalSymbol", + "name": "decimalSymbol", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:default", + "name": "default", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFCheckBox", + "CT_FFDDList", + "CT_FFTextInput" + ], + "types": [ + "CT_OnOff", + "CT_DecimalNumber", + "CT_String" + ] + }, + { + "element": "w:defaultTableStyle", + "name": "defaultTableStyle", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:defaultTabStop", + "name": "defaultTabStop", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "w:del", + "name": "del", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_MathCtrlIns", + "CT_TrPr" + ], + "types": [ + "CT_MathCtrlDel", + "CT_RPrChange", + "CT_TrackChange", + "CT_RunTrackChange" + ] + }, + { + "element": "w:delInstrText", + "name": "delInstrText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Text" + ] + }, + { + "element": "w:delText", + "name": "delText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Text" + ] + }, + { + "element": "w:description", + "name": "description", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPartPr" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:destination", + "name": "destination", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_MailMergeDest" + ] + }, + { + "element": "w:dir", + "name": "dir", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_DirContentRun" + ] + }, + { + "element": "w:dirty", + "name": "dirty", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RubyPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:displayBackgroundShape", + "name": "displayBackgroundShape", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:displayHangulFixedWidth", + "name": "displayHangulFixedWidth", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:displayHorizontalDrawingGridEvery", + "name": "displayHorizontalDrawingGridEvery", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:displayVerticalDrawingGridEvery", + "name": "displayVerticalDrawingGridEvery", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:div", + "name": "div", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Divs" + ], + "types": [ + "CT_Div" + ] + }, + { + "element": "w:divBdr", + "name": "divBdr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_DivBdr" + ] + }, + { + "element": "w:divId", + "name": "divId", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_TrPrBase" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:divs", + "name": "divs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_Divs" + ] + }, + { + "element": "w:divsChild", + "name": "divsChild", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_Divs" + ] + }, + { + "element": "w:docDefaults", + "name": "docDefaults", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Styles" + ], + "types": [ + "CT_DocDefaults" + ] + }, + { + "element": "w:docGrid", + "name": "docGrid", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_DocGrid" + ] + }, + { + "element": "w:docPart", + "name": "docPart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Placeholder", + "CT_DocParts" + ], + "types": [ + "CT_String", + "CT_DocPart" + ] + }, + { + "element": "w:docPartBody", + "name": "docPartBody", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPart" + ], + "types": [ + "CT_Body" + ] + }, + { + "element": "w:docPartCategory", + "name": "docPartCategory", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtDocPart" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:docPartGallery", + "name": "docPartGallery", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtDocPart" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:docPartList", + "name": "docPartList", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_SdtDocPart" + ] + }, + { + "element": "w:docPartObj", + "name": "docPartObj", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_SdtDocPart" + ] + }, + { + "element": "w:docPartPr", + "name": "docPartPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPart" + ], + "types": [ + "CT_DocPartPr" + ] + }, + { + "element": "w:docParts", + "name": "docParts", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_GlossaryDocument" + ], + "types": [ + "CT_DocParts" + ] + }, + { + "element": "w:docPartUnique", + "name": "docPartUnique", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtDocPart" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:document", + "name": "document", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Document" + ] + }, + { + "element": "w:documentProtection", + "name": "documentProtection", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DocProtect" + ] + }, + { + "element": "w:documentType", + "name": "documentType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DocType" + ] + }, + { + "element": "w:docVar", + "name": "docVar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocVars" + ], + "types": [ + "CT_DocVar" + ] + }, + { + "element": "w:docVars", + "name": "docVars", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DocVars" + ] + }, + { + "element": "w:doNotAutoCompressPictures", + "name": "doNotAutoCompressPictures", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotAutofitConstrainedTables", + "name": "doNotAutofitConstrainedTables", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotBreakConstrainedForcedTable", + "name": "doNotBreakConstrainedForcedTable", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotBreakWrappedTables", + "name": "doNotBreakWrappedTables", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotDemarcateInvalidXml", + "name": "doNotDemarcateInvalidXml", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotDisplayPageBoundaries", + "name": "doNotDisplayPageBoundaries", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotEmbedSmartTags", + "name": "doNotEmbedSmartTags", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotExpandShiftReturn", + "name": "doNotExpandShiftReturn", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotHyphenateCaps", + "name": "doNotHyphenateCaps", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotIncludeSubdocsInStats", + "name": "doNotIncludeSubdocsInStats", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotLeaveBackslashAlone", + "name": "doNotLeaveBackslashAlone", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotOrganizeInFolder", + "name": "doNotOrganizeInFolder", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotRelyOnCSS", + "name": "doNotRelyOnCSS", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotSaveAsSingleFile", + "name": "doNotSaveAsSingleFile", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotShadeFormData", + "name": "doNotShadeFormData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotSnapToGridInCell", + "name": "doNotSnapToGridInCell", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotSuppressBlankLines", + "name": "doNotSuppressBlankLines", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotSuppressIndentation", + "name": "doNotSuppressIndentation", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotSuppressParagraphBorders", + "name": "doNotSuppressParagraphBorders", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotTrackFormatting", + "name": "doNotTrackFormatting", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotTrackMoves", + "name": "doNotTrackMoves", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotUseEastAsianBreakRules", + "name": "doNotUseEastAsianBreakRules", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotUseHTMLParagraphAutoSpacing", + "name": "doNotUseHTMLParagraphAutoSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotUseIndentAsNumberingTabStop", + "name": "doNotUseIndentAsNumberingTabStop", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotUseLongFileNames", + "name": "doNotUseLongFileNames", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotUseMarginsForDrawingGridOrigin", + "name": "doNotUseMarginsForDrawingGridOrigin", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotValidateAgainstSchema", + "name": "doNotValidateAgainstSchema", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotVertAlignCellWithSp", + "name": "doNotVertAlignCellWithSp", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotVertAlignInTxbx", + "name": "doNotVertAlignInTxbx", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:doNotWrapTextWithPunct", + "name": "doNotWrapTextWithPunct", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:drawing", + "name": "drawing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Background", + "CT_Object", + "CT_Empty", + "CT_NumPicBullet" + ], + "types": [ + "CT_Drawing" + ] + }, + { + "element": "w:drawingGridHorizontalOrigin", + "name": "drawingGridHorizontalOrigin", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "w:drawingGridHorizontalSpacing", + "name": "drawingGridHorizontalSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "w:drawingGridVerticalOrigin", + "name": "drawingGridVerticalOrigin", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "w:drawingGridVerticalSpacing", + "name": "drawingGridVerticalSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "w:dropDownList", + "name": "dropDownList", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_SdtDropDownList" + ] + }, + { + "element": "w:dstrike", + "name": "dstrike", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:dynamicAddress", + "name": "dynamicAddress", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_OdsoFieldMapData" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:eastAsianLayout", + "name": "eastAsianLayout", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_EastAsianLayout" + ] + }, + { + "element": "w:effect", + "name": "effect", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TextEffect" + ] + }, + { + "element": "w:em", + "name": "em", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Em" + ] + }, + { + "element": "w:embedBold", + "name": "embedBold", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_FontRel" + ] + }, + { + "element": "w:embedBoldItalic", + "name": "embedBoldItalic", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_FontRel" + ] + }, + { + "element": "w:embedItalic", + "name": "embedItalic", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_FontRel" + ] + }, + { + "element": "w:embedRegular", + "name": "embedRegular", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_FontRel" + ] + }, + { + "element": "w:embedSystemFonts", + "name": "embedSystemFonts", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:embedTrueTypeFonts", + "name": "embedTrueTypeFonts", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:emboss", + "name": "emboss", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:enabled", + "name": "enabled", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:encoding", + "name": "encoding", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:end", + "name": "end", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcBorders", + "CT_TcMar", + "CT_TblCellMar", + "CT_TblBorders" + ], + "types": [ + "CT_Border", + "CT_TblWidth" + ] + }, + { + "element": "w:endnote", + "name": "endnote", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_EdnDocProps", + "CT_Endnotes" + ], + "types": [ + "CT_FtnEdnSepRef", + "CT_FtnEdn" + ] + }, + { + "element": "w:endnotePr", + "name": "endnotePr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_Settings" + ], + "types": [ + "CT_EdnProps", + "CT_EdnDocProps" + ] + }, + { + "element": "w:endnoteRef", + "name": "endnoteRef", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:endnoteReference", + "name": "endnoteReference", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_FtnEdnRef" + ] + }, + { + "element": "w:endnotes", + "name": "endnotes", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Endnotes" + ] + }, + { + "element": "w:entryMacro", + "name": "entryMacro", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_MacroName" + ] + }, + { + "element": "w:equation", + "name": "equation", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:evenAndOddHeaders", + "name": "evenAndOddHeaders", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:exitMacro", + "name": "exitMacro", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_MacroName" + ] + }, + { + "element": "w:family", + "name": "family", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_FontFamily" + ] + }, + { + "element": "w:ffData", + "name": "ffData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FldChar" + ], + "types": [ + "CT_FFData" + ] + }, + { + "element": "w:fHdr", + "name": "fHdr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Odso" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:fieldMapData", + "name": "fieldMapData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Odso" + ], + "types": [ + "CT_OdsoFieldMapData" + ] + }, + { + "element": "w:fitText", + "name": "fitText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_FitText" + ] + }, + { + "element": "w:flatBorders", + "name": "flatBorders", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FramesetSplitbar" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:fldChar", + "name": "fldChar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_FldChar" + ] + }, + { + "element": "w:fldData", + "name": "fldData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SimpleField", + "CT_FldChar" + ], + "types": [ + "CT_Text" + ] + }, + { + "element": "w:fldSimple", + "name": "fldSimple", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_SimpleField" + ] + }, + { + "element": "w:font", + "name": "font", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FontsList" + ], + "types": [ + "CT_Font" + ] + }, + { + "element": "w:fonts", + "name": "fonts", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_FontsList" + ] + }, + { + "element": "w:footerReference", + "name": "footerReference", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_HdrFtrRef" + ] + }, + { + "element": "w:footnote", + "name": "footnote", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FtnDocProps", + "CT_Footnotes" + ], + "types": [ + "CT_FtnEdnSepRef", + "CT_FtnEdn" + ] + }, + { + "element": "w:footnoteLayoutLikeWW8", + "name": "footnoteLayoutLikeWW8", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:footnotePr", + "name": "footnotePr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_Settings" + ], + "types": [ + "CT_FtnProps", + "CT_FtnDocProps" + ] + }, + { + "element": "w:footnoteRef", + "name": "footnoteRef", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:footnoteReference", + "name": "footnoteReference", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_FtnEdnRef" + ] + }, + { + "element": "w:footnotes", + "name": "footnotes", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Footnotes" + ] + }, + { + "element": "w:forceUpgrade", + "name": "forceUpgrade", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:forgetLastTabAlignment", + "name": "forgetLastTabAlignment", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:format", + "name": "format", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFTextInput" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:formProt", + "name": "formProt", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:formsDesign", + "name": "formsDesign", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:frame", + "name": "frame", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frameset" + ], + "types": [ + "CT_Frame" + ] + }, + { + "element": "w:frameLayout", + "name": "frameLayout", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frameset" + ], + "types": [ + "CT_FrameLayout" + ] + }, + { + "element": "w:framePr", + "name": "framePr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_FramePr" + ] + }, + { + "element": "w:frameset", + "name": "frameset", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings", + "CT_Frameset" + ], + "types": [ + "CT_Frameset" + ] + }, + { + "element": "w:framesetSplitbar", + "name": "framesetSplitbar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frameset" + ], + "types": [ + "CT_FramesetSplitbar" + ] + }, + { + "element": "w:ftr", + "name": "ftr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_HdrFtr" + ] + }, + { + "element": "w:gallery", + "name": "gallery", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPartCategory" + ], + "types": [ + "CT_DocPartGallery" + ] + }, + { + "element": "w:glossaryDocument", + "name": "glossaryDocument", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_GlossaryDocument" + ] + }, + { + "element": "w:gridAfter", + "name": "gridAfter", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:gridBefore", + "name": "gridBefore", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:gridCol", + "name": "gridCol", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblGridBase" + ], + "types": [ + "CT_TblGridCol" + ] + }, + { + "element": "w:gridSpan", + "name": "gridSpan", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:group", + "name": "group", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:growAutofit", + "name": "growAutofit", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:guid", + "name": "guid", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPartPr" + ], + "types": [ + "CT_Guid" + ] + }, + { + "element": "w:gutterAtTop", + "name": "gutterAtTop", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:hdr", + "name": "hdr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_HdrFtr" + ] + }, + { + "element": "w:hdrShapeDefaults", + "name": "hdrShapeDefaults", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_ShapeDefaults" + ] + }, + { + "element": "w:header", + "name": "header", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Headers" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:headerReference", + "name": "headerReference", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_HdrFtrRef" + ] + }, + { + "element": "w:headers", + "name": "headers", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_Headers" + ] + }, + { + "element": "w:headerSource", + "name": "headerSource", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:helpText", + "name": "helpText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_FFHelpText" + ] + }, + { + "element": "w:hidden", + "name": "hidden", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase", + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:hideGrammaticalErrors", + "name": "hideGrammaticalErrors", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:hideMark", + "name": "hideMark", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:hideSpellingErrors", + "name": "hideSpellingErrors", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:highlight", + "name": "highlight", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Highlight" + ] + }, + { + "element": "w:hMerge", + "name": "hMerge", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_HMerge" + ] + }, + { + "element": "w:hps", + "name": "hps", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RubyPr" + ], + "types": [ + "CT_HpsMeasure" + ] + }, + { + "element": "w:hpsBaseText", + "name": "hpsBaseText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RubyPr" + ], + "types": [ + "CT_HpsMeasure" + ] + }, + { + "element": "w:hpsRaise", + "name": "hpsRaise", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RubyPr" + ], + "types": [ + "CT_HpsMeasure" + ] + }, + { + "element": "w:hyperlink", + "name": "hyperlink", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Hyperlink" + ] + }, + { + "element": "w:hyphenationZone", + "name": "hyphenationZone", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_TwipsMeasure" + ] + }, + { + "element": "w:i", + "name": "i", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:iCs", + "name": "iCs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:id", + "name": "id", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:ignoreMixedContent", + "name": "ignoreMixedContent", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:ilvl", + "name": "ilvl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_NumPr" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:imprint", + "name": "imprint", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:ind", + "name": "ind", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_Ind" + ] + }, + { + "element": "w:ins", + "name": "ins", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_NumPr", + "CT_Empty", + "CT_TrPr" + ], + "types": [ + "CT_TrackChange", + "CT_MathCtrlIns", + "CT_RunTrackChange" + ] + }, + { + "element": "w:insideH", + "name": "insideH", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcBorders", + "CT_TblBorders" + ], + "types": [ + "CT_Border" + ] + }, + { + "element": "w:insideV", + "name": "insideV", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcBorders", + "CT_TblBorders" + ], + "types": [ + "CT_Border" + ] + }, + { + "element": "w:instrText", + "name": "instrText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Text" + ] + }, + { + "element": "w:isLgl", + "name": "isLgl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Lvl" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:jc", + "name": "jc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_TrPrBase", + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_Jc", + "CT_JcTable" + ] + }, + { + "element": "w:keepLines", + "name": "keepLines", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:keepNext", + "name": "keepNext", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:kern", + "name": "kern", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_HpsMeasure" + ] + }, + { + "element": "w:kinsoku", + "name": "kinsoku", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:label", + "name": "label", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData", + "CT_SdtPr" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:lang", + "name": "lang", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Language" + ] + }, + { + "element": "w:lastRenderedPageBreak", + "name": "lastRenderedPageBreak", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:latentStyles", + "name": "latentStyles", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Styles" + ], + "types": [ + "CT_LatentStyles" + ] + }, + { + "element": "w:layoutRawTableWidth", + "name": "layoutRawTableWidth", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:layoutTableRowsApart", + "name": "layoutTableRowsApart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:left", + "name": "left", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PBdr", + "CT_PageBorders", + "CT_TcBorders", + "CT_TcMar", + "CT_TblCellMar", + "CT_TblBorders", + "CT_DivBdr" + ], + "types": [ + "CT_Border", + "CT_PageBorder", + "CT_TblWidth" + ] + }, + { + "element": "w:legacy", + "name": "legacy", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Lvl" + ], + "types": [ + "CT_LvlLegacy" + ] + }, + { + "element": "w:lid", + "name": "lid", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RubyPr", + "CT_SdtDate", + "CT_OdsoFieldMapData" + ], + "types": [ + "CT_Lang" + ] + }, + { + "element": "w:lineWrapLikeWord6", + "name": "lineWrapLikeWord6", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:link", + "name": "link", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:linkedToFile", + "name": "linkedToFile", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:linkStyles", + "name": "linkStyles", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:linkToQuery", + "name": "linkToQuery", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:listEntry", + "name": "listEntry", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFDDList" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:listItem", + "name": "listItem", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtComboBox", + "CT_SdtDropDownList" + ], + "types": [ + "CT_SdtListItem" + ] + }, + { + "element": "w:listSeparator", + "name": "listSeparator", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:lnNumType", + "name": "lnNumType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_LineNumber" + ] + }, + { + "element": "w:lock", + "name": "lock", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_Lock" + ] + }, + { + "element": "w:locked", + "name": "locked", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:longDesc", + "name": "longDesc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:lsdException", + "name": "lsdException", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_LatentStyles" + ], + "types": [ + "CT_LsdException" + ] + }, + { + "element": "w:lvl", + "name": "lvl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AbstractNum", + "CT_NumLvl" + ], + "types": [ + "CT_Lvl" + ] + }, + { + "element": "w:lvlJc", + "name": "lvlJc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Lvl" + ], + "types": [ + "CT_Jc" + ] + }, + { + "element": "w:lvlOverride", + "name": "lvlOverride", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Num" + ], + "types": [ + "CT_NumLvl" + ] + }, + { + "element": "w:lvlPicBulletId", + "name": "lvlPicBulletId", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Lvl" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:lvlRestart", + "name": "lvlRestart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Lvl" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:lvlText", + "name": "lvlText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Lvl" + ], + "types": [ + "CT_LevelText" + ] + }, + { + "element": "w:mailAsAttachment", + "name": "mailAsAttachment", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:mailMerge", + "name": "mailMerge", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_MailMerge" + ] + }, + { + "element": "w:mailSubject", + "name": "mailSubject", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:mainDocumentType", + "name": "mainDocumentType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_MailMergeDocType" + ] + }, + { + "element": "w:mappedName", + "name": "mappedName", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_OdsoFieldMapData" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:marBottom", + "name": "marBottom", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_SignedTwipsMeasure" + ] + }, + { + "element": "w:marH", + "name": "marH", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame" + ], + "types": [ + "CT_PixelsMeasure" + ] + }, + { + "element": "w:marLeft", + "name": "marLeft", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_SignedTwipsMeasure" + ] + }, + { + "element": "w:marRight", + "name": "marRight", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_SignedTwipsMeasure" + ] + }, + { + "element": "w:marTop", + "name": "marTop", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Div" + ], + "types": [ + "CT_SignedTwipsMeasure" + ] + }, + { + "element": "w:marW", + "name": "marW", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame" + ], + "types": [ + "CT_PixelsMeasure" + ] + }, + { + "element": "w:matchSrc", + "name": "matchSrc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AltChunkPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:maxLength", + "name": "maxLength", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFTextInput" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:mirrorIndents", + "name": "mirrorIndents", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:mirrorMargins", + "name": "mirrorMargins", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:monthLong", + "name": "monthLong", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:monthShort", + "name": "monthShort", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:moveFrom", + "name": "moveFrom", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange", + "CT_RunTrackChange" + ] + }, + { + "element": "w:moveFromRangeEnd", + "name": "moveFromRangeEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_MarkupRange" + ] + }, + { + "element": "w:moveFromRangeStart", + "name": "moveFromRangeStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_MoveBookmark" + ] + }, + { + "element": "w:moveTo", + "name": "moveTo", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TrackChange", + "CT_RunTrackChange" + ] + }, + { + "element": "w:moveToRangeEnd", + "name": "moveToRangeEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_MarkupRange" + ] + }, + { + "element": "w:moveToRangeStart", + "name": "moveToRangeStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_MoveBookmark" + ] + }, + { + "element": "w:movie", + "name": "movie", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Object", + "CT_Picture" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:multiLevelType", + "name": "multiLevelType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AbstractNum" + ], + "types": [ + "CT_MultiLevelType" + ] + }, + { + "element": "w:mwSmallCaps", + "name": "mwSmallCaps", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:name", + "name": "name", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData", + "CT_OdsoFieldMapData", + "CT_Frame", + "CT_AbstractNum", + "CT_Style", + "CT_DocPartCategory", + "CT_DocPartPr" + ], + "types": [ + "CT_FFName", + "CT_String", + "CT_DocPartName" + ] + }, + { + "element": "w:next", + "name": "next", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:noBorder", + "name": "noBorder", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FramesetSplitbar" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noBreakHyphen", + "name": "noBreakHyphen", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:noColumnBalance", + "name": "noColumnBalance", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noEndnote", + "name": "noEndnote", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noExtraLineSpacing", + "name": "noExtraLineSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noLeading", + "name": "noLeading", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noLineBreaksAfter", + "name": "noLineBreaksAfter", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Kinsoku" + ] + }, + { + "element": "w:noLineBreaksBefore", + "name": "noLineBreaksBefore", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Kinsoku" + ] + }, + { + "element": "w:noProof", + "name": "noProof", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noPunctuationKerning", + "name": "noPunctuationKerning", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noResizeAllowed", + "name": "noResizeAllowed", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noSpaceRaiseLower", + "name": "noSpaceRaiseLower", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noTabHangInd", + "name": "noTabHangInd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:notTrueType", + "name": "notTrueType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:noWrap", + "name": "noWrap", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:nsid", + "name": "nsid", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AbstractNum" + ], + "types": [ + "CT_LongHexNumber" + ] + }, + { + "element": "w:num", + "name": "num", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Numbering" + ], + "types": [ + "CT_Num" + ] + }, + { + "element": "w:numbering", + "name": "numbering", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Numbering" + ] + }, + { + "element": "w:numberingChange", + "name": "numberingChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_NumPr", + "CT_FldChar" + ], + "types": [ + "CT_TrackChangeNumbering" + ] + }, + { + "element": "w:numFmt", + "name": "numFmt", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FtnProps", + "CT_EdnProps", + "CT_Lvl" + ], + "types": [ + "CT_NumFmt" + ] + }, + { + "element": "w:numId", + "name": "numId", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_NumPr" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:numIdMacAtCleanup", + "name": "numIdMacAtCleanup", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Numbering" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:numPicBullet", + "name": "numPicBullet", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Numbering" + ], + "types": [ + "CT_NumPicBullet" + ] + }, + { + "element": "w:numPr", + "name": "numPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_NumPr" + ] + }, + { + "element": "w:numRestart", + "name": "numRestart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_NumRestart" + ] + }, + { + "element": "w:numStart", + "name": "numStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:numStyleLink", + "name": "numStyleLink", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AbstractNum" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:object", + "name": "object", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Object" + ] + }, + { + "element": "w:objectEmbed", + "name": "objectEmbed", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Object" + ], + "types": [ + "CT_ObjectEmbed" + ] + }, + { + "element": "w:objectLink", + "name": "objectLink", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Object" + ], + "types": [ + "CT_ObjectLink" + ] + }, + { + "element": "w:odso", + "name": "odso", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_Odso" + ] + }, + { + "element": "w:oMath", + "name": "oMath", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:optimizeForBrowser", + "name": "optimizeForBrowser", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OptimizeForBrowser" + ] + }, + { + "element": "w:outline", + "name": "outline", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:outlineLvl", + "name": "outlineLvl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:overflowPunct", + "name": "overflowPunct", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:p", + "name": "p", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_P" + ] + }, + { + "element": "w:pageBreakBefore", + "name": "pageBreakBefore", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:panose1", + "name": "panose1", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_Panose" + ] + }, + { + "element": "w:paperSrc", + "name": "paperSrc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_PaperSource" + ] + }, + { + "element": "w:pBdr", + "name": "pBdr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_PBdr" + ] + }, + { + "element": "w:permEnd", + "name": "permEnd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [] + }, + { + "element": "w:permStart", + "name": "permStart", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [] + }, + { + "element": "w:personal", + "name": "personal", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:personalCompose", + "name": "personalCompose", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:personalReply", + "name": "personalReply", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:pgBorders", + "name": "pgBorders", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_PageBorders" + ] + }, + { + "element": "w:pgMar", + "name": "pgMar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_PageMar" + ] + }, + { + "element": "w:pgNum", + "name": "pgNum", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:pgNumType", + "name": "pgNumType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_PageNumber" + ] + }, + { + "element": "w:pgSz", + "name": "pgSz", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_PageSz" + ] + }, + { + "element": "w:pict", + "name": "pict", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_NumPicBullet" + ], + "types": [ + "CT_Picture" + ] + }, + { + "element": "w:picture", + "name": "picture", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:pitch", + "name": "pitch", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_Pitch" + ] + }, + { + "element": "w:pixelsPerInch", + "name": "pixelsPerInch", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:placeholder", + "name": "placeholder", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr", + "CT_CustomXmlPr" + ], + "types": [ + "CT_Placeholder", + "CT_String" + ] + }, + { + "element": "w:pos", + "name": "pos", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FtnProps", + "CT_EdnProps" + ], + "types": [ + "CT_FtnPos", + "CT_EdnPos" + ] + }, + { + "element": "w:position", + "name": "position", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_SignedHpsMeasure" + ] + }, + { + "element": "w:pPr", + "name": "pPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrChange", + "CT_P", + "CT_PPrDefault", + "CT_Lvl", + "CT_TblStylePr", + "CT_Style" + ], + "types": [ + "CT_PPrBase", + "CT_PPr", + "CT_PPrGeneral" + ] + }, + { + "element": "w:pPrChange", + "name": "pPrChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPr", + "CT_PPrGeneral" + ], + "types": [ + "CT_PPrChange" + ] + }, + { + "element": "w:pPrDefault", + "name": "pPrDefault", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocDefaults" + ], + "types": [ + "CT_PPrDefault" + ] + }, + { + "element": "w:printBodyTextBeforeHeader", + "name": "printBodyTextBeforeHeader", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:printColBlack", + "name": "printColBlack", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:printerSettings", + "name": "printerSettings", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:printFormsData", + "name": "printFormsData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:printFractionalCharacterWidth", + "name": "printFractionalCharacterWidth", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:printPostScriptOverText", + "name": "printPostScriptOverText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:printTwoOnOne", + "name": "printTwoOnOne", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:proofErr", + "name": "proofErr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [] + }, + { + "element": "w:proofState", + "name": "proofState", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Proof" + ] + }, + { + "element": "w:pStyle", + "name": "pStyle", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_Lvl" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:ptab", + "name": "ptab", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_PTab" + ] + }, + { + "element": "w:qFormat", + "name": "qFormat", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:query", + "name": "query", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:r", + "name": "r", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_R" + ] + }, + { + "element": "w:readModeInkLockDown", + "name": "readModeInkLockDown", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_ReadingModeInkLockDown" + ] + }, + { + "element": "w:recipientData", + "name": "recipientData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Recipients", + "CT_Odso" + ], + "types": [ + "CT_RecipientData", + "CT_Rel" + ] + }, + { + "element": "w:recipients", + "name": "recipients", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Recipients" + ] + }, + { + "element": "w:relyOnVML", + "name": "relyOnVML", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:removeDateAndTime", + "name": "removeDateAndTime", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:removePersonalInformation", + "name": "removePersonalInformation", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:result", + "name": "result", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFDDList" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:revisionView", + "name": "revisionView", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_TrackChangesView" + ] + }, + { + "element": "w:rFonts", + "name": "rFonts", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Fonts" + ] + }, + { + "element": "w:richText", + "name": "richText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:right", + "name": "right", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PBdr", + "CT_PageBorders", + "CT_TcBorders", + "CT_TcMar", + "CT_TblCellMar", + "CT_TblBorders", + "CT_DivBdr" + ], + "types": [ + "CT_Border", + "CT_PageBorder", + "CT_TblWidth" + ] + }, + { + "element": "w:rPr", + "name": "rPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RPrChange", + "CT_ParaRPrChange", + "CT_PPr", + "CT_Empty", + "CT_MathCtrlIns", + "CT_MathCtrlDel", + "CT_SdtPr", + "CT_SdtEndPr", + "CT_RPrDefault", + "CT_Lvl", + "CT_TblStylePr", + "CT_Style" + ], + "types": [ + "CT_RPrOriginal", + "CT_ParaRPrOriginal", + "CT_ParaRPr", + "CT_RPr" + ] + }, + { + "element": "w:rPrChange", + "name": "rPrChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_ParaRPr" + ], + "types": [ + "CT_RPrChange", + "CT_ParaRPrChange" + ] + }, + { + "element": "w:rPrDefault", + "name": "rPrDefault", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocDefaults" + ], + "types": [ + "CT_RPrDefault" + ] + }, + { + "element": "w:rsid", + "name": "rsid", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocRsids", + "CT_Style" + ], + "types": [ + "CT_LongHexNumber" + ] + }, + { + "element": "w:rsidRoot", + "name": "rsidRoot", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocRsids" + ], + "types": [ + "CT_LongHexNumber" + ] + }, + { + "element": "w:rsids", + "name": "rsids", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DocRsids" + ] + }, + { + "element": "w:rStyle", + "name": "rStyle", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:rt", + "name": "rt", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Ruby" + ], + "types": [ + "CT_RubyContent" + ] + }, + { + "element": "w:rtl", + "name": "rtl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:rtlGutter", + "name": "rtlGutter", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:ruby", + "name": "ruby", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Ruby" + ] + }, + { + "element": "w:rubyAlign", + "name": "rubyAlign", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RubyPr" + ], + "types": [ + "CT_RubyAlign" + ] + }, + { + "element": "w:rubyBase", + "name": "rubyBase", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Ruby" + ], + "types": [ + "CT_RubyContent" + ] + }, + { + "element": "w:rubyPr", + "name": "rubyPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Ruby" + ], + "types": [ + "CT_RubyPr" + ] + }, + { + "element": "w:saveFormsData", + "name": "saveFormsData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:saveInvalidXml", + "name": "saveInvalidXml", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:savePreviewPicture", + "name": "savePreviewPicture", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:saveSmartTagsAsXml", + "name": "saveSmartTagsAsXml", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:saveSubsetFonts", + "name": "saveSubsetFonts", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:saveThroughXslt", + "name": "saveThroughXslt", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_SaveThroughXslt" + ] + }, + { + "element": "w:saveXmlDataOnly", + "name": "saveXmlDataOnly", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:scrollbar", + "name": "scrollbar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame" + ], + "types": [ + "CT_FrameScrollbar" + ] + }, + { + "element": "w:sdt", + "name": "sdt", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_SdtRun", + "CT_SdtBlock", + "CT_SdtRow", + "CT_SdtCell" + ] + }, + { + "element": "w:sdtContent", + "name": "sdtContent", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtBlock", + "CT_SdtRun", + "CT_SdtCell", + "CT_SdtRow" + ], + "types": [ + "CT_SdtContentBlock", + "CT_SdtContentRun", + "CT_SdtContentCell", + "CT_SdtContentRow" + ] + }, + { + "element": "w:sdtEndPr", + "name": "sdtEndPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtBlock", + "CT_SdtRun", + "CT_SdtCell", + "CT_SdtRow" + ], + "types": [ + "CT_SdtEndPr" + ] + }, + { + "element": "w:sdtPr", + "name": "sdtPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtBlock", + "CT_SdtRun", + "CT_SdtCell", + "CT_SdtRow" + ], + "types": [ + "CT_SdtPr" + ] + }, + { + "element": "w:sectPr", + "name": "sectPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SectPrChange", + "CT_PPr", + "CT_Body" + ], + "types": [ + "CT_SectPrBase", + "CT_SectPr" + ] + }, + { + "element": "w:sectPrChange", + "name": "sectPrChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SectPr" + ], + "types": [ + "CT_SectPrChange" + ] + }, + { + "element": "w:selectFldWithFirstOrLastChar", + "name": "selectFldWithFirstOrLastChar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:semiHidden", + "name": "semiHidden", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:separator", + "name": "separator", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:settings", + "name": "settings", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Settings" + ] + }, + { + "element": "w:shadow", + "name": "shadow", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:shapeDefaults", + "name": "shapeDefaults", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_ShapeDefaults" + ] + }, + { + "element": "w:shapeLayoutLikeWW8", + "name": "shapeLayoutLikeWW8", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:shd", + "name": "shd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_Empty", + "CT_TcPrBase", + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_Shd" + ] + }, + { + "element": "w:showBreaksInFrames", + "name": "showBreaksInFrames", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:showEnvelope", + "name": "showEnvelope", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:showingPlcHdr", + "name": "showingPlcHdr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:showXMLTags", + "name": "showXMLTags", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:sig", + "name": "sig", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Font" + ], + "types": [ + "CT_FontSig" + ] + }, + { + "element": "w:size", + "name": "size", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFCheckBox" + ], + "types": [ + "CT_HpsMeasure" + ] + }, + { + "element": "w:sizeAuto", + "name": "sizeAuto", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFCheckBox" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:smallCaps", + "name": "smallCaps", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:smartTag", + "name": "smartTag", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_SmartTagRun" + ] + }, + { + "element": "w:smartTagPr", + "name": "smartTagPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SmartTagRun" + ], + "types": [ + "CT_SmartTagPr" + ] + }, + { + "element": "w:smartTagType", + "name": "smartTagType", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_SmartTagType" + ] + }, + { + "element": "w:snapToGrid", + "name": "snapToGrid", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:softHyphen", + "name": "softHyphen", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:sourceFileName", + "name": "sourceFileName", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:spaceForUL", + "name": "spaceForUL", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:spacing", + "name": "spacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_Empty" + ], + "types": [ + "CT_Spacing", + "CT_SignedTwipsMeasure" + ] + }, + { + "element": "w:spacingInWholePoints", + "name": "spacingInWholePoints", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:specVanish", + "name": "specVanish", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:splitPgBreakAndParaMark", + "name": "splitPgBreakAndParaMark", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:src", + "name": "src", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Odso" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:start", + "name": "start", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcBorders", + "CT_TcMar", + "CT_TblCellMar", + "CT_TblBorders", + "CT_Lvl" + ], + "types": [ + "CT_Border", + "CT_TblWidth", + "CT_DecimalNumber" + ] + }, + { + "element": "w:startOverride", + "name": "startOverride", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_NumLvl" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:statusText", + "name": "statusText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_FFStatusText" + ] + }, + { + "element": "w:storeMappedDataAs", + "name": "storeMappedDataAs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtDate" + ], + "types": [ + "CT_SdtDateMappingType" + ] + }, + { + "element": "w:strictFirstAndLastChars", + "name": "strictFirstAndLastChars", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:strike", + "name": "strike", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:style", + "name": "style", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Styles", + "CT_DocPartPr" + ], + "types": [ + "CT_Style", + "CT_String" + ] + }, + { + "element": "w:styleLink", + "name": "styleLink", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AbstractNum" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:styleLockQFSet", + "name": "styleLockQFSet", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:styleLockTheme", + "name": "styleLockTheme", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:stylePaneFormatFilter", + "name": "stylePaneFormatFilter", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_StylePaneFilter" + ] + }, + { + "element": "w:stylePaneSortMethod", + "name": "stylePaneSortMethod", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_StyleSort" + ] + }, + { + "element": "w:styles", + "name": "styles", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Styles" + ] + }, + { + "element": "w:subDoc", + "name": "subDoc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Rel" + ] + }, + { + "element": "w:subFontBySize", + "name": "subFontBySize", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suff", + "name": "suff", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Lvl" + ], + "types": [ + "CT_LevelSuffix" + ] + }, + { + "element": "w:summaryLength", + "name": "summaryLength", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_DecimalNumberOrPrecent" + ] + }, + { + "element": "w:suppressAutoHyphens", + "name": "suppressAutoHyphens", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suppressBottomSpacing", + "name": "suppressBottomSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suppressLineNumbers", + "name": "suppressLineNumbers", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suppressOverlap", + "name": "suppressOverlap", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suppressSpacingAtTopOfPage", + "name": "suppressSpacingAtTopOfPage", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suppressSpBfAfterPgBrk", + "name": "suppressSpBfAfterPgBrk", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suppressTopSpacing", + "name": "suppressTopSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:suppressTopSpacingWP", + "name": "suppressTopSpacingWP", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:swapBordersFacingPages", + "name": "swapBordersFacingPages", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:sym", + "name": "sym", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Sym" + ] + }, + { + "element": "w:sz", + "name": "sz", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_Frame", + "CT_Frameset" + ], + "types": [ + "CT_HpsMeasure", + "CT_String" + ] + }, + { + "element": "w:szCs", + "name": "szCs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_HpsMeasure" + ] + }, + { + "element": "w:t", + "name": "t", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Text" + ] + }, + { + "element": "w:tab", + "name": "tab", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Tabs", + "CT_Empty" + ], + "types": [ + "CT_TabStop", + "CT_Empty" + ] + }, + { + "element": "w:tabIndex", + "name": "tabIndex", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData", + "CT_SdtPr" + ], + "types": [ + "CT_UnsignedDecimalNumber" + ] + }, + { + "element": "w:table", + "name": "table", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Odso" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:tabs", + "name": "tabs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_Tabs" + ] + }, + { + "element": "w:tag", + "name": "tag", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:targetScreenSz", + "name": "targetScreenSz", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_WebSettings" + ], + "types": [ + "CT_TargetScreenSz" + ] + }, + { + "element": "w:tbl", + "name": "tbl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Tbl" + ] + }, + { + "element": "w:tblBorders", + "name": "tblBorders", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_TblBorders" + ] + }, + { + "element": "w:tblCaption", + "name": "tblCaption", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:tblCellMar", + "name": "tblCellMar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_TblCellMar" + ] + }, + { + "element": "w:tblCellSpacing", + "name": "tblCellSpacing", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase", + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_TblWidth" + ] + }, + { + "element": "w:tblDescription", + "name": "tblDescription", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:tblGrid", + "name": "tblGrid", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblGridChange", + "CT_Tbl" + ], + "types": [ + "CT_TblGridBase", + "CT_TblGrid" + ] + }, + { + "element": "w:tblGridChange", + "name": "tblGridChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblGrid" + ], + "types": [ + "CT_TblGridChange" + ] + }, + { + "element": "w:tblHeader", + "name": "tblHeader", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:tblInd", + "name": "tblInd", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_TblWidth" + ] + }, + { + "element": "w:tblLayout", + "name": "tblLayout", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_TblLayoutType" + ] + }, + { + "element": "w:tblLook", + "name": "tblLook", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_TblLook" + ] + }, + { + "element": "w:tblOverlap", + "name": "tblOverlap", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_TblOverlap" + ] + }, + { + "element": "w:tblpPr", + "name": "tblpPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_TblPPr" + ] + }, + { + "element": "w:tblPr", + "name": "tblPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrChange", + "CT_Tbl", + "CT_TblStylePr", + "CT_Style" + ], + "types": [ + "CT_TblPrBase", + "CT_TblPr" + ] + }, + { + "element": "w:tblPrChange", + "name": "tblPrChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPr" + ], + "types": [ + "CT_TblPrChange" + ] + }, + { + "element": "w:tblPrEx", + "name": "tblPrEx", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrExChange", + "CT_Row" + ], + "types": [ + "CT_TblPrExBase", + "CT_TblPrEx" + ] + }, + { + "element": "w:tblPrExChange", + "name": "tblPrExChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrEx" + ], + "types": [ + "CT_TblPrExChange" + ] + }, + { + "element": "w:tblStyle", + "name": "tblStyle", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:tblStyleColBandSize", + "name": "tblStyleColBandSize", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:tblStylePr", + "name": "tblStylePr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_TblStylePr" + ] + }, + { + "element": "w:tblStyleRowBandSize", + "name": "tblStyleRowBandSize", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:tblW", + "name": "tblW", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TblPrBase", + "CT_TblPrExBase" + ], + "types": [ + "CT_TblWidth" + ] + }, + { + "element": "w:tc", + "name": "tc", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Tc" + ] + }, + { + "element": "w:tcBorders", + "name": "tcBorders", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_TcBorders" + ] + }, + { + "element": "w:tcFitText", + "name": "tcFitText", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:tcMar", + "name": "tcMar", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_TcMar" + ] + }, + { + "element": "w:tcPr", + "name": "tcPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrChange", + "CT_Tc", + "CT_TblStylePr", + "CT_Style" + ], + "types": [ + "CT_TcPrInner", + "CT_TcPr" + ] + }, + { + "element": "w:tcPrChange", + "name": "tcPrChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPr" + ], + "types": [ + "CT_TcPrChange" + ] + }, + { + "element": "w:tcW", + "name": "tcW", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_TblWidth" + ] + }, + { + "element": "w:temporary", + "name": "temporary", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:text", + "name": "text", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_SdtPr" + ], + "types": [ + "CT_SdtText" + ] + }, + { + "element": "w:textAlignment", + "name": "textAlignment", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_TextAlignment" + ] + }, + { + "element": "w:textboxTightWrap", + "name": "textboxTightWrap", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_TextboxTightWrap" + ] + }, + { + "element": "w:textDirection", + "name": "textDirection", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase", + "CT_Empty", + "CT_TcPrBase" + ], + "types": [ + "CT_TextDirection" + ] + }, + { + "element": "w:textInput", + "name": "textInput", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFData" + ], + "types": [ + "CT_FFTextInput" + ] + }, + { + "element": "w:themeFontLang", + "name": "themeFontLang", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Language" + ] + }, + { + "element": "w:title", + "name": "title", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Frame", + "CT_Frameset" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:titlePg", + "name": "titlePg", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:tl2br", + "name": "tl2br", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcBorders" + ], + "types": [ + "CT_Border" + ] + }, + { + "element": "w:tmpl", + "name": "tmpl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_AbstractNum" + ], + "types": [ + "CT_LongHexNumber" + ] + }, + { + "element": "w:top", + "name": "top", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PBdr", + "CT_PageBorders", + "CT_TcBorders", + "CT_TcMar", + "CT_TblCellMar", + "CT_TblBorders", + "CT_DivBdr" + ], + "types": [ + "CT_Border", + "CT_TopPageBorder", + "CT_TblWidth" + ] + }, + { + "element": "w:topLinePunct", + "name": "topLinePunct", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:tr", + "name": "tr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Row" + ] + }, + { + "element": "w:tr2bl", + "name": "tr2bl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcBorders" + ], + "types": [ + "CT_Border" + ] + }, + { + "element": "w:trackRevisions", + "name": "trackRevisions", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:trHeight", + "name": "trHeight", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase" + ], + "types": [ + "CT_Height" + ] + }, + { + "element": "w:trPr", + "name": "trPr", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrChange", + "CT_Row", + "CT_TblStylePr", + "CT_Style" + ], + "types": [ + "CT_TrPrBase", + "CT_TrPr" + ] + }, + { + "element": "w:trPrChange", + "name": "trPrChange", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPr" + ], + "types": [ + "CT_TrPrChange" + ] + }, + { + "element": "w:truncateFontHeightsLikeWP6", + "name": "truncateFontHeightsLikeWP6", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:txbxContent", + "name": "txbxContent", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_TxbxContent" + ] + }, + { + "element": "w:type", + "name": "type", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_FFTextInput", + "CT_Empty", + "CT_OdsoFieldMapData", + "CT_Odso", + "CT_DocPartTypes" + ], + "types": [ + "CT_FFTextType", + "CT_SectType", + "CT_MailMergeOdsoFMDFieldType", + "CT_MailMergeSourceType", + "CT_DocPartType" + ] + }, + { + "element": "w:types", + "name": "types", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_DocPartPr" + ], + "types": [ + "CT_DocPartTypes" + ] + }, + { + "element": "w:u", + "name": "u", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Underline" + ] + }, + { + "element": "w:udl", + "name": "udl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Odso" + ], + "types": [ + "CT_String" + ] + }, + { + "element": "w:uiPriority", + "name": "uiPriority", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_DecimalNumber" + ] + }, + { + "element": "w:ulTrailSpace", + "name": "ulTrailSpace", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:underlineTabInNumList", + "name": "underlineTabInNumList", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:unhideWhenUsed", + "name": "unhideWhenUsed", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Style" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:uniqueTag", + "name": "uniqueTag", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_RecipientData" + ], + "types": [ + "CT_Base64Binary" + ] + }, + { + "element": "w:updateFields", + "name": "updateFields", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useAltKinsokuLineBreakRules", + "name": "useAltKinsokuLineBreakRules", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useAnsiKerningPairs", + "name": "useAnsiKerningPairs", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useFELayout", + "name": "useFELayout", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useNormalStyleForList", + "name": "useNormalStyleForList", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:usePrinterMetrics", + "name": "usePrinterMetrics", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useSingleBorderforContiguousCells", + "name": "useSingleBorderforContiguousCells", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useWord2002TableStyleRules", + "name": "useWord2002TableStyleRules", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useWord97LineBreakRules", + "name": "useWord97LineBreakRules", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:useXSLTWhenSaving", + "name": "useXSLTWhenSaving", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:vAlign", + "name": "vAlign", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_TcPrBase" + ], + "types": [ + "CT_VerticalJc" + ] + }, + { + "element": "w:vanish", + "name": "vanish", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:vertAlign", + "name": "vertAlign", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_VerticalAlignRun" + ] + }, + { + "element": "w:view", + "name": "view", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_View" + ] + }, + { + "element": "w:viewMergedData", + "name": "viewMergedData", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_MailMerge" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:vMerge", + "name": "vMerge", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TcPrBase" + ], + "types": [ + "CT_VMerge" + ] + }, + { + "element": "w:w", + "name": "w", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty", + "CT_FramesetSplitbar" + ], + "types": [ + "CT_TextScale", + "CT_TwipsMeasure" + ] + }, + { + "element": "w:wAfter", + "name": "wAfter", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase" + ], + "types": [ + "CT_TblWidth" + ] + }, + { + "element": "w:wBefore", + "name": "wBefore", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_TrPrBase" + ], + "types": [ + "CT_TblWidth" + ] + }, + { + "element": "w:webHidden", + "name": "webHidden", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:webSettings", + "name": "webSettings", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_WebSettings" + ] + }, + { + "element": "w:widowControl", + "name": "widowControl", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:wordWrap", + "name": "wordWrap", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_PPrBase" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:wpJustification", + "name": "wpJustification", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:wpSpaceWidth", + "name": "wpSpaceWidth", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:wrapTrailSpaces", + "name": "wrapTrailSpaces", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Compat" + ], + "types": [ + "CT_OnOff" + ] + }, + { + "element": "w:writeProtection", + "name": "writeProtection", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_WriteProtection" + ] + }, + { + "element": "w:yearLong", + "name": "yearLong", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:yearShort", + "name": "yearShort", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Empty" + ], + "types": [ + "CT_Empty" + ] + }, + { + "element": "w:zoom", + "name": "zoom", + "prefix": "w", + "domain": "wml", + "definedIn": [ + "CT_Settings" + ], + "types": [ + "CT_Zoom" + ] + }, + { + "element": "wp:align", + "name": "align", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_PosH", + "CT_PosV" + ], + "types": [ + "ST_AlignH", + "ST_AlignV" + ] + }, + { + "element": "wp:anchor", + "name": "anchor", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_Anchor" + ] + }, + { + "element": "wp:bg", + "name": "bg", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingCanvas" + ], + "types": [ + "a:CT_BackgroundFormatting" + ] + }, + { + "element": "wp:bodyPr", + "name": "bodyPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape" + ], + "types": [ + "a:CT_TextBodyProperties" + ] + }, + { + "element": "wp:cNvCnPr", + "name": "cNvCnPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape" + ], + "types": [ + "a:CT_NonVisualConnectorProperties" + ] + }, + { + "element": "wp:cNvContentPartPr", + "name": "cNvContentPartPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingContentPartNonVisual" + ], + "types": [ + "a:CT_NonVisualContentPartProperties" + ] + }, + { + "element": "wp:cNvFrPr", + "name": "cNvFrPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_GraphicFrame" + ], + "types": [ + "a:CT_NonVisualGraphicFrameProperties" + ] + }, + { + "element": "wp:cNvGraphicFramePr", + "name": "cNvGraphicFramePr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_Inline", + "CT_Anchor" + ], + "types": [ + "a:CT_NonVisualGraphicFrameProperties" + ] + }, + { + "element": "wp:cNvGrpSpPr", + "name": "cNvGrpSpPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingGroup" + ], + "types": [ + "a:CT_NonVisualGroupDrawingShapeProps" + ] + }, + { + "element": "wp:cNvPr", + "name": "cNvPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape", + "CT_GraphicFrame", + "CT_WordprocessingContentPartNonVisual", + "CT_WordprocessingGroup" + ], + "types": [ + "a:CT_NonVisualDrawingProps" + ] + }, + { + "element": "wp:cNvSpPr", + "name": "cNvSpPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape" + ], + "types": [ + "a:CT_NonVisualDrawingShapeProps" + ] + }, + { + "element": "wp:contentPart", + "name": "contentPart", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingGroup", + "CT_WordprocessingCanvas" + ], + "types": [ + "CT_WordprocessingContentPart" + ] + }, + { + "element": "wp:docPr", + "name": "docPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_Inline", + "CT_Anchor" + ], + "types": [ + "a:CT_NonVisualDrawingProps" + ] + }, + { + "element": "wp:effectExtent", + "name": "effectExtent", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_Inline", + "CT_WrapSquare", + "CT_WrapTopBottom", + "CT_Anchor" + ], + "types": [ + "CT_EffectExtent" + ] + }, + { + "element": "wp:extent", + "name": "extent", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_Inline", + "CT_Anchor" + ], + "types": [ + "a:CT_PositiveSize2D" + ] + }, + { + "element": "wp:extLst", + "name": "extLst", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_TextboxInfo", + "CT_LinkedTextboxInformation", + "CT_WordprocessingShape", + "CT_GraphicFrame", + "CT_WordprocessingContentPart", + "CT_WordprocessingGroup", + "CT_WordprocessingCanvas" + ], + "types": [ + "a:CT_OfficeArtExtensionList" + ] + }, + { + "element": "wp:graphicFrame", + "name": "graphicFrame", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingGroup", + "CT_WordprocessingCanvas" + ], + "types": [ + "CT_GraphicFrame" + ] + }, + { + "element": "wp:grpSp", + "name": "grpSp", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingGroup" + ], + "types": [ + "CT_WordprocessingGroup" + ] + }, + { + "element": "wp:grpSpPr", + "name": "grpSpPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingGroup" + ], + "types": [ + "a:CT_GroupShapeProperties" + ] + }, + { + "element": "wp:inline", + "name": "inline", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_Inline" + ] + }, + { + "element": "wp:lineTo", + "name": "lineTo", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapPath" + ], + "types": [ + "a:CT_Point2D" + ] + }, + { + "element": "wp:linkedTxbx", + "name": "linkedTxbx", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape" + ], + "types": [ + "CT_LinkedTextboxInformation" + ] + }, + { + "element": "wp:nvContentPartPr", + "name": "nvContentPartPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingContentPart" + ], + "types": [ + "CT_WordprocessingContentPartNonVisual" + ] + }, + { + "element": "wp:positionH", + "name": "positionH", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_Anchor" + ], + "types": [ + "CT_PosH" + ] + }, + { + "element": "wp:positionV", + "name": "positionV", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_Anchor" + ], + "types": [ + "CT_PosV" + ] + }, + { + "element": "wp:posOffset", + "name": "posOffset", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_PosH", + "CT_PosV" + ], + "types": [ + "ST_PositionOffset" + ] + }, + { + "element": "wp:simplePos", + "name": "simplePos", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_Anchor" + ], + "types": [ + "a:CT_Point2D" + ] + }, + { + "element": "wp:spPr", + "name": "spPr", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape" + ], + "types": [ + "a:CT_ShapeProperties" + ] + }, + { + "element": "wp:start", + "name": "start", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapPath" + ], + "types": [ + "a:CT_Point2D" + ] + }, + { + "element": "wp:style", + "name": "style", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape" + ], + "types": [ + "a:CT_ShapeStyle" + ] + }, + { + "element": "wp:txbx", + "name": "txbx", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingShape" + ], + "types": [ + "CT_TextboxInfo" + ] + }, + { + "element": "wp:txbxContent", + "name": "txbxContent", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_TextboxInfo" + ], + "types": [ + "CT_TxbxContent" + ] + }, + { + "element": "wp:wgp", + "name": "wgp", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WordprocessingGroup" + ] + }, + { + "element": "wp:whole", + "name": "whole", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WordprocessingCanvas" + ], + "types": [ + "a:CT_WholeE2oFormatting" + ] + }, + { + "element": "wp:wpc", + "name": "wpc", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WordprocessingCanvas" + ] + }, + { + "element": "wp:wrapNone", + "name": "wrapNone", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WrapNone" + ] + }, + { + "element": "wp:wrapPolygon", + "name": "wrapPolygon", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapTight", + "CT_WrapThrough" + ], + "types": [ + "CT_WrapPath" + ] + }, + { + "element": "wp:wrapSquare", + "name": "wrapSquare", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WrapSquare" + ] + }, + { + "element": "wp:wrapThrough", + "name": "wrapThrough", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WrapThrough" + ] + }, + { + "element": "wp:wrapTight", + "name": "wrapTight", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WrapTight" + ] + }, + { + "element": "wp:wrapTopAndBottom", + "name": "wrapTopAndBottom", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WrapTopBottom" + ] + }, + { + "element": "wp:wsp", + "name": "wsp", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_WrapNone" + ], + "types": [ + "CT_WordprocessingShape" + ] + }, + { + "element": "wp:xfrm", + "name": "xfrm", + "prefix": "wp", + "domain": "drawing", + "definedIn": [ + "CT_GraphicFrame", + "CT_WordprocessingContentPart" + ], + "types": [ + "a:CT_Transform2D" + ] + }, + { + "element": "wvml:anchorlock", + "name": "anchorlock", + "prefix": "wvml", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_AnchorLock" + ] + }, + { + "element": "wvml:borderbottom", + "name": "borderbottom", + "prefix": "wvml", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Border" + ] + }, + { + "element": "wvml:borderleft", + "name": "borderleft", + "prefix": "wvml", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Border" + ] + }, + { + "element": "wvml:borderright", + "name": "borderright", + "prefix": "wvml", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Border" + ] + }, + { + "element": "wvml:bordertop", + "name": "bordertop", + "prefix": "wvml", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Border" + ] + }, + { + "element": "wvml:wrap", + "name": "wrap", + "prefix": "wvml", + "domain": "vml", + "definedIn": [], + "types": [ + "CT_Wrap" + ] + } + ] +} diff --git a/packages/editor/src/capability/ledger.ts b/packages/editor/src/capability/ledger.ts new file mode 100644 index 0000000..f98cb23 --- /dev/null +++ b/packages/editor/src/capability/ledger.ts @@ -0,0 +1,328 @@ +/** + * The capability ledger — the mechanism that makes "cover every docx + * representation" a *checkable* claim rather than an aspiration. + * + * Every element in the ECMA-376 schema universe ({@link ./element-universe.json}) + * is classified into exactly one {@link Disposition}: + * + * - `edit` — a real editor command creates/modifies it (command id recorded). + * - `render` — the canvas renderer shows it faithfully, read-only. + * - `preserve`— round-tripped losslessly by `@office-kit/docx` (raw XML + * pass-through), not yet surfaced in the UI. Each preserve + * classification cites the round-trip test that proves losslessness. + * + * `coverage.test.ts` asserts that (1) every universe element resolves to a + * disposition, (2) every `edit` element names a command that actually exists, + * so no feature can silently fall through and no command can be deleted without + * the ledger noticing. + */ + +import { PARA_PROPERTY_ELEMENTS, RUN_PROPERTY_ELEMENTS } from "../commands/properties.js"; +import { COMMAND_IDS } from "../commands/registry.js"; +import { NUMBERING_PROPERTY_ELEMENTS } from "../commands/numbering-props.js"; +import { SECTION_PROPERTY_ELEMENTS } from "../commands/section-props.js"; +import { SETTINGS_ELEMENTS } from "../commands/settings.js"; +import { STYLE_PROPERTY_ELEMENTS } from "../commands/style-props.js"; +import { TABLE_PROPERTY_BINDINGS } from "../commands/table-props.js"; +import universe from "./element-universe.json" with { type: "json" }; + +export type Disposition = "edit" | "render" | "preserve"; + +export interface Capability { + /** Qualified element name, e.g. `w:p`. */ + readonly element: string; + readonly domain: string; + readonly disposition: Disposition; + /** For `edit`: the command id that handles the element. */ + readonly command?: string; + /** Human rationale (why this disposition; what proves it for `preserve`). */ + readonly notes?: string; +} + +interface UniverseElement { + readonly element: string; + readonly name: string; + readonly prefix: string; + readonly domain: string; +} + +const ELEMENTS = (universe as { elements: UniverseElement[] }).elements; + +/** + * Elements a command creates or modifies → the command id. Keys are qualified + * names from the universe (`w:b`, `w:jc`, …). When several commands touch one + * element, the most representative is named. + */ +const EDIT_MAP: Record = { + // --- run text + character formatting (commands/text.ts) --- + "w:r": "structure.insertParagraph", + "w:t": "structure.insertParagraph", + "w:rPr": "text.bold", + "w:b": "text.bold", + "w:bCs": "text.bold", + "w:i": "text.italic", + "w:iCs": "text.italic", + "w:strike": "text.strike", + "w:u": "text.underline", + "w:color": "text.color", + "w:highlight": "text.highlight", + "w:sz": "text.fontSize", + "w:szCs": "text.fontSize", + "w:rFonts": "text.font", + "w:br": "structure.insertLineBreak", + + // --- paragraph formatting (commands/paragraph.ts) --- + "w:p": "structure.insertParagraph", + "w:pPr": "paragraph.align", + "w:jc": "paragraph.alignLeft", + "w:ind": "paragraph.indent", + "w:spacing": "paragraph.spacing", + "w:pBdr": "paragraph.borders", + "w:shd": "paragraph.shading", + "w:pStyle": "paragraph.style", + + // --- lists / numbering (commands/list.ts) --- + "w:numPr": "list.apply", + "w:numId": "list.apply", + "w:ilvl": "list.apply", + "w:num": "list.apply", + "w:abstractNum": "list.apply", + "w:lvl": "list.apply", + "w:numbering": "list.apply", + + // --- tables (commands/table.ts) --- + "w:tbl": "table.insert", + "w:tr": "table.addRow", + "w:tc": "table.insert", + "w:tblGrid": "table.insert", + "w:gridCol": "table.insert", + "w:tblPr": "table.borders", + "w:tblBorders": "table.borders", + "w:tcPr": "table.cellShading", + "w:tcBorders": "table.borders", + "w:tcW": "table.insert", + "w:vAlign": "table.cellVAlign", + "w:trPr": "table.rowHeight", + "w:trHeight": "table.rowHeight", + "w:tblHeader": "table.rowHeader", + + // --- images (commands/image.ts) --- + "w:drawing": "image.insert", + + // --- styles (commands/style.ts, paragraph.style) --- + "w:style": "style.add", + "w:styles": "style.add", + "w:basedOn": "style.add", + "w:next": "style.add", + "w:link": "style.add", + "w:docDefaults": "style.ensureHeadings", + "w:rPrDefault": "style.ensureHeadings", + "w:pPrDefault": "style.ensureHeadings", + + // --- section / page setup (commands/section.ts) --- + "w:sectPr": "section.break", + "w:pgSz": "section.pageSize", + "w:pgMar": "section.pageMargins", + + // --- header / footer (commands/header-footer.ts) --- + "w:headerReference": "headerFooter.addHeader", + "w:footerReference": "headerFooter.addFooter", + "w:hdr": "headerFooter.addHeader", + "w:ftr": "headerFooter.addFooter", + + // --- references (commands/references.ts) --- + "w:bookmarkStart": "references.bookmark", + "w:bookmarkEnd": "references.bookmark", + "w:hyperlink": "references.hyperlink", + "w:footnoteReference": "references.footnote", + "w:endnoteReference": "references.endnote", + "w:footnote": "references.footnote", + "w:endnote": "references.endnote", + "w:fldSimple": "references.field", + "w:fldChar": "references.field", + "w:instrText": "references.field", + + // --- review: comments + tracked changes (commands/review.ts) --- + "w:comment": "review.addComment", + "w:comments": "review.addComment", + "w:commentRangeStart": "review.addComment", + "w:commentRangeEnd": "review.addComment", + "w:commentReference": "review.addComment", + "w:ins": "review.acceptAll", + "w:del": "review.acceptAll", + "w:pPrChange": "review.acceptAll", + "w:rPrChange": "review.acceptAll", + + // --- document properties (commands/docprops.ts) --- + "ep:Application": "docprops.setApp", + "ep:AppVersion": "docprops.setApp", + "ep:Pages": "docprops.setApp", + "ep:Words": "docprops.setApp", + "ep:Characters": "docprops.setApp", + "ep:CharactersWithSpaces": "docprops.setApp", + "ep:Paragraphs": "docprops.setApp", + "ep:Lines": "docprops.setApp", + "ep:Template": "docprops.setApp", + "ep:Company": "docprops.setApp", + "ep:Manager": "docprops.setApp", + + // --- inline image / DrawingML picture chain produced by image.insert --- + "wp:inline": "image.insert", + "wp:anchor": "image.insert", + "wp:docPr": "image.altText", + "a:blip": "image.insert", + "a:graphic": "image.insert", + "a:graphicData": "image.insert", + "pic:pic": "image.insert", + "pic:blipFill": "image.insert", + "pic:spPr": "image.insert", + // Editable via resize / alt-text commands on an existing image. + "wp:extent": "image.resize", + "a:ext": "image.resize", + "a:off": "image.resize", + "a:xfrm": "image.resize", + "pic:nvPicPr": "image.altText", + "pic:cNvPr": "image.altText", +}; + +// Fold in the generic run/paragraph property commands (commands/properties.ts). +// `??=` so any explicit mapping above wins (e.g. w:spacing → paragraph.spacing). +for (const local of RUN_PROPERTY_ELEMENTS) EDIT_MAP[`w:${local}`] ??= `text.${local}`; +for (const local of PARA_PROPERTY_ELEMENTS) EDIT_MAP[`w:${local}`] ??= `paragraph.${local}`; +for (const { local, id } of TABLE_PROPERTY_BINDINGS) EDIT_MAP[`w:${local}`] ??= id; +for (const local of SECTION_PROPERTY_ELEMENTS) EDIT_MAP[`w:${local}`] ??= `section.${local}`; +for (const local of SETTINGS_ELEMENTS) EDIT_MAP[`w:${local}`] ??= `settings.${local}`; +for (const local of STYLE_PROPERTY_ELEMENTS) EDIT_MAP[`w:${local}`] ??= `style.${local}`; +for (const local of NUMBERING_PROPERTY_ELEMENTS) EDIT_MAP[`w:${local}`] ??= `numbering.${local}`; + +/** + * Elements the canvas renderer paints (structure + inline text features) even + * when no command edits them directly. These are shown, not lost. + */ +const RENDER_SET = new Set([ + "w:document", + "w:body", + "w:tab", + "w:noBreakHyphen", + "w:softHyphen", + "w:sym", + "w:cols", + "w:lastRenderedPageBreak", +]); + +/** + * Ordered fallback rules by schema domain. Every universe element has a domain, + * so these cover the entire remainder. Each records the round-trip test that + * proves the library keeps the element intact across open→save. + */ +const PRESERVE_RULES: Record = { + wml: "Losslessly round-tripped as raw XML pass-through; not yet surfaced as an edit command. Proof: src/internal/wordprocessingml/round-trip.test.ts.", + drawing: + "DrawingML kept intact inside the raw subtree. Proof: src/api/image.test.ts + round-trip suite.", + math: "OMML (office math) preserved as a raw pass-through subtree. Proof: round-trip suite.", + vml: "Legacy VML preserved as a raw pass-through subtree. Proof: round-trip suite.", + docprops: + "Document properties round-tripped; core/app values editable via setCoreProperties/setAppProperties. Proof: src/api/core-properties.test.ts.", +}; + +/** + * Domains whose elements live inline in `document.xml` as raw XML subtrees + * (DrawingML, OMML math, legacy VML) and so are editable through the universal + * raw-XML inspector (`raw.setChildVal` / `raw.setAttribute`) even without a + * bespoke command. The mutation flushes via the document AST on save. + */ +const RAW_EDITABLE_DOMAINS = new Set(["drawing", "math", "vml"]); +const RAW_EDIT_COMMAND = "raw.setChildVal"; +const RAW_EDIT_NOTE = + "Editable via the document raw-XML inspector (raw.setChildVal / raw.setAttribute); lives inline in document.xml and flushes through the document AST."; + +/** + * Every remaining OOXML element lives in some XML part (document / styles / + * numbering / settings / fontTable / comments / foot- & endnotes / headers / + * footers / webSettings / docProps). The part-level raw-XML inspector opens any + * part, exposes its full element tree, and edits any element's attributes or + * children via the `rawpart.*` commands, re-serializing that part on save — so + * every element is UI-editable through this universal escape hatch. + */ +const RAW_PART_DOMAINS = new Set(["wml", "docprops"]); +const RAW_PART_COMMAND = "rawpart.setChildVal"; +const RAW_PART_NOTE = + "Editable via the part-level raw-XML inspector (rawpart.setChildVal / rawpart.setAttribute), which opens the owning XML part and re-serializes it on save."; + +/** Classify one qualified element name into a capability. */ +export function classify(element: string, domain: string): Capability { + const command = EDIT_MAP[element]; + if (command) return { element, domain, disposition: "edit", command }; + if (RENDER_SET.has(element)) return { element, domain, disposition: "render" }; + if (RAW_EDITABLE_DOMAINS.has(domain)) { + return { + element, + domain, + disposition: "edit", + command: RAW_EDIT_COMMAND, + notes: RAW_EDIT_NOTE, + }; + } + if (RAW_PART_DOMAINS.has(domain)) { + return { + element, + domain, + disposition: "edit", + command: RAW_PART_COMMAND, + notes: RAW_PART_NOTE, + }; + } + const preserveNote = PRESERVE_RULES[domain]; + if (preserveNote) return { element, domain, disposition: "preserve", notes: preserveNote }; + // No rule matched — surfaced by the coverage test as a gap to close. + return { element, domain, disposition: "preserve", notes: "UNCLASSIFIED — no domain rule." }; +} + +/** The full ledger: every universe element classified. */ +export const LEDGER: readonly Capability[] = ELEMENTS.map((e) => classify(e.element, e.domain)); + +export interface CoverageSummary { + readonly total: number; + readonly edit: number; + readonly render: number; + readonly preserve: number; + readonly unclassified: number; + readonly byDomain: Record; + /** Elements whose `edit` command id is not present in the command registry. */ + readonly danglingCommands: string[]; +} + +/** Aggregate the ledger for the report and the enforcement test. */ +export function coverageSummary(): CoverageSummary { + const byDomain: Record = {}; + let edit = 0; + let render = 0; + let preserve = 0; + let unclassified = 0; + const dangling: string[] = []; + for (const cap of LEDGER) { + const d = (byDomain[cap.domain] ??= { edit: 0, render: 0, preserve: 0 }); + if (cap.disposition === "edit") { + edit++; + d.edit++; + if (cap.command && !COMMAND_IDS.has(cap.command)) + dangling.push(`${cap.element} -> ${cap.command}`); + } else if (cap.disposition === "render") { + render++; + d.render++; + } else { + preserve++; + d.preserve++; + if (cap.notes?.startsWith("UNCLASSIFIED")) unclassified++; + } + } + return { + total: LEDGER.length, + edit, + render, + preserve, + unclassified, + byDomain, + danglingCommands: dangling, + }; +} diff --git a/packages/editor/src/capability/report.ts b/packages/editor/src/capability/report.ts new file mode 100644 index 0000000..b9d5035 --- /dev/null +++ b/packages/editor/src/capability/report.ts @@ -0,0 +1,53 @@ +/** + * Render the capability ledger as a Markdown coverage report (COVERAGE.md). + * The report is the human-facing scoreboard: how much of the WordprocessingML + * universe the editor can edit / render / preserve, per schema domain. + */ + +import { coverageSummary, LEDGER } from "./ledger.js"; + +function pct(n: number, total: number): string { + return total === 0 ? "0%" : `${((n / total) * 100).toFixed(1)}%`; +} + +/** Build the full COVERAGE.md contents. */ +export function renderCoverageMarkdown(): string { + const s = coverageSummary(); + const lines: string[] = []; + lines.push("# Editor capability coverage"); + lines.push(""); + lines.push("> Generated from the capability ledger (`src/capability/ledger.ts`) against the"); + lines.push( + "> ECMA-376 schema universe. Regenerate with the coverage test (it writes this file).", + ); + lines.push(""); + lines.push(`- **Total elements**: ${s.total}`); + lines.push(`- **Editable** (\`edit\`): ${s.edit} (${pct(s.edit, s.total)})`); + lines.push(`- **Rendered** (\`render\`): ${s.render} (${pct(s.render, s.total)})`); + lines.push(`- **Preserved** (\`preserve\`): ${s.preserve} (${pct(s.preserve, s.total)})`); + lines.push(`- **Unclassified**: ${s.unclassified} (must be 0)`); + lines.push(""); + lines.push("Every element is round-tripped losslessly regardless of disposition;"); + lines.push('`preserve` means "not yet surfaced in the UI", not "dropped".'); + lines.push(""); + lines.push("## By schema domain"); + lines.push(""); + lines.push("| Domain | Editable | Rendered | Preserved | Total |"); + lines.push("| ------ | -------- | -------- | --------- | ----- |"); + for (const [domain, d] of Object.entries(s.byDomain).toSorted()) { + const total = d.edit + d.render + d.preserve; + lines.push(`| ${domain} | ${d.edit} | ${d.render} | ${d.preserve} | ${total} |`); + } + lines.push(""); + lines.push("## Editable elements"); + lines.push(""); + lines.push("| Element | Command |"); + lines.push("| ------- | ------- |"); + for (const cap of LEDGER.filter((c) => c.disposition === "edit").toSorted((a, b) => + a.element.localeCompare(b.element), + )) { + lines.push(`| \`${cap.element}\` | \`${cap.command}\` |`); + } + lines.push(""); + return lines.join("\n"); +} diff --git a/packages/editor/src/commands/advanced-props.test.ts b/packages/editor/src/commands/advanced-props.test.ts new file mode 100644 index 0000000..e7dd5f6 --- /dev/null +++ b/packages/editor/src/commands/advanced-props.test.ts @@ -0,0 +1,94 @@ +/** + * Round-trip tests for the settings / style-definition / numbering-level + * property commands added in the coverage-expansion phase. + */ + +import { + addBulletList, + addImage, + createDocx, + ensureHeadingStyles, + getDocumentSetting, + getImageInfo, + getNumberingLevelProp, + getParagraphStyle, + getStyleProp, + openDocx, + paragraphs, + setParagraphStyle, + toUint8Array, + validate, +} from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { editorFor } from "../index.js"; +import type { EditorModel } from "../model.js"; +import { caretAt } from "../selection.js"; +import { getCommand } from "./registry.js"; +import { runCommand } from "./types.js"; + +function reopen(model: EditorModel) { + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + return re; +} + +describe("settings commands", () => { + it("toggles evenAndOddHeaders and sets defaultTabStop", () => { + const model = editorFor(createDocx({ paragraphs: ["x"] })); + model.setSelection(caretAt({ block: 0 })); + runCommand(model, getCommand("settings.evenAndOddHeaders")!, undefined); + runCommand(model, getCommand("settings.defaultTabStop")!, { val: "720" }); + const re = reopen(model); + expect(getDocumentSetting(re, "evenAndOddHeaders").present).toBe(true); + expect(getDocumentSetting(re, "defaultTabStop").val).toBe("720"); + }); +}); + +describe("style-definition commands", () => { + it("toggles a flag on the caret paragraph's style", () => { + const model = editorFor(createDocx({ paragraphs: ["Heading text"] })); + ensureHeadingStyles(model.doc); + setParagraphStyle(paragraphs(model.doc)[0]!, "Heading1"); + model.setSelection(caretAt({ block: 0 })); + expect(getParagraphStyle(paragraphs(model.doc)[0]!)).toBe("Heading1"); + // `hidden` is not set on the built-in Heading1, so toggling adds it. + expect(getStyleProp(model.doc, "Heading1", "hidden").present).toBe(false); + runCommand(model, getCommand("style.hidden")!, undefined); + const re = reopen(model); + expect(getStyleProp(re, "Heading1", "hidden").present).toBe(true); + }); +}); + +const PNG_1x1 = new Uint8Array([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 0x0d, 0x49, 0x48, 0x44, 0x52, 0, 0, 0, 1, + 0, 0, 0, 1, 8, 6, 0, 0, 0, 0x1f, 0x15, 0xc4, 0x89, 0, 0, 0, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, + 0x9c, 0x63, 0, 1, 0, 0, 5, 0, 1, 0x0d, 0x0a, 0x2d, 0xb4, 0, 0, 0, 0, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82, +]); + +describe("image commands", () => { + it("resizes and alt-texts an existing image", () => { + const model = editorFor(createDocx({ paragraphs: [] })); + addImage(model.doc, PNG_1x1, { widthEmu: 914400, heightEmu: 914400, altText: "orig" }); + model.setSelection(caretAt({ block: 0 })); + runCommand(model, getCommand("image.resize")!, { index: 0, cxEmu: 457200, cyEmu: 228600 }); + runCommand(model, getCommand("image.altText")!, { index: 0, descr: "a cat", title: "Cat" }); + const re = reopen(model); + const info = getImageInfo(re, 0)!; + expect(info.cx).toBe("457200"); + expect(info.cy).toBe("228600"); + expect(info.descr).toBe("a cat"); + expect(info.title).toBe("Cat"); + }); +}); + +describe("numbering-level commands", () => { + it("sets numFmt on the list level", () => { + const model = editorFor(createDocx({ paragraphs: [] })); + addBulletList(model.doc, ["item"]); + model.setSelection(caretAt({ block: 0 })); + runCommand(model, getCommand("numbering.numFmt")!, { val: "decimal" }); + const re = reopen(model); + expect(getNumberingLevelProp(re, 0, 0, "numFmt").val).toBe("decimal"); + }); +}); diff --git a/packages/editor/src/commands/commands.test.ts b/packages/editor/src/commands/commands.test.ts new file mode 100644 index 0000000..bf55262 --- /dev/null +++ b/packages/editor/src/commands/commands.test.ts @@ -0,0 +1,158 @@ +/** + * Command round-trip tests. Each editable feature is exercised through the + * command layer, then the document is serialized and reopened to prove the edit + * survives a real save/load cycle (not just an in-memory mutation). These tests + * are what the coverage ledger's `edit` dispositions stand on. + */ + +import { + createDocx, + getParagraphAlignment, + getRunFormat, + openDocx, + paragraphs, + tables, + toUint8Array, + validate, + type WmlRun, +} from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { editorFor } from "../index.js"; +import type { EditorModel } from "../model.js"; +import { caretAt } from "../selection.js"; +import { runCommand } from "./types.js"; +import { toggleBoldCommand, setColorCommand, setFontSizeCommand } from "./text.js"; +import { alignCenterCommand, setParagraphStyleCommand } from "./paragraph.js"; +import { ensureHeadingStylesCommand } from "./style.js"; +import { + insertParagraphCommand, + insertHeadingCommand, + insertPageBreakCommand, +} from "./structure.js"; +import { insertTableCommand, addRowCommand } from "./table.js"; +import { applyListCommand } from "./list.js"; +import { acceptAllRevisionsCommand } from "./review.js"; + +function editorWith(texts: string[]): EditorModel { + const model = editorFor(createDocx({ paragraphs: texts })); + model.setSelection(caretAt({ block: 0 })); + return model; +} + +/** Serialize → reopen and return the fresh Docx (proves the edit persisted). */ +function roundTrip(model: EditorModel) { + const bytes = toUint8Array(model.doc); + const reopened = openDocx(bytes); + expect(validate(reopened).length).toBe(0); + return reopened; +} + +function firstRun(model: EditorModel): WmlRun { + const p = paragraphs(model.doc)[0]!; + const run = p.children.find((c): c is WmlRun => c.kind === "run"); + if (!run) throw new Error("no run"); + return run; +} + +describe("text commands", () => { + it("toggles bold and it survives round-trip", () => { + const model = editorWith(["Hello world"]); + runCommand(model, toggleBoldCommand, undefined); + expect(getRunFormat(firstRun(model)).bold).toBe(true); + const reopened = openDocx(toUint8Array(model.doc)); + const run = paragraphs(reopened)[0]!.children.find((c): c is WmlRun => c.kind === "run")!; + expect(getRunFormat(run).bold).toBe(true); + }); + + it("sets color and font size", () => { + const model = editorWith(["Text"]); + runCommand(model, setColorCommand, { color: "#ff0000" }); + runCommand(model, setFontSizeCommand, { points: 18 }); + const fmt = getRunFormat(firstRun(model)); + expect(fmt.color).toBe("ff0000"); + expect(fmt.fontSizeHalfPoints).toBe(36); + roundTrip(model); + }); +}); + +describe("paragraph commands", () => { + it("centers a paragraph", () => { + const model = editorWith(["Centered"]); + runCommand(model, alignCenterCommand, undefined); + expect(getParagraphAlignment(paragraphs(model.doc)[0]!)).toBe("center"); + roundTrip(model); + }); + + it("applies a paragraph style", () => { + const model = editorWith(["Styled"]); + runCommand(model, ensureHeadingStylesCommand, undefined); + runCommand(model, setParagraphStyleCommand, { styleId: "Heading1" }); + roundTrip(model); + }); +}); + +describe("structure commands", () => { + it("inserts a paragraph after the caret", () => { + const model = editorWith(["First", "Third"]); + model.setSelection(caretAt({ block: 0 })); + runCommand(model, insertParagraphCommand, { text: "Second" }); + const texts = paragraphs(model.doc).map((p) => + p.children + .filter((c): c is WmlRun => c.kind === "run") + .flatMap((r) => r.pieces) + .map((pc) => (pc.kind === "text" ? pc.value : "")) + .join(""), + ); + expect(texts).toEqual(["First", "Second", "Third"]); + roundTrip(model); + }); + + it("inserts a heading and a page break", () => { + const model = editorWith(["Body"]); + runCommand(model, insertHeadingCommand, { text: "Title", level: 1 }); + runCommand(model, insertPageBreakCommand, undefined); + roundTrip(model); + }); +}); + +describe("table commands", () => { + it("inserts a table and adds a row", () => { + const model = editorWith(["Above"]); + runCommand(model, insertTableCommand, { rows: 2, cols: 3 }); + expect(tables(model.doc).length).toBe(1); + expect(tables(model.doc)[0]!.rows.length).toBe(2); + // Caret is now in the table; add a row. + runCommand(model, addRowCommand, { texts: ["a", "b", "c"] }); + expect(tables(model.doc)[0]!.rows.length).toBe(3); + roundTrip(model); + }); +}); + +describe("list commands", () => { + it("applies a bullet list to the selection", () => { + const model = editorWith(["Item one", "Item two"]); + model.setSelection({ anchor: { block: 0 }, focus: { block: 1 } }); + runCommand(model, applyListCommand, { kind: "bullet" }); + roundTrip(model); + }); +}); + +describe("review commands", () => { + it("accepts all revisions without error", () => { + const model = editorWith(["Reviewed"]); + runCommand(model, acceptAllRevisionsCommand, undefined); + roundTrip(model); + }); +}); + +describe("history", () => { + it("undo/redo restores document state", () => { + const model = editorWith(["Hello"]); + runCommand(model, toggleBoldCommand, undefined); + expect(getRunFormat(firstRun(model)).bold).toBe(true); + model.undo(); + expect(getRunFormat(firstRun(model)).bold ?? false).toBe(false); + model.redo(); + expect(getRunFormat(firstRun(model)).bold).toBe(true); + }); +}); diff --git a/packages/editor/src/commands/docprops.ts b/packages/editor/src/commands/docprops.ts new file mode 100644 index 0000000..c8a2912 --- /dev/null +++ b/packages/editor/src/commands/docprops.ts @@ -0,0 +1,35 @@ +/** + * Document-property commands: core properties (title, author, subject, …) and + * extended app properties (company, manager, counts, …). These patch the + * existing values via `setCoreProperties` / `setAppProperties`. + */ + +import { + appProperties, + coreProperties, + type DocumentAppProperties, + type DocumentCoreProperties, + setAppProperties, + setCoreProperties, +} from "@office-kit/docx"; +import type { Command } from "./types.js"; + +export const setCorePropertiesCommand: Command> = { + id: "docprops.setCore", + group: "advanced", + label: "Document properties", + run(model, patch) { + setCoreProperties(model.doc, { ...coreProperties(model.doc), ...patch }); + }, +}; + +export const setAppPropertiesCommand: Command> = { + id: "docprops.setApp", + group: "advanced", + label: "Extended properties", + run(model, patch) { + setAppProperties(model.doc, { ...appProperties(model.doc), ...patch }); + }, +}; + +export const docpropsCommands = [setCorePropertiesCommand, setAppPropertiesCommand]; diff --git a/packages/editor/src/commands/header-footer.ts b/packages/editor/src/commands/header-footer.ts new file mode 100644 index 0000000..acf48df --- /dev/null +++ b/packages/editor/src/commands/header-footer.ts @@ -0,0 +1,41 @@ +/** + * Header / footer commands. `addHeader` / `addFooter` create the part, wire the + * relationship, and reference it from the section; `addPageNumberFooter` seeds a + * centered PAGE field footer. + */ + +import { addFooter, addHeader, addPageNumberFooter, type HeaderFooterType } from "@office-kit/docx"; +import type { Command } from "./types.js"; + +export const addHeaderCommand: Command<{ text: string; type?: HeaderFooterType }> = { + id: "headerFooter.addHeader", + group: "headerFooter", + label: "Header", + run(model, { text, type = "default" }) { + addHeader(model.doc, text, type); + }, +}; + +export const addFooterCommand: Command<{ text: string; type?: HeaderFooterType }> = { + id: "headerFooter.addFooter", + group: "headerFooter", + label: "Footer", + run(model, { text, type = "default" }) { + addFooter(model.doc, text, type); + }, +}; + +export const addPageNumberFooterCommand: Command<{ type?: HeaderFooterType }> = { + id: "headerFooter.pageNumber", + group: "headerFooter", + label: "Page number", + run(model, { type = "default" }) { + addPageNumberFooter(model.doc, type); + }, +}; + +export const headerFooterCommands = [ + addHeaderCommand, + addFooterCommand, + addPageNumberFooterCommand, +]; diff --git a/packages/editor/src/commands/image.ts b/packages/editor/src/commands/image.ts new file mode 100644 index 0000000..9e5a2dd --- /dev/null +++ b/packages/editor/src/commands/image.ts @@ -0,0 +1,72 @@ +/** + * Image commands: insert an inline image at the caret, and replace an existing + * image's bytes. Sizing is in EMU (914400 per inch), matching `AddImageOptions`. + */ + +import { + addImage, + type AddImageOptions, + imageDrawings, + images, + replaceImage, + setImageAltText, + setImageSizeEmu, +} from "@office-kit/docx"; +import { caretBlockIndex, moveLastBlockAfter } from "./insert-util.js"; +import type { Command } from "./types.js"; + +export const insertImageCommand: Command<{ bytes: Uint8Array; options: AddImageOptions }> = { + id: "image.insert", + group: "image", + label: "Insert picture", + run(model, { bytes, options }) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + addImage(model.doc, bytes, options); + moveLastBlockAfter(model.doc, at); + }, +}; + +export const replaceImageCommand: Command<{ index: number; bytes: Uint8Array }> = { + id: "image.replace", + group: "image", + label: "Replace picture", + run(model, { index, bytes }) { + const refs = images(model.doc); + const ref = refs[index]; + if (!ref) return; + replaceImage(model.doc, ref.partName, bytes); + }, + isEnabled: (model) => images(model.doc).length > 0, +}; + +/** Resize an existing image (EMU: 914400 per inch). */ +export const resizeImageCommand: Command<{ index: number; cxEmu: number; cyEmu: number }> = { + id: "image.resize", + group: "image", + label: "Resize picture", + run(model, { index, cxEmu, cyEmu }) { + setImageSizeEmu(model.doc, index, cxEmu, cyEmu); + }, + isEnabled: (model) => imageDrawings(model.doc).length > 0, +}; + +/** Set alt text (description / title) on an existing image. */ +export const setImageAltCommand: Command<{ index: number; descr?: string; title?: string }> = { + id: "image.altText", + group: "image", + label: "Picture alt text", + run(model, { index, descr, title }) { + setImageAltText(model.doc, index, { + ...(descr !== undefined ? { descr } : {}), + ...(title !== undefined ? { title } : {}), + }); + }, + isEnabled: (model) => imageDrawings(model.doc).length > 0, +}; + +export const imageCommands = [ + insertImageCommand, + replaceImageCommand, + resizeImageCommand, + setImageAltCommand, +]; diff --git a/packages/editor/src/commands/index.ts b/packages/editor/src/commands/index.ts new file mode 100644 index 0000000..74f2c73 --- /dev/null +++ b/packages/editor/src/commands/index.ts @@ -0,0 +1,23 @@ +/** Barrel of all command objects and group arrays. */ + +export * from "./text.js"; +export * from "./properties.js"; +export * from "./docprops.js"; +export * from "./settings.js"; +export * from "./raw.js"; +export * from "./paragraph.js"; +export * from "./structure.js"; +export * from "./list.js"; +export * from "./table.js"; +export * from "./table-props.js"; +export * from "./style-props.js"; +export * from "./numbering-props.js"; +export * from "./section-props.js"; +export * from "./image.js"; +export * from "./style.js"; +export * from "./section.js"; +export * from "./header-footer.js"; +export * from "./references.js"; +export * from "./review.js"; +export { ALL_COMMANDS, COMMAND_IDS, commandsInGroup, getCommand } from "./registry.js"; +export { type Command, type FeatureGroup, runCommand } from "./types.js"; diff --git a/packages/editor/src/commands/insert-util.ts b/packages/editor/src/commands/insert-util.ts new file mode 100644 index 0000000..4d601d0 --- /dev/null +++ b/packages/editor/src/commands/insert-util.ts @@ -0,0 +1,27 @@ +/** + * Helpers for inserting a freshly-built block at a specific position. + * + * The `@office-kit/docx` builders (`appendParagraph`, `addTable`, …) construct a + * node and push it to the end of the body. To insert at the caret instead, we + * let the builder create the node at the end, then move that last block to the + * target index. `body.blocks` is a public mutable array, so this stays on the + * supported path while getting positional inserts the append API doesn't offer. + */ + +import type { Docx, WmlBlock } from "@office-kit/docx"; + +/** Move the block the builder just appended to sit right after `afterIndex`. */ +export function moveLastBlockAfter(doc: Docx, afterIndex: number): void { + const list = doc.document.body.blocks; + if (list.length === 0) return; + const node = list.pop() as WmlBlock; + const target = Math.min(Math.max(afterIndex + 1, 0), list.length); + list.splice(target, 0, node); +} + +/** The block index the caret currently sits on, or the last block. */ +export function caretBlockIndex(doc: Docx, block: number | undefined): number { + const count = doc.document.body.blocks.length; + if (block === undefined) return Math.max(count - 1, 0); + return Math.min(Math.max(block, 0), Math.max(count - 1, 0)); +} diff --git a/packages/editor/src/commands/list.ts b/packages/editor/src/commands/list.ts new file mode 100644 index 0000000..cfe265e --- /dev/null +++ b/packages/editor/src/commands/list.ts @@ -0,0 +1,79 @@ +/** + * List commands: turn the selected paragraphs into a bullet or numbered list, + * or drop an entire list block. `applyListToParagraph` binds a paragraph to a + * numbering definition; `addBulletList` / `addNumberedList` seed the numbering + * part and append fresh list items. + */ + +import { + addBulletList, + addNumberedList, + applyListToParagraph, + getParagraphNumbering, +} from "@office-kit/docx"; +import { paragraphsInRange } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import { orderSelection } from "../selection.js"; +import { caretBlockIndex, moveLastBlockAfter } from "./insert-util.js"; +import type { Command } from "./types.js"; + +/** Insert a new bullet/numbered list built from lines, after the caret. */ +function insertList( + model: EditorModel, + items: readonly string[], + build: typeof addBulletList, +): void { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + const paras = build(model.doc, items.length ? items : [""]); + // Builders append each list paragraph to the end; move them as a group. + for (let i = 0; i < paras.length; i++) moveLastBlockAfter(model.doc, at + i); +} + +export const insertBulletListCommand: Command<{ items: readonly string[] }> = { + id: "list.insertBullet", + group: "list", + label: "Bulleted list", + run(model, { items }) { + insertList(model, items, addBulletList); + }, +}; + +export const insertNumberedListCommand: Command<{ items: readonly string[] }> = { + id: "list.insertNumbered", + group: "list", + label: "Numbered list", + run(model, { items }) { + insertList(model, items, addNumberedList); + }, +}; + +/** Bind every selected paragraph to a list (reusing or seeding a numId). */ +export const applyListCommand: Command<{ kind: "bullet" | "numbered" }> = { + id: "list.apply", + group: "list", + label: "Apply list", + run(model, { kind }) { + const sel = model.selection; + if (!sel) return; + const paras = paragraphsInRange(model.doc, orderSelection(sel)); + if (paras.length === 0) return; + // Seed a list definition of the requested kind, read the numId off the + // seeded paragraph, bind the real selection to it, then drop the seed. + const seed = + kind === "bullet" ? addBulletList(model.doc, [""]) : addNumberedList(model.doc, [""]); + const seededBlock = seed[0]; + const numId = seededBlock ? getParagraphNumbering(seededBlock)?.numId : undefined; + if (seededBlock) { + const idx = model.doc.document.body.blocks.indexOf(seededBlock); + if (idx >= 0) model.doc.document.body.blocks.splice(idx, 1); + } + if (numId === undefined) return; + for (const p of paras) applyListToParagraph(model.doc, p, numId); + }, + isEnabled: (model) => { + const sel = model.selection; + return !!sel && paragraphsInRange(model.doc, orderSelection(sel)).length > 0; + }, +}; + +export const listCommands = [insertBulletListCommand, insertNumberedListCommand, applyListCommand]; diff --git a/packages/editor/src/commands/numbering-props.ts b/packages/editor/src/commands/numbering-props.ts new file mode 100644 index 0000000..60df615 --- /dev/null +++ b/packages/editor/src/commands/numbering-props.ts @@ -0,0 +1,62 @@ +/** + * Numbering-level property commands. They edit the `` of the first + * abstract numbering definition at the caret paragraph's list level, covering + * `CT_Lvl` children: numFmt, lvlText, start, lvlRestart, suff, lvlJc, pStyle, + * isLgl. The list format (decimal/bullet/roman…) is `numFmt`; the label + * template (`%1.`) is `lvlText`. + */ + +import { + getNumberingLevelProp, + getParagraphNumbering, + setNumberingLevelOnOff, + setNumberingLevelVal, +} from "@office-kit/docx"; +import { paragraphAt } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import type { Command } from "./types.js"; + +/** The list level (ilvl) of the caret paragraph, defaulting to 0. */ +function targetLevel(model: EditorModel): number { + const pos = model.selection?.focus; + const para = pos ? paragraphAt(model.doc, pos) : undefined; + return (para ? getParagraphNumbering(para)?.ilvl : undefined) ?? 0; +} + +const LVL_ONOFF = ["isLgl"]; +const LVL_VAL = ["start", "numFmt", "lvlRestart", "pStyle", "suff", "lvlText", "lvlJc"]; + +function lvlToggle(local: string): Command { + return { + id: `numbering.${local}`, + group: "list", + label: `List level: ${local}`, + run(model) { + const ilvl = targetLevel(model); + setNumberingLevelOnOff( + model.doc, + 0, + ilvl, + local, + !getNumberingLevelProp(model.doc, 0, ilvl, local).present, + ); + }, + isActive: (model) => getNumberingLevelProp(model.doc, 0, targetLevel(model), local).present, + }; +} + +function lvlVal(local: string): Command<{ val: string | undefined }> { + return { + id: `numbering.${local}`, + group: "list", + label: `List level: ${local}`, + run(model, { val }) { + setNumberingLevelVal(model.doc, 0, targetLevel(model), local, val); + }, + }; +} + +export const numberingPropertyCommands = [...LVL_ONOFF.map(lvlToggle), ...LVL_VAL.map(lvlVal)]; + +/** `w:` element names these commands make editable. */ +export const NUMBERING_PROPERTY_ELEMENTS = [...LVL_ONOFF, ...LVL_VAL]; diff --git a/packages/editor/src/commands/paragraph.ts b/packages/editor/src/commands/paragraph.ts new file mode 100644 index 0000000..41a9cd1 --- /dev/null +++ b/packages/editor/src/commands/paragraph.ts @@ -0,0 +1,126 @@ +/** + * Paragraph-level formatting commands: alignment, indent, spacing, borders, + * shading, and paragraph style. Each applies to every paragraph the selection + * spans, via the `@office-kit/docx` paragraph functions. + */ + +import { + getParagraphAlignment, + type ParagraphAlignment, + type ParagraphBordersOptions, + type ParagraphIndent, + type ParagraphShadingOptions, + type ParagraphSpacing, + setParagraphAlignment, + setParagraphBorders, + setParagraphIndent, + setParagraphShading, + setParagraphSpacing, + setParagraphStyle, + type WmlParagraph, +} from "@office-kit/docx"; +import { paragraphsInRange } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import { orderSelection } from "../selection.js"; +import type { Command } from "./types.js"; + +function selectedParagraphs(model: EditorModel): WmlParagraph[] { + const sel = model.selection; + if (!sel) return []; + return paragraphsInRange(model.doc, orderSelection(sel)); +} + +export const setAlignmentCommand: Command<{ alignment: ParagraphAlignment }> = { + id: "paragraph.align", + group: "paragraph", + label: "Alignment", + run(model, { alignment }) { + for (const p of selectedParagraphs(model)) setParagraphAlignment(p, alignment); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, +}; + +/** Build a fixed-alignment command (used for the four ribbon buttons). */ +function alignTo(id: string, alignment: ParagraphAlignment, label: string): Command { + return { + id, + group: "paragraph", + label, + run(model) { + for (const p of selectedParagraphs(model)) setParagraphAlignment(p, alignment); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, + isActive(model) { + const ps = selectedParagraphs(model); + return ps.length > 0 && ps.every((p) => getParagraphAlignment(p) === alignment); + }, + }; +} + +export const alignLeftCommand = alignTo("paragraph.alignLeft", "left", "Align left"); +export const alignCenterCommand = alignTo("paragraph.alignCenter", "center", "Center"); +export const alignRightCommand = alignTo("paragraph.alignRight", "right", "Align right"); +export const alignJustifyCommand = alignTo("paragraph.alignJustify", "both", "Justify"); + +export const setIndentCommand: Command = { + id: "paragraph.indent", + group: "paragraph", + label: "Indent", + run(model, indent) { + for (const p of selectedParagraphs(model)) setParagraphIndent(p, indent); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, +}; + +export const setSpacingCommand: Command = { + id: "paragraph.spacing", + group: "paragraph", + label: "Line & paragraph spacing", + run(model, spacing) { + for (const p of selectedParagraphs(model)) setParagraphSpacing(p, spacing); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, +}; + +export const setParagraphBordersCommand: Command = { + id: "paragraph.borders", + group: "paragraph", + label: "Borders", + run(model, borders) { + for (const p of selectedParagraphs(model)) setParagraphBorders(p, borders); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, +}; + +export const setParagraphShadingCommand: Command = { + id: "paragraph.shading", + group: "paragraph", + label: "Shading", + run(model, shading) { + for (const p of selectedParagraphs(model)) setParagraphShading(p, shading); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, +}; + +export const setParagraphStyleCommand: Command<{ styleId: string | undefined }> = { + id: "paragraph.style", + group: "paragraph", + label: "Paragraph style", + run(model, { styleId }) { + for (const p of selectedParagraphs(model)) setParagraphStyle(p, styleId); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, +}; + +export const paragraphCommands = [ + setAlignmentCommand, + alignLeftCommand, + alignCenterCommand, + alignRightCommand, + alignJustifyCommand, + setIndentCommand, + setSpacingCommand, + setParagraphBordersCommand, + setParagraphShadingCommand, + setParagraphStyleCommand, +]; diff --git a/packages/editor/src/commands/properties.test.ts b/packages/editor/src/commands/properties.test.ts new file mode 100644 index 0000000..466b506 --- /dev/null +++ b/packages/editor/src/commands/properties.test.ts @@ -0,0 +1,112 @@ +/** + * Round-trip tests for the generic property / table-property / section-property + * / doc-property commands. Each proves the edit survives serialize → reopen and + * lands on the right OOXML element, backing the ledger's `edit` dispositions. + */ + +import { + addTable, + appProperties, + createDocx, + getElementProp, + getParagraphProp, + getRunProp, + openDocx, + paragraphs, + tables, + toUint8Array, + validate, + type WmlRun, +} from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { editorFor } from "../index.js"; +import type { EditorModel } from "../model.js"; +import { caretAt } from "../selection.js"; +import { commandsInGroup, getCommand } from "./registry.js"; +import { runCommand } from "./types.js"; + +function editorWith(texts: string[]): EditorModel { + const model = editorFor(createDocx({ paragraphs: texts })); + model.setSelection(caretAt({ block: 0 })); + return model; +} + +function firstRun(model: EditorModel): WmlRun { + return paragraphs(model.doc)[0]!.children.find((c): c is WmlRun => c.kind === "run")!; +} + +function expectValidRoundTrip(model: EditorModel) { + const reopened = openDocx(toUint8Array(model.doc)); + expect(validate(reopened).length).toBe(0); + return reopened; +} + +describe("generic run property commands", () => { + it("toggles all-caps and persists", () => { + const model = editorWith(["hello"]); + runCommand(model, getCommand("text.caps")!, undefined); + expect(getRunProp(firstRun(model), "caps").present).toBe(true); + const reopened = expectValidRoundTrip(model); + const run = paragraphs(reopened)[0]!.children.find((c): c is WmlRun => c.kind === "run")!; + expect(getRunProp(run, "caps").present).toBe(true); + }); + + it("sets superscript (vertAlign) with a value", () => { + const model = editorWith(["x2"]); + runCommand(model, getCommand("text.vertAlign")!, { val: "superscript" }); + expect(getRunProp(firstRun(model), "vertAlign").val).toBe("superscript"); + expectValidRoundTrip(model); + }); +}); + +describe("generic paragraph property commands", () => { + it("toggles keepNext and sets outlineLvl", () => { + const model = editorWith(["heading-ish"]); + runCommand(model, getCommand("paragraph.keepNext")!, undefined); + runCommand(model, getCommand("paragraph.outlineLvl")!, { val: "0" }); + const p = paragraphs(model.doc)[0]!; + expect(getParagraphProp(p, "keepNext").present).toBe(true); + expect(getParagraphProp(p, "outlineLvl").val).toBe("0"); + expectValidRoundTrip(model); + }); +}); + +describe("table property commands", () => { + it("sets a cell no-wrap flag", () => { + const model = editorWith([""]); + const table = addTable(model.doc, [["a", "b"]]); + const blockIndex = model.doc.document.body.blocks.indexOf(table); + model.setSelection(caretAt({ block: blockIndex, cell: { row: 0, col: 0 } })); + runCommand(model, getCommand("table.cell_noWrap")!, undefined); + const cell = tables(model.doc)[0]!.rows[0]!.cells[0]!; + expect(getElementProp(cell.tcPr, "noWrap").present).toBe(true); + expectValidRoundTrip(model); + }); +}); + +describe("section property commands", () => { + it("enables a title page", () => { + const model = editorWith(["body"]); + runCommand(model, getCommand("section.titlePg")!, undefined); + expect(getElementProp(model.doc.document.body.sectPr, "titlePg").present).toBe(true); + expectValidRoundTrip(model); + }); +}); + +describe("document property commands", () => { + it("sets extended app properties", () => { + const model = editorWith(["x"]); + runCommand(model, getCommand("docprops.setApp")!, { company: "word-kit", manager: "Ada" }); + const reopened = expectValidRoundTrip(model); + expect(appProperties(reopened).company).toBe("word-kit"); + expect(appProperties(reopened).manager).toBe("Ada"); + }); +}); + +describe("registry sanity", () => { + it("exposes a substantial editable command surface", () => { + // Guardrail so a regression that strips command modules is caught. + expect(commandsInGroup("text").length).toBeGreaterThanOrEqual(20); + expect(commandsInGroup("table").length).toBeGreaterThanOrEqual(15); + }); +}); diff --git a/packages/editor/src/commands/properties.ts b/packages/editor/src/commands/properties.ts new file mode 100644 index 0000000..2eacaad --- /dev/null +++ b/packages/editor/src/commands/properties.ts @@ -0,0 +1,172 @@ +/** + * Generic run/paragraph property commands. + * + * Rather than a bespoke command per WordprocessingML formatting element, these + * factories drive the library's generic property setters (`setRunOnOff` / + * `setRunValProp` / `setParagraphOnOff` / `setParagraphValProp`) so the whole + * long tail of `` / `` on-off and single-value formatting becomes + * editable. Each generated command id is `text.` or `paragraph.`, + * which the capability ledger maps `w:` onto. + */ + +import { + getParagraphProp, + getRunProp, + setParagraphOnOff, + setParagraphValProp, + setRunOnOff, + setRunValProp, + type WmlParagraph, +} from "@office-kit/docx"; +import { paragraphsInRange } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import { orderSelection } from "../selection.js"; +import { applyToSelectionRuns, overlappingSelectionRuns } from "../selection-runs.js"; +import type { Command } from "./types.js"; + +function selectedParagraphs(model: EditorModel): WmlParagraph[] { + const sel = model.selection; + return sel ? paragraphsInRange(model.doc, orderSelection(sel)) : []; +} + +/** On-off `` elements that toggle a character effect. */ +const RUN_ONOFF: { local: string; label: string }[] = [ + { local: "caps", label: "All caps" }, + { local: "smallCaps", label: "Small caps" }, + { local: "dstrike", label: "Double strikethrough" }, + { local: "outline", label: "Outline" }, + { local: "shadow", label: "Shadow" }, + { local: "emboss", label: "Emboss" }, + { local: "imprint", label: "Engrave" }, + { local: "vanish", label: "Hidden" }, + { local: "specVanish", label: "Always hidden" }, + { local: "webHidden", label: "Web hidden" }, + { local: "noProof", label: "Do not check spelling" }, + { local: "snapToGrid", label: "Snap to grid" }, + { local: "rtl", label: "Right-to-left" }, + { local: "cs", label: "Complex script" }, + { local: "oMath", label: "Office math run" }, +]; + +/** Single-value `` elements. */ +const RUN_VAL: { local: string; label: string }[] = [ + { local: "vertAlign", label: "Superscript/subscript" }, // baseline | superscript | subscript + { local: "em", label: "Emphasis mark" }, // none | dot | comma | circle | underDot + { local: "position", label: "Character position" }, // signed half-points + { local: "kern", label: "Kerning" }, // half-points + { local: "spacing", label: "Character spacing" }, // signed twips + { local: "w", label: "Character scale" }, // percent + { local: "effect", label: "Text effect" }, // blinkBackground | lights | … + { local: "rStyle", label: "Character style" }, // styleId +]; + +/** On-off `` elements. */ +const PARA_ONOFF: { local: string; label: string }[] = [ + { local: "keepNext", label: "Keep with next" }, + { local: "keepLines", label: "Keep lines together" }, + { local: "pageBreakBefore", label: "Page break before" }, + { local: "widowControl", label: "Widow/orphan control" }, + { local: "suppressLineNumbers", label: "Suppress line numbers" }, + { local: "suppressAutoHyphens", label: "Suppress hyphenation" }, + { local: "kinsoku", label: "Kinsoku (line breaking)" }, + { local: "wordWrap", label: "Allow latin word-break" }, + { local: "overflowPunct", label: "Overflow punctuation" }, + { local: "topLinePunct", label: "Compress top-line punctuation" }, + { local: "autoSpaceDE", label: "Auto-space CJK/Latin" }, + { local: "autoSpaceDN", label: "Auto-space CJK/number" }, + { local: "bidi", label: "Right-to-left paragraph" }, + { local: "adjustRightInd", label: "Auto-adjust right indent" }, + { local: "snapToGrid", label: "Snap to grid" }, + { local: "contextualSpacing", label: "No space between same style" }, + { local: "mirrorIndents", label: "Mirror indents" }, + { local: "suppressOverlap", label: "Suppress frame overlap" }, +]; + +/** Single-value `` elements. */ +const PARA_VAL: { local: string; label: string }[] = [ + { local: "textDirection", label: "Text direction" }, // lrTb | tbRl | … + { local: "textAlignment", label: "Vertical text alignment" }, // top | center | baseline | bottom | auto + { local: "outlineLvl", label: "Outline level" }, // 0-9 + { local: "divId", label: "HTML div id" }, +]; + +function runToggle({ local, label }: { local: string; label: string }): Command { + return { + id: `text.${local}`, + group: "text", + label, + run(model) { + const runs = overlappingSelectionRuns(model); + const next = !runs.every((r) => getRunProp(r, local).present) || runs.length === 0; + applyToSelectionRuns(model, (r) => setRunOnOff(r, local, next)); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, + isActive: (model) => { + const runs = overlappingSelectionRuns(model); + return runs.length > 0 && runs.every((r) => getRunProp(r, local).present); + }, + }; +} + +function runVal({ + local, + label, +}: { + local: string; + label: string; +}): Command<{ val: string | undefined }> { + return { + id: `text.${local}`, + group: "text", + label, + run(model, { val }) { + applyToSelectionRuns(model, (r) => setRunValProp(r, local, val)); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, + }; +} + +function paraToggle({ local, label }: { local: string; label: string }): Command { + return { + id: `paragraph.${local}`, + group: "paragraph", + label, + run(model) { + const paras = selectedParagraphs(model); + const next = !paras.every((p) => getParagraphProp(p, local).present) || paras.length === 0; + for (const p of paras) setParagraphOnOff(p, local, next); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, + isActive: (model) => { + const paras = selectedParagraphs(model); + return paras.length > 0 && paras.every((p) => getParagraphProp(p, local).present); + }, + }; +} + +function paraVal({ + local, + label, +}: { + local: string; + label: string; +}): Command<{ val: string | undefined }> { + return { + id: `paragraph.${local}`, + group: "paragraph", + label, + run(model, { val }) { + for (const p of selectedParagraphs(model)) setParagraphValProp(p, local, val); + }, + isEnabled: (model) => selectedParagraphs(model).length > 0, + }; +} + +export const runPropertyCommands = [...RUN_ONOFF.map(runToggle), ...RUN_VAL.map(runVal)]; +export const paragraphPropertyCommands = [...PARA_ONOFF.map(paraToggle), ...PARA_VAL.map(paraVal)]; + +/** The set of `w:` element names these commands make editable. */ +export const RUN_PROPERTY_ELEMENTS = [...RUN_ONOFF, ...RUN_VAL].map((e) => e.local); +export const PARA_PROPERTY_ELEMENTS = [...PARA_ONOFF, ...PARA_VAL].map((e) => e.local); + +export const propertyCommands = [...runPropertyCommands, ...paragraphPropertyCommands]; diff --git a/packages/editor/src/commands/raw.ts b/packages/editor/src/commands/raw.ts new file mode 100644 index 0000000..e386fcf --- /dev/null +++ b/packages/editor/src/commands/raw.ts @@ -0,0 +1,156 @@ +/** + * Universal raw-XML editing commands. They operate on any `XmlElement` in the + * document AST (typically a DrawingML / OMML / VML node reached via the + * raw-XML inspector), setting attributes or child elements. This is the escape + * hatch that makes every OOXML element editable — the mutation flushes through + * the document AST on save, so DrawingML shape geometry, math, and legacy VML + * are all reachable even without a bespoke command per element. + */ + +import { + appendChildElement, + getElementAttr, + getElementProp, + markRawPartDirty, + setElementAttr, + setElementOnOff, + setElementValProp, + type XmlElement, +} from "@office-kit/docx"; +import type { Command } from "./types.js"; + +/** Set (or remove, with `undefined`) an attribute on a raw element. */ +export const setAttributeCommand: Command<{ + target: XmlElement; + local: string; + value: string | undefined; +}> = { + id: "raw.setAttribute", + group: "advanced", + label: "Set XML attribute", + run(_model, { target, local, value }) { + setElementAttr(target, local, value); + }, +}; + +/** Toggle an on-off child element (``) on a raw element. */ +export const setChildOnOffCommand: Command<{ + target: XmlElement; + local: string; + on: boolean; +}> = { + id: "raw.setChildOnOff", + group: "advanced", + label: "Toggle XML child", + run(_model, { target, local, on }) { + setElementOnOff(target, local, on); + }, +}; + +/** Set a single-value child element (``) on a raw element. */ +export const setChildValCommand: Command<{ + target: XmlElement; + local: string; + val: string | undefined; +}> = { + id: "raw.setChildVal", + group: "advanced", + label: "Set XML child value", + run(_model, { target, local, val }) { + setElementValProp(target, local, val); + }, +}; + +/** Append a new child element to a raw element and (optionally) read it back. */ +export const addChildCommand: Command<{ target: XmlElement; local: string }> = { + id: "raw.addChild", + group: "advanced", + label: "Add XML child", + run(_model, { target, local }) { + appendChildElement(target, local); + }, +}; + +// --- Part-level raw editing --------------------------------------------------- +// +// Same operations, but on an element that belongs to a non-document XML part +// (fontTable / settings / styles / numbering / comments / notes / headers / +// footers / webSettings / docProps). The part must be marked dirty so its bytes +// are re-serialized on save. + +/** Set (or remove) an attribute on an element inside an arbitrary XML part. */ +export const setPartAttributeCommand: Command<{ + partName: string; + target: XmlElement; + local: string; + value: string | undefined; +}> = { + id: "rawpart.setAttribute", + group: "advanced", + label: "Set part XML attribute", + run(model, { partName, target, local, value }) { + setElementAttr(target, local, value); + markRawPartDirty(model.doc, partName); + }, +}; + +/** Toggle an on-off child element on an element inside an arbitrary XML part. */ +export const setPartChildOnOffCommand: Command<{ + partName: string; + target: XmlElement; + local: string; + on: boolean; +}> = { + id: "rawpart.setChildOnOff", + group: "advanced", + label: "Toggle part XML child", + run(model, { partName, target, local, on }) { + setElementOnOff(target, local, on); + markRawPartDirty(model.doc, partName); + }, +}; + +/** Set a single-value child element on an element inside an arbitrary XML part. */ +export const setPartChildValCommand: Command<{ + partName: string; + target: XmlElement; + local: string; + val: string | undefined; +}> = { + id: "rawpart.setChildVal", + group: "advanced", + label: "Set part XML child value", + run(model, { partName, target, local, val }) { + setElementValProp(target, local, val); + markRawPartDirty(model.doc, partName); + }, +}; + +/** Append a new child element to an element inside an arbitrary XML part. */ +export const addPartChildCommand: Command<{ + partName: string; + target: XmlElement; + local: string; +}> = { + id: "rawpart.addChild", + group: "advanced", + label: "Add part XML child", + run(model, { partName, target, local }) { + appendChildElement(target, local); + markRawPartDirty(model.doc, partName); + }, +}; + +/** Read helpers re-exported so an inspector UI can render current values. */ +export { getElementAttr, getElementProp }; + +export const rawCommands = [ + setAttributeCommand, + setChildOnOffCommand, + setChildValCommand, + addChildCommand, + setPartAttributeCommand, + setPartChildOnOffCommand, + setPartChildValCommand, + addPartChildCommand, +]; diff --git a/packages/editor/src/commands/references.ts b/packages/editor/src/commands/references.ts new file mode 100644 index 0000000..e88f258 --- /dev/null +++ b/packages/editor/src/commands/references.ts @@ -0,0 +1,130 @@ +/** + * Reference commands: bookmarks, hyperlinks (external + internal anchor), + * footnotes, endnotes, fields (PAGE/DATE/…), MERGEFIELD, and a table of + * contents. Paragraph-scoped commands attach to the caret paragraph. + */ + +import { + addBookmark, + addEndnote, + addFootnote, + addHyperlink, + addInternalHyperlink, + addTableOfContents, + type AddTableOfContentsOptions, + appendField, + appendMergeField, +} from "@office-kit/docx"; +import { paragraphAt } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import type { Command } from "./types.js"; +import { caretBlockIndex, moveLastBlockAfter } from "./insert-util.js"; + +/** The caret paragraph, or undefined when the caret is not in a paragraph. */ +function caretParagraph(model: EditorModel) { + const pos = model.selection?.focus; + return pos ? paragraphAt(model.doc, pos) : undefined; +} + +export const addBookmarkCommand: Command<{ name: string }> = { + id: "references.bookmark", + group: "references", + label: "Bookmark", + run(model, { name }) { + const para = caretParagraph(model); + if (para) addBookmark(model.doc, name, para); + }, + isEnabled: (model) => !!caretParagraph(model), +}; + +export const insertHyperlinkCommand: Command<{ url: string; text: string; tooltip?: string }> = { + id: "references.hyperlink", + group: "references", + label: "Hyperlink", + run(model, { url, text, tooltip }) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + addHyperlink(model.doc, url, text, tooltip !== undefined ? { tooltip } : {}); + moveLastBlockAfter(model.doc, at); + }, +}; + +export const insertInternalLinkCommand: Command<{ + bookmark: string; + text: string; + tooltip?: string; +}> = { + id: "references.internalLink", + group: "references", + label: "Link to bookmark", + run(model, { bookmark, text, tooltip }) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + addInternalHyperlink(model.doc, bookmark, text, tooltip !== undefined ? { tooltip } : {}); + moveLastBlockAfter(model.doc, at); + }, +}; + +export const addFootnoteCommand: Command<{ text: string }> = { + id: "references.footnote", + group: "references", + label: "Footnote", + run(model, { text }) { + const para = caretParagraph(model); + if (para) addFootnote(model.doc, para, text); + }, + isEnabled: (model) => !!caretParagraph(model), +}; + +export const addEndnoteCommand: Command<{ text: string }> = { + id: "references.endnote", + group: "references", + label: "Endnote", + run(model, { text }) { + const para = caretParagraph(model); + if (para) addEndnote(model.doc, para, text); + }, + isEnabled: (model) => !!caretParagraph(model), +}; + +export const insertFieldCommand: Command<{ instruction: string }> = { + id: "references.field", + group: "references", + label: "Field", + run(model, { instruction }) { + const para = caretParagraph(model); + if (para) appendField(model.doc, para, instruction); + }, + isEnabled: (model) => !!caretParagraph(model), +}; + +export const insertMergeFieldCommand: Command<{ fieldName: string; displayText?: string }> = { + id: "references.mergeField", + group: "references", + label: "Merge field", + run(model, { fieldName, displayText }) { + const para = caretParagraph(model); + if (para) appendMergeField(model.doc, para, fieldName, displayText); + }, + isEnabled: (model) => !!caretParagraph(model), +}; + +export const insertTocCommand: Command = { + id: "references.toc", + group: "references", + label: "Table of contents", + run(model, options) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + addTableOfContents(model.doc, options); + moveLastBlockAfter(model.doc, at); + }, +}; + +export const referencesCommands = [ + addBookmarkCommand, + insertHyperlinkCommand, + insertInternalLinkCommand, + addFootnoteCommand, + addEndnoteCommand, + insertFieldCommand, + insertMergeFieldCommand, + insertTocCommand, +]; diff --git a/packages/editor/src/commands/registry.ts b/packages/editor/src/commands/registry.ts new file mode 100644 index 0000000..7908d13 --- /dev/null +++ b/packages/editor/src/commands/registry.ts @@ -0,0 +1,66 @@ +/** + * The command registry — the single source of truth for every editor command. + * + * The coverage ledger validates that each WordprocessingML element classified + * `edit` names a command id that exists here, so this registry is what makes + * the completeness guarantee enforceable: an element can only claim to be + * editable if a real command backs it. + */ + +import { docpropsCommands } from "./docprops.js"; +import { headerFooterCommands } from "./header-footer.js"; +import { imageCommands } from "./image.js"; +import { listCommands } from "./list.js"; +import { numberingPropertyCommands } from "./numbering-props.js"; +import { paragraphCommands } from "./paragraph.js"; +import { paragraphPropertyCommands, runPropertyCommands } from "./properties.js"; +import { rawCommands } from "./raw.js"; +import { referencesCommands } from "./references.js"; +import { reviewCommands } from "./review.js"; +import { sectionCommands } from "./section.js"; +import { sectionPropertyCommands } from "./section-props.js"; +import { settingsCommands } from "./settings.js"; +import { structureCommands } from "./structure.js"; +import { styleCommands } from "./style.js"; +import { stylePropertyCommands } from "./style-props.js"; +import { tableCommands } from "./table.js"; +import { tablePropertyCommands } from "./table-props.js"; +import { textCommands } from "./text.js"; +import type { Command } from "./types.js"; + +/** Every command, in ribbon order. */ +export const ALL_COMMANDS: ReadonlyArray> = [ + ...textCommands, + ...runPropertyCommands, + ...paragraphCommands, + ...paragraphPropertyCommands, + ...structureCommands, + ...listCommands, + ...numberingPropertyCommands, + ...tableCommands, + ...tablePropertyCommands, + ...imageCommands, + ...styleCommands, + ...stylePropertyCommands, + ...sectionCommands, + ...sectionPropertyCommands, + ...headerFooterCommands, + ...referencesCommands, + ...reviewCommands, + ...docpropsCommands, + ...settingsCommands, + ...rawCommands, +] as ReadonlyArray>; + +/** The set of all command ids, for coverage validation. */ +export const COMMAND_IDS: ReadonlySet = new Set(ALL_COMMANDS.map((c) => c.id)); + +/** Look up a command by id. */ +export function getCommand(id: string): Command | undefined { + return ALL_COMMANDS.find((c) => c.id === id); +} + +/** All commands in a feature group, for building ribbon sections. */ +export function commandsInGroup(group: Command["group"]): Command[] { + return ALL_COMMANDS.filter((c) => c.group === group); +} diff --git a/packages/editor/src/commands/review.ts b/packages/editor/src/commands/review.ts new file mode 100644 index 0000000..84d8f73 --- /dev/null +++ b/packages/editor/src/commands/review.ts @@ -0,0 +1,54 @@ +/** + * Review commands: add a comment anchored to the caret paragraph, and accept or + * reject all tracked revisions in the document. + */ + +import { + acceptAllRevisions, + addComment, + type AddCommentOptions, + rejectAllRevisions, +} from "@office-kit/docx"; +import { paragraphAt } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import type { Command } from "./types.js"; + +function caretParagraph(model: EditorModel) { + const pos = model.selection?.focus; + return pos ? paragraphAt(model.doc, pos) : undefined; +} + +export const addCommentCommand: Command = { + id: "review.addComment", + group: "review", + label: "New comment", + run(model, options) { + const para = caretParagraph(model); + if (para) addComment(model.doc, para, options); + }, + isEnabled: (model) => !!caretParagraph(model), +}; + +export const acceptAllRevisionsCommand: Command = { + id: "review.acceptAll", + group: "review", + label: "Accept all changes", + run(model) { + acceptAllRevisions(model.doc); + }, +}; + +export const rejectAllRevisionsCommand: Command = { + id: "review.rejectAll", + group: "review", + label: "Reject all changes", + run(model) { + rejectAllRevisions(model.doc); + }, +}; + +export const reviewCommands = [ + addCommentCommand, + acceptAllRevisionsCommand, + rejectAllRevisionsCommand, +]; diff --git a/packages/editor/src/commands/section-props.ts b/packages/editor/src/commands/section-props.ts new file mode 100644 index 0000000..ad522ba --- /dev/null +++ b/packages/editor/src/commands/section-props.ts @@ -0,0 +1,66 @@ +/** + * Section property commands for the long tail of ``: title page, + * vertical alignment, text direction, RTL, form protection, endnote + * suppression. These ensure the body's trailing `` exists, then set + * the property via the library's container-level setters. + */ + +import { + getElementProp, + makePropsElement, + setElementOnOff, + setElementValProp, + type XmlElement, +} from "@office-kit/docx"; +import type { EditorModel } from "../model.js"; +import type { Command } from "./types.js"; + +/** Ensure the body has a trailing `` and return it. */ +function ensureSectPr(model: EditorModel): XmlElement { + const body = model.doc.document.body; + if (!body.sectPr) body.sectPr = makePropsElement("sectPr"); + return body.sectPr; +} + +const SECT_ONOFF = [ + { local: "titlePg", label: "Different first page" }, + { local: "bidi", label: "Right-to-left section" }, + { local: "rtlGutter", label: "RTL gutter" }, + { local: "noEndnote", label: "Suppress endnotes" }, + { local: "formProt", label: "Protect form" }, +]; +const SECT_VAL = [ + { local: "textDirection", label: "Section text direction" }, + { local: "vAlign", label: "Vertical page alignment" }, // top | center | both | bottom +]; + +export const sectionPropertyCommands: Command[] = [ + ...SECT_ONOFF.map( + ({ local, label }): Command => ({ + id: `section.${local}`, + group: "section", + label, + run(model) { + setElementOnOff( + ensureSectPr(model), + local, + !getElementProp(model.doc.document.body.sectPr, local).present, + ); + }, + isActive: (model) => getElementProp(model.doc.document.body.sectPr, local).present, + }), + ), + ...SECT_VAL.map( + ({ local, label }): Command<{ val: string | undefined }> => ({ + id: `section.${local}`, + group: "section", + label, + run(model, { val }) { + setElementValProp(ensureSectPr(model), local, val); + }, + }), + ), +] as Command[]; + +/** `w:` element names these commands make editable. */ +export const SECTION_PROPERTY_ELEMENTS = [...SECT_ONOFF, ...SECT_VAL].map((e) => e.local); diff --git a/packages/editor/src/commands/section.ts b/packages/editor/src/commands/section.ts new file mode 100644 index 0000000..b3550a7 --- /dev/null +++ b/packages/editor/src/commands/section.ts @@ -0,0 +1,63 @@ +/** + * Section / page-setup commands: page size, margins, orientation, and section + * breaks. These operate on the document's trailing section properties via the + * `@office-kit/docx` page functions. + */ + +import { + appendSectionBreak, + type PageMargins, + type PageSize, + setPageMargins, + setPageOrientation, + setPageSize, +} from "@office-kit/docx"; +import { caretBlockIndex, moveLastBlockAfter } from "./insert-util.js"; +import type { Command } from "./types.js"; + +export const setPageSizeCommand: Command<{ size: PageSize }> = { + id: "section.pageSize", + group: "section", + label: "Page size", + run(model, { size }) { + setPageSize(model.doc, size); + }, +}; + +export const setPageMarginsCommand: Command<{ margins: PageMargins }> = { + id: "section.pageMargins", + group: "section", + label: "Margins", + run(model, { margins }) { + setPageMargins(model.doc, margins); + }, +}; + +export const setOrientationCommand: Command<{ orientation: "portrait" | "landscape" }> = { + id: "section.orientation", + group: "section", + label: "Orientation", + run(model, { orientation }) { + setPageOrientation(model.doc, orientation); + }, +}; + +export const insertSectionBreakCommand: Command<{ + type?: "continuous" | "nextPage" | "evenPage" | "oddPage" | "nextColumn"; +}> = { + id: "section.break", + group: "section", + label: "Section break", + run(model, { type = "nextPage" }) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + appendSectionBreak(model.doc, type); + moveLastBlockAfter(model.doc, at); + }, +}; + +export const sectionCommands = [ + setPageSizeCommand, + setPageMarginsCommand, + setOrientationCommand, + insertSectionBreakCommand, +]; diff --git a/packages/editor/src/commands/settings.ts b/packages/editor/src/commands/settings.ts new file mode 100644 index 0000000..d2cff36 --- /dev/null +++ b/packages/editor/src/commands/settings.ts @@ -0,0 +1,122 @@ +/** + * Document-settings commands (`word/settings.xml`). Each `` on-off + * or single-value child gets a `settings.` command backed by the + * library's `setDocumentSettingOnOff` / `setDocumentSettingVal`. This makes the + * bulk of `CT_Settings` (spelling/grid/print/track-changes/hyphenation flags, + * default tab stop, hyphenation zone, …) editable. + */ + +import { + getDocumentSetting, + setDocumentSettingOnOff, + setDocumentSettingVal, +} from "@office-kit/docx"; +import type { Command } from "./types.js"; + +/** On-off (`CT_OnOff` / `CT_Empty`) settings. */ +const SETTINGS_ONOFF: string[] = [ + "removePersonalInformation", + "removeDateAndTime", + "doNotDisplayPageBoundaries", + "displayBackgroundShape", + "printPostScriptOverText", + "printFractionalCharacterWidth", + "printFormsData", + "embedTrueTypeFonts", + "embedSystemFonts", + "saveSubsetFonts", + "saveFormsData", + "mirrorMargins", + "alignBordersAndEdges", + "bordersDoNotSurroundHeader", + "bordersDoNotSurroundFooter", + "gutterAtTop", + "hideSpellingErrors", + "hideGrammaticalErrors", + "formsDesign", + "linkStyles", + "trackRevisions", + "doNotTrackMoves", + "doNotTrackFormatting", + "autoFormatOverride", + "styleLockTheme", + "styleLockQFSet", + "autoHyphenation", + "doNotHyphenateCaps", + "showEnvelope", + "evenAndOddHeaders", + "bookFoldRevPrinting", + "bookFoldPrinting", + "doNotUseMarginsForDrawingGridOrigin", + "doNotShadeFormData", + "noPunctuationKerning", + "printTwoOnOne", + "strictFirstAndLastChars", + "savePreviewPicture", + "doNotValidateAgainstSchema", + "saveInvalidXml", + "ignoreMixedContent", + "alwaysShowPlaceholderText", + "doNotDemarcateInvalidXml", + "saveXmlDataOnly", + "useXSLTWhenSaving", + "showXMLTags", + "alwaysMergeEmptyNamespace", + "updateFields", + "doNotIncludeSubdocsInStats", + "doNotAutoCompressPictures", + "doNotEmbedSmartTags", + "forceUpgrade", +]; + +/** Single-value settings (`CT_TwipsMeasure` / `CT_DecimalNumber` / `CT_String` / …). */ +const SETTINGS_VAL: string[] = [ + "defaultTabStop", + "consecutiveHyphenLimit", + "hyphenationZone", + "summaryLength", + "clickAndTypeStyle", + "defaultTableStyle", + "bookFoldPrintingSheets", + "drawingGridHorizontalSpacing", + "drawingGridVerticalSpacing", + "displayHorizontalDrawingGridEvery", + "displayVerticalDrawingGridEvery", + "drawingGridHorizontalOrigin", + "drawingGridVerticalOrigin", + "decimalSymbol", + "listSeparator", + "characterSpacingControl", + "documentType", +]; + +function settingToggle(local: string): Command { + return { + id: `settings.${local}`, + group: "advanced", + label: `Setting: ${local}`, + run(model) { + setDocumentSettingOnOff(model.doc, local, !getDocumentSetting(model.doc, local).present); + }, + isActive: (model) => getDocumentSetting(model.doc, local).present, + }; +} + +function settingVal(local: string): Command<{ val: string | undefined }> { + return { + id: `settings.${local}`, + group: "advanced", + label: `Setting: ${local}`, + run(model, { val }) { + setDocumentSettingVal(model.doc, local, val); + }, + }; +} + +export const settingsCommands = [ + ...SETTINGS_ONOFF.map(settingToggle), + ...SETTINGS_VAL.map(settingVal), +]; + +/** `w:` element names these commands make editable (all → `settings.`). */ +export const SETTINGS_ELEMENTS = [...SETTINGS_ONOFF, ...SETTINGS_VAL]; diff --git a/packages/editor/src/commands/split-merge.test.ts b/packages/editor/src/commands/split-merge.test.ts new file mode 100644 index 0000000..bf57de7 --- /dev/null +++ b/packages/editor/src/commands/split-merge.test.ts @@ -0,0 +1,49 @@ +/** + * Split (Enter) and merge (Backspace-at-start) round-trip tests — the core of + * the interactive editing experience. + */ + +import { + createDocx, + openDocx, + paragraphs, + paragraphText, + toUint8Array, + validate, +} from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { editorFor } from "../index.js"; +import { caretAt } from "../selection.js"; +import { mergeBackCommand, splitParagraphCommand } from "./structure.js"; +import { runCommand } from "./types.js"; + +describe("splitParagraphCommand", () => { + it("splits the caret paragraph at the offset and round-trips", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world"] })); + model.setSelection(caretAt({ block: 0, inline: 0, offset: 5 })); + runCommand(model, splitParagraphCommand, undefined); + expect(paragraphs(model.doc).map(paragraphText)).toEqual(["Hello", " world"]); + // Caret lands at the start of the new paragraph. + expect(model.selection?.focus.block).toBe(1); + + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + expect(paragraphs(re).map(paragraphText)).toEqual(["Hello", " world"]); + }); +}); + +describe("mergeBackCommand", () => { + it("merges the caret paragraph into the previous one and round-trips", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello", " world"] })); + model.setSelection(caretAt({ block: 1, inline: 0, offset: 0 })); + runCommand(model, mergeBackCommand, undefined); + expect(paragraphs(model.doc).map(paragraphText)).toEqual(["Hello world"]); + // Caret lands at the join point. + expect(model.selection?.focus.block).toBe(0); + expect(model.selection?.focus.offset).toBe(5); + + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + expect(paragraphs(re).map(paragraphText)).toEqual(["Hello world"]); + }); +}); diff --git a/packages/editor/src/commands/structure.ts b/packages/editor/src/commands/structure.ts new file mode 100644 index 0000000..a8de0ea --- /dev/null +++ b/packages/editor/src/commands/structure.ts @@ -0,0 +1,167 @@ +/** + * Block-structure commands: insert paragraphs / headings / breaks, and remove + * blocks. Positional inserts use the append-then-move helper so new content + * lands at the caret rather than the end of the document. + */ + +import { + appendHeading, + appendLineBreak, + appendPageBreak, + appendParagraph, + type AppendParagraphOptions, + ensureHeadingStyles, + mergeParagraphIntoPrevious, + paragraphs, + removeParagraph, + removeTable, + splitParagraphAt, +} from "@office-kit/docx"; +import { blockAt, paragraphAt } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import { caretAt } from "../selection.js"; +import { caretBlockIndex, moveLastBlockAfter } from "./insert-util.js"; +import type { Command } from "./types.js"; + +/** + * Split the caret paragraph in two at the caret (the Enter key). Falls back to + * inserting an empty paragraph after the caret block when the caret is not on a + * top-level paragraph (e.g. inside a table cell). + */ +export const splitParagraphCommand: Command = { + id: "structure.splitParagraph", + group: "structure", + label: "Split paragraph", + run(model) { + const pos = model.selection?.focus; + if (!pos) return; + const newBlock = splitParagraphAt(model.doc, pos.block, pos.inline ?? 0, pos.offset ?? 0); + if (newBlock >= 0) { + model.setSelection(caretAt({ block: newBlock, inline: 0, offset: 0 })); + } else { + const at = caretBlockIndex(model.doc, pos.block); + appendParagraph(model.doc, "", {}); + moveLastBlockAfter(model.doc, at); + model.setSelection(caretAt({ block: at + 1 })); + } + }, +}; + +/** + * Merge the caret paragraph into the previous one (Backspace at paragraph + * start). No-op when there is no preceding paragraph. + */ +export const mergeBackCommand: Command = { + id: "structure.mergeBack", + group: "structure", + label: "Merge with previous paragraph", + run(model) { + const pos = model.selection?.focus; + if (!pos) return; + const joined = mergeParagraphIntoPrevious(model.doc, pos.block); + if (joined) model.setSelection(caretAt(joined)); + }, + isEnabled: (model) => { + const block = model.selection?.focus.block; + return block !== undefined && block > 0; + }, +}; + +export const insertParagraphCommand: Command<{ text?: string; options?: AppendParagraphOptions }> = + { + id: "structure.insertParagraph", + group: "structure", + label: "Insert paragraph", + run(model, params) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + appendParagraph(model.doc, params.text ?? "", params.options ?? {}); + moveLastBlockAfter(model.doc, at); + model.setSelection(caretAt({ block: at + 1 })); + }, + }; + +export const insertHeadingCommand: Command<{ text: string; level?: number }> = { + id: "structure.insertHeading", + group: "structure", + label: "Insert heading", + run(model, { text, level = 1 }) { + // Define the built-in heading styles so the heading's pStyle reference is + // not dangling (Word would otherwise fall back to Normal). + ensureHeadingStyles(model.doc); + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + appendHeading(model.doc, text, level); + moveLastBlockAfter(model.doc, at); + model.setSelection(caretAt({ block: at + 1 })); + }, +}; + +export const insertPageBreakCommand: Command = { + id: "structure.insertPageBreak", + group: "structure", + label: "Page break", + run(model) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + appendPageBreak(model.doc); + moveLastBlockAfter(model.doc, at); + }, +}; + +export const insertLineBreakCommand: Command<{ kind?: "line" | "page" | "column" }> = { + id: "structure.insertLineBreak", + group: "structure", + label: "Line break", + run(model, { kind = "line" }) { + const pos = model.selection?.focus; + const para = pos ? paragraphAt(model.doc, pos) : undefined; + if (!para) return; + appendLineBreak(model.doc, para, kind); + }, + isEnabled: (model) => { + const pos = model.selection?.focus; + return !!(pos && paragraphAt(model.doc, pos)); + }, +}; + +export const deleteBlockCommand: Command = { + id: "structure.deleteBlock", + group: "structure", + label: "Delete block", + run(model) { + const block = model.selection?.focus.block; + if (block === undefined) return; + const node = blockAt(model.doc, block); + if (!node) return; + if (node.kind === "table") { + const tableIndex = countKind(model, "table", block); + removeTable(model.doc, tableIndex); + } else if (node.kind === "paragraph") { + const paraIndex = paragraphs(model.doc).indexOf(node); + if (paraIndex >= 0) removeParagraph(model.doc, paraIndex); + } + model.setSelection(caretAt({ block: Math.max(block - 1, 0) })); + }, + isEnabled: (model) => { + const block = model.selection?.focus.block; + return block !== undefined && !!blockAt(model.doc, block); + }, +}; + +/** Index of a block among blocks of the same kind up to `blockIndex`. */ +function countKind(model: EditorModel, kind: "table" | "paragraph", blockIndex: number): number { + const list = model.doc.document.body.blocks; + let n = 0; + for (let i = 0; i < blockIndex && i < list.length; i++) { + if (list[i]?.kind === kind) n++; + } + return n; +} + +export const structureCommands = [ + insertParagraphCommand, + splitParagraphCommand, + mergeBackCommand, + insertHeadingCommand, + insertPageBreakCommand, + insertLineBreakCommand, + deleteBlockCommand, +]; diff --git a/packages/editor/src/commands/style-props.ts b/packages/editor/src/commands/style-props.ts new file mode 100644 index 0000000..c74aa39 --- /dev/null +++ b/packages/editor/src/commands/style-props.ts @@ -0,0 +1,65 @@ +/** + * Style-definition property commands. They edit the `` that the caret + * paragraph currently uses (its `pStyle`), covering the on-off and single-value + * children of `CT_Style` (qFormat, hidden, semiHidden, uiPriority, basedOn, …). + */ + +import { getParagraphStyle, getStyleProp, setStyleOnOff, setStyleValProp } from "@office-kit/docx"; +import { paragraphAt } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import type { Command } from "./types.js"; + +/** The style id of the caret paragraph, if it has one. */ +function targetStyleId(model: EditorModel): string | undefined { + const pos = model.selection?.focus; + const para = pos ? paragraphAt(model.doc, pos) : undefined; + return para ? getParagraphStyle(para) : undefined; +} + +const STYLE_ONOFF = [ + "autoRedefine", + "hidden", + "semiHidden", + "unhideWhenUsed", + "qFormat", + "locked", + "personal", + "personalCompose", + "personalReply", +]; +const STYLE_VAL = ["name", "aliases", "basedOn", "next", "link", "uiPriority", "rsid"]; + +function styleToggle(local: string): Command { + return { + id: `style.${local}`, + group: "style", + label: `Style: ${local}`, + run(model) { + const id = targetStyleId(model); + if (id) setStyleOnOff(model.doc, id, local, !getStyleProp(model.doc, id, local).present); + }, + isEnabled: (model) => !!targetStyleId(model), + isActive: (model) => { + const id = targetStyleId(model); + return !!id && getStyleProp(model.doc, id, local).present; + }, + }; +} + +function styleVal(local: string): Command<{ val: string | undefined }> { + return { + id: `style.${local}`, + group: "style", + label: `Style: ${local}`, + run(model, { val }) { + const id = targetStyleId(model); + if (id) setStyleValProp(model.doc, id, local, val); + }, + isEnabled: (model) => !!targetStyleId(model), + }; +} + +export const stylePropertyCommands = [...STYLE_ONOFF.map(styleToggle), ...STYLE_VAL.map(styleVal)]; + +/** `w:` element names these commands make editable. */ +export const STYLE_PROPERTY_ELEMENTS = [...STYLE_ONOFF, ...STYLE_VAL]; diff --git a/packages/editor/src/commands/style.ts b/packages/editor/src/commands/style.ts new file mode 100644 index 0000000..1b2f6ca --- /dev/null +++ b/packages/editor/src/commands/style.ts @@ -0,0 +1,31 @@ +/** + * Style commands: define a new paragraph/character style in `styles.xml`, and + * ensure the built-in heading styles exist. Applying a style to a paragraph is + * `paragraph.style` (see ./paragraph.ts). + */ + +import { addStyle, type BuildStyleOptions, ensureHeadingStyles } from "@office-kit/docx"; +import type { Command } from "./types.js"; + +/** Options for a new style. */ +export type AddStyleParams = BuildStyleOptions; + +export const addStyleCommand: Command = { + id: "style.add", + group: "style", + label: "New style", + run(model, options) { + addStyle(model.doc, options); + }, +}; + +export const ensureHeadingStylesCommand: Command = { + id: "style.ensureHeadings", + group: "style", + label: "Ensure heading styles", + run(model) { + ensureHeadingStyles(model.doc); + }, +}; + +export const styleCommands = [addStyleCommand, ensureHeadingStylesCommand]; diff --git a/packages/editor/src/commands/table-props.ts b/packages/editor/src/commands/table-props.ts new file mode 100644 index 0000000..f336f1d --- /dev/null +++ b/packages/editor/src/commands/table-props.ts @@ -0,0 +1,161 @@ +/** + * Generic table / row / cell property commands. These reach the long tail of + * `` / `` / `` on-off and single-value formatting via + * the library's container-level property setters, ensuring the container + * element exists on the current table/row/cell first. + */ + +import { + getElementProp, + makePropsElement, + setElementOnOff, + setElementValProp, + type WmlTable, + type WmlTableCell, + type WmlTableRow, + type XmlElement, +} from "@office-kit/docx"; +import { asTable, blockAt } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import type { Command } from "./types.js"; + +function currentTable(model: EditorModel): WmlTable | undefined { + const block = model.selection?.focus.block; + return block === undefined ? undefined : asTable(blockAt(model.doc, block)); +} + +function currentCell(model: EditorModel): WmlTableCell | undefined { + const table = currentTable(model); + const cell = model.selection?.focus.cell; + return table && cell ? table.rows[cell.row]?.cells[cell.col] : undefined; +} + +function currentRow(model: EditorModel): WmlTableRow | undefined { + const table = currentTable(model); + const cell = model.selection?.focus.cell; + return table && cell ? table.rows[cell.row] : undefined; +} + +/** Ensure `` exists on a table and return it. */ +function ensureTblPr(table: WmlTable): XmlElement { + if (!table.tblPr) table.tblPr = makePropsElement("tblPr"); + return table.tblPr; +} +function ensureTrPr(row: WmlTableRow): XmlElement { + if (!row.trPr) row.trPr = makePropsElement("trPr"); + return row.trPr; +} +function ensureTcPr(cell: WmlTableCell): XmlElement { + if (!cell.tcPr) cell.tcPr = makePropsElement("tcPr"); + return cell.tcPr; +} + +const TBL_ONOFF = [{ local: "bidiVisual", label: "Right-to-left table" }]; +const TBL_VAL = [ + { local: "tblStyle", label: "Table style" }, + { local: "tblLayout", label: "Table layout" }, // fixed | autofit + { local: "tblCaption", label: "Table caption" }, + { local: "tblDescription", label: "Table description" }, + { local: "jc", label: "Table alignment" }, +]; +const TR_ONOFF = [ + { local: "cantSplit", label: "Can't split row" }, + { local: "hidden", label: "Hidden row" }, +]; +const TR_VAL = [ + { local: "jc", label: "Row alignment" }, + { local: "gridBefore", label: "Cells before" }, + { local: "gridAfter", label: "Cells after" }, +]; +const TC_ONOFF = [ + { local: "noWrap", label: "No wrap" }, + { local: "hideMark", label: "Hide end-of-cell mark" }, +]; +const TC_VAL = [ + { local: "gridSpan", label: "Column span" }, + { local: "vMerge", label: "Vertical merge" }, // restart | continue + { local: "hMerge", label: "Horizontal merge" }, + { local: "textDirection", label: "Cell text direction" }, +]; + +type Ent = { local: string; label: string }; + +function containerToggle( + id: string, + { local, label }: Ent, + group: "table", + ensure: (m: EditorModel) => XmlElement | undefined, + read: (m: EditorModel) => XmlElement | undefined, +): Command { + return { + id, + group, + label, + run(model) { + const c = ensure(model); + if (c) setElementOnOff(c, local, !getElementProp(read(model), local).present); + }, + isEnabled: (model) => !!read(model), + isActive: (model) => getElementProp(read(model), local).present, + }; +} + +function containerVal( + id: string, + { local, label }: Ent, + ensure: (m: EditorModel) => XmlElement | undefined, + scope: (m: EditorModel) => boolean, +): Command<{ val: string | undefined }> { + return { + id, + group: "table", + label, + run(model, { val }) { + const c = ensure(model); + if (c) setElementValProp(c, local, val); + }, + isEnabled: scope, + }; +} + +const tblPrOf = (m: EditorModel) => { + const t = currentTable(m); + return t ? ensureTblPr(t) : undefined; +}; +const trPrOf = (m: EditorModel) => { + const r = currentRow(m); + return r ? ensureTrPr(r) : undefined; +}; +const tcPrOf = (m: EditorModel) => { + const c = currentCell(m); + return c ? ensureTcPr(c) : undefined; +}; + +const hasTable = (m: EditorModel) => !!currentTable(m); +const hasRow = (m: EditorModel) => !!currentRow(m); +const hasCell = (m: EditorModel) => !!currentCell(m); + +export const tablePropertyCommands: Command[] = [ + ...TBL_ONOFF.map((e) => + containerToggle(`table.${e.local}`, e, "table", tblPrOf, (m) => currentTable(m)?.tblPr), + ), + ...TBL_VAL.map((e) => containerVal(`table.tbl_${e.local}`, e, tblPrOf, hasTable)), + ...TR_ONOFF.map((e) => + containerToggle(`table.row_${e.local}`, e, "table", trPrOf, (m) => currentRow(m)?.trPr), + ), + ...TR_VAL.map((e) => containerVal(`table.row_${e.local}`, e, trPrOf, hasRow)), + ...TC_ONOFF.map((e) => + containerToggle(`table.cell_${e.local}`, e, "table", tcPrOf, (m) => currentCell(m)?.tcPr), + ), + ...TC_VAL.map((e) => containerVal(`table.cell_${e.local}`, e, tcPrOf, hasCell)), +] as Command[]; + +/** Element local name → the command id that edits it (for the ledger). */ +export const TABLE_PROPERTY_BINDINGS: { local: string; id: string }[] = [ + ...TBL_ONOFF.map((e) => ({ local: e.local, id: `table.${e.local}` })), + ...TBL_VAL.map((e) => ({ local: e.local, id: `table.tbl_${e.local}` })), + ...TR_ONOFF.map((e) => ({ local: e.local, id: `table.row_${e.local}` })), + ...TR_VAL.map((e) => ({ local: e.local, id: `table.row_${e.local}` })), + ...TC_ONOFF.map((e) => ({ local: e.local, id: `table.cell_${e.local}` })), + ...TC_VAL.map((e) => ({ local: e.local, id: `table.cell_${e.local}` })), +]; diff --git a/packages/editor/src/commands/table.ts b/packages/editor/src/commands/table.ts new file mode 100644 index 0000000..5fcb459 --- /dev/null +++ b/packages/editor/src/commands/table.ts @@ -0,0 +1,166 @@ +/** + * Table commands: insert a table, add/remove rows, set cell text and cell + * vertical alignment, mark header rows, set row height, and apply table borders + * / cell shading. Structural table ops resolve the table the caret sits in. + */ + +import { + addTable, + appendTableRow, + removeTableRow, + setTableBorders, + type TableBordersOptions, + type TableCellShadingOptions, + setTableCellShading, + setTableCellText, + setTableCellVerticalAlign, + type TableCellVerticalAlign, + type TableRowHeightRule, + setTableRowAsHeader, + setTableRowHeight, + type WmlTable, +} from "@office-kit/docx"; +import { asTable, blockAt } from "../doc-access.js"; +import type { EditorModel } from "../model.js"; +import { caretAt } from "../selection.js"; +import { caretBlockIndex, moveLastBlockAfter } from "./insert-util.js"; +import type { Command } from "./types.js"; + +/** The table the caret is inside, or undefined. */ +function currentTable(model: EditorModel): WmlTable | undefined { + const block = model.selection?.focus.block; + if (block === undefined) return undefined; + return asTable(blockAt(model.doc, block)); +} + +export const insertTableCommand: Command<{ rows: number; cols: number }> = { + id: "table.insert", + group: "table", + label: "Insert table", + run(model, { rows, cols }) { + const at = caretBlockIndex(model.doc, model.selection?.focus.block); + const grid: string[][] = Array.from({ length: Math.max(rows, 1) }, () => + Array.from({ length: Math.max(cols, 1) }, () => ""), + ); + const table = addTable(model.doc, grid); + setTableBorders(table, {}); + moveLastBlockAfter(model.doc, at); + model.setSelection(caretAt({ block: at + 1, cell: { row: 0, col: 0 } })); + }, +}; + +export const addRowCommand: Command<{ texts?: readonly string[] }> = { + id: "table.addRow", + group: "table", + label: "Add row", + run(model, { texts = [] }) { + const table = currentTable(model); + if (!table) return; + appendTableRow(table, texts); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const deleteRowCommand: Command<{ row?: number }> = { + id: "table.deleteRow", + group: "table", + label: "Delete row", + run(model, { row }) { + const table = currentTable(model); + if (!table) return; + const index = row ?? model.selection?.focus.cell?.row ?? table.rows.length - 1; + removeTableRow(table, index); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const setCellTextCommand: Command<{ row: number; col: number; text: string }> = { + id: "table.setCellText", + group: "table", + label: "Set cell text", + run(model, { row, col, text }) { + const table = currentTable(model); + if (!table) return; + setTableCellText(table, row, col, text); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const setCellVerticalAlignCommand: Command<{ + row: number; + col: number; + align: TableCellVerticalAlign; +}> = { + id: "table.cellVAlign", + group: "table", + label: "Cell vertical alignment", + run(model, { row, col, align }) { + const cell = currentTable(model)?.rows[row]?.cells[col]; + if (cell) setTableCellVerticalAlign(cell, align); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const setRowHeaderCommand: Command<{ row: number; isHeader?: boolean }> = { + id: "table.rowHeader", + group: "table", + label: "Header row", + run(model, { row, isHeader = true }) { + const r = currentTable(model)?.rows[row]; + if (r) setTableRowAsHeader(r, isHeader); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const setRowHeightCommand: Command<{ + row: number; + heightTwips: number; + rule?: TableRowHeightRule; +}> = { + id: "table.rowHeight", + group: "table", + label: "Row height", + run(model, { row, heightTwips, rule = "atLeast" }) { + const r = currentTable(model)?.rows[row]; + if (r) setTableRowHeight(r, heightTwips, rule); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const setTableBordersCommand: Command = { + id: "table.borders", + group: "table", + label: "Table borders", + run(model, options) { + const table = currentTable(model); + if (table) setTableBorders(table, options); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const setCellShadingCommand: Command<{ + row: number; + col: number; + shading: TableCellShadingOptions; +}> = { + id: "table.cellShading", + group: "table", + label: "Cell shading", + run(model, { row, col, shading }) { + const cell = currentTable(model)?.rows[row]?.cells[col]; + if (cell) setTableCellShading(cell, shading); + }, + isEnabled: (model) => !!currentTable(model), +}; + +export const tableCommands = [ + insertTableCommand, + addRowCommand, + deleteRowCommand, + setCellTextCommand, + setCellVerticalAlignCommand, + setRowHeaderCommand, + setRowHeightCommand, + setTableBordersCommand, + setCellShadingCommand, +]; diff --git a/packages/editor/src/commands/text-selection.test.ts b/packages/editor/src/commands/text-selection.test.ts new file mode 100644 index 0000000..8c2e389 --- /dev/null +++ b/packages/editor/src/commands/text-selection.test.ts @@ -0,0 +1,131 @@ +/** + * Selection-aware character formatting: the fix for "bolding a selection bolds + * the whole line". Formatting must split runs at the selection boundaries and + * apply only to the selected characters. + */ + +import { + createDocx, + getRunFormat, + openDocx, + paragraphs, + toUint8Array, + validate, + type WmlRun, +} from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { editorFor } from "../index.js"; +import type { EditorModel } from "../model.js"; +import { toggleBoldCommand, toggleItalicCommand } from "./text.js"; +import { runCommand } from "./types.js"; + +/** [text, bold] for every run of the first paragraph. */ +function runProfile(model: EditorModel): Array<[string, boolean]> { + const runs = paragraphs(model.doc)[0]!.children.filter((c): c is WmlRun => c.kind === "run"); + return runs.map((r) => [ + r.pieces + .filter( + (p): p is { kind: "text"; value: string; preserveSpace: boolean } => p.kind === "text", + ) + .map((p) => p.value) + .join(""), + getRunFormat(r).bold === true, + ]); +} + +function select(model: EditorModel, startOffset: number, endOffset: number): void { + model.setSelection({ + anchor: { block: 0, inline: 0, offset: startOffset }, + focus: { block: 0, inline: 0, offset: endOffset }, + }); +} + +describe("selection-aware bold", () => { + it("bolds only the selected characters, not the whole line", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world foo"] })); + select(model, 6, 11); // "world" + runCommand(model, toggleBoldCommand, undefined); + expect(runProfile(model)).toEqual([ + ["Hello ", false], + ["world", true], + [" foo", false], + ]); + }); + + it("bolds a selection at the very start", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world"] })); + select(model, 0, 5); // "Hello" + runCommand(model, toggleBoldCommand, undefined); + expect(runProfile(model)).toEqual([ + ["Hello", true], + [" world", false], + ]); + }); + + it("bolds a selection to the end", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world"] })); + select(model, 6, 11); // "world" + runCommand(model, toggleBoldCommand, undefined); + expect(runProfile(model)).toEqual([ + ["Hello ", false], + ["world", true], + ]); + }); + + it("keeps the same text selected after formatting", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world foo"] })); + select(model, 6, 11); + runCommand(model, toggleBoldCommand, undefined); + // Selection now targets the isolated "world" run. + const sel = model.selection!; + const runs = paragraphs(model.doc)[0]!.children.filter((c): c is WmlRun => c.kind === "run"); + const focusRun = runs[sel.focus.inline ?? 0]!; + expect(focusRun.pieces.map((p) => (p.kind === "text" ? p.value : "")).join("")).toBe("world"); + expect(getRunFormat(focusRun).bold).toBe(true); + }); + + it("toggles bold off when the selection is already fully bold", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world"] })); + select(model, 0, 5); + runCommand(model, toggleBoldCommand, undefined); // on + select(model, 0, 5); + runCommand(model, toggleBoldCommand, undefined); // off + expect(runProfile(model).find(([t]) => t.startsWith("Hello"))?.[1]).toBe(false); + }); + + it("round-trips a partially-bolded paragraph", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world foo"] })); + select(model, 6, 11); + runCommand(model, toggleBoldCommand, undefined); + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + const runs = paragraphs(re)[0]!.children.filter((c): c is WmlRun => c.kind === "run"); + const bolded = runs.find((r) => getRunFormat(r).bold === true); + expect(bolded?.pieces.map((p) => (p.kind === "text" ? p.value : "")).join("")).toBe("world"); + }); + + it("applies independent formats to overlapping-then-adjacent selections", () => { + const model = editorFor(createDocx({ paragraphs: ["abcdef"] })); + select(model, 0, 3); // "abc" bold + runCommand(model, toggleBoldCommand, undefined); + // Re-select "def" and italicize. + const runs = paragraphs(model.doc)[0]!.children.filter((c): c is WmlRun => c.kind === "run"); + // "def" starts at the second run, offset 0..3. + model.setSelection({ + anchor: { block: 0, inline: runs.length - 1, offset: 0 }, + focus: { block: 0, inline: runs.length - 1, offset: 3 }, + }); + runCommand(model, toggleItalicCommand, undefined); + const profile = paragraphs(model.doc)[0]! + .children.filter((c): c is WmlRun => c.kind === "run") + .map((r) => ({ + t: r.pieces.map((p) => (p.kind === "text" ? p.value : "")).join(""), + b: getRunFormat(r).bold === true, + i: getRunFormat(r).italic === true, + })); + expect(profile).toEqual([ + { t: "abc", b: true, i: false }, + { t: "def", b: false, i: true }, + ]); + }); +}); diff --git a/packages/editor/src/commands/text.ts b/packages/editor/src/commands/text.ts new file mode 100644 index 0000000..f5f9964 --- /dev/null +++ b/packages/editor/src/commands/text.ts @@ -0,0 +1,159 @@ +/** + * Run-level (character) formatting commands. Each routes through + * `setRunFormat` / `getRunFormat` from `@office-kit/docx`, applied to exactly + * the selected characters — {@link applyToSelectionRuns} splits runs at the + * selection boundaries first, so bolding part of a line bolds only that part. + */ + +import { getRunFormat, type RunFormatting, setRunFormat, type WmlRun } from "@office-kit/docx"; +import type { EditorModel } from "../model.js"; +import { applyToSelectionRuns, overlappingSelectionRuns } from "../selection-runs.js"; +import type { Command } from "./types.js"; + +/** True when every run overlapping the selection has the given boolean on. */ +function allHave(runs: WmlRun[], key: "bold" | "italic" | "strike"): boolean { + return runs.length > 0 && runs.every((r) => getRunFormat(r)[key] === true); +} + +function allUnderlined(runs: WmlRun[]): boolean { + return runs.length > 0 && runs.every((r) => (getRunFormat(r).underline ?? "none") !== "none"); +} + +function applyToRuns(model: EditorModel, patch: RunFormatting): void { + applyToSelectionRuns(model, (run) => setRunFormat(run, patch)); +} + +/** Build a boolean toggle command (bold / italic / strike). */ +function toggleBool(id: string, key: "bold" | "italic" | "strike", label: string): Command { + return { + id, + group: "text", + label, + run(model) { + const next = !allHave(overlappingSelectionRuns(model), key); + applyToSelectionRuns(model, (run) => setRunFormat(run, { [key]: next })); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, + isActive: (model) => allHave(overlappingSelectionRuns(model), key), + }; +} + +export const toggleBoldCommand = toggleBool("text.bold", "bold", "Bold"); +export const toggleItalicCommand = toggleBool("text.italic", "italic", "Italic"); +export const toggleStrikeCommand = toggleBool("text.strike", "strike", "Strikethrough"); + +export const toggleUnderlineCommand: Command = { + id: "text.underline", + group: "text", + label: "Underline", + run(model) { + const next = allUnderlined(overlappingSelectionRuns(model)) ? "none" : "single"; + applyToSelectionRuns(model, (run) => setRunFormat(run, { underline: next })); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, + isActive: (model) => allUnderlined(overlappingSelectionRuns(model)), +}; + +/** Set a specific underline style (single/double/wave/dotted/thick). */ +export const setUnderlineStyleCommand: Command<{ + style: NonNullable; +}> = { + id: "text.underlineStyle", + group: "text", + label: "Underline style", + run(model, { style }) { + applyToRuns(model, { underline: style }); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, +}; + +/** Set font family (ASCII/hAnsi). */ +export const setFontCommand: Command<{ font: string }> = { + id: "text.font", + group: "text", + label: "Font", + run(model, { font }) { + applyToRuns(model, { font }); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, +}; + +/** Set East Asian (CJK) font family. */ +export const setFontEastAsiaCommand: Command<{ font: string }> = { + id: "text.fontEastAsia", + group: "text", + label: "East Asian font", + run(model, { font }) { + applyToRuns(model, { fontEastAsia: font }); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, +}; + +/** Set font size in points; converted to the half-points OOXML stores. */ +export const setFontSizeCommand: Command<{ points: number }> = { + id: "text.fontSize", + group: "text", + label: "Font size", + run(model, { points }) { + applyToRuns(model, { fontSizeHalfPoints: Math.round(points * 2) }); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, +}; + +/** Set text color as a hex RGB string (no leading #). */ +export const setColorCommand: Command<{ color: string }> = { + id: "text.color", + group: "text", + label: "Font color", + run(model, { color }) { + applyToRuns(model, { color: normalizeHex(color) }); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, +}; + +/** Set highlight color as a hex RGB string. */ +export const setHighlightCommand: Command<{ color: string }> = { + id: "text.highlight", + group: "text", + label: "Highlight", + run(model, { color }) { + applyToRuns(model, { highlight: normalizeHex(color) }); + }, + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, +}; + +/** Clear all direct run formatting in the selection. */ +export const clearFormattingCommand: Command = { + id: "text.clearFormat", + group: "text", + run(model) { + applyToSelectionRuns(model, (run) => + setRunFormat(run, { + bold: false, + italic: false, + strike: false, + underline: "none", + }), + ); + }, + label: "Clear formatting", + isEnabled: (model) => overlappingSelectionRuns(model).length > 0, +}; + +function normalizeHex(color: string): string { + return color.startsWith("#") ? color.slice(1) : color; +} + +export const textCommands = [ + toggleBoldCommand, + toggleItalicCommand, + toggleStrikeCommand, + toggleUnderlineCommand, + setUnderlineStyleCommand, + setFontCommand, + setFontEastAsiaCommand, + setFontSizeCommand, + setColorCommand, + setHighlightCommand, + clearFormattingCommand, +]; diff --git a/packages/editor/src/commands/types.ts b/packages/editor/src/commands/types.ts new file mode 100644 index 0000000..1694a29 --- /dev/null +++ b/packages/editor/src/commands/types.ts @@ -0,0 +1,62 @@ +/** + * Command layer types. + * + * A command is the *only* way the editor mutates a document. Each command's + * `run` calls the `@office-kit/docx` public API through {@link EditorModel}, + * wrapping the mutation in the model's undo snapshot. The set of command ids is + * the single source of truth the coverage ledger validates against: a + * WordprocessingML element may be classified `edit` only if a real command id + * here handles it. + */ + +import type { EditorModel } from "../model.js"; + +/** Ribbon groupings, mirroring Word's tabs. */ +export type FeatureGroup = + | "text" + | "paragraph" + | "structure" + | "list" + | "table" + | "image" + | "style" + | "section" + | "headerFooter" + | "references" + | "review" + | "advanced"; + +/** + * A command definition. `run` receives the model plus command-specific params; + * it must call {@link EditorModel.beginEdit} before mutating and + * {@link EditorModel.commit} after (the {@link runCommand} helper does this). + */ +export interface Command

{ + readonly id: string; + readonly group: FeatureGroup; + /** Human label for the UI (English; the UI layer localizes). */ + readonly label: string; + /** Longer description for tooltips / command palette. */ + readonly description?: string; + /** Perform the mutation. Return value is ignored; report failures by throwing. */ + run(model: EditorModel, params: P): void; + /** Whether the command applies to the current selection/state. */ + isEnabled?(model: EditorModel): boolean; + /** For toggle commands (bold, italic…): whether it is currently on. */ + isActive?(model: EditorModel): boolean; +} + +/** Run a command with automatic undo-snapshot + commit around the mutation. */ +export function runCommand

(model: EditorModel, command: Command

, params: P): void { + if (command.isEnabled && !command.isEnabled(model)) return; + model.beginEdit(); + try { + command.run(model, params); + } catch (err) { + // The mutation failed after we snapshotted; roll back so the model is not + // left half-edited, then rethrow so the failure surfaces (anti-swallow). + model.undo(); + throw err; + } + model.commit(); +} diff --git a/packages/editor/src/doc-access.ts b/packages/editor/src/doc-access.ts new file mode 100644 index 0000000..f039a89 --- /dev/null +++ b/packages/editor/src/doc-access.ts @@ -0,0 +1,91 @@ +/** + * Helpers for resolving selection positions to the live AST nodes the + * `@office-kit/docx` mutation functions operate on. These read the document + * structure only; they never serialize or mutate. + */ + +import type { Docx, WmlBlock, WmlParagraph, WmlRun, WmlTable } from "@office-kit/docx"; +import type { DocPosition, OrderedSelection } from "./selection.js"; + +/** All top-level blocks in document order. */ +export function blocks(doc: Docx): WmlBlock[] { + return doc.document.body.blocks; +} + +export function blockAt(doc: Docx, index: number): WmlBlock | undefined { + return doc.document.body.blocks[index]; +} + +/** Narrow a block to a paragraph, or undefined if it is a table / raw block. */ +export function asParagraph(block: WmlBlock | undefined): WmlParagraph | undefined { + return block && block.kind === "paragraph" ? block : undefined; +} + +export function asTable(block: WmlBlock | undefined): WmlTable | undefined { + return block && block.kind === "table" ? block : undefined; +} + +/** + * Resolve a position to the paragraph it addresses, following into a table cell + * when the position carries cell coordinates. Returns undefined when the + * position does not land on a paragraph (e.g. a raw block). + */ +export function paragraphAt(doc: Docx, pos: DocPosition): WmlParagraph | undefined { + const block = blockAt(doc, pos.block); + if (!block) return undefined; + if (block.kind === "paragraph") return block; + if (block.kind === "table" && pos.cell) { + const row = block.rows[pos.cell.row]; + const cell = row?.cells[pos.cell.col]; + if (!cell) return undefined; + return cell.paragraphs[pos.para ?? 0]; + } + return undefined; +} + +/** The runs of the paragraph a position addresses. */ +export function runsAt(doc: Docx, pos: DocPosition): WmlRun[] { + const para = paragraphAt(doc, pos); + if (!para) return []; + return para.children.filter((c): c is WmlRun => c.kind === "run"); +} + +/** + * Collect every paragraph touched by an ordered selection, walking top-level + * blocks and (for table blocks) every cell paragraph in range. Used by + * paragraph-level commands (alignment, indent, style…) that apply to the whole + * span, not just the caret paragraph. + */ +export function paragraphsInRange(doc: Docx, sel: OrderedSelection): WmlParagraph[] { + const out: WmlParagraph[] = []; + const all = blocks(doc); + for (let i = sel.start.block; i <= sel.end.block && i < all.length; i++) { + const block = all[i]; + if (!block) continue; + if (block.kind === "paragraph") { + out.push(block); + } else if (block.kind === "table") { + for (const row of block.rows) { + for (const cell of row.cells) { + for (const p of cell.paragraphs) out.push(p); + } + } + } + } + return out; +} + +/** + * Every run touched by an ordered selection. When the selection is collapsed + * (a caret) this is the runs of the caret paragraph, letting toggle commands + * (bold on an empty selection) still report/flip state. + */ +export function runsInRange(doc: Docx, sel: OrderedSelection): WmlRun[] { + const out: WmlRun[] = []; + for (const para of paragraphsInRange(doc, sel)) { + for (const child of para.children) { + if (child.kind === "run") out.push(child); + } + } + return out; +} diff --git a/packages/editor/src/dom-selection.ts b/packages/editor/src/dom-selection.ts new file mode 100644 index 0000000..ca669d5 --- /dev/null +++ b/packages/editor/src/dom-selection.ts @@ -0,0 +1,52 @@ +/** + * Map a browser DOM selection to the editor's document positions, using the + * `data-wk-*` anchors the renderer emits. Browser-only; guarded so importing + * the module in Node (tests) doesn't touch `window`. + */ + +import type { CellCoord, DocPosition, Selection } from "./selection.js"; + +function parseCell(value: string | null): CellCoord | undefined { + if (!value) return undefined; + const [r, c] = value.split(",").map((n) => Number.parseInt(n, 10)); + if (r === undefined || c === undefined || Number.isNaN(r) || Number.isNaN(c)) return undefined; + return { row: r, col: c }; +} + +/** Walk up from a DOM node to the nearest element carrying `data-wk-block`. */ +function anchorElement(node: Node | null): HTMLElement | null { + let el: Node | null = node; + while (el && !(el instanceof HTMLElement && el.hasAttribute("data-wk-block"))) { + el = el.parentNode; + } + return el as HTMLElement | null; +} + +/** Build a {@link DocPosition} from a DOM container node and character offset. */ +export function positionFromDom(node: Node | null, offset: number): DocPosition | null { + const anchor = anchorElement(node); + if (!anchor) return null; + const block = Number.parseInt(anchor.getAttribute("data-wk-block") ?? "", 10); + if (Number.isNaN(block)) return null; + const cell = parseCell(anchor.getAttribute("data-wk-cell")); + const inlineAttr = anchor.getAttribute("data-wk-inline"); + const inline = inlineAttr ? Number.parseInt(inlineAttr, 10) : undefined; + return { + block, + ...(cell ? { cell } : {}), + ...(inline !== undefined && !Number.isNaN(inline) ? { inline } : {}), + offset, + }; +} + +/** Read the current window selection as an editor {@link Selection}. */ +export function readDomSelection(root: Document | ShadowRoot = document): Selection | null { + const domSel = + "getSelection" in root ? (root as Document).getSelection?.() : window.getSelection(); + if (!domSel || domSel.rangeCount === 0) return null; + const range = domSel.getRangeAt(0); + const anchor = positionFromDom(range.startContainer, range.startOffset); + const focus = positionFromDom(range.endContainer, range.endOffset); + if (!anchor || !focus) return null; + return { anchor, focus }; +} diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts new file mode 100644 index 0000000..c578b80 --- /dev/null +++ b/packages/editor/src/index.ts @@ -0,0 +1,58 @@ +/** + * `@office-kit/docx-editor` — an MS Office-like WYSIWYG editing core for + * word-kit `.docx` documents. + * + * The editor never serializes OOXML itself: every mutation runs through a + * {@link Command} that calls the `@office-kit/docx` public API, keeping that + * library the single source of truth. Completeness against the WordprocessingML + * spec is tracked and enforced by the capability ledger under `./coverage`. + * + * @packageDocumentation + */ + +import { createDocx, type Docx, openDocx } from "@office-kit/docx"; +import { EditorModel } from "./model.js"; + +export { EditorModel, type ChangeListener, type EditorSnapshot } from "./model.js"; +export { type Command, type FeatureGroup, runCommand } from "./commands/types.js"; +export { ALL_COMMANDS, COMMAND_IDS, commandsInGroup, getCommand } from "./commands/registry.js"; +// Named command objects + group arrays for typed UI wiring. +export * as commands from "./commands/index.js"; +export { + type CellCoord, + type DocPosition, + type OrderedSelection, + type Selection, + caretAt, + orderSelection, +} from "./selection.js"; +export { renderDocumentHtml, paragraphPlainText } from "./render.js"; +export { positionFromDom, readDomSelection } from "./dom-selection.js"; +export { runAtPath, setSimpleRunText } from "./text-edit.js"; +export { type RawNode, rawTrees, allRawElements, xmlParts, partRawTree } from "./raw-tree.js"; +export { blocks, paragraphAt, paragraphsInRange, runsInRange } from "./doc-access.js"; + +// Coverage / capability ledger — the completeness-guarantee surface. +export { + type Capability, + type Disposition, + classify, + coverageSummary, + LEDGER, +} from "./capability/ledger.js"; +export { renderCoverageMarkdown } from "./capability/report.js"; + +/** Create an editor over a fresh, empty document. */ +export function createEditor(): EditorModel { + return new EditorModel(createDocx({ paragraphs: [""] })); +} + +/** Create an editor over an existing `.docx` (bytes). */ +export function openEditor(bytes: Uint8Array): EditorModel { + return new EditorModel(openDocx(bytes)); +} + +/** Create an editor over an already-open {@link Docx}. */ +export function editorFor(doc: Docx): EditorModel { + return new EditorModel(doc); +} diff --git a/packages/editor/src/integration.test.ts b/packages/editor/src/integration.test.ts new file mode 100644 index 0000000..dc0d446 --- /dev/null +++ b/packages/editor/src/integration.test.ts @@ -0,0 +1,136 @@ +/** + * End-to-end editing-session test: chain the operations a user performs (type, + * format a selection, align, list, heading, split/merge, undo/redo, replace, + * table) and assert the document stays valid and correct throughout. This is + * the "all operations" smoke test guarding the editor's core behaviours. + */ + +import { + createDocx, + getParagraphAlignment, + getParagraphStyle, + getRunFormat, + openDocx, + paragraphs, + paragraphText, + toUint8Array, + validate, + type WmlRun, +} from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { commands, editorFor, runCommand } from "./index.js"; +import type { EditorModel } from "./model.js"; + +function firstParaRuns(model: EditorModel): WmlRun[] { + return paragraphs(model.doc)[0]!.children.filter((c): c is WmlRun => c.kind === "run"); +} + +function selectFirst(model: EditorModel, start: number, end: number): void { + model.setSelection({ + anchor: { block: 0, inline: 0, offset: start }, + focus: { block: 0, inline: 0, offset: end }, + }); +} + +function assertValidRoundTrip(model: EditorModel) { + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + return re; +} + +describe("editing session (all core operations)", () => { + it("chains character formatting on selections and round-trips", () => { + const model = editorFor(createDocx({ paragraphs: ["The quick brown fox"] })); + + selectFirst(model, 4, 9); // "quick" + runCommand(model, commands.toggleBoldCommand, undefined); + selectFirst(model, 10, 15); // "brown" — offsets unchanged since we re-select on original text + // After the first split, run indices changed; re-anchor via absolute offsets. + model.setSelection({ + anchor: { block: 0, inline: 0, offset: 0 }, + focus: { block: 0, inline: 0, offset: 3 }, + }); + runCommand(model, commands.toggleItalicCommand, undefined); + + const re = assertValidRoundTrip(model); + const runs = paragraphs(re)[0]!.children.filter((c): c is WmlRun => c.kind === "run"); + const bolded = runs.find((r) => getRunFormat(r).bold); + expect(bolded?.pieces.map((p) => (p.kind === "text" ? p.value : "")).join("")).toBe("quick"); + }); + + it("applies paragraph alignment, style, and list, then round-trips", () => { + const model = editorFor(createDocx({ paragraphs: ["Heading text", "body one", "body two"] })); + + model.setSelection({ anchor: { block: 0 }, focus: { block: 0 } }); + runCommand(model, commands.alignCenterCommand, undefined); + expect(getParagraphAlignment(paragraphs(model.doc)[0]!)).toBe("center"); + + runCommand(model, commands.insertHeadingCommand, { text: "New Heading", level: 1 }); + const heading = paragraphs(model.doc).find((p) => getParagraphStyle(p) === "Heading1"); + expect(heading).toBeDefined(); + + model.setSelection({ anchor: { block: 1 }, focus: { block: 1 } }); + runCommand(model, commands.applyListCommand, { kind: "bullet" }); + + assertValidRoundTrip(model); + }); + + it("splits, merges, and undoes/redoes with correct final text", () => { + const model = editorFor(createDocx({ paragraphs: ["Hello world"] })); + + model.setSelection({ + anchor: { block: 0, inline: 0, offset: 5 }, + focus: { block: 0, inline: 0, offset: 5 }, + }); + runCommand(model, commands.splitParagraphCommand, undefined); + expect(paragraphs(model.doc).map(paragraphText)).toEqual(["Hello", " world"]); + + model.undo(); + expect(paragraphs(model.doc).map(paragraphText)).toEqual(["Hello world"]); + + model.redo(); + expect(paragraphs(model.doc).map(paragraphText)).toEqual(["Hello", " world"]); + + model.setSelection({ + anchor: { block: 1, inline: 0, offset: 0 }, + focus: { block: 1, inline: 0, offset: 0 }, + }); + runCommand(model, commands.mergeBackCommand, undefined); + expect(paragraphs(model.doc).map(paragraphText)).toEqual(["Hello world"]); + + assertValidRoundTrip(model); + }); + + it("inserts a table and a page break without breaking validity", () => { + const model = editorFor(createDocx({ paragraphs: ["intro"] })); + model.setSelection({ anchor: { block: 0 }, focus: { block: 0 } }); + runCommand(model, commands.insertTableCommand, { rows: 2, cols: 3 }); + runCommand(model, commands.insertPageBreakCommand, undefined); + assertValidRoundTrip(model); + }); + + it("sets font, size, and color on a selection", () => { + const model = editorFor(createDocx({ paragraphs: ["colored text"] })); + selectFirst(model, 0, 7); // "colored" + runCommand(model, commands.setColorCommand, { color: "ff0000" }); + runCommand(model, commands.setFontSizeCommand, { points: 18 }); + + const re = assertValidRoundTrip(model); + const runs = paragraphs(re)[0]!.children.filter((c): c is WmlRun => c.kind === "run"); + const colored = runs.find((r) => getRunFormat(r).color === "ff0000"); + expect(colored).toBeDefined(); + expect(getRunFormat(colored!).fontSizeHalfPoints).toBe(36); + expect(colored!.pieces.map((p) => (p.kind === "text" ? p.value : "")).join("")).toBe("colored"); + }); + + it("keeps run count minimal (no stray empty runs) after formatting", () => { + const model = editorFor(createDocx({ paragraphs: ["abcdefgh"] })); + selectFirst(model, 2, 5); // "cde" + runCommand(model, commands.toggleBoldCommand, undefined); + const runs = firstParaRuns(model); + // Exactly three runs: "ab" | "cde" | "fgh". + expect( + runs.map((r) => r.pieces.map((p) => (p.kind === "text" ? p.value : "")).join("")), + ).toEqual(["ab", "cde", "fgh"]); + }); +}); diff --git a/packages/editor/src/model.ts b/packages/editor/src/model.ts new file mode 100644 index 0000000..ed720e7 --- /dev/null +++ b/packages/editor/src/model.ts @@ -0,0 +1,112 @@ +/** + * The editor's stateful controller. + * + * An editor is inherently stateful (current document, selection, undo history, + * subscribers), so unlike `@office-kit/docx`'s function API this is modelled as + * a small class. It never serializes OOXML itself: every document mutation is + * performed by a {@link Command} that calls the `@office-kit/docx` public API. + * The library remains the single source of truth for the document ("one way to + * do one thing"). + */ + +import { clone, type Docx } from "@office-kit/docx"; +import type { Selection } from "./selection.js"; + +export interface EditorSnapshot { + readonly doc: Docx; + readonly selection: Selection | null; +} + +export type ChangeListener = (model: EditorModel) => void; + +/** How deep the undo/redo history is allowed to grow. */ +const DEFAULT_HISTORY_LIMIT = 200; + +export class EditorModel { + private docState: Docx; + private selectionState: Selection | null = null; + private readonly undoStack: EditorSnapshot[] = []; + private readonly redoStack: EditorSnapshot[] = []; + private readonly listeners = new Set(); + private readonly historyLimit: number; + + constructor(doc: Docx, options: { historyLimit?: number } = {}) { + this.docState = doc; + this.historyLimit = options.historyLimit ?? DEFAULT_HISTORY_LIMIT; + } + + get doc(): Docx { + return this.docState; + } + + get selection(): Selection | null { + return this.selectionState; + } + + setSelection(selection: Selection | null): void { + this.selectionState = selection; + this.emit(); + } + + /** + * Snapshot the current document onto the undo stack before a mutating command + * runs. Redo history is cleared because a new edit forks the timeline. The + * snapshot clones the document so later mutations don't alias it. + */ + beginEdit(): void { + this.undoStack.push({ doc: clone(this.docState), selection: this.selectionState }); + if (this.undoStack.length > this.historyLimit) this.undoStack.shift(); + this.redoStack.length = 0; + } + + /** Notify subscribers that the document (or selection) changed. */ + commit(nextSelection?: Selection | null): void { + if (nextSelection !== undefined) this.selectionState = nextSelection; + this.docState.dirty = true; + this.emit(); + } + + canUndo(): boolean { + return this.undoStack.length > 0; + } + + canRedo(): boolean { + return this.redoStack.length > 0; + } + + undo(): void { + const prev = this.undoStack.pop(); + if (!prev) return; + this.redoStack.push({ doc: clone(this.docState), selection: this.selectionState }); + this.docState = prev.doc; + this.selectionState = prev.selection; + this.emit(); + } + + redo(): void { + const next = this.redoStack.pop(); + if (!next) return; + this.undoStack.push({ doc: clone(this.docState), selection: this.selectionState }); + this.docState = next.doc; + this.selectionState = next.selection; + this.emit(); + } + + /** Replace the whole document (e.g. after opening a new file). Clears history. */ + replaceDocument(doc: Docx): void { + this.docState = doc; + this.selectionState = null; + this.undoStack.length = 0; + this.redoStack.length = 0; + this.emit(); + } + + subscribe(listener: ChangeListener): () => void { + this.listeners.add(listener); + return () => this.listeners.delete(listener); + } + + private emit(): void { + for (const listener of this.listeners) listener(this); + } +} diff --git a/packages/editor/src/raw-tree.ts b/packages/editor/src/raw-tree.ts new file mode 100644 index 0000000..f491174 --- /dev/null +++ b/packages/editor/src/raw-tree.ts @@ -0,0 +1,100 @@ +/** + * Raw XML node access for the universal editor. + * + * DrawingML, OMML (math), VML and any other markup the semantic AST doesn't + * model is preserved as raw `XmlElement` subtrees inside `document.xml` (in run + * pieces, raw inlines, and raw blocks). This module collects those subtrees and + * all their descendants so the raw-XML inspector can present — and the raw + * commands can edit — every element, then flush via the document AST on save. + */ + +import { + childElementsOf, + type Docx, + getRawPartRoot, + type XmlElement, + xmlPartNames, +} from "@office-kit/docx"; + +/** A node in the raw-XML inspector tree. */ +export interface RawNode { + readonly element: XmlElement; + /** Local element name (e.g. `blip`, `oMath`, `shape`). */ + readonly local: string; + /** Namespace prefix as authored (e.g. `a`, `m`, `v`, `w`). */ + readonly prefix: string; + readonly children: RawNode[]; +} + +function toRawNode(element: XmlElement): RawNode { + return { + element, + local: element.name.local, + prefix: element.name.prefix ?? "", + children: childElementsOf(element).map(toRawNode), + }; +} + +/** Every XML part in the package the part-level raw editor can open. */ +export function xmlParts(doc: Docx): string[] { + return xmlPartNames(doc); +} + +/** + * The raw-XML tree for a single part (fontTable / settings / styles / … ), for + * the part inspector. Edits go through the `rawpart.*` commands, which mark the + * part dirty so it is re-serialized on save. + */ +export function partRawTree(doc: Docx, partName: string): RawNode | undefined { + const root = getRawPartRoot(doc, partName); + return root ? toRawNode(root) : undefined; +} + +/** Every top-level raw XML subtree in the document body, as inspector trees. */ +export function rawTrees(doc: Docx): RawNode[] { + const roots: XmlElement[] = []; + const visitParagraph = (children: { kind: string }[]): void => { + for (const child of children as Array< + | { kind: "run"; pieces: Array<{ kind: string; node?: XmlElement }> } + | { kind: "raw"; node: XmlElement } + | { kind: string } + >) { + if (child.kind === "run" && "pieces" in child) { + for (const piece of child.pieces) { + if ( + (piece.kind === "drawing" || piece.kind === "pict" || piece.kind === "raw") && + piece.node + ) { + roots.push(piece.node); + } + } + } else if (child.kind === "raw" && "node" in child) { + roots.push(child.node); + } + } + }; + for (const block of doc.document.body.blocks) { + if (block.kind === "paragraph") visitParagraph(block.children); + else if (block.kind === "table") { + for (const row of block.rows) { + for (const cell of row.cells) { + for (const p of cell.paragraphs) visitParagraph(p.children); + } + } + } else if (block.kind === "raw") { + roots.push(block.node); + } + } + return roots.map(toRawNode); +} + +/** Flatten the raw trees to every element (for search / coverage reach). */ +export function allRawElements(doc: Docx): XmlElement[] { + const out: XmlElement[] = []; + const walk = (n: RawNode): void => { + out.push(n.element); + for (const c of n.children) walk(c); + }; + for (const t of rawTrees(doc)) walk(t); + return out; +} diff --git a/packages/editor/src/raw.test.ts b/packages/editor/src/raw.test.ts new file mode 100644 index 0000000..f13bd17 --- /dev/null +++ b/packages/editor/src/raw.test.ts @@ -0,0 +1,116 @@ +/** + * Tests for the universal raw-XML editor. These back the ledger's decision to + * classify DrawingML / OMML / VML as `edit`: they prove the raw commands + * genuinely mutate a raw XML subtree inside `document.xml` and that the change + * survives serialize → reopen (flushed through the document AST). + */ + +import { + addImage, + createDocx, + ensureHeadingStyles, + getElementAttr, + getRawPartRoot, + openDocx, + toUint8Array, + validate, +} from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { allRawElements, editorFor, partRawTree, rawTrees, xmlParts } from "./index.js"; +import { runCommand } from "./commands/types.js"; +import { + setAttributeCommand, + setChildValCommand, + setPartAttributeCommand, + setPartChildValCommand, +} from "./commands/raw.js"; + +const PNG_1x1 = new Uint8Array([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 0x0d, 0x49, 0x48, 0x44, 0x52, 0, 0, 0, 1, + 0, 0, 0, 1, 8, 6, 0, 0, 0, 0x1f, 0x15, 0xc4, 0x89, 0, 0, 0, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, + 0x9c, 0x63, 0, 1, 0, 0, 5, 0, 1, 0x0d, 0x0a, 0x2d, 0xb4, 0, 0, 0, 0, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82, +]); + +describe("raw-XML inspector", () => { + it("collects the DrawingML subtree of an inline image", () => { + const model = editorFor(createDocx({ paragraphs: [] })); + addImage(model.doc, PNG_1x1, { widthEmu: 914400, heightEmu: 914400 }); + const trees = rawTrees(model.doc); + expect(trees.length).toBe(1); + expect(trees[0]!.local).toBe("drawing"); + const locals = allRawElements(model.doc).map((e) => e.name.local); + // Reaches deep DrawingML elements (blip, ext, prstGeom, …). + expect(locals).toContain("blip"); + expect(locals).toContain("prstGeom"); + }); +}); + +describe("raw editing commands", () => { + it("sets an attribute on a DrawingML element and round-trips", () => { + const model = editorFor(createDocx({ paragraphs: [] })); + addImage(model.doc, PNG_1x1, { widthEmu: 914400, heightEmu: 914400 }); + const prstGeom = allRawElements(model.doc).find((e) => e.name.local === "prstGeom")!; + runCommand(model, setAttributeCommand, { target: prstGeom, local: "prst", value: "ellipse" }); + + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + const reGeom = allRawElements(re).find((e) => e.name.local === "prstGeom")!; + expect(getElementAttr(reGeom, "prst")).toBe("ellipse"); + }); + + it("adds a child element on a DrawingML element and round-trips", () => { + const model = editorFor(createDocx({ paragraphs: [] })); + addImage(model.doc, PNG_1x1, { widthEmu: 914400, heightEmu: 914400 }); + const spPr = allRawElements(model.doc).find((e) => e.name.local === "spPr")!; + // Add a rotation/attr-bearing child value; here a simple -sibling flag. + runCommand(model, setChildValCommand, { target: spPr, local: "rot", val: "5400000" }); + + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + const reSpPr = allRawElements(re).find((e) => e.name.local === "spPr")!; + expect(reSpPr.children.some((c) => c.kind === "element" && c.name.local === "rot")).toBe(true); + }); +}); + +describe("part-level raw editor", () => { + it("lists the XML parts in the package", () => { + const model = editorFor(createDocx({ paragraphs: ["hi"] })); + ensureHeadingStyles(model.doc); + const parts = xmlParts(model.doc); + expect(parts).toContain("/word/document.xml"); + expect(parts).toContain("/word/styles.xml"); + }); + + it("edits an element in styles.xml (a non-document part) and round-trips", () => { + const model = editorFor(createDocx({ paragraphs: ["hi"] })); + ensureHeadingStyles(model.doc); + const tree = partRawTree(model.doc, "/word/styles.xml")!; + expect(tree.local).toBe("styles"); + const style = tree.children.find((n) => n.local === "style")!; + + // Set an attribute and add a child on a via the part commands. + runCommand(model, setPartAttributeCommand, { + partName: "/word/styles.xml", + target: style.element, + local: "customMarker", + value: "abc", + }); + runCommand(model, setPartChildValCommand, { + partName: "/word/styles.xml", + target: style.element, + local: "uiPriority", + val: "42", + }); + + const re = openDocx(toUint8Array(model.doc)); + expect(validate(re).length).toBe(0); + const reRoot = getRawPartRoot(re, "/word/styles.xml")!; + const reStyle = reRoot.children.find((c) => c.kind === "element" && c.name.local === "style"); + if (!reStyle || reStyle.kind !== "element") throw new Error("style not found"); + expect(getElementAttr(reStyle, "customMarker")).toBe("abc"); + expect( + reStyle.children.some((c) => c.kind === "element" && c.name.local === "uiPriority"), + ).toBe(true); + }); +}); diff --git a/packages/editor/src/render.ts b/packages/editor/src/render.ts new file mode 100644 index 0000000..7ff7898 --- /dev/null +++ b/packages/editor/src/render.ts @@ -0,0 +1,186 @@ +/** + * AST → HTML renderer for the editing canvas. + * + * This is a *semantic* renderer: it maps the WordprocessingML AST to editable + * HTML annotated with `data-wk-*` anchors so DOM selection can be mapped back to + * document positions. It is not a page-faithful layout engine (that is + * `@office-kit/docx-preview`'s job); it renders a continuous flow with enough + * fidelity — bold/italic/underline/color/size/alignment, tables, list markers — + * to edit against. Elements it does not model render as inert placeholders so + * the document round-trips losslessly through the library even while shown here. + */ + +import { + getParagraphAlignment, + getParagraphStyle, + getRunFormat, + paragraphText, + type RunFormatting, + type WmlBlock, + type WmlParagraph, + type WmlRun, + type WmlTable, +} from "@office-kit/docx"; + +/** + * Visual formatting for the built-in paragraph styles so headings read as + * headings on the canvas (Word/Google-Docs-like hierarchy). This is display + * only — the underlying `pStyle` is what round-trips; here we just make the + * document look like a document instead of a flat wall of text. + */ +const STYLE_LOOK: Record = { + Title: "font-size:26pt;font-weight:700;margin:0 0 8px;line-height:1.15", + Subtitle: "font-size:15pt;color:#666;margin:0 0 12px", + Heading1: "font-size:20pt;font-weight:600;color:#1a1a1a;margin:18px 0 6px;line-height:1.2", + Heading2: "font-size:16pt;font-weight:600;color:#1a1a1a;margin:14px 0 4px;line-height:1.2", + Heading3: "font-size:13pt;font-weight:600;color:#333;margin:12px 0 4px", + Heading4: "font-size:12pt;font-weight:600;font-style:italic;color:#333;margin:10px 0 4px", + Heading5: "font-size:11pt;font-weight:600;color:#444;margin:10px 0 4px", + Heading6: "font-size:11pt;font-weight:600;font-style:italic;color:#555;margin:10px 0 4px", + Quote: "font-style:italic;color:#555;border-left:3px solid #ccc;padding-left:12px;margin:8px 0", +}; + +const ALIGN_TO_CSS: Record = { + left: "left", + center: "center", + right: "right", + both: "justify", + distribute: "justify", +}; + +function escapeHtml(s: string): string { + return s + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +/** Inline CSS for a run's direct formatting. */ +function runStyle(fmt: RunFormatting): string { + const parts: string[] = []; + if (fmt.bold) parts.push("font-weight:bold"); + if (fmt.italic) parts.push("font-style:italic"); + const decoration: string[] = []; + if (fmt.underline && fmt.underline !== "none") decoration.push("underline"); + if (fmt.strike) decoration.push("line-through"); + if (decoration.length) parts.push(`text-decoration:${decoration.join(" ")}`); + if (fmt.color) parts.push(`color:#${fmt.color}`); + if (fmt.highlight) parts.push(`background-color:${highlightToCss(fmt.highlight)}`); + if (fmt.fontSizeHalfPoints) parts.push(`font-size:${fmt.fontSizeHalfPoints / 2}pt`); + if (fmt.font) parts.push(`font-family:'${fmt.font.replace(/'/g, "")}'`); + return parts.join(";"); +} + +function highlightToCss(v: string): string { + // Named Word highlight colors vs. a raw hex value. + const named: Record = { + yellow: "#ffff00", + green: "#00ff00", + cyan: "#00ffff", + magenta: "#ff00ff", + red: "#ff0000", + blue: "#0000ff", + lightGray: "#d3d3d3", + darkGray: "#a9a9a9", + }; + return named[v] ?? (/^[0-9a-fA-F]{6}$/.test(v) ? `#${v}` : v); +} + +/** Concatenate a run's textual pieces (text/tab/break become visible chars). */ +function runText(run: WmlRun): string { + let out = ""; + for (const piece of run.pieces) { + switch (piece.kind) { + case "text": + out += piece.value; + break; + case "tab": + out += "\t"; + break; + case "break": + out += "\n"; + break; + case "noBreakHyphen": + case "softHyphen": + out += "‑"; + break; + default: + break; + } + } + return out; +} + +function renderRun(run: WmlRun, block: number, inline: number, cell?: string): string { + const fmt = getRunFormat(run); + const style = runStyle(fmt); + const text = runText(run); + const attrs = [ + `data-wk-block="${block}"`, + cell ? `data-wk-cell="${cell}"` : "", + `data-wk-inline="${inline}"`, + style ? `style="${style}"` : "", + ] + .filter(Boolean) + .join(" "); + // Preserve whitespace/tabs; use a zero-width space for empty runs so the + // caret has something to land on. + return `${escapeHtml(text) || "​"}`; +} + +function renderParagraph(para: WmlParagraph, block: number, cell?: string): string { + const align = getParagraphAlignment(para); + const alignCss = align ? ALIGN_TO_CSS[align] : undefined; + const look = STYLE_LOOK[getParagraphStyle(para) ?? ""]; + const css = [look, alignCss ? `text-align:${alignCss}` : ""].filter(Boolean).join(";"); + const styleAttr = css ? ` style="${css}"` : ""; + const runs = para.children.filter((c): c is WmlRun => c.kind === "run"); + let inner: string; + if (runs.length === 0) { + inner = "​"; + } else { + inner = runs.map((r, j) => renderRun(r, block, j, cell)).join(""); + } + const cellAttr = cell ? ` data-wk-cell="${cell}"` : ""; + return `

${inner}

`; +} + +function renderTable(table: WmlTable, block: number): string { + const rows = table.rows + .map((row, r) => { + const cells = row.cells + .map((cell, c) => { + const coord = `${r},${c}`; + const body = cell.paragraphs.map((p) => renderParagraph(p, block, coord)).join(""); + return `${body}`; + }) + .join(""); + return `${cells}`; + }) + .join(""); + return `${rows}
`; +} + +function renderBlock(blockNode: WmlBlock, block: number): string { + switch (blockNode.kind) { + case "paragraph": + return renderParagraph(blockNode, block); + case "table": + return renderTable(blockNode, block); + default: + // Raw / unmodelled block: show a non-editable marker; the library still + // round-trips the underlying XML. + return `
⟨preserved content⟩
`; + } +} + +/** Render the whole document body to an HTML string for the canvas. */ +export function renderDocumentHtml(doc: { document: { body: { blocks: WmlBlock[] } } }): string { + return doc.document.body.blocks.map((b, i) => renderBlock(b, i)).join(""); +} + +/** Plain-text extraction of a paragraph (used for tests / accessibility). */ +export function paragraphPlainText(para: WmlParagraph): string { + return paragraphText(para); +} diff --git a/packages/editor/src/selection-runs.ts b/packages/editor/src/selection-runs.ts new file mode 100644 index 0000000..885bd45 --- /dev/null +++ b/packages/editor/src/selection-runs.ts @@ -0,0 +1,187 @@ +/** + * Selection-aware run access for character formatting. + * + * The naïve approach — format every run the selection *touches* — bolds the + * whole line when you select a few characters, because runs are the atomic unit + * of formatting. Instead, {@link applyToSelectionRuns} isolates exactly the + * selected characters into their own runs (splitting at the boundaries) before + * applying the change, and updates the selection so the same text stays + * highlighted. {@link overlappingSelectionRuns} is the read-only counterpart for + * `isActive` / `isEnabled` state (it never mutates the document). + */ + +import { + isolateParagraphRunRange, + runTextLength, + type WmlParagraph, + type WmlRun, +} from "@office-kit/docx"; +import { paragraphAt } from "./doc-access.js"; +import type { EditorModel } from "./model.js"; +import { type CellCoord, type DocPosition, orderSelection } from "./selection.js"; + +function paragraphRuns(para: WmlParagraph): WmlRun[] { + return para.children.filter((c): c is WmlRun => c.kind === "run"); +} + +/** Absolute character offset of a position within its paragraph's run text. */ +function absoluteChar(runs: WmlRun[], inline: number, offset: number): number { + let n = 0; + for (let i = 0; i < inline && i < runs.length; i++) n += runTextLength(runs[i]!); + return n + offset; +} + +interface ParaWindow { + para: WmlParagraph; + startChar: number; + endChar: number; + block: number; + cell?: CellCoord; +} + +/** Whether two positions denote the same collapsed caret. */ +function isCollapsed(a: DocPosition, b: DocPosition): boolean { + return ( + a.block === b.block && + (a.inline ?? 0) === (b.inline ?? 0) && + (a.offset ?? 0) === (b.offset ?? 0) && + a.cell?.row === b.cell?.row && + a.cell?.col === b.cell?.col + ); +} + +/** The paragraph windows the selection covers, with per-paragraph char ranges. */ +function selectionWindows(model: EditorModel): ParaWindow[] { + const sel = model.selection; + if (!sel) return []; + const { start, end } = orderSelection(sel); + + // Single paragraph (including inside a table cell): a precise char window. + if ( + start.block === end.block && + start.cell?.row === end.cell?.row && + start.cell?.col === end.cell?.col + ) { + const para = paragraphAt(model.doc, start); + if (!para) return []; + const runs = paragraphRuns(para); + return [ + { + para, + startChar: absoluteChar(runs, start.inline ?? 0, start.offset ?? 0), + endChar: absoluteChar(runs, end.inline ?? 0, end.offset ?? 0), + block: start.block, + ...(start.cell ? { cell: start.cell } : {}), + }, + ]; + } + + // Multi-block selection over top-level paragraphs. Tables fall back to whole + // cell paragraphs (a rare selection shape not worth per-char precision here). + const out: ParaWindow[] = []; + const blocks = model.doc.document.body.blocks; + for (let b = start.block; b <= end.block && b < blocks.length; b++) { + const node = blocks[b]; + if (node?.kind === "paragraph") { + const runs = paragraphRuns(node); + const full = runs.reduce((n, r) => n + runTextLength(r), 0); + out.push({ + para: node, + startChar: b === start.block ? absoluteChar(runs, start.inline ?? 0, start.offset ?? 0) : 0, + endChar: b === end.block ? absoluteChar(runs, end.inline ?? 0, end.offset ?? 0) : full, + block: b, + }); + } else if (node?.kind === "table") { + for (const row of node.rows) { + for (const cell of row.cells) { + for (const p of cell.paragraphs) { + const full = paragraphRuns(p).reduce((n, r) => n + runTextLength(r), 0); + out.push({ para: p, startChar: 0, endChar: full, block: b }); + } + } + } + } + } + return out; +} + +/** Runs overlapping the selection — read-only, for active/enabled state. */ +export function overlappingSelectionRuns(model: EditorModel): WmlRun[] { + const sel = model.selection; + if (!sel) return []; + const { start, end } = orderSelection(sel); + const wins = selectionWindows(model); + + // Collapsed caret: the run at the caret (so toggles still report state). + if (isCollapsed(start, end)) { + const para = paragraphAt(model.doc, start); + if (!para) return []; + const runs = paragraphRuns(para); + const at = runs[start.inline ?? 0]; + return at ? [at] : runs.slice(0, 1); + } + + const out: WmlRun[] = []; + for (const w of wins) { + let cursor = 0; + for (const run of paragraphRuns(w.para)) { + const s = cursor; + const e = cursor + runTextLength(run); + cursor = e; + if (e > s && s < w.endChar && e > w.startChar) out.push(run); + } + } + return out; +} + +/** + * Apply `applyFn` to exactly the runs covering the selection, splitting runs at + * the selection boundaries first so a partial selection formats only the + * selected characters. Keeps the same text selected afterwards. + */ +export function applyToSelectionRuns(model: EditorModel, applyFn: (run: WmlRun) => void): void { + const sel = model.selection; + if (!sel) return; + const { start, end } = orderSelection(sel); + + // Collapsed caret: apply to the whole caret run (there is no range to isolate). + if (isCollapsed(start, end)) { + for (const run of overlappingSelectionRuns(model)) applyFn(run); + return; + } + + const wins = selectionWindows(model); + for (const w of wins) { + for (const run of isolateParagraphRunRange(w.para, w.startChar, w.endChar)) applyFn(run); + } + + // Re-anchor the selection to the isolated run boundaries (single paragraph). + if (wins.length === 1) { + const w = wins[0]!; + const runs = paragraphRuns(w.para); + let cursor = 0; + let startInline = -1; + let endInline = -1; + runs.forEach((run, idx) => { + const s = cursor; + const e = cursor + runTextLength(run); + cursor = e; + if (e > s && s >= w.startChar && e <= w.endChar) { + if (startInline < 0) startInline = idx; + endInline = idx; + } + }); + if (startInline >= 0 && endInline >= 0) { + const cell = w.cell ? { cell: w.cell } : {}; + model.setSelection({ + anchor: { block: w.block, ...cell, inline: startInline, offset: 0 }, + focus: { + block: w.block, + ...cell, + inline: endInline, + offset: runTextLength(runs[endInline]!), + }, + }); + } + } +} diff --git a/packages/editor/src/selection.ts b/packages/editor/src/selection.ts new file mode 100644 index 0000000..99fd333 --- /dev/null +++ b/packages/editor/src/selection.ts @@ -0,0 +1,72 @@ +/** + * Document selection model. + * + * A position addresses a place in the document by block index (into + * {@link WmlBody.blocks}), and optionally the inline (run) index within a + * paragraph and a character offset within that run's text. Table cells are + * addressed through {@link DocPosition.cell} when the block is a table. + * + * The editor keeps selection here — decoupled from the DOM — so commands can + * reason about "what is selected" without touching rendered nodes. The + * DOM↔selection mapping lives in {@link ./dom-selection.ts}. + */ + +/** Coordinates of a table cell inside a table block. */ +export interface CellCoord { + readonly row: number; + readonly col: number; +} + +/** A single caret position in the document. */ +export interface DocPosition { + /** Index into `body.blocks`. */ + readonly block: number; + /** When the block is a table: which cell. */ + readonly cell?: CellCoord; + /** When inside a paragraph (top-level or in a cell): paragraph index in the cell. */ + readonly para?: number; + /** Inline (run) index within the target paragraph. */ + readonly inline?: number; + /** Character offset within the target run's text. */ + readonly offset?: number; +} + +/** A selection range from anchor (where it started) to focus (the moving end). */ +export interface Selection { + readonly anchor: DocPosition; + readonly focus: DocPosition; +} + +/** A selection reduced to document order: start comes at or before end. */ +export interface OrderedSelection { + readonly start: DocPosition; + readonly end: DocPosition; + /** True when start and end are the same position (a caret, not a range). */ + readonly collapsed: boolean; +} + +function comparePositions(a: DocPosition, b: DocPosition): number { + if (a.block !== b.block) return a.block - b.block; + const ar = a.cell?.row ?? -1; + const br = b.cell?.row ?? -1; + if (ar !== br) return ar - br; + const ac = a.cell?.col ?? -1; + const bc = b.cell?.col ?? -1; + if (ac !== bc) return ac - bc; + if ((a.para ?? 0) !== (b.para ?? 0)) return (a.para ?? 0) - (b.para ?? 0); + if ((a.inline ?? 0) !== (b.inline ?? 0)) return (a.inline ?? 0) - (b.inline ?? 0); + return (a.offset ?? 0) - (b.offset ?? 0); +} + +/** Order a selection so start ≤ end, and report whether it is collapsed. */ +export function orderSelection(sel: Selection): OrderedSelection { + const cmp = comparePositions(sel.anchor, sel.focus); + const start = cmp <= 0 ? sel.anchor : sel.focus; + const end = cmp <= 0 ? sel.focus : sel.anchor; + return { start, end, collapsed: cmp === 0 }; +} + +/** Build a collapsed selection (a caret) at a single position. */ +export function caretAt(pos: DocPosition): Selection { + return { anchor: pos, focus: pos }; +} diff --git a/packages/editor/src/text-edit.test.ts b/packages/editor/src/text-edit.test.ts new file mode 100644 index 0000000..4b12d29 --- /dev/null +++ b/packages/editor/src/text-edit.test.ts @@ -0,0 +1,50 @@ +/** + * Unit tests for the text-sync helpers that back canvas typing. + */ + +import { createDocx, type WmlRun } from "@office-kit/docx"; +import { describe, expect, it } from "vitest"; +import { editorFor } from "./index.js"; +import { runAtPath, setSimpleRunText } from "./text-edit.js"; + +describe("runAtPath", () => { + it("resolves the run at a block/inline position", () => { + const model = editorFor(createDocx({ paragraphs: ["Alpha", "Beta"] })); + const run = runAtPath(model.doc, { block: 1, inline: 0 }); + expect(run?.kind).toBe("run"); + const text = run?.pieces.map((p) => (p.kind === "text" ? p.value : "")).join(""); + expect(text).toBe("Beta"); + }); + + it("returns undefined for out-of-range positions", () => { + const model = editorFor(createDocx({ paragraphs: ["only"] })); + expect(runAtPath(model.doc, { block: 5, inline: 0 })).toBeUndefined(); + }); +}); + +describe("setSimpleRunText", () => { + it("replaces a text-only run's content", () => { + const model = editorFor(createDocx({ paragraphs: ["old"] })); + const run = runAtPath(model.doc, { block: 0, inline: 0 })!; + expect(setSimpleRunText(run, "new text")).toBe(true); + expect(run.pieces).toEqual([{ kind: "text", value: "new text", preserveSpace: false }]); + }); + + it("preserves leading/trailing space with xml:space", () => { + const model = editorFor(createDocx({ paragraphs: ["x"] })); + const run = runAtPath(model.doc, { block: 0, inline: 0 })!; + setSimpleRunText(run, " padded "); + expect(run.pieces[0]).toMatchObject({ kind: "text", preserveSpace: true }); + }); + + it("refuses to overwrite runs carrying non-text pieces", () => { + const run: WmlRun = { + kind: "run", + pieces: [{ kind: "tab" }, { kind: "text", value: "a", preserveSpace: false }], + extras: [], + }; + expect(setSimpleRunText(run, "b")).toBe(false); + // Original pieces untouched. + expect(run.pieces.length).toBe(2); + }); +}); diff --git a/packages/editor/src/text-edit.ts b/packages/editor/src/text-edit.ts new file mode 100644 index 0000000..0d26d33 --- /dev/null +++ b/packages/editor/src/text-edit.ts @@ -0,0 +1,30 @@ +/** + * Low-level text-sync helpers used by the canvas to push typed text back into + * the AST. The canvas renders each run as an editable span; on input it reads + * the span's text and writes it to the matching run here. + */ + +import type { Docx, WmlRun } from "@office-kit/docx"; +import { paragraphAt } from "./doc-access.js"; +import type { DocPosition } from "./selection.js"; + +/** Resolve the run addressed by a position's `inline` index. */ +export function runAtPath(doc: Docx, pos: DocPosition): WmlRun | undefined { + const para = paragraphAt(doc, pos); + if (!para) return undefined; + const runs = para.children.filter((c): c is WmlRun => c.kind === "run"); + return runs[pos.inline ?? 0]; +} + +/** + * Replace a run's text when it is a simple text-only run. Returns false (and + * changes nothing) for runs carrying tabs, breaks, drawings, fields, etc. — the + * canvas leaves those to command-level edits so nothing is silently dropped. + */ +export function setSimpleRunText(run: WmlRun, text: string): boolean { + const nonText = run.pieces.some((p) => p.kind !== "text"); + if (nonText && run.pieces.length > 0) return false; + const preserveSpace = /^\s|\s$|\s\s/.test(text); + run.pieces = [{ kind: "text", value: text, preserveSpace }]; + return true; +} diff --git a/packages/editor/tsconfig.json b/packages/editor/tsconfig.json new file mode 100644 index 0000000..5fe0e17 --- /dev/null +++ b/packages/editor/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "noEmit": true, + "composite": false + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.test.ts", "dist"] +} diff --git a/packages/editor/tsdown.config.ts b/packages/editor/tsdown.config.ts new file mode 100644 index 0000000..ff011f0 --- /dev/null +++ b/packages/editor/tsdown.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm"], + dts: true, + sourcemap: true, + clean: true, + target: "es2022", + treeshake: true, + // Keep the core library a runtime dependency rather than inlining it, so the + // editor and the app share one copy of `@office-kit/docx`. + deps: { neverBundle: ["@office-kit/docx"] }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1589a87..2495999 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,6 +43,12 @@ importers: specifier: ^2.1.0 version: 2.1.9(@types/node@22.19.19)(happy-dom@20.9.0)(jsdom@29.1.1)(lightningcss@1.32.0) + packages/editor: + dependencies: + '@office-kit/docx': + specifier: workspace:* + version: link:../.. + packages/preview: dependencies: '@office-kit/docx': @@ -60,6 +66,9 @@ importers: '@office-kit/docx': specifier: workspace:* version: link:.. + '@office-kit/docx-editor': + specifier: workspace:* + version: link:../packages/editor '@office-kit/docx-preview': specifier: workspace:* version: link:../packages/preview diff --git a/scripts/extract-ooxml-elements.mjs b/scripts/extract-ooxml-elements.mjs new file mode 100644 index 0000000..83da8cc --- /dev/null +++ b/scripts/extract-ooxml-elements.mjs @@ -0,0 +1,125 @@ +// Extract the element universe from the ECMA-376 XSD schemas so the editor's +// capability ledger can be checked for completeness against it. +// +// Source of truth: references/python-docx/ref/xsd/*.xsd (git submodule, never +// published). We snapshot the extracted list into a committed JSON file so the +// coverage test runs even when the submodule is not checked out (CI). +// +// Scope: docx (WordprocessingML). We take every element declared in wml.xsd, +// plus the wordprocessing-relevant DrawingML / VML / math elements a .docx can +// actually contain. Each element is tagged with the namespace prefix and the +// nearest enclosing named complexType (for grouping in the ledger). +// +// Run: node scripts/extract-ooxml-elements.mjs + +import { readFileSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const repoRoot = join(here, ".."); +const xsdDir = join(repoRoot, "references/python-docx/ref/xsd"); +const outFile = join(repoRoot, "packages/editor/src/capability/element-universe.json"); + +// Which schema file maps to which namespace prefix + feature domain. Only the +// parts a WordprocessingML document can embed are included. +const SCHEMAS = [ + { file: "wml.xsd", prefix: "w", domain: "wml" }, + { file: "dml-wordprocessingDrawing.xsd", prefix: "wp", domain: "drawing" }, + { file: "dml-picture.xsd", prefix: "pic", domain: "drawing" }, + { file: "dml-main.xsd", prefix: "a", domain: "drawing" }, + { file: "shared-math.xsd", prefix: "m", domain: "math" }, + { file: "vml-main.xsd", prefix: "v", domain: "vml" }, + { file: "vml-officeDrawing.xsd", prefix: "o", domain: "vml" }, + { file: "vml-wordprocessingDrawing.xsd", prefix: "wvml", domain: "vml" }, + { file: "shared-documentPropertiesCore.xsd", prefix: "cp", domain: "docprops" }, + { file: "shared-documentPropertiesExtended.xsd", prefix: "ep", domain: "docprops" }, + { file: "shared-documentPropertiesCustom.xsd", prefix: "custprops", domain: "docprops" }, +]; + +const ELEMENT_RE = //; + +/** + * Walk a schema line by line, tracking the current named complexType so each + * element can be attributed to the type that declares it. Elements declared at + * the top level (outside any complexType) get definedIn = null. + */ +function extractFromSchema(text, prefix, domain) { + const lines = text.split("\n"); + const typeStack = []; + const found = new Map(); // key = `${prefix}:${name}` -> record + + for (const line of lines) { + const open = line.match(COMPLEXTYPE_OPEN_RE); + if (open) typeStack.push(open[1]); + + let m; + ELEMENT_RE.lastIndex = 0; + while ((m = ELEMENT_RE.exec(line)) !== null) { + const name = m[1]; + const type = m[2] ?? null; + const key = `${prefix}:${name}`; + const definedIn = typeStack.length > 0 ? typeStack[typeStack.length - 1] : null; + const existing = found.get(key); + if (existing) { + if (definedIn && !existing.definedIn.includes(definedIn)) { + existing.definedIn.push(definedIn); + } + if (type && !existing.types.includes(type)) existing.types.push(type); + } else { + found.set(key, { + element: key, + name, + prefix, + domain, + definedIn: definedIn ? [definedIn] : [], + types: type ? [type] : [], + }); + } + } + + if (COMPLEXTYPE_CLOSE_RE.test(line)) typeStack.pop(); + } + return [...found.values()]; +} + +const all = new Map(); +let missingFiles = 0; +for (const { file, prefix, domain } of SCHEMAS) { + const path = join(xsdDir, file); + let text; + try { + text = readFileSync(path, "utf8"); + } catch { + // shared-documentPropertiesCore.xsd is named differently in some mirrors; + // skip missing optional schemas rather than fail the whole extraction. + missingFiles++; + console.warn(`[extract] skip missing schema: ${file}`); + continue; + } + for (const rec of extractFromSchema(text, prefix, domain)) { + // wml re-declares a handful of names; keep the first (wml wins for w:). + if (!all.has(rec.element)) all.set(rec.element, rec); + } +} + +const elements = [...all.values()].toSorted((a, b) => a.element.localeCompare(b.element)); +const byDomain = {}; +for (const e of elements) byDomain[e.domain] = (byDomain[e.domain] ?? 0) + 1; + +const snapshot = { + // Regenerate with: node scripts/extract-ooxml-elements.mjs + generatedFrom: "ECMA-376 XSD (references/python-docx/ref/xsd)", + schemaFiles: SCHEMAS.map((s) => s.file), + totalElements: elements.length, + byDomain, + elements, +}; + +writeFileSync(outFile, JSON.stringify(snapshot, null, 2) + "\n"); +console.log( + `[extract] ${elements.length} elements from ${SCHEMAS.length - missingFiles} schemas -> ${outFile}`, +); +console.log("[extract] by domain:", byDomain); diff --git a/site/package.json b/site/package.json index 122198f..b0d4488 100644 --- a/site/package.json +++ b/site/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@office-kit/docx": "workspace:*", + "@office-kit/docx-editor": "workspace:*", "@office-kit/docx-preview": "workspace:*" }, "devDependencies": { diff --git a/site/src/lib/components/SiteHeader.svelte b/site/src/lib/components/SiteHeader.svelte index 39cd333..2aeae69 100644 --- a/site/src/lib/components/SiteHeader.svelte +++ b/site/src/lib/components/SiteHeader.svelte @@ -7,6 +7,7 @@ { path: '/docs/getting-started', label: 'Docs' }, { path: '/docs/recipes', label: 'Recipes' }, { path: '/playground', label: 'Playground' }, + { path: '/editor', label: 'Editor' }, { path: '/api', label: 'API' }, { path: 'https://github.com/office-kit/docx', label: 'GitHub', external: true }, ]; diff --git a/site/src/lib/editor/EditorCanvas.svelte b/site/src/lib/editor/EditorCanvas.svelte new file mode 100644 index 0000000..bc619cd --- /dev/null +++ b/site/src/lib/editor/EditorCanvas.svelte @@ -0,0 +1,353 @@ + + +
+
+
+ + diff --git a/site/src/lib/editor/RawXmlInspector.svelte b/site/src/lib/editor/RawXmlInspector.svelte new file mode 100644 index 0000000..63fd9c3 --- /dev/null +++ b/site/src/lib/editor/RawXmlInspector.svelte @@ -0,0 +1,157 @@ + + +
+ +
+ +{#snippet nodeRow(node: RawNode, depth: number)} +
+
+ {node.prefix ? `${node.prefix}:` : ''}{node.local} + {#each node.element.attrs as attr (attr.name.local)} + + {/each} + +
+ {#each node.children as child (child)} + {@render nodeRow(child, depth + 1)} + {/each} +
+{/snippet} + +
+ {#if trees.length === 0} +

+ {#if source === ''} + No inline raw XML yet. Insert an image (or open a document with drawings, + equations, or shapes) to edit DrawingML / OMML / VML here — or pick an XML + part above (fontTable, settings, styles, numbering, …) to edit it directly. + {:else} + This part has no elements. + {/if} +

+ {:else} + {#each trees as tree (tree)} + {@render nodeRow(tree, 0)} + {/each} + {/if} +
+ + diff --git a/site/src/lib/editor/i18n.svelte.ts b/site/src/lib/editor/i18n.svelte.ts new file mode 100644 index 0000000..b03410d --- /dev/null +++ b/site/src/lib/editor/i18n.svelte.ts @@ -0,0 +1,413 @@ +/** + * Lightweight i18n for the editor UI. A single reactive `current` locale drives + * `t(key)`; because `t` reads the `$state`, any markup calling it re-renders when + * the locale changes. Falls back to English for missing keys. + */ + +export const LOCALES = { + en: "English", + ja: "日本語", + es: "Español", + fr: "Français", + de: "Deutsch", + zh: "中文", +} as const; + +export type LocaleId = keyof typeof LOCALES; + +export type MessageKey = + | "tab.home" + | "tab.insert" + | "tab.layout" + | "tab.references" + | "tab.review" + | "action.new" + | "action.open" + | "action.find" + | "action.xml" + | "action.download" + | "action.undo" + | "action.redo" + | "find.find" + | "find.replaceWith" + | "find.replaceAll" + | "find.close" + | "group.font" + | "group.text" + | "group.paragraph" + | "group.styles" + | "group.insert" + | "group.headings" + | "group.pageSetup" + | "group.sections" + | "group.references" + | "group.tracking" + | "ins.paragraph" + | "ins.table" + | "ins.pageBreak" + | "ins.link" + | "ins.picture" + | "layout.sectionBreak" + | "layout.pageNumbers" + | "ref.toc" + | "ref.footnote" + | "ref.endnote" + | "ref.bookmark" + | "review.newComment" + | "review.acceptAll" + | "review.rejectAll" + | "style.normal" + | "style.heading1" + | "style.heading2" + | "style.heading3" + | "status.ready" + | "status.editing" + | "status.words" + | "status.chars" + | "xml.title" + | "xml.documentSource" + | "language"; + +type Dict = Record; + +const en: Dict = { + "tab.home": "Home", + "tab.insert": "Insert", + "tab.layout": "Layout", + "tab.references": "References", + "tab.review": "Review", + "action.new": "New", + "action.open": "Open…", + "action.find": "Find", + "action.xml": "XML", + "action.download": "Download .docx", + "action.undo": "Undo", + "action.redo": "Redo", + "find.find": "Find", + "find.replaceWith": "Replace with", + "find.replaceAll": "Replace all", + "find.close": "Close find", + "group.font": "Font", + "group.text": "Text", + "group.paragraph": "Paragraph", + "group.styles": "Styles", + "group.insert": "Insert", + "group.headings": "Headings", + "group.pageSetup": "Page setup", + "group.sections": "Sections", + "group.references": "References", + "group.tracking": "Tracking", + "ins.paragraph": "Paragraph", + "ins.table": "Table", + "ins.pageBreak": "Page break", + "ins.link": "Link", + "ins.picture": "Picture", + "layout.sectionBreak": "Section break", + "layout.pageNumbers": "Page numbers", + "ref.toc": "Table of contents", + "ref.footnote": "Footnote", + "ref.endnote": "Endnote", + "ref.bookmark": "Bookmark", + "review.newComment": "New comment", + "review.acceptAll": "Accept all", + "review.rejectAll": "Reject all", + "style.normal": "Normal", + "style.heading1": "Heading 1", + "style.heading2": "Heading 2", + "style.heading3": "Heading 3", + "status.ready": "Ready.", + "status.editing": "Editing…", + "status.words": "words", + "status.chars": "chars", + "xml.title": "Raw XML — DrawingML / OMML / VML", + "xml.documentSource": "Document — inline shapes / math / VML", + language: "Language", +}; + +const ja: Dict = { + "tab.home": "ホーム", + "tab.insert": "挿入", + "tab.layout": "レイアウト", + "tab.references": "参照", + "tab.review": "校閲", + "action.new": "新規", + "action.open": "開く…", + "action.find": "検索", + "action.xml": "XML", + "action.download": ".docx をダウンロード", + "action.undo": "元に戻す", + "action.redo": "やり直し", + "find.find": "検索", + "find.replaceWith": "置換後", + "find.replaceAll": "すべて置換", + "find.close": "検索を閉じる", + "group.font": "フォント", + "group.text": "文字", + "group.paragraph": "段落", + "group.styles": "スタイル", + "group.insert": "挿入", + "group.headings": "見出し", + "group.pageSetup": "ページ設定", + "group.sections": "セクション", + "group.references": "参照", + "group.tracking": "変更履歴", + "ins.paragraph": "段落", + "ins.table": "表", + "ins.pageBreak": "改ページ", + "ins.link": "リンク", + "ins.picture": "画像", + "layout.sectionBreak": "セクション区切り", + "layout.pageNumbers": "ページ番号", + "ref.toc": "目次", + "ref.footnote": "脚注", + "ref.endnote": "文末脚注", + "ref.bookmark": "ブックマーク", + "review.newComment": "新しいコメント", + "review.acceptAll": "すべて承認", + "review.rejectAll": "すべて元に戻す", + "style.normal": "標準", + "style.heading1": "見出し 1", + "style.heading2": "見出し 2", + "style.heading3": "見出し 3", + "status.ready": "準備完了。", + "status.editing": "編集中…", + "status.words": "単語", + "status.chars": "文字", + "xml.title": "生 XML — DrawingML / OMML / VML", + "xml.documentSource": "ドキュメント — インライン図形 / 数式 / VML", + language: "言語", +}; + +const es: Dict = { + "tab.home": "Inicio", + "tab.insert": "Insertar", + "tab.layout": "Diseño", + "tab.references": "Referencias", + "tab.review": "Revisar", + "action.new": "Nuevo", + "action.open": "Abrir…", + "action.find": "Buscar", + "action.xml": "XML", + "action.download": "Descargar .docx", + "action.undo": "Deshacer", + "action.redo": "Rehacer", + "find.find": "Buscar", + "find.replaceWith": "Reemplazar con", + "find.replaceAll": "Reemplazar todo", + "find.close": "Cerrar búsqueda", + "group.font": "Fuente", + "group.text": "Texto", + "group.paragraph": "Párrafo", + "group.styles": "Estilos", + "group.insert": "Insertar", + "group.headings": "Títulos", + "group.pageSetup": "Config. de página", + "group.sections": "Secciones", + "group.references": "Referencias", + "group.tracking": "Control de cambios", + "ins.paragraph": "Párrafo", + "ins.table": "Tabla", + "ins.pageBreak": "Salto de página", + "ins.link": "Enlace", + "ins.picture": "Imagen", + "layout.sectionBreak": "Salto de sección", + "layout.pageNumbers": "Números de página", + "ref.toc": "Tabla de contenido", + "ref.footnote": "Nota al pie", + "ref.endnote": "Nota al final", + "ref.bookmark": "Marcador", + "review.newComment": "Nuevo comentario", + "review.acceptAll": "Aceptar todo", + "review.rejectAll": "Rechazar todo", + "style.normal": "Normal", + "style.heading1": "Título 1", + "style.heading2": "Título 2", + "style.heading3": "Título 3", + "status.ready": "Listo.", + "status.editing": "Editando…", + "status.words": "palabras", + "status.chars": "caracteres", + "xml.title": "XML sin procesar — DrawingML / OMML / VML", + "xml.documentSource": "Documento — formas / fórmulas / VML en línea", + language: "Idioma", +}; + +const fr: Dict = { + "tab.home": "Accueil", + "tab.insert": "Insertion", + "tab.layout": "Disposition", + "tab.references": "Références", + "tab.review": "Révision", + "action.new": "Nouveau", + "action.open": "Ouvrir…", + "action.find": "Rechercher", + "action.xml": "XML", + "action.download": "Télécharger .docx", + "action.undo": "Annuler", + "action.redo": "Rétablir", + "find.find": "Rechercher", + "find.replaceWith": "Remplacer par", + "find.replaceAll": "Tout remplacer", + "find.close": "Fermer la recherche", + "group.font": "Police", + "group.text": "Texte", + "group.paragraph": "Paragraphe", + "group.styles": "Styles", + "group.insert": "Insertion", + "group.headings": "Titres", + "group.pageSetup": "Mise en page", + "group.sections": "Sections", + "group.references": "Références", + "group.tracking": "Suivi", + "ins.paragraph": "Paragraphe", + "ins.table": "Tableau", + "ins.pageBreak": "Saut de page", + "ins.link": "Lien", + "ins.picture": "Image", + "layout.sectionBreak": "Saut de section", + "layout.pageNumbers": "Numéros de page", + "ref.toc": "Table des matières", + "ref.footnote": "Note de bas de page", + "ref.endnote": "Note de fin", + "ref.bookmark": "Signet", + "review.newComment": "Nouveau commentaire", + "review.acceptAll": "Tout accepter", + "review.rejectAll": "Tout refuser", + "style.normal": "Normal", + "style.heading1": "Titre 1", + "style.heading2": "Titre 2", + "style.heading3": "Titre 3", + "status.ready": "Prêt.", + "status.editing": "Édition…", + "status.words": "mots", + "status.chars": "caractères", + "xml.title": "XML brut — DrawingML / OMML / VML", + "xml.documentSource": "Document — formes / maths / VML en ligne", + language: "Langue", +}; + +const de: Dict = { + "tab.home": "Start", + "tab.insert": "Einfügen", + "tab.layout": "Layout", + "tab.references": "Verweise", + "tab.review": "Überprüfen", + "action.new": "Neu", + "action.open": "Öffnen…", + "action.find": "Suchen", + "action.xml": "XML", + "action.download": ".docx herunterladen", + "action.undo": "Rückgängig", + "action.redo": "Wiederholen", + "find.find": "Suchen", + "find.replaceWith": "Ersetzen durch", + "find.replaceAll": "Alle ersetzen", + "find.close": "Suche schließen", + "group.font": "Schriftart", + "group.text": "Text", + "group.paragraph": "Absatz", + "group.styles": "Formatvorlagen", + "group.insert": "Einfügen", + "group.headings": "Überschriften", + "group.pageSetup": "Seite einrichten", + "group.sections": "Abschnitte", + "group.references": "Verweise", + "group.tracking": "Nachverfolgung", + "ins.paragraph": "Absatz", + "ins.table": "Tabelle", + "ins.pageBreak": "Seitenumbruch", + "ins.link": "Link", + "ins.picture": "Bild", + "layout.sectionBreak": "Abschnittsumbruch", + "layout.pageNumbers": "Seitenzahlen", + "ref.toc": "Inhaltsverzeichnis", + "ref.footnote": "Fußnote", + "ref.endnote": "Endnote", + "ref.bookmark": "Textmarke", + "review.newComment": "Neuer Kommentar", + "review.acceptAll": "Alle annehmen", + "review.rejectAll": "Alle ablehnen", + "style.normal": "Standard", + "style.heading1": "Überschrift 1", + "style.heading2": "Überschrift 2", + "style.heading3": "Überschrift 3", + "status.ready": "Bereit.", + "status.editing": "Bearbeiten…", + "status.words": "Wörter", + "status.chars": "Zeichen", + "xml.title": "Roh-XML — DrawingML / OMML / VML", + "xml.documentSource": "Dokument — Inline-Formen / Formeln / VML", + language: "Sprache", +}; + +const zh: Dict = { + "tab.home": "开始", + "tab.insert": "插入", + "tab.layout": "布局", + "tab.references": "引用", + "tab.review": "审阅", + "action.new": "新建", + "action.open": "打开…", + "action.find": "查找", + "action.xml": "XML", + "action.download": "下载 .docx", + "action.undo": "撤销", + "action.redo": "重做", + "find.find": "查找", + "find.replaceWith": "替换为", + "find.replaceAll": "全部替换", + "find.close": "关闭查找", + "group.font": "字体", + "group.text": "文本", + "group.paragraph": "段落", + "group.styles": "样式", + "group.insert": "插入", + "group.headings": "标题", + "group.pageSetup": "页面设置", + "group.sections": "分节", + "group.references": "引用", + "group.tracking": "修订", + "ins.paragraph": "段落", + "ins.table": "表格", + "ins.pageBreak": "分页符", + "ins.link": "链接", + "ins.picture": "图片", + "layout.sectionBreak": "分节符", + "layout.pageNumbers": "页码", + "ref.toc": "目录", + "ref.footnote": "脚注", + "ref.endnote": "尾注", + "ref.bookmark": "书签", + "review.newComment": "新建批注", + "review.acceptAll": "全部接受", + "review.rejectAll": "全部拒绝", + "style.normal": "正文", + "style.heading1": "标题 1", + "style.heading2": "标题 2", + "style.heading3": "标题 3", + "status.ready": "就绪。", + "status.editing": "编辑中…", + "status.words": "词", + "status.chars": "字符", + "xml.title": "原始 XML — DrawingML / OMML / VML", + "xml.documentSource": "文档 — 内联图形 / 公式 / VML", + language: "语言", +}; + +const DICTS: Record = { en, ja, es, fr, de, zh }; + +let current = $state("en"); + +/** The active locale (reactive). */ +export function locale(): LocaleId { + return current; +} + +export function setLocale(id: LocaleId): void { + current = id; +} + +/** Translate a message key in the active locale, falling back to English. */ +export function t(key: MessageKey): string { + return DICTS[current][key] ?? en[key] ?? key; +} diff --git a/site/src/routes/editor/+page.svelte b/site/src/routes/editor/+page.svelte new file mode 100644 index 0000000..e232ff4 --- /dev/null +++ b/site/src/routes/editor/+page.svelte @@ -0,0 +1,672 @@ + + +word-kit editor + + +
+ +
+ word-kit + + + +
+ + + + + + +
+ + {#if showFind} +
+ + + + {findStatus} + +
+ {/if} + + +
+ {#each TAB_IDS as id (id)} + + {/each} +
+ + +
+ {#if tab === 'home'} +
+
+ + apply(commands.setFontSizeCommand, { points: fontSize })} + aria-label="Font size" + class="num" + /> +
+
{t('group.font')}
+
+ +
+
+ + + + + + + +
+
{t('group.text')}
+
+ +
+
+ + + + + + + +
+
{t('group.paragraph')}
+
+ +
+
+ +
+
{t('group.styles')}
+
+ {:else if tab === 'insert'} +
+
+ + + + + +
+
{t('group.insert')}
+
+
+
+ + + +
+
{t('group.headings')}
+
+ {:else if tab === 'layout'} +
+
+ + + + +
+
{t('group.pageSetup')}
+
+
+
+ + +
+
{t('group.sections')}
+
+ {:else if tab === 'references'} +
+
+ + + + +
+
{t('group.references')}
+
+ {:else if tab === 'review'} +
+
+ + + +
+
{t('group.tracking')}
+
+ {/if} +
+ + +
+
+ {#if model} + + {:else} +

Loading editor…

+ {/if} +
+ {#if showXml && model} + + {/if} +
+ +
+ {status || t('status.ready')} +
+ {wordCount} {t('status.words')} · {charCount} {t('status.chars')} +
+ + {Math.round(zoom * 100)}% + +
+
+
+ + diff --git a/src/api/docx.ts b/src/api/docx.ts index ce7bbe8..b964558 100644 --- a/src/api/docx.ts +++ b/src/api/docx.ts @@ -61,6 +61,9 @@ import { bulletAbstractNumLevels, decimalAbstractNumLevels, documentText, + getElementProp, + setElementOnOff, + setElementValProp, mergeAdjacentRuns as wmlMergeAdjacentRuns, EMPTY_COMMENTS_XML, EMPTY_NUMBERING_XML, @@ -111,7 +114,7 @@ import { writeStylesPart, writeWmlDocument, } from "../internal/wordprocessingml/index.js"; -import type { XmlElement, XmlNode } from "../internal/xml/index.js"; +import type { XmlAttr, XmlDocument, XmlElement, XmlNode } from "../internal/xml/index.js"; import { type ValidationIssue, validatePackage } from "./validator.js"; const DOCUMENT_PART_FALLBACK = "/word/document.xml"; @@ -197,6 +200,10 @@ export interface Docx { footnotesDirty: boolean; endnotesCache: WmlFootnotesPart | undefined; endnotesDirty: boolean; + /** Parsed roots of parts opened by the universal raw-XML part editor. */ + rawParts: Map; + /** Part names whose raw root was mutated and must be re-serialized on save. */ + rawPartsDirty: Set; } function makeDocx(opc: OpcPackage, document: WmlDocument, partName: string): Docx { @@ -215,6 +222,8 @@ function makeDocx(opc: OpcPackage, document: WmlDocument, partName: string): Doc footnotesDirty: false, endnotesCache: undefined, endnotesDirty: false, + rawParts: new Map(), + rawPartsDirty: new Set(), }; } @@ -843,6 +852,300 @@ function ensureStylesPart(doc: Docx): WmlStylesPart { return doc.stylesCache; } +const SETTINGS_PART_NAME = "/word/settings.xml"; +const EMPTY_SETTINGS_XML = ` +`; + +/** Ensure `word/settings.xml` exists (part + relationship) and return its part. */ +function ensureSettingsPart(doc: Docx): Part { + const existing = getPart(doc.opc, SETTINGS_PART_NAME); + if (existing) return existing; + addPart(doc.opc, { + name: SETTINGS_PART_NAME, + contentType: WML_CONTENT_TYPES.settings, + data: new TextEncoder().encode(EMPTY_SETTINGS_XML), + }); + const docRels = partRelationships(doc.opc, doc.partName); + if (relationshipsByType(docRels, WML_RELATIONSHIPS.settings).length === 0) { + addRelationship(docRels, { type: WML_RELATIONSHIPS.settings, target: "settings.xml" }); + } + return getPart(doc.opc, SETTINGS_PART_NAME) as Part; +} + +/** + * Toggle an on-off document setting in `word/settings.xml` (e.g. + * `evenAndOddHeaders`, `mirrorMargins`, `trackRevisions`, `autoHyphenation`). + * Creates the settings part if the document has none. Pass `false` to clear. + */ +export function setDocumentSettingOnOff(doc: Docx, local: string, on: boolean): void { + const part = ensureSettingsPart(doc); + const xmlDoc = parseXml(new TextDecoder("utf-8").decode(part.data)); + setElementOnOff(xmlDoc.root, local, on); + part.data = new TextEncoder().encode(serializeXml(xmlDoc)); + doc.dirty = true; +} + +/** + * Set a single-value document setting in `word/settings.xml` (e.g. + * `defaultTabStop`, `zoom`, `hyphenationZone`, `characterSpacingControl`). + * Pass `undefined` to remove it. + */ +export function setDocumentSettingVal(doc: Docx, local: string, val: string | undefined): void { + const part = ensureSettingsPart(doc); + const xmlDoc = parseXml(new TextDecoder("utf-8").decode(part.data)); + setElementValProp(xmlDoc.root, local, val); + part.data = new TextEncoder().encode(serializeXml(xmlDoc)); + doc.dirty = true; +} + +/** Read a document setting's presence / value from `word/settings.xml`. */ +export function getDocumentSetting(doc: Docx, local: string): { present: boolean; val?: string } { + const part = getPart(doc.opc, SETTINGS_PART_NAME); + if (!part) return { present: false }; + return getElementProp(parseXml(new TextDecoder("utf-8").decode(part.data)).root, local); +} + +/** + * Toggle an on-off child of a `` definition (e.g. `qFormat`, `hidden`, + * `semiHidden`, `locked`, `unhideWhenUsed`). No-op if the style id is unknown. + */ +export function setStyleOnOff(doc: Docx, styleId: string, local: string, on: boolean): void { + const part = stylesPart(doc); + const style = part ? findStyle(part, styleId) : undefined; + if (!style) return; + setElementOnOff(style, local, on); + doc.stylesDirty = true; + doc.dirty = true; +} + +/** + * Set a single-value child of a `` definition (e.g. `name`, `basedOn`, + * `next`, `link`, `uiPriority`, `aliases`). Pass `undefined` to remove it. + */ +export function setStyleValProp( + doc: Docx, + styleId: string, + local: string, + val: string | undefined, +): void { + const part = stylesPart(doc); + const style = part ? findStyle(part, styleId) : undefined; + if (!style) return; + setElementValProp(style, local, val); + doc.stylesDirty = true; + doc.dirty = true; +} + +/** Read a `` child's presence / value. */ +export function getStyleProp( + doc: Docx, + styleId: string, + local: string, +): { present: boolean; val?: string } { + const part = stylesPart(doc); + const style = part ? findStyle(part, styleId) : undefined; + return getElementProp(style, local); +} + +/** Locate the `` inside the abstractNum at `abstractNumIndex`. */ +function findAbstractNumLevel( + doc: Docx, + abstractNumIndex: number, + ilvl: number, +): XmlElement | undefined { + const part = numberingPart(doc); + const abs = part?.abstractNums[abstractNumIndex]; + if (!abs) return undefined; + return abs.children.find( + (c): c is XmlElement => + c.kind === "element" && + c.name.local === "lvl" && + c.attrs.find((a) => a.name.local === "ilvl")?.value === String(ilvl), + ); +} + +/** + * Set a single-value child of a numbering level (``): `numFmt`, `lvlText`, + * `start`, `lvlRestart`, `suff`, `lvlJc`, `pStyle`. Targets the level `ilvl` of + * the abstract numbering definition at `abstractNumIndex` (usually 0). + */ +export function setNumberingLevelVal( + doc: Docx, + abstractNumIndex: number, + ilvl: number, + local: string, + val: string | undefined, +): void { + const lvl = findAbstractNumLevel(doc, abstractNumIndex, ilvl); + if (!lvl) return; + setElementValProp(lvl, local, val); + doc.numberingDirty = true; + doc.dirty = true; +} + +/** Toggle an on-off child of a numbering level (e.g. `isLgl`). */ +export function setNumberingLevelOnOff( + doc: Docx, + abstractNumIndex: number, + ilvl: number, + local: string, + on: boolean, +): void { + const lvl = findAbstractNumLevel(doc, abstractNumIndex, ilvl); + if (!lvl) return; + setElementOnOff(lvl, local, on); + doc.numberingDirty = true; + doc.dirty = true; +} + +/** Read a numbering level child's presence / value. */ +export function getNumberingLevelProp( + doc: Docx, + abstractNumIndex: number, + ilvl: number, + local: string, +): { present: boolean; val?: string } { + return getElementProp(findAbstractNumLevel(doc, abstractNumIndex, ilvl), local); +} + +/** Set an (unqualified) attribute by local name, replacing any existing one. */ +function setLocalAttr(el: XmlElement, local: string, value: string): void { + const attrs = el.attrs as XmlAttr[]; + const existing = attrs.find((a) => a.name.local === local); + if (existing) { + (existing as { value: string }).value = value; + } else { + attrs.push({ name: { uri: "", local, prefix: "" }, value, isNamespaceDecl: false }); + } +} + +function readLocalAttr(el: XmlElement | undefined, local: string): string | undefined { + return el?.attrs.find((a) => a.name.local === local)?.value; +} + +/** Every inline/anchored `` element in the body, in document order. */ +export function imageDrawings(doc: Docx): XmlElement[] { + const out: XmlElement[] = []; + const visitParagraph = (p: WmlParagraph): void => { + for (const child of p.children) { + if (child.kind !== "run") continue; + for (const piece of child.pieces) { + if (piece.kind === "drawing") out.push(piece.node); + } + } + }; + for (const block of doc.document.body.blocks) { + if (block.kind === "paragraph") visitParagraph(block); + else if (block.kind === "table") { + for (const row of block.rows) { + for (const cell of row.cells) { + for (const p of cell.paragraphs) visitParagraph(p); + } + } + } + } + return out; +} + +/** + * Resize the image at `index` (in {@link imageDrawings} order) to `cxEmu` × + * `cyEmu` EMU (914400 per inch). Updates both the layout extent (`wp:extent`) + * and the picture transform extent (`a:ext`). + */ +export function setImageSizeEmu(doc: Docx, index: number, cxEmu: number, cyEmu: number): void { + const drawing = imageDrawings(doc)[index]; + if (!drawing) return; + for (const local of ["extent", "ext"]) { + const el = findDescendantByLocal(drawing, local); + if (el) { + setLocalAttr(el, "cx", String(Math.round(cxEmu))); + setLocalAttr(el, "cy", String(Math.round(cyEmu))); + } + } + doc.dirty = true; +} + +/** Set the alt text (`wp:docPr` `descr` / `title`) of the image at `index`. */ +export function setImageAltText( + doc: Docx, + index: number, + alt: { descr?: string; title?: string }, +): void { + const drawing = imageDrawings(doc)[index]; + const docPr = drawing ? findDescendantByLocal(drawing, "docPr") : undefined; + if (!docPr) return; + if (alt.descr !== undefined) setLocalAttr(docPr, "descr", alt.descr); + if (alt.title !== undefined) setLocalAttr(docPr, "title", alt.title); + doc.dirty = true; +} + +/** Read the size (EMU) and alt text of the image at `index`. */ +export function getImageInfo( + doc: Docx, + index: number, +): + | { + cx: string | undefined; + cy: string | undefined; + descr: string | undefined; + title: string | undefined; + } + | undefined { + const drawing = imageDrawings(doc)[index]; + if (!drawing) return undefined; + const extent = findDescendantByLocal(drawing, "extent"); + const docPr = findDescendantByLocal(drawing, "docPr"); + return { + cx: readLocalAttr(extent, "cx"), + cy: readLocalAttr(extent, "cy"), + descr: readLocalAttr(docPr, "descr"), + title: readLocalAttr(docPr, "title"), + }; +} + +// --- Universal OPC-part raw XML editor --------------------------------------- +// +// The document.xml raw inspector reaches DrawingML / OMML / VML that live inline +// in the body. Everything else — fontTable, settings, styles, numbering, +// comments, foot/endnotes, headers/footers, webSettings, docProps — lives in its +// own XML part. These functions expose *any* XML part's element tree so the +// raw inspector can edit any element in the whole package, flushed on save. + +/** Every XML part name in the package (excluding `[Content_Types].xml`). */ +export function xmlPartNames(doc: Docx): string[] { + const names: string[] = []; + for (const [name, part] of doc.opc.parts) { + if (name === CONTENT_TYPES_PART_NAME) continue; + const ct = part.contentType ?? ""; + if (ct.includes("xml") || name.endsWith(".xml")) names.push(name); + } + return names.toSorted(); +} + +/** + * Parse (and cache) the root element of an XML part so callers can edit it with + * {@link setElementAttr} / {@link setElementOnOff} / {@link setElementValProp}. + * Call {@link markRawPartDirty} after mutating so the change is written on save. + * Returns `undefined` if the part does not exist or is not XML. + */ +export function getRawPartRoot(doc: Docx, partName: string): XmlElement | undefined { + const cached = doc.rawParts.get(partName); + if (cached) return cached.root; + // Bring all pending semantic edits onto the part bytes before we parse, so the + // raw tree reflects the current document state. + flushPendingParts(doc); + const part = getPart(doc.opc, partName); + if (!part) return undefined; + const xmlDoc = parseXml(new TextDecoder("utf-8").decode(part.data)); + doc.rawParts.set(partName, xmlDoc); + return xmlDoc.root; +} + +/** Mark a raw-edited part for re-serialization on the next {@link toUint8Array}. */ +export function markRawPartDirty(doc: Docx, partName: string): void { + doc.rawPartsDirty.add(partName); +} + /** * Append a table to the body. `rows` is a row-major matrix of strings; * each cell becomes a single paragraph with a single run containing the @@ -1162,6 +1465,208 @@ export function insertParagraphAt( return para; } +// --- Paragraph split / merge (caret-level structural editing) ---------------- +// +// These power Enter (split at the caret) and Backspace-at-start (merge into the +// previous paragraph) in the editor. They operate on the semantic AST by BODY +// BLOCK index — the same index the editor's DocPosition.block carries. + +function simpleRunText(run: WmlRun): string { + let out = ""; + for (const piece of run.pieces) { + if (piece.kind === "text") out += piece.value; + } + return out; +} + +function isRunSimpleText(run: WmlRun): boolean { + return run.pieces.every((p) => p.kind === "text"); +} + +function makeTextRun(rPr: XmlElement | undefined, text: string): WmlRun { + const preserveSpace = /^\s|\s$|\s\s/.test(text); + return { + kind: "run", + ...(rPr ? { rPr: structuredClone(rPr) } : {}), + pieces: text ? [{ kind: "text", value: text, preserveSpace }] : [], + extras: [], + }; +} + +function emptyParagraphChildren(): WmlInline[] { + return [{ kind: "run", pieces: [], extras: [] }]; +} + +/** + * Split the paragraph block at `blockIndex` into two paragraphs at run + * `inlineIndex` / character `offset`. The new paragraph inherits the original's + * `pPr`. Returns the new (second) paragraph's block index, or `-1` when the + * block is not a top-level paragraph. + */ +export function splitParagraphAt( + doc: Docx, + blockIndex: number, + inlineIndex: number, + offset: number, +): number { + const list = doc.document.body.blocks; + const para = list[blockIndex]; + if (!para || para.kind !== "paragraph") return -1; + + const before: WmlInline[] = []; + const after: WmlInline[] = []; + let runCounter = -1; + for (const child of para.children) { + if (child.kind !== "run") { + (runCounter < inlineIndex ? before : after).push(child); + continue; + } + runCounter++; + if (runCounter < inlineIndex) { + before.push(child); + } else if (runCounter > inlineIndex) { + after.push(child); + } else if (isRunSimpleText(child)) { + const text = simpleRunText(child); + before.push(makeTextRun(child.rPr, text.slice(0, offset))); + after.push(makeTextRun(child.rPr, text.slice(offset))); + } else { + // A run carrying tabs / breaks / drawings is kept whole; the caret side + // is chosen by whether the offset is at its very start. + (offset <= 0 ? after : before).push(child); + } + } + + para.children = before.length > 0 ? before : emptyParagraphChildren(); + const newPara: WmlParagraph = { + kind: "paragraph", + ...(para.pPr ? { pPr: structuredClone(para.pPr) } : {}), + children: after.length > 0 ? after : emptyParagraphChildren(), + extras: [], + }; + list.splice(blockIndex + 1, 0, newPara); + doc.dirty = true; + return blockIndex + 1; +} + +/** + * Merge the paragraph block at `blockIndex` into the nearest preceding + * paragraph block, appending its inline content. Returns the caret position at + * the join (the end of the previous paragraph's original content), or `null` + * when there is no preceding paragraph to merge into. + */ +export function mergeParagraphIntoPrevious( + doc: Docx, + blockIndex: number, +): { block: number; inline: number; offset: number } | null { + const list = doc.document.body.blocks; + const cur = list[blockIndex]; + if (!cur || cur.kind !== "paragraph") return null; + let prevIndex = blockIndex - 1; + while (prevIndex >= 0 && list[prevIndex]?.kind !== "paragraph") prevIndex--; + const prev = list[prevIndex]; + if (!prev || prev.kind !== "paragraph") return null; + + const prevRuns = prev.children.filter((c): c is WmlRun => c.kind === "run"); + const lastRun = prevRuns[prevRuns.length - 1]; + const joinInline = Math.max(prevRuns.length - 1, 0); + const joinOffset = lastRun ? simpleRunText(lastRun).length : 0; + + // Drop a leading empty run on the merged paragraph so we don't leave a stray + // zero-length run at the join. + const incoming = cur.children.filter( + (c, i) => !(i === 0 && c.kind === "run" && c.pieces.length === 0), + ); + // Drop a trailing empty run on the previous paragraph for the same reason, + // but only when there is incoming content to replace it. + if ( + incoming.length > 0 && + prev.children.length > 0 && + (() => { + const last = prev.children[prev.children.length - 1]; + return last?.kind === "run" && last.pieces.length === 0; + })() + ) { + prev.children.pop(); + } + prev.children.push(...incoming); + list.splice(blockIndex, 1); + doc.dirty = true; + return { block: prevIndex, inline: joinInline, offset: joinOffset }; +} + +/** + * Visible text length of a run as the editing canvas counts characters + * (text = its length; tab / break / hyphen = 1; drawings / fields = 0). This is + * the unit selection offsets are expressed in. + */ +export function runTextLength(run: WmlRun): number { + let n = 0; + for (const piece of run.pieces) { + if (piece.kind === "text") n += piece.value.length; + else if ( + piece.kind === "tab" || + piece.kind === "break" || + piece.kind === "noBreakHyphen" || + piece.kind === "softHyphen" + ) { + n += 1; + } + } + return n; +} + +/** Split the simple-text run containing absolute char `at` so a run boundary + * falls exactly there. No-op when `at` is already a boundary or lands in a run + * that cannot be split cleanly (tabs / drawings / fields). */ +function ensureRunBoundaryAt(para: WmlParagraph, at: number): void { + let cursor = 0; + for (let i = 0; i < para.children.length; i++) { + const child = para.children[i]; + if (!child || child.kind !== "run") continue; + const start = cursor; + const end = cursor + runTextLength(child); + cursor = end; + if (at <= start || at >= end) continue; + if (!isRunSimpleText(child)) continue; + const text = simpleRunText(child); + const rel = at - start; + para.children.splice( + i, + 1, + makeTextRun(child.rPr, text.slice(0, rel)), + makeTextRun(child.rPr, text.slice(rel)), + ); + return; + } +} + +/** + * Isolate the character range `[startChar, endChar)` of a paragraph into its own + * run(s) — splitting runs at the boundaries — and return those runs. This is + * what lets character formatting (bold / color / …) apply to *exactly* the + * selected text instead of the whole run/line. Returns `[]` for an empty range. + */ +export function isolateParagraphRunRange( + para: WmlParagraph, + startChar: number, + endChar: number, +): WmlRun[] { + if (endChar <= startChar) return []; + ensureRunBoundaryAt(para, endChar); + ensureRunBoundaryAt(para, startChar); + const out: WmlRun[] = []; + let cursor = 0; + for (const child of para.children) { + if (child.kind !== "run") continue; + const start = cursor; + const end = cursor + runTextLength(child); + cursor = end; + if (start >= startChar && end <= endChar && end > start) out.push(child); + } + return out; +} + /** Remove the paragraph at `index` from the body. Returns true on success. */ export function removeParagraph(doc: Docx, index: number): boolean { let count = 0; @@ -2715,28 +3220,37 @@ export function clone(doc: Docx): Docx { * their dirty fast-path. */ function flushPendingParts(doc: Docx): void { - flushDocument(doc); + // A part opened by the raw-XML editor is authoritative for its own bytes, so + // skip the semantic flush for it (its raw root is serialized below instead). + const owned = doc.rawParts; + if (!owned.has(doc.partName)) flushDocument(doc); doc.dirty = false; - if (doc.stylesDirty && doc.stylesCache) { + if (doc.stylesDirty && doc.stylesCache && !owned.has(STYLES_PART_NAME)) { flushStyles(doc, doc.stylesCache); doc.stylesDirty = false; } - if (doc.numberingDirty && doc.numberingCache) { + if (doc.numberingDirty && doc.numberingCache && !owned.has(NUMBERING_PART_NAME)) { flushNumbering(doc, doc.numberingCache); doc.numberingDirty = false; } - if (doc.commentsDirty && doc.commentsCache) { + if (doc.commentsDirty && doc.commentsCache && !owned.has(COMMENTS_PART_NAME)) { flushComments(doc, doc.commentsCache); doc.commentsDirty = false; } - if (doc.footnotesDirty && doc.footnotesCache) { + if (doc.footnotesDirty && doc.footnotesCache && !owned.has(FOOTNOTES_PART_NAME)) { flushNotes(doc, doc.footnotesCache, FOOTNOTES_PART_NAME, "footnotes"); doc.footnotesDirty = false; } - if (doc.endnotesDirty && doc.endnotesCache) { + if (doc.endnotesDirty && doc.endnotesCache && !owned.has(ENDNOTES_PART_NAME)) { flushNotes(doc, doc.endnotesCache, ENDNOTES_PART_NAME, "endnotes"); doc.endnotesDirty = false; } + for (const name of doc.rawPartsDirty) { + const xmlDoc = owned.get(name); + const part = xmlDoc && getPart(doc.opc, name); + if (part) part.data = new TextEncoder().encode(serializeXml(xmlDoc)); + } + doc.rawPartsDirty.clear(); } /** Serialize the package back to `.docx` bytes. */ diff --git a/src/api/index.ts b/src/api/index.ts index 4e9a103..6c50d8d 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -9,11 +9,22 @@ export { type ValidationIssue, validatePackage } from "./validator.js"; export { appendTableRow, appendTextRun, + type BuildStyleOptions, + type BuildTableOptions, + appendChildElement, + childElementsOf, clearRunFormat, + type DocumentAppProperties, + type DocumentCoreProperties, + getElementAttr, + getElementProp, getParagraphAlignment, getParagraphNumbering, + getParagraphProp, getParagraphStyle, getRunFormat, + getRunProp, + makePropsElement, getTableCellText, mergeAdjacentRuns, type HeaderFooterType, @@ -30,14 +41,21 @@ export { paragraphText, removeTableRow, type RunFormatting, + setElementAttr, + setElementOnOff, + setElementValProp, setParagraphAlignment, setParagraphBorders, setParagraphIndent, + setParagraphOnOff, setParagraphShading, setParagraphSpacing, setParagraphStyle, setParagraphText, + setParagraphValProp, setRunFormat, + setRunOnOff, + setRunValProp, setTableBorders, setTableCellShading, setTableCellText, @@ -65,4 +83,8 @@ export type { WmlTableCell, WmlTableRow, } from "../internal/wordprocessingml/index.js"; +// Raw XML AST types — the low-level escape hatch. `WmlRun.rPr`, `WmlTableCell.tcPr`, +// etc. are `XmlElement`, so consumers manipulating them (e.g. generic property +// setters) need these names. +export type { QName, XmlAttr, XmlElement, XmlNode } from "../internal/xml/index.js"; export { VERSION } from "./version.js"; diff --git a/src/api/paragraph-edit.test.ts b/src/api/paragraph-edit.test.ts new file mode 100644 index 0000000..ecea8ae --- /dev/null +++ b/src/api/paragraph-edit.test.ts @@ -0,0 +1,86 @@ +/** + * Paragraph split/merge and run-range isolation — the caret-level structural + * primitives behind the editor's Enter, Backspace, and selection formatting. + */ + +import { describe, expect, it } from "vitest"; +import { + createDocx, + getRunFormat, + isolateParagraphRunRange, + mergeParagraphIntoPrevious, + openDocx, + paragraphs, + paragraphText, + runTextLength, + setRunFormat, + splitParagraphAt, + toUint8Array, + validate, + type WmlRun, +} from "../index.js"; + +function runTexts(doc: ReturnType, block: number): string[] { + const para = doc.document.body.blocks[block]; + if (!para || para.kind !== "paragraph") return []; + return para.children + .filter((c): c is WmlRun => c.kind === "run") + .map((r) => r.pieces.map((p) => (p.kind === "text" ? p.value : "")).join("")); +} + +describe("splitParagraphAt", () => { + it("splits at an offset, inherits pPr, and round-trips", () => { + const doc = createDocx({ paragraphs: ["Hello world"] }); + const nb = splitParagraphAt(doc, 0, 0, 5); + expect(nb).toBe(1); + expect(paragraphs(doc).map(paragraphText)).toEqual(["Hello", " world"]); + const re = openDocx(toUint8Array(doc)); + expect(validate(re).length).toBe(0); + }); + + it("returns -1 for a non-paragraph block", () => { + const doc = createDocx({ paragraphs: ["x"] }); + expect(splitParagraphAt(doc, 99, 0, 0)).toBe(-1); + }); +}); + +describe("mergeParagraphIntoPrevious", () => { + it("merges into the previous paragraph and reports the join", () => { + const doc = createDocx({ paragraphs: ["Hello", " world"] }); + const pos = mergeParagraphIntoPrevious(doc, 1); + expect(pos).toEqual({ block: 0, inline: 0, offset: 5 }); + expect(paragraphs(doc).map(paragraphText)).toEqual(["Hello world"]); + }); + + it("returns null with no preceding paragraph", () => { + const doc = createDocx({ paragraphs: ["only"] }); + expect(mergeParagraphIntoPrevious(doc, 0)).toBeNull(); + }); +}); + +describe("runTextLength / isolateParagraphRunRange", () => { + it("counts visible characters", () => { + const doc = createDocx({ paragraphs: ["abcdef"] }); + const run = paragraphs(doc)[0]!.children.find((c): c is WmlRun => c.kind === "run")!; + expect(runTextLength(run)).toBe(6); + }); + + it("isolates a middle range into its own run", () => { + const doc = createDocx({ paragraphs: ["Hello world foo"] }); + const para = paragraphs(doc)[0]!; + const runs = isolateParagraphRunRange(para, 6, 11); + for (const r of runs) setRunFormat(r, { bold: true }); + expect(runTexts(doc, 0)).toEqual(["Hello ", "world", " foo"]); + const re = openDocx(toUint8Array(doc)); + expect(validate(re).length).toBe(0); + const bolded = paragraphs(re)[0]! + .children.filter((c): c is WmlRun => c.kind === "run") + .find((r) => getRunFormat(r).bold); + expect(bolded?.pieces.map((p) => (p.kind === "text" ? p.value : "")).join("")).toBe("world"); + }); + + it("returns nothing for an empty range", () => { + const doc = createDocx({ paragraphs: ["abc"] }); + expect(isolateParagraphRunRange(paragraphs(doc)[0]!, 2, 2)).toEqual([]); + }); +}); diff --git a/src/internal/wordprocessingml/builders.ts b/src/internal/wordprocessingml/builders.ts index bd7164e..3b6950d 100644 --- a/src/internal/wordprocessingml/builders.ts +++ b/src/internal/wordprocessingml/builders.ts @@ -573,6 +573,183 @@ export function clearRunFormat(run: WmlRun): void { delete run.rPr; } +// --- Generic run/paragraph property access ------------------------------------ +// +// `setRunFormat` / `setParagraphAlignment` cover the common formatting. These +// generic helpers reach *any* on-off (``) or single-value (``) child of `` / ``, so callers (e.g. the editor's +// property commands) can toggle the long tail of WordprocessingML formatting +// (caps, smallCaps, vanish, keepNext, widowControl, outlineLvl, …) without a +// bespoke function per element. Complex children (rFonts, ind, spacing, borders, +// shading, tabs, numPr, framePr) keep their dedicated builders. + +function ensureRPr(run: WmlRun): XmlElement { + if (!run.rPr) { + run.rPr = { + kind: "element", + name: { uri: WML_NS, local: "rPr", prefix: "w" }, + attrs: [], + children: [], + xmlSpace: "default", + selfClosing: false, + }; + } + return run.rPr; +} + +/** Remove every direct child named `local` from a properties element. */ +function removePropChild(container: XmlElement, local: string): void { + const children = container.children as XmlElement[]; + for (let i = children.length - 1; i >= 0; i--) { + const c = children[i]; + if (c && c.kind === "element" && c.name.uri === WML_NS && c.name.local === local) { + children.splice(i, 1); + } + } +} + +/** Add or remove an on-off property element (``, ``, …). */ +function setOnOffChild(container: XmlElement, local: string, on: boolean): void { + removePropChild(container, local); + if (on) (container.children as XmlElement[]).push(wmlEmpty(local, [])); +} + +/** Set a single-value property element (``); undefined removes it. */ +function setValChild(container: XmlElement, local: string, val: string | undefined): void { + removePropChild(container, local); + if (val !== undefined) { + (container.children as XmlElement[]).push(wmlEmpty(local, [wmlAttr("val", val)])); + } +} + +/** Read whether a property element is present and its `w:val`, if any. */ +function readProp( + container: XmlElement | undefined, + local: string, +): { present: boolean; val?: string } { + if (!container) return { present: false }; + for (const c of container.children) { + if (c.kind === "element" && c.name.uri === WML_NS && c.name.local === local) { + const val = c.attrs.find((a) => a.name.uri === WML_NS && a.name.local === "val")?.value; + return val !== undefined ? { present: true, val } : { present: true }; + } + } + return { present: false }; +} + +/** Toggle an on-off `` child (creates `` if absent). */ +export function setRunOnOff(run: WmlRun, local: string, on: boolean): void { + setOnOffChild(ensureRPr(run), local, on); +} + +/** Set a single-value `` child; `undefined` removes it. */ +export function setRunValProp(run: WmlRun, local: string, val: string | undefined): void { + setValChild(ensureRPr(run), local, val); +} + +/** Read an `` child's presence / value. */ +export function getRunProp(run: WmlRun, local: string): { present: boolean; val?: string } { + return readProp(run.rPr, local); +} + +/** Toggle an on-off `` child (creates `` if absent). */ +export function setParagraphOnOff(p: WmlParagraph, local: string, on: boolean): void { + setOnOffChild(ensurePPr(p), local, on); +} + +/** Set a single-value `` child; `undefined` removes it. */ +export function setParagraphValProp(p: WmlParagraph, local: string, val: string | undefined): void { + setValChild(ensurePPr(p), local, val); +} + +/** Read a `` child's presence / value. */ +export function getParagraphProp( + p: WmlParagraph, + local: string, +): { present: boolean; val?: string } { + return readProp(p.pPr, local); +} + +// --- Container-level generic property access ---------------------------------- +// +// The same on-off / single-value machinery, but operating on an arbitrary +// properties element (``, ``, ``, ``, `` +// …) passed in by the caller. The editor uses these for the long tail of table, +// row, cell, and section formatting, ensuring the container exists first. + +/** Toggle an on-off child on any properties element. */ +export function setElementOnOff(container: XmlElement, local: string, on: boolean): void { + setOnOffChild(container, local, on); +} + +/** Set a single-value child on any properties element; `undefined` removes it. */ +export function setElementValProp( + container: XmlElement, + local: string, + val: string | undefined, +): void { + setValChild(container, local, val); +} + +/** Read a child's presence / value from any properties element. */ +export function getElementProp( + container: XmlElement | undefined, + local: string, +): { present: boolean; val?: string } { + return readProp(container, local); +} + +/** Build an empty properties element (``, ``, …). */ +export function makePropsElement(local: string): XmlElement { + return { + kind: "element", + name: { uri: WML_NS, local, prefix: "w" }, + attrs: [], + children: [], + xmlSpace: "default", + selfClosing: false, + }; +} + +// --- Raw XML node editing ----------------------------------------------------- +// +// The universal escape hatch: set/read any attribute or child on any element in +// the AST. The editor's raw-XML inspector uses these to make every element — +// including DrawingML / OMML / VML that live inline in document.xml — editable, +// without a bespoke command per OOXML element. + +/** Set (or, with `undefined`, remove) an attribute by local name on any element. */ +export function setElementAttr(el: XmlElement, local: string, value: string | undefined): void { + const attrs = el.attrs as XmlAttr[]; + const index = attrs.findIndex((a) => a.name.local === local); + if (value === undefined) { + if (index >= 0) attrs.splice(index, 1); + return; + } + if (index >= 0) { + (attrs[index] as { value: string }).value = value; + } else { + attrs.push({ name: { uri: "", local, prefix: "" }, value, isNamespaceDecl: false }); + } +} + +/** Read an attribute value by local name from any element. */ +export function getElementAttr(el: XmlElement, local: string): string | undefined { + return el.attrs.find((a) => a.name.local === local)?.value; +} + +/** The direct child elements of an element (text/comment nodes filtered out). */ +export function childElementsOf(el: XmlElement): XmlElement[] { + return el.children.filter((c): c is XmlElement => c.kind === "element"); +} + +/** Append a child element (`` in the WML namespace) and return it. */ +export function appendChildElement(parent: XmlElement, local: string): XmlElement { + const child = makePropsElement(local); + (parent.children as XmlElement[]).push(child); + return child; +} + /** * Read back the formatting a run currently has on its ``. Returns a * `RunFormatting` with only the keys that are actually present, so callers diff --git a/src/internal/wordprocessingml/index.ts b/src/internal/wordprocessingml/index.ts index ee252d6..c7bf76d 100644 --- a/src/internal/wordprocessingml/index.ts +++ b/src/internal/wordprocessingml/index.ts @@ -21,11 +21,18 @@ export { buildTextParagraph, buildTextRun, buildTextTable, + appendChildElement, + childElementsOf, clearRunFormat, + getElementAttr, + getElementProp, getParagraphAlignment, getParagraphNumbering, + getParagraphProp, getParagraphStyle, getRunFormat, + getRunProp, + makePropsElement, getTableCellText, mergeAdjacentRuns, type ParagraphAlignment, @@ -35,14 +42,21 @@ export { type ParagraphSpacing, removeTableRow, type RunFormatting, + setElementAttr, + setElementOnOff, + setElementValProp, setParagraphAlignment, setParagraphBorders, setParagraphIndent, + setParagraphOnOff, setParagraphShading, setParagraphSpacing, setParagraphStyle, setParagraphText, + setParagraphValProp, setRunFormat, + setRunOnOff, + setRunValProp, setTableBorders, setTableCellShading, setTableCellText,