@heycys/gallery 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +51 -1
- package/browser/editor/components/callout/index.mjs +40 -15
- package/browser/editor/components/columns/page.mjs +45 -32
- package/browser/editor/components/details/index.mjs +2 -1
- package/browser/editor/components/dialog/index.mjs +2 -1
- package/browser/editor/components/dialog/page.mjs +0 -18
- package/browser/editor/components/divider/index.mjs +1 -1
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/figure/page.mjs +10 -1
- package/browser/editor/components/file/page.mjs +2 -2
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/heading/index.mjs +2 -0
- package/browser/editor/components/heading/page.mjs +6 -0
- package/browser/editor/components/highlight/index.mjs +4 -20
- package/browser/editor/components/icons.mjs +13 -2
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/page.mjs +2 -2
- package/browser/editor/components/installed/index.mjs +82 -29
- package/browser/editor/components/installed/page.mjs +146 -34
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/kit.mjs +3 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/page.mjs +44 -14
- package/browser/editor/components/pages.mjs +2 -2
- package/browser/editor/components/registry.mjs +68 -33
- package/browser/editor/components/section/index.mjs +2 -1
- package/browser/editor/components/set-apart.mjs +24 -0
- package/browser/editor/components/table/index.mjs +64 -5
- package/browser/editor/components/table/page.mjs +30 -19
- package/browser/editor/page/annotate/anchors.mjs +4 -3
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/annotate/index.mjs +61 -34
- package/browser/editor/page/autosave.mjs +357 -38
- package/browser/editor/page/beside.mjs +5 -5
- package/browser/editor/page/block-menu/colors.mjs +3 -1
- package/browser/editor/page/block-menu/index.mjs +8 -6
- package/browser/editor/page/blocks.mjs +16 -7
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +145 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +970 -0
- package/browser/editor/page/board/settings.mjs +209 -0
- package/browser/editor/page/caret.mjs +5 -2
- package/browser/editor/page/changes/bar.mjs +94 -0
- package/browser/editor/page/changes/ghost.mjs +206 -0
- package/browser/editor/page/changes/gone-words.mjs +94 -0
- package/browser/editor/page/changes/index.mjs +447 -0
- package/browser/editor/page/changes/words.mjs +27 -0
- package/browser/editor/page/clipboard/import/colors.mjs +3 -3
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +156 -26
- package/browser/editor/page/clipboard/own/blocks.mjs +25 -16
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +16 -7
- package/browser/editor/page/clipboard/own/export.mjs +6 -6
- package/browser/editor/page/clipboard/own/selection.mjs +3 -3
- package/browser/editor/page/clipboard/own/writers.mjs +0 -11
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +98 -25
- package/browser/editor/page/conflicts.mjs +13 -33
- package/browser/editor/page/convert.mjs +8 -7
- package/browser/editor/page/core.mjs +81 -27
- package/browser/editor/page/custom-page.mjs +106 -0
- package/browser/editor/page/drag/index.mjs +40 -24
- package/browser/editor/page/drag/preview.mjs +9 -4
- package/browser/editor/page/editor.mjs +120 -28
- package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
- package/browser/editor/page/emoji-picker/grid.mjs +7 -5
- package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
- package/browser/editor/page/emoji-picker/icons.mjs +0 -1
- package/browser/editor/page/emoji-picker/index.mjs +11 -9
- package/browser/editor/page/emoji-picker/styles.mjs +156 -2
- package/browser/editor/page/emoji-picker/support.mjs +6 -4
- package/browser/editor/page/emoji-picker/upload.mjs +14 -13
- package/browser/editor/page/fills.mjs +5 -3
- package/browser/editor/page/fold/index.mjs +348 -0
- package/browser/editor/page/fold/rule.mjs +125 -0
- package/browser/editor/page/folded.mjs +23 -0
- package/browser/editor/page/format-bar/bar.mjs +2 -1
- package/browser/editor/page/format-bar/index.mjs +1 -1
- package/browser/editor/page/geometry.mjs +8 -6
- package/browser/editor/page/handle/index.mjs +22 -14
- package/browser/editor/page/hints/index.mjs +1 -1
- package/browser/editor/page/history.mjs +24 -4
- package/browser/editor/page/insert/index.mjs +30 -17
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/long-runs.mjs +75 -0
- package/browser/editor/page/look.mjs +69 -6
- package/browser/editor/page/margin.mjs +63 -27
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +86 -31
- package/browser/editor/page/merge.mjs +24 -0
- package/browser/editor/page/notices.mjs +3 -3
- package/browser/editor/page/offered.mjs +1 -1
- package/browser/editor/page/outline/folds.mjs +11 -10
- package/browser/editor/page/outline/index.mjs +131 -45
- package/browser/editor/page/outline/list.mjs +23 -11
- package/browser/editor/page/outline/read.mjs +1 -1
- package/browser/editor/page/outline/strip.mjs +7 -1
- package/browser/editor/page/page-objects.mjs +13 -2
- package/browser/editor/page/panel.mjs +9 -13
- package/browser/editor/page/present-links.mjs +11 -2
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/delete.mjs +8 -6
- package/browser/editor/page/selection/index.mjs +10 -3
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +101 -6
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/cell-bar.mjs +4 -1
- package/browser/editor/page/table/cells.mjs +103 -47
- package/browser/editor/page/table/icons.mjs +3 -1
- package/browser/editor/page/table/index.mjs +40 -16
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +150 -0
- package/browser/editor/page/table/widths.mjs +9 -4
- package/browser/editor/page/text-select/index.mjs +43 -14
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/tooltip.mjs +1 -1
- package/browser/editor/page/type-grid.mjs +4 -3
- package/browser/editor/page/typing/code-edges.mjs +63 -17
- package/browser/editor/page/typing/index.mjs +65 -9
- package/browser/editor/page/typing/leave.mjs +1 -1
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/annotations.mjs +8 -10
- package/browser/shared/block-packs.mjs +404 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/code-folds.mjs +5 -1
- package/browser/shared/colors.mjs +17 -14
- package/browser/shared/component-catalog.mjs +345 -54
- package/browser/shared/component-source.mjs +37 -0
- package/browser/shared/components/callout.mjs +4 -2
- package/browser/shared/components/index.mjs +72 -9
- package/browser/shared/components/installed.mjs +110 -8
- package/browser/shared/components/page.mjs +22 -3
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -1
- package/browser/shared/components/text.mjs +2 -2
- package/browser/shared/document-look.mjs +183 -0
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
- package/browser/shared/emoji/data/README.md +4 -2
- package/browser/shared/emoji/data/categories.json +1 -1
- package/browser/shared/emoji/data/keywords-en.json +1 -1
- package/browser/shared/emoji/data/keywords-zh.json +1 -1
- package/browser/shared/emoji/data/names.json +1 -1
- package/browser/shared/emoji/data/positions.json +1 -1
- package/browser/shared/emoji/data/twemoji-index.json +1 -1
- package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
- package/browser/shared/emoji/data.mjs +10 -12
- package/browser/shared/emoji/emoji.mjs +8 -7
- package/browser/shared/emoji/icon-value.mjs +4 -3
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/html-tree.mjs +11 -5
- package/browser/shared/i18n/en.mjs +374 -35
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/long-runs.mjs +39 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/new-names.mjs +5 -2
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +458 -0
- package/browser/shared/pack-manifest.mjs +77 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +388 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/preferences.mjs +10 -4
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +13 -5
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +134 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-look.mjs +91 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/browser/shared/zoom.mjs +5 -5
- package/dist/chunk-2NRBY6AJ.mjs +2 -0
- package/dist/chunk-32ZUEFZ7.mjs +2 -0
- package/dist/chunk-35NQ4PLQ.mjs +2 -0
- package/dist/chunk-3KJHLHUO.mjs +2 -0
- package/dist/chunk-3NJACR4W.mjs +2 -0
- package/dist/chunk-4AV456RQ.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5XYHDBJ5.mjs +2 -0
- package/dist/chunk-5ZJA7CXT.mjs +2 -0
- package/dist/chunk-6A53MZYZ.mjs +2 -0
- package/dist/chunk-6EXH3ORZ.mjs +166 -0
- package/dist/chunk-6EZ7FNIK.mjs +3 -0
- package/dist/{chunk-UXUK4PMC.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/{chunk-6U2SLSDN.mjs → chunk-6VTU6KEO.mjs} +1 -1
- package/dist/chunk-B4P2CM2J.mjs +3 -0
- package/dist/chunk-BPL64HGA.mjs +4 -0
- package/dist/chunk-BVEFGE4B.mjs +2 -0
- package/dist/chunk-BZ5RAF7L.mjs +2 -0
- package/dist/chunk-CRJEG7MT.mjs +2 -0
- package/dist/{chunk-B3VTYBYR.mjs → chunk-D4CKRD3V.mjs} +91 -91
- package/dist/chunk-D4EURAX4.mjs +4 -0
- package/dist/chunk-DQCE7TJY.mjs +5 -0
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/{chunk-DB4WKGYF.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-FJYN7RTH.mjs +4 -0
- package/dist/chunk-FWNRPMCJ.mjs +12 -0
- package/dist/chunk-FWW4CSAZ.mjs +2 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-GY3FAUVM.mjs +2 -0
- package/dist/chunk-HLYV7RIH.mjs +2 -0
- package/dist/chunk-HMYTM3GT.mjs +15 -0
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JVHHHGEA.mjs +3 -0
- package/dist/chunk-KTKHRC6H.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-MHW7ZKOU.mjs +2 -0
- package/dist/chunk-N76HWBA3.mjs +10 -0
- package/dist/chunk-N7AZZLGT.mjs +548 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-YXAUQPVK.mjs → chunk-NFMCP2HI.mjs} +3 -3
- package/dist/chunk-NG375ILQ.mjs +2 -0
- package/dist/chunk-NVRNLK25.mjs +6 -0
- package/dist/chunk-NWFBE2YA.mjs +2 -0
- package/dist/chunk-NWR2LT5B.mjs +2 -0
- package/dist/chunk-OJKMINIU.mjs +20 -0
- package/dist/chunk-OUUP3WKT.mjs +2 -0
- package/dist/chunk-OW5NWPOJ.mjs +10 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-POQSE4C2.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/{chunk-Z52HTUW7.mjs → chunk-PVER7LSC.mjs} +2 -2
- package/dist/chunk-PZDLJJTJ.mjs +3 -0
- package/dist/chunk-Q47PLKIJ.mjs +15 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QKXMPUXC.mjs +2 -0
- package/dist/chunk-QOUEFUCH.mjs +16 -0
- package/dist/chunk-RFDZXFJF.mjs +13 -0
- package/dist/chunk-RKPWLGZ3.mjs +4 -0
- package/dist/chunk-RMECZA2K.mjs +2 -0
- package/dist/{chunk-EUX7IC5J.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SX4LJYT6.mjs +8 -0
- package/dist/chunk-SXHBYZST.mjs +16 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TEZAWDSQ.mjs +2 -0
- package/dist/chunk-UBBRTJ2R.mjs +24 -0
- package/dist/chunk-UFNYFFKO.mjs +20 -0
- package/dist/chunk-UGWYKHBL.mjs +170 -0
- package/dist/chunk-UKSHDZZ6.mjs +2 -0
- package/dist/chunk-UMHUSOPJ.mjs +2 -0
- package/dist/chunk-UNOYVIYR.mjs +2 -0
- package/dist/chunk-V6RIYQZZ.mjs +4 -0
- package/dist/chunk-VJPFVNNW.mjs +15 -0
- package/dist/chunk-VS3ZMVGX.mjs +5 -0
- package/dist/chunk-VTKNEYT3.mjs +6 -0
- package/dist/chunk-VXACTLO3.mjs +3 -0
- package/dist/chunk-W3BGBJQW.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YQGT4AB2.mjs +6 -0
- package/dist/chunk-ZB4H7ZN4.mjs +2 -0
- package/dist/{chunk-ACOPDCNB.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZUNVAXLH.mjs +2 -0
- package/dist/chunk-ZWPMCK7P.mjs +2 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-EVJ3BX3M.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +14 -14
- package/kit/math.js +18 -2
- package/kit/report.css +500 -151
- package/kit/runtime.js +1720 -170
- package/kit/state.js +10 -1
- package/kit/tables.js +172 -37
- package/kit/ui.js +166 -27
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +156 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +130 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +295 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +246 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +351 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +201 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +102 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +76 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +238 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +158 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +138 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +166 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +151 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +185 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +120 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +342 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +267 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +312 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +258 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/release.json +13 -11
- package/sdk/doc-kit.d.ts +404 -7
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +71 -26
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/example-report.html +1 -1
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +221 -0
- package/skill/references/writing-html.md +9 -7
- package/skill/sdk/doc-kit.d.ts +404 -7
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BK2e_07w.js +13 -0
- package/web/assets/index-CWFI83mF.css +1 -0
- package/web/index.html +2 -2
- package/browser/editor/components/callout/page.mjs +0 -13
- package/dist/chunk-2PBALTR3.mjs +0 -57
- package/dist/chunk-3LA3EMDE.mjs +0 -15
- package/dist/chunk-5FRMCDPY.mjs +0 -16
- package/dist/chunk-5LEK2CBS.mjs +0 -2
- package/dist/chunk-5OFN5AHC.mjs +0 -2
- package/dist/chunk-5SIYS5HN.mjs +0 -2
- package/dist/chunk-5TEK3RAD.mjs +0 -2
- package/dist/chunk-6CYG3Z4V.mjs +0 -2
- package/dist/chunk-7GHT2UCA.mjs +0 -15
- package/dist/chunk-7QQBR7PB.mjs +0 -2
- package/dist/chunk-ATCJYAR4.mjs +0 -2
- package/dist/chunk-C7HWOBIF.mjs +0 -2
- package/dist/chunk-E7VYDG2X.mjs +0 -2
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FQGQH4KM.mjs +0 -2
- package/dist/chunk-G7TOXONE.mjs +0 -6
- package/dist/chunk-GPF4YWWB.mjs +0 -9
- package/dist/chunk-GYQV7Y4J.mjs +0 -120
- package/dist/chunk-HMHK3EQ6.mjs +0 -2
- package/dist/chunk-HQQMJCQJ.mjs +0 -10
- package/dist/chunk-IERUOGC3.mjs +0 -6
- package/dist/chunk-ITNLYXXV.mjs +0 -3
- package/dist/chunk-L4DVONOG.mjs +0 -2
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LC7YNQFG.mjs +0 -2
- package/dist/chunk-LHTFLRB6.mjs +0 -4
- package/dist/chunk-NFIBI4IP.mjs +0 -26
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O52JMOCZ.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-QMQUXTU4.mjs +0 -12
- package/dist/chunk-QVWVFC5K.mjs +0 -6
- package/dist/chunk-QYKCJ7FG.mjs +0 -8
- package/dist/chunk-QZY6Q64C.mjs +0 -2
- package/dist/chunk-TDQP3DKQ.mjs +0 -10
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-UNUEWH4S.mjs +0 -2
- package/dist/chunk-V4CPWKMZ.mjs +0 -2
- package/dist/chunk-VACRB2NE.mjs +0 -3
- package/dist/chunk-W63L7367.mjs +0 -7
- package/dist/chunk-W7CXPCRV.mjs +0 -6
- package/dist/chunk-XINNG4F2.mjs +0 -4
- package/dist/chunk-YL2DPWVS.mjs +0 -4
- package/dist/chunk-YZ5Z6H4W.mjs +0 -4
- package/dist/chunk-ZBIM6ARY.mjs +0 -216
- package/skill/references/building-components.md +0 -327
- package/web/assets/index-B6Ai3wsa.js +0 -13
- package/web/assets/index-SYPC3EZy.css +0 -1
|
@@ -29,11 +29,13 @@ import { unpack } from "./sync-state.mjs";
|
|
|
29
29
|
// (settled) and the reader pauses, the page reloads to show it, where the reader was
|
|
30
30
|
// (reloadView). Only when that write put texts the reader committed back as they were (an Agent
|
|
31
31
|
// writing the whole file from what it read earlier) does the page ask first: it keeps the texts it
|
|
32
|
-
// committed (commits.committed(), and those of its earlier loads
|
|
33
|
-
// made and moved this load (commits.placedUnits()) and what its
|
|
34
|
-
// those of earlier loads too), and the server says which the
|
|
35
|
-
// /__gallery/edit/reverted): a text as it was, a block it made gone, a
|
|
36
|
-
// it was in, a part as before a write of the page's.
|
|
32
|
+
// committed (commits.committed(), and those of its earlier loads: the journal), the blocks it
|
|
33
|
+
// made and moved this load (commits.placedUnits(), and those earlier loads made) and what its
|
|
34
|
+
// components wrote (commits.written(), those of earlier loads too), and the server says which the
|
|
35
|
+
// file now has as before (POST /__gallery/edit/reverted): a text as it was, a block it made gone, a
|
|
36
|
+
// block it moved back in the unit it was in, a part as before a write of the page's. A page going away
|
|
37
|
+
// keeps all of it in localStorage (journalKey) with the version of the file it last knew; the next
|
|
38
|
+
// page of the document, in this tab or another, opening on another version, asks at once.
|
|
37
39
|
|
|
38
40
|
const IDLE = 1600;
|
|
39
41
|
const LONGEST = 8000;
|
|
@@ -41,13 +43,45 @@ const RETRY = [1000, 2000, 5000, 10000, 30000];
|
|
|
41
43
|
const QUIET = 1500; // how long the reader has changed nothing before the page reloads by itself
|
|
42
44
|
const STORE_EVERY = 1000; // the crash buffer while typing, at most this often
|
|
43
45
|
const JOURNAL_FOR = 60 * 60 * 1000; // how long a committed text is checked for being put back
|
|
46
|
+
const JOURNAL_SIZE = 100_000; // the most characters one document's journal keeps (the newest entries)
|
|
44
47
|
const OWN_FOR = 5000; // how long the live-reload channel may still announce a version this page wrote
|
|
48
|
+
// A page of the Agent's own (its address's ?agent: the Agent 自用 one gallery open prints, gallery
|
|
49
|
+
// component try's): its commits say so (`agent`), and are no reader's edit to the review of the
|
|
50
|
+
// Agent's changes, so none ends a document's first writing (docs/editor.md "Agent's changes").
|
|
51
|
+
const AGENT_PAGE = typeof location !== "undefined" && new URLSearchParams(location.search).has("agent");
|
|
45
52
|
|
|
46
53
|
// A committed text as the revert check names it, whichever load named it: the report's title, a block of
|
|
47
54
|
// a unit by the unit's id (or what named the unit, with none) and its place in it, any other by what
|
|
48
55
|
// names it but the words it had.
|
|
49
56
|
const sameText = (block) => JSON.stringify(block?.title ? "title" : block?.unit ? [block.unit.id ?? block.unit.blockId ?? [block.unit.key, block.unit.open], block.self ? true : block.path ?? null] : { ...block, before: undefined });
|
|
50
57
|
|
|
58
|
+
// The journal's texts (journal()) with those of commits not answered yet (`requests`: on their way, or
|
|
59
|
+
// the crash buffer's) taken as committed, as committedText (commit.mjs) takes a commit's: what each
|
|
60
|
+
// replaced first stays where the text started, what it was between is `earlier`, and one back as it
|
|
61
|
+
// was first and nothing between is none; committed now (`at`).
|
|
62
|
+
function folded(texts, requests) {
|
|
63
|
+
const named = new Map(texts.map((entry) => [sameText(entry.block), entry]));
|
|
64
|
+
let serial = 0;
|
|
65
|
+
for (const request of requests) {
|
|
66
|
+
for (const text of request?.texts ?? []) {
|
|
67
|
+
const mine = text?.parts?.find((part) => part.keep)?.html;
|
|
68
|
+
if (typeof mine !== "string" || !text.block) continue;
|
|
69
|
+
const name = sameText(text.block);
|
|
70
|
+
const was = named.get(name);
|
|
71
|
+
const original = was?.original ?? text.block.before;
|
|
72
|
+
if (typeof original !== "string" || (was && was.mine === mine)) continue;
|
|
73
|
+
const earlier = [...new Set([...(was?.earlier ?? []), ...(was ? [was.mine] : [])])].filter((each) => each !== mine && each !== original).slice(-TEXTS_KEPT);
|
|
74
|
+
if (mine === original && earlier.length === 0) {
|
|
75
|
+
named.delete(name);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const entry = { key: was?.key ?? `f${serial++}`, block: { ...text.block, before: mine }, original, mine, ...(earlier.length > 0 ? { earlier } : {}), ...(was?.time ? { time: was.time } : {}), at: Date.now() };
|
|
79
|
+
named.set(name, entry);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return [...named.values()];
|
|
83
|
+
}
|
|
84
|
+
|
|
51
85
|
/**
|
|
52
86
|
* map: the page's map (slug, version, token); commits: createCommits(); blocked(): commits wait
|
|
53
87
|
* (an input method is composing); changedAt(): when the reader last changed anything; holding(asked):
|
|
@@ -58,14 +92,14 @@ const sameText = (block) => JSON.stringify(block?.title ? "title" : block?.unit
|
|
|
58
92
|
* warn("storage"): the crash buffer could not be written; storage: localStorage
|
|
59
93
|
* (get/set/remove/keys); tab(): this tab's id (a duplicated tab takes a new one); notice(): what the
|
|
60
94
|
* page says after it reloads by itself (a merge it just made), or null; session: sessionStorage
|
|
61
|
-
* (get/
|
|
95
|
+
* (get/remove), read once for the journal an earlier Gallery kept there; reverted(entries): texts, blocks and components' writes of the reader's that
|
|
62
96
|
* someone else's write put back, for the reader to decide on (decide) before the page shows that
|
|
63
97
|
* write (a component's with `written`: the parts, by name, and the hashes the file holds of them);
|
|
64
|
-
* before(): called right
|
|
98
|
+
* listed(): words were added to what the page could not put back (lostKey), to be shown; before(): called right
|
|
65
99
|
* before a commit goes, a promise it waits for (or null): what goes with the edit elsewhere is told
|
|
66
100
|
* first (where the words of the reader's 批注 went: annotate/ sync).
|
|
67
101
|
*/
|
|
68
|
-
export function createAutosave({ map, commits, blocked, changedAt, holding = () => false, refresh, applied, failed, warn = () => {}, storage, tab, notice = () => null, session = null, reverted = () => {}, before = () => null }) {
|
|
102
|
+
export function createAutosave({ map, commits, blocked, changedAt, holding = () => false, refresh, applied, failed, warn = () => {}, storage, tab, notice = () => null, session = null, reverted = () => {}, listed = () => {}, before = () => null }) {
|
|
69
103
|
let known = map.version; // the file's version as the page last knew it
|
|
70
104
|
// Versions this page's commits wrote (and the one it opened on), in order, and when: the
|
|
71
105
|
// live-reload channel announces them too, a little later, in the order they were written. Only
|
|
@@ -96,17 +130,39 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
96
130
|
let unstored = false; // the crash buffer could not be written
|
|
97
131
|
let storedFrom = null; // what the page held (collect()'s result) when the buffer was last written with nothing on its way; null: write it anew
|
|
98
132
|
const events = []; // [version, when]: what the live-reload channel announced while a commit was on its way
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
|
|
133
|
+
// What earlier pages of the document committed, made and wrote (the journal, journalKey: what each
|
|
134
|
+
// page kept as it went away, by tab), taken by this one as its own: the texts, still checked for an
|
|
135
|
+
// hour, each under a key of its own (`c<n>`: an earlier load's keys name its blocks, as this one's
|
|
136
|
+
// name others); the blocks they made (`m<n>`: by the file's id, with their words), until the file is
|
|
137
|
+
// found without one (listed) or the page no longer shows one it was found with (the reader deleted
|
|
138
|
+
// it); what their components wrote, the commits' own again (carry), by instance. This tab's are taken
|
|
139
|
+
// as the page is made, those of tabs no longer open once it knows which are (opened).
|
|
103
140
|
let carried = [];
|
|
141
|
+
let carriedMade = [];
|
|
142
|
+
let textSerial = 0;
|
|
143
|
+
let madeSerial = 0;
|
|
144
|
+
// The version of the file the page last knew: every write up to it the page's own or asked of (the
|
|
145
|
+
// revert check answered about it, what it put back held for the reader). What the page keeps as it
|
|
146
|
+
// goes away says it; null while a question about what earlier pages kept is not answered yet.
|
|
147
|
+
let seen = map.version;
|
|
148
|
+
let asking = false; // what earlier pages kept, taken, is to be asked of (the file not the version they last knew)
|
|
149
|
+
const adopt = (departures) => {
|
|
150
|
+
let ask = false;
|
|
151
|
+
for (const { known, entries } of departures) {
|
|
152
|
+
if (known !== map.version) ask = true;
|
|
153
|
+
carried.push(...entries.filter((entry) => entry.instance === undefined && entry.made === undefined && entry.block).map((entry) => ({ ...entry, key: `c${textSerial++}` })));
|
|
154
|
+
carriedMade.push(...entries.filter((entry) => typeof entry.made === "string" && !carriedMade.some((other) => other.id === entry.made))
|
|
155
|
+
.map(({ made, parent, text, time }) => ({ key: `m${madeSerial++}`, id: made, parent: parent ?? null, text: String(text ?? ""), time, confirmed: known === map.version })));
|
|
156
|
+
commits.carry(entries.filter((entry) => entry.instance !== undefined).map(({ instance, parts, time }) => ({ id: instance, parts, time })));
|
|
157
|
+
}
|
|
158
|
+
if (ask) {
|
|
159
|
+
asking = true;
|
|
160
|
+
seen = null;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
104
163
|
try {
|
|
105
|
-
|
|
106
|
-
carried = kept.filter((entry) => entry.instance === undefined).map((entry, index) => ({ ...entry, key: `c${index}` }));
|
|
107
|
-
commits.carry(kept.filter((entry) => entry.instance !== undefined).map(({ instance, parts, time }) => ({ id: instance, parts, time })));
|
|
164
|
+
adopt([...legacyJournal(session, map.slug), ...takeJournal(storage, map.slug, (id) => id === tab())]);
|
|
108
165
|
} catch {}
|
|
109
|
-
session?.remove(journalKey);
|
|
110
166
|
const reverts = new Map(); // key -> entry: put back by someone else, waiting for the reader
|
|
111
167
|
let checking = false;
|
|
112
168
|
const waiters = [];
|
|
@@ -227,8 +283,11 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
227
283
|
retryAt = 0;
|
|
228
284
|
offline = false;
|
|
229
285
|
known = receipt.version;
|
|
286
|
+
// Written over the version the page last knew, no one else's write between: the page knows this one.
|
|
287
|
+
if (!receipt.foreign && seen !== null && sent.request.known === seen) seen = receipt.version;
|
|
230
288
|
if (receipt.wrote !== false) own.push({ version: receipt.version, at: Date.now() }); // one that changed nothing wrote no version
|
|
231
289
|
if (receipt.foreign) foreign = true;
|
|
290
|
+
deleted(sent.request, receipt);
|
|
232
291
|
applied(commits.apply(sent.pending, receipt, { alone: !foreign }), receipt);
|
|
233
292
|
after = commits.collect();
|
|
234
293
|
recount(after);
|
|
@@ -335,7 +394,7 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
335
394
|
if (closed) return;
|
|
336
395
|
leaving = true;
|
|
337
396
|
store();
|
|
338
|
-
keepJournal();
|
|
397
|
+
keepJournal([flight?.request ?? parked?.request, buffer]); // what is on its way or in the buffer, as the file is to have it
|
|
339
398
|
if (flight || parked || stopped || waiting() === 0 || !buffer) return; // what is on its way is in the buffer
|
|
340
399
|
postCommit(map, buffer, { keepalive: true }).catch(() => {});
|
|
341
400
|
}
|
|
@@ -347,6 +406,8 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
347
406
|
*/
|
|
348
407
|
function heard(version, anyway = false, at = Date.now()) {
|
|
349
408
|
if (closed) return;
|
|
409
|
+
// A write the reader asked for is on its way (showOwn): what is heard meanwhile is its own, or heard again once it failed.
|
|
410
|
+
if (owning) return void (missed = true);
|
|
350
411
|
// It may be the commit on its way, or one whose answer was lost: known once that one is answered
|
|
351
412
|
// (as of when it was announced).
|
|
352
413
|
if ((flight || parked) && !anyway) return void events.push([version, at]);
|
|
@@ -386,20 +447,45 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
386
447
|
}
|
|
387
448
|
const texts = journal();
|
|
388
449
|
const units = commits.placedUnits();
|
|
450
|
+
// The blocks earlier pages made: those the file was not yet found with, and those the page shows (one
|
|
451
|
+
// found with it and no longer shown, the reader deleted).
|
|
452
|
+
const made = carriedMade.filter((entry) => !entry.confirmed || commits.unitOf(entry.id) !== null);
|
|
389
453
|
const instances = commits.written();
|
|
390
|
-
if (texts.length === 0 && units.length === 0 && instances.length === 0) return true;
|
|
454
|
+
if (texts.length === 0 && units.length === 0 && made.length === 0 && instances.length === 0) return true;
|
|
391
455
|
checking = true;
|
|
392
456
|
let answer = null;
|
|
393
457
|
try {
|
|
394
|
-
const response = await postJson("/__gallery/edit/reverted", map.token, { slug: map.slug, opening: map.version, texts: texts.map(({ key, block, original, earlier }) => ({ key, block, original, ...(earlier ? { earlier } : {}) })), units, instances: instances.map(({ key, id, parts }) => ({ key, id, parts })), pageIds: commits.pageIds() });
|
|
458
|
+
const response = await postJson("/__gallery/edit/reverted", map.token, { slug: map.slug, opening: map.version, texts: texts.map(({ key, block, original, earlier }) => ({ key, block, original, ...(earlier ? { earlier } : {}) })), units: [...units, ...made.map(({ key, id, parent }) => ({ key, id, parent }))], instances: instances.map(({ key, id, parts }) => ({ key, id, parts })), pageIds: commits.pageIds() });
|
|
395
459
|
answer = await response.json();
|
|
396
460
|
} catch {}
|
|
397
461
|
checking = false;
|
|
398
462
|
if (closed) return false;
|
|
463
|
+
if (answer?.ok) {
|
|
464
|
+
// A block an earlier page made that the file no longer has is no block of this load's to hold a
|
|
465
|
+
// card for: its words are listed (lostKey), as what a page could not put back is; the others are
|
|
466
|
+
// found with the file, asked of while the page shows them.
|
|
467
|
+
const gone = made.filter(({ key }) => (answer.units ?? []).some((entry) => entry.key === key && entry.gone));
|
|
468
|
+
// One made inside another gone (a quote's paragraph, a list's item) went with it, its words among that one's.
|
|
469
|
+
const goneIds = new Set(gone.map(({ id }) => id));
|
|
470
|
+
const words = gone.filter(({ text, parent }) => text && !goneIds.has(parent)).map(({ text }) => ({ why: "reverted", text }));
|
|
471
|
+
const kept = words.length === 0 || keepLost(storage, map.slug, words);
|
|
472
|
+
if (kept) carriedMade = carriedMade.filter((entry) => !gone.includes(entry)); // asked again otherwise
|
|
473
|
+
for (const entry of made) if (!gone.includes(entry)) entry.confirmed = true;
|
|
474
|
+
if (kept && words.length > 0) listed();
|
|
475
|
+
// All of it asked of (no question waits to be asked again, which may carry more): the page knows the
|
|
476
|
+
// file as it was answered about.
|
|
477
|
+
if (kept && !recheck) {
|
|
478
|
+
seen = answer.version ?? null;
|
|
479
|
+
asking = false;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
// Of the blocks it made that the write took out, those inside another such go with it, one card.
|
|
483
|
+
const goneUnits = (answer?.units ?? []).filter(({ gone, key }) => gone && !made.some((entry) => entry.key === key)).map(({ key }) => key);
|
|
399
484
|
const back = answer?.ok ? [
|
|
400
485
|
...answer.reverted.map(({ key, theirs }) => ({ ...texts.find((entry) => entry.key === key), theirs })).filter((entry) => entry.key),
|
|
401
|
-
// A block put back: by its unit, with what it holds (the reader's words, to copy)
|
|
402
|
-
|
|
486
|
+
// A block put back: by its unit, with what it holds (the reader's words, to copy) and, taken out, the
|
|
487
|
+
// blocks taken out inside it (`within`, decided with it; what it holds that the file still has is not).
|
|
488
|
+
...(answer.units ?? []).filter(({ key, gone }) => units.some((unit) => unit.key === key) && !(gone && commits.heldWithin?.(key, goneUnits))).map(({ key, gone }) => ({ key: `p${key}`, unit: key, gone: Boolean(gone), mine: commits.unitText(key), ...(gone ? { within: goneUnits.filter((inner) => commits.heldWithin?.(inner, [key])) } : {}) })),
|
|
403
489
|
// Parts a component wrote put back: by its unit, with the hashes the file holds of them (`written`)
|
|
404
490
|
// and what the page holds of them (`data`, the reader's, kept with the crash buffer); none the page
|
|
405
491
|
// holds as the file does, however the file spells it (heldOtherwise).
|
|
@@ -448,19 +534,22 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
448
534
|
storage.remove(bufferKey());
|
|
449
535
|
storage.remove(keptKey());
|
|
450
536
|
storedFrom = null; // written anew if anything stores after all
|
|
451
|
-
keepJournal();
|
|
537
|
+
keepJournal(); // a write landing after that answer and before the page shown again is served is asked of there (opened)
|
|
452
538
|
refresh();
|
|
453
539
|
reloadView(map.slug, null, notice());
|
|
454
540
|
}
|
|
455
541
|
|
|
456
|
-
// The texts committed, this load's and earlier ones', one of each block (sameText): what
|
|
457
|
-
//
|
|
458
|
-
// between (two of one block are no one question: the
|
|
459
|
-
// was first, it is asked of what it was between.
|
|
542
|
+
// The texts committed, this load's and earlier ones', one of each block (sameText): what was committed
|
|
543
|
+
// of a block before (`at`, when it was last committed: two tabs' pages are taken in no order of their
|
|
544
|
+
// own) is where that text started, and what it was between (two of one block are no one question: the
|
|
545
|
+
// server's answer would name neither); back as it was first, it is asked of what it was between. Joined
|
|
546
|
+
// with one of this load's, it goes by that one's key and naming (decide lets this load's go by its key).
|
|
460
547
|
const journal = () => {
|
|
461
548
|
const now = commits.committed().map((entry) => ({ ...entry, time: Date.now() }));
|
|
549
|
+
const own = new Set(now.map((entry) => entry.key));
|
|
462
550
|
const texts = new Map();
|
|
463
|
-
|
|
551
|
+
const when = (entry) => entry.at ?? entry.time ?? 0;
|
|
552
|
+
for (const entry of [...carried, ...now].sort((a, b) => when(a) - when(b))) {
|
|
464
553
|
const name = sameText(entry.block);
|
|
465
554
|
const was = texts.get(name);
|
|
466
555
|
if (!was) {
|
|
@@ -468,7 +557,8 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
468
557
|
continue;
|
|
469
558
|
}
|
|
470
559
|
const earlier = [...new Set([...(was.earlier ?? []), was.mine, entry.original, ...(entry.earlier ?? [])])].filter((text) => text !== entry.mine && text !== was.original).slice(-TEXTS_KEPT);
|
|
471
|
-
const
|
|
560
|
+
const named = own.has(was.key) && !own.has(entry.key) ? { key: was.key, block: { ...was.block, before: entry.mine } } : {};
|
|
561
|
+
const joined = { ...entry, ...named, original: was.original, earlier, time: Math.max(was.time ?? 0, entry.time ?? 0) || undefined };
|
|
472
562
|
if (earlier.length === 0) delete joined.earlier;
|
|
473
563
|
if (entry.mine === was.original && earlier.length === 0) texts.delete(name);
|
|
474
564
|
else texts.set(name, joined);
|
|
@@ -476,16 +566,73 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
476
566
|
return [...texts.values()];
|
|
477
567
|
};
|
|
478
568
|
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
function
|
|
483
|
-
const
|
|
484
|
-
|
|
569
|
+
// A commit of the page's that the file took deleted blocks (`request`'s removals, answered `receipt`): of
|
|
570
|
+
// the blocks earlier pages made, those (and those made inside them) are the reader's own deletion, asked
|
|
571
|
+
// of by no page any more: this one's, and those kept by pages of tabs gone that no page took yet.
|
|
572
|
+
function deleted(request, receipt) {
|
|
573
|
+
const ids = (request.units ?? []).filter((op) => op.remove && !(receipt.units ?? []).some((answer) => answer.key === op.key && answer.status === "conflict"))
|
|
574
|
+
.flatMap((op) => [op.unit?.id, ...(op.items ?? []).map((item) => item?.id)]).filter((id) => typeof id === "string");
|
|
575
|
+
if (ids.length === 0) return;
|
|
576
|
+
const gone = madeWithin(ids, carriedMade.map(({ id, parent }) => ({ id, parent })));
|
|
577
|
+
carriedMade = carriedMade.filter((entry) => !gone.has(entry.id));
|
|
578
|
+
try {
|
|
579
|
+
forgetMade(storage, map.slug, ids);
|
|
580
|
+
} catch {}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// What the page committed (journal()), made (its blocks the file has, by their ids, with their words:
|
|
584
|
+
// this load's and those of earlier loads it still shows or has not found the file with yet) and what
|
|
585
|
+
// its components wrote (commits.written()), kept in the journal under this tab with the version of the
|
|
586
|
+
// file it last knew (`known`, null when it does not), for the next page of the document, in this tab
|
|
587
|
+
// or another, which takes them as its own, and asks of them at once if it opens on another version
|
|
588
|
+
// (opened): when the page goes to show the file again, when it goes away (a reload of the reader's,
|
|
589
|
+
// another document opened, the tab closed) and after a write the reader asked for (showOwn). `pending`:
|
|
590
|
+
// commits not answered yet (on their way, or the crash buffer's, which the next page sends), whose
|
|
591
|
+
// texts are taken as committed, the reader's own words (an undo back to what an earlier commit
|
|
592
|
+
// replaced) being no one else's write.
|
|
593
|
+
function keepJournal(pending = []) {
|
|
594
|
+
const time = Date.now();
|
|
595
|
+
const made = new Map();
|
|
596
|
+
for (const { key, id, parent, from } of commits.placedUnits()) if (from === undefined && !reverts.has(`p${key}`)) made.set(id, { made: id, parent, text: commits.unitText(key), time });
|
|
597
|
+
for (const entry of carriedMade) {
|
|
598
|
+
const unit = commits.unitOf(entry.id);
|
|
599
|
+
if (made.has(entry.id) || (entry.confirmed && unit === null)) continue;
|
|
600
|
+
made.set(entry.id, { made: entry.id, parent: entry.parent, text: (unit !== null && commits.unitText(unit)) || entry.text, time: entry.time ?? time });
|
|
601
|
+
}
|
|
602
|
+
const entries = [
|
|
603
|
+
...folded(journal(), pending.filter(Boolean)).map((entry) => ({ ...entry, time: entry.time ?? time })),
|
|
485
604
|
...commits.written().map(({ id, parts, time }) => ({ instance: id, parts, time })),
|
|
605
|
+
...made.values(),
|
|
486
606
|
];
|
|
487
|
-
|
|
488
|
-
|
|
607
|
+
try {
|
|
608
|
+
keepDeparture(storage, map.slug, tab(), entries.length > 0 ? { known: seen, time, entries } : null);
|
|
609
|
+
} catch {}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* The page opened and edits, the workbench told it is ready (`open`: the ids of the tabs that answered
|
|
614
|
+
* they show the document now). What pages of tabs no longer open kept is taken too (the document
|
|
615
|
+
* opened again in another tab), and where this page opened on another version of the file than an
|
|
616
|
+
* earlier page last knew (someone else's write landing while no page was there to hear of it, or
|
|
617
|
+
* between the last question of a page showing the file again and this page being served, which it
|
|
618
|
+
* never hears of as a write), all it took is asked of at once (checkReverted): a text put back is a
|
|
619
|
+
* card, a block made that the file no longer has is listed. On the very version, nothing is asked.
|
|
620
|
+
* A page done with, or going to be shown again (it kept its journal already), takes nothing: the next
|
|
621
|
+
* page does; one whose write (showOwn) failed takes it then.
|
|
622
|
+
*/
|
|
623
|
+
let unopened = null; // opened()'s call while the page was to be shown again by showOwn: { open }
|
|
624
|
+
function opened(open = null) {
|
|
625
|
+
if (closed) return;
|
|
626
|
+
if (reloading) return void (unopened = { open });
|
|
627
|
+
if (open) {
|
|
628
|
+
try {
|
|
629
|
+
adopt(takeJournal(storage, map.slug, (id) => id !== tab() && !open.has(id)));
|
|
630
|
+
} catch {}
|
|
631
|
+
forgetOld(storage);
|
|
632
|
+
}
|
|
633
|
+
if (!asking) return;
|
|
634
|
+
if (checking) recheck = true;
|
|
635
|
+
else checkReverted();
|
|
489
636
|
}
|
|
490
637
|
|
|
491
638
|
/**
|
|
@@ -499,7 +646,7 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
499
646
|
// A block put back: kept (made again, or moved again where the page has it), or the file's. Parts a
|
|
500
647
|
// component wrote: written again over the file's (its hashes of them), or the file's.
|
|
501
648
|
if (entry.written) commits.rewrite(entry.unit, entry.written, mine);
|
|
502
|
-
else commits.putBack(entry.unit, { gone: entry.gone, mine });
|
|
649
|
+
else commits.putBack(entry.unit, { gone: entry.gone, mine, within: entry.within });
|
|
503
650
|
reverts.delete(key);
|
|
504
651
|
storedFrom = null;
|
|
505
652
|
if (mine) changed(true);
|
|
@@ -523,6 +670,54 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
523
670
|
return true;
|
|
524
671
|
}
|
|
525
672
|
|
|
673
|
+
/**
|
|
674
|
+
* A write the reader asked for that changes the file (撤回 of the Agent's changes and its 撤销:
|
|
675
|
+
* changes/): `run()` makes it, resolving with whether it did (the version it wrote, when known); then the page shows the file as after a
|
|
676
|
+
* write of its own, at once, asking nothing of what it put back (the revert check: the reader asked
|
|
677
|
+
* for it), and what is heard meanwhile shows nothing first. The caller saved what waited first
|
|
678
|
+
* (flush) and made sure nothing waits for the reader. Resolves with whether the page goes.
|
|
679
|
+
*/
|
|
680
|
+
let owning = false; // showOwn's write is on its way
|
|
681
|
+
let missed = false; // and the live-reload channel spoke meanwhile
|
|
682
|
+
async function showOwn(run) {
|
|
683
|
+
if (closed || reloading) return false;
|
|
684
|
+
reloading = owning = true;
|
|
685
|
+
missed = false;
|
|
686
|
+
clearTimeout(reloadTimer);
|
|
687
|
+
let done = false;
|
|
688
|
+
let wrote = null; // the version its write left, when run() says
|
|
689
|
+
try {
|
|
690
|
+
const result = await run();
|
|
691
|
+
done = Boolean(result);
|
|
692
|
+
if (typeof result === "string") wrote = result;
|
|
693
|
+
} catch {}
|
|
694
|
+
owning = false;
|
|
695
|
+
if (closed) return done;
|
|
696
|
+
if (!done) {
|
|
697
|
+
reloading = false;
|
|
698
|
+
refresh();
|
|
699
|
+
if (unopened) {
|
|
700
|
+
const { open } = unopened;
|
|
701
|
+
unopened = null;
|
|
702
|
+
opened(open);
|
|
703
|
+
}
|
|
704
|
+
if (missed) heard(null, true);
|
|
705
|
+
else if (foreign) maybeReload();
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
storage.remove(bufferKey());
|
|
709
|
+
storage.remove(keptKey());
|
|
710
|
+
storedFrom = null;
|
|
711
|
+
// The page knew the file it asked to be written as; a write landing before the page shown again is
|
|
712
|
+
// served is asked of there. Not told which version that is, or with a question of its own not answered
|
|
713
|
+
// yet, the next page asks whatever it opens on.
|
|
714
|
+
seen = asking ? null : wrote;
|
|
715
|
+
keepJournal();
|
|
716
|
+
refresh();
|
|
717
|
+
reloadView(map.slug, null, null);
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
|
|
526
721
|
/** Show the file as it is once nothing waits (the reader gave a change up for the file's, or what the page is made of changed). */
|
|
527
722
|
function reloadSoon() {
|
|
528
723
|
foreign = true;
|
|
@@ -552,10 +747,12 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
552
747
|
changed,
|
|
553
748
|
flush,
|
|
554
749
|
leave,
|
|
750
|
+
opened,
|
|
555
751
|
heard,
|
|
556
752
|
store,
|
|
557
753
|
decide,
|
|
558
754
|
reloadSoon,
|
|
755
|
+
showOwn,
|
|
559
756
|
close,
|
|
560
757
|
get state() {
|
|
561
758
|
return { waiting: waiting(), syncing: Boolean(flight), offline, stopped, foreign, reloading, held: commits.issues.size + reverts.size, drafts, unstored };
|
|
@@ -566,7 +763,7 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
|
|
|
566
763
|
// A commit sent: the server's answer, or { ok: false, reason: "server" } when it failed or answered
|
|
567
764
|
// no JSON (a lost connection rejects: the caller reads that as offline).
|
|
568
765
|
async function postCommit(map, request, { keepalive = false } = {}) {
|
|
569
|
-
const response = await postJson("/__gallery/edit/commit", map.token, { slug: map.slug, ...request }, { keepalive });
|
|
766
|
+
const response = await postJson("/__gallery/edit/commit", map.token, { slug: map.slug, ...request, ...(AGENT_PAGE ? { agent: true } : {}) }, { keepalive });
|
|
570
767
|
if (response.status >= 500) return { ok: false, reason: "server" };
|
|
571
768
|
return response.json().catch(() => ({ ok: false, reason: "server" }));
|
|
572
769
|
}
|
|
@@ -646,6 +843,128 @@ function keepLost(storage, slug, items) {
|
|
|
646
843
|
return storage.set(lostKey(slug), JSON.stringify([...readLost(storage, slug), ...items.map((item) => ({ ...item, time }))].slice(-100))) !== false;
|
|
647
844
|
}
|
|
648
845
|
|
|
846
|
+
/**
|
|
847
|
+
* Where the pages of a document keep, as they go away, what they committed, made and wrote, for the
|
|
848
|
+
* next page of it to ask of (createAutosave: keepJournal, opened), in localStorage: { v: 1, tabs: {
|
|
849
|
+
* <tab>: { known, time, entries } } }, one departure a tab, `known` the version of the file that page
|
|
850
|
+
* last knew (null: it did not), each entry with its `time`: a text ({ key, block, original, mine,
|
|
851
|
+
* earlier?, at }, `at` when it was last committed), a block made ({ made, parent, text }; taken out of
|
|
852
|
+
* every departure once a page's commit deletes it: forgetMade) or what a component wrote ({ instance, parts }).
|
|
853
|
+
* Entries are kept for JOURNAL_FOR, the newest of them JOURNAL_SIZE characters at most.
|
|
854
|
+
*/
|
|
855
|
+
export const journalKey = (slug) => `gallery-edit:${slug}:journal`;
|
|
856
|
+
const JOURNAL_KEY = /^gallery-edit:(.+):journal$/;
|
|
857
|
+
|
|
858
|
+
// The departures the journal holds, by tab, their entries still asked of (none left: no departure).
|
|
859
|
+
function readJournal(storage, slug) {
|
|
860
|
+
let record = null;
|
|
861
|
+
try {
|
|
862
|
+
record = JSON.parse(storage.get(journalKey(slug)) ?? "null");
|
|
863
|
+
} catch {}
|
|
864
|
+
const tabs = {};
|
|
865
|
+
const now = Date.now();
|
|
866
|
+
for (const [tab, departure] of Object.entries(record?.tabs && typeof record.tabs === "object" ? record.tabs : {})) {
|
|
867
|
+
const entries = (Array.isArray(departure?.entries) ? departure.entries : []).filter((entry) => entry && typeof entry === "object" && now - entry.time < JOURNAL_FOR);
|
|
868
|
+
if (entries.length > 0) tabs[tab] = { known: typeof departure.known === "string" ? departure.known : null, time: departure.time, entries };
|
|
869
|
+
}
|
|
870
|
+
return tabs;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// The journal written as `tabs`, the newest entries first as long as they fit (one too long left out),
|
|
874
|
+
// or taken away when nothing is left. A write that fails leaves it as it was: the crash buffer comes first.
|
|
875
|
+
function writeJournal(storage, slug, tabs) {
|
|
876
|
+
const all = Object.entries(tabs).flatMap(([tab, departure]) => departure.entries.map((entry) => ({ tab, entry, size: JSON.stringify(entry).length })))
|
|
877
|
+
.sort((a, b) => b.entry.time - a.entry.time);
|
|
878
|
+
let room = JOURNAL_SIZE;
|
|
879
|
+
const fits = new Set();
|
|
880
|
+
for (const { entry, size } of all) {
|
|
881
|
+
if (size > room) continue;
|
|
882
|
+
room -= size;
|
|
883
|
+
fits.add(entry);
|
|
884
|
+
}
|
|
885
|
+
const kept = {};
|
|
886
|
+
for (const [tab, departure] of Object.entries(tabs)) {
|
|
887
|
+
const entries = departure.entries.filter((entry) => fits.has(entry));
|
|
888
|
+
if (entries.length > 0) kept[tab] = { ...departure, entries };
|
|
889
|
+
}
|
|
890
|
+
if (Object.keys(kept).length === 0) return void storage.remove(journalKey(slug));
|
|
891
|
+
const text = JSON.stringify({ v: 1, tabs: kept });
|
|
892
|
+
if (storage.get(journalKey(slug)) !== text) storage.set(journalKey(slug), text);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// The departures of the tabs `which` picks, taken out of the journal: [{ known, entries }].
|
|
896
|
+
function takeJournal(storage, slug, which) {
|
|
897
|
+
const tabs = readJournal(storage, slug);
|
|
898
|
+
const taken = Object.keys(tabs).filter(which);
|
|
899
|
+
if (taken.length === 0) return [];
|
|
900
|
+
const departures = taken.map((tab) => tabs[tab]);
|
|
901
|
+
for (const tab of taken) delete tabs[tab];
|
|
902
|
+
writeJournal(storage, slug, tabs);
|
|
903
|
+
return departures;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// The ids of `ids` and of the blocks made (`made`: [{ id, parent }]) inside one of them, at any depth.
|
|
907
|
+
function madeWithin(ids, made) {
|
|
908
|
+
const gone = new Set(ids);
|
|
909
|
+
for (let more = true; more;) {
|
|
910
|
+
more = false;
|
|
911
|
+
for (const { id, parent } of made) {
|
|
912
|
+
if (gone.has(id) || !gone.has(parent)) continue;
|
|
913
|
+
gone.add(id);
|
|
914
|
+
more = true;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
return gone;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// The blocks made that the reader deleted (`ids`, and those made inside them) taken out of every
|
|
921
|
+
// departure the journal holds.
|
|
922
|
+
function forgetMade(storage, slug, ids) {
|
|
923
|
+
const tabs = readJournal(storage, slug);
|
|
924
|
+
let changed = false;
|
|
925
|
+
for (const departure of Object.values(tabs)) {
|
|
926
|
+
const gone = madeWithin(ids, departure.entries.filter((entry) => typeof entry.made === "string").map(({ made, parent }) => ({ id: made, parent })));
|
|
927
|
+
const entries = departure.entries.filter((entry) => typeof entry.made !== "string" || !gone.has(entry.made));
|
|
928
|
+
if (entries.length === departure.entries.length) continue;
|
|
929
|
+
departure.entries = entries;
|
|
930
|
+
changed = true;
|
|
931
|
+
}
|
|
932
|
+
if (changed) writeJournal(storage, slug, tabs);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// This tab's departure written (null: none), beside the other tabs'.
|
|
936
|
+
function keepDeparture(storage, slug, tab, departure) {
|
|
937
|
+
const tabs = readJournal(storage, slug);
|
|
938
|
+
if (departure) tabs[tab] = departure;
|
|
939
|
+
else if (tabs[tab]) delete tabs[tab];
|
|
940
|
+
else if (storage.get(journalKey(slug)) === null) return;
|
|
941
|
+
writeJournal(storage, slug, tabs);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// What a Gallery before 2026-11-08 kept for the next load in the tab (sessionStorage, under the same
|
|
945
|
+
// key): its entries, or { asked, entries }, read once as this tab's departure, the version it last knew
|
|
946
|
+
// that `asked` (none of "own" or nothing: not known).
|
|
947
|
+
function legacyJournal(session, slug) {
|
|
948
|
+
if (!session) return [];
|
|
949
|
+
let stored = null;
|
|
950
|
+
try {
|
|
951
|
+
stored = JSON.parse(session.get(journalKey(slug)) ?? "null");
|
|
952
|
+
} catch {}
|
|
953
|
+
session.remove(journalKey(slug));
|
|
954
|
+
const entries = (Array.isArray(stored) ? stored : Array.isArray(stored?.entries) ? stored.entries : []).filter((entry) => entry && typeof entry === "object" && Date.now() - entry.time < JOURNAL_FOR);
|
|
955
|
+
const known = !Array.isArray(stored) && typeof stored?.asked === "string" && stored.asked !== "own" ? stored.asked : null;
|
|
956
|
+
return entries.length > 0 ? [{ known, entries }] : [];
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// The journals of documents whose every entry is older than JOURNAL_FOR, taken away (a document not
|
|
960
|
+
// opened again within the hour leaves none behind).
|
|
961
|
+
function forgetOld(storage) {
|
|
962
|
+
for (const key of storage.keys?.() ?? []) {
|
|
963
|
+
const slug = JOURNAL_KEY.exec(key)?.[1];
|
|
964
|
+
if (slug && Object.keys(readJournal(storage, slug)).length === 0) storage.remove(key);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
649
968
|
/**
|
|
650
969
|
* Reload the page to show the file as it is now, keeping where the reader was (`view`, or now):
|
|
651
970
|
* the scroll position, the block the caret was in (by its data-block-id) with the caret's offset in
|
|
@@ -6,16 +6,16 @@ import { isHost } from "./core.mjs";
|
|
|
6
6
|
// (selection/).
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Whether a click to the right of a block
|
|
10
|
-
*
|
|
11
|
-
* and the boxes text flows in (a list, a quote, a
|
|
9
|
+
* Whether a click to the right of a block, past the text area it stands in (insert/ boxedBeside),
|
|
10
|
+
* selects it: a boxed block (a code block, a highlight block, a disclosure, a card, a table, a
|
|
11
|
+
* divider…) or a row of columns, as opposed to text and the boxes text flows in (a list, a quote, a
|
|
12
|
+
* section).
|
|
12
13
|
*/
|
|
13
14
|
export const selectsBeside = (unit) => BESIDE.has(unit?.getAttribute?.("data-ge-unit-kind"));
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Whether Enter on a block selected (the first of those selected) puts a new paragraph after them
|
|
17
18
|
* (blocks.mjs, insert.paragraphAfter): a block of no text of its own, those a click to their right
|
|
18
|
-
* selects and a 选项卡区块; not a text block among them (a
|
|
19
|
-
* block, whose editor it opens).
|
|
19
|
+
* selects and a 选项卡区块; not a text block among them (a formula block, whose editor it opens).
|
|
20
20
|
*/
|
|
21
21
|
export const entersAfter = (unit) => Boolean(unit) && !isHost(unit) && ENTERS_AFTER.has(unit.getAttribute("data-ge-unit-kind"));
|
|
@@ -12,7 +12,7 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
12
12
|
// show one of the nine with none of a family (a callout's background is blue: `defaults`), that
|
|
13
13
|
// family has no 默认: that color is ringed for none, and picking it takes the class away. Each
|
|
14
14
|
// swatch names its color in a tooltip. The swatches are drawn with the kit's own classes, so they
|
|
15
|
-
// match the text in either theme. A pick gives every target that color of its family, the other family's staying (one
|
|
15
|
+
// match the text in either theme, a background's as the block's fill (`--doc-fill`). A pick gives every target that color of its family, the other family's staying (one
|
|
16
16
|
// undo step: look, history.mjs; a table cell's one color: table/). Only the families the targets take show.
|
|
17
17
|
|
|
18
18
|
const STYLE = `
|
|
@@ -21,6 +21,8 @@ const STYLE = `
|
|
|
21
21
|
.ge-pop .ge-color-cell > span { display: flex; align-items: center; justify-content: center; box-sizing: border-box; width: 26px; height: 26px; border-radius: 6px;
|
|
22
22
|
font-size: 16px; font-weight: 500; line-height: 1; box-shadow: inset 0 0 0 1px var(--ge-ring); }
|
|
23
23
|
.ge-pop .ge-color-cell > span:not([class*="doc-text-"]) { color: var(--ge-tx); }
|
|
24
|
+
/* A block's background swatch shows the block's fill, not the words' deeper one the kit gives a span. */
|
|
25
|
+
.ge-pop .ge-color-cell > span[class*="doc-highlight-"] { background: var(--doc-fill); }
|
|
24
26
|
.ge-pop .ge-color-cell:hover > span, .ge-pop .ge-color-cell[data-active] > span { box-shadow: inset 0 0 0 2px var(--ge-ring); }
|
|
25
27
|
.ge-pop .ge-color-cell[aria-current="true"] > span { box-shadow: inset 0 0 0 2px var(--ge-ring-strong); }
|
|
26
28
|
${Object.entries(RINGS).map(([name, [light, dark, strong, strongDark]]) => `.ge-pop .ge-color-cell[data-ring="${name}"] { --ge-ring: light-dark(${light}, ${dark}); --ge-ring-strong: light-dark(${strong}, ${strongDark}); }`).join("\n ")}
|
|
@@ -54,7 +54,7 @@ const WIDTH = MENU_WIDTH; // the menu, as wide as its grid (no room left beside
|
|
|
54
54
|
* color rows). copyLink(target): the block's address on the clipboard, in the click on its row; null
|
|
55
55
|
* on a page no address leads to; linkAhead(): the menu opens with that row, what the click will want is read now.
|
|
56
56
|
*/
|
|
57
|
-
export function createBlockMenu({ info, menu, selection, remove, turnInto, convert, turnIntoAll = () => null, convertAll = () => {}, below, belowTypes = () => [], add, look, copyLink = () => {}, linkAhead = () => {} }) {
|
|
57
|
+
export function createBlockMenu({ info, menu, selection, remove, takenWith = (units) => units, turnInto, convert, turnIntoAll = () => null, convertAll = () => {}, below, belowTypes = () => [], add, look, copyLink = () => {}, linkAhead = () => {} }) {
|
|
58
58
|
const chapters = sectionOps();
|
|
59
59
|
const columns = columnOps();
|
|
60
60
|
const { kindOf, nameOf, keepText, boxKindOf } = info;
|
|
@@ -95,12 +95,13 @@ export function createBlockMenu({ info, menu, selection, remove, turnInto, conve
|
|
|
95
95
|
// where it is. What it holds comes out as it stands, so a block in a column keeps its column, the row
|
|
96
96
|
// of columns coming out whole, and one in a section in a Sheet panel ends in the panel. None for a
|
|
97
97
|
// block that has no 分区与分栏 › of its own (no columns row, in a section: a list item, a flowchart's
|
|
98
|
-
// node, a quote's later paragraph, a block an item holds)
|
|
98
|
+
// node, a quote's later paragraph, a block an item holds): asked of the block alone (a folded heading
|
|
99
|
+
// whose section a column cannot take keeps it).
|
|
99
100
|
const dissolveRow = (units) => {
|
|
100
101
|
const section = chapters?.dissolvesFrom(units[0]);
|
|
101
102
|
if (!section || units.some((unit) => chapters.dissolvesFrom(unit) !== section)) return [];
|
|
102
103
|
const own = units[0] === section;
|
|
103
|
-
if (!own && units.some((unit) => (columns?.columnsCheck([unit]) ?? null) === null)) return [];
|
|
104
|
+
if (!own && units.some((unit) => (columns?.columnsCheck([unit], (alone) => [alone]) ?? null) === null)) return [];
|
|
104
105
|
const reason = chapters.unwrapCheck(section);
|
|
105
106
|
return [{ label: own ? t("解散分区") : t("解散所在分区"), icon: ICONS.dissolve, disabled: Boolean(reason), note: reason || undefined, run: () => chapters.unwrap(section, own ? null : units) }];
|
|
106
107
|
};
|
|
@@ -149,8 +150,9 @@ export function createBlockMenu({ info, menu, selection, remove, turnInto, conve
|
|
|
149
150
|
const colors = colorRow(group);
|
|
150
151
|
items.push(...colors, ...(colors.length > 0 ? [{ separator: true }] : []));
|
|
151
152
|
// Blocks next to each other in the page or a Sheet panel become a section; a selection with gaps does not.
|
|
152
|
-
|
|
153
|
-
const
|
|
153
|
+
// A folded heading among them goes in with what it hides (fold/).
|
|
154
|
+
const wrap = chapters?.wrapCheck(takenWith(group)) ?? null;
|
|
155
|
+
const sections = [...(wrap !== null ? [{ label: t("组成新分区"), icon: ICONS.group, disabled: Boolean(wrap), note: wrap || undefined, run: () => chapters.wrap(takenWith(group)) }] : []), ...dissolveRow(group)];
|
|
154
156
|
// Neighbours in one container go side by side, a column each.
|
|
155
157
|
items.push(...groupRow(sections, splitRows(group)));
|
|
156
158
|
items.push({ label: t("删除"), icon: ICONS.trash, hint: "Del", disabled: Boolean(refused), note, run: () => remove(group) });
|
|
@@ -193,7 +195,7 @@ export function createBlockMenu({ info, menu, selection, remove, turnInto, conve
|
|
|
193
195
|
}
|
|
194
196
|
const sections = [];
|
|
195
197
|
if (chapter(target)) sections.push({ label: t("在下方新建分区"), icon: ICONS.section, run: () => add(target, "section") });
|
|
196
|
-
if (chapters?.wrapCheck([target]) === "") sections.push({ label: t("组成新分区"), icon: ICONS.group, run: () => chapters.wrap([target]) });
|
|
198
|
+
if (chapters?.wrapCheck(takenWith([target])) === "") sections.push({ label: t("组成新分区"), icon: ICONS.group, run: () => chapters.wrap(takenWith([target])) });
|
|
197
199
|
sections.push(...dissolveRow([target]));
|
|
198
200
|
const splits = splitRows([target]);
|
|
199
201
|
// 选中外层 joins 分区与分栏 › where the block has that submenu; a block with none gets none for it.
|