@panphora/clayjs 1.15.2 → 1.16.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 +83090 -58706
- 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-NWPPXOCZ.js +1 -0
- package/dist/m/attrs/save-freeze-FUP4Q4X3.js +1 -0
- package/dist/m/c-2AZDZWCK.js +1 -0
- package/dist/m/c-2JL6E75N.js +1 -0
- package/dist/m/c-2M73252O.js +1 -0
- package/dist/m/c-2SPVQSHC.js +1 -0
- package/dist/m/c-33HUYEDI.js +1 -0
- package/dist/m/c-33JJ6CBX.js +2 -0
- package/dist/m/c-35NBGMZB.js +1 -0
- package/dist/m/c-3GJ4SDE2.js +1 -0
- package/dist/m/c-3IQRECYS.js +1 -0
- package/dist/m/c-3OWDMNJR.js +2 -0
- package/dist/m/c-46XYM55L.js +1 -0
- package/dist/m/c-4B6H4G5V.js +1 -0
- package/dist/m/c-4DRMS4QG.js +9 -0
- package/dist/m/c-4FFHZM32.js +1 -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-4YSCRICO.js +1 -0
- package/dist/m/c-54RCDCBU.js +1 -0
- package/dist/m/c-5M4YEKCX.js +4 -0
- package/dist/m/c-5R4PTRG2.js +1 -0
- package/dist/m/c-5V3MOVJT.js +1 -0
- package/dist/m/c-5VYOWDTI.js +1 -0
- package/dist/m/c-5Y6TNX5W.js +34 -0
- package/dist/m/c-5YIHJ3TJ.js +1 -0
- package/dist/m/c-66O32MV3.js +28 -0
- package/dist/m/c-6HMB24EV.js +1 -0
- package/dist/m/c-7DJDKPGL.js +1 -0
- package/dist/m/c-7O6AFR65.js +1 -0
- package/dist/m/c-7SWMYKAI.js +1 -0
- package/dist/m/c-7VGZ7RU5.js +1 -0
- package/dist/m/c-A7LS5UZW.js +1 -0
- package/dist/m/c-ANQTJ3B5.js +2 -0
- package/dist/m/c-AQLFEATB.js +1 -0
- package/dist/m/c-AYVOREBE.js +1 -0
- package/dist/m/c-B2ZXPOS3.js +3 -0
- package/dist/m/c-BBVGTQG7.js +1 -0
- package/dist/m/c-BMIZKMPV.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-CJZSLMVQ.js +1 -0
- package/dist/m/c-CYWLPPUS.js +1 -0
- package/dist/m/c-CZUSOB7V.js +1 -0
- package/dist/m/c-DBE6ORSI.js +1 -0
- package/dist/m/c-DCFSEJZG.js +1 -0
- package/dist/m/c-DNZ5IFM6.js +1 -0
- package/dist/m/c-EDHUR4MX.js +1 -0
- package/dist/m/c-EJTGYSLN.js +1 -0
- package/dist/m/c-EY6UOM54.js +1 -0
- package/dist/m/c-F3CKJTJS.js +1 -0
- package/dist/m/c-F7Y6FLPY.js +1 -0
- package/dist/m/c-FA4DZVTC.js +1 -0
- package/dist/m/c-FILLTJA7.js +1 -0
- package/dist/m/c-G2BUZITR.js +1 -0
- package/dist/m/c-GB3JTV6E.js +1 -0
- package/dist/m/c-GBGWXTX4.js +1 -0
- package/dist/m/c-GHBCCVG4.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-H4LG442Q.js +1 -0
- package/dist/m/c-HA6INT6J.js +1 -0
- package/dist/m/c-HPURYVZS.js +2 -0
- package/dist/m/c-HRDCD3WN.js +67 -0
- package/dist/m/c-HT33EQRN.js +1 -0
- package/dist/m/c-HVYXIS72.js +1 -0
- package/dist/m/c-IB52R237.js +1 -0
- package/dist/m/c-IJUK2GPW.js +1 -0
- package/dist/m/c-IKWNE4R4.js +1 -0
- package/dist/m/c-IU3IYEU6.js +1 -0
- package/dist/m/c-IZ2EBRAJ.js +1 -0
- package/dist/m/c-J7CA54IP.js +1 -0
- package/dist/m/c-JAX2667S.js +6 -0
- package/dist/m/c-KI7M4AY3.js +1 -0
- package/dist/m/c-KIPQJX4B.js +1 -0
- package/dist/m/c-KKWLDOPM.js +1 -0
- package/dist/m/c-KR4UW4KW.js +1 -0
- package/dist/m/c-KY3VJGUA.js +8 -0
- package/dist/m/c-L4WQSC27.js +1 -0
- package/dist/m/c-LFPHCXY3.js +1 -0
- package/dist/m/c-LR4CGEPT.js +91 -0
- package/dist/m/c-LRPUO2MX.js +1 -0
- package/dist/m/c-LTGMXXKO.js +1 -0
- package/dist/m/c-LXENEBV7.js +1 -0
- package/dist/m/c-LZJPNR2W.js +1 -0
- package/dist/m/c-MMUIUUZG.js +2 -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-NMJRXKPC.js +8 -0
- package/dist/m/c-NRPJEVJS.js +1 -0
- package/dist/m/c-NUHP2XDB.js +1 -0
- package/dist/m/c-NZMNXVF6.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-OYTFP5QN.js +1 -0
- package/dist/m/c-P7KNDG34.js +1 -0
- package/dist/m/c-PPOSCAQD.js +1 -0
- package/dist/m/c-PQ5LK6QE.js +993 -0
- package/dist/m/c-PZ4XEPUP.js +2 -0
- package/dist/m/c-QHIWXHRO.js +1 -0
- package/dist/m/c-QHWJ5ZIJ.js +1 -0
- package/dist/m/c-QIX5BJYN.js +1 -0
- package/dist/m/c-QNKREOL6.js +1 -0
- package/dist/m/c-QQHEX6HA.js +1 -0
- package/dist/m/c-R7RMANJI.js +9 -0
- package/dist/m/c-RI4NT75Y.js +1 -0
- package/dist/m/c-RM7J7BV2.js +1 -0
- package/dist/m/c-RUJKSUQW.js +1 -0
- package/dist/m/c-RVMWGXEJ.js +1 -0
- package/dist/m/c-S7H2DRCB.js +1 -0
- package/dist/m/c-S7LK4KUE.js +1 -0
- package/dist/m/c-SGCCC4FW.js +25 -0
- package/dist/m/c-SGIA4IEQ.js +188 -0
- package/dist/m/c-SWRJFCNN.js +1 -0
- package/dist/m/c-T4VO4OCB.js +1 -0
- package/dist/m/c-TCCA5BZN.js +2 -0
- package/dist/m/c-TQEMVJCS.js +1 -0
- package/dist/m/c-TQZ2JYHD.js +1 -0
- package/dist/m/c-TR6RMDQ7.js +3 -0
- package/dist/m/c-TRS6TM6O.js +1 -0
- package/dist/m/c-UGHH4MB3.js +1 -0
- package/dist/m/c-UKHTLWUW.js +1 -0
- package/dist/m/c-UL2YUY52.js +1 -0
- package/dist/m/c-UNN7LWCT.js +1 -0
- package/dist/m/c-UXBMRDZB.js +235 -0
- package/dist/m/c-V7PZZRG7.js +1 -0
- package/dist/m/c-VAK7SG37.js +1 -0
- package/dist/m/c-VDSS4K3Z.js +1 -0
- package/dist/m/c-VFX45IZQ.js +1 -0
- package/dist/m/c-VHNSBD2M.js +1 -0
- package/dist/m/c-VKEDWYDF.js +1 -0
- package/dist/m/c-VL52ADDR.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-WWDBYXLK.js +1 -0
- package/dist/m/c-WYFDLITL.js +1 -0
- package/dist/m/c-XN6MBKI6.js +67 -0
- package/dist/m/c-XNNW2CWK.js +1 -0
- package/dist/m/c-XPELB6E5.js +1 -0
- package/dist/m/c-XQXZAO7N.js +1 -0
- package/dist/m/c-Y6USGTS5.js +5 -0
- package/dist/m/c-YDH7Q3NY.js +1 -0
- package/dist/m/c-YG2NJYS6.js +135 -0
- package/dist/m/c-Z36J63PP.js +1 -0
- package/dist/m/c-Z4VRC7GU.js +7 -0
- package/dist/m/c-Z6K52OLP.js +19 -0
- package/dist/m/c-ZDY2MDAA.js +21 -0
- package/dist/m/c-ZE46QDIH.js +1 -0
- package/dist/m/c-ZUCOKOHT.js +1 -0
- package/dist/m/core/admin-attrs-VGNLAUDK.js +1 -0
- package/dist/m/core/autosave-E4PEFPZ6.js +1 -0
- package/dist/m/core/conflict-notice-VQ6Y64PH.js +1 -0
- package/dist/m/core/draft-mode-WSQAT67S.js +1 -0
- package/dist/m/core/host-permission-XN3K2IW3.js +1 -0
- package/dist/m/core/is-edit-mode-JXHDVGUL.js +1 -0
- package/dist/m/core/persist-HKHA66IY.js +3 -0
- package/dist/m/core/recovery-TBBSICE2.js +1 -0
- package/dist/m/core/save-WUCHTQBE.js +1 -0
- package/dist/m/core/save-core-FJVHT5M3.js +1 -0
- package/dist/m/core/snapshot-F3SWDZMM.js +1 -0
- package/dist/m/core/unsaved-warning-STKBHE6G.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-23DPTUT4.js +1 -0
- package/dist/m/internals/index-WOVAP3RU.js +1 -0
- package/dist/m/lib/cache-bust-CGWT6ZJI.js +1 -0
- package/dist/m/lib/region-policy-SB2AWVG5.js +1 -0
- package/dist/m/loader-HXX6YNH5.js +1 -0
- package/dist/m/manifest-F22DEDAC.js +1 -0
- package/dist/m/manifest-edit-C3C7376B.js +1 -0
- package/dist/m/manifest.json +3491 -0
- package/dist/m/options/options-2LH76JQ3.js +1 -0
- package/dist/m/page/editor-XUTB2HB2.js +189 -0
- package/dist/m/plugins/ai-edit-ZQ4CGWIP.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-ZIBFAA3R.js +1 -0
- package/dist/m/plugins/derive-UAAA4V4S.js +1 -0
- package/dist/m/plugins/indicator-PV4YW2ID.js +1 -0
- package/dist/m/plugins/live-NUTTXSBS.js +1 -0
- package/dist/m/plugins/menu-HCKO3DSP.js +138 -0
- package/dist/m/plugins/message-LQ6EDH4V.js +1 -0
- package/dist/m/plugins/page-KSUH7G6J.js +2 -0
- package/dist/m/plugins/page-view-W73OW7WI.js +1 -0
- package/dist/m/plugins/people-AJJ32YCG.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-RC3L2F6X.js +517 -0
- package/dist/m/plugins/richclay-RC3L2F6X.js.LEGAL.txt +1 -0
- package/dist/m/plugins/sortable-YRMQX3ZU.js +1 -0
- package/dist/m/plugins/source-KHK5UUSK.js +1 -0
- package/dist/m/plugins/undo-OF2L3CXU.js +1 -0
- package/dist/m/plugins/unsent-HJFLQJ2O.js +1 -0
- package/dist/m/plugins/upgrade-ZNYODP5Y.js +1 -0
- package/dist/m/plugins/upload-XSGNILUY.js +1 -0
- package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +21 -0
- package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +1 -0
- package/dist/m/plugins/wire-ZWVWKF76.js +1 -0
- package/dist/m/reader-core-ILWLXVMP.js +68 -0
- package/dist/m/route/route-KOCZSEGN.js +1 -0
- package/dist/m/sync/live-sync-4AUVXVJU.js +1 -0
- package/dist/m/ui/index-EVHKMKBL.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 +3800 -0
- package/dist/page/themes/light-1.css +406 -0
- package/dist/server/core.cjs +23662 -22860
- 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/conflict-download.js +22 -0
- package/src/core/conflict-notice-ui.js +1173 -0
- package/src/core/conflict-notice.js +140 -697
- package/src/core/edit-mode.js +147 -14
- package/src/core/etag.js +30 -12
- package/src/core/host-meta.js +72 -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 +109 -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 +805 -118
- package/src/core/snapshot.js +121 -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 +141 -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 +79 -5
- 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 +17 -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/checklist.js +1 -1
- package/src/page/chrome.js +411 -61
- package/src/page/csv-import.js +17 -2
- package/src/page/document-title-dom.js +40 -0
- package/src/page/document-title-runtime.js +76 -0
- package/src/page/document-title.js +9 -0
- package/src/page/drag.js +48 -13
- package/src/page/drop.js +2 -1
- package/src/page/editor.js +330 -86
- package/src/page/feature-loader.js +72 -0
- package/src/page/features/board.js +12 -0
- package/src/page/features/code.js +13 -0
- package/src/page/features/media.js +290 -0
- package/src/page/features/registry.js +23 -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-gate.js +179 -0
- package/src/page/format-level.js +157 -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 +18 -25
- package/src/page/items.js +52 -11
- package/src/page/link.js +1 -0
- package/src/page/markdown.js +86 -1
- package/src/page/media-views.js +3 -0
- package/src/page/media.js +33 -245
- package/src/page/outline-cache.js +11 -0
- package/src/page/placeholder.js +27 -7
- package/src/page/projection.js +196 -50
- 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 +7 -4
- package/src/page/schema.js +14 -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/light-1.css +139 -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.js +390 -107
- package/src/page/ybind/awareness.js +172 -0
- package/src/page/ybind/binding.js +9 -1
- 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 +25 -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 +84 -22
- package/src/page/ybind/recovery-proof.js +191 -0
- package/src/page/ybind/recovery-replay.js +130 -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 +282 -34
- 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 +1022 -275
- 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/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 +535 -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,25 @@
|
|
|
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";
|
|
13
14
|
|
|
14
15
|
export const ATOM = "";
|
|
15
16
|
export const BREAK = '@{"type":"hard_break"}';
|
|
16
17
|
const CODES = ["b", "i", "s", "c", "a"];
|
|
17
18
|
const TAGS = { b: "strong", i: "em", s: "s", c: "code" };
|
|
18
19
|
const NEST = ["a", "b", "i", "s", "c"];
|
|
20
|
+
const KNOWN = new Set(CODES);
|
|
21
|
+
|
|
22
|
+
// A block or an inline span the runtime has no schema for rides in an inert
|
|
23
|
+
// semantic envelope: canonical JSON, base64url, in one attribute. The block
|
|
24
|
+
// envelope holds the block record, the marks envelope the descriptors of one
|
|
25
|
+
// run, and the visible text stays the readable fallback.
|
|
26
|
+
export const OPAQUE = "data-clay-page-opaque";
|
|
27
|
+
export const VALUE = "data-clay-page-value";
|
|
28
|
+
export const MARKS = "data-clay-page-marks";
|
|
29
|
+
const ENVELOPE = "1";
|
|
30
|
+
const STRUCTURAL = new Set(["id", "t", "parent", "c", "m"]);
|
|
31
|
+
const knownType = (t) => Object.hasOwn(DEFAULTS, t);
|
|
19
32
|
|
|
20
33
|
// Mirrors schema.js attrs minus id and pos (a test pins the two together).
|
|
21
34
|
export const DEFAULTS = {
|
|
@@ -48,6 +61,67 @@ export function orderedIds(map) {
|
|
|
48
61
|
});
|
|
49
62
|
}
|
|
50
63
|
|
|
64
|
+
// ---- envelopes --------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
const b64url = (text) => {
|
|
67
|
+
let bin = "";
|
|
68
|
+
for (const byte of new TextEncoder().encode(text)) bin += String.fromCharCode(byte);
|
|
69
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const fromB64url = (text) => {
|
|
73
|
+
const bin = atob(String(text).replace(/-/g, "+").replace(/_/g, "/"));
|
|
74
|
+
return new TextDecoder().decode(Uint8Array.from(bin, (ch) => ch.charCodeAt(0)));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// A key any object would take as its prototype rather than as data.
|
|
78
|
+
const hostile = (value) => {
|
|
79
|
+
if (value === null || typeof value !== "object") return false;
|
|
80
|
+
if (Array.isArray(value)) return value.some(hostile);
|
|
81
|
+
return Object.keys(value).some((key) => key === "__proto__" || hostile(value[key]));
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// One envelope's JSON, under the codec's budget: deeper or larger refuses the
|
|
85
|
+
// whole source rather than cutting the envelope short.
|
|
86
|
+
function decodeJson(text) {
|
|
87
|
+
let value;
|
|
88
|
+
try { value = JSON.parse(fromB64url(text)); }
|
|
89
|
+
catch { throw new SyntaxError("page: an envelope is not readable canonical JSON"); }
|
|
90
|
+
try { bounded(value); }
|
|
91
|
+
catch (error) { throw new SyntaxError(error.message); }
|
|
92
|
+
if (hostile(value)) throw new SyntaxError("page: an envelope holds a prototype key");
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// A block envelope: a record, whose own type and structural fields are kept
|
|
97
|
+
// apart from it.
|
|
98
|
+
function recordOf(text) {
|
|
99
|
+
const value = decodeJson(text);
|
|
100
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new SyntaxError("page: a block envelope is not a record");
|
|
101
|
+
if ("id" in value || "pos" in value) throw new SyntaxError("page: a block envelope holds a structural field");
|
|
102
|
+
if ("t" in value && (typeof value.t !== "string" || !value.t)) throw new SyntaxError("page: a block envelope names no type");
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// A marks envelope: the descriptors of one run, validated and put back in the
|
|
107
|
+
// codec's canonical order however they arrived.
|
|
108
|
+
function entriesOfEnvelope(text) {
|
|
109
|
+
try { return normalizeEntries(decodeJson(text)); }
|
|
110
|
+
catch (error) { throw error instanceof SyntaxError ? error : new SyntaxError(error.message); }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The entries of a marks envelope as it arrived, validated by the same reader
|
|
114
|
+
// the article uses.
|
|
115
|
+
export const marksEntries = (text) => entriesOfEnvelope(text);
|
|
116
|
+
|
|
117
|
+
const envelopeOf = (value) => ` ${OPAQUE}="${ENVELOPE}" ${VALUE}="${escAttr(b64url(canon(value)))}"`;
|
|
118
|
+
const marksEnvelope = (entries) => (entries.length ? ` ${MARKS}="${escAttr(b64url(JSON.stringify(entries)))}"` : "");
|
|
119
|
+
|
|
120
|
+
// The same two envelopes as attribute maps, for the internal rich clipboard,
|
|
121
|
+
// which writes them onto its own elements instead of an article line.
|
|
122
|
+
export const envelopeAttrs = (record) => ({ [OPAQUE]: ENVELOPE, [VALUE]: b64url(canon(record)) });
|
|
123
|
+
export const marksAttrs = (entries) => ({ [MARKS]: b64url(JSON.stringify(normalizeEntries(entries))) });
|
|
124
|
+
|
|
51
125
|
// ---- marks ------------------------------------------------------------------
|
|
52
126
|
|
|
53
127
|
// inline.js unitsOf: runs [[n, key]] or per-unit keys -> one key per unit, or null.
|
|
@@ -72,28 +146,29 @@ export function runsOf(units) {
|
|
|
72
146
|
return out;
|
|
73
147
|
}
|
|
74
148
|
|
|
75
|
-
// A mark key as { b: true, a: ["href"] ... }
|
|
149
|
+
// A mark key as { marks: { b: true, a: ["href"] ... }, entries: [...] }, the
|
|
150
|
+
// entries being the descriptors of every mark this runtime has no code for, in
|
|
151
|
+
// the codec's canonical order.
|
|
76
152
|
function marksOfKey(key) {
|
|
77
|
-
const
|
|
78
|
-
if (!key || key[0] === "@") return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
for (; j < key.length; j++) {
|
|
84
|
-
const ch = key[j];
|
|
85
|
-
if (str) { if (ch === "\\") j++; else if (ch === '"') str = false; }
|
|
86
|
-
else if (ch === '"') str = true;
|
|
87
|
-
else if (ch === "[") depth++;
|
|
88
|
-
else if (ch === "]" && --depth === 0) { j++; break; }
|
|
89
|
-
}
|
|
90
|
-
out[code] = JSON.parse(key.slice(i, j));
|
|
91
|
-
i = j;
|
|
92
|
-
} else out[code] = true;
|
|
153
|
+
const marks = {};
|
|
154
|
+
if (!key || key[0] === "@") return { marks, entries: [] };
|
|
155
|
+
const opaque = [];
|
|
156
|
+
for (const desc of descriptors(key)) {
|
|
157
|
+
if (desc.name === undefined && KNOWN.has(desc.code)) marks[desc.code] = desc.attrs ?? true;
|
|
158
|
+
else opaque.push(desc);
|
|
93
159
|
}
|
|
94
|
-
return
|
|
160
|
+
return { marks, entries: opaque.length ? entriesOf(opaque) : [] };
|
|
95
161
|
}
|
|
96
162
|
|
|
163
|
+
// One unit's key, as the record keeps it: the codes this runtime knows, then
|
|
164
|
+
// every descriptor it keeps for a newer runtime.
|
|
165
|
+
const unitKey = (key, text, i) => {
|
|
166
|
+
if (!key) return "";
|
|
167
|
+
if (key[0] === "@") return key === BREAK && text[i] === ATOM ? key : "";
|
|
168
|
+
const { marks, entries } = marksOfKey(key);
|
|
169
|
+
return keyOfMarks(safeMarks(marks), entries);
|
|
170
|
+
};
|
|
171
|
+
|
|
97
172
|
// A link to a script URL is never kept: it would run on the page's origin when a
|
|
98
173
|
// reader clicks it in the saved article.
|
|
99
174
|
const SCRIPT_URL = /^(javascript|vbscript|data):/i;
|
|
@@ -102,14 +177,14 @@ const safeMarks = (marks) => {
|
|
|
102
177
|
return marks;
|
|
103
178
|
};
|
|
104
179
|
|
|
105
|
-
function keyOfMarks(marks) {
|
|
180
|
+
function keyOfMarks(marks, entries = []) {
|
|
106
181
|
let key = "";
|
|
107
182
|
for (const code of CODES) {
|
|
108
183
|
if (!marks[code]) continue;
|
|
109
184
|
key += code;
|
|
110
185
|
if (Array.isArray(marks[code])) key += JSON.stringify(marks[code]);
|
|
111
186
|
}
|
|
112
|
-
return key;
|
|
187
|
+
return entries.length ? key + keyOf(entries) : key;
|
|
113
188
|
}
|
|
114
189
|
|
|
115
190
|
// ---- text normalization -----------------------------------------------------
|
|
@@ -175,7 +250,7 @@ function layout(blocks) {
|
|
|
175
250
|
let prev = null;
|
|
176
251
|
for (const id of orderedIds(blocks)) {
|
|
177
252
|
const b = blocks[id];
|
|
178
|
-
const t =
|
|
253
|
+
const t = typeof b.t === "string" && b.t ? b.t : null;
|
|
179
254
|
let parent = b.parent ?? null;
|
|
180
255
|
if (parent !== null) {
|
|
181
256
|
const at = stack.lastIndexOf(parent);
|
|
@@ -207,7 +282,7 @@ const columnWidth = (value) => (typeof value === "number" && Number.isFinite(val
|
|
|
207
282
|
function cellModel(value) {
|
|
208
283
|
if (value === null || typeof value !== "object" || typeof value.c !== "string") return normalizeText(cellText(value), null).c;
|
|
209
284
|
const raw = unitsOf(value.m, value.c.length);
|
|
210
|
-
const units = raw && raw.map((k, i) => (
|
|
285
|
+
const units = raw && raw.map((k, i) => unitKey(k, value.c, i));
|
|
211
286
|
if (!units) return normalizeText(cellText(value), null).c;
|
|
212
287
|
const n = normalizeText(value.c, units);
|
|
213
288
|
const fields = textFields(n.c, n.units);
|
|
@@ -240,10 +315,44 @@ function projectBoard(b) {
|
|
|
240
315
|
};
|
|
241
316
|
}
|
|
242
317
|
|
|
318
|
+
// The record a block envelope carries: its own type first, then every field the
|
|
319
|
+
// runtime keeps for the block, extras included.
|
|
320
|
+
const recordOfItem = (item) => {
|
|
321
|
+
const { t, parent: _p, id: _i, ...fields } = item;
|
|
322
|
+
return { t, ...fields };
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// The fields of a known block the runtime has no schema attribute for. They are
|
|
326
|
+
// merged back only when serialized, inside the inert payload.
|
|
327
|
+
const extrasOfItem = (item) => {
|
|
328
|
+
const out = {};
|
|
329
|
+
for (const [k, v] of Object.entries(item)) if (!STRUCTURAL.has(k) && !(knownType(item.t) && Object.hasOwn(DEFAULTS[item.t], k))) out[k] = v;
|
|
330
|
+
return Object.keys(out).length ? envelopeOf(out) : "";
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const extrasOfBlock = (t, b) => {
|
|
334
|
+
const out = {};
|
|
335
|
+
for (const [k, v] of Object.entries(b)) if (!STRUCTURAL.has(k) && k !== "pos" && !Object.hasOwn(DEFAULTS[t], k)) out[k] = v;
|
|
336
|
+
return out;
|
|
337
|
+
};
|
|
338
|
+
|
|
243
339
|
function projectOne({ id, b, t, parent, indent }) {
|
|
244
340
|
if (!t) return { id, t: "preserved", html: "" };
|
|
245
|
-
|
|
246
|
-
|
|
341
|
+
if (!knownType(t)) {
|
|
342
|
+
const { t: _t, id: _id, pos: _pos, parent: _p, ...rest } = b;
|
|
343
|
+
// The text and its marks are kept as they stand, but marks in the older
|
|
344
|
+
// per-unit form come back as runs, so one record has one revision whichever
|
|
345
|
+
// form it was written in.
|
|
346
|
+
if (typeof rest.c === "string" && rest.m !== undefined) {
|
|
347
|
+
const units = unitsOf(rest.m, rest.c.length);
|
|
348
|
+
if (units && units.some(Boolean)) rest.m = runsOf(units);
|
|
349
|
+
else delete rest.m;
|
|
350
|
+
}
|
|
351
|
+
return { id, t, ...(parent ? { parent } : {}), ...rest };
|
|
352
|
+
}
|
|
353
|
+
const { t: _t, id: _id, pos, c, m, rows, cols, columns, cards, parent: _p, indent: _i, ...attrs } = b;
|
|
354
|
+
const extras = extrasOfBlock(t, attrs);
|
|
355
|
+
for (const k of Object.keys(extras)) delete attrs[k];
|
|
247
356
|
const fields = { ...attrs, parent };
|
|
248
357
|
if (t === "list_item") fields.indent = indent;
|
|
249
358
|
if (t === "heading") fields.level = clampLevel(attrs.level ?? 2);
|
|
@@ -253,13 +362,13 @@ function projectOne({ id, b, t, parent, indent }) {
|
|
|
253
362
|
if (t === "chart" && typeof fields.title === "string") fields.title = normalizeText(fields.title, null).c;
|
|
254
363
|
if (t === "table") Object.assign(fields, projectTable(b));
|
|
255
364
|
else if (t === "board") Object.assign(fields, projectBoard(b));
|
|
256
|
-
const item = { id, t, ...omitDefaults(t, fields) };
|
|
365
|
+
const item = { id, t, ...omitDefaults(t, fields), ...extras };
|
|
257
366
|
if (t === "table") { item.cols = fields.cols; item.rows = fields.rows; }
|
|
258
367
|
if (t === "board") { item.columns = fields.columns; item.cards = fields.cards; }
|
|
259
368
|
if (TEXT.has(t)) {
|
|
260
369
|
const text = typeof c === "string" ? c : "";
|
|
261
370
|
const raw = unitsOf(m, text.length);
|
|
262
|
-
const units = raw && raw.map((k, i) => (
|
|
371
|
+
const units = raw && raw.map((k, i) => unitKey(k, text, i));
|
|
263
372
|
if (t === "code_block") Object.assign(item, { c: text.replace(/\r\n?/g, "\n") });
|
|
264
373
|
else {
|
|
265
374
|
const n = normalizeText(text, units);
|
|
@@ -301,7 +410,7 @@ const escText = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>
|
|
|
301
410
|
const escAttr = (s) => escText(String(s)).replace(/"/g, """);
|
|
302
411
|
const attr = (name, value) => (value === null || value === undefined ? "" : ` ${name}="${escAttr(value)}"`);
|
|
303
412
|
|
|
304
|
-
export function renderInline(c, m) {
|
|
413
|
+
export function renderInline(c, m, marksEnvelopes = true) {
|
|
305
414
|
const units = unitsOf(m, c.length) || [];
|
|
306
415
|
let html = "";
|
|
307
416
|
const open = [];
|
|
@@ -316,12 +425,13 @@ export function renderInline(c, m) {
|
|
|
316
425
|
}
|
|
317
426
|
let j = i + 1;
|
|
318
427
|
while (j < c.length && (units[j] || "") === key && !(c[j] === ATOM && key[0] === "@")) j++;
|
|
319
|
-
const marks = marksOfKey(key);
|
|
428
|
+
const { marks, entries } = marksOfKey(key);
|
|
320
429
|
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 }));
|
|
430
|
+
if (entries.length && marksEnvelopes) want.push({ sig: `marks${canon(entries)}`, tag: "span", entries });
|
|
321
431
|
let keep = 0;
|
|
322
432
|
while (keep < open.length && keep < want.length && open[keep].sig === want[keep].sig) keep++;
|
|
323
433
|
closeTo(keep);
|
|
324
|
-
for (const w of want.slice(keep)) { html += w.tag === "a" ? `<a${attr("href", w.href)}>` : `<${w.tag}>`; open.push(w); }
|
|
434
|
+
for (const w of want.slice(keep)) { html += w.entries ? `<span${marksEnvelope(w.entries)}>` : w.tag === "a" ? `<a${attr("href", w.href)}>` : `<${w.tag}>`; open.push(w); }
|
|
325
435
|
html += escText(c.slice(i, j));
|
|
326
436
|
i = j;
|
|
327
437
|
}
|
|
@@ -338,26 +448,28 @@ const dataAttrs = (obj) => Object.entries(obj).map(([k, v]) => attr(`data-${k}`,
|
|
|
338
448
|
|
|
339
449
|
function renderLeaf(item, clean, tables) {
|
|
340
450
|
const id = attr("data-id", item.id);
|
|
451
|
+
if (!knownType(item.t)) return `<div${id}${envelopeOf(recordOfItem(item))}>${renderInline(item.c ?? "", item.m, false)}</div>`;
|
|
452
|
+
const at = id + extrasOfItem(item);
|
|
341
453
|
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 "code_block": return `<pre${
|
|
346
|
-
case "divider": return `<hr${
|
|
347
|
-
case "image": return `<figure${
|
|
454
|
+
case "paragraph": return `<p${at}>${inlineOf(item)}</p>`;
|
|
455
|
+
case "heading": { const h = `h${item.level ?? 2}`; return `<${h}${at}>${inlineOf(item)}</${h}>`; }
|
|
456
|
+
case "callout": return `<aside${at} class="page-callout">${inlineOf(item)}</aside>`;
|
|
457
|
+
case "code_block": return `<pre${at}${attr("data-lang", item.lang || null)}><code>${escText(item.c ?? "")}</code></pre>`;
|
|
458
|
+
case "divider": return `<hr${at}>`;
|
|
459
|
+
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
460
|
case "file": {
|
|
349
461
|
const href = /^(https?:\/\/|\/(?!\/))/i.test(item.src ?? "") ? item.src : null;
|
|
350
|
-
return `<div${
|
|
462
|
+
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
463
|
}
|
|
352
464
|
case "table": {
|
|
353
465
|
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
466
|
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${
|
|
467
|
+
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
468
|
}
|
|
357
469
|
case "chart": {
|
|
358
470
|
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
471
|
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${
|
|
472
|
+
return `<figure${at} data-type="chart"${data}>${renderChartSvg(chart, { width: 640, height: 320 })}<figcaption>${escText(item.title ?? "")}</figcaption></figure>`;
|
|
361
473
|
}
|
|
362
474
|
case "board": {
|
|
363
475
|
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 +477,16 @@ function renderLeaf(item, clean, tables) {
|
|
|
365
477
|
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
478
|
return `<div${attr("data-col", col.id)}${col.known ? "" : " data-missing"}>${col.known ? `<h4>${escText(col.name)}</h4>` : ""}<ul>${cards}</ul></div>`;
|
|
367
479
|
});
|
|
368
|
-
return `<section${
|
|
480
|
+
return `<section${at} data-type="board">\n${parts.join("\n")}\n</section>`;
|
|
369
481
|
}
|
|
370
|
-
case "tool": return `<section${
|
|
371
|
-
case "preserved": return preservedHtml(item, clean);
|
|
482
|
+
case "tool": return `<section${at} data-type="tool">${toolData(item)}</section>`;
|
|
483
|
+
case "preserved": return preservedHtml(item, clean, at);
|
|
372
484
|
default: return "";
|
|
373
485
|
}
|
|
374
486
|
}
|
|
375
487
|
|
|
376
488
|
// Markup the schema has no node for, kept as authored inside a marked wrapper.
|
|
377
|
-
const preservedHtml = (item, clean
|
|
489
|
+
const preservedHtml = (item, clean, id = attr("data-id", item.id)) => `<div${id} data-type="preserved">${clean.preserved(item.html || "")}</div>`;
|
|
378
490
|
|
|
379
491
|
const RAW = { preserved: (html) => html, fallback: (html) => html };
|
|
380
492
|
|
|
@@ -423,11 +535,11 @@ export function renderModel(model, { fallbackOf = () => "", clean = RAW } = {})
|
|
|
423
535
|
}
|
|
424
536
|
if (lists.length < d + 1) { add(`<${tag}>`); lists.push(tag); }
|
|
425
537
|
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)}`);
|
|
538
|
+
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
539
|
continue;
|
|
428
540
|
}
|
|
429
541
|
if (item.t === "toggle") {
|
|
430
|
-
add(`<details${attr("data-id", item.id)}${item.open ? " open" : ""}><summary>${inlineOf(item)}</summary>`);
|
|
542
|
+
add(`<details${attr("data-id", item.id)}${extrasOfItem(item)}${item.open ? " open" : ""}><summary>${inlineOf(item)}</summary>`);
|
|
431
543
|
stack.push(item.id);
|
|
432
544
|
continue;
|
|
433
545
|
}
|
|
@@ -453,12 +565,12 @@ const INLINE_TAGS = new Set(["A", "ABBR", "B", "BDI", "BDO", "BR", "CITE", "CODE
|
|
|
453
565
|
function inlineOfEl(el, skip = () => false) {
|
|
454
566
|
let c = "";
|
|
455
567
|
const units = [];
|
|
456
|
-
const walk = (node, marks) => {
|
|
568
|
+
const walk = (node, marks, entries) => {
|
|
457
569
|
for (const child of node.childNodes) {
|
|
458
570
|
if (skip(child)) continue;
|
|
459
571
|
if (child.nodeType === 3) {
|
|
460
572
|
c += child.data;
|
|
461
|
-
const key = keyOfMarks(safeMarks({ ...marks }));
|
|
573
|
+
const key = keyOfMarks(safeMarks({ ...marks }), entries);
|
|
462
574
|
for (let i = 0; i < child.data.length; i++) units.push(key);
|
|
463
575
|
continue;
|
|
464
576
|
}
|
|
@@ -467,20 +579,44 @@ function inlineOfEl(el, skip = () => false) {
|
|
|
467
579
|
if (tag === "br") { c += ATOM; units.push(BREAK); continue; }
|
|
468
580
|
if (tag === "span" && child.hasAttribute("data-atom")) { c += ATOM; units.push(child.getAttribute("data-atom")); continue; }
|
|
469
581
|
const next = { ...marks };
|
|
582
|
+
if (tag === "span" && child.hasAttribute(MARKS)) {
|
|
583
|
+
walk(child, next, normalizeEntries([...entries, ...entriesOfEnvelope(child.getAttribute(MARKS))]));
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
470
586
|
if (tag === "strong" || tag === "b") next.b = true;
|
|
471
587
|
else if (tag === "em" || tag === "i") next.i = true;
|
|
472
588
|
else if (tag === "s" || tag === "del" || tag === "strike") next.s = true;
|
|
473
589
|
else if (tag === "code") next.c = true;
|
|
474
590
|
else if (tag === "a" && child.hasAttribute("href")) next.a = [child.getAttribute("href")];
|
|
475
|
-
walk(child, next);
|
|
591
|
+
walk(child, next, entries);
|
|
476
592
|
}
|
|
477
593
|
};
|
|
478
|
-
walk(el, {});
|
|
594
|
+
walk(el, {}, []);
|
|
479
595
|
return normalizeText(c, units);
|
|
480
596
|
}
|
|
481
597
|
|
|
482
598
|
const text = (el) => normalizeText(el ? el.textContent : "", null).c;
|
|
483
599
|
|
|
600
|
+
// The block envelope an element carries, or null. A malformed, oversized or
|
|
601
|
+
// hostile one refuses the whole article: it never falls back to plain text.
|
|
602
|
+
const envelopeAt = (el) => {
|
|
603
|
+
if (!el.hasAttribute(OPAQUE)) return null;
|
|
604
|
+
if (el.getAttribute(OPAQUE) !== ENVELOPE) throw new SyntaxError(`page: unknown envelope version ${el.getAttribute(OPAQUE)}`);
|
|
605
|
+
const text = el.getAttribute(VALUE);
|
|
606
|
+
if (text === null) throw new SyntaxError("page: a block envelope holds no value");
|
|
607
|
+
return recordOf(text);
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// The record a block envelope carries, validated; null when the element carries
|
|
611
|
+
// no envelope at all.
|
|
612
|
+
export const envelopeRecord = (el) => envelopeAt(el);
|
|
613
|
+
|
|
614
|
+
// The extras a known element's envelope adds to it.
|
|
615
|
+
const extrasAt = (el) => {
|
|
616
|
+
const value = envelopeAt(el);
|
|
617
|
+
return value && typeof value.t !== "string" ? value : null;
|
|
618
|
+
};
|
|
619
|
+
|
|
484
620
|
export function parseArticle(article) {
|
|
485
621
|
const items = [];
|
|
486
622
|
const walk = (container, parent) => {
|
|
@@ -506,7 +642,10 @@ export function parseArticle(article) {
|
|
|
506
642
|
flushLoose();
|
|
507
643
|
};
|
|
508
644
|
const idOf = (el) => el.getAttribute("data-id") || null;
|
|
509
|
-
const push = (el, t, parent, fields) =>
|
|
645
|
+
const push = (el, t, parent, fields) => {
|
|
646
|
+
const extra = extrasAt(el);
|
|
647
|
+
items.push({ id: idOf(el), t, parent, ...(extra ? { ...extra, ...fields } : fields) });
|
|
648
|
+
};
|
|
510
649
|
const list = (el, parent, depth) => {
|
|
511
650
|
for (const li of el.children) {
|
|
512
651
|
if (li.tagName !== "LI") continue;
|
|
@@ -515,13 +654,20 @@ export function parseArticle(article) {
|
|
|
515
654
|
const n = inlineOfEl(li, (child) => child === box || nested.includes(child));
|
|
516
655
|
const kind = box ? "check" : el.tagName === "OL" ? "ordered" : "bullet";
|
|
517
656
|
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) });
|
|
657
|
+
items.push({ id: idOf(li), t: "list_item", ...omitDefaults("list_item", fields), ...(extrasAt(li) ?? {}), ...textFields(n.c, n.units) });
|
|
519
658
|
for (const sub of nested) list(sub, parent, depth + 1);
|
|
520
659
|
}
|
|
521
660
|
};
|
|
522
661
|
const blockOf = (el, parent) => {
|
|
523
662
|
const tag = el.tagName;
|
|
524
663
|
const P = { parent };
|
|
664
|
+
const record = envelopeAt(el);
|
|
665
|
+
if (record && typeof record.t === "string") {
|
|
666
|
+
if (knownType(record.t) || record.t === "opaque_block") throw new SyntaxError(`page: an envelope names the known block type ${record.t}`);
|
|
667
|
+
const { t, ...fields } = record;
|
|
668
|
+
items.push({ id: idOf(el), t, parent, ...fields });
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
525
671
|
const onlyImage = tag === "P" && el.children.length === 1 && el.children[0].tagName === "IMG" && !el.textContent.trim();
|
|
526
672
|
if (tag === "P" && !onlyImage) return push(el, "paragraph", parent, { ...omitDefaults("paragraph", P), ...tf(el) });
|
|
527
673
|
if (/^H[1-6]$/.test(tag)) return push(el, "heading", parent, { ...omitDefaults("heading", { ...P, level: +tag[1] }), ...tf(el) });
|