@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
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { UPLOAD_LIMITS, mediaUrl, sizeLimit } from "../../../shared/media.mjs";
|
|
2
|
+
import { cellPicture, pictureFile } from "../../components/table/index.mjs";
|
|
3
|
+
import { ownHTML } from "../core.mjs";
|
|
4
|
+
import { gestureLock } from "../gesture.mjs";
|
|
5
|
+
import { drawAt, drawBox, layerOf } from "../overlay-layer.mjs";
|
|
6
|
+
import { onSettle, own } from "../overlays.mjs";
|
|
7
|
+
import { blobBase64 } from "../post.mjs";
|
|
8
|
+
import { addStyle, element } from "../ui.mjs";
|
|
9
|
+
import { t } from "../../../shared/i18n/index.mjs";
|
|
10
|
+
|
|
11
|
+
// 单元格里的图片 (the user's, 2026-11-09: no image block, a light one; Markdown tables hold pictures):
|
|
12
|
+
// an <img> amid a table cell's words, a picture of the document's folder (components/table/ cellPicture; the
|
|
13
|
+
// file takes it as source/blocks.mjs cellPictureProblem says, the kit lays it out: table.css). notion-
|
|
14
|
+
// lite has none; this is the plainest that works, flat:
|
|
15
|
+
// - A press on one selects it (the selection around it, a 2px blue frame over it, no caret): Delete
|
|
16
|
+
// or Backspace then takes it out, a typed character takes its place, Esc puts the caret after it;
|
|
17
|
+
// the arrows go past it as past a character (the browser's: an <img> in an editable text is one).
|
|
18
|
+
// - A gray bar at its right edge (the image block's handle) under the pointer or while it is
|
|
19
|
+
// selected: dragged, the picture's width in pixels (its height by its ratio), at least MIN_WIDTH,
|
|
20
|
+
// at most its table's frame, written as its width attribute; one undo step on letting go, Esc
|
|
21
|
+
// putting it back.
|
|
22
|
+
// - Where pictures come from (clipboard/, table/cells.mjs): a picture file pasted into a cell (a
|
|
23
|
+
// screenshot, a copied picture) sent to the document's folder as an image block's (fromFiles); the
|
|
24
|
+
// pictures of cells pasted (another program's table, a Markdown table, the page's own cells of
|
|
25
|
+
// another document) each made a file of the folder first (resolve: one of the folder as it is,
|
|
26
|
+
// another document's, a data: one and a web one copied in, the server downloading a web one as it
|
|
27
|
+
// does an image block's link), then put in by what pastedLines makes of each (maker): a picture of
|
|
28
|
+
// no file a link to it (a web one) or its alt words.
|
|
29
|
+
|
|
30
|
+
const MIN_WIDTH = 16;
|
|
31
|
+
const MAX_PICTURES = 50; // the pictures a paste copies in at most (each a download)
|
|
32
|
+
const WIDTH = /^[1-9]\d{0,3}$/;
|
|
33
|
+
const WEB = /^https?:\/\/[^\s"<>]+$/i;
|
|
34
|
+
const DATA = /^data:image\/[a-z0-9.+-]+;base64,/i;
|
|
35
|
+
// A file of a document's folder as the preview serves it (a copy of the page's HTML), or as a cell's text writes it.
|
|
36
|
+
const SERVED = /^(?:https?:\/\/[^/]+)?\/__gallery\/edit\/asset\/([^/?#]+)\/(assets\/[^/?#]+)$/;
|
|
37
|
+
const FOLDER_FILE = /^assets\/[A-Za-z0-9][A-Za-z0-9._-]{0,80}$/;
|
|
38
|
+
const CELL = '[data-ge-kind="cell"]';
|
|
39
|
+
// The name of a picture's file in its address (its last part, its escapes read).
|
|
40
|
+
const nameOf = (src) => {
|
|
41
|
+
const name = src.split(/[?#]/)[0].split("/").pop() || src;
|
|
42
|
+
try {
|
|
43
|
+
return decodeURIComponent(name);
|
|
44
|
+
} catch {
|
|
45
|
+
return name;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const STYLE = `
|
|
50
|
+
[data-ge-editing] ${CELL}[contenteditable="true"] img { cursor: default; }
|
|
51
|
+
.ge-layer > .ge-cellpic-handle { pointer-events: auto; }
|
|
52
|
+
.ge-cellpic-frame { box-sizing: border-box; border: 2px solid var(--ge-accent); border-radius: 2px; pointer-events: none; }
|
|
53
|
+
/* The image block's handle (image/page.mjs): a plain gray bar, no border. */
|
|
54
|
+
.ge-cellpic-handle { display: flex; align-items: center; justify-content: center; width: 12px; cursor: col-resize; }
|
|
55
|
+
.ge-cellpic-handle::after { content: ""; width: 4px; height: 32px; max-height: 70%; border-radius: 4px; background: light-dark(rgb(55 53 47 / 35%), rgb(255 255 255 / 38%)); transition: background 120ms ease; }
|
|
56
|
+
.ge-cellpic-handle:hover::after, html[data-ge-cellpic-resize] .ge-cellpic-handle::after { background: light-dark(rgb(55 53 47 / 60%), rgb(255 255 255 / 62%)); }
|
|
57
|
+
${gestureLock("data-ge-cellpic-resize", { cursor: "col-resize" })}
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
// The report this page shows (its main's data-doc-id: its folder's name).
|
|
61
|
+
const thisReport = () => document.querySelector(".doc-page")?.dataset.docId ?? null;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* active(): whether the tools may act. recordStep(host, before): a text step of a text block
|
|
65
|
+
* (history.mjs). say: the status line. upload(kind, body): POST /__gallery/edit/upload, the server's
|
|
66
|
+
* answer (an Error when it fails).
|
|
67
|
+
*/
|
|
68
|
+
export function createCellPictures({ active, recordStep, say, upload }) {
|
|
69
|
+
addStyle(STYLE);
|
|
70
|
+
let hovered = null; // the picture under the pointer
|
|
71
|
+
let picked = null; // the picture selected
|
|
72
|
+
let drag = null; // its edge dragged: { img, host, x, start, before, had }
|
|
73
|
+
const frame = element("div", { class: "ge-cellpic-frame", "data-doc-dev": "" });
|
|
74
|
+
const handle = element("div", { class: "ge-cellpic-handle", "data-doc-dev": "" });
|
|
75
|
+
// The picture they are drawn for: the frame the selected one's (or the dragged one's), the bar any of them.
|
|
76
|
+
const framed = () => drag?.img ?? picked;
|
|
77
|
+
const barred = () => drag?.img ?? picked ?? hovered;
|
|
78
|
+
own(frame, "cell picture", { alive: () => Boolean(framed()?.isConnected) });
|
|
79
|
+
own(handle, "cell picture", { alive: () => Boolean(barred()?.isConnected) });
|
|
80
|
+
// The cell of the picture drawn for, watched: a picture taken out (Delete, undo, someone else's
|
|
81
|
+
// words merged) takes them away at once, before the page draws again.
|
|
82
|
+
const watch = new MutationObserver(() => {
|
|
83
|
+
if (!barred()?.isConnected) draw();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// A picture of a cell the reader writes in, and that cell; or null.
|
|
87
|
+
const pictureAt = (node) => {
|
|
88
|
+
const img = node?.closest?.("img");
|
|
89
|
+
const host = img?.closest(CELL);
|
|
90
|
+
return img && host?.getAttribute("contenteditable") === "true" && host.closest("main") && !host.closest("[data-ge-lock], [inert]") && pictureFile(img) ? { img, host } : null;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
function draw() {
|
|
94
|
+
if (picked && !picked.isConnected) picked = null;
|
|
95
|
+
if (hovered && !hovered.isConnected) hovered = null;
|
|
96
|
+
const img = barred();
|
|
97
|
+
watch.disconnect();
|
|
98
|
+
if (!img?.isConnected || !active()) {
|
|
99
|
+
frame.remove();
|
|
100
|
+
handle.remove();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
watch.observe(img.closest(CELL) ?? img.parentNode, { childList: true, subtree: true });
|
|
104
|
+
const layer = layerOf(img);
|
|
105
|
+
const rect = img.getBoundingClientRect();
|
|
106
|
+
if (img === framed()) drawBox(frame, layer, rect);
|
|
107
|
+
else frame.remove();
|
|
108
|
+
const origin = layer.getBoundingClientRect();
|
|
109
|
+
handle.style.height = `${Math.max(20, Math.round(rect.height))}px`;
|
|
110
|
+
drawAt(handle, layer, rect.right - origin.left - 2, rect.top - origin.top + Math.min(0, (rect.height - 20) / 2));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Whether the selection is the picture alone (a press on it, or the browser's own).
|
|
114
|
+
const around = (img) => {
|
|
115
|
+
const selection = getSelection();
|
|
116
|
+
if (!selection.rangeCount || !img.parentNode) return false;
|
|
117
|
+
const range = selection.getRangeAt(0);
|
|
118
|
+
const at = [...img.parentNode.childNodes].indexOf(img);
|
|
119
|
+
return range.startContainer === img.parentNode && range.endContainer === img.parentNode && range.startOffset === at && range.endOffset === at + 1;
|
|
120
|
+
};
|
|
121
|
+
function pick({ img, host }) {
|
|
122
|
+
if (document.activeElement !== host) host.focus({ preventScroll: true });
|
|
123
|
+
const range = document.createRange();
|
|
124
|
+
range.selectNode(img);
|
|
125
|
+
getSelection().removeAllRanges();
|
|
126
|
+
getSelection().addRange(range);
|
|
127
|
+
picked = img;
|
|
128
|
+
draw();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ---------- the pointer ----------
|
|
132
|
+
|
|
133
|
+
document.addEventListener("pointermove", (event) => {
|
|
134
|
+
if (drag) return;
|
|
135
|
+
const at = pictureAt(event.target);
|
|
136
|
+
const next = at ? at.img : event.target === handle ? hovered : null;
|
|
137
|
+
if (next !== hovered) {
|
|
138
|
+
hovered = next;
|
|
139
|
+
draw();
|
|
140
|
+
}
|
|
141
|
+
}, { passive: true });
|
|
142
|
+
// A press on a picture selects it, before the cells' tools (a drag between cells) and the caret hear it.
|
|
143
|
+
window.addEventListener("pointerdown", (event) => {
|
|
144
|
+
const at = event.button === 0 && active() ? pictureAt(event.target) : null;
|
|
145
|
+
if (!at) return;
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
event.stopImmediatePropagation();
|
|
148
|
+
pick(at);
|
|
149
|
+
}, true);
|
|
150
|
+
window.addEventListener("mousedown", (event) => {
|
|
151
|
+
if (event.button === 0 && active() && (pictureAt(event.target) || event.target === handle)) event.preventDefault(); // no caret, no drag of the picture
|
|
152
|
+
}, true);
|
|
153
|
+
document.addEventListener("selectionchange", () => {
|
|
154
|
+
if (picked && !(picked.isConnected && around(picked))) {
|
|
155
|
+
picked = null;
|
|
156
|
+
draw();
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
document.addEventListener("keydown", (event) => {
|
|
160
|
+
if (event.key !== "Escape" || event.isComposing) return;
|
|
161
|
+
if (drag) return void (event.preventDefault(), event.stopImmediatePropagation(), end(false));
|
|
162
|
+
if (!picked || !around(picked)) return;
|
|
163
|
+
event.preventDefault();
|
|
164
|
+
event.stopImmediatePropagation();
|
|
165
|
+
const range = document.createRange();
|
|
166
|
+
range.setStartAfter(picked);
|
|
167
|
+
range.collapse(true);
|
|
168
|
+
getSelection().removeAllRanges();
|
|
169
|
+
getSelection().addRange(range);
|
|
170
|
+
}, true);
|
|
171
|
+
for (const type of ["scroll", "resize"]) window.addEventListener(type, () => { if (drag || picked || hovered) draw(); }, { capture: true, passive: true });
|
|
172
|
+
onSettle(draw);
|
|
173
|
+
|
|
174
|
+
// ---------- its width ----------
|
|
175
|
+
|
|
176
|
+
handle.addEventListener("pointerdown", (event) => {
|
|
177
|
+
const img = picked ?? hovered;
|
|
178
|
+
const host = img?.closest(CELL);
|
|
179
|
+
if (event.button !== 0 || !host || !active()) return;
|
|
180
|
+
event.preventDefault();
|
|
181
|
+
event.stopPropagation();
|
|
182
|
+
handle.setPointerCapture(event.pointerId);
|
|
183
|
+
drag = { img, host, x: event.clientX, start: img.getBoundingClientRect().width, before: ownHTML(host), had: img.getAttribute("width") };
|
|
184
|
+
document.documentElement.setAttribute("data-ge-cellpic-resize", "");
|
|
185
|
+
});
|
|
186
|
+
handle.addEventListener("pointermove", (event) => {
|
|
187
|
+
if (!drag) return;
|
|
188
|
+
const room = drag.host.closest(".doc-table-wrap")?.clientWidth || 2000; // never wider than its table's frame
|
|
189
|
+
drag.img.setAttribute("width", String(Math.round(Math.max(MIN_WIDTH, Math.min(room, drag.start + event.clientX - drag.x)))));
|
|
190
|
+
draw();
|
|
191
|
+
});
|
|
192
|
+
function end(keep) {
|
|
193
|
+
if (!drag) return;
|
|
194
|
+
const { img, host, before, had } = drag;
|
|
195
|
+
drag = null;
|
|
196
|
+
document.documentElement.removeAttribute("data-ge-cellpic-resize");
|
|
197
|
+
if (!keep) {
|
|
198
|
+
if (had === null) img.removeAttribute("width");
|
|
199
|
+
else img.setAttribute("width", had);
|
|
200
|
+
} else if (img.getAttribute("width") !== had) recordStep(host, before);
|
|
201
|
+
draw();
|
|
202
|
+
}
|
|
203
|
+
handle.addEventListener("pointerup", () => end(true));
|
|
204
|
+
handle.addEventListener("pointercancel", () => end(false));
|
|
205
|
+
|
|
206
|
+
// ---------- pictures pasted ----------
|
|
207
|
+
|
|
208
|
+
const sent = async (blob, name) => (await upload("image", { name, type: blob.type, data: await blobBase64(blob) })).path;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Picture files pasted into a cell (a screenshot, a copied picture), each sent to the document's
|
|
212
|
+
* folder as an image block's (10 MB at most): the cell's pictures, in order, those that could not
|
|
213
|
+
* go said.
|
|
214
|
+
*/
|
|
215
|
+
async function fromFiles(files) {
|
|
216
|
+
const pictures = [...files].filter((file) => /^image\//.test(file.type));
|
|
217
|
+
if (pictures.some((file) => file.size > UPLOAD_LIMITS.image)) say(t("图片太大(最多 {0})。", sizeLimit("image")), "error");
|
|
218
|
+
const made = await Promise.all(pictures.filter((file) => file.size <= UPLOAD_LIMITS.image).map(async (file) => {
|
|
219
|
+
try {
|
|
220
|
+
return cellPicture(document, await sent(file, file.name || `image.${file.type.split("/")[1] ?? "png"}`), { alt: "" });
|
|
221
|
+
} catch (error) {
|
|
222
|
+
say(t("{0}:{1}", t("无法上传这张图片"), error.message), "error");
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}));
|
|
226
|
+
return made.filter(Boolean);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// A pasted picture's address as a file of this document's folder ({ path }), or null.
|
|
230
|
+
async function fileOf(src, from, here) {
|
|
231
|
+
const served = SERVED.exec(src);
|
|
232
|
+
const [report, file] = served ? [decodeURIComponent(served[1]), served[2]] : FOLDER_FILE.test(src) ? [from ?? here, src] : [null, null];
|
|
233
|
+
if (file && report === here) return { path: file };
|
|
234
|
+
const copied = async (address, name) => {
|
|
235
|
+
const response = await fetch(address);
|
|
236
|
+
const blob = response.ok ? await response.blob() : null;
|
|
237
|
+
return blob && /^image\//.test(blob.type) && blob.size <= UPLOAD_LIMITS.image ? { path: await sent(blob, name) } : null;
|
|
238
|
+
};
|
|
239
|
+
if (file && report) return copied(mediaUrl("asset", encodeURIComponent(report), file), file.slice("assets/".length));
|
|
240
|
+
if (DATA.test(src)) return copied(src, "image");
|
|
241
|
+
if (WEB.test(src)) return { path: (await upload("image", { url: src })).path };
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The pictures of pasted cells (`htmls`: their inline HTML) as files of this document's folder: a
|
|
247
|
+
* Map of each address to { path } (assets/<file>), or null where none could be had. `from`: the
|
|
248
|
+
* report the page's own cells came from (their assets/ that report's).
|
|
249
|
+
*/
|
|
250
|
+
async function resolve(htmls, from = null) {
|
|
251
|
+
const addresses = new Set();
|
|
252
|
+
const template = document.createElement("template");
|
|
253
|
+
for (const html of htmls) {
|
|
254
|
+
if (!html.includes("<img")) continue;
|
|
255
|
+
template.innerHTML = html;
|
|
256
|
+
for (const img of template.content.querySelectorAll("img[src]")) addresses.add(img.getAttribute("src"));
|
|
257
|
+
}
|
|
258
|
+
const found = new Map();
|
|
259
|
+
if (addresses.size === 0) return found;
|
|
260
|
+
const here = thisReport();
|
|
261
|
+
const list = [...addresses];
|
|
262
|
+
if (list.some((src) => !(SERVED.exec(src)?.[1] === here || (FOLDER_FILE.test(src) && (from ?? here) === here)))) say(t("正在下载…"));
|
|
263
|
+
await Promise.all(list.slice(0, MAX_PICTURES).map(async (src) => found.set(src, await fileOf(src, from, here).catch(() => null))));
|
|
264
|
+
return found;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* What pastedLines makes of a pasted picture (`found`: resolve's answer): the cell's picture, its
|
|
269
|
+
* alt and width kept; else a web one a link to it (`links`), any other its alt words (undefined:
|
|
270
|
+
* an element that is no picture).
|
|
271
|
+
*/
|
|
272
|
+
const maker = (found, links = true) => (img) => {
|
|
273
|
+
if (img.localName !== "img") return undefined;
|
|
274
|
+
const src = img.getAttribute("src") ?? "";
|
|
275
|
+
const alt = img.getAttribute("alt") ?? "";
|
|
276
|
+
const width = img.getAttribute("width") ?? "";
|
|
277
|
+
const file = found.get(src);
|
|
278
|
+
if (file) return cellPicture(document, file.path, { alt, width: WIDTH.test(width) ? Number(width) : null });
|
|
279
|
+
if (links && WEB.test(src)) {
|
|
280
|
+
const link = document.createElement("a");
|
|
281
|
+
link.setAttribute("href", src);
|
|
282
|
+
link.textContent = alt || nameOf(src);
|
|
283
|
+
return link;
|
|
284
|
+
}
|
|
285
|
+
return alt ? document.createTextNode(alt) : null;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
fromFiles, resolve, maker,
|
|
290
|
+
/** The tools' nodes (kept in the top layer with a modal dialog). */
|
|
291
|
+
get nodes() { return [frame, handle].filter((node) => node.isConnected); },
|
|
292
|
+
/** Take them away (the page stops editing). */
|
|
293
|
+
hide() {
|
|
294
|
+
hovered = picked = null;
|
|
295
|
+
if (drag) end(false);
|
|
296
|
+
draw();
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { TABLE } from "../../components/kit.mjs";
|
|
2
|
+
import { insertRow, moveRow, removeRows, tableState } from "../../components/table/page.mjs";
|
|
3
|
+
import { tableOf } from "../../components/table/grid.mjs";
|
|
4
|
+
import { ownHTML } from "../core.mjs";
|
|
5
|
+
import { menuEntry, viewKeys } from "../page-objects.mjs";
|
|
6
|
+
import { CHART_SOURCE, TABLE_READERS, VIEW_FROM, nextChartKey } from "../../../shared/table-chart.mjs";
|
|
7
|
+
import { t } from "../../../shared/i18n/index.mjs";
|
|
8
|
+
import { TABLE_ICONS } from "./icons.mjs";
|
|
9
|
+
|
|
10
|
+
// The views of a table (docs/editor.md, "Table views"; the plan's 阶段 4): an instance of a custom
|
|
11
|
+
// block whose needs hold "tables", bound to a table of the document by the key its frame carries
|
|
12
|
+
// (shared/table-chart.mjs VIEW_FROM, the key a chart drawn from a table reads it by), reads the table's
|
|
13
|
+
// rows (the kit's context.table()) and changes them only by asking: a doc-table-intent the kit puts on
|
|
14
|
+
// the instance (runtime/kernel.js), which these tools answer at once, made as the table's own tools make
|
|
15
|
+
// a change, so that a view has no commit, undo or conflict of its own:
|
|
16
|
+
//
|
|
17
|
+
// set one cell's words: a text step of that cell (history.mjs recordStep), its commit a cell's text
|
|
18
|
+
// as typing's is, merged word by word with someone else's change of the cell (source/merge.mjs);
|
|
19
|
+
// move a row put before or after another, the cells it names set in the same step (a card dropped
|
|
20
|
+
// in another column: its status and its place);
|
|
21
|
+
// add a row put in after another or last, its cells' words those it names;
|
|
22
|
+
// remove a row taken out (never the last of the body, as the tools' 删除);
|
|
23
|
+
// check nothing: answered as the others would be (the kit's table().canEdit()), so that a view of a
|
|
24
|
+
// table these tools do not manage shows it read-only;
|
|
25
|
+
//
|
|
26
|
+
// move, add and remove are the table tools' operations (components/table/page.mjs moveRow, insertRow,
|
|
27
|
+
// removeRows) in one undo step each (index.mjs change), their commit the table's operation, which a
|
|
28
|
+
// change someone else made to the table meanwhile holds back as a conflict with its card, as any. Only a
|
|
29
|
+
// table these tools manage (GRID: written as the kit writes one) and with no merged cell takes them: a
|
|
30
|
+
// view of any other is read-only, as it is in an export (the kit asks nothing there). Its rows of data
|
|
31
|
+
// are those after its header row: the head's rows, or with no head its body's first row, which a view
|
|
32
|
+
// reads its columns' names from; no intent puts a row there or takes that one.
|
|
33
|
+
//
|
|
34
|
+
// 视图 › of a table's block menu (menuRow) lists the custom blocks that read tables and that the
|
|
35
|
+
// document's menus would offer (their `readsTables` row of the custom blocks' menu variants, which follows
|
|
36
|
+
// the 组件列表 switches; page-objects.mjs viewKeys: no other menu lists them, as one put in unbound only
|
|
37
|
+
// says it has no table) and puts one in right after the table bound to it, in one undo step: the table's key
|
|
38
|
+
// where it names this table (the first frame carrying it, as the kit and the checks read a key), or a new
|
|
39
|
+
// one (the first of t1, t2 … the page does not hold) put on its frame in that step (a table made from "/"
|
|
40
|
+
// has none; the second of two an Agent wrote with one key is not the one it names). The commit writes
|
|
41
|
+
// both, and the server makes sure of the key against the file (source/chart-keys.mjs relinkMade); a key
|
|
42
|
+
// it gives the pair anew the page follows, its undo steps too (page/commit.mjs apply, history.mjs rekeyed).
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* active(): whether the page edits now. change(unit, mutate, said, touched): the table tools' one undo
|
|
46
|
+
* step (index.mjs). tableAt(node): the table unit these tools manage that a node is in. recordStep(host,
|
|
47
|
+
* before): a text step of a text block (history.mjs). insertBelow(unit, key, { attributes, done }): a
|
|
48
|
+
* block of the menu's `key` put in below a block in one undo step, `attributes` ([element, names]) recorded
|
|
49
|
+
* with it and `done(made)` run in it on the new block (editor.mjs insertBelow). drawn(): the tools drawn
|
|
50
|
+
* again (a row taken out).
|
|
51
|
+
*/
|
|
52
|
+
export function createViews({ active, change, tableAt, recordStep, insertBelow, drawn = () => {} }) {
|
|
53
|
+
const merged = (rows) => rows.some((row) => [...row.cells].some((cell) => cell.rowSpan !== 1 || cell.colSpan !== 1));
|
|
54
|
+
const writable = (cell) => cell?.getAttribute("contenteditable") === "true";
|
|
55
|
+
const holds = (cell, text) => cell.textContent === text && cell.childElementCount === 0;
|
|
56
|
+
|
|
57
|
+
// What a view asks (`detail` of doc-table-intent: kernel.js tableView), made, or refused (false).
|
|
58
|
+
function run({ table, op, row = null, before = null, after = null, cells = [] }) {
|
|
59
|
+
if (!active() || !table?.isConnected) return false;
|
|
60
|
+
const unit = tableAt(table);
|
|
61
|
+
if (!unit || tableOf(unit) !== table) return false;
|
|
62
|
+
const state = tableState(unit);
|
|
63
|
+
if (merged(state.rows) || !Array.isArray(cells) || !cells.every(([column, text]) => Number.isInteger(column) && column >= 0 && column < state.columns && typeof text === "string")) return false;
|
|
64
|
+
// A view's table().canEdit(): whether an intent of this table would be taken now, nothing changed.
|
|
65
|
+
if (op === "check") return true;
|
|
66
|
+
// Its rows of data: after the header a view reads its names from (the head, else the body's first row).
|
|
67
|
+
const all = state.rows;
|
|
68
|
+
const data = all.slice(Math.max(1, state.head?.rows.length ?? 0));
|
|
69
|
+
const ofData = (node) => data.includes(node);
|
|
70
|
+
const cellsOf = (target) => cells.map(([column]) => target.cells[column]);
|
|
71
|
+
if (op === "set") {
|
|
72
|
+
if (!ofData(row) || cells.length !== 1) return false;
|
|
73
|
+
const [[column, text]] = cells;
|
|
74
|
+
const cell = row.cells[column];
|
|
75
|
+
if (!writable(cell)) return false;
|
|
76
|
+
if (holds(cell, text)) return true;
|
|
77
|
+
const was = ownHTML(cell);
|
|
78
|
+
cell.textContent = text;
|
|
79
|
+
recordStep(cell, was);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (op === "move") {
|
|
83
|
+
const target = before ?? after;
|
|
84
|
+
if (!ofData(row) || (target && !ofData(target)) || !cellsOf(row).every(writable)) return false;
|
|
85
|
+
const from = all.indexOf(row);
|
|
86
|
+
const rest = all.filter((node) => node !== row);
|
|
87
|
+
const to = !target || target === row ? from : before ? rest.indexOf(before) : rest.indexOf(after) + 1;
|
|
88
|
+
if (to === from && cells.every(([column, text]) => holds(row.cells[column], text))) return true;
|
|
89
|
+
return change(unit, () => {
|
|
90
|
+
if (to !== from && moveRow(unit, from, to) === false) return false;
|
|
91
|
+
for (const [column, text] of cells) row.cells[column].textContent = text;
|
|
92
|
+
return true;
|
|
93
|
+
}, null, cellsOf(row)) !== null;
|
|
94
|
+
}
|
|
95
|
+
if (op === "add") {
|
|
96
|
+
if (after && !ofData(after)) return false;
|
|
97
|
+
const at = after ? all.indexOf(after) + 1 : all.length;
|
|
98
|
+
return change(unit, () => {
|
|
99
|
+
const made = insertRow(unit, at);
|
|
100
|
+
for (const [column, text] of cells) if (made.cells[column]) made.cells[column].textContent = text;
|
|
101
|
+
return made;
|
|
102
|
+
}, null) !== null;
|
|
103
|
+
}
|
|
104
|
+
if (op === "remove") {
|
|
105
|
+
if (!ofData(row)) return false;
|
|
106
|
+
const at = all.indexOf(row);
|
|
107
|
+
const done = change(unit, () => removeRows(unit, at, at), null) !== null;
|
|
108
|
+
drawn();
|
|
109
|
+
return done;
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
document.addEventListener("doc-table-intent", (event) => {
|
|
114
|
+
if (run(event.detail ?? {})) event.preventDefault();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// The frame a key names, as the kit reads it (runtime/table-reading.js frameOf) and the checks do: the
|
|
118
|
+
// first that carries it, none of a dev block's.
|
|
119
|
+
const frameOf = (key) => [...document.querySelectorAll(`[${CHART_SOURCE}]`)].find((node) => node.getAttribute(CHART_SOURCE) === key && node.matches(TABLE.frame) && !node.closest("[data-doc-dev]")) ?? null;
|
|
120
|
+
// A view of the block `key` put in right after `unit`, bound to its table: by its key where that names
|
|
121
|
+
// it, else by a new one put on it in the same step (a table made from "/" has none; one of two an Agent
|
|
122
|
+
// wrote with one key is not the one it names, the first: a view by it would read and change that one).
|
|
123
|
+
function insertView(unit, key) {
|
|
124
|
+
const own = unit.getAttribute(CHART_SOURCE);
|
|
125
|
+
const taken = new Set([...document.querySelectorAll([CHART_SOURCE, ...TABLE_READERS].map((name) => `[${name}]`).join(", "))].flatMap((node) => [CHART_SOURCE, ...TABLE_READERS].map((name) => node.getAttribute(name)).filter((value) => value !== null)));
|
|
126
|
+
const bound = own !== null && frameOf(own) === unit ? own : nextChartKey(taken);
|
|
127
|
+
insertBelow(unit, key, {
|
|
128
|
+
attributes: [[unit, [CHART_SOURCE]]],
|
|
129
|
+
done(made) {
|
|
130
|
+
made?.setAttribute(VIEW_FROM, bound);
|
|
131
|
+
if (bound !== own) unit.setAttribute(CHART_SOURCE, bound);
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
/** The 视图 › row of a table's block menu: one for each custom block that reads tables, or null where there is none or the table cannot be read as rows (no frame, a merged cell). */
|
|
138
|
+
menuRow(unit) {
|
|
139
|
+
const keys = viewKeys();
|
|
140
|
+
if (keys.length === 0 || !unit.matches(TABLE.frame) || merged(tableState(unit).rows)) return null;
|
|
141
|
+
return {
|
|
142
|
+
label: t("视图"), icon: TABLE_ICONS.view,
|
|
143
|
+
submenu: () => viewKeys().map((key) => {
|
|
144
|
+
const row = menuEntry(key).variant;
|
|
145
|
+
return { label: row.label, icon: row.icon, run: () => insertView(unit, key) };
|
|
146
|
+
}),
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -2,6 +2,7 @@ import { SPAN } from "../../../shared/media.mjs";
|
|
|
2
2
|
import { COLUMN_WIDTH, MIN_COLUMN_WIDTH, widthOf } from "../../components/table/index.mjs";
|
|
3
3
|
import { relayout, tableParts, tableState } from "../../components/table/page.mjs";
|
|
4
4
|
import { widthHolder } from "../../../shared/table-slots.mjs";
|
|
5
|
+
import { GONE_WORDS } from "../core.mjs";
|
|
5
6
|
import { gestureLock } from "../gesture.mjs";
|
|
6
7
|
import { drawBox } from "../overlay-layer.mjs";
|
|
7
8
|
import { hideTooltip, tooltip } from "../tooltip.mjs";
|
|
@@ -15,7 +16,7 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
15
16
|
// index.mjs COLUMN_WIDTH; shared/table-slots.mjs widthHolder: a merged cell holds none), the kit laying the table
|
|
16
17
|
// out at them (tables/layout.js manualLayout); the first
|
|
17
18
|
// drag of a table the kit lays out gives every column the width it has then. A double click fits
|
|
18
|
-
// the column to its widest cell, unwrapped. The menus'
|
|
19
|
+
// the column to its widest cell, unwrapped. The menus' 自动调整列宽 takes the widths off (the kit's
|
|
19
20
|
// again) or gives each column its width as it is; 均分列宽 shares the columns' room out equally.
|
|
20
21
|
// Sizing columns takes the table's own width off (--doc-span: the table is as wide as its
|
|
21
22
|
// columns again).
|
|
@@ -114,18 +115,22 @@ export function createColumnWidths(tools) {
|
|
|
114
115
|
relayout(unit);
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
// A column fitted to its widest cell of it alone, unwrapped (+1px)
|
|
118
|
+
// A column fitted to its widest cell of it alone, unwrapped (+1px): by its words, not the words an
|
|
119
|
+
// Agent took out that the page shows in it (changes/: out of the layout while it is measured).
|
|
118
120
|
function fit(unit, index) {
|
|
119
121
|
const { slots } = tableState(unit);
|
|
120
122
|
const widest = Math.max(0, ...[...slots.places].filter(([, place]) => place.c === index && place.cols === 1).map(([cell]) => {
|
|
121
123
|
const style = getComputedStyle(cell);
|
|
122
124
|
const was = cell.style.whiteSpace;
|
|
125
|
+
const gone = [...cell.querySelectorAll(GONE_WORDS)];
|
|
126
|
+
for (const mark of gone) mark.hidden = true;
|
|
123
127
|
cell.style.whiteSpace = "nowrap";
|
|
124
128
|
const range = document.createRange();
|
|
125
129
|
range.selectNodeContents(cell);
|
|
126
130
|
const width = range.getBoundingClientRect().width + parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
|
|
127
131
|
cell.style.whiteSpace = was;
|
|
128
132
|
if (cell.getAttribute("style") === "") cell.removeAttribute("style");
|
|
133
|
+
for (const mark of gone) mark.hidden = false;
|
|
129
134
|
return width;
|
|
130
135
|
}));
|
|
131
136
|
const widths = shown(unit);
|
|
@@ -291,9 +296,9 @@ export function createColumnWidths(tools) {
|
|
|
291
296
|
/** The edges plain again (the tools no longer stand by the table). */
|
|
292
297
|
disarm() { armed = null; },
|
|
293
298
|
get dragging() { return drag !== null; },
|
|
294
|
-
/**
|
|
299
|
+
/** 自动调整列宽: the kit's widths, from the columns' words (the reader's taken off; sizing a column fixes them again). */
|
|
295
300
|
fit(unit) {
|
|
296
|
-
if (set(unit, null, t("
|
|
301
|
+
if (set(unit, null, t("已自动调整列宽"))) return true;
|
|
297
302
|
tools.say(t("列宽已按内容调整,无需再调。"));
|
|
298
303
|
return false;
|
|
299
304
|
},
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { chipBox } from "../chip-fills.mjs";
|
|
2
2
|
import { DETAILS, DIALOG } from "../../components/kit.mjs";
|
|
3
3
|
import { boxRole } from "../../components/registry.mjs";
|
|
4
|
-
import { UNIT, can, isHost, mergeInto, partsOf, removalTarget, takeOut, textEnd, unitElement } from "../core.mjs";
|
|
4
|
+
import { UNIT, can, isEmpty, isHost, mergeInto, partsOf, removalTarget, takeOut, textEnd, unitElement } from "../core.mjs";
|
|
5
5
|
import { atomOf, caretAt, caretAtOffset, dragPlace, editable, hosts, pointRange, select } from "../caret.mjs";
|
|
6
6
|
import { edgeFollower } from "../edge-scroll.mjs";
|
|
7
|
+
import { FOLDED } from "../folded.mjs";
|
|
7
8
|
import { gapScore } from "../geometry.mjs";
|
|
8
9
|
import { endsGesture, gestureLock } from "../gesture.mjs";
|
|
9
10
|
import { joinCode } from "../marks.mjs";
|
|
@@ -21,8 +22,10 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
21
22
|
// the window's edges), drawn with the CSS Custom Highlight API in the selection's own colors, the
|
|
22
23
|
// browser's selecting held off meanwhile; back in that block, the browser's again. Shift+click in
|
|
23
24
|
// another block selects from the caret to there.
|
|
24
|
-
// Its text is that of body text, headings and list items (in quotes, highlight blocks, columns…)
|
|
25
|
-
//
|
|
25
|
+
// Its text is that of body text, headings and list items (in quotes, highlight blocks, callouts, columns…),
|
|
26
|
+
// and the page's title's, which a deletion takes its part of but never joins with the body's (notion-lite's
|
|
27
|
+
// selection runs from its page title into the blocks; the user's: what is left of the body stays in the body).
|
|
28
|
+
// A block holding none (a code block, a table, a file, an image, a formula block, a
|
|
26
29
|
// divider…) is taken whole as it passes it, filled as a selected block is (selection/ mark), its
|
|
27
30
|
// own text not marked: over one, an end of the selection stands before it or after it, as the drag
|
|
28
31
|
// goes, and a press begun in one (its code, a cell) takes it whole once it has left it.
|
|
@@ -107,6 +110,10 @@ function lineStrips(texts, origin) {
|
|
|
107
110
|
|
|
108
111
|
// The text blocks it takes text from, and a deletion joins: body text, headings, list items.
|
|
109
112
|
const isText = (host) => isHost(host) && (host.getAttribute("data-ge-kind") ?? "flow") === "flow";
|
|
113
|
+
// The page's title: text it takes too (drawn, copied, deleted), kept apart: a deletion leaves it what
|
|
114
|
+
// stands outside the selection and joins nothing to it (remove).
|
|
115
|
+
const isTitle = (host) => isHost(host) && host.getAttribute("data-ge-kind") === "title";
|
|
116
|
+
const isPiece = (host) => isText(host) || isTitle(host);
|
|
110
117
|
const textHosts = (unit) => [...unit.querySelectorAll("[data-ge-block], [data-ge-new]")].filter((node) => isHost(node) && isText(node));
|
|
111
118
|
|
|
112
119
|
// The outermost block around `node` holding no text of the body (a code block, a table, a file…),
|
|
@@ -193,12 +200,12 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
193
200
|
function pointAt(x, y, from) {
|
|
194
201
|
const place = dragPlace([from.node, from.offset], x, y);
|
|
195
202
|
const host = place && editable(place[0]);
|
|
196
|
-
if (host?.closest("main") &&
|
|
203
|
+
if (host?.closest("main") && isPiece(host)) return { host, node: place[0], offset: place[1] };
|
|
197
204
|
const whole = wholeOf(document.elementFromPoint(x, y));
|
|
198
205
|
if (whole) return edge(whole, !from || before(from, edge(whole, false)));
|
|
199
206
|
let best = null;
|
|
200
207
|
let bestScore = null;
|
|
201
|
-
for (const each of hosts().filter((node) => node.closest("main") &&
|
|
208
|
+
for (const each of hosts().filter((node) => node.closest("main") && isPiece(node))) {
|
|
202
209
|
const rect = each.getBoundingClientRect();
|
|
203
210
|
// By height, then (level ones: columns side by side) by width; of nested ones, the innermost.
|
|
204
211
|
const score = gapScore(rect, x, y);
|
|
@@ -219,7 +226,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
219
226
|
// Where the selection starts, `focus` being its other end: the press's place in body text; begun
|
|
220
227
|
// in a block taken whole (its code, a cell), that block's edge away from `focus`.
|
|
221
228
|
function startOf(anchor, focus) {
|
|
222
|
-
if (
|
|
229
|
+
if (isPiece(anchor.host)) return anchor;
|
|
223
230
|
const whole = wholeOf(anchor.host) ?? unitElement(anchor.host);
|
|
224
231
|
if (!whole) return anchor;
|
|
225
232
|
const head = edge(whole, false);
|
|
@@ -242,7 +249,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
242
249
|
// text it reaches: none when its text stands before the start (the selection begun in a block the
|
|
243
250
|
// item holds) or after the end.
|
|
244
251
|
const reaches = (host) => host === selection.start.host || host === selection.end.host || (range.isPointInRange(host, 0) && range.isPointInRange(host, textEnd(host)));
|
|
245
|
-
const texts = hosts().filter((host) => host.closest("main") &&
|
|
252
|
+
const texts = hosts().filter((host) => host.closest("main") && isPiece(host) && range.intersectsNode(host) && reaches(host) && !folded(host)).map((host) => {
|
|
246
253
|
const part = document.createRange();
|
|
247
254
|
part.setStart(host, 0);
|
|
248
255
|
part.setEnd(host, textEnd(host));
|
|
@@ -250,6 +257,20 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
250
257
|
if (host === selection.end.host) part.setEnd(selection.end.node, selection.end.offset);
|
|
251
258
|
return { host, range: part };
|
|
252
259
|
});
|
|
260
|
+
// What a folded heading hides (fold/) between the ends goes with the selection, wherever in the
|
|
261
|
+
// heading's words it begins: its text blocks' text in full and its other blocks whole (below), as
|
|
262
|
+
// a deletion takes the blocks between the ends whole (unitsBetween), so a copy or a cut carries
|
|
263
|
+
// what the deletion takes. An end is never in what is hidden (hosts() are those shown), so what is
|
|
264
|
+
// hidden and in the range lies between the ends.
|
|
265
|
+
const hidden = [...document.querySelectorAll(`main [${FOLDED}] :is([data-ge-block], [data-ge-new]), main :is([data-ge-block], [data-ge-new])[${FOLDED}]`)]
|
|
266
|
+
.filter((host) => isHost(host) && isText(host) && range.intersectsNode(host) && !folded(host));
|
|
267
|
+
for (const host of hidden) {
|
|
268
|
+
const part = document.createRange();
|
|
269
|
+
part.setStart(host, 0);
|
|
270
|
+
part.setEnd(host, textEnd(host));
|
|
271
|
+
texts.push({ host, range: part });
|
|
272
|
+
}
|
|
273
|
+
if (hidden.length > 0) texts.sort((a, b) => (a.host.compareDocumentPosition(b.host) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1));
|
|
253
274
|
const wholes = [...wholeClosed];
|
|
254
275
|
for (const unit of document.querySelectorAll(`main :is(${UNIT})`)) {
|
|
255
276
|
if (wholes.some((other) => other === unit || other.contains(unit))) continue;
|
|
@@ -348,7 +369,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
348
369
|
|
|
349
370
|
// Drawn again over its text blocks turned into another type (`texts`: where its pieces are now, in
|
|
350
371
|
// page order), as notion-lite's placeCaret(keep) keeps a selection; when one of them holds no text of
|
|
351
|
-
// the body now (a
|
|
372
|
+
// the body now (a disclosure's title, code), let go instead. Returns whether it is drawn.
|
|
352
373
|
function reselect(texts) {
|
|
353
374
|
if (!cross) return false;
|
|
354
375
|
if (texts.length === 0 || !texts.every(({ host }) => host.isConnected && isText(host))) {
|
|
@@ -481,7 +502,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
481
502
|
select(range);
|
|
482
503
|
return;
|
|
483
504
|
}
|
|
484
|
-
const texts = hosts().filter((host) => host.closest("main") &&
|
|
505
|
+
const texts = hosts().filter((host) => host.closest("main") && isPiece(host));
|
|
485
506
|
const next = texts.find((host) => before(point, { node: host, offset: 0 }));
|
|
486
507
|
const previous = texts.filter((host) => before({ node: host, offset: textEnd(host) }, point)).at(-1);
|
|
487
508
|
const host = forward ? next ?? previous : previous ?? next;
|
|
@@ -489,14 +510,17 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
489
510
|
}
|
|
490
511
|
|
|
491
512
|
// Delete it: the first block keeps its text before it and takes the last block's after it, the
|
|
492
|
-
// blocks between go (those taken whole among them); one undo step, the caret where it began.
|
|
513
|
+
// blocks between go (those taken whole among them); one undo step, the caret where it began. From
|
|
514
|
+
// the page's title (`apart`) nothing joins: the title keeps what stands before it (empty, it says
|
|
515
|
+
// 未命名文档), the last block what stands after it in a block of its own (gone when that is nothing).
|
|
493
516
|
// Returns whether it went.
|
|
494
517
|
function remove() {
|
|
495
518
|
const selection = cross;
|
|
496
519
|
const { start, end } = selection;
|
|
497
520
|
letGo();
|
|
498
521
|
if (!(start.host ?? start.node).isConnected || !(end.host ?? end.node).isConnected) return false;
|
|
499
|
-
|
|
522
|
+
const apart = isTitle(start.host) || isTitle(end.host);
|
|
523
|
+
if (![start.host, end.host].every((host) => !host || isPiece(host))) {
|
|
500
524
|
say(t("跨块删除只支持正文、标题和列表里的文字。"));
|
|
501
525
|
return false;
|
|
502
526
|
}
|
|
@@ -538,9 +562,14 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
538
562
|
}
|
|
539
563
|
for (const target of targets) takeOut(target);
|
|
540
564
|
// Joined unless the two cannot be (a block that may not merge, lists that cannot go along):
|
|
541
|
-
// then each keeps what is left of its text.
|
|
542
|
-
|
|
543
|
-
if (
|
|
565
|
+
// then each keeps what is left of its text. Apart from the title, the last block left empty
|
|
566
|
+
// goes as the blocks between do (it was all selected), else it stays with its rest.
|
|
567
|
+
if (apart) {
|
|
568
|
+
const last = isTitle(end.host) ? null : end.host;
|
|
569
|
+
if (last && endTarget && isEmpty(last) && can(last, "remove") && !keepText(endTarget)) takeOut(endTarget);
|
|
570
|
+
} else if (start.host && end.host && mergeInto(start.host, end.host, { anyKind: true }) && endTarget !== end.host && endTarget.isConnected) takeOut(endTarget);
|
|
571
|
+
if (start.host && !apart) joinCode(start.host); // inline code meeting inline code at the join is one piece
|
|
572
|
+
if (isTitle(start.host) && isEmpty(start.host)) start.host.replaceChildren(); // no <br> left in an emptied title
|
|
544
573
|
return { touched: touched.filter((host) => host.isConnected), focus: start.host ?? end.host ?? null };
|
|
545
574
|
});
|
|
546
575
|
if (!result) return false;
|