@panphora/clayjs 1.15.2 → 1.17.0
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/README.md +4 -5
- package/THIRD-PARTY-NOTICES.md +16 -0
- package/compat/highlight-11.9.0.min.js +1213 -0
- package/compat/highlight-LICENSE +29 -0
- package/compat/journal-assets.lock.json +22 -0
- package/compat/overtype-2.6.1.min.js +116 -0
- package/compat/overtype-LICENSE +21 -0
- package/dist/all.js +90 -0
- package/dist/clay-dom.js +84 -0
- package/dist/clay-events.js +103 -0
- package/dist/clay-internals.js +85 -0
- package/dist/clay-options.js +93 -0
- package/dist/clay-router.js +98 -0
- package/dist/clay-ui.js +95 -0
- package/dist/clay-utils.js +84 -0
- package/dist/clay.js +146 -0
- package/dist/clay.standalone.js +84291 -57611
- package/dist/m/attrs/add-from-T5LJXFFI.js +1 -0
- package/dist/m/attrs/onaftersave-OKSWEJQF.js +1 -0
- package/dist/m/attrs/refetch-on-save-ZUE7PSCI.js +1 -0
- package/dist/m/attrs/save-freeze-MYNVXREN.js +1 -0
- package/dist/m/c-2AZDZWCK.js +1 -0
- package/dist/m/c-2SPVQSHC.js +1 -0
- package/dist/m/c-2YYDMLNZ.js +1 -0
- package/dist/m/c-336SGU5W.js +1 -0
- package/dist/m/c-33JJ6CBX.js +2 -0
- package/dist/m/c-3GJ4SDE2.js +1 -0
- package/dist/m/c-3H6BZDNJ.js +6 -0
- package/dist/m/c-3OWDMNJR.js +2 -0
- package/dist/m/c-3RUU4TPX.js +91 -0
- package/dist/m/c-3XIRD4NU.js +1 -0
- package/dist/m/c-46XYM55L.js +1 -0
- package/dist/m/c-4DFEJ2PO.js +3 -0
- package/dist/m/c-4JZDZFF6.js +1 -0
- package/dist/m/c-4L3BTFRK.js +1 -0
- package/dist/m/c-4Q2XTQ2N.js +2 -0
- package/dist/m/c-4WKFKEKF.js +1 -0
- package/dist/m/c-56QRZTZH.js +1 -0
- package/dist/m/c-5J4E7O4Y.js +4 -0
- package/dist/m/c-5LKDWQTL.js +19 -0
- package/dist/m/c-5QWQ7A5L.js +1 -0
- package/dist/m/c-5RJFTLSF.js +1 -0
- package/dist/m/c-5V3MOVJT.js +1 -0
- package/dist/m/c-5VYOWDTI.js +1 -0
- package/dist/m/c-5YIHJ3TJ.js +1 -0
- package/dist/m/c-6AZOGAPE.js +1 -0
- package/dist/m/c-6CRUUXOX.js +5 -0
- package/dist/m/c-6HMB24EV.js +1 -0
- package/dist/m/c-6KEVEQ7L.js +1 -0
- package/dist/m/c-6NC5I2TV.js +1 -0
- package/dist/m/c-74MGYWZF.js +1 -0
- package/dist/m/c-7DJDKPGL.js +1 -0
- package/dist/m/c-7OLLJPWP.js +1 -0
- package/dist/m/c-7SWMYKAI.js +1 -0
- package/dist/m/c-A3E3NIMC.js +1 -0
- package/dist/m/c-A7LS5UZW.js +1 -0
- package/dist/m/c-AMSNPOCX.js +1 -0
- package/dist/m/c-AQLFEATB.js +1 -0
- package/dist/m/c-B3JM5ZXC.js +1 -0
- package/dist/m/c-BBVGTQG7.js +1 -0
- package/dist/m/c-BPF2NSPV.js +1 -0
- package/dist/m/c-BQ6LOBEE.js +1 -0
- package/dist/m/c-BTDI4Y23.js +1 -0
- package/dist/m/c-BWFVSBDF.js +1 -0
- package/dist/m/c-BYTKL6UX.js +1 -0
- package/dist/m/c-CFHW5AMY.js +6 -0
- package/dist/m/c-CJ3A7ZKE.js +1 -0
- package/dist/m/c-CQHPGKX2.js +1 -0
- package/dist/m/c-CYWLPPUS.js +1 -0
- package/dist/m/c-CZUSOB7V.js +1 -0
- package/dist/m/c-DCFSEJZG.js +1 -0
- package/dist/m/c-DCXOXBF3.js +1 -0
- package/dist/m/c-DFS4XZJV.js +2 -0
- package/dist/m/c-DNENWY4O.js +1 -0
- package/dist/m/c-DNZ5IFM6.js +1 -0
- package/dist/m/c-E4LIR5X5.js +1 -0
- package/dist/m/c-EJTGYSLN.js +1 -0
- package/dist/m/c-EVCQ3BKA.js +1 -0
- package/dist/m/c-EZU56NQV.js +34 -0
- package/dist/m/c-FDNHHZY5.js +1 -0
- package/dist/m/c-FILLTJA7.js +1 -0
- package/dist/m/c-FRLHSY7E.js +1 -0
- package/dist/m/c-FROJUZMV.js +1 -0
- package/dist/m/c-G2JPKCTP.js +1 -0
- package/dist/m/c-GB6TU7WV.js +1 -0
- package/dist/m/c-GFJJEBTU.js +1 -0
- package/dist/m/c-GJAEGGXY.js +1 -0
- package/dist/m/c-GOWBDM6J.js +1 -0
- package/dist/m/c-GQ6F6IDK.js +1 -0
- package/dist/m/c-GSFIGKOP.js +1 -0
- package/dist/m/c-GY422N3Q.js +1 -0
- package/dist/m/c-H4LG442Q.js +1 -0
- package/dist/m/c-HA6INT6J.js +1 -0
- package/dist/m/c-HAWFNBYG.js +1 -0
- package/dist/m/c-HDDEEL77.js +1 -0
- package/dist/m/c-HFKUVACH.js +1 -0
- package/dist/m/c-HHDFCNHV.js +1 -0
- package/dist/m/c-HPURYVZS.js +2 -0
- package/dist/m/c-I2ZATQCD.js +2 -0
- package/dist/m/c-IEM4NTCS.js +1 -0
- package/dist/m/c-IJUK2GPW.js +1 -0
- package/dist/m/c-IW6GGOU2.js +1 -0
- package/dist/m/c-JAX2667S.js +6 -0
- package/dist/m/c-JDCX26UP.js +25 -0
- package/dist/m/c-JRKY44DK.js +1 -0
- package/dist/m/c-JU3NK25H.js +1 -0
- package/dist/m/c-KAU6E43D.js +1 -0
- package/dist/m/c-KBS3UV6B.js +1 -0
- package/dist/m/c-KGVGROZT.js +1 -0
- package/dist/m/c-KI7M4AY3.js +1 -0
- package/dist/m/c-KIPQJX4B.js +1 -0
- package/dist/m/c-KQ6TYJAP.js +135 -0
- package/dist/m/c-KU3ZFADW.js +1 -0
- package/dist/m/c-L4WQSC27.js +1 -0
- package/dist/m/c-LFPHCXY3.js +1 -0
- package/dist/m/c-LRPUO2MX.js +1 -0
- package/dist/m/c-LWLBHLVC.js +3 -0
- package/dist/m/c-LZJPNR2W.js +1 -0
- package/dist/m/c-M2L47S2X.js +7 -0
- package/dist/m/c-MFP2ZWD4.js +1 -0
- package/dist/m/c-MKSQ4Y57.js +1 -0
- package/dist/m/c-MTQHWQC3.js +1 -0
- package/dist/m/c-N326R2JD.js +1 -0
- package/dist/m/c-N7JPUPGC.js +1 -0
- package/dist/m/c-NRPJEVJS.js +1 -0
- package/dist/m/c-NUFFJVVJ.js +1 -0
- package/dist/m/c-NUHP2XDB.js +1 -0
- package/dist/m/c-NUHSPT5P.js +1 -0
- package/dist/m/c-O72HVYSA.js +1 -0
- package/dist/m/c-OCSZ4QGN.js +1 -0
- package/dist/m/c-OIBUTDXI.js +1 -0
- package/dist/m/c-OIDRZKAF.js +1 -0
- package/dist/m/c-OW5QIGG3.js +1 -0
- package/dist/m/c-P7KNDG34.js +1 -0
- package/dist/m/c-PGRCK73F.js +1 -0
- package/dist/m/c-PQ5LK6QE.js +993 -0
- package/dist/m/c-PS5ARVWR.js +9 -0
- package/dist/m/c-PZ4XEPUP.js +2 -0
- package/dist/m/c-Q622NS2Y.js +1 -0
- package/dist/m/c-Q7NQD65V.js +1 -0
- package/dist/m/c-QH63LQOS.js +1 -0
- package/dist/m/c-QHIWXHRO.js +1 -0
- package/dist/m/c-QHWJ5ZIJ.js +1 -0
- package/dist/m/c-QICP2YR5.js +1 -0
- package/dist/m/c-QJ4OM3G6.js +1 -0
- package/dist/m/c-QNKREOL6.js +1 -0
- package/dist/m/c-R3L7ZJGB.js +2 -0
- package/dist/m/c-R7IWVINQ.js +1 -0
- package/dist/m/c-RM7J7BV2.js +1 -0
- package/dist/m/c-RSMOODDU.js +1 -0
- package/dist/m/c-RVMWGXEJ.js +1 -0
- package/dist/m/c-RYUXUUBX.js +1 -0
- package/dist/m/c-S4ZEH46B.js +9 -0
- package/dist/m/c-S7H2DRCB.js +1 -0
- package/dist/m/c-S7LK4KUE.js +1 -0
- package/dist/m/c-SDAXDM2D.js +1 -0
- package/dist/m/c-SGIA4IEQ.js +188 -0
- package/dist/m/c-SMBZG5X4.js +1 -0
- package/dist/m/c-SMGU7RT3.js +235 -0
- package/dist/m/c-SPIORRYS.js +1 -0
- package/dist/m/c-SWLRT66R.js +1 -0
- package/dist/m/c-SZGYW5HT.js +1 -0
- package/dist/m/c-TCCA5BZN.js +2 -0
- package/dist/m/c-TCJTVAFN.js +1 -0
- package/dist/m/c-TJ6WOJL3.js +67 -0
- package/dist/m/c-TQEMVJCS.js +1 -0
- package/dist/m/c-TRS6TM6O.js +1 -0
- package/dist/m/c-TYLXX4NF.js +21 -0
- package/dist/m/c-U62OB4BT.js +1 -0
- package/dist/m/c-U6YWUAR3.js +8 -0
- package/dist/m/c-UDCSU5G5.js +2 -0
- package/dist/m/c-UDUUJPFZ.js +1 -0
- package/dist/m/c-UGHH4MB3.js +1 -0
- package/dist/m/c-UL2YUY52.js +1 -0
- package/dist/m/c-VAK7SG37.js +1 -0
- package/dist/m/c-VDSS4K3Z.js +1 -0
- package/dist/m/c-VE6ZMYMC.js +1 -0
- package/dist/m/c-VG5XIN4T.js +1 -0
- package/dist/m/c-VHM5XQHK.js +1 -0
- package/dist/m/c-VHNSBD2M.js +1 -0
- package/dist/m/c-VI5RMSVY.js +1 -0
- package/dist/m/c-VKEDWYDF.js +1 -0
- package/dist/m/c-VRZN56XY.js +1 -0
- package/dist/m/c-W5MCHEGA.js +1 -0
- package/dist/m/c-WDC5GVKU.js +1 -0
- package/dist/m/c-WN5AY3OZ.js +1 -0
- package/dist/m/c-WNYBLIOZ.js +1 -0
- package/dist/m/c-WRBKEJD4.js +1 -0
- package/dist/m/c-WWXIDH4O.js +28 -0
- package/dist/m/c-WYFDLITL.js +1 -0
- package/dist/m/c-XCNTK76U.js +1 -0
- package/dist/m/c-XMS6DPBR.js +1 -0
- package/dist/m/c-XN6MBKI6.js +67 -0
- package/dist/m/c-XPELB6E5.js +1 -0
- package/dist/m/c-XQXZAO7N.js +1 -0
- package/dist/m/c-Y5HBBIQ4.js +1 -0
- package/dist/m/c-ZE46QDIH.js +1 -0
- package/dist/m/c-ZUCOKOHT.js +1 -0
- package/dist/m/c-ZVPVXTJF.js +4 -0
- package/dist/m/c-ZVRKXKM7.js +1 -0
- package/dist/m/c-ZWIOJGMT.js +1 -0
- package/dist/m/core/admin-attrs-QHOKPJ7W.js +1 -0
- package/dist/m/core/autosave-HRYGUWV6.js +1 -0
- package/dist/m/core/conflict-notice-6MROJN2L.js +1 -0
- package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
- package/dist/m/core/host-permission-FNXVEFNE.js +1 -0
- package/dist/m/core/is-edit-mode-KTWA3O5N.js +1 -0
- package/dist/m/core/persist-JFYRHMRJ.js +3 -0
- package/dist/m/core/recovery-FLTCC2OC.js +1 -0
- package/dist/m/core/save-HQZ4S667.js +1 -0
- package/dist/m/core/save-core-KGQWFUNH.js +1 -0
- package/dist/m/core/snapshot-EGQZNT45.js +1 -0
- package/dist/m/core/unsaved-warning-IDJLD66H.js +1 -0
- package/dist/m/dom/all-APS5ZSKP.js +1 -0
- package/dist/m/dom/dom-helpers-L7OSR6S4.js +1 -0
- package/dist/m/events/index-RN2JNGBV.js +1 -0
- package/dist/m/internals/index-PVXGPUDA.js +1 -0
- package/dist/m/lib/cache-bust-MUMFXZK6.js +1 -0
- package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
- package/dist/m/loader-S4I7GKXR.js +1 -0
- package/dist/m/manifest-4C419D67.js +1 -0
- package/dist/m/manifest-edit-B077F288.js +1 -0
- package/dist/m/manifest.json +3988 -0
- package/dist/m/options/options-EJMS3K24.js +1 -0
- package/dist/m/page/editor-NNJA4OKD.js +202 -0
- package/dist/m/plugins/ai-edit-QN4PMMNL.js +6 -0
- package/dist/m/plugins/bind-text-NX46N5UV.js +1 -0
- package/dist/m/plugins/cms-HP3LSTPN.js +2293 -0
- package/dist/m/plugins/demo-RM5IR6AO.js +1 -0
- package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
- package/dist/m/plugins/indicator-URDBBOQO.js +1 -0
- package/dist/m/plugins/live-HFWD4OIH.js +1 -0
- package/dist/m/plugins/menu-3HIEQSI6.js +138 -0
- package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
- package/dist/m/plugins/page-JOKB6XPR.js +2 -0
- package/dist/m/plugins/page-view-NXOJHNW6.js +1 -0
- package/dist/m/plugins/people-SGPJKANK.js +1 -0
- package/dist/m/plugins/quickcrop-QNY3PKLD.js +26 -0
- package/dist/m/plugins/quickcrop-QNY3PKLD.js.LEGAL.txt +7 -0
- package/dist/m/plugins/richclay-NRQDSWX6.js +517 -0
- package/dist/m/plugins/richclay-NRQDSWX6.js.LEGAL.txt +1 -0
- package/dist/m/plugins/sortable-GWT4PWDV.js +1 -0
- package/dist/m/plugins/source-4ZRSAIYM.js +1 -0
- package/dist/m/plugins/undo-VDA5P7FH.js +1 -0
- package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
- package/dist/m/plugins/upgrade-W7FG5VFG.js +1 -0
- package/dist/m/plugins/upload-WLYKK6TL.js +1 -0
- package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +21 -0
- package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +1 -0
- package/dist/m/plugins/wire-4N6GYAF6.js +1 -0
- package/dist/m/reader-core-DXYCURFF.js +68 -0
- package/dist/m/route/route-KOCZSEGN.js +1 -0
- package/dist/m/sync/live-sync-J7VMYTKS.js +1 -0
- package/dist/m/ui/index-3JLVI27O.js +1 -0
- package/dist/m/utils/index-4TJCVLT7.js +1 -0
- package/dist/m/vendor/Sortable.vendor-A755ITLN.js +3 -0
- package/dist/m/vendor/Sortable.vendor-A755ITLN.js.LEGAL.txt +1 -0
- package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +6 -0
- package/dist/offline-manifest.json +4034 -0
- package/dist/page/themes/light-1.css +430 -0
- package/dist/server/core.cjs +23748 -22855
- package/dist/server/offline-runtime.cjs +4954 -0
- package/dist/server/offline-runtime.mjs +4923 -0
- package/dist/server/rooms.mjs +9 -0
- package/docs/guide.md +1078 -669
- package/entries/all.js +2 -0
- package/entries/clay-data.js +1 -1
- package/entries/clay-dom.js +2 -0
- package/entries/clay-events.js +2 -0
- package/entries/clay-internals.js +2 -0
- package/entries/clay-options.js +2 -0
- package/entries/clay-router.js +2 -0
- package/entries/clay-ui.js +2 -0
- package/entries/clay-utils.js +2 -0
- package/entries/clay.js +2 -0
- package/entries/sap.js +6 -6
- package/fonts/ibm-plex-mono-LICENSE +93 -0
- package/fonts/ibm-plex-mono-latin-300-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-LICENSE +93 -0
- package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/fonts/ibm-plex.css +71 -0
- package/fonts/inter-LICENSE +93 -0
- package/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
- package/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-greek-wght-normal.woff2 +0 -0
- package/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
- package/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
- package/fonts/inter.css +62 -0
- package/fonts/newsreader-LICENSE +93 -0
- package/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
- package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
- package/fonts/newsreader-vietnamese-opsz-normal.woff2 +0 -0
- package/fonts/newsreader.css +26 -0
- package/fonts/work-sans-LICENSE +93 -0
- package/fonts/work-sans-latin-wght-normal.woff2 +0 -0
- package/fonts/work-sans.css +8 -0
- package/package.json +20 -3
- package/packed-contract.json +1 -0
- package/src/attrs/add-from.js +27 -4
- package/src/attrs/save-freeze.js +7 -52
- package/src/core/admin-attrs.js +119 -12
- package/src/core/admin-contenteditable.js +12 -10
- package/src/core/admin-inputs.js +14 -15
- package/src/core/admin-onclick.js +2 -0
- package/src/core/autosave.js +74 -21
- package/src/core/boot-phase.js +2 -1
- package/src/core/conflict-download.js +19 -23
- package/src/core/conflict-notice-ui.js +1173 -0
- package/src/core/conflict-notice.js +140 -697
- package/src/core/download.js +32 -0
- package/src/core/edit-mode.js +147 -14
- package/src/core/etag.js +30 -12
- package/src/core/host-meta.js +90 -8
- package/src/core/host-permission.js +29 -0
- package/src/core/is-edit-mode.js +145 -12
- package/src/core/mode-key.js +125 -0
- package/src/core/mode-lifecycle.js +544 -0
- package/src/core/mode-receipt.js +30 -0
- package/src/core/mode-refusal.js +13 -0
- package/src/core/mode-resources.js +52 -0
- package/src/core/mode-support.js +82 -0
- package/src/core/mode-switch.js +259 -0
- package/src/core/mode-transition.js +112 -0
- package/src/core/page-data-write.js +305 -0
- package/src/core/page-data.js +26 -227
- package/src/core/page-format-wire.js +4 -0
- package/src/core/page-format.js +58 -0
- package/src/core/persist.js +37 -9
- package/src/core/preserve-authored.js +114 -0
- package/src/core/recovery.js +772 -0
- package/src/core/runtime-url.js +105 -0
- package/src/core/save-core.js +113 -12
- package/src/core/save-replace.js +72 -0
- package/src/core/save-size-notice.js +134 -0
- package/src/core/save-size.js +140 -0
- package/src/core/save.js +806 -119
- package/src/core/snapshot.js +159 -11
- package/src/core/source-map.js +157 -9
- package/src/core/unsaved-warning.js +14 -4
- package/src/core/upgrade-run.js +408 -0
- package/src/core/version.js +18 -0
- package/src/lib/assets.js +30 -0
- package/src/lib/autosave-debug-gate.js +50 -0
- package/src/lib/autosave-scheduler.js +140 -0
- package/src/lib/boot-imports.js +8 -0
- package/src/lib/derived.js +3 -1
- package/src/lib/dirty-gate.js +15 -0
- package/src/lib/doc-storage.js +33 -0
- package/src/lib/effect.js +9 -4
- package/src/lib/mutation.js +4 -2
- package/src/lib/offline-runtime.js +226 -0
- package/src/lib/preload.js +48 -0
- package/src/lib/root-attrs.js +1 -1
- package/src/lib/trash.js +18 -0
- package/src/lib/undo/capture-move.js +152 -0
- package/src/live/local-channel.js +61 -0
- package/src/live/local-lane.js +60 -9
- package/src/live/server-lane.js +6 -3
- package/src/loader-logic.js +76 -15
- package/src/loader.js +218 -30
- package/src/page/adopt-boot.js +76 -22
- package/src/page/adopt.js +25 -4
- package/src/page/awareness.js +230 -0
- package/src/page/blocks.js +113 -6
- package/src/page/blocksel.js +20 -4
- package/src/page/board-face.js +13 -0
- package/src/page/board-panel.js +5 -17
- package/src/page/board-style.js +2 -13
- package/src/page/board-view.js +1 -11
- package/src/page/board-views.js +3 -0
- package/src/page/board.js +2 -2
- package/src/page/boot-pack.js +26 -0
- package/src/page/boot.js +237 -0
- package/src/page/chart-tables.js +11 -0
- package/src/page/chart.js +6 -10
- package/src/page/checklist.js +1 -1
- package/src/page/checkpoint-proof.js +289 -0
- package/src/page/chrome.js +431 -63
- package/src/page/csv-import.js +17 -2
- package/src/page/document-title-dom.js +52 -0
- package/src/page/document-title-runtime.js +90 -0
- package/src/page/document-title.js +12 -0
- package/src/page/drag.js +48 -13
- package/src/page/drop.js +2 -1
- package/src/page/editor.js +399 -90
- package/src/page/emoji-data.js +162 -0
- package/src/page/feature-loader.js +72 -0
- package/src/page/features/board.js +21 -0
- package/src/page/features/chart.js +11 -0
- package/src/page/features/code.js +13 -0
- package/src/page/features/dates.js +180 -0
- package/src/page/features/emoji.js +187 -0
- package/src/page/features/media.js +290 -0
- package/src/page/features/mentions.js +188 -0
- package/src/page/features/registry.js +28 -0
- package/src/page/features/table.js +383 -0
- package/src/page/{tool-view.js → features/tool.js} +33 -2
- package/src/page/format-codec.js +215 -0
- package/src/page/format-command.js +9 -0
- package/src/page/format-gate.js +179 -0
- package/src/page/format-host.js +54 -0
- package/src/page/format-level.js +157 -0
- package/src/page/format-native-commands.js +142 -0
- package/src/page/format-native.js +42 -0
- package/src/page/highlight-slot.js +23 -0
- package/src/page/highlight.js +30 -16
- package/src/page/history-intent.js +78 -0
- package/src/page/inline.js +45 -28
- package/src/page/items.js +67 -14
- package/src/page/link.js +1 -0
- package/src/page/markdown.js +112 -3
- package/src/page/media-views.js +3 -0
- package/src/page/media.js +33 -245
- package/src/page/mention-picker.js +99 -0
- package/src/page/merge.js +1 -1
- package/src/page/outline-cache.js +11 -0
- package/src/page/placeholder.js +27 -7
- package/src/page/projection.js +240 -51
- package/src/page/reader-patch.js +306 -0
- package/src/page/recover.js +1 -1
- package/src/page/rich/page-tool.js +1 -4
- package/src/page/runtime-owner.js +27 -0
- package/src/page/save-projection.js +46 -4
- package/src/page/save-states.js +1 -1
- package/src/page/schema.js +47 -0
- package/src/page/table-rect-key.js +3 -0
- package/src/page/table-select.js +4 -3
- package/src/page/table-style.js +1 -1
- package/src/page/table-views.js +3 -0
- package/src/page/table.js +8 -293
- package/src/page/themes/content.css +25 -1
- package/src/page/themes/light-1.css +163 -2
- package/src/page/themes/light-1.source.css +269 -0
- package/src/page/tool-capability.js +3 -0
- package/src/page/tool-views.js +3 -0
- package/src/page/view-hooks.js +32 -0
- package/src/page/view.js +390 -107
- package/src/page/ybind/awareness.js +172 -0
- package/src/page/ybind/binding.js +40 -5
- package/src/page/ybind/bridge.js +50 -47
- package/src/page/ybind/decode.js +52 -19
- package/src/page/ybind/doc.js +27 -2
- package/src/page/ybind/group.js +12 -3
- package/src/page/ybind/index.js +2 -0
- package/src/page/ybind/lineage.js +71 -0
- package/src/page/ybind/marks.js +26 -1
- package/src/page/ybind/migrate.js +48 -13
- package/src/page/ybind/moves.js +32 -21
- package/src/page/ybind/positions.js +50 -0
- package/src/page/ybind/provider.js +97 -24
- package/src/page/ybind/recovery-proof.js +191 -0
- package/src/page/ybind/recovery-replay.js +488 -0
- package/src/page/ybind/tokens.js +15 -6
- package/src/page/ybind/walk.js +10 -3
- package/src/page/ybind/writer.js +48 -4
- package/src/plugins/ai-edit.js +167 -32
- package/src/plugins/bind-text.js +218 -0
- package/src/plugins/cms.js +93 -0
- package/src/plugins/indicator.js +57 -5
- package/src/plugins/live.js +319 -35
- package/src/plugins/menu/claygoo.svg.js +1 -0
- package/src/plugins/menu/seo-head.js +323 -0
- package/src/plugins/menu/seo.js +849 -0
- package/src/plugins/menu.js +425 -0
- package/src/plugins/page-view.js +131 -0
- package/src/plugins/page.js +1131 -270
- package/src/plugins/people.js +158 -31
- package/src/plugins/richclay.js +119 -9
- package/src/plugins/sortable.js +370 -60
- package/src/plugins/source.js +189 -366
- package/src/plugins/undo.js +289 -19
- package/src/plugins/unsent.js +132 -0
- package/src/plugins/upgrade-run.js +1 -0
- package/src/plugins/upgrade.js +210 -0
- package/src/plugins/upload-task.js +571 -0
- package/src/plugins/upload-ui.js +265 -0
- package/src/plugins/upload.js +34 -153
- package/src/plugins/visitor-drafts/inert.js +32 -0
- package/src/plugins/visitor-drafts/intro.js +2 -1
- package/src/plugins/visitor-drafts/owner-chip.js +3 -0
- package/src/plugins/visitor-drafts/prompt.js +2 -2
- package/src/plugins/visitor-drafts-owner.js +85 -0
- package/src/plugins/visitor-drafts.js +31 -42
- package/src/plugins/wire.js +82 -1
- package/src/reader-core.js +26 -0
- package/src/recovery/conflicts.js +287 -0
- package/src/recovery/identity.js +154 -0
- package/src/recovery/store.js +792 -0
- package/src/recovery/undo.js +257 -0
- package/src/server/checkpoint/index.js +68 -4
- package/src/server/offline-runtime/index.js +214 -0
- package/src/server/rooms/index.js +2 -1
- package/src/server/rooms/live-data-rooms.js +2 -2
- package/src/server/rooms/page-admission.js +33 -0
- package/src/server/rooms/page-lineage.js +56 -0
- package/src/server/rooms/page-rebase.js +11 -5
- package/src/server/rooms/page-state.js +2 -0
- package/src/server/rooms/page-write-admission.js +9 -3
- package/src/source/session.js +705 -0
- package/src/sync/conflict-revert.js +5 -4
- package/src/sync/conflicts-edit.js +119 -0
- package/src/sync/conflicts-facade.js +49 -0
- package/src/sync/conflicts.js +99 -1
- package/src/sync/editing-marker.js +37 -6
- package/src/sync/editing-sender.js +8 -1
- package/src/sync/live-sync-edit.js +63 -0
- package/src/sync/live-sync.js +364 -119
- package/src/sync/local-presence.js +187 -0
- package/src/sync/merge-declarations.js +10 -0
- package/src/sync/merge-engine.js +12 -0
- package/src/sync/presence-store.js +412 -0
- package/src/sync/presence-target.js +243 -0
- package/src/sync/presence.js +72 -41
- package/src/sync/saved-handoff.js +200 -0
- package/src/sync/saved-stream.js +544 -0
- package/src/sync/version-guard.js +92 -0
- package/src/sync/wire-profile.js +81 -0
- package/src/ui/bevel-controls.js +2 -8
- package/src/ui/page-scheme.js +7 -0
- package/src/ui/skins/cms.js +1 -1
- package/src/ui/theme-config.js +150 -0
- package/src/ui/theme.js +6 -138
- package/src/ui/toast-lazy.js +11 -0
- package/src/vendor/LICENSES-optional.md +253 -0
- package/src/vendor/highlight.vendor.js +3 -0
- package/src/vendor/hljs-bash.vendor.js +2 -0
- package/src/vendor/hljs-css.vendor.js +2 -0
- package/src/vendor/hljs-javascript.vendor.js +2 -0
- package/src/vendor/hljs-json.vendor.js +2 -0
- package/src/vendor/hljs-python.vendor.js +2 -0
- package/src/vendor/hljs-xml.vendor.js +2 -0
- package/src/vendor/hyper-html-api-data.vendor.js +1 -1
- package/src/vendor/hyper-html-api-upgrade.vendor.js +5 -0
- package/src/vendor/hyper-morph-identity.vendor.js +2 -0
- package/src/vendor/hyper-morph-json.vendor.js +3 -0
- package/src/vendor/hyper-morph.vendor.js +6 -6
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +169 -84
- package/src/vendor/marked.vendor.js +68 -0
- package/src/vendor/overtype.vendor.js +994 -0
- package/src/vendor/richclay.vendor.js +17 -17
- package/src/vendor/sap-core.vendor.js +5 -5
- package/src/vendor/sap-ownership.vendor.js +11 -7
package/src/page/projection.js
CHANGED
|
@@ -10,12 +10,33 @@
|
|
|
10
10
|
// pos-keyed maps. parse(render(blocks)) equals project(blocks) for every kind.
|
|
11
11
|
import { chartModel, renderChartSvg } from "./rich/chart.js";
|
|
12
12
|
import { cellText } from "./rich/cell.js";
|
|
13
|
+
import { bounded, descriptors, entriesOf, keyOf, normalizeEntries } from "./format-codec.js";
|
|
14
|
+
import { nativeAttrs } from "./format-native.js";
|
|
13
15
|
|
|
14
16
|
export const ATOM = "";
|
|
15
17
|
export const BREAK = '@{"type":"hard_break"}';
|
|
16
18
|
const CODES = ["b", "i", "s", "c", "a"];
|
|
17
19
|
const TAGS = { b: "strong", i: "em", s: "s", c: "code" };
|
|
18
20
|
const NEST = ["a", "b", "i", "s", "c"];
|
|
21
|
+
const KNOWN = new Set(CODES);
|
|
22
|
+
|
|
23
|
+
// A block or an inline span the runtime has no schema for rides in an inert
|
|
24
|
+
// semantic envelope: canonical JSON, base64url, in one attribute. The block
|
|
25
|
+
// envelope holds the block record, the marks envelope the descriptors of one
|
|
26
|
+
// run, and the visible text stays the readable fallback.
|
|
27
|
+
export const OPAQUE = "data-clay-page-opaque";
|
|
28
|
+
export const VALUE = "data-clay-page-value";
|
|
29
|
+
export const MARKS = "data-clay-page-marks";
|
|
30
|
+
// A person mention's span states its id plainly beside the envelope that carries it:
|
|
31
|
+
// the label is the text, and a reader without the editor shows a name, never a link.
|
|
32
|
+
export const MENTION = "data-page-mention";
|
|
33
|
+
// A date mention reads as a `time` element: the text is the ISO date and `datetime`
|
|
34
|
+
// repeats it, so a reader without the editor shows the day and no zone or reminder.
|
|
35
|
+
export const DATE = "data-page-date";
|
|
36
|
+
const DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
37
|
+
const ENVELOPE = "1";
|
|
38
|
+
const STRUCTURAL = new Set(["id", "t", "parent", "c", "m"]);
|
|
39
|
+
const knownType = (t) => Object.hasOwn(DEFAULTS, t);
|
|
19
40
|
|
|
20
41
|
// Mirrors schema.js attrs minus id and pos (a test pins the two together).
|
|
21
42
|
export const DEFAULTS = {
|
|
@@ -23,6 +44,7 @@ export const DEFAULTS = {
|
|
|
23
44
|
heading: { parent: null, level: 2 },
|
|
24
45
|
list_item: { parent: null, kind: "bullet", indent: 0, checked: false, owner: null, due: null },
|
|
25
46
|
callout: { parent: null },
|
|
47
|
+
quote: { parent: null },
|
|
26
48
|
code_block: { parent: null, lang: "" },
|
|
27
49
|
toggle: { parent: null, open: false },
|
|
28
50
|
divider: { parent: null },
|
|
@@ -34,7 +56,7 @@ export const DEFAULTS = {
|
|
|
34
56
|
tool: { parent: null, artifact: null, rev: null, state: {} },
|
|
35
57
|
preserved: { parent: null, html: "" },
|
|
36
58
|
};
|
|
37
|
-
const TEXT = new Set(["paragraph", "heading", "list_item", "callout", "code_block", "toggle"]);
|
|
59
|
+
const TEXT = new Set(["paragraph", "heading", "list_item", "callout", "quote", "code_block", "toggle"]);
|
|
38
60
|
|
|
39
61
|
const same = (a, b) => canon(a) === canon(b);
|
|
40
62
|
|
|
@@ -48,6 +70,67 @@ export function orderedIds(map) {
|
|
|
48
70
|
});
|
|
49
71
|
}
|
|
50
72
|
|
|
73
|
+
// ---- envelopes --------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
const b64url = (text) => {
|
|
76
|
+
let bin = "";
|
|
77
|
+
for (const byte of new TextEncoder().encode(text)) bin += String.fromCharCode(byte);
|
|
78
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const fromB64url = (text) => {
|
|
82
|
+
const bin = atob(String(text).replace(/-/g, "+").replace(/_/g, "/"));
|
|
83
|
+
return new TextDecoder().decode(Uint8Array.from(bin, (ch) => ch.charCodeAt(0)));
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// A key any object would take as its prototype rather than as data.
|
|
87
|
+
const hostile = (value) => {
|
|
88
|
+
if (value === null || typeof value !== "object") return false;
|
|
89
|
+
if (Array.isArray(value)) return value.some(hostile);
|
|
90
|
+
return Object.keys(value).some((key) => key === "__proto__" || hostile(value[key]));
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// One envelope's JSON, under the codec's budget: deeper or larger refuses the
|
|
94
|
+
// whole source rather than cutting the envelope short.
|
|
95
|
+
function decodeJson(text) {
|
|
96
|
+
let value;
|
|
97
|
+
try { value = JSON.parse(fromB64url(text)); }
|
|
98
|
+
catch { throw new SyntaxError("page: an envelope is not readable canonical JSON"); }
|
|
99
|
+
try { bounded(value); }
|
|
100
|
+
catch (error) { throw new SyntaxError(error.message); }
|
|
101
|
+
if (hostile(value)) throw new SyntaxError("page: an envelope holds a prototype key");
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// A block envelope: a record, whose own type and structural fields are kept
|
|
106
|
+
// apart from it.
|
|
107
|
+
function recordOf(text) {
|
|
108
|
+
const value = decodeJson(text);
|
|
109
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new SyntaxError("page: a block envelope is not a record");
|
|
110
|
+
if ("id" in value || "pos" in value) throw new SyntaxError("page: a block envelope holds a structural field");
|
|
111
|
+
if ("t" in value && (typeof value.t !== "string" || !value.t)) throw new SyntaxError("page: a block envelope names no type");
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// A marks envelope: the descriptors of one run, validated and put back in the
|
|
116
|
+
// codec's canonical order however they arrived.
|
|
117
|
+
function entriesOfEnvelope(text) {
|
|
118
|
+
try { return normalizeEntries(decodeJson(text)); }
|
|
119
|
+
catch (error) { throw error instanceof SyntaxError ? error : new SyntaxError(error.message); }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// The entries of a marks envelope as it arrived, validated by the same reader
|
|
123
|
+
// the article uses.
|
|
124
|
+
export const marksEntries = (text) => entriesOfEnvelope(text);
|
|
125
|
+
|
|
126
|
+
const envelopeOf = (value) => ` ${OPAQUE}="${ENVELOPE}" ${VALUE}="${escAttr(b64url(canon(value)))}"`;
|
|
127
|
+
const marksEnvelope = (entries) => (entries.length ? ` ${MARKS}="${escAttr(b64url(JSON.stringify(entries)))}"` : "");
|
|
128
|
+
|
|
129
|
+
// The same two envelopes as attribute maps, for the internal rich clipboard,
|
|
130
|
+
// which writes them onto its own elements instead of an article line.
|
|
131
|
+
export const envelopeAttrs = (record) => ({ [OPAQUE]: ENVELOPE, [VALUE]: b64url(canon(record)) });
|
|
132
|
+
export const marksAttrs = (entries) => ({ [MARKS]: b64url(JSON.stringify(normalizeEntries(entries))) });
|
|
133
|
+
|
|
51
134
|
// ---- marks ------------------------------------------------------------------
|
|
52
135
|
|
|
53
136
|
// inline.js unitsOf: runs [[n, key]] or per-unit keys -> one key per unit, or null.
|
|
@@ -72,28 +155,36 @@ export function runsOf(units) {
|
|
|
72
155
|
return out;
|
|
73
156
|
}
|
|
74
157
|
|
|
75
|
-
// A mark key as { b: true, a: ["href"] ... }
|
|
158
|
+
// A mark key as { marks: { b: true, a: ["href"] ... }, native: [...], entries: [...] }:
|
|
159
|
+
// the codes this runtime knows, the named descriptors of the four formats it
|
|
160
|
+
// writes (format-native.js), and the entries of every mark it has no code for,
|
|
161
|
+
// each in the codec's canonical order.
|
|
76
162
|
function marksOfKey(key) {
|
|
77
|
-
const
|
|
78
|
-
if (!key || key[0] === "@") return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
out[code] = JSON.parse(key.slice(i, j));
|
|
91
|
-
i = j;
|
|
92
|
-
} else out[code] = true;
|
|
163
|
+
const marks = {}, native = [];
|
|
164
|
+
if (!key || key[0] === "@") return { marks, native: [], entries: [] };
|
|
165
|
+
const opaque = [];
|
|
166
|
+
for (const desc of descriptors(key)) {
|
|
167
|
+
if (desc.name === undefined) {
|
|
168
|
+
if (KNOWN.has(desc.code)) marks[desc.code] = desc.attrs ?? true;
|
|
169
|
+
else opaque.push(desc);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const attrs = nativeAttrs(desc.name, desc.attrs);
|
|
173
|
+
if (attrs) native.push({ name: desc.name, attrs });
|
|
174
|
+
else opaque.push(desc);
|
|
93
175
|
}
|
|
94
|
-
return
|
|
176
|
+
return { marks, native, entries: opaque.length ? entriesOf(opaque) : [] };
|
|
95
177
|
}
|
|
96
178
|
|
|
179
|
+
// One unit's key, as the record keeps it: the codes this runtime knows, then
|
|
180
|
+
// every descriptor it keeps for a newer runtime.
|
|
181
|
+
const unitKey = (key, text, i) => {
|
|
182
|
+
if (!key) return "";
|
|
183
|
+
if (key[0] === "@") return key === BREAK && text[i] === ATOM ? key : "";
|
|
184
|
+
const { marks, native, entries } = marksOfKey(key);
|
|
185
|
+
return keyOfMarks(safeMarks(marks), native.length ? [...entries, ...entriesOf(native)] : entries);
|
|
186
|
+
};
|
|
187
|
+
|
|
97
188
|
// A link to a script URL is never kept: it would run on the page's origin when a
|
|
98
189
|
// reader clicks it in the saved article.
|
|
99
190
|
const SCRIPT_URL = /^(javascript|vbscript|data):/i;
|
|
@@ -102,14 +193,14 @@ const safeMarks = (marks) => {
|
|
|
102
193
|
return marks;
|
|
103
194
|
};
|
|
104
195
|
|
|
105
|
-
function keyOfMarks(marks) {
|
|
196
|
+
function keyOfMarks(marks, entries = []) {
|
|
106
197
|
let key = "";
|
|
107
198
|
for (const code of CODES) {
|
|
108
199
|
if (!marks[code]) continue;
|
|
109
200
|
key += code;
|
|
110
201
|
if (Array.isArray(marks[code])) key += JSON.stringify(marks[code]);
|
|
111
202
|
}
|
|
112
|
-
return key;
|
|
203
|
+
return entries.length ? key + keyOf(entries) : key;
|
|
113
204
|
}
|
|
114
205
|
|
|
115
206
|
// ---- text normalization -----------------------------------------------------
|
|
@@ -175,7 +266,7 @@ function layout(blocks) {
|
|
|
175
266
|
let prev = null;
|
|
176
267
|
for (const id of orderedIds(blocks)) {
|
|
177
268
|
const b = blocks[id];
|
|
178
|
-
const t =
|
|
269
|
+
const t = typeof b.t === "string" && b.t ? b.t : null;
|
|
179
270
|
let parent = b.parent ?? null;
|
|
180
271
|
if (parent !== null) {
|
|
181
272
|
const at = stack.lastIndexOf(parent);
|
|
@@ -207,7 +298,7 @@ const columnWidth = (value) => (typeof value === "number" && Number.isFinite(val
|
|
|
207
298
|
function cellModel(value) {
|
|
208
299
|
if (value === null || typeof value !== "object" || typeof value.c !== "string") return normalizeText(cellText(value), null).c;
|
|
209
300
|
const raw = unitsOf(value.m, value.c.length);
|
|
210
|
-
const units = raw && raw.map((k, i) => (
|
|
301
|
+
const units = raw && raw.map((k, i) => unitKey(k, value.c, i));
|
|
211
302
|
if (!units) return normalizeText(cellText(value), null).c;
|
|
212
303
|
const n = normalizeText(value.c, units);
|
|
213
304
|
const fields = textFields(n.c, n.units);
|
|
@@ -240,10 +331,44 @@ function projectBoard(b) {
|
|
|
240
331
|
};
|
|
241
332
|
}
|
|
242
333
|
|
|
334
|
+
// The record a block envelope carries: its own type first, then every field the
|
|
335
|
+
// runtime keeps for the block, extras included.
|
|
336
|
+
const recordOfItem = (item) => {
|
|
337
|
+
const { t, parent: _p, id: _i, ...fields } = item;
|
|
338
|
+
return { t, ...fields };
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// The fields of a known block the runtime has no schema attribute for. They are
|
|
342
|
+
// merged back only when serialized, inside the inert payload.
|
|
343
|
+
const extrasOfItem = (item) => {
|
|
344
|
+
const out = {};
|
|
345
|
+
for (const [k, v] of Object.entries(item)) if (!STRUCTURAL.has(k) && !(knownType(item.t) && Object.hasOwn(DEFAULTS[item.t], k))) out[k] = v;
|
|
346
|
+
return Object.keys(out).length ? envelopeOf(out) : "";
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
const extrasOfBlock = (t, b) => {
|
|
350
|
+
const out = {};
|
|
351
|
+
for (const [k, v] of Object.entries(b)) if (!STRUCTURAL.has(k) && k !== "pos" && !Object.hasOwn(DEFAULTS[t], k)) out[k] = v;
|
|
352
|
+
return out;
|
|
353
|
+
};
|
|
354
|
+
|
|
243
355
|
function projectOne({ id, b, t, parent, indent }) {
|
|
244
356
|
if (!t) return { id, t: "preserved", html: "" };
|
|
245
|
-
|
|
246
|
-
|
|
357
|
+
if (!knownType(t)) {
|
|
358
|
+
const { t: _t, id: _id, pos: _pos, parent: _p, ...rest } = b;
|
|
359
|
+
// The text and its marks are kept as they stand, but marks in the older
|
|
360
|
+
// per-unit form come back as runs, so one record has one revision whichever
|
|
361
|
+
// form it was written in.
|
|
362
|
+
if (typeof rest.c === "string" && rest.m !== undefined) {
|
|
363
|
+
const units = unitsOf(rest.m, rest.c.length);
|
|
364
|
+
if (units && units.some(Boolean)) rest.m = runsOf(units);
|
|
365
|
+
else delete rest.m;
|
|
366
|
+
}
|
|
367
|
+
return { id, t, ...(parent ? { parent } : {}), ...rest };
|
|
368
|
+
}
|
|
369
|
+
const { t: _t, id: _id, pos, c, m, rows, cols, columns, cards, parent: _p, indent: _i, ...attrs } = b;
|
|
370
|
+
const extras = extrasOfBlock(t, attrs);
|
|
371
|
+
for (const k of Object.keys(extras)) delete attrs[k];
|
|
247
372
|
const fields = { ...attrs, parent };
|
|
248
373
|
if (t === "list_item") fields.indent = indent;
|
|
249
374
|
if (t === "heading") fields.level = clampLevel(attrs.level ?? 2);
|
|
@@ -253,13 +378,13 @@ function projectOne({ id, b, t, parent, indent }) {
|
|
|
253
378
|
if (t === "chart" && typeof fields.title === "string") fields.title = normalizeText(fields.title, null).c;
|
|
254
379
|
if (t === "table") Object.assign(fields, projectTable(b));
|
|
255
380
|
else if (t === "board") Object.assign(fields, projectBoard(b));
|
|
256
|
-
const item = { id, t, ...omitDefaults(t, fields) };
|
|
381
|
+
const item = { id, t, ...omitDefaults(t, fields), ...extras };
|
|
257
382
|
if (t === "table") { item.cols = fields.cols; item.rows = fields.rows; }
|
|
258
383
|
if (t === "board") { item.columns = fields.columns; item.cards = fields.cards; }
|
|
259
384
|
if (TEXT.has(t)) {
|
|
260
385
|
const text = typeof c === "string" ? c : "";
|
|
261
386
|
const raw = unitsOf(m, text.length);
|
|
262
|
-
const units = raw && raw.map((k, i) => (
|
|
387
|
+
const units = raw && raw.map((k, i) => unitKey(k, text, i));
|
|
263
388
|
if (t === "code_block") Object.assign(item, { c: text.replace(/\r\n?/g, "\n") });
|
|
264
389
|
else {
|
|
265
390
|
const n = normalizeText(text, units);
|
|
@@ -301,7 +426,11 @@ const escText = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>
|
|
|
301
426
|
const escAttr = (s) => escText(String(s)).replace(/"/g, """);
|
|
302
427
|
const attr = (name, value) => (value === null || value === undefined ? "" : ` ${name}="${escAttr(value)}"`);
|
|
303
428
|
|
|
304
|
-
|
|
429
|
+
// The element each of the four formats is read as in the saved article; the
|
|
430
|
+
// text color and the highlight carry their palette key as data-color.
|
|
431
|
+
const NATIVE_TAGS = { underline: "u", text_color: "span", highlight: "mark" };
|
|
432
|
+
|
|
433
|
+
export function renderInline(c, m, marksEnvelopes = true) {
|
|
305
434
|
const units = unitsOf(m, c.length) || [];
|
|
306
435
|
let html = "";
|
|
307
436
|
const open = [];
|
|
@@ -316,12 +445,22 @@ export function renderInline(c, m) {
|
|
|
316
445
|
}
|
|
317
446
|
let j = i + 1;
|
|
318
447
|
while (j < c.length && (units[j] || "") === key && !(c[j] === ATOM && key[0] === "@")) j++;
|
|
319
|
-
const marks = marksOfKey(key);
|
|
448
|
+
const { marks, native, entries } = marksOfKey(key);
|
|
320
449
|
const want = NEST.filter((code) => marks[code]).map((code) => ({ code, sig: code + JSON.stringify(marks[code]), tag: code === "a" ? "a" : TAGS[code], href: code === "a" ? marks.a[0] : null }));
|
|
450
|
+
for (const n of native) want.push({ sig: `native${n.name}${canon(n.attrs)}`, tag: NATIVE_TAGS[n.name], color: n.attrs.color ?? null });
|
|
451
|
+
const mention = entries.find((entry) => entry.name === "mention");
|
|
452
|
+
const date = entries.find((entry) => entry.name === "date");
|
|
453
|
+
const day = date && DAY.test(String(date.attrs.date)) ? String(date.attrs.date) : null;
|
|
454
|
+
if (entries.length && marksEnvelopes) want.push({ sig: `marks${canon(entries)}`, tag: day ? "time" : "span", entries, mention: mention?.attrs.id, day });
|
|
321
455
|
let keep = 0;
|
|
322
456
|
while (keep < open.length && keep < want.length && open[keep].sig === want[keep].sig) keep++;
|
|
323
457
|
closeTo(keep);
|
|
324
|
-
for (const w of want.slice(keep)) {
|
|
458
|
+
for (const w of want.slice(keep)) {
|
|
459
|
+
if (w.entries) html += w.day ? `<time${attr("datetime", w.day)}${attr(DATE, "")}${marksEnvelope(w.entries)}>` : `<span${marksEnvelope(w.entries)}${attr(MENTION, w.mention)}>`;
|
|
460
|
+
else if (w.tag === "a") html += `<a${attr("href", w.href)}>`;
|
|
461
|
+
else html += w.color ? `<${w.tag}${attr("data-color", w.color)}>` : `<${w.tag}>`;
|
|
462
|
+
open.push(w);
|
|
463
|
+
}
|
|
325
464
|
html += escText(c.slice(i, j));
|
|
326
465
|
i = j;
|
|
327
466
|
}
|
|
@@ -338,26 +477,29 @@ const dataAttrs = (obj) => Object.entries(obj).map(([k, v]) => attr(`data-${k}`,
|
|
|
338
477
|
|
|
339
478
|
function renderLeaf(item, clean, tables) {
|
|
340
479
|
const id = attr("data-id", item.id);
|
|
480
|
+
if (!knownType(item.t)) return `<div${id}${envelopeOf(recordOfItem(item))}>${renderInline(item.c ?? "", item.m, false)}</div>`;
|
|
481
|
+
const at = id + extrasOfItem(item);
|
|
341
482
|
switch (item.t) {
|
|
342
|
-
case "paragraph": return `<p${
|
|
343
|
-
case "heading": { const h = `h${item.level ?? 2}`; return `<${h}${
|
|
344
|
-
case "callout": return `<aside${
|
|
345
|
-
case "
|
|
346
|
-
case "
|
|
347
|
-
case "
|
|
483
|
+
case "paragraph": return `<p${at}>${inlineOf(item)}</p>`;
|
|
484
|
+
case "heading": { const h = `h${item.level ?? 2}`; return `<${h}${at}>${inlineOf(item)}</${h}>`; }
|
|
485
|
+
case "callout": return `<aside${at} class="page-callout">${inlineOf(item)}</aside>`;
|
|
486
|
+
case "quote": return `<blockquote${at}>${inlineOf(item)}</blockquote>`;
|
|
487
|
+
case "code_block": return `<pre${at}${attr("data-lang", item.lang || null)}><code>${escText(item.c ?? "")}</code></pre>`;
|
|
488
|
+
case "divider": return `<hr${at}>`;
|
|
489
|
+
case "image": return `<figure${at} data-type="image"${attr("data-align", item.align ?? null)}><img${attr("src", item.src ?? "")}${attr("alt", item.alt ?? "")}${attr("width", item.width ?? null)}>${item.caption ? `<figcaption>${escText(item.caption)}</figcaption>` : ""}</figure>`;
|
|
348
490
|
case "file": {
|
|
349
491
|
const href = /^(https?:\/\/|\/(?!\/))/i.test(item.src ?? "") ? item.src : null;
|
|
350
|
-
return `<div${
|
|
492
|
+
return `<div${at} data-type="file"${attr("data-src", item.src ?? "")}${attr("data-name", item.name ?? "")}${attr("data-size", item.size ?? null)}${attr("data-mime", item.mime ?? null)}><a${attr("href", href)} rel="noopener noreferrer">${escText(item.name || "file")}</a></div>`;
|
|
351
493
|
}
|
|
352
494
|
case "table": {
|
|
353
495
|
const head = item.cols.map((c) => `<th${attr("data-col", c.id)}${attr("data-kind", c.kind ?? null)}${attr("data-width", c.width ?? null)}${attr("style", c.width ? `width:${c.width}px` : null)}>${escText(c.name)}</th>`).join("");
|
|
354
496
|
const body = item.rows.map((r) => `<tr${attr("data-id", r.id)}>${item.cols.map((c) => `<td>${cellHtml(r.cells[c.id])}</td>`).join("")}</tr>`).join("\n");
|
|
355
|
-
return `<table${
|
|
497
|
+
return `<table${at}${attr("data-sort", item.sort != null ? JSON.stringify(item.sort) : null)}>\n<thead><tr>${head}</tr></thead>\n<tbody>\n${body}\n</tbody>\n</table>`;
|
|
356
498
|
}
|
|
357
499
|
case "chart": {
|
|
358
500
|
const data = dataAttrs({ source: item.source ?? null, kind: item.kind ?? null, x: item.x ?? null, series: item.series ? JSON.stringify(item.series) : null, highlight: item.highlight ?? null });
|
|
359
501
|
const chart = chartModel({ id: item.id, type: item.kind ?? "line", x: item.x, series: item.series ?? [], title: item.title ?? "", highlight: item.highlight }, tables.get(item.source));
|
|
360
|
-
return `<figure${
|
|
502
|
+
return `<figure${at} data-type="chart"${data}>${renderChartSvg(chart, { width: 640, height: 320 })}<figcaption>${escText(item.title ?? "")}</figcaption></figure>`;
|
|
361
503
|
}
|
|
362
504
|
case "board": {
|
|
363
505
|
const cols = [...item.columns.map((c) => ({ ...c, known: true })), ...[...new Set(item.cards.map((k) => k.col))].filter((col) => !item.columns.some((c) => c.id === col)).map((col) => ({ id: col, known: false }))];
|
|
@@ -365,16 +507,16 @@ function renderLeaf(item, clean, tables) {
|
|
|
365
507
|
const cards = item.cards.filter((k) => k.col === col.id).map((k) => `<li${attr("data-id", k.id)}${attr("data-owner", k.owner ?? null)}${attr("data-due", k.due ?? null)}>${escText(k.title)}</li>`).join("");
|
|
366
508
|
return `<div${attr("data-col", col.id)}${col.known ? "" : " data-missing"}>${col.known ? `<h4>${escText(col.name)}</h4>` : ""}<ul>${cards}</ul></div>`;
|
|
367
509
|
});
|
|
368
|
-
return `<section${
|
|
510
|
+
return `<section${at} data-type="board">\n${parts.join("\n")}\n</section>`;
|
|
369
511
|
}
|
|
370
|
-
case "tool": return `<section${
|
|
371
|
-
case "preserved": return preservedHtml(item, clean);
|
|
512
|
+
case "tool": return `<section${at} data-type="tool">${toolData(item)}</section>`;
|
|
513
|
+
case "preserved": return preservedHtml(item, clean, at);
|
|
372
514
|
default: return "";
|
|
373
515
|
}
|
|
374
516
|
}
|
|
375
517
|
|
|
376
518
|
// Markup the schema has no node for, kept as authored inside a marked wrapper.
|
|
377
|
-
const preservedHtml = (item, clean
|
|
519
|
+
const preservedHtml = (item, clean, id = attr("data-id", item.id)) => `<div${id} data-type="preserved">${clean.preserved(item.html || "")}</div>`;
|
|
378
520
|
|
|
379
521
|
const RAW = { preserved: (html) => html, fallback: (html) => html };
|
|
380
522
|
|
|
@@ -423,11 +565,11 @@ export function renderModel(model, { fallbackOf = () => "", clean = RAW } = {})
|
|
|
423
565
|
}
|
|
424
566
|
if (lists.length < d + 1) { add(`<${tag}>`); lists.push(tag); }
|
|
425
567
|
const box = item.kind === "check" ? `<input type="checkbox" disabled${item.checked ? " checked" : ""}>` : "";
|
|
426
|
-
add(`<li${attr("data-id", item.id)}${attr("data-owner", item.owner ?? null)}${attr("data-due", item.due ?? null)}>${box}${inlineOf(item)}`);
|
|
568
|
+
add(`<li${attr("data-id", item.id)}${attr("data-owner", item.owner ?? null)}${attr("data-due", item.due ?? null)}${extrasOfItem(item)}>${box}${inlineOf(item)}`);
|
|
427
569
|
continue;
|
|
428
570
|
}
|
|
429
571
|
if (item.t === "toggle") {
|
|
430
|
-
add(`<details${attr("data-id", item.id)}${item.open ? " open" : ""}><summary>${inlineOf(item)}</summary>`);
|
|
572
|
+
add(`<details${attr("data-id", item.id)}${extrasOfItem(item)}${item.open ? " open" : ""}><summary>${inlineOf(item)}</summary>`);
|
|
431
573
|
stack.push(item.id);
|
|
432
574
|
continue;
|
|
433
575
|
}
|
|
@@ -449,16 +591,27 @@ export function renderBlocks(blocks, opts) {
|
|
|
449
591
|
const DROP_TAGS = new Set(["SCRIPT", "STYLE", "TEMPLATE", "NOSCRIPT"]);
|
|
450
592
|
const INLINE_TAGS = new Set(["A", "ABBR", "B", "BDI", "BDO", "BR", "CITE", "CODE", "DATA", "DEL", "DFN", "EM", "FONT", "I", "INS", "KBD", "LABEL", "MARK", "Q", "S", "SAMP", "SMALL", "SPAN", "STRIKE", "STRONG", "SUB", "SUP", "TIME", "U", "VAR", "WBR"]);
|
|
451
593
|
|
|
594
|
+
// The named descriptor an inline element stands for, when it is one of the four
|
|
595
|
+
// formats: <u>, <mark> and a <span data-color> with a palette key. Anything else
|
|
596
|
+
// is not a format this runtime reads natively.
|
|
597
|
+
function nativeOfEl(tag, el) {
|
|
598
|
+
if (tag === "u") return { name: "underline", attrs: {} };
|
|
599
|
+
if (tag !== "mark" && tag !== "span") return null;
|
|
600
|
+
if (tag === "span" && !el.hasAttribute("data-color")) return null;
|
|
601
|
+
const name = tag === "mark" ? "highlight" : "text_color";
|
|
602
|
+
return { name, attrs: { color: el.getAttribute("data-color") } };
|
|
603
|
+
}
|
|
604
|
+
|
|
452
605
|
// Inline content of el as { c, units }, minus the children skip(child) names.
|
|
453
606
|
function inlineOfEl(el, skip = () => false) {
|
|
454
607
|
let c = "";
|
|
455
608
|
const units = [];
|
|
456
|
-
const walk = (node, marks) => {
|
|
609
|
+
const walk = (node, marks, entries) => {
|
|
457
610
|
for (const child of node.childNodes) {
|
|
458
611
|
if (skip(child)) continue;
|
|
459
612
|
if (child.nodeType === 3) {
|
|
460
613
|
c += child.data;
|
|
461
|
-
const key = keyOfMarks(safeMarks({ ...marks }));
|
|
614
|
+
const key = keyOfMarks(safeMarks({ ...marks }), entries);
|
|
462
615
|
for (let i = 0; i < child.data.length; i++) units.push(key);
|
|
463
616
|
continue;
|
|
464
617
|
}
|
|
@@ -467,20 +620,45 @@ function inlineOfEl(el, skip = () => false) {
|
|
|
467
620
|
if (tag === "br") { c += ATOM; units.push(BREAK); continue; }
|
|
468
621
|
if (tag === "span" && child.hasAttribute("data-atom")) { c += ATOM; units.push(child.getAttribute("data-atom")); continue; }
|
|
469
622
|
const next = { ...marks };
|
|
623
|
+
if ((tag === "span" || tag === "time") && child.hasAttribute(MARKS)) {
|
|
624
|
+
walk(child, next, normalizeEntries([...entries, ...entriesOfEnvelope(child.getAttribute(MARKS))]));
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
470
627
|
if (tag === "strong" || tag === "b") next.b = true;
|
|
471
628
|
else if (tag === "em" || tag === "i") next.i = true;
|
|
472
629
|
else if (tag === "s" || tag === "del" || tag === "strike") next.s = true;
|
|
473
630
|
else if (tag === "code") next.c = true;
|
|
474
631
|
else if (tag === "a" && child.hasAttribute("href")) next.a = [child.getAttribute("href")];
|
|
475
|
-
|
|
632
|
+
const named = nativeOfEl(tag, child);
|
|
633
|
+
walk(child, next, named ? [...entries, named] : entries);
|
|
476
634
|
}
|
|
477
635
|
};
|
|
478
|
-
walk(el, {});
|
|
636
|
+
walk(el, {}, []);
|
|
479
637
|
return normalizeText(c, units);
|
|
480
638
|
}
|
|
481
639
|
|
|
482
640
|
const text = (el) => normalizeText(el ? el.textContent : "", null).c;
|
|
483
641
|
|
|
642
|
+
// The block envelope an element carries, or null. A malformed, oversized or
|
|
643
|
+
// hostile one refuses the whole article: it never falls back to plain text.
|
|
644
|
+
const envelopeAt = (el) => {
|
|
645
|
+
if (!el.hasAttribute(OPAQUE)) return null;
|
|
646
|
+
if (el.getAttribute(OPAQUE) !== ENVELOPE) throw new SyntaxError(`page: unknown envelope version ${el.getAttribute(OPAQUE)}`);
|
|
647
|
+
const text = el.getAttribute(VALUE);
|
|
648
|
+
if (text === null) throw new SyntaxError("page: a block envelope holds no value");
|
|
649
|
+
return recordOf(text);
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
// The record a block envelope carries, validated; null when the element carries
|
|
653
|
+
// no envelope at all.
|
|
654
|
+
export const envelopeRecord = (el) => envelopeAt(el);
|
|
655
|
+
|
|
656
|
+
// The extras a known element's envelope adds to it.
|
|
657
|
+
const extrasAt = (el) => {
|
|
658
|
+
const value = envelopeAt(el);
|
|
659
|
+
return value && typeof value.t !== "string" ? value : null;
|
|
660
|
+
};
|
|
661
|
+
|
|
484
662
|
export function parseArticle(article) {
|
|
485
663
|
const items = [];
|
|
486
664
|
const walk = (container, parent) => {
|
|
@@ -506,7 +684,10 @@ export function parseArticle(article) {
|
|
|
506
684
|
flushLoose();
|
|
507
685
|
};
|
|
508
686
|
const idOf = (el) => el.getAttribute("data-id") || null;
|
|
509
|
-
const push = (el, t, parent, fields) =>
|
|
687
|
+
const push = (el, t, parent, fields) => {
|
|
688
|
+
const extra = extrasAt(el);
|
|
689
|
+
items.push({ id: idOf(el), t, parent, ...(extra ? { ...extra, ...fields } : fields) });
|
|
690
|
+
};
|
|
510
691
|
const list = (el, parent, depth) => {
|
|
511
692
|
for (const li of el.children) {
|
|
512
693
|
if (li.tagName !== "LI") continue;
|
|
@@ -515,17 +696,25 @@ export function parseArticle(article) {
|
|
|
515
696
|
const n = inlineOfEl(li, (child) => child === box || nested.includes(child));
|
|
516
697
|
const kind = box ? "check" : el.tagName === "OL" ? "ordered" : "bullet";
|
|
517
698
|
const fields = { parent, kind, indent: depth, checked: !!(box && box.hasAttribute("checked")), owner: li.getAttribute("data-owner"), due: li.getAttribute("data-due") };
|
|
518
|
-
items.push({ id: idOf(li), t: "list_item", ...omitDefaults("list_item", fields), ...textFields(n.c, n.units) });
|
|
699
|
+
items.push({ id: idOf(li), t: "list_item", ...omitDefaults("list_item", fields), ...(extrasAt(li) ?? {}), ...textFields(n.c, n.units) });
|
|
519
700
|
for (const sub of nested) list(sub, parent, depth + 1);
|
|
520
701
|
}
|
|
521
702
|
};
|
|
522
703
|
const blockOf = (el, parent) => {
|
|
523
704
|
const tag = el.tagName;
|
|
524
705
|
const P = { parent };
|
|
706
|
+
const record = envelopeAt(el);
|
|
707
|
+
if (record && typeof record.t === "string") {
|
|
708
|
+
if (knownType(record.t) || record.t === "opaque_block") throw new SyntaxError(`page: an envelope names the known block type ${record.t}`);
|
|
709
|
+
const { t, ...fields } = record;
|
|
710
|
+
items.push({ id: idOf(el), t, parent, ...fields });
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
525
713
|
const onlyImage = tag === "P" && el.children.length === 1 && el.children[0].tagName === "IMG" && !el.textContent.trim();
|
|
526
714
|
if (tag === "P" && !onlyImage) return push(el, "paragraph", parent, { ...omitDefaults("paragraph", P), ...tf(el) });
|
|
527
715
|
if (/^H[1-6]$/.test(tag)) return push(el, "heading", parent, { ...omitDefaults("heading", { ...P, level: +tag[1] }), ...tf(el) });
|
|
528
716
|
if (tag === "ASIDE") return push(el, "callout", parent, { ...omitDefaults("callout", P), ...tf(el) });
|
|
717
|
+
if (tag === "BLOCKQUOTE") return push(el, "quote", parent, { ...omitDefaults("quote", P), ...tf(el) });
|
|
529
718
|
if (tag === "PRE") {
|
|
530
719
|
const code = el.querySelector(":scope > code");
|
|
531
720
|
return push(el, "code_block", parent, { ...omitDefaults("code_block", { ...P, lang: el.getAttribute("data-lang") || "" }), c: (code || el).textContent });
|