@panphora/clayjs 1.16.0 → 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/dist/all.js +1 -1
- package/dist/clay-dom.js +1 -1
- package/dist/clay-events.js +1 -1
- package/dist/clay-internals.js +1 -1
- package/dist/clay-options.js +1 -1
- package/dist/clay-router.js +1 -1
- package/dist/clay-ui.js +1 -1
- package/dist/clay-utils.js +1 -1
- package/dist/clay.js +1 -1
- package/dist/clay.standalone.js +7917 -5621
- 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-2YYDMLNZ.js +1 -0
- package/dist/m/c-336SGU5W.js +1 -0
- package/dist/m/c-3H6BZDNJ.js +6 -0
- package/dist/m/{c-LR4CGEPT.js → c-3RUU4TPX.js} +1 -1
- package/dist/m/c-3XIRD4NU.js +1 -0
- package/dist/m/c-4DFEJ2PO.js +3 -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-6AZOGAPE.js +1 -0
- package/dist/m/{c-Y6USGTS5.js → c-6CRUUXOX.js} +5 -5
- package/dist/m/{c-54RCDCBU.js → c-6KEVEQ7L.js} +1 -1
- package/dist/m/{c-LTGMXXKO.js → c-6NC5I2TV.js} +1 -1
- package/dist/m/{c-YDH7Q3NY.js → c-74MGYWZF.js} +1 -1
- package/dist/m/{c-Z36J63PP.js → c-7OLLJPWP.js} +1 -1
- package/dist/m/c-A3E3NIMC.js +1 -0
- package/dist/m/{c-5R4PTRG2.js → c-AMSNPOCX.js} +1 -1
- package/dist/m/c-B3JM5ZXC.js +1 -0
- package/dist/m/c-BPF2NSPV.js +1 -0
- package/dist/m/c-BQ6LOBEE.js +1 -0
- package/dist/m/c-CJ3A7ZKE.js +1 -0
- package/dist/m/c-CQHPGKX2.js +1 -0
- package/dist/m/c-DCXOXBF3.js +1 -0
- package/dist/m/c-DFS4XZJV.js +2 -0
- package/dist/m/{c-F3CKJTJS.js → c-DNENWY4O.js} +1 -1
- package/dist/m/c-E4LIR5X5.js +1 -0
- package/dist/m/c-EVCQ3BKA.js +1 -0
- package/dist/m/{c-5Y6TNX5W.js → c-EZU56NQV.js} +2 -2
- package/dist/m/c-FDNHHZY5.js +1 -0
- package/dist/m/{c-SWRJFCNN.js → c-FRLHSY7E.js} +1 -1
- 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-GB3JTV6E.js → c-GFJJEBTU.js} +1 -1
- package/dist/m/{c-J7CA54IP.js → c-GSFIGKOP.js} +1 -1
- package/dist/m/{c-OYTFP5QN.js → c-GY422N3Q.js} +1 -1
- package/dist/m/c-HAWFNBYG.js +1 -0
- package/dist/m/{c-33HUYEDI.js → c-HDDEEL77.js} +1 -1
- package/dist/m/c-HFKUVACH.js +1 -0
- package/dist/m/c-HHDFCNHV.js +1 -0
- package/dist/m/c-I2ZATQCD.js +2 -0
- package/dist/m/c-IEM4NTCS.js +1 -0
- package/dist/m/c-IW6GGOU2.js +1 -0
- package/dist/m/{c-SGCCC4FW.js → c-JDCX26UP.js} +2 -2
- package/dist/m/c-JRKY44DK.js +1 -0
- package/dist/m/c-JU3NK25H.js +1 -0
- package/dist/m/{c-VFX45IZQ.js → c-KAU6E43D.js} +1 -1
- package/dist/m/c-KBS3UV6B.js +1 -0
- package/dist/m/c-KGVGROZT.js +1 -0
- package/dist/m/{c-YG2NJYS6.js → c-KQ6TYJAP.js} +2 -2
- package/dist/m/{c-2JL6E75N.js → c-KU3ZFADW.js} +1 -1
- package/dist/m/c-LWLBHLVC.js +3 -0
- package/dist/m/c-M2L47S2X.js +7 -0
- package/dist/m/c-MFP2ZWD4.js +1 -0
- package/dist/m/{c-4YSCRICO.js → c-MKSQ4Y57.js} +1 -1
- package/dist/m/{c-2M73252O.js → c-NUFFJVVJ.js} +1 -1
- package/dist/m/c-NUHSPT5P.js +1 -0
- package/dist/m/c-O72HVYSA.js +1 -0
- package/dist/m/c-OW5QIGG3.js +1 -0
- package/dist/m/c-PGRCK73F.js +1 -0
- package/dist/m/{c-4DRMS4QG.js → c-PS5ARVWR.js} +1 -1
- 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-TQZ2JYHD.js → c-QICP2YR5.js} +1 -1
- package/dist/m/{c-7VGZ7RU5.js → c-QJ4OM3G6.js} +1 -1
- package/dist/m/{c-MMUIUUZG.js → c-R3L7ZJGB.js} +1 -1
- package/dist/m/c-R7IWVINQ.js +1 -0
- package/dist/m/{c-HVYXIS72.js → c-RSMOODDU.js} +1 -1
- package/dist/m/{c-KKWLDOPM.js → c-RYUXUUBX.js} +1 -1
- package/dist/m/c-S4ZEH46B.js +9 -0
- package/dist/m/c-SDAXDM2D.js +1 -0
- package/dist/m/c-SMBZG5X4.js +1 -0
- package/dist/m/{c-UXBMRDZB.js → c-SMGU7RT3.js} +1 -1
- 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-TCJTVAFN.js +1 -0
- package/dist/m/{c-HRDCD3WN.js → c-TJ6WOJL3.js} +1 -1
- package/dist/m/c-TYLXX4NF.js +21 -0
- package/dist/m/c-U62OB4BT.js +1 -0
- package/dist/m/{c-NMJRXKPC.js → c-U6YWUAR3.js} +1 -1
- package/dist/m/c-UDCSU5G5.js +2 -0
- package/dist/m/{c-NZMNXVF6.js → c-UDUUJPFZ.js} +1 -1
- 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-VI5RMSVY.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-WWXIDH4O.js +28 -0
- package/dist/m/{c-QIX5BJYN.js → c-XCNTK76U.js} +1 -1
- package/dist/m/c-XMS6DPBR.js +1 -0
- package/dist/m/c-Y5HBBIQ4.js +1 -0
- package/dist/m/{c-5M4YEKCX.js → c-ZVPVXTJF.js} +1 -1
- package/dist/m/c-ZVRKXKM7.js +1 -0
- package/dist/m/{c-HT33EQRN.js → c-ZWIOJGMT.js} +1 -1
- 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/host-permission-FNXVEFNE.js +1 -0
- package/dist/m/core/is-edit-mode-KTWA3O5N.js +1 -0
- package/dist/m/core/{persist-HKHA66IY.js → persist-JFYRHMRJ.js} +1 -1
- 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/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/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 +1555 -1058
- package/dist/m/options/options-EJMS3K24.js +1 -0
- package/dist/m/page/{editor-XUTB2HB2.js → editor-NNJA4OKD.js} +21 -8
- package/dist/m/plugins/{ai-edit-ZQ4CGWIP.js → ai-edit-QN4PMMNL.js} +1 -1
- package/dist/m/plugins/demo-RM5IR6AO.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-HCKO3DSP.js → menu-3HIEQSI6.js} +2 -2
- 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/{richclay-RC3L2F6X.js → richclay-NRQDSWX6.js} +2 -2
- 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/{upgrade-ZNYODP5Y.js → upgrade-W7FG5VFG.js} +1 -1
- 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-ILWLXVMP.js → reader-core-DXYCURFF.js} +2 -2
- package/dist/m/sync/live-sync-J7VMYTKS.js +1 -0
- package/dist/m/ui/{index-EVHKMKBL.js → index-3JLVI27O.js} +1 -1
- package/dist/offline-manifest.json +857 -623
- package/dist/page/themes/light-1.css +25 -1
- package/dist/server/core.cjs +115 -24
- package/package.json +1 -1
- package/src/core/boot-phase.js +2 -1
- package/src/core/conflict-download.js +3 -29
- package/src/core/download.js +32 -0
- package/src/core/host-meta.js +18 -0
- package/src/core/save-core.js +8 -4
- package/src/core/save.js +4 -4
- package/src/core/snapshot.js +39 -1
- package/src/lib/autosave-scheduler.js +3 -4
- package/src/page/blocks.js +34 -1
- package/src/page/board-views.js +2 -16
- package/src/page/chart-tables.js +11 -0
- package/src/page/chart.js +6 -10
- package/src/page/checkpoint-proof.js +289 -0
- package/src/page/chrome.js +24 -6
- package/src/page/document-title-dom.js +12 -0
- package/src/page/document-title-runtime.js +15 -1
- package/src/page/document-title.js +4 -1
- package/src/page/editor.js +77 -12
- package/src/page/emoji-data.js +162 -0
- package/src/page/features/board.js +12 -3
- package/src/page/features/chart.js +11 -0
- package/src/page/features/dates.js +180 -0
- package/src/page/features/emoji.js +187 -0
- package/src/page/features/mentions.js +188 -0
- package/src/page/features/registry.js +6 -1
- package/src/page/features/table.js +2 -2
- package/src/page/format-command.js +9 -0
- package/src/page/format-host.js +54 -0
- package/src/page/format-native-commands.js +142 -0
- package/src/page/format-native.js +42 -0
- package/src/page/inline.js +32 -8
- package/src/page/items.js +15 -3
- package/src/page/markdown.js +26 -2
- package/src/page/mention-picker.js +99 -0
- package/src/page/merge.js +1 -1
- package/src/page/projection.js +58 -15
- package/src/page/save-projection.js +39 -0
- package/src/page/save-states.js +1 -1
- package/src/page/schema.js +33 -0
- package/src/page/themes/content.css +25 -1
- package/src/page/themes/light-1.css +25 -1
- package/src/page/view-hooks.js +32 -0
- package/src/page/ybind/binding.js +31 -4
- package/src/page/ybind/marks.js +2 -1
- package/src/page/ybind/provider.js +13 -2
- package/src/page/ybind/recovery-replay.js +362 -4
- package/src/plugins/live.js +37 -1
- package/src/plugins/page.js +117 -3
- package/src/plugins/visitor-drafts/intro.js +2 -1
- package/src/server/checkpoint/index.js +2 -2
- package/src/sync/saved-stream.js +17 -8
- package/dist/m/attrs/refetch-on-save-NWPPXOCZ.js +0 -1
- package/dist/m/attrs/save-freeze-FUP4Q4X3.js +0 -1
- package/dist/m/c-35NBGMZB.js +0 -1
- package/dist/m/c-3IQRECYS.js +0 -1
- package/dist/m/c-4B6H4G5V.js +0 -1
- package/dist/m/c-4FFHZM32.js +0 -1
- package/dist/m/c-66O32MV3.js +0 -28
- package/dist/m/c-7O6AFR65.js +0 -1
- package/dist/m/c-ANQTJ3B5.js +0 -2
- package/dist/m/c-AYVOREBE.js +0 -1
- package/dist/m/c-B2ZXPOS3.js +0 -3
- package/dist/m/c-BMIZKMPV.js +0 -1
- package/dist/m/c-CJZSLMVQ.js +0 -1
- package/dist/m/c-DBE6ORSI.js +0 -1
- package/dist/m/c-EDHUR4MX.js +0 -1
- package/dist/m/c-EY6UOM54.js +0 -1
- package/dist/m/c-F7Y6FLPY.js +0 -1
- package/dist/m/c-FA4DZVTC.js +0 -1
- package/dist/m/c-G2BUZITR.js +0 -1
- package/dist/m/c-GBGWXTX4.js +0 -1
- package/dist/m/c-GHBCCVG4.js +0 -1
- package/dist/m/c-IB52R237.js +0 -1
- package/dist/m/c-IKWNE4R4.js +0 -1
- package/dist/m/c-IU3IYEU6.js +0 -1
- package/dist/m/c-IZ2EBRAJ.js +0 -1
- package/dist/m/c-KR4UW4KW.js +0 -1
- package/dist/m/c-KY3VJGUA.js +0 -8
- package/dist/m/c-LXENEBV7.js +0 -1
- package/dist/m/c-PPOSCAQD.js +0 -1
- package/dist/m/c-QQHEX6HA.js +0 -1
- package/dist/m/c-R7RMANJI.js +0 -9
- package/dist/m/c-RI4NT75Y.js +0 -1
- package/dist/m/c-RUJKSUQW.js +0 -1
- package/dist/m/c-T4VO4OCB.js +0 -1
- package/dist/m/c-TR6RMDQ7.js +0 -3
- package/dist/m/c-UKHTLWUW.js +0 -1
- package/dist/m/c-UNN7LWCT.js +0 -1
- package/dist/m/c-V7PZZRG7.js +0 -1
- package/dist/m/c-VL52ADDR.js +0 -1
- package/dist/m/c-WWDBYXLK.js +0 -1
- package/dist/m/c-XNNW2CWK.js +0 -1
- package/dist/m/c-Z4VRC7GU.js +0 -7
- package/dist/m/c-Z6K52OLP.js +0 -19
- package/dist/m/c-ZDY2MDAA.js +0 -21
- package/dist/m/core/admin-attrs-VGNLAUDK.js +0 -1
- package/dist/m/core/autosave-E4PEFPZ6.js +0 -1
- package/dist/m/core/conflict-notice-VQ6Y64PH.js +0 -1
- package/dist/m/core/host-permission-XN3K2IW3.js +0 -1
- package/dist/m/core/is-edit-mode-JXHDVGUL.js +0 -1
- package/dist/m/core/recovery-TBBSICE2.js +0 -1
- package/dist/m/core/save-WUCHTQBE.js +0 -1
- package/dist/m/core/save-core-FJVHT5M3.js +0 -1
- package/dist/m/core/snapshot-F3SWDZMM.js +0 -1
- package/dist/m/core/unsaved-warning-STKBHE6G.js +0 -1
- package/dist/m/events/index-23DPTUT4.js +0 -1
- package/dist/m/internals/index-WOVAP3RU.js +0 -1
- package/dist/m/lib/cache-bust-CGWT6ZJI.js +0 -1
- package/dist/m/loader-HXX6YNH5.js +0 -1
- package/dist/m/manifest-F22DEDAC.js +0 -1
- package/dist/m/manifest-edit-C3C7376B.js +0 -1
- package/dist/m/options/options-2LH76JQ3.js +0 -1
- package/dist/m/plugins/demo-ZIBFAA3R.js +0 -1
- package/dist/m/plugins/indicator-PV4YW2ID.js +0 -1
- package/dist/m/plugins/live-NUTTXSBS.js +0 -1
- package/dist/m/plugins/page-KSUH7G6J.js +0 -2
- package/dist/m/plugins/page-view-W73OW7WI.js +0 -1
- package/dist/m/plugins/people-AJJ32YCG.js +0 -1
- package/dist/m/plugins/sortable-YRMQX3ZU.js +0 -1
- package/dist/m/plugins/source-KHK5UUSK.js +0 -1
- package/dist/m/plugins/undo-OF2L3CXU.js +0 -1
- package/dist/m/plugins/upload-XSGNILUY.js +0 -1
- package/dist/m/plugins/visitor-drafts-XK5GW55Q.js +0 -21
- package/dist/m/plugins/visitor-drafts-owner-KSSH75EV.js +0 -1
- package/dist/m/plugins/wire-ZWVWKF76.js +0 -1
- package/dist/m/sync/live-sync-4AUVXVJU.js +0 -1
- /package/dist/m/plugins/{richclay-RC3L2F6X.js.LEGAL.txt → richclay-NRQDSWX6.js.LEGAL.txt} +0 -0
|
@@ -95,6 +95,11 @@
|
|
|
95
95
|
article[data-page] {
|
|
96
96
|
--page-link: #164583;
|
|
97
97
|
--page-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
98
|
+
--page-color-gray: #5B5953; --page-color-brown: #8A5A1E; --page-color-orange: #B4531A; --page-color-yellow: #7A6210; --page-color-green: #3E6A28;
|
|
99
|
+
--page-color-blue: #1F5A8A; --page-color-purple: #5E4596; --page-color-pink: #A23E6E; --page-color-red: #9E3B2F;
|
|
100
|
+
--page-mark-bg-gray: rgba(35, 34, 31, 0.12); --page-mark-bg-brown: rgba(138, 90, 30, 0.20); --page-mark-bg-orange: rgba(180, 83, 26, 0.20);
|
|
101
|
+
--page-mark-bg-yellow: rgba(122, 98, 16, 0.22); --page-mark-bg-green: rgba(62, 106, 40, 0.20); --page-mark-bg-blue: rgba(31, 90, 138, 0.18);
|
|
102
|
+
--page-mark-bg-purple: rgba(94, 69, 150, 0.18); --page-mark-bg-pink: rgba(162, 62, 110, 0.18); --page-mark-bg-red: rgba(158, 59, 47, 0.18);
|
|
98
103
|
min-height: 100vh;
|
|
99
104
|
box-sizing: border-box;
|
|
100
105
|
padding: var(--page-pad-top) 16px 30vh;
|
|
@@ -135,7 +140,26 @@
|
|
|
135
140
|
article[data-page] th, article[data-page] td { min-width: 120px; padding: 6px 10px; border-inline-end: 1px solid var(--page-rule); border-block-end: 1px solid var(--page-rule); text-align: start; white-space: pre-wrap; }
|
|
136
141
|
article[data-page] th { background: var(--page-code-bg); color: var(--page-ink-soft); font-weight: 600; }
|
|
137
142
|
article[data-page] th[data-kind="number"], article[data-page] td[data-kind="number"] { text-align: end; }
|
|
138
|
-
article[data-page] blockquote { color: var(--page-ink-soft);
|
|
143
|
+
article[data-page] blockquote { color: var(--page-ink-soft); padding-inline-start: var(--page-indent); }
|
|
144
|
+
article[data-page] span[data-color="gray"] { color: var(--page-color-gray); }
|
|
145
|
+
article[data-page] span[data-color="brown"] { color: var(--page-color-brown); }
|
|
146
|
+
article[data-page] span[data-color="orange"] { color: var(--page-color-orange); }
|
|
147
|
+
article[data-page] span[data-color="yellow"] { color: var(--page-color-yellow); }
|
|
148
|
+
article[data-page] span[data-color="green"] { color: var(--page-color-green); }
|
|
149
|
+
article[data-page] span[data-color="blue"] { color: var(--page-color-blue); }
|
|
150
|
+
article[data-page] span[data-color="purple"] { color: var(--page-color-purple); }
|
|
151
|
+
article[data-page] span[data-color="pink"] { color: var(--page-color-pink); }
|
|
152
|
+
article[data-page] span[data-color="red"] { color: var(--page-color-red); }
|
|
153
|
+
article[data-page] mark[data-color="gray"] { background: var(--page-mark-bg-gray); }
|
|
154
|
+
article[data-page] mark[data-color="brown"] { background: var(--page-mark-bg-brown); }
|
|
155
|
+
article[data-page] mark[data-color="orange"] { background: var(--page-mark-bg-orange); }
|
|
156
|
+
article[data-page] mark[data-color="yellow"] { background: var(--page-mark-bg-yellow); }
|
|
157
|
+
article[data-page] mark[data-color="green"] { background: var(--page-mark-bg-green); }
|
|
158
|
+
article[data-page] mark[data-color="blue"] { background: var(--page-mark-bg-blue); }
|
|
159
|
+
article[data-page] mark[data-color="purple"] { background: var(--page-mark-bg-purple); }
|
|
160
|
+
article[data-page] mark[data-color="pink"] { background: var(--page-mark-bg-pink); }
|
|
161
|
+
article[data-page] mark[data-color="red"] { background: var(--page-mark-bg-red); }
|
|
162
|
+
article[data-page] mark { color: inherit; }
|
|
139
163
|
}
|
|
140
164
|
|
|
141
165
|
|
package/dist/server/core.cjs
CHANGED
|
@@ -53849,6 +53849,12 @@ var schema = new Qr.Schema({
|
|
|
53849
53849
|
"data-checked": n.attrs.checked ? "true" : "false"
|
|
53850
53850
|
}), 0]
|
|
53851
53851
|
},
|
|
53852
|
+
quote: {
|
|
53853
|
+
group: "block",
|
|
53854
|
+
content: "inline*",
|
|
53855
|
+
attrs: block,
|
|
53856
|
+
toDOM: (n) => ["blockquote", ref(n), 0]
|
|
53857
|
+
},
|
|
53852
53858
|
callout: {
|
|
53853
53859
|
group: "block",
|
|
53854
53860
|
content: "inline*",
|
|
@@ -53977,6 +53983,33 @@ var schema = new Qr.Schema({
|
|
|
53977
53983
|
attrs: { href: {} },
|
|
53978
53984
|
inclusive: false,
|
|
53979
53985
|
toDOM: (m2) => ["a", { href: safeHref(m2.attrs.href) }, 0]
|
|
53986
|
+
},
|
|
53987
|
+
// A person mention is ordinary text with this mark over it: the name is the label
|
|
53988
|
+
// and `id` is the people registry's reference. It links nowhere and notifies nobody.
|
|
53989
|
+
mention: {
|
|
53990
|
+
attrs: { id: {} },
|
|
53991
|
+
inclusive: false,
|
|
53992
|
+
excludes: "mention date link",
|
|
53993
|
+
toDOM: (m2) => ["span", { "data-page-mention": m2.attrs.id }, 0]
|
|
53994
|
+
},
|
|
53995
|
+
// A date mention is the calendar date as ordinary ISO text with this mark over it:
|
|
53996
|
+
// `date` is YYYY-MM-DD, and no time, zone, reminder or relative word is stored.
|
|
53997
|
+
date: {
|
|
53998
|
+
attrs: { date: {} },
|
|
53999
|
+
inclusive: false,
|
|
54000
|
+
excludes: "mention date link",
|
|
54001
|
+
toDOM: (m2) => ["time", { datetime: m2.attrs.date, "data-page-date": "" }, 0]
|
|
54002
|
+
},
|
|
54003
|
+
// The floor-1 formats (format-native.js): written as named descriptors,
|
|
54004
|
+
// drawn as the elements the saved article keeps for them.
|
|
54005
|
+
underline: { toDOM: () => ["u", 0] },
|
|
54006
|
+
text_color: {
|
|
54007
|
+
attrs: { color: {} },
|
|
54008
|
+
toDOM: (m2) => ["span", { "data-color": m2.attrs.color }, 0]
|
|
54009
|
+
},
|
|
54010
|
+
highlight: {
|
|
54011
|
+
attrs: { color: {} },
|
|
54012
|
+
toDOM: (m2) => ["mark", { "data-color": m2.attrs.color }, 0]
|
|
53980
54013
|
}
|
|
53981
54014
|
}
|
|
53982
54015
|
});
|
|
@@ -54125,23 +54158,44 @@ function entriesOfYjs(fields) {
|
|
|
54125
54158
|
return normalizeEntries(entries);
|
|
54126
54159
|
}
|
|
54127
54160
|
|
|
54161
|
+
// src/page/format-native.js
|
|
54162
|
+
var NATIVE_NAMES = /* @__PURE__ */ new Set(["underline", "text_color", "highlight"]);
|
|
54163
|
+
var PALETTE = ["gray", "brown", "orange", "yellow", "green", "blue", "purple", "pink", "red"];
|
|
54164
|
+
var COLORS = new Set(PALETTE);
|
|
54165
|
+
function nativeAttrs(name, attrs) {
|
|
54166
|
+
const plain4 = attrs !== null && typeof attrs === "object" && !Array.isArray(attrs);
|
|
54167
|
+
if (name === "underline") return plain4 && Object.keys(attrs).length === 0 ? {} : null;
|
|
54168
|
+
if (name === "text_color" || name === "highlight") {
|
|
54169
|
+
const keys = plain4 ? Object.keys(attrs) : [];
|
|
54170
|
+
return keys.length === 1 && keys[0] === "color" && COLORS.has(attrs.color) ? { color: attrs.color } : null;
|
|
54171
|
+
}
|
|
54172
|
+
return null;
|
|
54173
|
+
}
|
|
54174
|
+
|
|
54128
54175
|
// src/page/inline.js
|
|
54129
54176
|
var CODES = { strong: "b", em: "i", strike: "s", code: "c", link: "a" };
|
|
54177
|
+
var NATIVE = /* @__PURE__ */ new Set(["underline", "text_color", "highlight"]);
|
|
54130
54178
|
var NAMES = Object.fromEntries(Object.entries(CODES).map(([name, code]) => [code, name]));
|
|
54131
54179
|
function markKey(marks) {
|
|
54132
54180
|
let key = "";
|
|
54181
|
+
const named = [];
|
|
54133
54182
|
for (const mark of marks) {
|
|
54134
54183
|
if (isOpaque(mark)) {
|
|
54135
54184
|
key += keyOf(mark.attrs.entries);
|
|
54136
54185
|
continue;
|
|
54137
54186
|
}
|
|
54138
54187
|
const code = CODES[mark.type.name];
|
|
54139
|
-
if (!code)
|
|
54188
|
+
if (!code) {
|
|
54189
|
+
const native = nativeAttrs(mark.type.name, mark.attrs);
|
|
54190
|
+
if (!native && NATIVE.has(mark.type.name)) throw new TypeError(`page: the mark ${mark.type.name} has no key code`);
|
|
54191
|
+
named.push({ name: mark.type.name, attrs: native ?? mark.attrs });
|
|
54192
|
+
continue;
|
|
54193
|
+
}
|
|
54140
54194
|
key += code;
|
|
54141
54195
|
const names = Object.keys(mark.type.attrs);
|
|
54142
54196
|
if (names.length) key += JSON.stringify(names.map((name) => mark.attrs[name]));
|
|
54143
54197
|
}
|
|
54144
|
-
return key;
|
|
54198
|
+
return named.length ? key + keyOf(named) : key;
|
|
54145
54199
|
}
|
|
54146
54200
|
var parsed = /* @__PURE__ */ new WeakMap();
|
|
54147
54201
|
function marksOf(schema2, key) {
|
|
@@ -54153,15 +54207,23 @@ function marksOf(schema2, key) {
|
|
|
54153
54207
|
marks = [];
|
|
54154
54208
|
const opaque = [];
|
|
54155
54209
|
for (const desc of descriptors(key)) {
|
|
54156
|
-
|
|
54210
|
+
if (desc.code === void 0) {
|
|
54211
|
+
const native = nativeAttrs(desc.name, desc.attrs);
|
|
54212
|
+
const type = schema2.marks[desc.name];
|
|
54213
|
+
if (native) marks = type.create(native).addToSet(marks);
|
|
54214
|
+
else if (type && !NATIVE.has(desc.name) && Object.keys(desc.attrs ?? {}).every((field) => Object.hasOwn(type.attrs, field))) marks = type.create(desc.attrs).addToSet(marks);
|
|
54215
|
+
else opaque.push(desc);
|
|
54216
|
+
continue;
|
|
54217
|
+
}
|
|
54218
|
+
const name = NAMES[desc.code];
|
|
54157
54219
|
if (!name) {
|
|
54158
54220
|
opaque.push(desc);
|
|
54159
54221
|
continue;
|
|
54160
54222
|
}
|
|
54161
|
-
const
|
|
54162
|
-
if (!
|
|
54163
|
-
const attrs = desc.attrs ? Object.fromEntries(Object.keys(
|
|
54164
|
-
marks =
|
|
54223
|
+
const coded = schema2.marks[name];
|
|
54224
|
+
if (!coded) throw new TypeError(`page: unknown mark code ${desc.code} in ${key}`);
|
|
54225
|
+
const attrs = desc.attrs ? Object.fromEntries(Object.keys(coded.attrs).map((field, j3) => [field, desc.attrs[j3]])) : null;
|
|
54226
|
+
marks = coded.create(attrs).addToSet(marks);
|
|
54165
54227
|
}
|
|
54166
54228
|
if (opaque.length) marks = opaqueMark(entriesOf(opaque)).addToSet(marks);
|
|
54167
54229
|
cache.set(key, marks);
|
|
@@ -54404,6 +54466,9 @@ var KNOWN = new Set(CODES2);
|
|
|
54404
54466
|
var OPAQUE = "data-clay-page-opaque";
|
|
54405
54467
|
var VALUE = "data-clay-page-value";
|
|
54406
54468
|
var MARKS = "data-clay-page-marks";
|
|
54469
|
+
var MENTION = "data-page-mention";
|
|
54470
|
+
var DATE = "data-page-date";
|
|
54471
|
+
var DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
54407
54472
|
var ENVELOPE = "1";
|
|
54408
54473
|
var STRUCTURAL = /* @__PURE__ */ new Set(["id", "t", "parent", "c", "m"]);
|
|
54409
54474
|
var knownType = (t) => Object.hasOwn(DEFAULTS, t);
|
|
@@ -54412,6 +54477,7 @@ var DEFAULTS = {
|
|
|
54412
54477
|
heading: { parent: null, level: 2 },
|
|
54413
54478
|
list_item: { parent: null, kind: "bullet", indent: 0, checked: false, owner: null, due: null },
|
|
54414
54479
|
callout: { parent: null },
|
|
54480
|
+
quote: { parent: null },
|
|
54415
54481
|
code_block: { parent: null, lang: "" },
|
|
54416
54482
|
toggle: { parent: null, open: false },
|
|
54417
54483
|
divider: { parent: null },
|
|
@@ -54423,7 +54489,7 @@ var DEFAULTS = {
|
|
|
54423
54489
|
tool: { parent: null, artifact: null, rev: null, state: {} },
|
|
54424
54490
|
preserved: { parent: null, html: "" }
|
|
54425
54491
|
};
|
|
54426
|
-
var TEXT = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "code_block", "toggle"]);
|
|
54492
|
+
var TEXT = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "quote", "code_block", "toggle"]);
|
|
54427
54493
|
var same = (a, b2) => canon(a) === canon(b2);
|
|
54428
54494
|
function orderedIds(map2) {
|
|
54429
54495
|
return Object.keys(map2).sort((x3, y2) => {
|
|
@@ -54497,20 +54563,26 @@ function runsOf2(units) {
|
|
|
54497
54563
|
return out;
|
|
54498
54564
|
}
|
|
54499
54565
|
function marksOfKey(key) {
|
|
54500
|
-
const marks = {};
|
|
54501
|
-
if (!key || key[0] === "@") return { marks, entries: [] };
|
|
54566
|
+
const marks = {}, native = [];
|
|
54567
|
+
if (!key || key[0] === "@") return { marks, native: [], entries: [] };
|
|
54502
54568
|
const opaque = [];
|
|
54503
54569
|
for (const desc of descriptors(key)) {
|
|
54504
|
-
if (desc.name === void 0
|
|
54570
|
+
if (desc.name === void 0) {
|
|
54571
|
+
if (KNOWN.has(desc.code)) marks[desc.code] = desc.attrs ?? true;
|
|
54572
|
+
else opaque.push(desc);
|
|
54573
|
+
continue;
|
|
54574
|
+
}
|
|
54575
|
+
const attrs = nativeAttrs(desc.name, desc.attrs);
|
|
54576
|
+
if (attrs) native.push({ name: desc.name, attrs });
|
|
54505
54577
|
else opaque.push(desc);
|
|
54506
54578
|
}
|
|
54507
|
-
return { marks, entries: opaque.length ? entriesOf(opaque) : [] };
|
|
54579
|
+
return { marks, native, entries: opaque.length ? entriesOf(opaque) : [] };
|
|
54508
54580
|
}
|
|
54509
54581
|
var unitKey = (key, text4, i) => {
|
|
54510
54582
|
if (!key) return "";
|
|
54511
54583
|
if (key[0] === "@") return key === BREAK2 && text4[i] === ATOM2 ? key : "";
|
|
54512
|
-
const { marks, entries } = marksOfKey(key);
|
|
54513
|
-
return keyOfMarks(safeMarks(marks), entries);
|
|
54584
|
+
const { marks, native, entries } = marksOfKey(key);
|
|
54585
|
+
return keyOfMarks(safeMarks(marks), native.length ? [...entries, ...entriesOf(native)] : entries);
|
|
54514
54586
|
};
|
|
54515
54587
|
var SCRIPT_URL = /^(javascript|vbscript|data):/i;
|
|
54516
54588
|
var safeMarks = (marks) => {
|
|
@@ -54715,6 +54787,7 @@ var revOf = (model) => hash64(canon(model));
|
|
|
54715
54787
|
var escText = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\r/g, " ");
|
|
54716
54788
|
var escAttr = (s) => escText(String(s)).replace(/"/g, """);
|
|
54717
54789
|
var attr2 = (name, value) => value === null || value === void 0 ? "" : ` ${name}="${escAttr(value)}"`;
|
|
54790
|
+
var NATIVE_TAGS = { underline: "u", text_color: "span", highlight: "mark" };
|
|
54718
54791
|
function renderInline(c, m2, marksEnvelopes = true) {
|
|
54719
54792
|
const units = unitsOf2(m2, c.length) || [];
|
|
54720
54793
|
let html3 = "";
|
|
@@ -54732,14 +54805,20 @@ function renderInline(c, m2, marksEnvelopes = true) {
|
|
|
54732
54805
|
}
|
|
54733
54806
|
let j3 = i + 1;
|
|
54734
54807
|
while (j3 < c.length && (units[j3] || "") === key && !(c[j3] === ATOM2 && key[0] === "@")) j3++;
|
|
54735
|
-
const { marks, entries } = marksOfKey(key);
|
|
54808
|
+
const { marks, native, entries } = marksOfKey(key);
|
|
54736
54809
|
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 }));
|
|
54737
|
-
|
|
54810
|
+
for (const n of native) want.push({ sig: `native${n.name}${canon(n.attrs)}`, tag: NATIVE_TAGS[n.name], color: n.attrs.color ?? null });
|
|
54811
|
+
const mention = entries.find((entry) => entry.name === "mention");
|
|
54812
|
+
const date = entries.find((entry) => entry.name === "date");
|
|
54813
|
+
const day = date && DAY.test(String(date.attrs.date)) ? String(date.attrs.date) : null;
|
|
54814
|
+
if (entries.length && marksEnvelopes) want.push({ sig: `marks${canon(entries)}`, tag: day ? "time" : "span", entries, mention: mention?.attrs.id, day });
|
|
54738
54815
|
let keep = 0;
|
|
54739
54816
|
while (keep < open.length && keep < want.length && open[keep].sig === want[keep].sig) keep++;
|
|
54740
54817
|
closeTo(keep);
|
|
54741
54818
|
for (const w3 of want.slice(keep)) {
|
|
54742
|
-
html3 += w3.
|
|
54819
|
+
if (w3.entries) html3 += w3.day ? `<time${attr2("datetime", w3.day)}${attr2(DATE, "")}${marksEnvelope(w3.entries)}>` : `<span${marksEnvelope(w3.entries)}${attr2(MENTION, w3.mention)}>`;
|
|
54820
|
+
else if (w3.tag === "a") html3 += `<a${attr2("href", w3.href)}>`;
|
|
54821
|
+
else html3 += w3.color ? `<${w3.tag}${attr2("data-color", w3.color)}>` : `<${w3.tag}>`;
|
|
54743
54822
|
open.push(w3);
|
|
54744
54823
|
}
|
|
54745
54824
|
html3 += escText(c.slice(i, j3));
|
|
@@ -54765,6 +54844,8 @@ function renderLeaf(item, clean, tables) {
|
|
|
54765
54844
|
}
|
|
54766
54845
|
case "callout":
|
|
54767
54846
|
return `<aside${at2} class="page-callout">${inlineOf(item)}</aside>`;
|
|
54847
|
+
case "quote":
|
|
54848
|
+
return `<blockquote${at2}>${inlineOf(item)}</blockquote>`;
|
|
54768
54849
|
case "code_block":
|
|
54769
54850
|
return `<pre${at2}${attr2("data-lang", item.lang || null)}><code>${escText(item.c ?? "")}</code></pre>`;
|
|
54770
54851
|
case "divider":
|
|
@@ -54894,6 +54975,13 @@ function renderBlocks(blocks, opts) {
|
|
|
54894
54975
|
}
|
|
54895
54976
|
var DROP_TAGS = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "TEMPLATE", "NOSCRIPT"]);
|
|
54896
54977
|
var INLINE_TAGS = /* @__PURE__ */ 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"]);
|
|
54978
|
+
function nativeOfEl(tag, el3) {
|
|
54979
|
+
if (tag === "u") return { name: "underline", attrs: {} };
|
|
54980
|
+
if (tag !== "mark" && tag !== "span") return null;
|
|
54981
|
+
if (tag === "span" && !el3.hasAttribute("data-color")) return null;
|
|
54982
|
+
const name = tag === "mark" ? "highlight" : "text_color";
|
|
54983
|
+
return { name, attrs: { color: el3.getAttribute("data-color") } };
|
|
54984
|
+
}
|
|
54897
54985
|
function inlineOfEl(el3, skip = () => false) {
|
|
54898
54986
|
let c = "";
|
|
54899
54987
|
const units = [];
|
|
@@ -54919,7 +55007,7 @@ function inlineOfEl(el3, skip = () => false) {
|
|
|
54919
55007
|
continue;
|
|
54920
55008
|
}
|
|
54921
55009
|
const next2 = { ...marks };
|
|
54922
|
-
if (tag === "span" && child.hasAttribute(MARKS)) {
|
|
55010
|
+
if ((tag === "span" || tag === "time") && child.hasAttribute(MARKS)) {
|
|
54923
55011
|
walk2(child, next2, normalizeEntries([...entries, ...entriesOfEnvelope(child.getAttribute(MARKS))]));
|
|
54924
55012
|
continue;
|
|
54925
55013
|
}
|
|
@@ -54928,7 +55016,8 @@ function inlineOfEl(el3, skip = () => false) {
|
|
|
54928
55016
|
else if (tag === "s" || tag === "del" || tag === "strike") next2.s = true;
|
|
54929
55017
|
else if (tag === "code") next2.c = true;
|
|
54930
55018
|
else if (tag === "a" && child.hasAttribute("href")) next2.a = [child.getAttribute("href")];
|
|
54931
|
-
|
|
55019
|
+
const named = nativeOfEl(tag, child);
|
|
55020
|
+
walk2(child, next2, named ? [...entries, named] : entries);
|
|
54932
55021
|
}
|
|
54933
55022
|
};
|
|
54934
55023
|
walk2(el3, {}, []);
|
|
@@ -55004,6 +55093,7 @@ function parseArticle(article) {
|
|
|
55004
55093
|
if (tag === "P" && !onlyImage) return push(el3, "paragraph", parent2, { ...omitDefaults("paragraph", P3), ...tf2(el3) });
|
|
55005
55094
|
if (/^H[1-6]$/.test(tag)) return push(el3, "heading", parent2, { ...omitDefaults("heading", { ...P3, level: +tag[1] }), ...tf2(el3) });
|
|
55006
55095
|
if (tag === "ASIDE") return push(el3, "callout", parent2, { ...omitDefaults("callout", P3), ...tf2(el3) });
|
|
55096
|
+
if (tag === "BLOCKQUOTE") return push(el3, "quote", parent2, { ...omitDefaults("quote", P3), ...tf2(el3) });
|
|
55007
55097
|
if (tag === "PRE") {
|
|
55008
55098
|
const code = el3.querySelector(":scope > code");
|
|
55009
55099
|
return push(el3, "code_block", parent2, { ...omitDefaults("code_block", { ...P3, lang: el3.getAttribute("data-lang") || "" }), c: (code || el3).textContent });
|
|
@@ -59100,7 +59190,7 @@ function marksFromAttributes(a, blockType) {
|
|
|
59100
59190
|
const marks = [];
|
|
59101
59191
|
let unknown = null;
|
|
59102
59192
|
for (const [n, v3] of best) {
|
|
59103
|
-
if (schema.marks[n]) marks.push(schema.marks[n].create(v3 === true ? null : v3));
|
|
59193
|
+
if (schema.marks[n] && (!NATIVE_NAMES.has(n) || nativeAttrs(n, v3))) marks.push(schema.marks[n].create(v3 === true ? null : v3));
|
|
59104
59194
|
else (unknown ??= {})[n] = v3;
|
|
59105
59195
|
}
|
|
59106
59196
|
if (unknown) {
|
|
@@ -71394,7 +71484,7 @@ function merge32(base, local, remote, options = {}) {
|
|
|
71394
71484
|
}
|
|
71395
71485
|
|
|
71396
71486
|
// src/page/merge.js
|
|
71397
|
-
var TEXT2 = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "code_block", "toggle"]);
|
|
71487
|
+
var TEXT2 = /* @__PURE__ */ new Set(["paragraph", "heading", "list_item", "callout", "quote", "code_block", "toggle"]);
|
|
71398
71488
|
var same2 = (a, b2) => canon(a) === canon(b2);
|
|
71399
71489
|
function inlineOf2(item, doc) {
|
|
71400
71490
|
const article = doc.createElement("article");
|
|
@@ -72757,11 +72847,12 @@ __export(checkpoint_exports, {
|
|
|
72757
72847
|
|
|
72758
72848
|
// src/page/document-title.js
|
|
72759
72849
|
var UNTITLED = "Untitled";
|
|
72760
|
-
function documentTitle(items, { custom = false, currentTitle = "" } = {}) {
|
|
72850
|
+
function documentTitle(items, { custom = false, currentTitle = "", keepWithoutHeading = false } = {}) {
|
|
72761
72851
|
if (custom) return currentTitle;
|
|
72762
72852
|
const first2 = items.find(
|
|
72763
72853
|
(item) => item.t === "heading" && (item.level ?? 2) === 1 && item.parent == null
|
|
72764
72854
|
);
|
|
72855
|
+
if (!first2 && keepWithoutHeading && !["", UNTITLED].includes(String(currentTitle).trim())) return currentTitle;
|
|
72765
72856
|
return String(first2?.c ?? "").replace(/[\s\uFFFC]+/gu, " ").trim() || UNTITLED;
|
|
72766
72857
|
}
|
|
72767
72858
|
|
|
@@ -72973,7 +73064,7 @@ function renderCheckpoint(currentHtml, capture, { createDocument, recovery = fal
|
|
|
72973
73064
|
edits.push({ start: articleLoc.startTag.startOffset, end: articleLoc.startTag.endOffset, text: articleStart.slice(0, -1) + rev + ">" });
|
|
72974
73065
|
edits.push({ start: articleLoc.startTag.endOffset, end: articleLoc.endTag.startOffset, text: rendered.html });
|
|
72975
73066
|
if (!customTitleOf(placement.titleModes)) {
|
|
72976
|
-
const edit = titleEdit(placement, documentTitle(rendered.model));
|
|
73067
|
+
const edit = titleEdit(placement, documentTitle(rendered.model, { currentTitle: titleTextOf(placement.title), keepWithoutHeading: true }));
|
|
72977
73068
|
if (edit) edits.push(edit);
|
|
72978
73069
|
}
|
|
72979
73070
|
return { kind: "ok", html: replace(currentHtml, edits), revision: rendered.rev };
|
|
@@ -72986,7 +73077,7 @@ function isCheckpointCurrent(currentHtml, capture) {
|
|
|
72986
73077
|
const rendered = renderBlocks(decoded.blocks);
|
|
72987
73078
|
const articleLoc = placement.article.sourceCodeLocation;
|
|
72988
73079
|
if (attr3(placement.article, "data-rev") !== rendered.rev || currentHtml.slice(articleLoc.startTag.endOffset, articleLoc.endTag.startOffset) !== rendered.html) return false;
|
|
72989
|
-
if (!customTitleOf(placement.titleModes) && titleTextOf(placement.title) !== documentTitle(rendered.model)) return false;
|
|
73080
|
+
if (!customTitleOf(placement.titleModes) && titleTextOf(placement.title) !== documentTitle(rendered.model, { currentTitle: titleTextOf(placement.title), keepWithoutHeading: true })) return false;
|
|
72990
73081
|
return capture.stores.every((store) => {
|
|
72991
73082
|
const node = placement.tags.get(store.name);
|
|
72992
73083
|
const loc = node.sourceCodeLocation;
|
package/package.json
CHANGED
package/src/core/boot-phase.js
CHANGED
|
@@ -3,4 +3,5 @@
|
|
|
3
3
|
// engine's first pass has painted the page, then releases it (loader.js,
|
|
4
4
|
// mountDerivedEngine). Every other page, and any test that imports save.js
|
|
5
5
|
// directly, never sets the hold.
|
|
6
|
-
|
|
6
|
+
// servedHash: the fragment the page was served with, read at this module's evaluation.
|
|
7
|
+
export const bootPhase = { holdSettle: false, servedHash: typeof window === "undefined" ? "" : window.location.hash };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { serializeRecoveryClone, captureRecoveryPage } from "./snapshot.js";
|
|
2
2
|
import { rowOf } from "./conflict-presentation.js";
|
|
3
|
+
import { documentName, downloadHtml } from "./download.js";
|
|
4
|
+
|
|
5
|
+
export { documentName, downloadHtml };
|
|
3
6
|
|
|
4
7
|
// Download my copy: one file, openable in a browser as the page this tab had, with
|
|
5
8
|
// the replaced edits listed in a JSON block for anyone (or any tool) putting them
|
|
@@ -12,14 +15,6 @@ function stamp(d = new Date()) {
|
|
|
12
15
|
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
export function documentName(pathname = location.pathname) {
|
|
16
|
-
const last = pathname.split("/").filter(Boolean).pop();
|
|
17
|
-
if (!last) return pathname.endsWith("/") || pathname === "" ? "index" : "page";
|
|
18
|
-
let name = last;
|
|
19
|
-
try { name = decodeURIComponent(last); } catch {}
|
|
20
|
-
return name.replace(/\.(html?|htmlclay)$/i, "") || "page";
|
|
21
|
-
}
|
|
22
|
-
|
|
23
18
|
function embed(html, data) {
|
|
24
19
|
const json = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
25
20
|
const block = `<script type="application/json" id="clay-lost-edits" clay="no-save">${json}</script>`;
|
|
@@ -67,27 +62,6 @@ export function buildRecovery(records, { refused = false } = {}) {
|
|
|
67
62
|
};
|
|
68
63
|
}
|
|
69
64
|
|
|
70
|
-
export function downloadHtml({ html, name }) {
|
|
71
|
-
let url = null;
|
|
72
|
-
try {
|
|
73
|
-
url = URL.createObjectURL(new Blob([html], { type: "text/html" }));
|
|
74
|
-
const a = document.createElement("a");
|
|
75
|
-
a.setAttribute("clay", "no-save no-watch no-snapshot");
|
|
76
|
-
a.href = url;
|
|
77
|
-
a.download = name;
|
|
78
|
-
a.style.setProperty("display", "none", "important");
|
|
79
|
-
document.body.appendChild(a);
|
|
80
|
-
a.click();
|
|
81
|
-
a.remove();
|
|
82
|
-
// Revoked late: Safari cancels a download whose URL goes away too soon.
|
|
83
|
-
setTimeout(() => URL.revokeObjectURL(url), 40000);
|
|
84
|
-
return true;
|
|
85
|
-
} catch (err) {
|
|
86
|
-
console.error("clayjs: could not build the download", err);
|
|
87
|
-
if (url) URL.revokeObjectURL(url);
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
65
|
|
|
92
66
|
// The review panel's own copy: the page a reload kept, when there is one, with every
|
|
93
67
|
// stored row it drew listed beside it as JSON. The rows are already plain, so nothing
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Saving a page as a file the browser downloads. Kept apart from the conflict copy
|
|
2
|
+
// builders so an editor that only offers "download this page" loads none of them.
|
|
3
|
+
|
|
4
|
+
export function documentName(pathname = location.pathname) {
|
|
5
|
+
const last = pathname.split("/").filter(Boolean).pop();
|
|
6
|
+
if (!last) return pathname.endsWith("/") || pathname === "" ? "index" : "page";
|
|
7
|
+
let name = last;
|
|
8
|
+
try { name = decodeURIComponent(last); } catch {}
|
|
9
|
+
return name.replace(/\.(html?|htmlclay)$/i, "") || "page";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function downloadHtml({ html, name }) {
|
|
13
|
+
let url = null;
|
|
14
|
+
try {
|
|
15
|
+
url = URL.createObjectURL(new Blob([html], { type: "text/html" }));
|
|
16
|
+
const a = document.createElement("a");
|
|
17
|
+
a.setAttribute("clay", "no-save no-watch no-snapshot");
|
|
18
|
+
a.href = url;
|
|
19
|
+
a.download = name;
|
|
20
|
+
a.style.setProperty("display", "none", "important");
|
|
21
|
+
document.body.appendChild(a);
|
|
22
|
+
a.click();
|
|
23
|
+
a.remove();
|
|
24
|
+
// Revoked late: Safari cancels a download whose URL goes away too soon.
|
|
25
|
+
setTimeout(() => URL.revokeObjectURL(url), 40000);
|
|
26
|
+
return true;
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.error("clayjs: could not build the download", err);
|
|
29
|
+
if (url) URL.revokeObjectURL(url);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/core/host-meta.js
CHANGED
|
@@ -149,6 +149,24 @@ export async function hostPageFormat() {
|
|
|
149
149
|
return meta.extensions.includes("page-format-v1") ? 1 : 0;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Where this host serves the page state of one accepted version, or null.
|
|
154
|
+
*
|
|
155
|
+
* Two things have to be true: the host announced `page-recovery-v1` by name, and its
|
|
156
|
+
* document block named the resource as `pageState.href`. A host that has the resource
|
|
157
|
+
* but has not announced the extension is still launching it, and a client that inferred
|
|
158
|
+
* either one from the other would retire journaled work against a pair nobody promised.
|
|
159
|
+
* Absent, empty or not a string is null, which means no conditional read and no proof
|
|
160
|
+
* from one: the records stay.
|
|
161
|
+
*
|
|
162
|
+
* @returns {Promise<?string>}
|
|
163
|
+
*/
|
|
164
|
+
export async function hostPageStateHref() {
|
|
165
|
+
const meta = await hostMeta();
|
|
166
|
+
if (!meta.extensions.includes("page-recovery-v1")) return null;
|
|
167
|
+
return meta.document?.pageState?.href || null;
|
|
168
|
+
}
|
|
169
|
+
|
|
152
170
|
/**
|
|
153
171
|
* Whether this host keeps a version history a person can go back to.
|
|
154
172
|
*
|
package/src/core/save-core.js
CHANGED
|
@@ -881,11 +881,15 @@ async function sendSave(content, { captureId = null, conversionHeader = null, at
|
|
|
881
881
|
// One private implementation behind every entry point, so the hooks see the same
|
|
882
882
|
// thing whether the bytes came from a bound capture or a raw caller. `captureId`
|
|
883
883
|
// is null for a raw save: it belongs to no capture and can confirm none.
|
|
884
|
-
|
|
884
|
+
//
|
|
885
|
+
// `pageFormatFloor` is internal: one save may carry a floor this tab has not
|
|
886
|
+
// noted yet, which is how the format gate's activation writes the marker. It
|
|
887
|
+
// raises these bytes only, never what the tab knows the document at.
|
|
888
|
+
function runSave(html, captureId, callback, conversion, capture = null, pageFormatFloor = 0) {
|
|
885
889
|
// A capture taken before the floor rose cannot drop the marker by omitting it:
|
|
886
890
|
// the bytes that go out carry the floor this tab last saw. At floor 0 this is
|
|
887
891
|
// the string itself, unchanged.
|
|
888
|
-
html = withPageFormatFloor(html, knownPageFormatFloor());
|
|
892
|
+
html = withPageFormatFloor(html, Math.max(knownPageFormatFloor(), pageFormatFloor));
|
|
889
893
|
return new Promise((resolve) => {
|
|
890
894
|
const attempts = [];
|
|
891
895
|
// Read once, before the first request: the artifact belongs to the capture that
|
|
@@ -994,8 +998,8 @@ export function saveHtml(html, callback = () => {}) {
|
|
|
994
998
|
* @param {Object} [options.conversion] - {source:'file', base} or {source:'room', base, epoch}
|
|
995
999
|
* @returns {Promise<Object>}
|
|
996
1000
|
*/
|
|
997
|
-
export function saveCapturedHtml(html, captureId, callback = () => {}, { conversion, capture = null } = {}) {
|
|
998
|
-
return runSave(html, captureId, callback, conversion, capture);
|
|
1001
|
+
export function saveCapturedHtml(html, captureId, callback = () => {}, { conversion, capture = null, pageFormatFloor } = {}) {
|
|
1002
|
+
return runSave(html, captureId, callback, conversion, capture, pageFormatFloor);
|
|
999
1003
|
}
|
|
1000
1004
|
|
|
1001
1005
|
/**
|
package/src/core/save.js
CHANGED
|
@@ -1083,8 +1083,8 @@ function savePagePermitted(permit, callback = () => {}) {
|
|
|
1083
1083
|
* @param {Function} callback - Optional callback for custom handling
|
|
1084
1084
|
* @returns {Promise<{msg: string, msgType: string}>}
|
|
1085
1085
|
*/
|
|
1086
|
-
export function savePageForce(callback = () => {}, { quietConflict = false } = {}) {
|
|
1087
|
-
if (capabilityPending) return capabilityKnown.then(() => savePageForce(callback, { quietConflict }));
|
|
1086
|
+
export function savePageForce(callback = () => {}, { quietConflict = false, pageFormatFloor = 0 } = {}) {
|
|
1087
|
+
if (capabilityPending) return capabilityKnown.then(() => savePageForce(callback, { quietConflict, pageFormatFloor }));
|
|
1088
1088
|
return new Promise((resolve) => {
|
|
1089
1089
|
if (!isEditMode && !window.clay?.testMode) {
|
|
1090
1090
|
const skipped = skipped_('Not in edit mode');
|
|
@@ -1110,7 +1110,7 @@ export function savePageForce(callback = () => {}, { quietConflict = false } = {
|
|
|
1110
1110
|
}
|
|
1111
1111
|
|
|
1112
1112
|
const prepare = window.clay?.source?.ensureForSave?.();
|
|
1113
|
-
if (prepare) return prepare.then(() => resolve(savePageForce(callback, { quietConflict })));
|
|
1113
|
+
if (prepare) return prepare.then(() => resolve(savePageForce(callback, { quietConflict, pageFormatFloor })));
|
|
1114
1114
|
|
|
1115
1115
|
const wasOffline = !navigator.onLine;
|
|
1116
1116
|
if (wasOffline) {
|
|
@@ -1148,7 +1148,7 @@ export function savePageForce(callback = () => {}, { quietConflict = false } = {
|
|
|
1148
1148
|
}
|
|
1149
1149
|
resolve(result);
|
|
1150
1150
|
drainPendingSave();
|
|
1151
|
-
}, { capture });
|
|
1151
|
+
}, { capture, pageFormatFloor });
|
|
1152
1152
|
});
|
|
1153
1153
|
}
|
|
1154
1154
|
|
package/src/core/snapshot.js
CHANGED
|
@@ -105,6 +105,37 @@ export function attachCaptureArtifact(artifact) {
|
|
|
105
105
|
if (activeCapture && artifact) activeCapture.artifact = artifact;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// The page state of one save capture: the exact value its page tag carried when its
|
|
109
|
+
// bytes were serialized, copied so the edits that follow the capture can never reach it.
|
|
110
|
+
// Keyed by the capture id every accepted event carries, and dropped when the capture
|
|
111
|
+
// settles, so an accepted save reads the state it was captured from rather than the
|
|
112
|
+
// store's value at the moment the host answered.
|
|
113
|
+
let capturePageStateReader = null;
|
|
114
|
+
const capturePageStates = new Map();
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Register the reader that finds a page state in a final save clone.
|
|
118
|
+
*
|
|
119
|
+
* A page's own code registers it (page/save-projection.js), so a document without a
|
|
120
|
+
* page pays one null check per capture and nothing else. Read from the clone rather
|
|
121
|
+
* than from a store because that tag is what the file receives, after every transform
|
|
122
|
+
* and every authored save handler has run.
|
|
123
|
+
*/
|
|
124
|
+
export function setCapturePageState(reader) {
|
|
125
|
+
capturePageStateReader = reader;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The page state pinned to one capture, or null.
|
|
130
|
+
*
|
|
131
|
+
* @param {?number} captureId
|
|
132
|
+
* @returns {?Object}
|
|
133
|
+
*/
|
|
134
|
+
export function capturePageState(captureId) {
|
|
135
|
+
if (captureId === null || captureId === undefined) return null;
|
|
136
|
+
return capturePageStates.get(captureId) ?? null;
|
|
137
|
+
}
|
|
138
|
+
|
|
108
139
|
/** The artifact this capture's renderer attached, or null. */
|
|
109
140
|
export function captureArtifact(result) {
|
|
110
141
|
return result ? captureArtifacts.get(result) || null : null;
|
|
@@ -112,7 +143,9 @@ export function captureArtifact(result) {
|
|
|
112
143
|
|
|
113
144
|
/** Forget a capture's artifact: it was skipped, refused, or has now settled. */
|
|
114
145
|
export function releaseCaptureArtifact(result) {
|
|
115
|
-
if (result)
|
|
146
|
+
if (!result) return;
|
|
147
|
+
captureArtifacts.delete(result);
|
|
148
|
+
capturePageStates.delete(result.captureId);
|
|
116
149
|
}
|
|
117
150
|
|
|
118
151
|
/**
|
|
@@ -263,6 +296,11 @@ function serializeClone(clone) {
|
|
|
263
296
|
* cost somebody a save.
|
|
264
297
|
*/
|
|
265
298
|
function serializeSaveClone(clone, context = null) {
|
|
299
|
+
if (context && capturePageStateReader) {
|
|
300
|
+
let state = null;
|
|
301
|
+
try { state = capturePageStateReader(clone); } catch (_) {}
|
|
302
|
+
if (state) capturePageStates.set(context.captureId, state);
|
|
303
|
+
}
|
|
266
304
|
const today = serializeClone(clone);
|
|
267
305
|
if (!saveRenderer) return today;
|
|
268
306
|
const previous = activeCapture;
|
|
@@ -16,10 +16,9 @@ export const MAX_COOLDOWN_MS = 30000;
|
|
|
16
16
|
|
|
17
17
|
// Adaptive spacing: make the gap after a save at least COST_MULTIPLIER times that
|
|
18
18
|
// save's synchronous cost, so a three-second save earns twelve seconds of quiet
|
|
19
|
-
// rather than spending the quiet window doing the next capture.
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
export const ADAPTIVE_SPACING = false;
|
|
19
|
+
// rather than spending the quiet window doing the next capture. On now that local
|
|
20
|
+
// recovery keeps every keystroke the longer gap could leave unsent.
|
|
21
|
+
export const ADAPTIVE_SPACING = true;
|
|
23
22
|
export const COST_MULTIPLIER = ADAPTIVE_SPACING ? 4 : 0;
|
|
24
23
|
|
|
25
24
|
// "No such time yet": before the first activity or the first completed save the
|