@projektemacher/storymapjs 0.10.7 → 0.11.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/CHANGELOG +431 -19
- package/README.md +168 -17
- package/dist/assets/demo-bWnOyfUw.js +1 -0
- package/dist/assets/harness-C3JUv5Ii.js +1 -0
- package/dist/assets/harness-multi-XZNex3tb.js +1 -0
- package/dist/assets/harness-support-CjfZIVeb.js +1 -0
- package/dist/assets/index-wHPqGrBS.js +1 -0
- package/dist/assets/main-DQ32hWBM.js +17 -0
- package/dist/context.json +23 -9
- package/dist/css/fonts/files/amatic-sc-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-hebrew-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-hebrew-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/amatic-sc-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-100-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-100-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-200-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-600-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-800-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-100-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-100-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-200-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-600-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-800-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-100-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-100-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-200-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-600-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-800-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/bitter-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-arabic-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-200-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-600-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-800-normal.woff2 +0 -0
- package/dist/css/fonts/files/cairo-latin-ext-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/dancing-script-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/eb-garamond-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/old-standard-tt-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-hebrew-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-hebrew-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/open-sans-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-normal.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/playfair-display-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/raleway-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/raleway-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/raleway-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-greek-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/roboto-slab-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-300-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-300-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-400-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-500-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-700-italic.woff2 +0 -0
- package/dist/css/fonts/files/ubuntu-greek-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/files/unica-one-vietnamese-400-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-cyrillic-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-greek-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-greek-wght-normal.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-vietnamese-wght-italic.woff2 +0 -0
- package/dist/css/fonts/files/vollkorn-vietnamese-wght-normal.woff2 +0 -0
- package/dist/css/fonts/font.abril-droidsans.css +3 -0
- package/dist/css/fonts/font.amatic-andika.css +57 -0
- package/dist/css/fonts/font.bitter-raleway.css +111 -0
- package/dist/css/fonts/font.cairo.css +312 -0
- package/dist/css/fonts/font.clicker-garamond.css +93 -0
- package/dist/css/fonts/font.dancing-ledger.css +12 -0
- package/dist/css/fonts/font.default.css +183 -0
- package/dist/css/fonts/font.fjalla-average.css +3 -0
- package/dist/css/fonts/font.georgia-helvetica.css +3 -0
- package/dist/css/fonts/font.knightlab.css +642 -0
- package/dist/css/fonts/font.lustria-lato.css +3 -0
- package/dist/css/fonts/font.medula-lato.css +3 -0
- package/dist/css/fonts/font.oldstandard.css +84 -0
- package/dist/css/fonts/font.opensans-gentiumbook.css +183 -0
- package/dist/css/fonts/font.playfair-faunaone.css +39 -0
- package/dist/css/fonts/font.playfair.css +147 -0
- package/dist/css/fonts/font.pt.css +183 -0
- package/dist/css/fonts/font.roboto-megrim.css +3 -0
- package/dist/css/fonts/font.rufina-sintony.css +3 -0
- package/dist/css/fonts/font.ubuntu.css +291 -0
- package/dist/css/fonts/font.unicaone-vollkorn.css +84 -0
- package/dist/css/storymap.css +1 -1
- package/dist/demo.html +3 -2
- package/dist/docs/api/.nojekyll +1 -0
- package/dist/docs/api/assets/custom.css +47 -0
- package/dist/docs/api/assets/hierarchy.js +1 -0
- package/dist/docs/api/assets/highlight.css +57 -0
- package/dist/docs/api/assets/icons.js +18 -0
- package/dist/docs/api/assets/icons.svg +1 -0
- package/dist/docs/api/assets/main.js +60 -0
- package/dist/docs/api/assets/navigation.js +1 -0
- package/dist/docs/api/assets/search.js +1 -0
- package/dist/docs/api/assets/style.css +1648 -0
- package/dist/docs/api/classes/StoryMap.html +2112 -0
- package/dist/docs/api/functions/MediaType.html +51 -0
- package/dist/docs/api/functions/isPresentation3Collection.html +47 -0
- package/dist/docs/api/functions/isPresentation3Manifest.html +53 -0
- package/dist/docs/api/functions/isSlideshowCollection.html +51 -0
- package/dist/docs/api/functions/loadCSS.html +63 -0
- package/dist/docs/api/functions/manifestToStorymapData.html +49 -0
- package/dist/docs/api/functions/setLanguage.html +54 -0
- package/dist/docs/api/functions/slideshowToStorymapData.html +51 -0
- package/dist/docs/api/functions/slideshowVersion.html +48 -0
- package/dist/docs/api/functions/storymapToManifest.html +57 -0
- package/dist/docs/api/functions/validateStorymap.html +53 -0
- package/dist/docs/api/functions/validateStorymapAndReport.html +54 -0
- package/dist/docs/api/hierarchy.html +28 -0
- package/dist/docs/api/index.html +300 -0
- package/dist/docs/api/interfaces/AnimationHandle.html +60 -0
- package/dist/docs/api/interfaces/ImagereadyPayload.html +71 -0
- package/dist/docs/api/interfaces/LanguageEntry.html +102 -0
- package/dist/docs/api/interfaces/LatLngLiteral.html +73 -0
- package/dist/docs/api/interfaces/LoadOptions.html +59 -0
- package/dist/docs/api/interfaces/MapEvents.html +116 -0
- package/dist/docs/api/interfaces/MapMarkerEvents.html +66 -0
- package/dist/docs/api/interfaces/MarkerEventPayload.html +57 -0
- package/dist/docs/api/interfaces/MediaEvents.html +78 -0
- package/dist/docs/api/interfaces/MenuBarEvents.html +114 -0
- package/dist/docs/api/interfaces/MessageEvents.html +72 -0
- package/dist/docs/api/interfaces/OlLayer.html +1400 -0
- package/dist/docs/api/interfaces/OlMap.html +1656 -0
- package/dist/docs/api/interfaces/OlProjection.html +332 -0
- package/dist/docs/api/interfaces/OlSource.html +784 -0
- package/dist/docs/api/interfaces/OlTileLayer.html +1497 -0
- package/dist/docs/api/interfaces/OlVectorLayer.html +1559 -0
- package/dist/docs/api/interfaces/OlView.html +1958 -0
- package/dist/docs/api/interfaces/SlideBackgroundState.html +66 -0
- package/dist/docs/api/interfaces/SlideEvents.html +78 -0
- package/dist/docs/api/interfaces/SlideNavEvents.html +72 -0
- package/dist/docs/api/interfaces/SlideshowPlayerSettings.html +182 -0
- package/dist/docs/api/interfaces/SlideshowToStorymapResult.html +60 -0
- package/dist/docs/api/interfaces/SlideshowTranslatorOptions.html +65 -0
- package/dist/docs/api/interfaces/SlideshowWarning.html +72 -0
- package/dist/docs/api/interfaces/StoryMapEvents.html +146 -0
- package/dist/docs/api/interfaces/StoryMapMarker.html +763 -0
- package/dist/docs/api/interfaces/StorySliderEvents.html +102 -0
- package/dist/docs/api/interfaces/StorymapBasemap.html +69 -0
- package/dist/docs/api/interfaces/StorymapData.html +77 -0
- package/dist/docs/api/interfaces/StorymapDataWrapper.html +60 -0
- package/dist/docs/api/interfaces/StorymapDocument.html +68 -0
- package/dist/docs/api/interfaces/StorymapError.html +63 -0
- package/dist/docs/api/interfaces/StorymapGeoreference.html +93 -0
- package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +74 -0
- package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +69 -0
- package/dist/docs/api/interfaces/StorymapLanguageMap.html +57 -0
- package/dist/docs/api/interfaces/StorymapManifest.html +118 -0
- package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +137 -0
- package/dist/docs/api/interfaces/StorymapManifestBackground.html +81 -0
- package/dist/docs/api/interfaces/StorymapManifestCanvas.html +188 -0
- package/dist/docs/api/interfaces/StorymapManifestContentResource.html +97 -0
- package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +82 -0
- package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +87 -0
- package/dist/docs/api/interfaces/StorymapManifestImageService.html +69 -0
- package/dist/docs/api/interfaces/StorymapManifestRange.html +75 -0
- package/dist/docs/api/interfaces/StorymapManifestService.html +77 -0
- package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +69 -0
- package/dist/docs/api/interfaces/StorymapManifestStatement.html +63 -0
- package/dist/docs/api/interfaces/StorymapMapOptions.html +92 -0
- package/dist/docs/api/interfaces/StorymapOptions.html +734 -0
- package/dist/docs/api/interfaces/StorymapOverlayLayer.html +157 -0
- package/dist/docs/api/interfaces/StorymapSlide.html +186 -0
- package/dist/docs/api/interfaces/StorymapSlideBackground.html +72 -0
- package/dist/docs/api/interfaces/StorymapSlideLocation.html +161 -0
- package/dist/docs/api/interfaces/StorymapSlideMarker.html +103 -0
- package/dist/docs/api/interfaces/StorymapSlideMedia.html +149 -0
- package/dist/docs/api/interfaces/StorymapSlideNarration.html +117 -0
- package/dist/docs/api/interfaces/StorymapSlideText.html +72 -0
- package/dist/docs/api/interfaces/StorymapTilejson.html +105 -0
- package/dist/docs/api/interfaces/SwipableEvents.html +102 -0
- package/dist/docs/api/interfaces/TextEvents.html +66 -0
- package/dist/docs/api/media/es.json +31 -0
- package/dist/docs/api/media/events.md +66 -0
- package/dist/docs/api/media/migration-from-knightlab.md +399 -0
- package/dist/docs/api/media/slideshow.md +109 -0
- package/dist/docs/api/media/storymap-as-iiif-manifest.md +1007 -0
- package/dist/docs/api/modules.html +50 -0
- package/dist/docs/api/types/ContentState.html +70 -0
- package/dist/docs/api/types/FiredEvent.html +43 -0
- package/dist/docs/api/types/ImagereadyKind.html +34 -0
- package/dist/docs/api/types/MediaTypeMatch.html +78 -0
- package/dist/docs/api/types/SwipeDirection.html +36 -0
- package/dist/docs/api/types/TileSourceFactory.html +53 -0
- package/dist/docs/authoring.html +306 -0
- package/dist/docs/events.html +263 -0
- package/dist/docs/iiif.html +738 -69
- package/dist/docs/migration.html +360 -11
- package/dist/docs/readme.html +149 -17
- package/dist/embed/index.html +8 -1
- package/dist/examples/font-css-false.json +33 -0
- package/dist/examples/issue-242-nonlatin.json +55 -0
- package/dist/examples/issue-305-start-at-slide-data.json +96 -0
- package/dist/examples/issue-358-iframe.json +57 -0
- package/dist/examples/issue-iiif-geo.json +32 -0
- package/dist/examples/issue-image-alt.json +23 -0
- package/dist/examples/issue-image-region.json +42 -0
- package/dist/examples/issue-image-srcset.json +24 -0
- package/dist/examples/layers-control.json +60 -0
- package/dist/examples/map-area-overlays.json +68 -0
- package/dist/examples/map-template-provider.json +36 -0
- package/dist/examples/multi-media.json +71 -0
- package/dist/examples/no-map.json +44 -0
- package/dist/examples-iiif/annotated-image.json +204 -0
- package/dist/examples-iiif/bob-boilen.json +11 -5
- package/dist/examples-iiif/courbet.json +9 -6
- package/dist/examples-iiif/empty.json +8 -4
- package/dist/examples-iiif/flickr-drewvigal.json +248 -24
- package/dist/examples-iiif/flickr-zach.wise.json +8 -4
- package/dist/examples-iiif/font-css-false.json +114 -0
- package/dist/examples-iiif/georeferenced-layer-unsupported.json +153 -0
- package/dist/examples-iiif/georeferenced-layer.json +318 -0
- package/dist/examples-iiif/iiif-wellcome.json +9 -6
- package/dist/examples-iiif/instagram-chenpamela.json +381 -36
- package/dist/examples-iiif/instagram_brentfoster.json +429 -40
- package/dist/examples-iiif/instagram_couch.json +261 -26
- package/dist/examples-iiif/instagram_joegermuska.json +441 -41
- package/dist/examples-iiif/instagram_matteich.json +261 -26
- package/dist/examples-iiif/instagram_mirandamulligan.json +261 -26
- package/dist/examples-iiif/instagram_raymondmccrea.json +261 -26
- package/dist/examples-iiif/instagram_test.json +261 -26
- package/dist/examples-iiif/issue-134-no-lines.json +9 -5
- package/dist/examples-iiif/issue-177-color-vars.json +9 -5
- package/dist/examples-iiif/issue-211-rtl.json +9 -5
- package/dist/examples-iiif/issue-242-nonlatin.json +239 -0
- package/dist/examples-iiif/issue-272-facebook.json +9 -5
- package/dist/examples-iiif/issue-305-start-at-slide-data.json +305 -0
- package/dist/examples-iiif/issue-305-start-at-slide.json +9 -5
- package/dist/examples-iiif/issue-341-distance.json +9 -5
- package/dist/examples-iiif/issue-358-iframe.json +190 -0
- package/dist/examples-iiif/issue-360-juxtapose.json +22 -7
- package/dist/examples-iiif/issue-368-null-fields.json +9 -5
- package/dist/examples-iiif/issue-375-code-lists.json +9 -5
- package/dist/examples-iiif/issue-381-dateline.json +9 -5
- package/dist/examples-iiif/issue-405-custom-icon.json +203 -0
- package/dist/examples-iiif/issue-425-many-slides.json +9 -5
- package/dist/examples-iiif/issue-428-background.json +20 -8
- package/dist/examples-iiif/issue-435-googlemaps.json +9 -5
- package/dist/examples-iiif/issue-437-documentcloud.json +22 -7
- package/dist/examples-iiif/issue-451-webp.json +9 -5
- package/dist/examples-iiif/issue-455-audio.json +9 -5
- package/dist/examples-iiif/issue-480-shorts.json +9 -5
- package/dist/examples-iiif/issue-506-marker-sync.json +9 -5
- package/dist/examples-iiif/issue-iiif-geo.json +200 -0
- package/dist/examples-iiif/issue-image-alt.json +90 -0
- package/dist/examples-iiif/issue-image-region.json +203 -0
- package/dist/examples-iiif/issue-image-srcset.json +87 -0
- package/dist/examples-iiif/jansteen.json +9 -6
- package/dist/examples-iiif/katrina.json +197 -41
- package/dist/examples-iiif/layers-control.json +226 -0
- package/dist/examples-iiif/map-area-overlays.json +289 -0
- package/dist/examples-iiif/map-template-provider.json +133 -0
- package/dist/examples-iiif/marktwain.json +255 -58
- package/dist/examples-iiif/multi-media.json +237 -0
- package/dist/examples-iiif/no-map.json +148 -0
- package/dist/examples-iiif/population.json +440 -76
- package/dist/examples-iiif/president.json +456 -83
- package/dist/examples-iiif/scroll-hint.json +190 -0
- package/dist/examples-iiif/seurat.json +113 -22
- package/dist/examples-iiif/zoomify-clamp.json +153 -0
- package/dist/examples-slideshow/single.json +79 -0
- package/dist/examples-slideshow/static/pixel.png +0 -0
- package/dist/examples-slideshow/static.json +44 -0
- package/dist/harness-multi.html +17 -0
- package/dist/harness.html +4 -2
- package/dist/index.html +19 -12
- package/dist/js/storymap.d.ts +2669 -307
- package/dist/js/storymap.js +10820 -6196
- package/dist/js/storymap.js.map +1 -1
- package/dist/navplace-properties.json +54 -0
- package/dist/site.css +54 -36
- package/docs/migration-from-knightlab.md +279 -19
- package/docs/storymap-as-iiif-manifest.md +633 -136
- package/package.json +12 -7
- package/schema/storymap.schema.json +733 -80
- package/src/animation/easings.ts +8 -1
- package/src/animation/tween.ts +186 -0
- package/src/core/Browser.ts +6 -5
- package/src/core/Load.ts +54 -2
- package/src/core/Util.ts +257 -193
- package/src/core/mixins.ts +66 -35
- package/src/core/viewers.ts +94 -0
- package/src/dom/DomEvent.ts +27 -8
- package/src/globals.d.ts +8 -0
- package/src/language/Language.ts +206 -25
- package/src/language/locale/.expected-gaps.json +346 -0
- package/src/language/locale/be.json +15 -2
- package/src/language/locale/bg.json +15 -2
- package/src/language/locale/cs.json +15 -2
- package/src/language/locale/de.json +23 -2
- package/src/language/locale/el.json +15 -2
- package/src/language/locale/en.json +17 -3
- package/src/language/locale/es.json +15 -2
- package/src/language/locale/et.json +5 -1
- package/src/language/locale/fr.json +15 -2
- package/src/language/locale/he.json +16 -3
- package/src/language/locale/hu.json +15 -2
- package/src/language/locale/is.json +5 -1
- package/src/language/locale/it.json +15 -2
- package/src/language/locale/jp.json +15 -2
- package/src/language/locale/ko.json +15 -2
- package/src/language/locale/nl.json +15 -2
- package/src/language/locale/nn.json +5 -1
- package/src/language/locale/no.json +15 -2
- package/src/language/locale/pl.json +15 -2
- package/src/language/locale/pt.json +15 -2
- package/src/language/locale/ru.json +15 -2
- package/src/language/locale/sk.json +15 -2
- package/src/language/locale/sr.json +5 -1
- package/src/language/locale/sv.json +15 -2
- package/src/language/locale/tr.json +15 -2
- package/src/language/locale/uk.json +15 -2
- package/src/language/locale/ur.json +5 -1
- package/src/language/locale/zh-cn.json +15 -2
- package/src/language/locale/zh-tw.json +15 -2
- package/src/main.ts +143 -0
- package/src/map/Map.ts +227 -112
- package/src/map/MapMarker.ts +44 -8
- package/src/map/georeference.ts +325 -0
- package/src/map/openlayers/Map.OpenLayers.ts +1601 -263
- package/src/map/openlayers/MapMarker.OpenLayers.ts +348 -24
- package/src/map/openlayers/zoomifyTiles.ts +1 -4
- package/src/map/slideView.ts +149 -0
- package/src/map/types.ts +2 -0
- package/src/media/EmbedUtil.ts +333 -24
- package/src/media/Media.ts +270 -59
- package/src/media/embedId.ts +110 -0
- package/src/media/types/Audio.ts +9 -82
- package/src/media/types/Blockquote.ts +2 -3
- package/src/media/types/DailyMotion.ts +5 -10
- package/src/media/types/DocumentCloud.ts +6 -35
- package/src/media/types/Facebook.ts +3 -4
- package/src/media/types/Flickr.ts +23 -12
- package/src/media/types/GoogleDoc.ts +3 -4
- package/src/media/types/HtmlMedia.ts +233 -0
- package/src/media/types/IFrame.ts +3 -4
- package/src/media/types/Image.ts +87 -9
- package/src/media/types/Juxtapose.ts +14 -5
- package/src/media/types/SoundCloud.ts +28 -6
- package/src/media/types/Text.ts +46 -21
- package/src/media/types/Twitter.ts +35 -20
- package/src/media/types/Video.ts +9 -79
- package/src/media/types/Vimeo.ts +11 -11
- package/src/media/types/Website.ts +23 -13
- package/src/media/types/Wikipedia.ts +18 -8
- package/src/media/types/YouTube.ts +72 -40
- package/src/scss/Typography.scss +16 -18
- package/src/scss/VCO.StoryMap.scss +208 -12
- package/src/scss/Variables.scss +3 -2
- package/src/scss/core/Mixins.scss +5 -63
- package/src/scss/core/Reset.scss +5 -18
- package/src/scss/fonts/font.amatic-andika.scss +3 -0
- package/src/scss/fonts/font.bitter-raleway.scss +6 -0
- package/src/scss/fonts/font.cairo.scss +79 -0
- package/src/scss/fonts/font.clicker-garamond.scss +5 -0
- package/src/scss/fonts/font.dancing-ledger.scss +1 -0
- package/src/scss/fonts/font.knightlab.scss +14 -0
- package/src/scss/fonts/font.oldstandard.scss +6 -0
- package/src/scss/fonts/font.opensans-gentiumbook.scss +5 -0
- package/src/scss/fonts/font.playfair-faunaone.scss +2 -0
- package/src/scss/fonts/font.playfair.scss +4 -0
- package/src/scss/fonts/font.pt.scss +6 -0
- package/src/scss/fonts/font.ubuntu.scss +4 -0
- package/src/scss/fonts/font.unicaone-vollkorn.scss +5 -0
- package/src/scss/map/VCO.Map.scss +1 -1
- package/src/scss/map/VCO.MapMarker.scss +114 -8
- package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +7 -4
- package/src/scss/media/VCO.Media.scss +14 -17
- package/src/scss/media/types/VCO.Media.Blockquote.scss +1 -1
- package/src/scss/media/types/VCO.Media.Text.scss +13 -5
- package/src/scss/media/types/VCO.Media.Twitter.scss +4 -4
- package/src/scss/media/types/VCO.Media.Wikipedia.scss +3 -19
- package/src/scss/site/site.scss +55 -36
- package/src/scss/slider/VCO.Slide.scss +61 -13
- package/src/scss/slider/VCO.SlideNav.scss +34 -24
- package/src/scss/slider/VCO.StorySlider.scss +53 -1
- package/src/scss/snapmap/VCO.SnapMap.scss +3 -3
- package/src/scss/ui/VCO.Consent.scss +63 -13
- package/src/scss/ui/VCO.Layers.scss +119 -0
- package/src/scss/ui/VCO.MenuBar.Button.scss +143 -14
- package/src/scss/ui/VCO.MenuBar.scss +9 -2
- package/src/scss/ui/VCO.Message.scss +16 -5
- package/src/site/site.ts +2 -1
- package/src/slider/Slide.ts +326 -74
- package/src/slider/SlideNav.ts +54 -9
- package/src/slider/StorySlider.ts +352 -60
- package/src/storymap/Consent.ts +429 -82
- package/src/storymap/StoryMap.ts +2163 -340
- package/src/storymap/content-state.ts +180 -0
- package/src/storymap/font-css.ts +72 -0
- package/src/storymap/from-slideshow.ts +785 -0
- package/src/storymap/iiif-shared.ts +228 -0
- package/src/storymap/iiif.ts +1742 -95
- package/src/storymap/to-iiif.ts +1008 -0
- package/src/storymap/validate.ts +80 -7
- package/src/types.ts +591 -29
- package/src/ui/LayersControl.ts +302 -0
- package/src/ui/MenuBar.ts +325 -61
- package/src/ui/Message.ts +44 -2
- package/src/ui/Swipable.ts +170 -85
- package/dist/assets/demo-D6cTmzn6.js +0 -1
- package/dist/assets/harness-BPFlzutp.js +0 -1
- package/dist/assets/index-DDsPBPZA.js +0 -1
- package/dist/assets/main-Y-MYUSJ4.js +0 -17
- package/src/animation/morpheus.d.ts +0 -41
- package/src/scss/VCO.StoryMap.Dark.scss +0 -138
- package/src/scss/Variables.Dark.scss +0 -56
- package/src/scss/media/types/VCO.Media.Instagram.scss +0 -7
- package/src/scss/media/types/VCO.Media.Profile.scss +0 -5
- package/src/ui/Draggable.ts +0 -374
package/src/media/EmbedUtil.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
in a storymap's JSON can never execute code in a viewer's browser.
|
|
10
10
|
================================================== */
|
|
11
11
|
|
|
12
|
+
import { Language } from "../language/Language";
|
|
13
|
+
|
|
12
14
|
// Attributes copied from a pasted <iframe> onto the rebuilt element.
|
|
13
15
|
// src is handled separately (validated); everything else is dropped.
|
|
14
16
|
const IFRAME_ATTRIBUTES = [
|
|
@@ -21,6 +23,17 @@ const IFRAME_ATTRIBUTES = [
|
|
|
21
23
|
"title",
|
|
22
24
|
];
|
|
23
25
|
|
|
26
|
+
/**
|
|
27
|
+
* `sandbox` value for a rebuilt embed. It is deliberately *not* the most
|
|
28
|
+
* restrictive option: `allow-scripts allow-same-origin` are required by the
|
|
29
|
+
* major video providers to function, and note that the combination is only
|
|
30
|
+
* dangerous when the framed content is same-origin with the viewer, which the
|
|
31
|
+
* http(s)-only src check already rules out for the viewer itself. The value
|
|
32
|
+
* below removes the capabilities that enable clickjacking and top-level
|
|
33
|
+
* navigation.
|
|
34
|
+
*/
|
|
35
|
+
const ALLOWED_IFRAME_SANDBOX = "allow-scripts allow-same-origin allow-presentation allow-popups";
|
|
36
|
+
|
|
24
37
|
// Tags allowed to survive blockquote sanitization. Elements not listed
|
|
25
38
|
// are unwrapped (their children are kept); DROP_TAGS are removed along
|
|
26
39
|
// with their contents.
|
|
@@ -66,6 +79,158 @@ const DROP_TAGS = [
|
|
|
66
79
|
"SELECT",
|
|
67
80
|
];
|
|
68
81
|
|
|
82
|
+
// Drop list for slide text (issue #358): same as DROP_TAGS but IFRAME is
|
|
83
|
+
// rebuilt via buildIframe() instead of dropped, so extra media can be
|
|
84
|
+
// embedded in the text field.
|
|
85
|
+
const SLIDE_TEXT_DROP_TAGS = DROP_TAGS.filter((tag) => tag !== "IFRAME");
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Slide text is an allowlist, not a denylist.
|
|
89
|
+
*
|
|
90
|
+
* The previous denylist ("drop these 18 tags, keep everything else") let
|
|
91
|
+
* through `<audio>`, `<video>`, `<details>`, `<dialog>`, `<marquee>`,
|
|
92
|
+
* `<plaintext>`, `<xmp>` and friends, and copied *every* non-`on*` attribute
|
|
93
|
+
* verbatim. Two consequences worth naming:
|
|
94
|
+
*
|
|
95
|
+
* - `style` was passed through untouched, so a pasted
|
|
96
|
+
* `style="position:fixed;inset:0;z-index:2147483647;background:#fff"`
|
|
97
|
+
* painted a full-widget opaque overlay over the map and the controls:
|
|
98
|
+
* chrome spoofing plus clickjacking, from a single attribute.
|
|
99
|
+
* - `target` was only defaulted when absent, so a pasted `target="_top"`
|
|
100
|
+
* navigated the *host page* out of the viewer.
|
|
101
|
+
*
|
|
102
|
+
* This list covers prose and media embeds. Anything else is unwrapped (its
|
|
103
|
+
* text is kept) rather than dropped with its contents.
|
|
104
|
+
*
|
|
105
|
+
* Note on `style` (trusted authors): inline declarations pass through
|
|
106
|
+
* verbatim — there is no script execution from declarations in modern
|
|
107
|
+
* engines, `url()` tracking is at parity with allowlisted `<img>`, and the
|
|
108
|
+
* slide root is positioned and isolated so nothing escapes the slide box.
|
|
109
|
+
*/
|
|
110
|
+
const SLIDE_TEXT_TAGS = [
|
|
111
|
+
// structure / text
|
|
112
|
+
"P",
|
|
113
|
+
"BR",
|
|
114
|
+
"HR",
|
|
115
|
+
"DIV",
|
|
116
|
+
"SPAN",
|
|
117
|
+
"BLOCKQUOTE",
|
|
118
|
+
"PRE",
|
|
119
|
+
"CODE",
|
|
120
|
+
"KBD",
|
|
121
|
+
"SAMP",
|
|
122
|
+
"VAR",
|
|
123
|
+
// inline formatting
|
|
124
|
+
"EM",
|
|
125
|
+
"STRONG",
|
|
126
|
+
"B",
|
|
127
|
+
"I",
|
|
128
|
+
"U",
|
|
129
|
+
"S",
|
|
130
|
+
"STRIKE",
|
|
131
|
+
"DEL",
|
|
132
|
+
"INS",
|
|
133
|
+
"SMALL",
|
|
134
|
+
"SUB",
|
|
135
|
+
"SUP",
|
|
136
|
+
"MARK",
|
|
137
|
+
"ABBR",
|
|
138
|
+
"CITE",
|
|
139
|
+
"Q",
|
|
140
|
+
"TIME",
|
|
141
|
+
"DFN",
|
|
142
|
+
// lists
|
|
143
|
+
"UL",
|
|
144
|
+
"OL",
|
|
145
|
+
"LI",
|
|
146
|
+
"DL",
|
|
147
|
+
"DT",
|
|
148
|
+
"DD",
|
|
149
|
+
// tables
|
|
150
|
+
"TABLE",
|
|
151
|
+
"THEAD",
|
|
152
|
+
"TBODY",
|
|
153
|
+
"TFOOT",
|
|
154
|
+
"TR",
|
|
155
|
+
"TH",
|
|
156
|
+
"TD",
|
|
157
|
+
"CAPTION",
|
|
158
|
+
"COLGROUP",
|
|
159
|
+
"COL",
|
|
160
|
+
// media (the src/srcset URLs are validated)
|
|
161
|
+
"IMG",
|
|
162
|
+
"FIGURE",
|
|
163
|
+
"FIGCAPTION",
|
|
164
|
+
"PICTURE",
|
|
165
|
+
"SOURCE",
|
|
166
|
+
"AUDIO",
|
|
167
|
+
"VIDEO",
|
|
168
|
+
"TRACK",
|
|
169
|
+
// links
|
|
170
|
+
"A",
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Attributes allowed on slide-text elements. `id`/`name` are deliberately
|
|
175
|
+
* absent: they enable DOM clobbering of host-page globals. `style` passes
|
|
176
|
+
* through verbatim — tour authors are trusted; the slide root is positioned
|
|
177
|
+
* and isolated, so declarations cannot escape it (see VCO.Slide.scss).
|
|
178
|
+
* `class` is kept — the story fixtures and
|
|
179
|
+
* the migrated site content style slides through it, and a class name cannot
|
|
180
|
+
* execute anything.
|
|
181
|
+
*/
|
|
182
|
+
const SLIDE_TEXT_ATTRIBUTES = [
|
|
183
|
+
"class",
|
|
184
|
+
"style",
|
|
185
|
+
"title",
|
|
186
|
+
"lang",
|
|
187
|
+
"dir",
|
|
188
|
+
"alt",
|
|
189
|
+
"width",
|
|
190
|
+
"height",
|
|
191
|
+
"colspan",
|
|
192
|
+
"rowspan",
|
|
193
|
+
"headers",
|
|
194
|
+
"scope",
|
|
195
|
+
"datetime",
|
|
196
|
+
"cite",
|
|
197
|
+
"start",
|
|
198
|
+
"reversed",
|
|
199
|
+
"type",
|
|
200
|
+
"value",
|
|
201
|
+
"controls",
|
|
202
|
+
"loop",
|
|
203
|
+
"muted",
|
|
204
|
+
"playsinline",
|
|
205
|
+
"preload",
|
|
206
|
+
"poster",
|
|
207
|
+
"kind",
|
|
208
|
+
"srclang",
|
|
209
|
+
"label",
|
|
210
|
+
"default",
|
|
211
|
+
"sizes",
|
|
212
|
+
"loading",
|
|
213
|
+
"decoding",
|
|
214
|
+
"open",
|
|
215
|
+
// a source/track is only useful with a machine-readable kind
|
|
216
|
+
"media",
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
/** URL-bearing attributes validated to http(s) in slide text. */
|
|
220
|
+
const URL_ATTRIBUTES = [
|
|
221
|
+
"href",
|
|
222
|
+
"src",
|
|
223
|
+
"srcset",
|
|
224
|
+
"cite",
|
|
225
|
+
"data",
|
|
226
|
+
"poster",
|
|
227
|
+
"action",
|
|
228
|
+
"formaction",
|
|
229
|
+
"longdesc",
|
|
230
|
+
"profile",
|
|
231
|
+
"background",
|
|
232
|
+
];
|
|
233
|
+
|
|
69
234
|
function parseInert(html: string): Document {
|
|
70
235
|
return new DOMParser().parseFromString(html, "text/html");
|
|
71
236
|
}
|
|
@@ -110,11 +275,9 @@ export function buildIframe(html: string): HTMLIFrameElement | null {
|
|
|
110
275
|
iframe.setAttribute("src", src);
|
|
111
276
|
if (pasted) {
|
|
112
277
|
for (let i = 0; i < IFRAME_ATTRIBUTES.length; i++) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
pasted.getAttribute(IFRAME_ATTRIBUTES[i]),
|
|
117
|
-
);
|
|
278
|
+
const value = pasted.getAttribute(IFRAME_ATTRIBUTES[i]);
|
|
279
|
+
if (value !== null) {
|
|
280
|
+
iframe.setAttribute(IFRAME_ATTRIBUTES[i], value);
|
|
118
281
|
}
|
|
119
282
|
}
|
|
120
283
|
} else {
|
|
@@ -123,9 +286,42 @@ export function buildIframe(html: string): HTMLIFrameElement | null {
|
|
|
123
286
|
iframe.setAttribute("frameborder", "0");
|
|
124
287
|
iframe.setAttribute("allowfullscreen", "");
|
|
125
288
|
}
|
|
289
|
+
if (!iframe.hasAttribute("title")) {
|
|
290
|
+
const localeMedia = (Language as unknown as { media?: { iframe_title?: unknown } }).media;
|
|
291
|
+
const localeTitle =
|
|
292
|
+
typeof localeMedia?.iframe_title === "string" && localeMedia.iframe_title !== ""
|
|
293
|
+
? localeMedia.iframe_title
|
|
294
|
+
: undefined;
|
|
295
|
+
const messagesTitle = Language.messages["media.iframe_title"];
|
|
296
|
+
iframe.setAttribute(
|
|
297
|
+
"title",
|
|
298
|
+
localeTitle ??
|
|
299
|
+
(typeof messagesTitle === "string" && messagesTitle !== ""
|
|
300
|
+
? messagesTitle
|
|
301
|
+
: "Embedded media"),
|
|
302
|
+
);
|
|
303
|
+
}
|
|
126
304
|
return iframe;
|
|
127
305
|
}
|
|
128
306
|
|
|
307
|
+
/* Sanitizers
|
|
308
|
+
Two entry points, one walker: both rebuild clean DOM from an allowlist
|
|
309
|
+
so markup stored in a storymap's JSON can never execute code in a
|
|
310
|
+
viewer's browser. They differ only in what they allow.
|
|
311
|
+
================================================== */
|
|
312
|
+
|
|
313
|
+
/** What a sanitizer pass is permitted to keep. */
|
|
314
|
+
interface SanitizeRules {
|
|
315
|
+
/** Tags rebuilt as-is (with the filtered attributes). */
|
|
316
|
+
tags: readonly string[];
|
|
317
|
+
/** Tags removed together with their contents. */
|
|
318
|
+
dropTags: readonly string[];
|
|
319
|
+
/** Attributes copied verbatim (the rest are dropped). */
|
|
320
|
+
attributes: readonly string[];
|
|
321
|
+
/** Rebuild a pasted <iframe> instead of dropping it. */
|
|
322
|
+
rebuildIframes: boolean;
|
|
323
|
+
}
|
|
324
|
+
|
|
129
325
|
/* Sanitize pasted blockquote markup into a DocumentFragment.
|
|
130
326
|
Allowlisted formatting tags are kept (with all attributes stripped,
|
|
131
327
|
except a validated href on links), unknown tags are unwrapped, and
|
|
@@ -133,36 +329,149 @@ export function buildIframe(html: string): HTMLIFrameElement | null {
|
|
|
133
329
|
================================================== */
|
|
134
330
|
export function sanitizeBlockquote(html: string): DocumentFragment {
|
|
135
331
|
const fragment = document.createDocumentFragment();
|
|
136
|
-
appendSanitized(parseInert(html).body, fragment
|
|
332
|
+
appendSanitized(parseInert(html).body, fragment, {
|
|
333
|
+
tags: BLOCKQUOTE_TAGS,
|
|
334
|
+
dropTags: DROP_TAGS,
|
|
335
|
+
attributes: [],
|
|
336
|
+
rebuildIframes: false,
|
|
337
|
+
});
|
|
338
|
+
return fragment;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* Sanitize slide text (issue #358) into a DocumentFragment.
|
|
342
|
+
Allowlisted prose/media tags survive with allowlisted attributes; URL
|
|
343
|
+
attributes are validated to http(s); `style`, `id` and `name` are
|
|
344
|
+
dropped; `target` is always forced to `_blank`; and <iframe> embeds are
|
|
345
|
+
rebuilt via buildIframe() so extra media can live in the text field.
|
|
346
|
+
Anything outside the allowlist is unwrapped (its text is kept) rather
|
|
347
|
+
than dropped with its contents, so a story that used a stray tag still
|
|
348
|
+
reads correctly.
|
|
349
|
+
|
|
350
|
+
This is also the sanitizer for author-supplied *strings* that were
|
|
351
|
+
previously injected raw — media credit, media caption and the slide
|
|
352
|
+
navigation headline. It is the migration path for removed media types
|
|
353
|
+
(e.g. vine): paste the provider's iframe snippet into the slide text.
|
|
354
|
+
|
|
355
|
+
The result must be appended as a live DocumentFragment and never
|
|
356
|
+
re-serialised through innerHTML: the fragment-based build is what makes
|
|
357
|
+
the classic "reparse mXSS" unreachable here.
|
|
358
|
+
================================================== */
|
|
359
|
+
export function sanitizeSlideText(html: string): DocumentFragment {
|
|
360
|
+
const fragment = document.createDocumentFragment();
|
|
361
|
+
appendSanitized(parseInert(html).body, fragment, {
|
|
362
|
+
tags: SLIDE_TEXT_TAGS,
|
|
363
|
+
dropTags: SLIDE_TEXT_DROP_TAGS,
|
|
364
|
+
attributes: SLIDE_TEXT_ATTRIBUTES,
|
|
365
|
+
rebuildIframes: true,
|
|
366
|
+
});
|
|
137
367
|
return fragment;
|
|
138
368
|
}
|
|
139
369
|
|
|
140
|
-
|
|
370
|
+
/** True when `url` may be used as an href/src. */
|
|
371
|
+
function isSafeURL(url: string | null): url is string {
|
|
372
|
+
return validateWebURL(url) !== null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Validate a srcset-style attribute: every candidate URL must be http(s).
|
|
377
|
+
* `srcset` is a comma-separated list of "<url> <descriptor>" pairs, so the
|
|
378
|
+
* whole attribute is dropped unless *every* candidate passes.
|
|
379
|
+
*/
|
|
380
|
+
function sanitizeSrcset(value: string): string | null {
|
|
381
|
+
const candidates = value
|
|
382
|
+
.split(",")
|
|
383
|
+
.map((part) => part.trim())
|
|
384
|
+
.filter(Boolean);
|
|
385
|
+
if (candidates.length === 0) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
const kept: string[] = [];
|
|
389
|
+
for (const candidate of candidates) {
|
|
390
|
+
const url = candidate.split(/\s+/)[0];
|
|
391
|
+
if (!isSafeURL(url)) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
kept.push(candidate);
|
|
395
|
+
}
|
|
396
|
+
return kept.join(", ");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function appendSanitized(node: Node, parent: Node, rules: SanitizeRules): void {
|
|
141
400
|
for (let i = 0; i < node.childNodes.length; i++) {
|
|
142
401
|
const child = node.childNodes[i];
|
|
143
402
|
if (child.nodeType === 3) {
|
|
144
|
-
parent.appendChild(document.createTextNode(child.nodeValue));
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
403
|
+
parent.appendChild(document.createTextNode(child.nodeValue ?? ""));
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (child.nodeType !== 1) {
|
|
407
|
+
// Comments and other node types are dropped
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
const el = child as Element;
|
|
411
|
+
const tag = el.tagName.toUpperCase();
|
|
412
|
+
|
|
413
|
+
if (rules.dropTags.includes(tag)) {
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (tag === "IFRAME" && rules.rebuildIframes) {
|
|
417
|
+
const clean = buildIframe(el.outerHTML);
|
|
418
|
+
if (clean) {
|
|
419
|
+
clean.setAttribute("loading", "lazy");
|
|
420
|
+
// A rebuilt embed still runs with full privileges unless it is
|
|
421
|
+
// sandboxed. This is the allowlist for what third-party embed
|
|
422
|
+
// pages can do; presentation and popups stay enabled because
|
|
423
|
+
// several legacy providers need them to work at all.
|
|
424
|
+
clean.setAttribute("sandbox", ALLOWED_IFRAME_SANDBOX);
|
|
425
|
+
clean.setAttribute("referrerpolicy", "no-referrer");
|
|
426
|
+
parent.appendChild(clean);
|
|
427
|
+
}
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
if (!rules.tags.includes(tag)) {
|
|
431
|
+
// Not on the allowlist: unwrap, keeping its children and text
|
|
432
|
+
appendSanitized(child, parent, rules);
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const cleanEl = document.createElement(tag);
|
|
437
|
+
for (let j = 0; j < el.attributes.length; j++) {
|
|
438
|
+
const attr = el.attributes[j];
|
|
439
|
+
const name = attr.name.toLowerCase();
|
|
440
|
+
// Belt-and-braces: `on*` and `srcdoc` are not on any allowlist,
|
|
441
|
+
// but never let one through if a list is edited carelessly.
|
|
442
|
+
if (name.startsWith("on") || name === "srcdoc") {
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (name === "srcset") {
|
|
446
|
+
const safe = sanitizeSrcset(attr.value);
|
|
447
|
+
if (safe) {
|
|
448
|
+
cleanEl.setAttribute("srcset", safe);
|
|
449
|
+
}
|
|
148
450
|
continue;
|
|
149
451
|
}
|
|
150
|
-
if (
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
if (href) {
|
|
155
|
-
el.setAttribute("href", href);
|
|
156
|
-
el.setAttribute("target", "_blank");
|
|
157
|
-
}
|
|
452
|
+
if (URL_ATTRIBUTES.includes(name)) {
|
|
453
|
+
const safe = validateWebURL(attr.value);
|
|
454
|
+
if (safe) {
|
|
455
|
+
cleanEl.setAttribute(attr.name, safe);
|
|
158
456
|
}
|
|
159
|
-
|
|
160
|
-
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (rules.attributes.includes(name)) {
|
|
460
|
+
cleanEl.setAttribute(attr.name, attr.value);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (tag === "A") {
|
|
464
|
+
// Always overwritten, never inherited from the pasted markup: a
|
|
465
|
+
// `target="_top"` would navigate the host page out of the viewer.
|
|
466
|
+
if (cleanEl.hasAttribute("href")) {
|
|
467
|
+
cleanEl.setAttribute("target", "_blank");
|
|
468
|
+
cleanEl.setAttribute("rel", "noopener noreferrer");
|
|
161
469
|
} else {
|
|
162
|
-
//
|
|
163
|
-
|
|
470
|
+
// a link with no safe href is not a link
|
|
471
|
+
cleanEl.removeAttribute("target");
|
|
164
472
|
}
|
|
165
473
|
}
|
|
166
|
-
|
|
474
|
+
appendSanitized(child, cleanEl, rules);
|
|
475
|
+
parent.appendChild(cleanEl);
|
|
167
476
|
}
|
|
168
477
|
}
|