@panphora/clayjs 1.17.0 → 1.18.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 +72474 -62090
- package/dist/m/attrs/{save-freeze-MYNVXREN.js → save-freeze-LWGF6XUN.js} +1 -1
- package/dist/m/c-2GRUM77Q.js +30 -0
- package/dist/m/c-2KIEGNC4.js +1 -0
- package/dist/m/{c-AMSNPOCX.js → c-2KL3BD52.js} +1 -1
- package/dist/m/c-2ZZBC45O.js +1 -0
- package/dist/m/c-372N6H3B.js +1 -0
- package/dist/m/{c-4WKFKEKF.js → c-3G2DGZUP.js} +1 -1
- package/dist/m/c-3LDGIBMN.js +1 -0
- package/dist/m/c-3O7OBDCM.js +1 -0
- package/dist/m/c-4ASQPRQL.js +1 -0
- package/dist/m/c-4TXNLX4K.js +6 -0
- package/dist/m/c-4YU3BR4D.js +6 -0
- package/dist/m/c-5734MF2P.js +1 -0
- package/dist/m/c-57XDY6HC.js +1 -0
- package/dist/m/{c-KAU6E43D.js → c-5B4YBZXC.js} +1 -1
- package/dist/m/c-5ONTYIUI.js +1 -0
- package/dist/m/c-5OOVFCJM.js +1 -0
- package/dist/m/{c-3XIRD4NU.js → c-5T6NZHNM.js} +1 -1
- package/dist/m/{c-74MGYWZF.js → c-5ZQV7KC4.js} +1 -1
- package/dist/m/{c-7OLLJPWP.js → c-6DB2OLRJ.js} +1 -1
- package/dist/m/c-6DNRCPNM.js +1 -0
- package/dist/m/c-6UGWFMQC.js +2 -0
- package/dist/m/c-7K4SCQB7.js +1 -0
- package/dist/m/c-7MG5RU63.js +1 -0
- package/dist/m/c-7PRJCA3E.js +1 -0
- package/dist/m/c-A6L3FMUS.js +1 -0
- package/dist/m/c-AMU3BPPR.js +4 -0
- package/dist/m/{c-Y5HBBIQ4.js → c-AMYEFA2E.js} +1 -1
- package/dist/m/c-AQYCG7QW.js +1 -0
- package/dist/m/c-ATKAOH23.js +1 -0
- package/dist/m/c-B5CS55WR.js +1 -0
- package/dist/m/c-B5UJQT7W.js +1 -0
- package/dist/m/c-B7J4K2AE.js +3 -0
- package/dist/m/c-BHZYSHW4.js +1 -0
- package/dist/m/{c-VHM5XQHK.js → c-BIJALSRD.js} +1 -1
- package/dist/m/c-BJ7YQ5QZ.js +1 -0
- package/dist/m/{c-KIPQJX4B.js → c-BRLCTNMC.js} +1 -1
- package/dist/m/{c-VE6ZMYMC.js → c-BUAYFEV5.js} +1 -1
- package/dist/m/c-C6IPRG34.js +1 -0
- package/dist/m/{c-KU3ZFADW.js → c-CAS3NND4.js} +1 -1
- package/dist/m/{c-PS5ARVWR.js → c-CCQ25GFY.js} +1 -1
- package/dist/m/c-CJFDLD43.js +1 -0
- package/dist/m/c-COPTL5WB.js +1 -0
- package/dist/m/c-D3E4WJ4M.js +166 -0
- package/dist/m/c-D5IKEKXW.js +7 -0
- package/dist/m/c-DHBRA6DL.js +1 -0
- package/dist/m/c-DKLS74XB.js +72 -0
- package/dist/m/c-DVYGFTSK.js +3 -0
- package/dist/m/c-E3ZXARWA.js +1 -0
- package/dist/m/c-EK63G3CG.js +1 -0
- package/dist/m/c-ERQSNR6K.js +13 -0
- package/dist/m/c-EVYAISP3.js +1 -0
- package/dist/m/c-EXKHPOVC.js +3 -0
- package/dist/m/{c-QJ4OM3G6.js → c-FWKHM4E7.js} +1 -1
- package/dist/m/{c-4Q2XTQ2N.js → c-GBKB5WDL.js} +1 -1
- package/dist/m/c-GNDL3TKB.js +1 -0
- package/dist/m/c-GRWMD6O5.js +1 -0
- package/dist/m/c-GRXHHFPO.js +1 -0
- package/dist/m/c-HG2C77BM.js +4 -0
- package/dist/m/c-HHGJBU4D.js +1 -0
- package/dist/m/c-HMV6P4RX.js +1 -0
- package/dist/m/c-HMYWIHFG.js +1 -0
- package/dist/m/c-HT2DKBV2.js +1 -0
- package/dist/m/c-I2SCCUEW.js +1 -0
- package/dist/m/{c-TJ6WOJL3.js → c-ICJYHABF.js} +2 -2
- package/dist/m/c-IMZCWYHR.js +7 -0
- package/dist/m/c-IVMD3FEM.js +1 -0
- package/dist/m/{c-WDC5GVKU.js → c-IVTRVENZ.js} +1 -1
- package/dist/m/c-JKZJIUIP.js +1 -0
- package/dist/m/{c-UDUUJPFZ.js → c-JNLX3RJB.js} +1 -1
- package/dist/m/c-K3ADYNLU.js +1 -0
- package/dist/m/c-KGHVFRR3.js +1 -0
- package/dist/m/{c-5QWQ7A5L.js → c-KJJPV77R.js} +1 -1
- package/dist/m/{c-CZUSOB7V.js → c-KNPDOMDY.js} +1 -1
- package/dist/m/{c-EZU56NQV.js → c-KP64LT2A.js} +2 -2
- package/dist/m/c-KQ7E3PYY.js +1 -0
- package/dist/m/c-L3F5ZLIV.js +1 -0
- package/dist/m/{c-3RUU4TPX.js → c-L42OLXWM.js} +3 -2
- package/dist/m/c-L5VFATT6.js +1 -0
- package/dist/m/c-L7JL5TL3.js +3 -0
- package/dist/m/c-LKSL4AUJ.js +1 -0
- package/dist/m/c-M6FNQCTQ.js +1 -0
- package/dist/m/c-MCOOHCSG.js +1 -0
- package/dist/m/c-MHI3GYKF.js +1 -0
- package/dist/m/c-MWXFLW4J.js +1 -0
- package/dist/m/{c-5RJFTLSF.js → c-NEL7HQW3.js} +1 -1
- package/dist/m/{c-DCXOXBF3.js → c-NQJRVJ56.js} +1 -1
- package/dist/m/c-NWX3MFT4.js +1 -0
- package/dist/m/{c-HPURYVZS.js → c-OJYM642Q.js} +1 -1
- package/dist/m/c-OKXI52N7.js +1 -0
- package/dist/m/{c-R3L7ZJGB.js → c-OPLUZR3A.js} +1 -1
- package/dist/m/{c-GSFIGKOP.js → c-OTMKN2OO.js} +1 -1
- package/dist/m/{c-6NC5I2TV.js → c-OYRZ7XG2.js} +1 -1
- package/dist/m/{c-EVCQ3BKA.js → c-P3OFYUMA.js} +1 -1
- package/dist/m/c-PLN76GF3.js +6 -0
- package/dist/m/c-PLP4JKFC.js +1 -0
- package/dist/m/c-Q26MME6N.js +1 -0
- package/dist/m/{c-S7H2DRCB.js → c-Q3XOWZEV.js} +1 -1
- package/dist/m/{c-FRLHSY7E.js → c-QIKT6SKM.js} +1 -1
- package/dist/m/c-QIXT3Q7C.js +28 -0
- package/dist/m/c-QO4HNGCQ.js +1 -0
- package/dist/m/{c-JU3NK25H.js → c-R27DWQKX.js} +1 -1
- package/dist/m/{c-RSMOODDU.js → c-R2XUODVY.js} +1 -1
- package/dist/m/{c-QNKREOL6.js → c-R7LBFMF5.js} +1 -1
- package/dist/m/c-RND3G2S2.js +1 -0
- package/dist/m/{c-Q622NS2Y.js → c-S2U6NJU4.js} +1 -1
- package/dist/m/c-SPZPGD3R.js +1 -0
- package/dist/m/c-SW4YEG2D.js +8 -0
- package/dist/m/c-T637T7SN.js +1 -0
- package/dist/m/c-TJAXGIRV.js +1 -0
- package/dist/m/{c-RYUXUUBX.js → c-TNEM3RNM.js} +1 -1
- package/dist/m/c-TTB5EK4S.js +32 -0
- package/dist/m/c-U7SHNWDH.js +1 -0
- package/dist/m/c-UDHIVLYH.js +20 -0
- package/dist/m/{c-BBVGTQG7.js → c-UGNV5MFB.js} +1 -1
- package/dist/m/{c-QICP2YR5.js → c-UORXLSD3.js} +1 -1
- package/dist/m/c-UPD33ZPE.js +1 -0
- package/dist/m/c-URSMSFCB.js +1 -0
- package/dist/m/c-UY4QX42B.js +1 -0
- package/dist/m/c-V44KWI2L.js +4 -0
- package/dist/m/c-VILENZTD.js +1 -0
- package/dist/m/{c-HDDEEL77.js → c-VJYEVRYK.js} +1 -1
- package/dist/m/{c-SMBZG5X4.js → c-VR2BJ4AN.js} +1 -1
- package/dist/m/c-W4JCVLAB.js +1 -0
- package/dist/m/c-W6DQSHXI.js +135 -0
- package/dist/m/c-WBGWGOM7.js +1 -0
- package/dist/m/{c-4L3BTFRK.js → c-WCXLG3MV.js} +1 -1
- package/dist/m/c-WGW764WX.js +1 -0
- package/dist/m/c-WMRJKQ2V.js +5 -0
- package/dist/m/c-WNTYKCDG.js +1 -0
- package/dist/m/c-WQWIRWO3.js +72 -0
- package/dist/m/c-X5LNHET5.js +1 -0
- package/dist/m/{c-I2ZATQCD.js → c-X5TSXZYJ.js} +2 -2
- package/dist/m/c-XGH4GS2T.js +1 -0
- package/dist/m/c-Y6F2FORL.js +1 -0
- package/dist/m/c-YBKHUAK7.js +10 -0
- package/dist/m/c-YBSS55KU.js +20 -0
- package/dist/m/c-YCLU4UNT.js +2 -0
- package/dist/m/c-YVZ2L7CE.js +1 -0
- package/dist/m/c-ZK4GIZH2.js +1 -0
- package/dist/m/c-ZRXJD4G6.js +1 -0
- package/dist/m/c-ZWBI4HYK.js +1 -0
- package/dist/m/core/{admin-attrs-QHOKPJ7W.js → admin-attrs-YY7T5FGU.js} +1 -1
- package/dist/m/core/autosave-S6OMNDCK.js +1 -0
- package/dist/m/core/conflict-notice-IWHMHH43.js +1 -0
- package/dist/m/core/{host-permission-FNXVEFNE.js → host-permission-6EVJGNPL.js} +1 -1
- package/dist/m/core/is-edit-mode-GCX6767E.js +1 -0
- package/dist/m/core/{persist-JFYRHMRJ.js → persist-UKXV5KLA.js} +1 -1
- package/dist/m/core/recovery-DRFZRJED.js +1 -0
- package/dist/m/core/save-LYY7K6U7.js +1 -0
- package/dist/m/core/save-core-MKRPSEEO.js +1 -0
- package/dist/m/core/snapshot-NU3YM6GR.js +1 -0
- package/dist/m/core/unsaved-warning-7QTKEN7Z.js +1 -0
- package/dist/m/internals/{index-PVXGPUDA.js → index-TGLQINN3.js} +1 -1
- package/dist/m/loader-3BBNZZGM.js +1 -0
- package/dist/m/manifest-F449FF98.js +1 -0
- package/dist/m/manifest-edit-4396A009.js +1 -0
- package/dist/m/manifest.json +2111 -1573
- package/dist/m/page/{editor-NNJA4OKD.js → editor-6LRB3GE4.js} +123 -21
- package/dist/m/plugins/ai-edit-UTV7YO2I.js +6 -0
- package/dist/m/plugins/{cms-HP3LSTPN.js → cms-LRAOZHT7.js} +9 -9
- package/dist/m/plugins/{demo-RM5IR6AO.js → demo-OYO5GCAO.js} +1 -1
- package/dist/m/plugins/{derive-UAAA4V4S.js → derive-FRE5JJQE.js} +1 -1
- package/dist/m/plugins/indicator-4VDXWYTD.js +1 -0
- package/dist/m/plugins/live-AD4H6XSL.js +1 -0
- package/dist/m/plugins/menu-M5WW7DBF.js +1 -0
- package/dist/m/plugins/page-MD3T2ZX3.js +2 -0
- package/dist/m/plugins/page-view-PAWVZNFY.js +1 -0
- package/dist/m/plugins/{people-SGPJKANK.js → people-JCHVPF7P.js} +1 -1
- package/dist/m/plugins/quickcrop-BQ5YYFCH.js +26 -0
- package/dist/m/plugins/{richclay-NRQDSWX6.js → richclay-KLGETK77.js} +2 -2
- package/dist/m/plugins/sortable-4S6SQC3D.js +1 -0
- package/dist/m/plugins/source-TJXOIOYY.js +1 -0
- package/dist/m/plugins/undo-NLPGCJQY.js +1 -0
- package/dist/m/plugins/{unsent-HJFLQJ2O.js → unsent-OA4RGBUT.js} +1 -1
- package/dist/m/plugins/upgrade-HSUNDNJD.js +1 -0
- package/dist/m/plugins/{upload-WLYKK6TL.js → upload-NHGJXZK2.js} +1 -1
- package/dist/m/plugins/visitor-drafts-BW43DGY3.js +20 -0
- package/dist/m/plugins/visitor-drafts-owner-7ODQG7JX.js +1 -0
- package/dist/m/plugins/{wire-4N6GYAF6.js → wire-VBWXEXU2.js} +1 -1
- package/dist/m/reader-core-4W2KYEWQ.js +77 -0
- package/dist/m/route/route-62CHXL5B.js +1 -0
- package/dist/m/sync/live-sync-MO5DH33W.js +1 -0
- package/dist/m/ui/index-IVWN2QC4.js +1 -0
- package/dist/m/vendor/sap-core.vendor-RN4ZVY4X.js +6 -0
- package/dist/offline-manifest.json +1367 -930
- package/dist/page/themes/light-1.css +8 -7
- package/dist/server/core.cjs +1440 -288
- package/dist/server/offline-runtime.cjs +63 -63
- package/dist/server/offline-runtime.mjs +63 -63
- package/dist/server/page-compaction-worker.cjs +3710 -0
- package/dist/server/rooms.mjs +5 -0
- package/docs/guide.md +653 -101
- package/entries/sap.js +5 -5
- package/package.json +1 -1
- package/src/core/admin-contenteditable.js +5 -2
- package/src/core/admin-inputs.js +1 -0
- package/src/core/admin-onclick.js +2 -1
- package/src/core/conflict-notice-ui.js +4 -7
- package/src/core/download.js +2 -2
- package/src/core/host-meta.js +38 -0
- package/src/core/is-edit-mode.js +17 -1
- package/src/core/mode-key.js +125 -19
- package/src/core/mode-support.js +5 -0
- package/src/core/mode-transition.js +20 -6
- package/src/core/preserve-authored.js +4 -4
- package/src/core/recovery.js +121 -33
- package/src/core/save-accepted.js +33 -0
- package/src/core/save-core.js +106 -31
- package/src/core/save-job.js +108 -0
- package/src/core/save-prepare.js +53 -0
- package/src/core/save-size-notice.js +3 -1
- package/src/core/save-slices.js +15 -0
- package/src/core/save.js +557 -127
- package/src/core/serialize-steps.js +109 -0
- package/src/core/snapshot.js +170 -39
- package/src/core/source-map.js +83 -38
- package/src/core/stale-host-notice.js +1 -0
- package/src/core/upgrade-run.js +59 -8
- package/src/dom/active-element.js +5 -0
- package/src/lib/assets.js +1 -0
- package/src/lib/slice.js +65 -0
- package/src/lib/uimotion.js +774 -0
- package/src/lib/unsaved-state.js +2 -2
- package/src/live/fast-lane.js +10 -3
- package/src/live/local-lane.js +202 -11
- package/src/live/ops.js +16 -0
- package/src/live/page-compaction.js +162 -0
- package/src/live/server-lane.js +1 -0
- package/src/live/store.js +11 -3
- package/src/loader-logic.js +3 -1
- package/src/loader.js +14 -4
- package/src/page/adopt-boot.js +2 -1
- package/src/page/awareness.js +33 -2
- package/src/page/blocks.js +89 -27
- package/src/page/boot-pack.js +1 -1
- package/src/page/chart-tables.js +21 -3
- package/src/page/chart.js +406 -63
- package/src/page/checklist.js +10 -135
- package/src/page/checkpoint-proof.js +7 -1
- package/src/page/chrome.js +250 -51
- package/src/page/clipboard-shape.js +126 -0
- package/src/page/drag.js +33 -3
- package/src/page/editor.js +136 -25
- package/src/page/export-assets.js +357 -0
- package/src/page/export-html.js +209 -0
- package/src/page/export-markdown.js +361 -0
- package/src/page/features/checklist.js +428 -0
- package/src/page/features/export-html.js +189 -0
- package/src/page/features/export-markdown.js +169 -0
- package/src/page/features/import-markdown.js +349 -0
- package/src/page/features/media.js +61 -5
- package/src/page/features/registry.js +18 -0
- package/src/page/features/table.js +373 -83
- package/src/page/features/title-cover.js +331 -0
- package/src/page/features/title-icon.js +213 -0
- package/src/page/features/toc.js +87 -0
- package/src/page/format-command.js +25 -1
- package/src/page/format-gate.js +68 -18
- package/src/page/format-host.js +17 -0
- package/src/page/format-native-commands.js +21 -5
- package/src/page/image-actions.js +64 -0
- package/src/page/import-markdown.js +262 -0
- package/src/page/items.js +135 -17
- package/src/page/markdown.js +6 -2
- package/src/page/media.js +35 -119
- package/src/page/placeholder.js +14 -1
- package/src/page/projection.js +98 -10
- package/src/page/recover.js +10 -12
- package/src/page/recovery-ui.js +464 -0
- package/src/page/rich/chart.js +63 -7
- package/src/page/save-projection.js +28 -0
- package/src/page/save-states.js +13 -3
- package/src/page/schema.js +19 -3
- package/src/page/table-paste.js +3 -1
- package/src/page/table-style.js +4 -4
- package/src/page/table.js +44 -2
- package/src/page/themes/light-1.css +8 -7
- package/src/page/themes/light-1.source.css +8 -7
- package/src/page/toc-link.js +31 -0
- package/src/page/toc.js +5 -0
- package/src/page/view-hooks.js +38 -12
- package/src/page/view.js +13 -0
- package/src/page/ybind/binding.js +88 -5
- package/src/page/ybind/bridge.js +187 -20
- package/src/page/ybind/containment.js +162 -0
- package/src/page/ybind/doc.js +17 -9
- package/src/page/ybind/file-debt.js +63 -0
- package/src/page/ybind/layout.js +7 -2
- package/src/page/ybind/marks.js +1 -1
- package/src/page/ybind/moves.js +5 -4
- package/src/page/ybind/origins.js +106 -4
- package/src/page/ybind/parts.js +8 -1
- package/src/page/ybind/provider.js +113 -17
- package/src/page/ybind/recovery-proof.js +32 -9
- package/src/page/ybind/recovery-replay.js +558 -15
- package/src/page/ybind/recovery.js +174 -45
- package/src/page/ybind/table.js +67 -11
- package/src/page/ybind/walk-delta.js +258 -0
- package/src/page/ybind/walk.js +54 -29
- package/src/page/ybind/writer.js +1 -1
- package/src/plugins/ai-edit.js +13 -9
- package/src/plugins/indicator-chip.js +91 -0
- package/src/plugins/indicator.js +13 -80
- package/src/plugins/live.js +89 -14
- package/src/plugins/menu/actions.js +196 -0
- package/src/plugins/menu/people.js +279 -0
- package/src/plugins/menu/placement.js +121 -0
- package/src/plugins/menu/preferences.js +9 -0
- package/src/plugins/menu/seo.js +316 -397
- package/src/plugins/menu/style.js +171 -0
- package/src/plugins/menu/variants.js +296 -0
- package/src/plugins/menu.js +186 -183
- package/src/plugins/page-view.js +3 -2
- package/src/plugins/page.js +249 -44
- package/src/plugins/sortable.js +8 -1
- package/src/plugins/source.js +6 -0
- package/src/plugins/upgrade.js +51 -17
- package/src/plugins/upload-ui.js +12 -17
- package/src/plugins/visitor-drafts/bottom-ui.js +12 -4
- package/src/plugins/visitor-drafts/intro-style.js +7 -2
- package/src/plugins/visitor-drafts/intro.js +5 -3
- package/src/plugins/visitor-drafts/owner-chip.js +8 -12
- package/src/plugins/visitor-drafts/prompt.js +11 -9
- package/src/plugins/visitor-drafts/source.js +4 -3
- package/src/plugins/visitor-drafts/store.js +138 -9
- package/src/plugins/visitor-drafts/ui-memory.js +2 -2
- package/src/plugins/visitor-drafts-owner.js +4 -6
- package/src/plugins/visitor-drafts.js +5 -3
- package/src/recovery/store.js +1 -1
- package/src/route/route.js +4 -0
- package/src/server/rooms/index.js +5 -1
- package/src/server/rooms/live-data-rooms.js +302 -50
- package/src/server/rooms/page-compaction-worker.js +12 -0
- package/src/server/rooms/page-compactor.js +92 -0
- package/src/server/rooms/page-room-conformance.js +461 -0
- package/src/source/parse-steps.js +94 -0
- package/src/source/session.js +233 -57
- package/src/sync/editing-sender.js +12 -0
- package/src/sync/live-sync-edit.js +22 -2
- package/src/sync/live-sync.js +150 -23
- package/src/sync/page-relay.js +52 -0
- package/src/sync/presence-store.js +44 -4
- package/src/sync/presence.js +6 -3
- package/src/sync/saved-stream.js +11 -6
- package/src/ui/bevel-controls.js +1 -0
- package/src/ui/bevel-dialog.js +5 -2
- package/src/ui/editor-ui.js +77 -0
- package/src/ui/page-colour.js +281 -0
- package/src/ui/toast.js +16 -7
- package/src/vendor/hyper-html-api-upgrade.vendor.js +2 -2
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +9 -9
- package/src/vendor/parse5.vendor.js +2 -2
- package/src/vendor/sap-core.vendor.js +5 -5
- package/dist/m/c-2SPVQSHC.js +0 -1
- package/dist/m/c-336SGU5W.js +0 -1
- package/dist/m/c-3H6BZDNJ.js +0 -6
- package/dist/m/c-4DFEJ2PO.js +0 -3
- package/dist/m/c-56QRZTZH.js +0 -1
- package/dist/m/c-5J4E7O4Y.js +0 -4
- package/dist/m/c-5LKDWQTL.js +0 -19
- package/dist/m/c-5V3MOVJT.js +0 -1
- package/dist/m/c-6AZOGAPE.js +0 -1
- package/dist/m/c-6CRUUXOX.js +0 -5
- package/dist/m/c-6HMB24EV.js +0 -1
- package/dist/m/c-6KEVEQ7L.js +0 -1
- package/dist/m/c-A3E3NIMC.js +0 -1
- package/dist/m/c-BQ6LOBEE.js +0 -1
- package/dist/m/c-BTDI4Y23.js +0 -1
- package/dist/m/c-CJ3A7ZKE.js +0 -1
- package/dist/m/c-CQHPGKX2.js +0 -1
- package/dist/m/c-DFS4XZJV.js +0 -2
- package/dist/m/c-DNENWY4O.js +0 -1
- package/dist/m/c-E4LIR5X5.js +0 -1
- package/dist/m/c-FDNHHZY5.js +0 -1
- package/dist/m/c-FROJUZMV.js +0 -1
- package/dist/m/c-G2JPKCTP.js +0 -1
- package/dist/m/c-GB6TU7WV.js +0 -1
- package/dist/m/c-GFJJEBTU.js +0 -1
- package/dist/m/c-GJAEGGXY.js +0 -1
- package/dist/m/c-GOWBDM6J.js +0 -1
- package/dist/m/c-HFKUVACH.js +0 -1
- package/dist/m/c-HHDFCNHV.js +0 -1
- package/dist/m/c-IEM4NTCS.js +0 -1
- package/dist/m/c-JDCX26UP.js +0 -25
- package/dist/m/c-KGVGROZT.js +0 -1
- package/dist/m/c-KQ6TYJAP.js +0 -135
- package/dist/m/c-LFPHCXY3.js +0 -1
- package/dist/m/c-LRPUO2MX.js +0 -1
- package/dist/m/c-LWLBHLVC.js +0 -3
- package/dist/m/c-M2L47S2X.js +0 -7
- package/dist/m/c-MFP2ZWD4.js +0 -1
- package/dist/m/c-MKSQ4Y57.js +0 -1
- package/dist/m/c-NUFFJVVJ.js +0 -1
- package/dist/m/c-NUHSPT5P.js +0 -1
- package/dist/m/c-O72HVYSA.js +0 -1
- package/dist/m/c-OIBUTDXI.js +0 -1
- package/dist/m/c-OW5QIGG3.js +0 -1
- package/dist/m/c-PGRCK73F.js +0 -1
- package/dist/m/c-Q7NQD65V.js +0 -1
- package/dist/m/c-QH63LQOS.js +0 -1
- package/dist/m/c-R7IWVINQ.js +0 -1
- package/dist/m/c-RM7J7BV2.js +0 -1
- package/dist/m/c-S4ZEH46B.js +0 -9
- package/dist/m/c-SDAXDM2D.js +0 -1
- package/dist/m/c-SMGU7RT3.js +0 -235
- package/dist/m/c-SPIORRYS.js +0 -1
- package/dist/m/c-SWLRT66R.js +0 -1
- package/dist/m/c-TCJTVAFN.js +0 -1
- package/dist/m/c-TQEMVJCS.js +0 -1
- package/dist/m/c-TYLXX4NF.js +0 -21
- package/dist/m/c-U62OB4BT.js +0 -1
- package/dist/m/c-U6YWUAR3.js +0 -8
- package/dist/m/c-UDCSU5G5.js +0 -2
- package/dist/m/c-VI5RMSVY.js +0 -1
- package/dist/m/c-VRZN56XY.js +0 -1
- package/dist/m/c-W5MCHEGA.js +0 -1
- package/dist/m/c-WNYBLIOZ.js +0 -1
- package/dist/m/c-WWXIDH4O.js +0 -28
- package/dist/m/c-XCNTK76U.js +0 -1
- package/dist/m/c-XMS6DPBR.js +0 -1
- package/dist/m/c-ZUCOKOHT.js +0 -1
- package/dist/m/c-ZVPVXTJF.js +0 -4
- package/dist/m/c-ZVRKXKM7.js +0 -1
- package/dist/m/core/autosave-HRYGUWV6.js +0 -1
- package/dist/m/core/conflict-notice-6MROJN2L.js +0 -1
- package/dist/m/core/is-edit-mode-KTWA3O5N.js +0 -1
- package/dist/m/core/recovery-FLTCC2OC.js +0 -1
- package/dist/m/core/save-HQZ4S667.js +0 -1
- package/dist/m/core/save-core-KGQWFUNH.js +0 -1
- package/dist/m/core/snapshot-EGQZNT45.js +0 -1
- package/dist/m/core/unsaved-warning-IDJLD66H.js +0 -1
- package/dist/m/loader-S4I7GKXR.js +0 -1
- package/dist/m/manifest-4C419D67.js +0 -1
- package/dist/m/manifest-edit-B077F288.js +0 -1
- package/dist/m/plugins/ai-edit-QN4PMMNL.js +0 -6
- package/dist/m/plugins/indicator-URDBBOQO.js +0 -1
- package/dist/m/plugins/live-HFWD4OIH.js +0 -1
- package/dist/m/plugins/menu-3HIEQSI6.js +0 -138
- package/dist/m/plugins/page-JOKB6XPR.js +0 -2
- package/dist/m/plugins/page-view-NXOJHNW6.js +0 -1
- package/dist/m/plugins/quickcrop-QNY3PKLD.js +0 -26
- package/dist/m/plugins/sortable-GWT4PWDV.js +0 -1
- package/dist/m/plugins/source-4ZRSAIYM.js +0 -1
- package/dist/m/plugins/undo-VDA5P7FH.js +0 -1
- package/dist/m/plugins/upgrade-W7FG5VFG.js +0 -1
- package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +0 -21
- package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +0 -1
- package/dist/m/reader-core-DXYCURFF.js +0 -68
- package/dist/m/route/route-KOCZSEGN.js +0 -1
- package/dist/m/sync/live-sync-J7VMYTKS.js +0 -1
- package/dist/m/ui/index-3JLVI27O.js +0 -1
- package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +0 -6
- /package/dist/m/{c-FILLTJA7.js → c-QTTJYJMA.js} +0 -0
- /package/dist/m/plugins/{quickcrop-QNY3PKLD.js.LEGAL.txt → quickcrop-BQ5YYFCH.js.LEGAL.txt} +0 -0
- /package/dist/m/plugins/{richclay-NRQDSWX6.js.LEGAL.txt → richclay-KLGETK77.js.LEGAL.txt} +0 -0
package/src/core/source-map.js
CHANGED
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
* verify(out, today) reparse and compare trees before anything is sent
|
|
22
22
|
* adopt(bytes) re-model and re-pair against what the host accepted
|
|
23
23
|
*
|
|
24
|
+
* EVERY EXPENSIVE WALK IS A GENERATOR. `modelSteps`, `pairCapturedSteps`, `vDiffSteps`,
|
|
25
|
+
* `vParseErrorsSteps` and the verifier built from them yield between whole units of work,
|
|
26
|
+
* and the synchronous functions are `drain` of those generators (`src/lib/slice.js`). One
|
|
27
|
+
* walk, so a sliced run and a one-shot run cannot disagree about what this module says.
|
|
28
|
+
*
|
|
24
29
|
* THE FLOOR IS TODAY'S BEHAVIOUR. Anything that does not verify is sent as the full
|
|
25
30
|
* serialization instead, and counted. A fetch that does not return this document, a
|
|
26
31
|
* source whose shape outside <html> disagrees with the live document, a render that
|
|
@@ -37,13 +42,17 @@
|
|
|
37
42
|
* of this code wrote `by <a>Ana</a> <a>Bo</a>` back as `AnaBo` with a green check.
|
|
38
43
|
*/
|
|
39
44
|
|
|
40
|
-
import {
|
|
45
|
+
import { parseSteps } from '../source/parse-steps.js';
|
|
46
|
+
import { drain } from '../lib/slice.js';
|
|
41
47
|
|
|
42
48
|
const RAW_TEXT = new Set(['script', 'style', 'xmp', 'iframe', 'noembed', 'noframes', 'plaintext', 'noscript']);
|
|
43
49
|
const RCDATA = new Set(['textarea', 'title']);
|
|
44
50
|
const textContext = (tag) => (RAW_TEXT.has(tag) ? 'raw' : RCDATA.has(tag) ? 'rcdata' : 'normal');
|
|
45
51
|
const VOID = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
|
46
52
|
const XHTML = 'http://www.w3.org/1999/xhtml';
|
|
53
|
+
// Nodes one walk compares between two yields. It only decides where a sliced walk may
|
|
54
|
+
// pause; the walk itself is the same walk at any value.
|
|
55
|
+
const YIELD_EVERY = 1500;
|
|
47
56
|
|
|
48
57
|
const escText = (s) => s.replace(/&/g, '&').replace(/ /g, ' ').replace(/</g, '<').replace(/>/g, '>');
|
|
49
58
|
const escAttr = (s) => s.replace(/&/g, '&').replace(/ /g, ' ').replace(/"/g, '"');
|
|
@@ -53,16 +62,21 @@ const escAttr = (s) => s.replace(/&/g, '&').replace(/ /g, ' ').replace
|
|
|
53
62
|
// =============================================================================
|
|
54
63
|
|
|
55
64
|
export function model(src) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
return drain(modelSteps(src));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The same model, parsed in slices so a large document does not hold the thread for the
|
|
70
|
+
* whole parse.
|
|
71
|
+
*
|
|
72
|
+
* The error counts come out of the SAME parse, so they cost nothing here. They are the
|
|
73
|
+
* only evidence of input a parser throws away, which a tree comparison cannot see by
|
|
74
|
+
* construction: a duplicate attribute is discarded during parsing, so a render that wrote
|
|
75
|
+
* one twice reparsed to exactly the right tree. That is how the same `xmlns:xlink` was
|
|
76
|
+
* added to a file on every save with the verifier green each time.
|
|
77
|
+
*/
|
|
78
|
+
export function* modelSteps(src) {
|
|
79
|
+
const { document: doc, errors: parseErrors } = yield* parseSteps(src, { sourceCodeLocationInfo: true });
|
|
66
80
|
return modelFromParsed(src, doc, parseErrors);
|
|
67
81
|
}
|
|
68
82
|
|
|
@@ -350,10 +364,26 @@ function keysOfLive(n, keyMap) {
|
|
|
350
364
|
keyMap.set(n, k);
|
|
351
365
|
return k;
|
|
352
366
|
}
|
|
353
|
-
function
|
|
367
|
+
function* keysOfLiveSteps(n, keyMap, walked) {
|
|
368
|
+
if (++walked.n % YIELD_EVERY === 0) yield;
|
|
369
|
+
let k;
|
|
370
|
+
if (n.nodeType === 3) k = { tag: '#text', shallow: 't:' + n.data, content: 't:' + n.data, deep: 't:' + n.data };
|
|
371
|
+
else if (n.nodeType === 8) k = { tag: '#comment', shallow: 'c:' + n.data, content: 'c:' + n.data, deep: 'c:' + n.data };
|
|
372
|
+
else {
|
|
373
|
+
const kids = [];
|
|
374
|
+
for (const c of liveKids(n)) kids.push(yield* keysOfLiveSteps(c, keyMap, walked));
|
|
375
|
+
const shallow = 'e:' + n.localName + '|' + liveAttrsKey(n);
|
|
376
|
+
k = { tag: n.localName, shallow, content: 'e:' + n.localName + '|' + hashKey(kids.map((c) => c.content)), deep: shallow + '|' + hashKey(kids.map((c) => c.deep)) };
|
|
377
|
+
}
|
|
378
|
+
keyMap.set(n, k);
|
|
379
|
+
return k;
|
|
380
|
+
}
|
|
381
|
+
function* keysOfLocSteps(loc, walked) {
|
|
382
|
+
if (++walked.n % YIELD_EVERY === 0) yield;
|
|
354
383
|
if (loc.kind === 'text') return (loc.keys = { tag: '#text', shallow: 't:' + loc.value, content: 't:' + loc.value, deep: 't:' + loc.value });
|
|
355
384
|
if (loc.kind === 'comment') return (loc.keys = { tag: '#comment', shallow: 'c:' + loc.value, content: 'c:' + loc.value, deep: 'c:' + loc.value });
|
|
356
|
-
const kids =
|
|
385
|
+
const kids = [];
|
|
386
|
+
for (const c of loc.children) kids.push(yield* keysOfLocSteps(c, walked));
|
|
357
387
|
const shallow = 'e:' + loc.tag + '|' + srcAttrsKey(loc);
|
|
358
388
|
return (loc.keys = { tag: loc.tag, shallow, content: 'e:' + loc.tag + '|' + hashKey(kids.map((c) => c.content)), deep: shallow + '|' + hashKey(kids.map((c) => c.deep)) });
|
|
359
389
|
}
|
|
@@ -493,10 +523,16 @@ function describeLoc(l) {
|
|
|
493
523
|
* @param {Function} [resolve] - node -> the identity to key the map by (default: itself)
|
|
494
524
|
*/
|
|
495
525
|
export function pair(root, m, resolve = (n) => n) {
|
|
526
|
+
return drain(pairSteps(root, m, resolve));
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/** The same pairing pass, `yield`ing every `YIELD_EVERY` nodes hashed or bound. */
|
|
530
|
+
export function* pairSteps(root, m, resolve = (n) => n) {
|
|
496
531
|
const map = new WeakMap();
|
|
497
532
|
const keyMap = new Map();
|
|
498
|
-
|
|
499
|
-
|
|
533
|
+
const walked = { n: 0 };
|
|
534
|
+
yield* keysOfLiveSteps(root, keyMap, walked);
|
|
535
|
+
yield* keysOfLocSteps(m.root, walked);
|
|
500
536
|
const stats = { paired: 0, unmatchedLive: [], unmatchedSource: [], attrDiffs: [], textDiffs: 0, unresolved: 0 };
|
|
501
537
|
// A token identifying THIS pairing pass, stamped on the model and on every loc that
|
|
502
538
|
// binds. render trusts a loc only when the two still agree, which rules out a loc
|
|
@@ -505,11 +541,12 @@ export function pair(root, m, resolve = (n) => n) {
|
|
|
505
541
|
// model, so holding the node here would keep every node the page has since deleted.
|
|
506
542
|
const gen = {};
|
|
507
543
|
m.gen = gen;
|
|
508
|
-
|
|
544
|
+
yield* bindSteps(root, m.root, map, keyMap, stats, 'html', resolve, gen, walked);
|
|
509
545
|
return { map, stats };
|
|
510
546
|
}
|
|
511
547
|
|
|
512
|
-
function
|
|
548
|
+
function* bindSteps(node, loc, map, keyMap, stats, path, resolve, gen, walked) {
|
|
549
|
+
if (++walked.n % YIELD_EVERY === 0) yield;
|
|
513
550
|
const key = resolve(node);
|
|
514
551
|
if (key) { map.set(key, loc); loc.gen = gen; stats.paired++; }
|
|
515
552
|
else stats.unresolved++;
|
|
@@ -520,7 +557,7 @@ function bind(node, loc, map, keyMap, stats, path, resolve, gen) {
|
|
|
520
557
|
const usedL = new Set(), usedS = new Set();
|
|
521
558
|
for (const [i, j] of pairs) {
|
|
522
559
|
usedL.add(i); usedS.add(j);
|
|
523
|
-
|
|
560
|
+
yield* bindSteps(L[i], S[j], map, keyMap, stats, path + '>' + (L[i].nodeType === 1 ? L[i].localName : '#') + '[' + i + ']', resolve, gen, walked);
|
|
524
561
|
}
|
|
525
562
|
for (let i = 0; i < L.length; i++) if (!usedL.has(i)) stats.unmatchedLive.push({ path, node: describe(L[i]) });
|
|
526
563
|
for (let j = 0; j < S.length; j++) if (!usedS.has(j)) stats.unmatchedSource.push({ path, node: describeLoc(S[j]) });
|
|
@@ -547,9 +584,14 @@ function bind(node, loc, map, keyMap, stats, path, resolve, gen) {
|
|
|
547
584
|
* @returns {?{map: WeakMap, stats: Object}} null when the trees are not the same shape
|
|
548
585
|
*/
|
|
549
586
|
export function pairCaptured(root, m, provenance = (n) => n) {
|
|
587
|
+
return drain(pairCapturedSteps(root, m, provenance));
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/** The same pairing walk, `yield`ing every `YIELD_EVERY` nodes compared. */
|
|
591
|
+
export function* pairCapturedSteps(root, m, provenance = (n) => n) {
|
|
550
592
|
if (!m.root) return null;
|
|
551
593
|
const found = [];
|
|
552
|
-
const unresolved =
|
|
594
|
+
const unresolved = yield* matchCapturedSteps(root, m.root, provenance, found, { n: 0 });
|
|
553
595
|
if (unresolved < 0) return null;
|
|
554
596
|
const map = new WeakMap();
|
|
555
597
|
// One token for this pass, set on the model and on every bound loc, exactly as `pair`
|
|
@@ -567,7 +609,8 @@ export function pairCaptured(root, m, provenance = (n) => n) {
|
|
|
567
609
|
}
|
|
568
610
|
|
|
569
611
|
/** @returns {number} unresolved nodes below this pair, or -1 when the two differ at all */
|
|
570
|
-
function
|
|
612
|
+
function* matchCapturedSteps(node, loc, provenance, found, compared) {
|
|
613
|
+
if (++compared.n % YIELD_EVERY === 0) yield;
|
|
571
614
|
if (loc.kind === 'text') {
|
|
572
615
|
if (node.nodeType !== 3 || node.data !== loc.value) return -1;
|
|
573
616
|
} else if (loc.kind === 'comment') {
|
|
@@ -583,7 +626,7 @@ function matchCaptured(node, loc, provenance, found) {
|
|
|
583
626
|
const L = capturedKids(node), S = loc.children;
|
|
584
627
|
if (L.length !== S.length) return -1;
|
|
585
628
|
for (let i = 0; i < L.length; i++) {
|
|
586
|
-
const n =
|
|
629
|
+
const n = yield* matchCapturedSteps(L[i], S[i], provenance, found, compared);
|
|
587
630
|
if (n < 0) return -1;
|
|
588
631
|
unresolved += n;
|
|
589
632
|
}
|
|
@@ -1027,7 +1070,7 @@ function lis(vals) {
|
|
|
1027
1070
|
// the right one.
|
|
1028
1071
|
|
|
1029
1072
|
export function verify(rendered, today, liveDocument, clone = null, sourceErrors = null) {
|
|
1030
|
-
return
|
|
1073
|
+
return drain(verifyRenderedSteps(rendered, today, liveDocument, clone, sourceErrors, false));
|
|
1031
1074
|
}
|
|
1032
1075
|
|
|
1033
1076
|
/**
|
|
@@ -1044,10 +1087,14 @@ export function verify(rendered, today, liveDocument, clone = null, sourceErrors
|
|
|
1044
1087
|
* same walk, told to retain what it parsed.
|
|
1045
1088
|
*/
|
|
1046
1089
|
export function verifyForSave(rendered, today, liveDocument, clone = null, sourceErrors = null) {
|
|
1047
|
-
return
|
|
1090
|
+
return drain(verifyForSaveSteps(rendered, today, liveDocument, clone, sourceErrors));
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
export function* verifyForSaveSteps(rendered, today, liveDocument, clone = null, sourceErrors = null) {
|
|
1094
|
+
return yield* verifyRenderedSteps(rendered, today, liveDocument, clone, sourceErrors, true);
|
|
1048
1095
|
}
|
|
1049
1096
|
|
|
1050
|
-
function
|
|
1097
|
+
export function* verifyRenderedSteps(rendered, today, liveDocument, clone, sourceErrors, retain) {
|
|
1051
1098
|
const P = new DOMParser();
|
|
1052
1099
|
const A = P.parseFromString(rendered, 'text/html');
|
|
1053
1100
|
const outsideA = vOutside(A), outsideLive = vOutside(liveDocument);
|
|
@@ -1060,17 +1107,17 @@ function verifyRendered(rendered, today, liveDocument, clone, sourceErrors, reta
|
|
|
1060
1107
|
let cloneDiff = null;
|
|
1061
1108
|
if (clone) {
|
|
1062
1109
|
at = [];
|
|
1063
|
-
cloneDiff =
|
|
1110
|
+
cloneDiff = yield* vDiffSteps(A.documentElement, clone, 'html', at);
|
|
1064
1111
|
if (!cloneDiff) {
|
|
1065
|
-
const w =
|
|
1112
|
+
const w = yield* vParseErrorsSteps(rendered, sourceErrors, retain);
|
|
1066
1113
|
if (w.diff) return { ok: false, diff: w.diff };
|
|
1067
1114
|
return retain ? withCandidate({ ok: true, diff: null, oracle: 'clone' }, w, rendered, liveDocument)
|
|
1068
1115
|
: { ok: true, diff: null, oracle: 'clone' };
|
|
1069
1116
|
}
|
|
1070
1117
|
}
|
|
1071
1118
|
const B = P.parseFromString(today, 'text/html');
|
|
1072
|
-
const diff =
|
|
1073
|
-
const worse = diff ? null :
|
|
1119
|
+
const diff = yield* vDiffSteps(A.documentElement, B.documentElement, 'html');
|
|
1120
|
+
const worse = diff ? null : yield* vParseErrorsSteps(rendered, sourceErrors, retain);
|
|
1074
1121
|
if (!diff) {
|
|
1075
1122
|
if (worse.diff) return { ok: false, diff: worse.diff };
|
|
1076
1123
|
return retain ? withCandidate({ ok: true, diff: null, oracle: 'today' }, worse, rendered, liveDocument)
|
|
@@ -1114,12 +1161,9 @@ export function nodeAt(root, at) {
|
|
|
1114
1161
|
* represent, such as a duplicated element, change the tree, and the comparison above
|
|
1115
1162
|
* is what catches those.
|
|
1116
1163
|
*/
|
|
1117
|
-
function
|
|
1164
|
+
export function* vParseErrorsSteps(rendered, sourceErrors, retain) {
|
|
1118
1165
|
if (!sourceErrors) return { diff: null };
|
|
1119
|
-
const seen =
|
|
1120
|
-
const doc = parse(rendered, retain
|
|
1121
|
-
? { sourceCodeLocationInfo: true, onParseError: (e) => seen.set(e.code, (seen.get(e.code) || 0) + 1) }
|
|
1122
|
-
: { onParseError: (e) => seen.set(e.code, (seen.get(e.code) || 0) + 1) });
|
|
1166
|
+
const { document: doc, errors: seen } = yield* parseSteps(rendered, retain ? { sourceCodeLocationInfo: true } : {});
|
|
1123
1167
|
for (const [code, n] of seen) {
|
|
1124
1168
|
const was = sourceErrors.get(code) || 0;
|
|
1125
1169
|
if (n > was) return { diff: `the render introduced parse errors the source does not have: ${code} ${was} -> ${n}` };
|
|
@@ -1164,7 +1208,7 @@ function vOutside(doc) {
|
|
|
1164
1208
|
* still changes the tree its markup parses to. Recursion terminates because each step
|
|
1165
1209
|
* compares strictly less markup than the one above it.
|
|
1166
1210
|
*/
|
|
1167
|
-
function
|
|
1211
|
+
function* vNoscriptSteps(a, b, path, compared) {
|
|
1168
1212
|
const P = new DOMParser();
|
|
1169
1213
|
// Read each side the way it was parsed, which verify fixes, not the node. `a` is always
|
|
1170
1214
|
// the render reparsed by DOMParser, with scripting off, so its <noscript> text is TEXT,
|
|
@@ -1177,7 +1221,7 @@ function vNoscript(a, b, path) {
|
|
|
1177
1221
|
const kids = Array.from(el.childNodes);
|
|
1178
1222
|
return kids.length && kids.every((n) => n.nodeType === 3) ? kids.map((n) => n.data).join('') : el.innerHTML;
|
|
1179
1223
|
};
|
|
1180
|
-
return
|
|
1224
|
+
return yield* vDiffSteps(P.parseFromString(a.innerHTML, 'text/html').body, P.parseFromString(raw(b), 'text/html').body, path + '>#noscript', [], compared);
|
|
1181
1225
|
}
|
|
1182
1226
|
function vKids(el) {
|
|
1183
1227
|
const list = el.localName === 'template' && el.content ? el.content.childNodes : el.childNodes;
|
|
@@ -1197,17 +1241,18 @@ function sameAttrsInOrder(a, b) {
|
|
|
1197
1241
|
}
|
|
1198
1242
|
return true;
|
|
1199
1243
|
}
|
|
1200
|
-
function
|
|
1244
|
+
export function* vDiffSteps(a, b, path, at = [], compared = { n: 0 }) {
|
|
1245
|
+
if (++compared.n % YIELD_EVERY === 0) yield;
|
|
1201
1246
|
if (a.nodeType !== b.nodeType) return path + ': node type ' + a.nodeType + ' vs ' + b.nodeType;
|
|
1202
1247
|
if (a.nodeType === 3 || a.nodeType === 8) return a.data === b.data ? null : path + ': text ' + JSON.stringify(a.data.slice(0, 60)) + ' vs ' + JSON.stringify(b.data.slice(0, 60));
|
|
1203
1248
|
if (a.localName !== b.localName || a.namespaceURI !== b.namespaceURI) return path + ': tag ' + a.localName + ' vs ' + b.localName;
|
|
1204
1249
|
if (!sameAttrsInOrder(a, b) && vAttrs(a) !== vAttrs(b)) return path + ': attrs ' + vAttrs(a) + ' vs ' + vAttrs(b);
|
|
1205
|
-
if (a.localName === 'noscript' && a.namespaceURI === XHTML) return
|
|
1250
|
+
if (a.localName === 'noscript' && a.namespaceURI === XHTML) return yield* vNoscriptSteps(a, b, path, compared);
|
|
1206
1251
|
const ka = vKids(a), kb = vKids(b);
|
|
1207
1252
|
if (ka.length !== kb.length) return path + ': ' + ka.length + ' vs ' + kb.length + ' children';
|
|
1208
1253
|
for (let i = 0; i < ka.length; i++) {
|
|
1209
1254
|
at.push(i);
|
|
1210
|
-
const d =
|
|
1255
|
+
const d = yield* vDiffSteps(ka[i], kb[i], path + '>' + (ka[i].localName || '#') + '[' + i + ']', at, compared);
|
|
1211
1256
|
if (d) return d;
|
|
1212
1257
|
at.pop();
|
|
1213
1258
|
}
|
package/src/core/upgrade-run.js
CHANGED
|
@@ -8,6 +8,8 @@ const MANIFEST_FAILED = "The new version could not be downloaded. Nothing was ch
|
|
|
8
8
|
const SAVE_FAILED = "The upgrade could not be saved. Nothing was changed.";
|
|
9
9
|
const CONFLICT = "This document changed somewhere else. Reload and try again.";
|
|
10
10
|
const BUSY = "Something else is changing this document. Nothing was changed.";
|
|
11
|
+
const UNDECLARED = "This document does not say which parts are its data, so it cannot be upgraded safely. Nothing was changed.";
|
|
12
|
+
const PAGE_LOST = "The new version has no place for this page's content. Nothing was changed.";
|
|
11
13
|
|
|
12
14
|
async function digestOf(bytes) {
|
|
13
15
|
const subtle = globalThis.crypto && globalThis.crypto.subtle;
|
|
@@ -116,6 +118,26 @@ async function declaredRenames(htmlText) {
|
|
|
116
118
|
return mod && mod.renames && typeof mod.renames === "object" ? mod.renames : {};
|
|
117
119
|
}
|
|
118
120
|
|
|
121
|
+
// The page editor's content is its article and the live stores beside it, not values a
|
|
122
|
+
// rules tag can name: the upgrade carries them whole into the new version's article.
|
|
123
|
+
const PAGE_STORE = 'script[clay~="live"][merge]';
|
|
124
|
+
|
|
125
|
+
function carryPage(doc, afterDoc, article) {
|
|
126
|
+
const target = afterDoc.querySelector("article[data-page]");
|
|
127
|
+
if (!target) return null;
|
|
128
|
+
target.replaceWith(afterDoc.importNode(article, true));
|
|
129
|
+
for (const store of doc.querySelectorAll(PAGE_STORE)) {
|
|
130
|
+
const name = store.getAttribute("merge");
|
|
131
|
+
if (name !== "page" && !name.startsWith("page.")) continue;
|
|
132
|
+
const copy = afterDoc.importNode(store, true);
|
|
133
|
+
const existing = [...afterDoc.querySelectorAll(PAGE_STORE)].find((el) => el.getAttribute("merge") === name);
|
|
134
|
+
if (existing) existing.replaceWith(copy);
|
|
135
|
+
else afterDoc.querySelector("article[data-page]").after(copy);
|
|
136
|
+
}
|
|
137
|
+
const doctype = afterDoc.doctype ? `<!DOCTYPE ${afterDoc.doctype.name}>\n` : "";
|
|
138
|
+
return doctype + afterDoc.documentElement.outerHTML;
|
|
139
|
+
}
|
|
140
|
+
|
|
119
141
|
export async function prepare(update, {
|
|
120
142
|
doc = document,
|
|
121
143
|
loc = location,
|
|
@@ -187,13 +209,23 @@ export async function prepare(update, {
|
|
|
187
209
|
}
|
|
188
210
|
const afterDoc = new DOMParser().parseFromString(result.html, "text/html");
|
|
189
211
|
const before = upgrade.extractAll(doc).dataByName;
|
|
212
|
+
const article = doc.querySelector("article[data-page]");
|
|
213
|
+
if (!article && !Object.keys(before || {}).length) {
|
|
214
|
+
return { ok: false, code: "undeclared", message: UNDECLARED };
|
|
215
|
+
}
|
|
216
|
+
let html = result.html;
|
|
217
|
+
if (article) {
|
|
218
|
+
const carried = carryPage(doc, afterDoc, article);
|
|
219
|
+
if (!carried) return { ok: false, code: "lost", lost: [], discarded: 0, message: PAGE_LOST };
|
|
220
|
+
html = carried;
|
|
221
|
+
}
|
|
190
222
|
const after = upgrade.extractAll(afterDoc).dataByName;
|
|
191
223
|
const lost = lostValues(before, after, renames);
|
|
192
224
|
const discarded = result.summary && result.summary.totals ? result.summary.totals.discarded || 0 : 0;
|
|
193
225
|
if (lost.length || discarded > 0) {
|
|
194
226
|
return { ok: false, code: "lost", lost, discarded, message: lossMessage(lost, discarded) };
|
|
195
227
|
}
|
|
196
|
-
return { ok: true, html
|
|
228
|
+
return { ok: true, html, version: result.toVersion || latest.version };
|
|
197
229
|
}
|
|
198
230
|
|
|
199
231
|
function lossMessage(lost, discarded) {
|
|
@@ -249,7 +281,17 @@ async function applyUnderSlot(update, { doc, loc, fetchFn, clay, reload, replace
|
|
|
249
281
|
}
|
|
250
282
|
}
|
|
251
283
|
|
|
252
|
-
|
|
284
|
+
// An editing tab's live article holds the editor, not the page: the upgrade starts from
|
|
285
|
+
// the document as a save writes it.
|
|
286
|
+
let source = doc;
|
|
287
|
+
if (pageClay.isEditMode && typeof pageClay.getHTML === "function") {
|
|
288
|
+
try {
|
|
289
|
+
source = new DOMParser().parseFromString(await pageClay.getHTML(), "text/html");
|
|
290
|
+
} catch {
|
|
291
|
+
return { ok: false, code: "failed", message: SAVE_FAILED };
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const prepared = await prepare(update, { doc: source, loc, fetchFn });
|
|
253
295
|
if (!prepared.ok) return prepared;
|
|
254
296
|
|
|
255
297
|
const save = typeof replace === "function"
|
|
@@ -294,11 +336,20 @@ function downloadName(loc) {
|
|
|
294
336
|
return /\.html?$/i.test(name) ? name : `${name}.html`;
|
|
295
337
|
}
|
|
296
338
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
339
|
+
// A view-mode tab has no save capture, and edits nothing, so the copy is the stored file
|
|
340
|
+
// this upgrade is about to replace. Only a host without version history asks for it.
|
|
341
|
+
export async function pageBytes(clay, { loc = location, fetchFn = (url, init) => fetch(url, init) } = {}) {
|
|
342
|
+
if (typeof clay.getHTML === "function") return clay.getHTML();
|
|
343
|
+
const res = await fetchFn(loc.href, { cache: "no-store", credentials: "same-origin" });
|
|
344
|
+
if (!res.ok) throw new Error(`copy fetch ${res.status}`);
|
|
345
|
+
return res.text();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export async function downloadCopy({ clay, doc = document, loc = location, fetchFn } = {}) {
|
|
349
|
+
if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") return false;
|
|
300
350
|
try {
|
|
301
|
-
const
|
|
351
|
+
const bytes = await pageBytes(clay, { loc, fetchFn });
|
|
352
|
+
const url = URL.createObjectURL(new Blob([bytes], { type: "text/html" }));
|
|
302
353
|
const a = doc.createElement("a");
|
|
303
354
|
a.setAttribute("clay", "editor-ui");
|
|
304
355
|
a.href = url;
|
|
@@ -371,8 +422,8 @@ export async function start(update, options = {}) {
|
|
|
371
422
|
};
|
|
372
423
|
|
|
373
424
|
if (download) {
|
|
374
|
-
download.addEventListener("click", () => {
|
|
375
|
-
if (downloadCopy({ clay, doc, loc: options.loc })) {
|
|
425
|
+
download.addEventListener("click", async () => {
|
|
426
|
+
if (await downloadCopy({ clay, doc, loc: options.loc, fetchFn: options.fetchFn })) {
|
|
376
427
|
agree.disabled = false;
|
|
377
428
|
status.textContent = "Your copy was downloaded.";
|
|
378
429
|
} else {
|
package/src/lib/assets.js
CHANGED
|
@@ -10,6 +10,7 @@ const ASSETS = {
|
|
|
10
10
|
"highlight/json": () => import("../vendor/hljs-json.vendor.js"),
|
|
11
11
|
"highlight/python": () => import("../vendor/hljs-python.vendor.js"),
|
|
12
12
|
"highlight/xml": () => import("../vendor/hljs-xml.vendor.js"),
|
|
13
|
+
uimotion: () => import("./uimotion.js"),
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export function createAssets(table) {
|
package/src/lib/slice.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* slice.js — a generator that can be run twice two ways.
|
|
3
|
+
*
|
|
4
|
+
* Every expensive walk in save verification is written once, as a generator that yields
|
|
5
|
+
* between whole units of work. `drain` runs it to completion in the calling task, which
|
|
6
|
+
* is the synchronous function this module had before; `runSliced` resumes it and hands
|
|
7
|
+
* the event loop back whenever a slice has spent its budget, so the same code can also
|
|
8
|
+
* run across tasks. There is one implementation, so the two cannot drift apart.
|
|
9
|
+
*
|
|
10
|
+
* YIELD POINTS ARE COOPERATIVE, NOT PREEMPTIVE. A generator yields only between units of
|
|
11
|
+
* work the walk itself chose, so nothing outside sees a half-built model or a half-paired
|
|
12
|
+
* map: an abort runs the generator's `finally` blocks and returns `{ aborted: true }`
|
|
13
|
+
* with no result at all, and the caller must treat a partial walk as no walk.
|
|
14
|
+
*
|
|
15
|
+
* LAZY. Nothing imports this from the editor's ready path; only source modules that
|
|
16
|
+
* already load parse5 do.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Run a generator to completion in this task and return its value. */
|
|
20
|
+
export function drain(gen) {
|
|
21
|
+
let step = gen.next();
|
|
22
|
+
while (!step.done) step = gen.next();
|
|
23
|
+
return step.value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const viaTimer = () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
27
|
+
|
|
28
|
+
/** A task boundary that works in a hidden tab, where timers are throttled. */
|
|
29
|
+
const viaChannel = () => new Promise((resolve) => {
|
|
30
|
+
if (typeof MessageChannel !== "function") { viaTimer().then(resolve); return; }
|
|
31
|
+
const channel = new MessageChannel();
|
|
32
|
+
channel.port1.onmessage = () => { channel.port1.close(); resolve(); };
|
|
33
|
+
channel.port2.postMessage(null);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const defaultYieldTask = () => {
|
|
37
|
+
const scheduler = globalThis.scheduler;
|
|
38
|
+
return scheduler?.yield ? scheduler.yield() : viaChannel();
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const monotonic = () => (globalThis.performance ? globalThis.performance.now() : Date.now());
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Resume a generator, yielding to a task whenever a slice has spent `budgetMs`.
|
|
45
|
+
*
|
|
46
|
+
* Resolves with the generator's own return value, rejects with its exception. When
|
|
47
|
+
* `signal` aborts, the generator is closed (`gen.return()`, so `finally` blocks run) and
|
|
48
|
+
* the result is `{ aborted: true }`; nothing partial is handed back.
|
|
49
|
+
*/
|
|
50
|
+
export async function runSliced(gen, {
|
|
51
|
+
budgetMs = 4,
|
|
52
|
+
signal,
|
|
53
|
+
now = monotonic,
|
|
54
|
+
yieldTask = defaultYieldTask,
|
|
55
|
+
} = {}) {
|
|
56
|
+
let sliceStart = now();
|
|
57
|
+
for (;;) {
|
|
58
|
+
if (signal?.aborted) { gen.return(undefined); return { aborted: true }; }
|
|
59
|
+
const step = gen.next();
|
|
60
|
+
if (step.done) return step.value;
|
|
61
|
+
if (now() - sliceStart < budgetMs) continue;
|
|
62
|
+
await yieldTask();
|
|
63
|
+
sliceStart = now();
|
|
64
|
+
}
|
|
65
|
+
}
|