edgepress 2026.10.1 → 2026.10.13
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/LICENSE +21 -0
- package/README.md +216 -16
- package/config.yml +99 -127
- package/content/assets/edgepress/brand/avatar.png +0 -0
- package/content/assets/edgepress/brand/deploy-esa.svg +1 -0
- package/content/assets/edgepress/brand/home-hero-768.webp +0 -0
- package/content/assets/edgepress/brand/home-hero.png +0 -0
- package/content/assets/edgepress/brand/home-hero.webp +0 -0
- package/content/assets/edgepress/brand/mascot.png +0 -0
- package/content/assets/edgepress/brand/mascot.webp +0 -0
- package/content/assets/edgepress/brand/og-image.png +0 -0
- package/content/assets/edgepress/brand/og-image.webp +0 -0
- package/content/assets/edgepress/brand/sources/edgepress-avatar-master.png +0 -0
- package/content/assets/edgepress/brand/sources/export-manifest.json +181 -0
- package/content/assets/edgepress/brand/sources/prompts.json +12 -0
- package/content/assets/edgepress/favicon/apple-touch-icon.png +0 -0
- package/content/assets/edgepress/favicon/favicon-16.png +0 -0
- package/content/assets/edgepress/favicon/favicon-32.png +0 -0
- package/content/assets/edgepress/favicon/favicon-48.png +0 -0
- package/content/assets/edgepress/favicon/favicon-64.png +0 -0
- package/content/assets/edgepress/favicon/favicon.ico +0 -0
- package/content/assets/edgepress/icons/LICENSE.txt +43 -0
- package/content/assets/edgepress/icons/arrow-right.svg +16 -0
- package/content/assets/edgepress/icons/arrow-up-right.svg +16 -0
- package/content/assets/edgepress/icons/book-open.svg +16 -0
- package/content/assets/edgepress/icons/check-circle.svg +16 -0
- package/content/assets/edgepress/icons/check.svg +15 -0
- package/content/assets/edgepress/icons/cloud.svg +15 -0
- package/content/assets/edgepress/icons/code.svg +16 -0
- package/content/assets/edgepress/icons/cpu.svg +28 -0
- package/content/assets/edgepress/icons/file-text.svg +19 -0
- package/content/assets/edgepress/icons/github.svg +17 -0
- package/content/assets/edgepress/icons/globe.svg +17 -0
- package/content/assets/edgepress/icons/help-circle.svg +17 -0
- package/content/assets/edgepress/icons/home.svg +16 -0
- package/content/assets/edgepress/icons/layers.svg +17 -0
- package/content/assets/edgepress/icons/layout-grid.svg +18 -0
- package/content/assets/edgepress/icons/mail.svg +16 -0
- package/content/assets/edgepress/icons/newspaper.svg +18 -0
- package/content/assets/edgepress/icons/palette.svg +19 -0
- package/content/assets/edgepress/icons/plug.svg +18 -0
- package/content/assets/edgepress/icons/provenance.json +8 -0
- package/content/assets/edgepress/icons/puzzle.svg +15 -0
- package/content/assets/edgepress/icons/rocket.svg +18 -0
- package/content/assets/edgepress/icons/rss.svg +17 -0
- package/content/assets/edgepress/icons/search.svg +16 -0
- package/content/assets/edgepress/icons/settings.svg +16 -0
- package/content/assets/edgepress/icons/shield-check.svg +16 -0
- package/content/assets/edgepress/icons/sparkles.svg +18 -0
- package/content/assets/edgepress/icons/terminal.svg +16 -0
- package/content/assets/edgepress/icons/x.svg +16 -0
- package/{static → content/assets}/edgepress-markdown-guide.svg +1 -1
- package/content/assets/images/previews/edgepress-en.webp +0 -0
- package/content/assets/images/previews/edgepress-revisions-en.png +0 -0
- package/content/assets/images/previews/edgepress-workflow-en.90f4650b21013786.gif +0 -0
- package/content/assets/images/previews/edgepress-workflow-zh.41f1e0a685f47267.gif +0 -0
- package/content/assets/images/previews/edgepress-zh.webp +0 -0
- package/content/assets/images/previews/provenance.json +49 -0
- package/content/guides/markdown-media.md +38 -0
- package/content/guides/platforms.md +15 -0
- package/content/guides/product-demos.md +37 -0
- package/content/guides/zh-cn.md +62 -0
- package/content/pages/deployment/en.json +74 -0
- package/content/pages/deployment/zh-cn.json +74 -0
- package/content/pages/home/en.json +248 -0
- package/content/pages/home/zh-cn.json +248 -0
- package/content/pages/local-tools/en.json +14 -0
- package/content/pages/local-tools/zh-cn.json +14 -0
- package/content/pages/page-authoring/en.json +107 -0
- package/content/pages/page-authoring/zh-cn.json +107 -0
- package/content/pages/plugin-development/en.json +202 -0
- package/content/pages/plugin-development/zh-cn.json +202 -0
- package/content/pages/privacy-policy/en.json +171 -0
- package/content/pages/privacy-policy/zh-cn.json +171 -0
- package/content/pages/project-introduction/en.json +158 -0
- package/content/pages/project-introduction/zh-cn.json +158 -0
- package/content/pages/quick-start/en.json +325 -0
- package/content/pages/quick-start/zh-cn.json +325 -0
- package/content/pages/theme-development/en.json +353 -0
- package/content/pages/theme-development/zh-cn.json +349 -0
- package/content/posts/2026-09-24-edgepress-release-2026-9-1/en.md +1 -1
- package/content/posts/2026-09-24-edgepress-release-2026-9-1/zh-cn.md +1 -1
- package/content/posts/2026-10-03-edgepress-release-2026-10-3/en.md +16 -0
- package/content/posts/2026-10-03-edgepress-release-2026-10-3/zh-cn.md +16 -0
- package/content/posts/2026-10-03-edgepress-release-202610-4/en.md +22 -0
- package/content/posts/2026-10-03-edgepress-release-202610-4/zh-cn.md +20 -0
- package/content/posts/2026-10-03-edgepress-release-202610-5/en.md +15 -0
- package/content/posts/2026-10-03-edgepress-release-202610-5/zh-cn.md +15 -0
- package/edgeone.json +43 -0
- package/esa.jsonc +9 -0
- package/languages/base/en.json +75 -10
- package/languages/packs/zh-CN.json +74 -9
- package/netlify.toml +6 -0
- package/package.json +37 -6
- package/plugins/consent/index.js +10 -17
- package/project-compatibility.json +142 -25
- package/schemas/pages.schema.json +74 -0
- package/src/assets.js +146 -18
- package/src/browser-audit.js +158 -0
- package/src/build.js +34 -9
- package/src/cli.js +46 -41
- package/src/config.js +114 -63
- package/src/consent-csp.js +137 -0
- package/src/content.js +55 -30
- package/src/data-saver.js +194 -0
- package/src/deploy.js +28 -0
- package/src/document.js +44 -0
- package/src/embed.js +60 -0
- package/src/generators.js +101 -59
- package/src/i18n.js +19 -3
- package/src/icons.js +5 -4
- package/src/image-dimensions.js +17 -0
- package/src/local-tool.js +29 -0
- package/src/maintenance.js +25 -8
- package/src/markdown-fixture.js +20 -0
- package/src/markdown.js +80 -16
- package/src/media-assets.js +19 -0
- package/src/media-viewer.js +47 -0
- package/src/oembed.js +53 -0
- package/src/page-blocks.js +124 -54
- package/src/page-check.js +29 -39
- package/src/plugin-api.js +7 -1
- package/src/post-details.js +60 -0
- package/src/post-template.js +5 -0
- package/src/publication-time.js +47 -0
- package/src/report-path.js +19 -0
- package/src/report-visuals.js +91 -18
- package/src/revision-cards.js +30 -0
- package/src/revision-images.js +44 -0
- package/src/revisions.js +77 -0
- package/src/rss.js +100 -0
- package/src/service-block.js +18 -0
- package/src/theme.js +59 -9
- package/src/video-metadata.js +36 -0
- package/static/edgepress/data-saver.css +12 -0
- package/static/edgepress/data-saver.js +333 -0
- package/static/edgepress/document-viewer.js +35 -0
- package/static/edgepress/external-links-policy.js +14 -0
- package/static/edgepress/external-links.css +13 -0
- package/static/edgepress/external-links.js +120 -0
- package/static/edgepress/fonts/faces.css +2217 -0
- package/static/edgepress/fonts/noto-sans-OFL.txt +93 -0
- package/static/edgepress/fonts/noto-sans-cyrillic-ext-wght-normal.82ff72b28e6610f2.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-cyrillic-wght-normal.6ab64433de6077ca.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-devanagari-wght-normal.ea6a530b75d93de7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-greek-ext-wght-normal.790b255c10c32e0b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-greek-wght-normal.7f655207c2f6c140.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-latin-ext-wght-normal.6d5a79315528df19.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-latin-wght-normal.51ca196f49a33e79.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-100-wght-normal.ad5f29028d5699a5.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-101-wght-normal.e189b81fc22ca6af.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-102-wght-normal.941c0c2971fc1d6d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-103-wght-normal.bafbd591af6493ff.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-104-wght-normal.b0bf80ced89dd61b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-105-wght-normal.8d8b4e6f4a00621d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-106-wght-normal.bae74acc629d2e74.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-107-wght-normal.a42eff5010de7b0d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-108-wght-normal.91882203459867be.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-109-wght-normal.a91f8b038e5ce108.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-110-wght-normal.bbca9081655c4523.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-111-wght-normal.372be010ac0e87cb.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-112-wght-normal.34a4580239eae8dc.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-113-wght-normal.614ab8f616352583.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-114-wght-normal.cf7b8344807a316e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-115-wght-normal.fb29957c7adccb9a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-116-wght-normal.a98dc5a726f82141.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-117-wght-normal.d94b5af0c14838af.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-118-wght-normal.76c9ddb85ae4578c.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-119-wght-normal.b3b2374881f4cd93.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-21-wght-normal.c1409c43e55ecff2.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-22-wght-normal.77037ed42ff4e7b0.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-23-wght-normal.38d0df21ac374e93.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-24-wght-normal.8fa21e7e457acf3e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-25-wght-normal.f760b7a3871d214d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-26-wght-normal.be8386e7bd7facfe.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-27-wght-normal.4895abcaddbd162e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-28-wght-normal.82540b6201a9b9ad.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-29-wght-normal.ff21d8fcc60ce391.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-30-wght-normal.1f76f6ffded00b9e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-31-wght-normal.e6c25be1bb08a63a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-32-wght-normal.0cda750d7d04a4e1.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-33-wght-normal.b9732b5606bd87c5.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-34-wght-normal.38aa326b4c84902a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-35-wght-normal.bd98226c8e0aa808.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-36-wght-normal.0db1ca695a491d37.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-37-wght-normal.8df409a4e0a237c2.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-38-wght-normal.672d2d994994a3c3.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-39-wght-normal.272d6d0e153f56e8.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-4-wght-normal.9fafd93ac77b81ff.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-40-wght-normal.5b9ef1ed48420aa7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-41-wght-normal.30aee47f660fd88a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-42-wght-normal.ec0014830db682b6.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-43-wght-normal.43df2b5dad9bb835.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-44-wght-normal.acaa6195041b1a92.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-45-wght-normal.8cdb9903f770db21.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-46-wght-normal.6590d0a6fe94571c.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-47-wght-normal.b05afdd32b3bf722.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-48-wght-normal.c9585f7d070700be.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-49-wght-normal.4943895a4dfa5dcf.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-5-wght-normal.e64f57937e3ae4fe.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-50-wght-normal.13e51063d7743cfe.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-51-wght-normal.fd4df1f02c2cb4d7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-52-wght-normal.06999a39c4c3a7ea.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-53-wght-normal.767b7b9864658d91.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-54-wght-normal.4cd00537a46f6f1a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-55-wght-normal.0118ec5d8c30b197.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-56-wght-normal.a3e4a78929826930.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-57-wght-normal.7623501009e4a6db.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-58-wght-normal.56ae1a59a32e4a25.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-59-wght-normal.7a377a40e99fd9bc.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-6-wght-normal.17e15c4f0a5bfd92.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-60-wght-normal.3657f66babdf6aff.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-61-wght-normal.23919a2eb11d25dd.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-62-wght-normal.a901edf25bc1cfae.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-63-wght-normal.92f56f713cc0b62f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-64-wght-normal.4929c9f39a5a4bd9.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-65-wght-normal.8daa61282fb62a11.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-66-wght-normal.6479166925eb462b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-67-wght-normal.a6b0e11c4c761ffd.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-68-wght-normal.65b77f1fe9d68dae.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-69-wght-normal.b34f765cbbf4d02e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-70-wght-normal.a99d55c00e4f95b7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-71-wght-normal.3298bed30dc8d233.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-72-wght-normal.6597209ca9707726.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-73-wght-normal.e7ac1d4930eabd78.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-74-wght-normal.1f0287be83a28e7a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-75-wght-normal.d9a4bb7bcc2be578.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-76-wght-normal.5a019946bcadcec6.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-77-wght-normal.7c445e85d04f5319.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-78-wght-normal.7d4afb70f641781c.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-79-wght-normal.5798753a721bb4ec.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-80-wght-normal.db887159ca6e46f3.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-81-wght-normal.71e5743bbd225b3d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-82-wght-normal.8c5094c3785fd04f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-83-wght-normal.4a60a1ccba905284.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-84-wght-normal.3ed54e59ef4758e3.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-85-wght-normal.e87e0a1342e1778c.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-86-wght-normal.6d3ac3e20959dbcb.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-87-wght-normal.0eeffd5daad5c17b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-88-wght-normal.b1d9582dfa268463.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-89-wght-normal.8b437aeb9e9fcb5a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-90-wght-normal.83b0a59e0a5e045a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-91-wght-normal.382f72b98d4bb9d7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-97-wght-normal.5e52856457c5cdab.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-98-wght-normal.ffded4e7fd560d93.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-99-wght-normal.54e302c23f11a8fd.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-OFL.txt +93 -0
- package/static/edgepress/fonts/noto-sans-sc-cyrillic-wght-normal.5932d441e7126669.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-latin-ext-wght-normal.e316201f3fc493d1.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-latin-wght-normal.c1d919c8701a86ed.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-sc-vietnamese-wght-normal.cba3d00c8db989f0.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-0-wght-normal.63c21eda5d20203f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-100-wght-normal.87a7c76301c24a28.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-101-wght-normal.c9e83fc4ffd53746.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-102-wght-normal.9a00ae0e5735852b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-103-wght-normal.7cfe93b3221f4def.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-104-wght-normal.2d5ac7497d84cb99.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-105-wght-normal.0989885bb16bcd9b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-106-wght-normal.1faa921b035064e7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-107-wght-normal.2f6006745ae16d69.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-108-wght-normal.a61e48c10a2cf4b9.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-109-wght-normal.f28c767724736d2d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-110-wght-normal.4b04bd88c3dc7c5d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-111-wght-normal.b6251e1967932a52.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-112-wght-normal.e264513b32f90660.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-113-wght-normal.46cb347d88f3338e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-114-wght-normal.9f9e1e0d0ab2aeb4.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-115-wght-normal.653dd2ab7d551b40.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-116-wght-normal.4718bf3627191297.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-117-wght-normal.b241a9409682af5f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-118-wght-normal.fda2800dc1c06852.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-119-wght-normal.948af36bd63a72c7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-19-wght-normal.62191cdc3a10e60a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-20-wght-normal.65c90892c2e01657.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-21-wght-normal.d3f59b094c334866.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-22-wght-normal.b1983a041d7e4e1f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-23-wght-normal.16e2163b66c7732a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-24-wght-normal.72c8561976116537.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-25-wght-normal.b2948d928ce4dd54.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-26-wght-normal.d583236b90abedc9.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-27-wght-normal.7d6073ba07597c9b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-28-wght-normal.517204d716b089cd.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-29-wght-normal.10189a8f8ca38099.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-30-wght-normal.695a71d72dfab3f7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-31-wght-normal.868d59473ef0e73c.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-32-wght-normal.92efa2d4b3702ec0.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-33-wght-normal.d2274bcd5636197d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-34-wght-normal.1ac8c3718ee2eed2.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-35-wght-normal.00b3df730d5a4c73.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-36-wght-normal.6963feb6c628b81f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-37-wght-normal.a1b4bd294af24cd1.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-38-wght-normal.8edb2f7f2955921b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-39-wght-normal.37bf7394eb3148c6.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-40-wght-normal.3efa655bc48f9133.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-41-wght-normal.48d47014544ebd5d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-42-wght-normal.214c733a59d423e7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-43-wght-normal.c2c9876f138bb20f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-44-wght-normal.28928bfea29db06a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-45-wght-normal.bf3743f8155fa9d2.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-46-wght-normal.06970903593781c3.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-47-wght-normal.8932ed83a91794d4.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-48-wght-normal.dfd9225628bcf234.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-49-wght-normal.c27d341ad39d44eb.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-50-wght-normal.01a0f4e7dfba0a56.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-51-wght-normal.5a30022af3d30e0f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-52-wght-normal.4884f032342a3274.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-53-wght-normal.537adcae44511270.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-54-wght-normal.6bc8c7d3e47c6fde.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-55-wght-normal.725a48711f1e1997.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-56-wght-normal.f43ecaa73e0cd8fc.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-57-wght-normal.15b24e9d42a3270f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-58-wght-normal.9b2d8a71667d3da6.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-59-wght-normal.a68535a6b3289d89.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-6-wght-normal.32cece1ae80c4f2b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-60-wght-normal.3b2c56a921d1cad4.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-61-wght-normal.54f51f80a0740878.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-62-wght-normal.ba029c5bb6c07bf1.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-63-wght-normal.380919beec4c7f3d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-64-wght-normal.f96fe0be479d201f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-65-wght-normal.7d544b80701fe678.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-66-wght-normal.fab669c07a1e3bee.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-67-wght-normal.0001bb744743fdfa.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-68-wght-normal.1a57eda03886b43c.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-69-wght-normal.017fecc749bcd6d5.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-7-wght-normal.cd0f0cac743dbbfe.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-70-wght-normal.79fb9d70b9534ec7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-71-wght-normal.04a6ea581b5f1195.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-72-wght-normal.d3a4eb35499157b7.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-73-wght-normal.d81f8484404ee465.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-74-wght-normal.4a5da9e0c2702f7d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-75-wght-normal.8b87f9c6c164513a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-76-wght-normal.a71463dbfd9fa7b5.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-77-wght-normal.d094414ea752cd52.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-78-wght-normal.04f7c97bd9cbc73b.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-79-wght-normal.1ed089d037a02049.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-8-wght-normal.d052677dfb5db5bd.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-80-wght-normal.6d41ca59cfd50442.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-81-wght-normal.f09bd0afa8a58114.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-82-wght-normal.7920841c526b1b02.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-83-wght-normal.0c6f7f82db8da0d8.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-84-wght-normal.f37c0a853b31265e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-85-wght-normal.4173bff087653b82.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-86-wght-normal.dac35605ebec15c4.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-87-wght-normal.8ac85fdd0b15a6bd.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-88-wght-normal.61625b0b21e8407f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-89-wght-normal.a1da3dccbf00698e.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-90-wght-normal.bf08f0355222a782.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-91-wght-normal.2ecf295bba2bfaa3.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-92-wght-normal.36508326bb68115f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-97-wght-normal.c712899e0fc9e947.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-98-wght-normal.13a648e521d18d7f.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-99-wght-normal.7f8c9a777e64159a.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-OFL.txt +93 -0
- package/static/edgepress/fonts/noto-sans-tc-cyrillic-wght-normal.dd0980ced8e46cb3.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-latin-ext-wght-normal.817d96335dc52ce6.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-latin-wght-normal.50cb5fb0a522cfaf.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-tc-vietnamese-wght-normal.2a77fb7b70fa304d.woff2 +0 -0
- package/static/edgepress/fonts/noto-sans-vietnamese-wght-normal.791e3f213c155a5b.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-OFL.txt +93 -0
- package/static/edgepress/fonts/noto-serif-cyrillic-ext-wght-normal.7c7afb20d33e30ec.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-cyrillic-wght-normal.54e3bd0c4a002b0f.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-greek-ext-wght-normal.9b3f4c4ff3adefd2.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-greek-wght-normal.1252037b6f1d6e86.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-latin-ext-wght-normal.2654f8d1261a420f.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-latin-wght-normal.46281456234014ce.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-math-wght-normal.d4a6aba2cb4636b3.woff2 +0 -0
- package/static/edgepress/fonts/noto-serif-vietnamese-wght-normal.fb6a5ed734c2fbe3.woff2 +0 -0
- package/static/edgepress/fonts/provenance.json +1356 -0
- package/static/edgepress/fonts.css +14 -0
- package/static/edgepress/image-viewer.js +23 -0
- package/static/edgepress/images.css +4 -0
- package/static/edgepress/link-directory.css +14 -0
- package/static/edgepress/local-time.js +12 -0
- package/static/edgepress/media-viewer.css +1 -0
- package/static/edgepress/media-viewer.js +111 -0
- package/static/edgepress/navigation-select.js +14 -0
- package/static/edgepress/oembed.js +129 -0
- package/static/edgepress/plugins/backend/external-api.js +4 -0
- package/static/edgepress/plugins/backend/external-widget.js +13 -0
- package/static/edgepress/plugins/consent/choices.js +47 -0
- package/static/edgepress/plugins/consent/manager.js +56 -74
- package/static/edgepress/project-demo.js +93 -0
- package/static/edgepress/search.js +2 -2
- package/static/edgepress/services-consent.js +3 -0
- package/static/edgepress/services.js +15 -0
- package/static/edgepress/webmcp.js +86 -0
- package/tests/assets-runtime.test.mjs +91 -0
- package/tests/audit.test.mjs +142 -0
- package/tests/brand-regression.test.mjs +110 -0
- package/tests/consent-browser.test.mjs +132 -0
- package/tests/consent-config.test.mjs +85 -0
- package/tests/consent-csp.test.mjs +90 -0
- package/tests/data-saver-loading.test.mjs +158 -0
- package/tests/data-saver-network.test.mjs +99 -0
- package/tests/data-saver.test.mjs +294 -0
- package/tests/document-package.test.mjs +28 -0
- package/tests/document-viewer.test.mjs +152 -0
- package/tests/edge-issues.test.mjs +65 -0
- package/tests/embed-syntax.test.mjs +68 -0
- package/tests/external-links.test.mjs +198 -0
- package/tests/fixtures/recording.mp4 +0 -0
- package/tests/fonts.test.mjs +99 -0
- package/tests/image-dimensions.test.mjs +15 -0
- package/tests/image-viewer.test.mjs +36 -0
- package/tests/json-pages.test.mjs +66 -0
- package/tests/link-directory.test.mjs +51 -0
- package/tests/local-tool.test.mjs +34 -0
- package/tests/markdown-media.test.mjs +119 -0
- package/tests/media-block.test.mjs +102 -0
- package/tests/navigation.test.mjs +87 -0
- package/tests/oembed-layout.test.mjs +98 -0
- package/tests/oembed.test.mjs +96 -0
- package/tests/page-authoring.test.mjs +27 -0
- package/tests/page-formatting.test.mjs +37 -0
- package/tests/post-list.test.mjs +96 -0
- package/tests/project-demo.test.mjs +73 -0
- package/tests/publication-time.test.mjs +43 -0
- package/tests/release-version.test.mjs +28 -0
- package/tests/revisions.test.mjs +93 -0
- package/tests/rss.test.mjs +54 -0
- package/tests/services.test.mjs +35 -0
- package/tests/theme-layout.test.mjs +95 -0
- package/tests/video-metadata.test.mjs +28 -0
- package/tests/webmcp.test.mjs +121 -0
- package/tests/writing.test.mjs +101 -0
- package/themes/atelier/assets/style.css +144 -22
- package/themes/atelier/layouts/partials/head.html +8 -1
- package/themes/atelier/layouts/partials/header.html +3 -1
- package/themes/default/assets/data-saver-theme.css +2 -0
- package/themes/default/assets/style.css +139 -23
- package/themes/default/layouts/partials/head.html +9 -2
- package/themes/default/layouts/partials/header.html +3 -1
- package/themes/default/theme.json +1 -0
- package/themes/folio/README.md +7 -0
- package/themes/folio/assets/data-saver-theme.css +3 -0
- package/themes/folio/assets/folio/navigation.js +10 -0
- package/themes/folio/assets/style.css +516 -0
- package/themes/folio/layouts/layout.html +15 -0
- package/themes/folio/layouts/partials/footer.html +6 -0
- package/themes/folio/layouts/partials/head.html +30 -0
- package/themes/folio/layouts/partials/header.html +8 -0
- package/themes/folio/theme.json +7 -0
- package/themes/signal/assets/style.css +143 -21
- package/themes/signal/layouts/partials/head.html +8 -1
- package/themes/signal/layouts/partials/header.html +3 -1
- package/tools/README.md +14 -0
- package/tools/assets/format-pages.mjs +56 -0
- package/tools/assets/generate-brand-assets.py +160 -0
- package/tools/assets/sync-fonts.mjs +71 -0
- package/tools/assets/sync-icons.mjs +17 -0
- package/tools/assets/video-preview.mjs +15 -0
- package/tools/recordings/capture-document-demo.mjs +147 -0
- package/tools/recordings/demo-workbench.mjs +57 -0
- package/tools/recordings/desktop-recording.mjs +92 -0
- package/tools/recordings/provision-vm.sh +18 -0
- package/tools/recordings/start-vm-desktop.sh +28 -0
- package/tools/recordings/vm-desktop.mjs +124 -0
- package/tools/verification/README.md +44 -0
- package/tools/verification/data-saver-site.mjs +405 -0
- package/tools/verification/page-performance.mjs +76 -0
- package/tools/verification/verify-brand-assets.py +52 -0
- package/tools/verification/verify-brand.mjs +180 -0
- package/vercel.json +36 -0
- package/wrangler.jsonc +5 -7
- package/content/pages/home/en.md +0 -99
- package/content/pages/home/zh-cn.md +0 -99
- package/content/pages/plugin-development/en.md +0 -109
- package/content/pages/plugin-development/zh-cn.md +0 -109
- package/content/pages/privacy-policy/en.md +0 -93
- package/content/pages/privacy-policy/zh-cn.md +0 -93
- package/content/pages/project-introduction/en.md +0 -88
- package/content/pages/project-introduction/zh-cn.md +0 -88
- package/content/pages/quick-start/en.md +0 -153
- package/content/pages/quick-start/zh-cn.md +0 -153
- package/content/pages/theme-development/en.md +0 -132
- package/content/pages/theme-development/zh-cn.md +0 -132
- package/src/worker.js +0 -139
- package/static/edgepress/brand/edgepress-mark.svg +0 -7
- package/static/edgepress/brand/mascot-209.webp +0 -0
- package/static/edgepress/brand/mascot-418.png +0 -0
- package/static/edgepress/brand/mascot-418.webp +0 -0
- package/static/edgepress/brand/mascot.png +0 -0
- package/static/edgepress/brand/og-image.png +0 -0
- package/static/edgepress/brand/og-image.svg +0 -46
- package/static/edgepress/icons.svg +0 -24
package/src/theme.js
CHANGED
|
@@ -18,23 +18,36 @@ function escapeHtml(value) {
|
|
|
18
18
|
})[char]);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
function navigationItems(config, locale, items) {
|
|
21
|
+
function navigationItems(config, locale, items, currentPath = '', scope = 'primary') {
|
|
22
22
|
const values = items.length ? items : [
|
|
23
23
|
{ key: 'home', url: '@home' },
|
|
24
24
|
{ key: 'archives', url: '@archives' },
|
|
25
25
|
{ key: 'search', url: '@search' },
|
|
26
26
|
{ key: 'feed', url: '@feed' }
|
|
27
27
|
];
|
|
28
|
-
return values.map((item) => {
|
|
28
|
+
return values.map((item, index) => {
|
|
29
29
|
const path = item.url === '@home' ? localizedUrl(config, locale, '') :
|
|
30
30
|
item.url === '@archives' ? localizedUrl(config, locale, 'archives/') :
|
|
31
|
-
item.url === '@feed' ? localizedUrl(config, locale, '
|
|
31
|
+
item.url === '@feed' ? localizedUrl(config, locale, 'rss.xml') :
|
|
32
32
|
item.url === '@search' ? localizedUrl(config, locale, 'search/') :
|
|
33
33
|
item.url.startsWith('/') ? localizedUrl(config, locale, item.url) : item.url;
|
|
34
34
|
const label = item.labels?.[locale] ?? item.labels?.[config.i18n.defaultLocale] ?? translate(config, locale, item.key);
|
|
35
35
|
const iconName = item.icon || defaultNavigationIcons[item.key];
|
|
36
36
|
const icon = isIconName(iconName) ? renderIcon(iconName, 'navigation-icon') : '';
|
|
37
|
-
|
|
37
|
+
const attributes = item.target === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '';
|
|
38
|
+
if (item.children?.length) {
|
|
39
|
+
const choices = [{ path, label, target:item.target }, ...item.children.map(child => ({
|
|
40
|
+
path: child.url === '@home' ? localizedUrl(config, locale, '') : child.url === '@archives' ? localizedUrl(config, locale, 'archives/') :
|
|
41
|
+
child.url === '@feed' ? localizedUrl(config, locale, 'rss.xml') : child.url === '@search' ? localizedUrl(config, locale, 'search/') :
|
|
42
|
+
child.url.startsWith('/') ? localizedUrl(config, locale, child.url) : child.url,
|
|
43
|
+
label: child.labels?.[locale] ?? child.labels?.[config.i18n.defaultLocale] ?? translate(config, locale, child.key), target:child.target
|
|
44
|
+
}))];
|
|
45
|
+
return '<span class="navigation-select" hidden>' + icon + '<select name="edgepress-navigation-' + scope + '-' + index + '" data-navigation-select aria-label="' + escapeHtml(label) + '">' +
|
|
46
|
+
'<option value="" selected disabled hidden>' + escapeHtml(label) + '</option>' +
|
|
47
|
+
choices.map(choice => '<option value="' + escapeHtml(choice.path) + '"'+(choice.target==='_blank'?' data-target="_blank"':'')+'>' + escapeHtml(choice.label) + '</option>').join('') +
|
|
48
|
+
'</select></span><noscript>' + choices.map(choice => '<a href="' + escapeHtml(choice.path) + '"'+(choice.target==='_blank'?' target="_blank" rel="noopener noreferrer"':'')+'>' + escapeHtml(choice.label) + '</a>').join('') + '</noscript>';
|
|
49
|
+
}
|
|
50
|
+
return '<a href="' + escapeHtml(path) + '"'+attributes+'>' + icon + escapeHtml(label) + '</a>';
|
|
38
51
|
}).join('');
|
|
39
52
|
}
|
|
40
53
|
|
|
@@ -97,7 +110,8 @@ export async function renderLayout(config, extensions, page, body) {
|
|
|
97
110
|
const title = page.title ? page.title + config.site.head.titleSeparator + titleSuffix : titleSuffix;
|
|
98
111
|
const robots = page.robots || config.site.seo.robots || 'index,follow';
|
|
99
112
|
const keywords = (page.keywords || config.site.seo.keywords || []).join(', ');
|
|
100
|
-
const
|
|
113
|
+
const imagePath = page.image || config.site.seo.image || '';
|
|
114
|
+
const image = imagePath.startsWith('/') && config.site.url ? new URL(imagePath, config.site.url).href : imagePath;
|
|
101
115
|
const currentPrefix = localePrefix(config, locale);
|
|
102
116
|
const currentPath = page.urlPath || localizedUrl(config, locale, '');
|
|
103
117
|
const localeRoute = currentPrefix && currentPath.startsWith(currentPrefix + '/')
|
|
@@ -130,13 +144,13 @@ export async function renderLayout(config, extensions, page, body) {
|
|
|
130
144
|
footerClass: componentClass(config.site.components.footer, 'site-footer'),
|
|
131
145
|
footerCopyClass: componentClass(Boolean(config.site.footer), 'footer-copy'),
|
|
132
146
|
footerNavigationClass: componentClass(config.site.components.footerNavigation && config.site.footerNavigation.length, 'footer-navigation'),
|
|
133
|
-
primaryNavigationHtml: navigationItems(config, locale, config.site.navigation),
|
|
134
|
-
footerNavigationHtml: navigationItems(config, locale, config.site.footerNavigation),
|
|
147
|
+
primaryNavigationHtml: navigationItems(config, locale, config.site.navigation, page.urlPath || localizedUrl(config, locale, '')),
|
|
148
|
+
footerNavigationHtml: navigationItems(config, locale, config.site.footerNavigation, '', 'footer'),
|
|
135
149
|
localeLinksHtml,
|
|
136
150
|
stylesheet,
|
|
137
151
|
homePath: localizedUrl(config, locale, ''),
|
|
138
152
|
archivesPath: localizedUrl(config, locale, 'archives/'),
|
|
139
|
-
feedPath: localizedUrl(config, locale, '
|
|
153
|
+
feedPath: localizedUrl(config, locale, 'rss.xml'),
|
|
140
154
|
homeLabel: translate(config, locale, 'home'),
|
|
141
155
|
archivesLabel: translate(config, locale, 'archives'),
|
|
142
156
|
feedLabel: translate(config, locale, 'feed'),
|
|
@@ -162,9 +176,39 @@ export async function renderLayout(config, extensions, page, body) {
|
|
|
162
176
|
return escapeHtml(value);
|
|
163
177
|
});
|
|
164
178
|
const html = '<!doctype html>' + rendered;
|
|
165
|
-
|
|
179
|
+
let filtered = await extensions.filter('html:afterLayout', html, context);
|
|
166
180
|
if (typeof filtered !== 'string') throw new Error('html:afterLayout filters must return a string');
|
|
181
|
+
filtered = filtered.replace(/<\/head\s*>/i, '<link rel="stylesheet" href="/edgepress/fonts.css"></head>');
|
|
182
|
+
if (/class="link-directory-section"/.test(filtered)) filtered = filtered.replace(/<\/head\s*>/i, '<link rel="stylesheet" href="/edgepress/link-directory.css"></head>');
|
|
183
|
+
if(/<img\b[^>]*\sloading=["\']lazy["\']/i.test(filtered))filtered=filtered.replace(/<\/head\s*>/i, '<link rel="stylesheet" href="/edgepress/images.css"></head>');
|
|
184
|
+
if(/\b(?:post-content|image-block|media-text|data-edgepress-oembed)\b/.test(filtered)){
|
|
185
|
+
const keys=['openImage','closeImage','zoomIn','zoomOut','saveOriginal','retryMedia','loading','imageUnavailable'];
|
|
186
|
+
const labels=Object.fromEntries(keys.map(key=>[key,translate(config,locale,'imageViewer'+key[0].toUpperCase()+key.slice(1))]).filter(([key,value])=>value!=='imageViewer'+key[0].toUpperCase()+key.slice(1)));
|
|
187
|
+
filtered=filtered.replace('</head>','<link rel="stylesheet" href="/edgepress/image-viewer.css"></head>').replace('</body>','<script id="edgepress-image-viewer-config" type="application/json">'+JSON.stringify(labels).replace(/</g,'\\u003c')+'</script><script type="module" src="/edgepress/image-viewer.js"></script></body>');
|
|
188
|
+
}
|
|
167
189
|
const scripts = [];
|
|
190
|
+
if (config.site.externalLinks?.enabled) {
|
|
191
|
+
const labels = Object.fromEntries(['title', 'description', 'back', 'continue'].map(key => [key, translate(config, locale, 'externalLink' + key[0].toUpperCase() + key.slice(1))]));
|
|
192
|
+
const settings = { ...config.site.externalLinks, siteUrl: config.site.url, labels };
|
|
193
|
+
filtered = filtered.replace(/<\/head\s*>/i, '<link rel="stylesheet" href="/edgepress/external-links.css"></head>');
|
|
194
|
+
scripts.push('<script id="edgepress-external-links-config" type="application/json">' + JSON.stringify(settings).replace(/</g, '\\u003c') + '</script><script type="module" src="/edgepress/external-links.js"></script>');
|
|
195
|
+
}
|
|
196
|
+
if (/<main\b/i.test(filtered)) scripts.push('<script type="module" src="/edgepress/webmcp.js"></script>');
|
|
197
|
+
if (/data-edgepress-(?:media-viewer|video)(?:\s|=|>)/i.test(filtered)) {
|
|
198
|
+
filtered = filtered.replace(/<\/head\s*>/i, '<link rel="stylesheet" href="/edgepress/media-viewer.css"><link rel="stylesheet" href="/edgepress/image-viewer.css"></head>');
|
|
199
|
+
scripts.push('<script type="module" src="/edgepress/media-viewer.js"></script>');
|
|
200
|
+
if (filtered.includes('data-media-service')) scripts.push('<script defer src="/edgepress/services-consent.js"></script>');
|
|
201
|
+
}
|
|
202
|
+
if (/data-edgepress-document(?:\s|=|>)/i.test(filtered)) {
|
|
203
|
+
const keys = ['preview', 'close', 'loading', 'error', 'page', 'sheet'];
|
|
204
|
+
const labels = Object.fromEntries(keys.map(key => [key, translate(config, locale, 'documentViewer' + key[0].toUpperCase() + key.slice(1))]));
|
|
205
|
+
filtered = filtered.replace(/<\/head\s*>/i, '<link rel="stylesheet" href="/edgepress/document-viewer/styles.css"></head>');
|
|
206
|
+
scripts.push('<script id="edgepress-document-viewer-config" type="application/json">' + JSON.stringify(labels).replace(/</g, '\\u003c') + '</script><script type="module" src="/edgepress/document-viewer.js"></script>');
|
|
207
|
+
if (filtered.includes('data-document-service')) scripts.push('<script defer src="/edgepress/services-consent.js"></script>');
|
|
208
|
+
}
|
|
209
|
+
if (filtered.includes('data-project-demo')) scripts.push('<script defer src="/edgepress/project-demo.js"></script>');
|
|
210
|
+
if (filtered.includes('data-local-time')) scripts.push('<script defer src="/edgepress/local-time.js"></script>');
|
|
211
|
+
if (filtered.includes('data-navigation-select')) scripts.push('<script defer src="/edgepress/navigation-select.js"></script>');
|
|
168
212
|
if (!/src=["']\/edgepress\/code-copy\.js["']/i.test(filtered)) scripts.push('<script defer src="/edgepress/code-copy.js"></script>');
|
|
169
213
|
if (/data-post-toc(?:\s|>)/i.test(filtered) && !/src=["']\/edgepress\/post-toc\.js["']/i.test(filtered)) {
|
|
170
214
|
scripts.push('<script defer src="/edgepress/post-toc.js"></script>');
|
|
@@ -172,6 +216,12 @@ export async function renderLayout(config, extensions, page, body) {
|
|
|
172
216
|
if (/data-edgepress-search(?:\s|=|>)/i.test(filtered) && !/src=["']\/edgepress\/search\.js["']/i.test(filtered)) {
|
|
173
217
|
scripts.push('<script defer src="/edgepress/search.js"></script>');
|
|
174
218
|
}
|
|
219
|
+
if (/data-edgepress-oembed(?:\s|=|>)/i.test(filtered)) {
|
|
220
|
+
filtered = filtered.replace(/<\/body\s*>/i, '<script type="module" src="/edgepress/oembed.js"></script></body>');
|
|
221
|
+
}
|
|
222
|
+
if (/data-edgepress-service(?:\s|=|>)/i.test(filtered) && !/src=["']\/edgepress\/services-consent\.js["']/i.test(filtered)) {
|
|
223
|
+
scripts.push('<script defer src="/edgepress/services-consent.js"></script>');
|
|
224
|
+
}
|
|
175
225
|
if (!scripts.length) return filtered;
|
|
176
226
|
const integration = scripts.join('');
|
|
177
227
|
return /<\/body\s*>/i.test(filtered)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {readFile} from 'node:fs/promises';
|
|
2
|
+
import {posix} from 'node:path';
|
|
3
|
+
|
|
4
|
+
// Offline-generated sidecars keep duration and posters available without requesting media.
|
|
5
|
+
export async function collectVideoMetadata(assets) {
|
|
6
|
+
const known = new Map(assets.map(item => [item.path, item])), result = new Map();
|
|
7
|
+
for (const video of assets.filter(item => /\.(?:mp4|webm|ogv|ogg)$/i.test(item.path))) {
|
|
8
|
+
const sidecar = known.get(video.path + '.json');
|
|
9
|
+
if (!sidecar) continue;
|
|
10
|
+
const data = JSON.parse((sidecar.content ?? await readFile(sidecar.source)).toString());
|
|
11
|
+
const duration = Number(data.duration), width = Number(data.width), height = Number(data.height);
|
|
12
|
+
if (![duration, width, height].every(value => Number.isFinite(value) && value > 0)) throw new Error('Invalid video metadata: ' + sidecar.path);
|
|
13
|
+
if (typeof data.poster !== 'string' || /[\\?#\x00-\x1f]|^[a-z]+:|^\/\//i.test(data.poster)) throw new Error('Invalid video poster: ' + sidecar.path);
|
|
14
|
+
const poster = posix.normalize(posix.join(posix.dirname(video.path), data.poster));
|
|
15
|
+
if (!known.has(poster) || !/\.(?:jpe?g|png|webp|avif)$/i.test(poster)) throw new Error('Missing local video poster: ' + sidecar.path);
|
|
16
|
+
result.set('/' + video.path, {duration, width, height, poster: '/' + poster});
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function reserveVideoMetadata(html, metadata, path, origin) {
|
|
22
|
+
return html.replace(/<video\b([^>]*)>([\s\S]*?)<\/video>/gi, (tag, attributes, content) => {
|
|
23
|
+
const src = attributes.match(/\ssrc=["']([^"']+)["']/i)?.[1] ?? content.match(/<source\b[^>]*\ssrc=["']([^"']+)["']/i)?.[1];
|
|
24
|
+
if (!src) return tag;
|
|
25
|
+
let url;
|
|
26
|
+
try { url = new URL(src.replaceAll('&', '&'), new URL('/' + path, origin)); } catch { return tag; }
|
|
27
|
+
if (url.origin !== new URL(origin).origin) return tag;
|
|
28
|
+
const data = metadata.get(decodeURI(url.pathname));
|
|
29
|
+
if (!data) return tag;
|
|
30
|
+
const escape = value => String(value).replaceAll('&', '&').replaceAll('"', '"').replaceAll('<', '<');
|
|
31
|
+
for (const [name, value] of Object.entries({'data-duration': data.duration, poster: data.poster, width: data.width, height: data.height})) {
|
|
32
|
+
if (!new RegExp('\\s' + name + '\\s*=', 'i').test(attributes)) attributes += ' ' + name + '="' + escape(value) + '"';
|
|
33
|
+
}
|
|
34
|
+
return '<video' + attributes + '>' + content + '</video>';
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
.edgepress-data-offer{position:fixed;inset:auto 1rem 1rem auto;z-index:1200;width:min(27rem,calc(100vw - 2rem));padding:1.2rem;border:1px solid var(--line,GrayText);border-radius:1rem;background:var(--surface,var(--paper,Canvas));color:var(--ink,CanvasText);box-shadow:0 12px 40px #0002;visibility:visible;font:1rem/1.6 system-ui,sans-serif}.edgepress-data-offer h2{margin:0 0 .5rem;font:inherit;font-weight:700}.edgepress-data-offer p{margin:.5rem 0 1rem}.edgepress-data-offer>div{display:flex;flex-wrap:wrap;gap:.6rem}.edgepress-data-return{display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:.75rem;margin:1.5rem auto;padding:.75rem 1rem;max-width:68rem;color:var(--muted,var(--ink,CanvasText));font:inherit}.edgepress-data-offer[hidden],.edgepress-data-return[hidden]{display:none!important}.edgepress-data-offer button,.edgepress-data-return button,.edgepress-data-placeholder button{appearance:none;font:inherit;color:var(--ink,CanvasText);background:var(--surface,var(--paper,Canvas));border:1px solid var(--line,GrayText);border-radius:.65rem;min-height:44px;padding:.5rem .8rem;cursor:pointer}.edgepress-data-offer button[data-data-mode=text]{background:var(--ink,CanvasText);color:var(--paper,Canvas)}.edgepress-data-offer button:focus-visible,.edgepress-data-return button:focus-visible,.edgepress-data-placeholder button:focus-visible{outline:3px solid var(--accent,Highlight);outline-offset:3px}.edgepress-data-placeholder{display:inline-flex;align-items:center;flex-wrap:wrap;gap:.6rem;max-width:100%;padding:.6rem .8rem;border:1px dashed var(--line,GrayText);border-radius:.65rem;color:var(--muted,var(--ink,CanvasText));background:var(--surface,var(--paper,Canvas));overflow-wrap:anywhere}.edgepress-data-placeholder[data-loaded=true]{display:contents}
|
|
2
|
+
html[data-edgepress-data-mode=text]{--edgepress-font-sans:system-ui,sans-serif;--edgepress-font-serif:Georgia,serif;--edgepress-font-mono:ui-monospace,monospace}html[data-edgepress-data-mode=text] [hidden],html[data-edgepress-data-mode=text] .edgepress-data-placeholder[data-data-decorative]{display:none!important}html[data-edgepress-data-mode=text] .edgepress-data-brand{display:inline;color:inherit;background:none;padding:0;border:0;font:inherit}html[data-edgepress-data-mode=text] .edgepress-data-placeholder:not([data-data-brand])>[data-data-description]{display:block;font-size:.9em;line-height:1.6}html[data-edgepress-data-mode=text] .edgepress-data-placeholder:focus-within{outline:2px solid var(--accent,Highlight);outline-offset:2px}html[data-edgepress-data-mode=text] main{overflow-wrap:anywhere}
|
|
3
|
+
html[data-edgepress-data-mode] .edgepress-data-placeholder noscript{display:none!important}html:not([data-edgepress-data-mode]) .edgepress-data-placeholder{display:contents}html:not([data-edgepress-data-mode]) [data-data-description]{display:none}html[data-edgepress-data-mode=full]:not([data-edgepress-data-ready=true]) body{visibility:hidden}
|
|
4
|
+
@media(forced-colors:active){.edgepress-data-offer{border:2px solid CanvasText;box-shadow:none}.edgepress-data-offer button[data-data-mode=text]{background:Canvas;color:CanvasText;border:2px solid Highlight}}@media(prefers-reduced-motion:reduce){.edgepress-data-offer *,.edgepress-data-return *{transition:none;animation:none}}
|
|
5
|
+
html[data-edgepress-data-mode=text] a .edgepress-data-placeholder>[data-data-description]{position:static;width:auto;height:auto;margin:0;overflow:visible;clip-path:none;white-space:normal}
|
|
6
|
+
html[data-edgepress-data-mode=text] [data-oembed-placeholder]{display:none}html[data-edgepress-data-mode=text] .edgepress-oembed:not([data-loaded=true]) [data-oembed-status]{min-height:0}
|
|
7
|
+
.edgepress-data-wait{position:fixed;inset:0;z-index:1190;display:grid;place-items:center;padding:1rem;background:var(--paper,var(--surface,Canvas));color:var(--ink,CanvasText);visibility:visible;font:1rem/1.6 system-ui,"Segoe UI","PingFang TC","PingFang SC","Microsoft JhengHei","Microsoft YaHei","Noto Sans CJK TC","Noto Sans CJK SC","Arial Unicode MS",sans-serif}.edgepress-data-wait[hidden]{display:none!important}.edgepress-data-wait>p{margin:0;padding:1rem;max-width:30rem;text-align:center}.edgepress-data-wait .edgepress-data-offer{max-height:calc(100dvh - 2rem);overflow:auto}.edgepress-data-offer,.edgepress-data-offer button{font-family:inherit}html[data-edgepress-data-ready=false] body{visibility:hidden}
|
|
8
|
+
html[data-edgepress-data-mode=text]{--edgepress-font-sans:system-ui,"Segoe UI","PingFang TC","PingFang SC","Microsoft JhengHei","Microsoft YaHei","Noto Sans CJK TC","Noto Sans CJK SC","Arial Unicode MS",sans-serif;--edgepress-font-serif:Georgia,"Songti TC","Songti SC","Noto Serif CJK TC","Noto Serif CJK SC","PMingLiU","SimSun",serif;--edgepress-font-mono:ui-monospace,"Cascadia Mono","Consolas","Microsoft JhengHei","Microsoft YaHei",monospace;font-synthesis:weight}html[data-edgepress-data-mode=text] body{font-family:var(--edgepress-font-sans)}html[data-edgepress-data-mode=text] input,html[data-edgepress-data-mode=text] button,html[data-edgepress-data-mode=text] select,html[data-edgepress-data-mode=text] textarea{font-family:inherit}
|
|
9
|
+
.edgepress-service>[data-service-load],.edgepress-service>[data-service-consent-settings]{appearance:none;font:inherit;min-height:44px;margin:.4rem .5rem .4rem 0;padding:.5rem .85rem;color:var(--ink,CanvasText);background:var(--surface,var(--paper,Canvas));border:1px solid var(--line,GrayText);border-radius:.65rem;cursor:pointer}.edgepress-service>button:focus-visible{outline:3px solid var(--accent,Highlight);outline-offset:3px}.edgepress-service>button:disabled{cursor:wait;opacity:.6}
|
|
10
|
+
.edgepress-data-wait,.edgepress-data-offer{box-sizing:border-box;color-scheme:light dark}
|
|
11
|
+
.edgepress-data-wait{background:var(--paper,var(--surface,var(--night,Canvas)))}.edgepress-data-offer{background:var(--surface,var(--paper,var(--panel,Canvas)))}
|
|
12
|
+
.edgepress-data-progress{max-width:30rem;width:100%;text-align:center}.edgepress-data-progress p{margin:0 0 1rem;overflow-wrap:anywhere}.edgepress-data-progress progress{appearance:none;display:block;width:min(20rem,100%);height:.6rem;margin:auto;border:1px solid var(--line,GrayText);border-radius:1rem;overflow:hidden;background:var(--surface,Canvas);accent-color:var(--accent,Highlight)}.edgepress-data-progress progress::-webkit-progress-bar{background:var(--surface,Canvas)}.edgepress-data-progress progress::-webkit-progress-value{background:var(--accent,Highlight)}.edgepress-data-progress progress::-moz-progress-bar{background:var(--accent,Highlight)}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const configuration = document.getElementById('edgepress-data-saver-config');
|
|
3
|
+
if (!configuration) return;
|
|
4
|
+
const settings = JSON.parse(configuration.textContent);
|
|
5
|
+
const parameters = new URL(location.href).searchParams;
|
|
6
|
+
if (parameters.has('data-save') && (!settings.enabled || !settings.debug || parameters.getAll('data-save').length !== 1 || parameters.get('data-save') !== '')) {
|
|
7
|
+
location.replace(settings.notFoundUrl);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!settings.enabled) return;
|
|
11
|
+
const modes = ['auto', 'text', 'full'];
|
|
12
|
+
const key = 'edgepress-data-mode';
|
|
13
|
+
const query = parameters.has('data-save') ? 'text' : parameters.get('data-mode');
|
|
14
|
+
let preference = settings.mode;
|
|
15
|
+
try { const saved = localStorage.getItem(key); if (modes.includes(saved)) preference = saved; } catch {}
|
|
16
|
+
if (modes.includes(query)) preference = query;
|
|
17
|
+
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
|
18
|
+
const reduced = settings.respectBrowserPreference && (connection?.saveData === true || matchMedia('(prefers-reduced-data: reduce)').matches);
|
|
19
|
+
const mode = preference === 'auto' ? reduced ? 'text' : 'full' : preference;
|
|
20
|
+
document.documentElement.dataset.edgepressDataMode = mode;
|
|
21
|
+
if (mode === 'full' && settings.firstImage) {
|
|
22
|
+
const link = document.createElement('link');
|
|
23
|
+
link.rel = 'preload';
|
|
24
|
+
link.as = 'image';
|
|
25
|
+
link.href = settings.firstImage.href;
|
|
26
|
+
if (settings.firstImage.srcset) link.imageSrcset = settings.firstImage.srcset;
|
|
27
|
+
if (settings.firstImage.sizes) link.imageSizes = settings.firstImage.sizes;
|
|
28
|
+
if (settings.firstImage.type) link.type = settings.firstImage.type;
|
|
29
|
+
link.fetchPriority = 'high';
|
|
30
|
+
document.head.append(link);
|
|
31
|
+
}
|
|
32
|
+
for (const hint of (mode === 'text' ? settings.textPreloads : settings.fullPreloads) || []) {
|
|
33
|
+
const link = document.createElement('link');
|
|
34
|
+
link.rel = hint.rel;
|
|
35
|
+
link.href = hint.href;
|
|
36
|
+
if (hint.as) link.as = hint.as;
|
|
37
|
+
link.dataset.edgepressDataPreload = '';
|
|
38
|
+
document.head.append(link);
|
|
39
|
+
}
|
|
40
|
+
const resources = new Map();
|
|
41
|
+
let firstScreenReady = false;
|
|
42
|
+
let dismissed = false;
|
|
43
|
+
let offerRequested = false;
|
|
44
|
+
let monitor;
|
|
45
|
+
let switching = false;
|
|
46
|
+
const prepareWaiting = () => {
|
|
47
|
+
const waiting = document.querySelector('[data-data-wait]');
|
|
48
|
+
if (!waiting) return;
|
|
49
|
+
waiting.hidden = false;
|
|
50
|
+
const offer = waiting.querySelector('[data-data-offer]');
|
|
51
|
+
if (offer) {
|
|
52
|
+
offer.hidden = mode !== 'full' || !settings.detectSlowConnection;
|
|
53
|
+
earlyObserver.disconnect();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const earlyObserver = new MutationObserver(prepareWaiting);
|
|
57
|
+
earlyObserver.observe(document.documentElement, { childList: true, subtree: true });
|
|
58
|
+
document.documentElement.dataset.edgepressDataReady = 'false';
|
|
59
|
+
const switchView = selected => {
|
|
60
|
+
if (switching || !['text', 'full'].includes(selected)) return;
|
|
61
|
+
switching = true;
|
|
62
|
+
const url = new URL(location.href);
|
|
63
|
+
url.searchParams.delete('data-save');
|
|
64
|
+
document.documentElement.dataset.edgepressDataReady = 'false';
|
|
65
|
+
const waiting = document.querySelector('[data-data-wait]');
|
|
66
|
+
if (waiting) waiting.hidden = false;
|
|
67
|
+
document.querySelectorAll('[data-data-mode]').forEach(control => { control.disabled = true; });
|
|
68
|
+
let persisted = false;
|
|
69
|
+
try { sessionStorage.setItem('edgepress-data-focus', selected); sessionStorage.setItem('edgepress-data-scroll', String(scrollY)); } catch {}
|
|
70
|
+
try { localStorage.setItem(key, selected); persisted = localStorage.getItem(key) === selected; } catch {}
|
|
71
|
+
if (persisted) url.searchParams.delete('data-mode'); else url.searchParams.set('data-mode', selected);
|
|
72
|
+
location.assign(url.href);
|
|
73
|
+
};
|
|
74
|
+
document.addEventListener('click', event => {
|
|
75
|
+
const button = event.target.closest('[data-data-mode]');
|
|
76
|
+
if (button) switchView(button.dataset.dataMode);
|
|
77
|
+
});
|
|
78
|
+
document.addEventListener('focusin', event => {
|
|
79
|
+
if (event.target.closest('[data-data-offer]')) offerRequested = true;
|
|
80
|
+
});
|
|
81
|
+
const progress = (phase, completed, total) => {
|
|
82
|
+
const indicator = document.querySelector('[data-data-progress]');
|
|
83
|
+
const label = document.querySelector('[data-data-progress-label]');
|
|
84
|
+
if (!indicator || !label || switching) return;
|
|
85
|
+
if (indicator.max !== Math.max(1, total)) indicator.max = Math.max(1, total);
|
|
86
|
+
if (indicator.value !== completed) indicator.value = completed;
|
|
87
|
+
const message = (settings.labels[phase] || settings.labels.loading).replace('{loaded}', completed).replace('{total}', total);
|
|
88
|
+
if (label.textContent !== message) label.textContent = message;
|
|
89
|
+
if (indicator.getAttribute('aria-label') !== message) indicator.setAttribute('aria-label', message);
|
|
90
|
+
};
|
|
91
|
+
const showOffer = () => {
|
|
92
|
+
if (firstScreenReady || dismissed) return;
|
|
93
|
+
offerRequested = true;
|
|
94
|
+
const offer = document.querySelector('[data-data-offer]');
|
|
95
|
+
if (offer) {
|
|
96
|
+
offer.hidden = false;
|
|
97
|
+
offer.querySelector('h2').textContent = settings.labels.slowTitle;
|
|
98
|
+
offer.querySelector('[data-data-loading-notice]').textContent = settings.labels.slowNotice;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const offerTimer = mode === 'full' && preference === 'auto' && settings.detectSlowConnection
|
|
102
|
+
? setTimeout(showOffer, Math.max(0, (settings.promptAfterMs || 5000) - performance.now()))
|
|
103
|
+
: null;
|
|
104
|
+
const activateResources = (kind, feature) => {
|
|
105
|
+
const loading = [];
|
|
106
|
+
for (const template of document.querySelectorAll('template[data-edgepress-data-resource]')) {
|
|
107
|
+
if (template.dataset.edgepressDataResource !== kind) continue;
|
|
108
|
+
if (feature && template.dataset.dataFeature !== feature) continue;
|
|
109
|
+
if (!feature && kind === 'style' && template.dataset.dataFeature === 'fonts') continue;
|
|
110
|
+
const original = template.content.firstElementChild;
|
|
111
|
+
if (!original) continue;
|
|
112
|
+
const source = original.getAttribute('src') || original.getAttribute('href');
|
|
113
|
+
const identity = kind + ':' + original.tagName + ':' + (original.getAttribute('rel') || '') + ':' + source;
|
|
114
|
+
if (resources.has(identity)) continue;
|
|
115
|
+
const element = document.createElement(original.tagName);
|
|
116
|
+
for (const attribute of original.attributes) element.setAttribute(attribute.name, attribute.value);
|
|
117
|
+
if (element.tagName === 'SCRIPT') element.async = false;
|
|
118
|
+
if (element.tagName === 'SCRIPT' || element.tagName === 'LINK' && element.rel === 'stylesheet') loading.push(new Promise(resolve => {
|
|
119
|
+
element.addEventListener('load', () => resolve(true), { once: true });
|
|
120
|
+
element.addEventListener('error', () => {
|
|
121
|
+
resources.delete(identity);
|
|
122
|
+
element.replaceWith(template);
|
|
123
|
+
resolve(false);
|
|
124
|
+
}, { once: true });
|
|
125
|
+
}));
|
|
126
|
+
resources.set(identity, element);
|
|
127
|
+
template.replaceWith(element);
|
|
128
|
+
}
|
|
129
|
+
return loading;
|
|
130
|
+
};
|
|
131
|
+
const activateMedia = host => {
|
|
132
|
+
const template = host.querySelector(':scope > template');
|
|
133
|
+
if (!template) return;
|
|
134
|
+
if (template.hasAttribute('data-edgepress-data-html')) template.innerHTML = template.content.textContent;
|
|
135
|
+
host.replaceChildren(template.content.cloneNode(true));
|
|
136
|
+
host.dataset.loaded = 'true';
|
|
137
|
+
document.dispatchEvent(new CustomEvent('edgepress:data-media', { detail: { root: host } }));
|
|
138
|
+
};
|
|
139
|
+
const deferMedia = (element, activate, label = '') => {
|
|
140
|
+
if (mode !== 'text') { activate(); return null; }
|
|
141
|
+
const host = document.createElement('span');
|
|
142
|
+
host.className = 'edgepress-data-placeholder';
|
|
143
|
+
const text = document.createElement('span');
|
|
144
|
+
text.dataset.dataDescription = '';
|
|
145
|
+
text.textContent = label;
|
|
146
|
+
const button = document.createElement('button');
|
|
147
|
+
button.type = 'button';
|
|
148
|
+
button.textContent = settings.labels.load;
|
|
149
|
+
if (label) button.setAttribute('aria-label', settings.labels.load + ': ' + label);
|
|
150
|
+
button.addEventListener('click', () => {
|
|
151
|
+
host.replaceChildren(element);
|
|
152
|
+
host.dataset.loaded = 'true';
|
|
153
|
+
activate();
|
|
154
|
+
if (!element.matches('a, button, input, select, textarea, [tabindex]')) element.tabIndex = -1;
|
|
155
|
+
element.focus({ preventScroll: true });
|
|
156
|
+
}, { once: true });
|
|
157
|
+
host.append(text, button);
|
|
158
|
+
return host;
|
|
159
|
+
};
|
|
160
|
+
window.edgepressDataSaver = Object.freeze({ mode, preference, deferMedia });
|
|
161
|
+
const initialize = () => {
|
|
162
|
+
const offer = document.querySelector('[data-data-offer]');
|
|
163
|
+
const waiting = document.querySelector('[data-data-wait]');
|
|
164
|
+
prepareWaiting();
|
|
165
|
+
let revealPage = () => {};
|
|
166
|
+
const returnEntry = document.querySelector('[data-data-return]');
|
|
167
|
+
if (returnEntry) returnEntry.hidden = mode !== 'text';
|
|
168
|
+
if (offer && offerRequested) offer.hidden = false;
|
|
169
|
+
const closeOffer = () => {
|
|
170
|
+
if (!offer) return;
|
|
171
|
+
if (offer.contains(document.activeElement)) {
|
|
172
|
+
const main = document.querySelector('main');
|
|
173
|
+
if (main) { if (!main.hasAttribute('tabindex')) main.tabIndex = -1; main.focus({ preventScroll: true }); }
|
|
174
|
+
}
|
|
175
|
+
offer.hidden = true;
|
|
176
|
+
};
|
|
177
|
+
const dismiss = () => {
|
|
178
|
+
dismissed = true;
|
|
179
|
+
offerRequested = false;
|
|
180
|
+
clearTimeout(offerTimer);
|
|
181
|
+
if (firstScreenReady) { revealPage(); closeOffer(); return; }
|
|
182
|
+
if (offer) {
|
|
183
|
+
offer.querySelector('h2').textContent = settings.labels.loading;
|
|
184
|
+
offer.querySelector('[data-data-loading-notice]').textContent = settings.labels.loadingNotice;
|
|
185
|
+
}
|
|
186
|
+
const status = waiting?.querySelector('[data-data-progress-label]');
|
|
187
|
+
if (status) { status.tabIndex = -1; status.focus({ preventScroll: true }); }
|
|
188
|
+
};
|
|
189
|
+
document.querySelector('[data-data-dismiss]')?.addEventListener('click', dismiss);
|
|
190
|
+
document.addEventListener('keydown', event => { if (event.key === 'Escape' && offer && !offer.hidden) dismiss(); });
|
|
191
|
+
let requestedFocus = false;
|
|
192
|
+
let position = 0;
|
|
193
|
+
try {
|
|
194
|
+
requestedFocus = modes.includes(sessionStorage.getItem('edgepress-data-focus'));
|
|
195
|
+
position = Number(sessionStorage.getItem('edgepress-data-scroll')) || 0;
|
|
196
|
+
sessionStorage.removeItem('edgepress-data-focus');
|
|
197
|
+
sessionStorage.removeItem('edgepress-data-scroll');
|
|
198
|
+
} catch { requestedFocus = modes.includes(query); }
|
|
199
|
+
const focusDeadline = performance.now() + 8000;
|
|
200
|
+
const restoreFocus = () => {
|
|
201
|
+
if (!requestedFocus || document.activeElement !== document.body) return;
|
|
202
|
+
const target = document.querySelector('main');
|
|
203
|
+
if (!target) return;
|
|
204
|
+
if (getComputedStyle(target).visibility !== 'visible') {
|
|
205
|
+
if (performance.now() < focusDeadline) requestAnimationFrame(restoreFocus);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (!target.hasAttribute('tabindex')) target.tabIndex = -1;
|
|
209
|
+
target.focus({ preventScroll: true });
|
|
210
|
+
if (position > 0) scrollTo({ top: position, behavior: 'instant' });
|
|
211
|
+
};
|
|
212
|
+
const loading = activateResources('style', mode === 'text' ? 'core' : undefined);
|
|
213
|
+
const controls = activateResources('script', 'core');
|
|
214
|
+
const criticalReady = results => {
|
|
215
|
+
if (results.every(Boolean)) return true;
|
|
216
|
+
clearTimeout(offerTimer);
|
|
217
|
+
offerRequested = true;
|
|
218
|
+
if (offer) {
|
|
219
|
+
offer.hidden = false;
|
|
220
|
+
offer.querySelector('h2').textContent = settings.labels.loading;
|
|
221
|
+
offer.querySelector('[data-data-loading-notice]').textContent = settings.labels.loadFailed;
|
|
222
|
+
offer.querySelector('[data-data-dismiss]').hidden = true;
|
|
223
|
+
offer.querySelector('[data-data-mode=text]').hidden = mode === 'text';
|
|
224
|
+
const retry = offer.querySelector('[data-data-retry]');
|
|
225
|
+
retry.hidden = false;
|
|
226
|
+
retry.addEventListener('click', () => location.reload(), { once:true });
|
|
227
|
+
}
|
|
228
|
+
const status = waiting?.querySelector('[data-data-progress-label]');
|
|
229
|
+
if (status) status.textContent = settings.labels.loadFailed;
|
|
230
|
+
return false;
|
|
231
|
+
};
|
|
232
|
+
let completedStyles = 0;
|
|
233
|
+
let completedControls = 0;
|
|
234
|
+
const updateProgress = () => {
|
|
235
|
+
if (completedStyles < loading.length) progress('progressStyles', completedStyles, loading.length);
|
|
236
|
+
else progress('progressControls', completedControls, controls.length);
|
|
237
|
+
};
|
|
238
|
+
updateProgress();
|
|
239
|
+
for (const resource of loading) void resource.then(() => { completedStyles++; updateProgress(); });
|
|
240
|
+
for (const resource of controls) void resource.then(() => { completedControls++; updateProgress(); });
|
|
241
|
+
if (mode === 'full') {
|
|
242
|
+
const reveal = () => {
|
|
243
|
+
if (switching) return;
|
|
244
|
+
if (document.documentElement.dataset.edgepressDataReady === 'true') return;
|
|
245
|
+
document.documentElement.dataset.edgepressDataReady = 'true';
|
|
246
|
+
if (waiting) waiting.hidden = true;
|
|
247
|
+
document.querySelectorAll('[data-edgepress-data-preload]').forEach(link => link.remove());
|
|
248
|
+
requestAnimationFrame(() => {
|
|
249
|
+
activateResources('script');
|
|
250
|
+
const loadFonts = () => { if (!switching) activateResources('style', 'fonts'); };
|
|
251
|
+
if (typeof requestIdleCallback === 'function') requestIdleCallback(loadFonts, {timeout:1500});
|
|
252
|
+
else setTimeout(loadFonts, 250);
|
|
253
|
+
});
|
|
254
|
+
requestAnimationFrame(restoreFocus);
|
|
255
|
+
};
|
|
256
|
+
revealPage = reveal;
|
|
257
|
+
let stylesReady = false;
|
|
258
|
+
const visibleImages = new Set();
|
|
259
|
+
const ready = () => {
|
|
260
|
+
stylesReady = true;
|
|
261
|
+
for (const image of document.images) {
|
|
262
|
+
const rectangle = image.getBoundingClientRect();
|
|
263
|
+
if (rectangle.width > 0 && rectangle.height > 0 && rectangle.top < innerHeight && rectangle.bottom > 0) visibleImages.add(image);
|
|
264
|
+
}
|
|
265
|
+
for (const image of visibleImages) if (image.loading === 'lazy' && !image.complete) image.loading = 'eager';
|
|
266
|
+
checkFirstScreen();
|
|
267
|
+
};
|
|
268
|
+
void Promise.all([...loading, ...controls]).then(results => {
|
|
269
|
+
if (switching || !criticalReady(results)) return;
|
|
270
|
+
document.querySelectorAll('[data-edgepress-data-media]').forEach(activateMedia);
|
|
271
|
+
ready();
|
|
272
|
+
}, ready);
|
|
273
|
+
const checkFirstScreen = () => {
|
|
274
|
+
if (!stylesReady || document.readyState === 'loading') return;
|
|
275
|
+
const completedImages = [...visibleImages].filter(image => image.complete).length;
|
|
276
|
+
progress('progressMedia', completedImages, visibleImages.size);
|
|
277
|
+
if (completedImages < visibleImages.size) return;
|
|
278
|
+
firstScreenReady = true;
|
|
279
|
+
clearTimeout(offerTimer);
|
|
280
|
+
clearInterval(monitor);
|
|
281
|
+
if (!offerRequested || dismissed) { reveal(); closeOffer(); }
|
|
282
|
+
};
|
|
283
|
+
monitor = setInterval(checkFirstScreen, 100);
|
|
284
|
+
requestAnimationFrame(checkFirstScreen);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
void Promise.all([...loading, ...controls]).then(results => {
|
|
288
|
+
if (switching || !criticalReady(results)) return;
|
|
289
|
+
document.documentElement.dataset.edgepressDataReady = 'true';
|
|
290
|
+
if (waiting) waiting.hidden = true;
|
|
291
|
+
document.querySelectorAll('[data-edgepress-data-preload]').forEach(link => link.remove());
|
|
292
|
+
requestAnimationFrame(restoreFocus);
|
|
293
|
+
});
|
|
294
|
+
document.addEventListener('click', event => {
|
|
295
|
+
const button = event.target.closest('[data-oembed-load]');
|
|
296
|
+
if (!button || !document.querySelector('template[data-edgepress-data-resource="script"][data-data-feature="embed"]')) return;
|
|
297
|
+
button.disabled = true;
|
|
298
|
+
button.setAttribute('aria-busy', 'true');
|
|
299
|
+
void Promise.all(activateResources('script', 'embed')).then(results => {
|
|
300
|
+
button.disabled = false;
|
|
301
|
+
button.removeAttribute('aria-busy');
|
|
302
|
+
if (results.every(Boolean)) button.click();
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
for (const host of document.querySelectorAll('[data-edgepress-data-media]')) {
|
|
306
|
+
if (host.hasAttribute('data-data-decorative') || host.hasAttribute('data-data-brand')) continue;
|
|
307
|
+
const button = document.createElement('button');
|
|
308
|
+
button.type = 'button';
|
|
309
|
+
button.textContent = settings.labels.load;
|
|
310
|
+
const descriptionNode = host.querySelector('[data-data-description]');
|
|
311
|
+
if (descriptionNode && !descriptionNode.textContent.trim()) descriptionNode.textContent = settings.labels.missingDescription;
|
|
312
|
+
const description = descriptionNode?.textContent;
|
|
313
|
+
if (description) button.setAttribute('aria-label', settings.labels.load + ': ' + description);
|
|
314
|
+
const link = host.closest('a');
|
|
315
|
+
if (link) link.after(button); else host.append(button);
|
|
316
|
+
button.addEventListener('click', () => {
|
|
317
|
+
if (link) button.remove();
|
|
318
|
+
activateMedia(host);
|
|
319
|
+
activateResources('style', host.dataset.dataFeature);
|
|
320
|
+
activateResources('script', host.dataset.dataFeature);
|
|
321
|
+
const target = host.querySelector('button, a, [tabindex], img, video, audio, iframe');
|
|
322
|
+
if (target && !target.matches('a, button, input, select, textarea, [tabindex]')) target.tabIndex = -1;
|
|
323
|
+
target?.focus({ preventScroll: true });
|
|
324
|
+
}, { once: true });
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
addEventListener('pagehide', () => { earlyObserver.disconnect(); clearTimeout(offerTimer); clearInterval(monitor); }, { once: true });
|
|
328
|
+
const start = () => {
|
|
329
|
+
if (document.hidden) initialize();
|
|
330
|
+
else requestAnimationFrame(() => setTimeout(initialize, 0));
|
|
331
|
+
};
|
|
332
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start, { once: true }); else start();
|
|
333
|
+
})();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { mountDocument } from './document-viewer/index.js';
|
|
2
|
+
import { readChoice } from './plugins/consent/choices.js';
|
|
3
|
+
|
|
4
|
+
const labels = JSON.parse(document.getElementById('edgepress-document-viewer-config')?.textContent || '{}');
|
|
5
|
+
const settings = JSON.parse(document.getElementById('edgepress-privacy-config')?.textContent || '{}');
|
|
6
|
+
const viewers = new Map();
|
|
7
|
+
|
|
8
|
+
function allowed(root) {
|
|
9
|
+
const id = root.dataset.documentService;
|
|
10
|
+
const origins = [root.dataset.documentSrc, root.dataset.documentPreview].filter(Boolean).map(source => new URL(source, document.baseURI).origin);
|
|
11
|
+
if (!id) return origins.every(origin => origin === location.origin);
|
|
12
|
+
const service = settings.privacy?.integrations?.find(item => item.id === id);
|
|
13
|
+
const permitted = service?.backendUrl ? [location.origin, new URL(service.backendUrl).origin, ...(service.csp?.['connect-src'] || [])] : [];
|
|
14
|
+
if (service?.provider === 'external-api' && service.enabled !== false && origins.every(origin => permitted.includes(origin)) && readChoice(settings)?.allowed.includes(id)) return true;
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function refresh() {
|
|
19
|
+
for (const root of document.querySelectorAll('[data-edgepress-document]')) {
|
|
20
|
+
if (viewers.has(root)) continue;
|
|
21
|
+
if (root.closest('[data-edgepress-oembed], [data-edgepress-service], template')) continue;
|
|
22
|
+
const viewer = mountDocument(root.querySelector('[data-document-mount]'), {
|
|
23
|
+
src: root.dataset.documentSrc, previewSrc: root.dataset.documentPreview,
|
|
24
|
+
title: root.dataset.documentTitle, format: root.dataset.documentFormat,
|
|
25
|
+
locale: document.documentElement.lang, labels, canLoad: () => allowed(root)
|
|
26
|
+
});
|
|
27
|
+
viewers.set(root, viewer);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
refresh();
|
|
31
|
+
document.addEventListener('edgepress:data-media', refresh);
|
|
32
|
+
|
|
33
|
+
addEventListener('pagehide', () => { for (const viewer of viewers.values()) viewer.close(false); });
|
|
34
|
+
addEventListener('storage', () => { for (const [root, viewer] of viewers) if (!allowed(root)) viewer.close(false); });
|
|
35
|
+
document.addEventListener('visibilitychange', () => { for (const [root, viewer] of viewers) if (!allowed(root)) viewer.close(false); });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function linkOrigin(value) {
|
|
2
|
+
const url = new URL(value);
|
|
3
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.hostname.includes('*') || url.username || url.password || url.pathname !== '/' || url.search || url.hash) throw new Error('Trusted sites must be exact HTTP(S) origins, without credentials, paths or wildcards');
|
|
4
|
+
return url.origin;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function classifyLink(value, settings, base) {
|
|
8
|
+
let url;
|
|
9
|
+
try { url = new URL(value, base); } catch { return { kind: 'blocked' }; }
|
|
10
|
+
if (['javascript:', 'data:', 'vbscript:', 'file:', 'blob:', 'filesystem:', 'about:'].includes(url.protocol) || url.username || url.password) return { kind: 'blocked' };
|
|
11
|
+
if (!['http:', 'https:'].includes(url.protocol)) return { kind: 'native' };
|
|
12
|
+
const origins = new Set([new URL(settings.siteUrl).origin, ...settings.trustedOrigins]);
|
|
13
|
+
return { kind: origins.has(url.origin) ? 'native' : 'external', url: url.href, domain: url.host, origin: url.origin };
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.edgepress-external-overlay{--external-paper:var(--external-link-surface,var(--surface,var(--panel,var(--paper,var(--external-auto-paper,Canvas)))));--external-ink:var(--external-link-ink,var(--ink,var(--text,var(--external-auto-ink,CanvasText))));--external-accent:var(--external-link-accent,var(--accent,var(--external-auto-accent,LinkText)));position:fixed;inset:0;z-index:100000;display:grid;place-items:center;padding:clamp(16px,4vw,40px);background:rgba(0,0,0,.52);color:var(--external-ink);font:inherit;overflow:auto;overscroll-behavior:contain;color-scheme:inherit}
|
|
2
|
+
.edgepress-external-overlay[hidden]{display:none!important}
|
|
3
|
+
.edgepress-external-panel{box-sizing:border-box;width:min(100%,520px);max-height:90dvh;overflow:auto;background:var(--external-paper);color:var(--external-ink);border:1px solid var(--line,currentColor);border-radius:var(--radius-card,20px);padding:clamp(22px,5vw,36px);box-shadow:0 24px 80px rgba(0,0,0,.25);text-align:start;overflow-wrap:anywhere}
|
|
4
|
+
.edgepress-external-panel h2{margin:0 0 16px;font:inherit;font-size:1.35rem;font-weight:750;color:inherit}
|
|
5
|
+
.edgepress-external-panel p{margin:12px 0;line-height:1.65;color:inherit}
|
|
6
|
+
.edgepress-external-url{font-size:1rem;font-weight:650;overflow-wrap:anywhere;word-break:break-word;unicode-bidi:plaintext}
|
|
7
|
+
.edgepress-external-actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:24px}
|
|
8
|
+
.edgepress-external-actions button{appearance:none;box-sizing:border-box;flex:1;min-width:140px;min-height:48px;margin:0;padding:12px 18px;border:1px solid var(--external-accent);border-radius:var(--radius-small,12px);background:var(--external-paper);color:var(--external-ink);font:inherit;font-weight:650;line-height:1.4;cursor:pointer}
|
|
9
|
+
.edgepress-external-actions button:last-child{border-width:2px}
|
|
10
|
+
.edgepress-external-actions button:hover{box-shadow:inset 0 0 0 1px var(--external-accent)}
|
|
11
|
+
.edgepress-external-actions button:focus-visible{outline:3px solid var(--external-accent);outline-offset:4px}
|
|
12
|
+
@media(forced-colors:active){.edgepress-external-panel{background:Canvas;color:CanvasText;border:2px solid CanvasText}.edgepress-external-actions button{background:ButtonFace;color:ButtonText;border-color:ButtonText}.edgepress-external-actions button:focus-visible{outline-color:Highlight}}
|
|
13
|
+
@media(prefers-reduced-motion:reduce){.edgepress-external-overlay,.edgepress-external-overlay *{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
|