@heycys/gallery 0.1.1 → 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 +1 -1
- package/browser/editor/components/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.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/icons.mjs +8 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/installed/index.mjs +11 -4
- package/browser/editor/components/installed/page.mjs +27 -16
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/registry.mjs +13 -4
- package/browser/editor/components/table/index.mjs +59 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- 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 +1 -1
- package/browser/editor/page/changes/bar.mjs +6 -14
- package/browser/editor/page/changes/index.mjs +2 -2
- 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 +124 -13
- package/browser/editor/page/clipboard/own/blocks.mjs +11 -11
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/selection.mjs +1 -1
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +80 -22
- package/browser/editor/page/conflicts.mjs +7 -7
- package/browser/editor/page/core.mjs +31 -15
- package/browser/editor/page/custom-page.mjs +106 -0
- package/browser/editor/page/editor.mjs +51 -14
- package/browser/editor/page/emoji-picker/styles.mjs +7 -12
- package/browser/editor/page/emoji-picker/upload.mjs +2 -2
- package/browser/editor/page/handle/index.mjs +5 -8
- package/browser/editor/page/history.mjs +24 -4
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/look.mjs +54 -3
- package/browser/editor/page/margin.mjs +18 -3
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +18 -7
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +13 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +11 -2
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +48 -4
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/cells.mjs +102 -46
- package/browser/editor/page/table/icons.mjs +2 -0
- package/browser/editor/page/table/index.mjs +29 -10
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +150 -0
- package/browser/editor/page/text-select/index.mjs +26 -12
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/typing/index.mjs +53 -3
- package/browser/editor/page/ui.mjs +13 -0
- 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/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +323 -46
- package/browser/shared/component-source.mjs +37 -0
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +18 -8
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -0
- 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/i18n/en.mjs +307 -27
- package/browser/shared/json-layout.mjs +47 -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/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +331 -67
- 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/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- 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-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/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-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-6VTU6KEO.mjs} +1 -1
- package/dist/chunk-B4P2CM2J.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-BPL64HGA.mjs} +1 -1
- package/dist/chunk-BVEFGE4B.mjs +2 -0
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CRJEG7MT.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.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-GB5SOYQJ.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-KTKHRC6H.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-MHW7ZKOU.mjs} +1 -1
- package/dist/chunk-N76HWBA3.mjs +10 -0
- package/dist/chunk-N7AZZLGT.mjs +548 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.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-4FS7Z7WR.mjs → chunk-OUUP3WKT.mjs} +1 -1
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-OW5NWPOJ.mjs} +1 -1
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-POQSE4C2.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/{chunk-XNROSH2T.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-7DTINW6U.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-UNOYVIYR.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-V6RIYQZZ.mjs} +1 -1
- 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-YI43RG4P.mjs +2 -0
- package/dist/chunk-YQGT4AB2.mjs +6 -0
- package/dist/chunk-ZB4H7ZN4.mjs +2 -0
- package/dist/{chunk-IVDLMMBD.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-U6KNPJPR.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/report.css +255 -17
- package/kit/runtime.js +1600 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +128 -43
- package/kit/ui.js +77 -35
- 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 +12 -10
- package/sdk/doc-kit.d.ts +396 -5
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +56 -23
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +221 -0
- package/skill/references/writing-html.md +6 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- 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/dist/chunk-3HIRPVLU.mjs +0 -2
- package/dist/chunk-5MHMDLZD.mjs +0 -4
- package/dist/chunk-64K7IPLO.mjs +0 -255
- package/dist/chunk-6QXGZM36.mjs +0 -8
- package/dist/chunk-6RGJOMJP.mjs +0 -16
- package/dist/chunk-AJ73XJF3.mjs +0 -2
- package/dist/chunk-AUZGSZJH.mjs +0 -13
- package/dist/chunk-BFE45AKL.mjs +0 -2
- package/dist/chunk-BXO2ZY5P.mjs +0 -2
- package/dist/chunk-CEH4MRCC.mjs +0 -2
- package/dist/chunk-CY2FNNAB.mjs +0 -16
- package/dist/chunk-DFUDV4LX.mjs +0 -2
- package/dist/chunk-DKXG4XDG.mjs +0 -2
- package/dist/chunk-EZQ34M3F.mjs +0 -124
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FUKQNOQS.mjs +0 -9
- package/dist/chunk-JPOSLGOC.mjs +0 -6
- package/dist/chunk-L3QKH4OK.mjs +0 -26
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LEF6DRCK.mjs +0 -59
- package/dist/chunk-NO5NJCHO.mjs +0 -2
- package/dist/chunk-NQPVAU63.mjs +0 -2
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O35FIXRB.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-PL6GHLGD.mjs +0 -15
- package/dist/chunk-QJIR2BLP.mjs +0 -6
- package/dist/chunk-QUPLVPB2.mjs +0 -7
- package/dist/chunk-R7BNENLY.mjs +0 -4
- package/dist/chunk-S6O4UHLC.mjs +0 -2
- package/dist/chunk-SGJWQKEI.mjs +0 -2
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-TYK6VNAB.mjs +0 -10
- package/dist/chunk-UALRNVSE.mjs +0 -4
- package/dist/chunk-V3HXVQEM.mjs +0 -2
- package/dist/chunk-V5VXUJKG.mjs +0 -2
- package/dist/chunk-VBXMADMP.mjs +0 -2
- package/dist/chunk-VNV55RUA.mjs +0 -2
- package/dist/chunk-VPD2PS35.mjs +0 -2
- package/dist/chunk-W4VKN3GF.mjs +0 -7
- package/dist/chunk-W5BXXPDJ.mjs +0 -3
- package/dist/chunk-XUNHRCOG.mjs +0 -6
- package/skill/references/building-components.md +0 -367
- package/web/assets/index-Bh74DfsV.css +0 -1
- package/web/assets/index-UW0RyFFt.js +0 -13
|
@@ -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
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
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
7
|
import { FOLDED } from "../folded.mjs";
|
|
@@ -22,7 +22,9 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
22
22
|
// the window's edges), drawn with the CSS Custom Highlight API in the selection's own colors, the
|
|
23
23
|
// browser's selecting held off meanwhile; back in that block, the browser's again. Shift+click in
|
|
24
24
|
// another block selects from the caret to there.
|
|
25
|
-
// Its text is that of body text, headings and list items (in quotes, highlight blocks, callouts, columns…)
|
|
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).
|
|
26
28
|
// A block holding none (a code block, a table, a file, an image, a formula block, a
|
|
27
29
|
// divider…) is taken whole as it passes it, filled as a selected block is (selection/ mark), its
|
|
28
30
|
// own text not marked: over one, an end of the selection stands before it or after it, as the drag
|
|
@@ -108,6 +110,10 @@ function lineStrips(texts, origin) {
|
|
|
108
110
|
|
|
109
111
|
// The text blocks it takes text from, and a deletion joins: body text, headings, list items.
|
|
110
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);
|
|
111
117
|
const textHosts = (unit) => [...unit.querySelectorAll("[data-ge-block], [data-ge-new]")].filter((node) => isHost(node) && isText(node));
|
|
112
118
|
|
|
113
119
|
// The outermost block around `node` holding no text of the body (a code block, a table, a file…),
|
|
@@ -194,12 +200,12 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
194
200
|
function pointAt(x, y, from) {
|
|
195
201
|
const place = dragPlace([from.node, from.offset], x, y);
|
|
196
202
|
const host = place && editable(place[0]);
|
|
197
|
-
if (host?.closest("main") &&
|
|
203
|
+
if (host?.closest("main") && isPiece(host)) return { host, node: place[0], offset: place[1] };
|
|
198
204
|
const whole = wholeOf(document.elementFromPoint(x, y));
|
|
199
205
|
if (whole) return edge(whole, !from || before(from, edge(whole, false)));
|
|
200
206
|
let best = null;
|
|
201
207
|
let bestScore = null;
|
|
202
|
-
for (const each of hosts().filter((node) => node.closest("main") &&
|
|
208
|
+
for (const each of hosts().filter((node) => node.closest("main") && isPiece(node))) {
|
|
203
209
|
const rect = each.getBoundingClientRect();
|
|
204
210
|
// By height, then (level ones: columns side by side) by width; of nested ones, the innermost.
|
|
205
211
|
const score = gapScore(rect, x, y);
|
|
@@ -220,7 +226,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
220
226
|
// Where the selection starts, `focus` being its other end: the press's place in body text; begun
|
|
221
227
|
// in a block taken whole (its code, a cell), that block's edge away from `focus`.
|
|
222
228
|
function startOf(anchor, focus) {
|
|
223
|
-
if (
|
|
229
|
+
if (isPiece(anchor.host)) return anchor;
|
|
224
230
|
const whole = wholeOf(anchor.host) ?? unitElement(anchor.host);
|
|
225
231
|
if (!whole) return anchor;
|
|
226
232
|
const head = edge(whole, false);
|
|
@@ -243,7 +249,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
243
249
|
// text it reaches: none when its text stands before the start (the selection begun in a block the
|
|
244
250
|
// item holds) or after the end.
|
|
245
251
|
const reaches = (host) => host === selection.start.host || host === selection.end.host || (range.isPointInRange(host, 0) && range.isPointInRange(host, textEnd(host)));
|
|
246
|
-
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) => {
|
|
247
253
|
const part = document.createRange();
|
|
248
254
|
part.setStart(host, 0);
|
|
249
255
|
part.setEnd(host, textEnd(host));
|
|
@@ -496,7 +502,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
496
502
|
select(range);
|
|
497
503
|
return;
|
|
498
504
|
}
|
|
499
|
-
const texts = hosts().filter((host) => host.closest("main") &&
|
|
505
|
+
const texts = hosts().filter((host) => host.closest("main") && isPiece(host));
|
|
500
506
|
const next = texts.find((host) => before(point, { node: host, offset: 0 }));
|
|
501
507
|
const previous = texts.filter((host) => before({ node: host, offset: textEnd(host) }, point)).at(-1);
|
|
502
508
|
const host = forward ? next ?? previous : previous ?? next;
|
|
@@ -504,14 +510,17 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
504
510
|
}
|
|
505
511
|
|
|
506
512
|
// Delete it: the first block keeps its text before it and takes the last block's after it, the
|
|
507
|
-
// 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).
|
|
508
516
|
// Returns whether it went.
|
|
509
517
|
function remove() {
|
|
510
518
|
const selection = cross;
|
|
511
519
|
const { start, end } = selection;
|
|
512
520
|
letGo();
|
|
513
521
|
if (!(start.host ?? start.node).isConnected || !(end.host ?? end.node).isConnected) return false;
|
|
514
|
-
|
|
522
|
+
const apart = isTitle(start.host) || isTitle(end.host);
|
|
523
|
+
if (![start.host, end.host].every((host) => !host || isPiece(host))) {
|
|
515
524
|
say(t("跨块删除只支持正文、标题和列表里的文字。"));
|
|
516
525
|
return false;
|
|
517
526
|
}
|
|
@@ -553,9 +562,14 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
|
|
|
553
562
|
}
|
|
554
563
|
for (const target of targets) takeOut(target);
|
|
555
564
|
// Joined unless the two cannot be (a block that may not merge, lists that cannot go along):
|
|
556
|
-
// then each keeps what is left of its text.
|
|
557
|
-
|
|
558
|
-
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
|
|
559
573
|
return { touched: touched.filter((host) => host.isConnected), focus: start.host ?? end.host ?? null };
|
|
560
574
|
});
|
|
561
575
|
if (!result) return false;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { TODO_EVENT, TODO_MOST, TODO_ROUTE } from "../../shared/workspace-query.mjs";
|
|
2
|
+
import { postAnswer } from "./post.mjs";
|
|
3
|
+
|
|
4
|
+
// To-dos of documents checked from this page (workspace.setTodo, the plan's 5.1; docs/editor.md "To-dos
|
|
5
|
+
// checked from another page"): the kit's ask (TODO_EVENT, cancelable on the window: { ask: { slug, ref,
|
|
6
|
+
// done }, answer(promise) }) taken by whoever holds the page's token (a custom page's board, a document's
|
|
7
|
+
// editor) and written by the workspace's service (POST TODO_ROUTE, one document a request: the edit
|
|
8
|
+
// service's setTodos, one commit of the reader's). The checks of one document wait in a line of their own:
|
|
9
|
+
// those asked while one write of it is out go together in the next (its items in the order asked, the
|
|
10
|
+
// last of an item winning), so that a reader ticking five boxes quickly makes two commits, not five.
|
|
11
|
+
// Each ask is answered { ok: true, changed, block } (`block` the item's id now, which the commit gives
|
|
12
|
+
// one that had none) or { ok: false, reason, message? }, never rejected.
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* `token`: the page map's. `done(ask, answer)`: an ask answered (the board keeps an undo step of one that
|
|
16
|
+
* changed its document). Returns { write(ask) (a promise of its answer), idle() (once every write asked so
|
|
17
|
+
* far is answered), listen() (takes the kit's asks; returns the function that stops it) }.
|
|
18
|
+
*/
|
|
19
|
+
export function createTodoWrites({ token, done = () => {} }) {
|
|
20
|
+
const lines = new Map(); // slug -> { waiting: [{ ask, resolve }], out: Promise | null }
|
|
21
|
+
|
|
22
|
+
async function send(slug, line) {
|
|
23
|
+
const batch = line.waiting.splice(0, TODO_MOST);
|
|
24
|
+
const answer = await postAnswer(TODO_ROUTE, token, { slug, items: batch.map(({ ask }) => ({ ref: ask.ref, done: ask.done })) });
|
|
25
|
+
batch.forEach(({ ask, resolve }, index) => {
|
|
26
|
+
const result = answer?.ok ? answer.results?.[index] ?? { ok: false, reason: "failed" } : { ok: false, reason: answer?.reason === "offline" ? "offline" : answer?.reason ?? "failed", ...(typeof answer?.message === "string" ? { message: answer.message } : {}) };
|
|
27
|
+
try {
|
|
28
|
+
done(ask, result);
|
|
29
|
+
} finally {
|
|
30
|
+
resolve(result);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// The line of a document: written once nothing of it is out, what waits then going together.
|
|
36
|
+
function run(slug) {
|
|
37
|
+
const line = lines.get(slug);
|
|
38
|
+
if (line.out || line.waiting.length === 0) return;
|
|
39
|
+
// A microtask's wait, so that the asks of one gesture (a block checking several at once) go together.
|
|
40
|
+
line.out = Promise.resolve().then(() => send(slug, line)).catch(() => {}).finally(() => {
|
|
41
|
+
line.out = null;
|
|
42
|
+
if (line.waiting.length > 0) run(slug);
|
|
43
|
+
else lines.delete(slug);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function write(ask) {
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
if (!lines.has(ask.slug)) lines.set(ask.slug, { waiting: [], out: null });
|
|
50
|
+
lines.get(ask.slug).waiting.push({ ask, resolve });
|
|
51
|
+
run(ask.slug);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
write,
|
|
57
|
+
async idle() {
|
|
58
|
+
for (;;) {
|
|
59
|
+
const out = [...lines.values()].map((line) => line.out).filter(Boolean);
|
|
60
|
+
if (out.length === 0) return;
|
|
61
|
+
await Promise.all(out);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
listen() {
|
|
65
|
+
const take = (event) => {
|
|
66
|
+
const { ask, answer } = event.detail ?? {};
|
|
67
|
+
if (event.defaultPrevented || !ask || typeof answer !== "function") return;
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
answer(write(ask));
|
|
70
|
+
};
|
|
71
|
+
addEventListener(TODO_EVENT, take);
|
|
72
|
+
return () => removeEventListener(TODO_EVENT, take);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
boxKind, can, emptyContainer, isEmpty, isFirstLine, isHost, limitText, mergeWithPrevious, nestedBlocks, nestedLists, nextLine, parentItem, previousLine, removalTarget, splitBlock, takeOut, textEnd, unitElement,
|
|
2
|
+
UNIT, boxKind, can, emptyContainer, isEmpty, isFirstLine, isHost, limitText, mergeWithPrevious, nestedBlocks, nestedLists, nextLine, parentItem, previousLine, removalTarget, splitBlock, takeOut, textEnd, unitElement, newParagraphHost, withLeads,
|
|
3
3
|
} from "../core.mjs";
|
|
4
4
|
import { atEdge, caretAt, hosts, select, textNear } from "../caret.mjs";
|
|
5
5
|
import { convertible } from "../convert.mjs";
|
|
6
6
|
import { joinCode } from "../marks.mjs";
|
|
7
7
|
import { numberWithUnit, sideOf, WORD } from "../../../shared/inline-spacing.mjs";
|
|
8
8
|
import { pageOf, pagesAround } from "../page-objects.mjs";
|
|
9
|
-
import { BLOCK_TYPES, HOSTS, firstSaysOf, placeholderOf, textFilters, textTypeOf } from "../../components/registry.mjs";
|
|
9
|
+
import { BLOCK_TYPES, HOSTS, accepts, firstSaysOf, placeholderOf, textFilters, textTypeOf } from "../../components/registry.mjs";
|
|
10
10
|
import { t } from "../../../shared/i18n/index.mjs";
|
|
11
11
|
|
|
12
12
|
// Typing in a block (docs/editor.md, "Browser side"): every key goes first to the component the block
|
|
@@ -25,6 +25,8 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
25
25
|
// 3万5千), and a block written without such spaces is typed in its own way (none added).
|
|
26
26
|
const HAN = /[\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/;
|
|
27
27
|
const LATIN = /[A-Za-z0-9]/;
|
|
28
|
+
// The text blocks that say their placeholder whenever they are empty (HOSTS' `untitled`: the page's title).
|
|
29
|
+
const UNTITLED = Object.keys(HOSTS).filter((kind) => HOSTS[kind].untitled).map((kind) => `main [data-ge-kind="${kind}"]`).join(", ");
|
|
28
30
|
const needsSpace = (a, b, before) => ((HAN.test(a) && LATIN.test(b)) || (LATIN.test(a) && HAN.test(b))) && !numberWithUnit(a, b, before);
|
|
29
31
|
// The block's own way with Chinese beside Latin letters and digits, from its text but what was just
|
|
30
32
|
// typed: true when it writes them together more often than apart (a number's unit is no sign either way).
|
|
@@ -61,8 +63,43 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
61
63
|
return Boolean(key(pageOf(host)?.keys ?? {})?.(ctx, ...rest) || pagesAround(host).some((page) => key(page.keys?.around ?? {})?.(ctx, ...rest)));
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
// Enter in the page's title (HOSTS' `opensBody`): notion-lite's splitBlock for the page (enter.js, its
|
|
67
|
+
// first rule): what is selected goes, what follows the caret leaves the title for a new paragraph right
|
|
68
|
+
// below it, the first block of the page (an empty one at its end, a new untitled document's too), and
|
|
69
|
+
// the caret goes to its start; the title keeps what stands before the caret, never a line break. One
|
|
70
|
+
// undo step, the caret back in the title where it was. Below the title is the header's first line when it has one
|
|
71
|
+
// (the paragraph goes before it, in the header), else the first block after the header.
|
|
72
|
+
function enterBody(title) {
|
|
73
|
+
const selection = getSelection();
|
|
74
|
+
if (!selection.rangeCount || !title.contains(selection.getRangeAt(0).startContainer) || !title.contains(selection.getRangeAt(0).endContainer)) return;
|
|
75
|
+
const range = selection.getRangeAt(0);
|
|
76
|
+
const header = title.parentElement;
|
|
77
|
+
let line = title.nextElementSibling;
|
|
78
|
+
while (line && !line.matches(UNIT)) line = line.nextElementSibling;
|
|
79
|
+
const [box, before] = line ? [header, withLeads(line)[0]] : [header.parentElement, header.nextSibling];
|
|
80
|
+
const paragraph = newParagraphHost(document);
|
|
81
|
+
if (!box?.hasAttribute("data-ge-box") || !accepts(box.getAttribute("data-ge-box-kind"), paragraph.getAttribute("data-ge-type"))) {
|
|
82
|
+
say(limitText(title, "split"));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
struct([...new Set([header, box])], [title], () => {
|
|
86
|
+
range.deleteContents();
|
|
87
|
+
const tail = document.createRange();
|
|
88
|
+
tail.setStart(range.startContainer, range.startOffset);
|
|
89
|
+
tail.setEnd(title, title.childNodes.length);
|
|
90
|
+
const moved = tail.extractContents();
|
|
91
|
+
if (moved.textContent.length > 0) paragraph.append(document.createTextNode(moved.textContent)); // the title's words, plain
|
|
92
|
+
title.normalize();
|
|
93
|
+
if (isEmpty(title)) title.replaceChildren();
|
|
94
|
+
box.insertBefore(paragraph, before);
|
|
95
|
+
return { touched: [title, paragraph], focus: paragraph };
|
|
96
|
+
}, { caret: true });
|
|
97
|
+
caretAt(paragraph, "start");
|
|
98
|
+
}
|
|
99
|
+
|
|
64
100
|
// Enter.
|
|
65
101
|
function split(host) {
|
|
102
|
+
if (HOSTS[host.getAttribute("data-ge-kind")]?.opensBody) return enterBody(host);
|
|
66
103
|
// The caret at the very start of a block with text: an empty paragraph goes before the block and
|
|
67
104
|
// the caret stays (a block that splits does this itself, splitBlock). This comes first: in a code
|
|
68
105
|
// block too, whose own Enter breaks the line.
|
|
@@ -266,10 +303,23 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
|
|
|
266
303
|
if (hint) host.setAttribute("data-ge-placeholder", hint);
|
|
267
304
|
else host?.removeAttribute("data-ge-placeholder");
|
|
268
305
|
host?.toggleAttribute("data-ge-adding", add);
|
|
306
|
+
untitled();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// The page's title says 未命名文档 whenever it is empty, the caret in it or not (HOSTS' `untitled`:
|
|
310
|
+
// notion-lite's page title, data-ph 新页面); asked again on every move of the caret and every input,
|
|
311
|
+
// so an undo, a deletion across blocks and the workbench's renaming are followed too.
|
|
312
|
+
function untitled() {
|
|
313
|
+
if (!UNTITLED) return;
|
|
314
|
+
for (const host of document.querySelectorAll(UNTITLED)) {
|
|
315
|
+
if (!isHost(host)) continue;
|
|
316
|
+
if (isEmpty(host)) host.setAttribute("data-ge-placeholder", placeholderOf(host));
|
|
317
|
+
else if (host !== placeholder) host.removeAttribute("data-ge-placeholder");
|
|
318
|
+
}
|
|
269
319
|
}
|
|
270
320
|
|
|
271
321
|
return {
|
|
272
|
-
split, backspace, forwardDelete, autoSpace, updatePlaceholder,
|
|
322
|
+
split, backspace, forwardDelete, autoSpace, updatePlaceholder, untitled,
|
|
273
323
|
/** Tab (`back`: Shift+Tab). Whether the key was taken. */
|
|
274
324
|
tab: (host, back) => asked((keys) => keys.tab, host, back),
|
|
275
325
|
/** Ctrl+Enter. Whether the key was taken. */
|
|
@@ -55,6 +55,19 @@ export function button(label, action, { primary = false, ...props } = {}) {
|
|
|
55
55
|
return node;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* A text button in the editor's one button look (look.mjs BUTTONS, `.ge-btn`): no line, no fill, a gray
|
|
60
|
+
* under the pointer. `primary` the pale blue one (add, confirm, save; `data-primary`), `danger` with it the
|
|
61
|
+
* pale red (a delete), `quiet` a small one for looking, not deciding (`data-quiet`). A press on it leaves
|
|
62
|
+
* the selection where it is (button()).
|
|
63
|
+
*/
|
|
64
|
+
export function textButton(label, action, { primary = false, danger = false, quiet = false, class: own = "", ...props } = {}) {
|
|
65
|
+
const node = button(label, action, { primary, class: `ge-btn${own ? ` ${own}` : ""}`, ...props });
|
|
66
|
+
if (danger) node.dataset.danger = "";
|
|
67
|
+
if (quiet) node.dataset.quiet = "";
|
|
68
|
+
return node;
|
|
69
|
+
}
|
|
70
|
+
|
|
58
71
|
// Editor UI lives in the top layer with an open modal dialog, otherwise it would be inert.
|
|
59
72
|
export function layer() {
|
|
60
73
|
return document.querySelector(DIALOG.open) ?? document.body;
|