@projektemacher/storymapjs 0.10.6 → 0.10.8
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 +358 -16
- package/README.md +43 -9
- package/dist/assets/demo-DBpeF31K.js +1 -0
- package/dist/assets/harness-Cr0rYpvt.js +1 -0
- package/dist/assets/harness-multi-CYHgI0a9.js +1 -0
- package/dist/assets/harness-support-Do7sIp2j.js +1 -0
- package/dist/assets/index-wHPqGrBS.js +1 -0
- package/dist/assets/main-DXalctuR.js +17 -0
- package/dist/context.json +12 -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 +101 -21
- 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 +2 -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 +1604 -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/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/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 +197 -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/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/StorymapData.html +71 -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 +105 -0
- package/dist/docs/api/interfaces/StorymapManifestBackground.html +81 -0
- package/dist/docs/api/interfaces/StorymapManifestCanvas.html +140 -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 +532 -0
- package/dist/docs/api/interfaces/StorymapOverlayLayer.html +126 -0
- package/dist/docs/api/interfaces/StorymapSlide.html +132 -0
- package/dist/docs/api/interfaces/StorymapSlideBackground.html +72 -0
- package/dist/docs/api/interfaces/StorymapSlideLocation.html +117 -0
- package/dist/docs/api/interfaces/StorymapSlideMarker.html +104 -0
- package/dist/docs/api/interfaces/StorymapSlideMedia.html +110 -0
- package/dist/docs/api/interfaces/StorymapSlideNarration.html +65 -0
- package/dist/docs/api/interfaces/StorymapSlideText.html +72 -0
- package/dist/docs/api/interfaces/StorymapTilejson.html +105 -0
- package/dist/docs/api/media/es.json +31 -0
- package/dist/docs/api/media/migration-from-knightlab.md +359 -0
- package/dist/docs/api/modules.html +50 -0
- package/dist/docs/api/types/ContentState.html +70 -0
- package/dist/docs/api/types/ImagereadyKind.html +34 -0
- package/dist/docs/api/types/MediaTypeMatch.html +78 -0
- package/dist/docs/api/types/TileSourceFactory.html +53 -0
- package/dist/docs/authoring.html +293 -0
- package/dist/docs/iiif.html +617 -62
- package/dist/docs/migration.html +314 -12
- package/dist/docs/readme.html +40 -9
- package/dist/embed/index.html +130 -5
- 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/map-area-overlays.json +68 -0
- package/dist/examples/no-map.json +44 -0
- package/dist/examples-iiif/annotated-image.json +188 -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/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/map-area-overlays.json +289 -0
- package/dist/examples-iiif/marktwain.json +255 -58
- 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/harness-multi.html +17 -0
- package/dist/harness.html +3 -2
- package/dist/index.html +33 -10
- package/dist/js/storymap.d.ts +1558 -114
- package/dist/js/storymap.js +10113 -6490
- package/dist/js/storymap.js.map +1 -1
- package/dist/navplace-properties.json +40 -0
- package/docs/migration-from-knightlab.md +359 -0
- package/docs/storymap-as-iiif-manifest.md +934 -0
- package/package.json +16 -10
- package/schema/storymap.schema.json +431 -78
- package/src/animation/easings.ts +25 -0
- package/src/animation/tween.ts +186 -0
- package/src/core/Browser.ts +20 -0
- package/src/core/Load.ts +232 -0
- package/src/core/Util.ts +416 -0
- package/src/core/mixins.ts +188 -0
- package/src/core/viewers.ts +94 -0
- package/src/dom/Dom.ts +31 -0
- package/src/dom/DomEvent.ts +80 -0
- package/src/globals.d.ts +24 -0
- package/src/language/Language.ts +281 -0
- package/src/language/locale/.expected-gaps.json +86 -0
- package/src/language/locale/be.json +31 -0
- package/src/language/locale/bg.json +31 -0
- package/src/language/locale/cs.json +31 -0
- package/src/language/locale/de.json +31 -0
- package/src/language/locale/el.json +31 -0
- package/src/language/locale/en.json +32 -0
- package/src/language/locale/es.json +31 -0
- package/src/language/locale/et.json +22 -0
- package/src/language/locale/fr.json +31 -0
- package/src/language/locale/he.json +31 -0
- package/src/language/locale/hu.json +31 -0
- package/src/language/locale/is.json +22 -0
- package/src/language/locale/it.json +31 -0
- package/src/language/locale/jp.json +31 -0
- package/src/language/locale/ko.json +31 -0
- package/src/language/locale/nl.json +31 -0
- package/src/language/locale/nn.json +22 -0
- package/src/language/locale/no.json +31 -0
- package/src/language/locale/pl.json +31 -0
- package/src/language/locale/pt.json +31 -0
- package/src/language/locale/ru.json +31 -0
- package/src/language/locale/sk.json +31 -0
- package/src/language/locale/sr.json +21 -0
- package/src/language/locale/sv.json +31 -0
- package/src/language/locale/tr.json +31 -0
- package/src/language/locale/uk.json +31 -0
- package/src/language/locale/ur.json +22 -0
- package/src/language/locale/zh-cn.json +31 -0
- package/src/language/locale/zh-tw.json +31 -0
- package/src/main.ts +143 -0
- package/src/map/Map.ts +794 -0
- package/src/map/MapMarker.ts +172 -0
- package/src/map/georeference.ts +325 -0
- package/src/map/openlayers/Map.OpenLayers.ts +2492 -0
- package/src/map/openlayers/MapMarker.OpenLayers.ts +400 -0
- package/src/map/openlayers/zoomifyTiles.ts +25 -0
- package/src/map/types.ts +17 -0
- package/src/media/EmbedUtil.ts +452 -0
- package/src/media/Media.ts +597 -0
- package/src/media/MediaType.ts +163 -0
- package/src/media/embedId.ts +104 -0
- package/src/media/types/Audio.ts +14 -0
- package/src/media/types/Blockquote.ts +39 -0
- package/src/media/types/DailyMotion.ts +53 -0
- package/src/media/types/DocumentCloud.ts +12 -0
- package/src/media/types/Facebook.ts +40 -0
- package/src/media/types/Flickr.ts +115 -0
- package/src/media/types/GoogleDoc.ts +58 -0
- package/src/media/types/HtmlMedia.ts +167 -0
- package/src/media/types/IFrame.ts +50 -0
- package/src/media/types/Image.ts +115 -0
- package/src/media/types/Juxtapose.ts +41 -0
- package/src/media/types/SoundCloud.ts +99 -0
- package/src/media/types/Text.ts +178 -0
- package/src/media/types/Twitter.ts +109 -0
- package/src/media/types/Video.ts +14 -0
- package/src/media/types/Vimeo.ts +65 -0
- package/src/media/types/Website.ts +46 -0
- package/src/media/types/Wikipedia.ts +134 -0
- package/src/media/types/YouTube.ts +224 -0
- package/src/scss/Typography.scss +235 -0
- package/src/scss/VCO.StoryMap.Dark.scss +150 -0
- package/src/scss/VCO.StoryMap.scss +195 -0
- package/src/scss/Variables.Dark.scss +57 -0
- package/src/scss/Variables.scss +48 -0
- package/src/scss/core/Mixins.scss +54 -0
- package/src/scss/core/Reset.scss +206 -0
- package/src/scss/fonts/_font.base.scss +113 -0
- package/src/scss/fonts/font.abril-droidsans.scss +75 -0
- package/src/scss/fonts/font.amatic-andika.scss +76 -0
- package/src/scss/fonts/font.bitter-raleway.scss +92 -0
- package/src/scss/fonts/font.cairo.scss +79 -0
- package/src/scss/fonts/font.clicker-garamond.scss +97 -0
- package/src/scss/fonts/font.dancing-ledger.scss +75 -0
- package/src/scss/fonts/font.default.scss +9 -0
- package/src/scss/fonts/font.fjalla-average.scss +80 -0
- package/src/scss/fonts/font.georgia-helvetica.scss +58 -0
- package/src/scss/fonts/font.knightlab.scss +111 -0
- package/src/scss/fonts/font.lustria-lato.scss +80 -0
- package/src/scss/fonts/font.medula-lato.scss +73 -0
- package/src/scss/fonts/font.oldstandard.scss +94 -0
- package/src/scss/fonts/font.opensans-gentiumbook.scss +85 -0
- package/src/scss/fonts/font.playfair-faunaone.scss +88 -0
- package/src/scss/fonts/font.playfair.scss +89 -0
- package/src/scss/fonts/font.pt.scss +96 -0
- package/src/scss/fonts/font.roboto-megrim.scss +73 -0
- package/src/scss/fonts/font.rufina-sintony.scss +73 -0
- package/src/scss/fonts/font.ubuntu.scss +82 -0
- package/src/scss/fonts/font.unicaone-vollkorn.scss +90 -0
- package/src/scss/icons/Icons.scss +239 -0
- package/src/scss/map/VCO.ImageMarker.scss +23 -0
- package/src/scss/map/VCO.Map.scss +21 -0
- package/src/scss/map/VCO.MapMarker.scss +242 -0
- package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +126 -0
- package/src/scss/media/VCO.Media.scss +219 -0
- package/src/scss/media/types/VCO.Media.Blockquote.scss +76 -0
- package/src/scss/media/types/VCO.Media.IFrame.scss +11 -0
- package/src/scss/media/types/VCO.Media.Image.scss +13 -0
- package/src/scss/media/types/VCO.Media.Text.scss +98 -0
- package/src/scss/media/types/VCO.Media.Twitter.scss +87 -0
- package/src/scss/media/types/VCO.Media.Wikipedia.scss +65 -0
- package/src/scss/site/site.scss +748 -0
- package/src/scss/slider/VCO.Slide.scss +457 -0
- package/src/scss/slider/VCO.SlideNav.scss +332 -0
- package/src/scss/slider/VCO.StorySlider.scss +66 -0
- package/src/scss/snapmap/VCO.SnapMap.scss +103 -0
- package/src/scss/ui/VCO.Consent.scss +121 -0
- package/src/scss/ui/VCO.MenuBar.Button.scss +107 -0
- package/src/scss/ui/VCO.MenuBar.scss +20 -0
- package/src/scss/ui/VCO.Message.scss +101 -0
- package/src/site/site.ts +88 -0
- package/src/slider/Slide.ts +554 -0
- package/src/slider/SlideNav.ts +246 -0
- package/src/slider/StorySlider.ts +833 -0
- package/src/storymap/Consent.ts +471 -0
- package/src/storymap/StoryMap.ts +2118 -0
- package/src/storymap/content-state.ts +185 -0
- package/src/storymap/iiif.ts +1844 -0
- package/src/storymap/to-iiif.ts +921 -0
- package/src/storymap/validate.ts +257 -0
- package/src/types.ts +494 -0
- package/src/ui/MenuBar.ts +376 -0
- package/src/ui/Message.ts +127 -0
- package/src/ui/Swipable.ts +455 -0
- package/dist/assets/demo-CVQ7kFek.js +0 -1
- package/dist/assets/harness-C-VZV-ou.js +0 -1
- package/dist/assets/index-DDsPBPZA.js +0 -1
- package/dist/assets/main-DwbXrrYn.js +0 -17
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/* EmbedUtil
|
|
2
|
+
Utilities for safely rendering user-pasted embed snippets.
|
|
3
|
+
|
|
4
|
+
The media "url" field is overloaded: for the iframe and blockquote
|
|
5
|
+
media types it holds raw HTML pasted by the user (that markup is
|
|
6
|
+
what routes the media to those types in MediaType.js). These helpers
|
|
7
|
+
parse that HTML inertly -- DOMParser never executes scripts or event
|
|
8
|
+
handlers -- and rebuild clean DOM from an allowlist, so markup stored
|
|
9
|
+
in a storymap's JSON can never execute code in a viewer's browser.
|
|
10
|
+
================================================== */
|
|
11
|
+
|
|
12
|
+
// Attributes copied from a pasted <iframe> onto the rebuilt element.
|
|
13
|
+
// src is handled separately (validated); everything else is dropped.
|
|
14
|
+
const IFRAME_ATTRIBUTES = [
|
|
15
|
+
"width",
|
|
16
|
+
"height",
|
|
17
|
+
"frameborder",
|
|
18
|
+
"allowfullscreen",
|
|
19
|
+
"allow",
|
|
20
|
+
"scrolling",
|
|
21
|
+
"title",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `sandbox` value for a rebuilt embed. It is deliberately *not* the most
|
|
26
|
+
* restrictive option: `allow-scripts allow-same-origin` are required by the
|
|
27
|
+
* major video providers to function, and note that the combination is only
|
|
28
|
+
* dangerous when the framed content is same-origin with the viewer, which the
|
|
29
|
+
* http(s)-only src check already rules out for the viewer itself. The value
|
|
30
|
+
* below removes the capabilities that enable clickjacking and top-level
|
|
31
|
+
* navigation.
|
|
32
|
+
*/
|
|
33
|
+
const ALLOWED_IFRAME_SANDBOX = "allow-scripts allow-same-origin allow-presentation allow-popups";
|
|
34
|
+
|
|
35
|
+
// Tags allowed to survive blockquote sanitization. Elements not listed
|
|
36
|
+
// are unwrapped (their children are kept); DROP_TAGS are removed along
|
|
37
|
+
// with their contents.
|
|
38
|
+
const BLOCKQUOTE_TAGS = [
|
|
39
|
+
"BLOCKQUOTE",
|
|
40
|
+
"P",
|
|
41
|
+
"CITE",
|
|
42
|
+
"EM",
|
|
43
|
+
"STRONG",
|
|
44
|
+
"B",
|
|
45
|
+
"I",
|
|
46
|
+
"U",
|
|
47
|
+
"Q",
|
|
48
|
+
"A",
|
|
49
|
+
"BR",
|
|
50
|
+
"SPAN",
|
|
51
|
+
"SMALL",
|
|
52
|
+
"SUP",
|
|
53
|
+
"SUB",
|
|
54
|
+
"FOOTER",
|
|
55
|
+
"UL",
|
|
56
|
+
"OL",
|
|
57
|
+
"LI",
|
|
58
|
+
];
|
|
59
|
+
const DROP_TAGS = [
|
|
60
|
+
"SCRIPT",
|
|
61
|
+
"STYLE",
|
|
62
|
+
"TEMPLATE",
|
|
63
|
+
"IFRAME",
|
|
64
|
+
"FRAME",
|
|
65
|
+
"OBJECT",
|
|
66
|
+
"EMBED",
|
|
67
|
+
"APPLET",
|
|
68
|
+
"LINK",
|
|
69
|
+
"META",
|
|
70
|
+
"BASE",
|
|
71
|
+
"SVG",
|
|
72
|
+
"MATH",
|
|
73
|
+
"FORM",
|
|
74
|
+
"INPUT",
|
|
75
|
+
"BUTTON",
|
|
76
|
+
"TEXTAREA",
|
|
77
|
+
"SELECT",
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
// Drop list for slide text (issue #358): same as DROP_TAGS but IFRAME is
|
|
81
|
+
// rebuilt via buildIframe() instead of dropped, so extra media can be
|
|
82
|
+
// embedded in the text field.
|
|
83
|
+
const SLIDE_TEXT_DROP_TAGS = DROP_TAGS.filter((tag) => tag !== "IFRAME");
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Slide text is an allowlist, not a denylist.
|
|
87
|
+
*
|
|
88
|
+
* The previous denylist ("drop these 18 tags, keep everything else") let
|
|
89
|
+
* through `<audio>`, `<video>`, `<details>`, `<dialog>`, `<marquee>`,
|
|
90
|
+
* `<plaintext>`, `<xmp>` and friends, and copied *every* non-`on*` attribute
|
|
91
|
+
* verbatim. Two consequences worth naming:
|
|
92
|
+
*
|
|
93
|
+
* - `style` was passed through untouched, so a pasted
|
|
94
|
+
* `style="position:fixed;inset:0;z-index:2147483647;background:#fff"`
|
|
95
|
+
* painted a full-widget opaque overlay over the map and the controls:
|
|
96
|
+
* chrome spoofing plus clickjacking, from a single attribute.
|
|
97
|
+
* - `target` was only defaulted when absent, so a pasted `target="_top"`
|
|
98
|
+
* navigated the *host page* out of the viewer.
|
|
99
|
+
*
|
|
100
|
+
* This list covers prose and media embeds. Anything else is unwrapped (its
|
|
101
|
+
* text is kept) rather than dropped with its contents.
|
|
102
|
+
*/
|
|
103
|
+
const SLIDE_TEXT_TAGS = [
|
|
104
|
+
// structure / text
|
|
105
|
+
"P",
|
|
106
|
+
"BR",
|
|
107
|
+
"HR",
|
|
108
|
+
"DIV",
|
|
109
|
+
"SPAN",
|
|
110
|
+
"BLOCKQUOTE",
|
|
111
|
+
"PRE",
|
|
112
|
+
"CODE",
|
|
113
|
+
"KBD",
|
|
114
|
+
"SAMP",
|
|
115
|
+
"VAR",
|
|
116
|
+
// inline formatting
|
|
117
|
+
"EM",
|
|
118
|
+
"STRONG",
|
|
119
|
+
"B",
|
|
120
|
+
"I",
|
|
121
|
+
"U",
|
|
122
|
+
"S",
|
|
123
|
+
"STRIKE",
|
|
124
|
+
"DEL",
|
|
125
|
+
"INS",
|
|
126
|
+
"SMALL",
|
|
127
|
+
"SUB",
|
|
128
|
+
"SUP",
|
|
129
|
+
"MARK",
|
|
130
|
+
"ABBR",
|
|
131
|
+
"CITE",
|
|
132
|
+
"Q",
|
|
133
|
+
"TIME",
|
|
134
|
+
"DFN",
|
|
135
|
+
// lists
|
|
136
|
+
"UL",
|
|
137
|
+
"OL",
|
|
138
|
+
"LI",
|
|
139
|
+
"DL",
|
|
140
|
+
"DT",
|
|
141
|
+
"DD",
|
|
142
|
+
// tables
|
|
143
|
+
"TABLE",
|
|
144
|
+
"THEAD",
|
|
145
|
+
"TBODY",
|
|
146
|
+
"TFOOT",
|
|
147
|
+
"TR",
|
|
148
|
+
"TH",
|
|
149
|
+
"TD",
|
|
150
|
+
"CAPTION",
|
|
151
|
+
"COLGROUP",
|
|
152
|
+
"COL",
|
|
153
|
+
// media (the src/srcset URLs are validated)
|
|
154
|
+
"IMG",
|
|
155
|
+
"FIGURE",
|
|
156
|
+
"FIGCAPTION",
|
|
157
|
+
"PICTURE",
|
|
158
|
+
"SOURCE",
|
|
159
|
+
"AUDIO",
|
|
160
|
+
"VIDEO",
|
|
161
|
+
"TRACK",
|
|
162
|
+
// links
|
|
163
|
+
"A",
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Attributes allowed on slide-text elements. `id`/`name` are deliberately
|
|
168
|
+
* absent: they enable DOM clobbering of host-page globals. `style` is
|
|
169
|
+
* deliberately absent (see above). `class` is kept — the story fixtures and
|
|
170
|
+
* the migrated site content style slides through it, and a class name cannot
|
|
171
|
+
* execute anything.
|
|
172
|
+
*/
|
|
173
|
+
const SLIDE_TEXT_ATTRIBUTES = [
|
|
174
|
+
"class",
|
|
175
|
+
"title",
|
|
176
|
+
"lang",
|
|
177
|
+
"dir",
|
|
178
|
+
"alt",
|
|
179
|
+
"width",
|
|
180
|
+
"height",
|
|
181
|
+
"colspan",
|
|
182
|
+
"rowspan",
|
|
183
|
+
"headers",
|
|
184
|
+
"scope",
|
|
185
|
+
"datetime",
|
|
186
|
+
"cite",
|
|
187
|
+
"start",
|
|
188
|
+
"reversed",
|
|
189
|
+
"type",
|
|
190
|
+
"value",
|
|
191
|
+
"controls",
|
|
192
|
+
"loop",
|
|
193
|
+
"muted",
|
|
194
|
+
"playsinline",
|
|
195
|
+
"preload",
|
|
196
|
+
"poster",
|
|
197
|
+
"kind",
|
|
198
|
+
"srclang",
|
|
199
|
+
"label",
|
|
200
|
+
"default",
|
|
201
|
+
"sizes",
|
|
202
|
+
"loading",
|
|
203
|
+
"decoding",
|
|
204
|
+
"open",
|
|
205
|
+
// a source/track is only useful with a machine-readable kind
|
|
206
|
+
"media",
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
/** URL-bearing attributes validated to http(s) in slide text. */
|
|
210
|
+
const URL_ATTRIBUTES = [
|
|
211
|
+
"href",
|
|
212
|
+
"src",
|
|
213
|
+
"srcset",
|
|
214
|
+
"cite",
|
|
215
|
+
"data",
|
|
216
|
+
"poster",
|
|
217
|
+
"action",
|
|
218
|
+
"formaction",
|
|
219
|
+
"longdesc",
|
|
220
|
+
"profile",
|
|
221
|
+
"background",
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
function parseInert(html: string): Document {
|
|
225
|
+
return new DOMParser().parseFromString(html, "text/html");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Return an absolute http(s) URL for url, or null if it is empty,
|
|
229
|
+
unparseable, or uses any other protocol (javascript:, data:, ...).
|
|
230
|
+
Relative and protocol-relative URLs resolve against the document.
|
|
231
|
+
================================================== */
|
|
232
|
+
export function validateWebURL(url: string | null): string | null {
|
|
233
|
+
if (!url) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const a = document.createElement("a");
|
|
237
|
+
a.href = url;
|
|
238
|
+
if (a.protocol === "http:" || a.protocol === "https:") {
|
|
239
|
+
return a.href;
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Build a clean <iframe> element from a pasted embed snippet.
|
|
245
|
+
Only the validated src and allowlisted presentation attributes
|
|
246
|
+
survive; event handlers, extra tags and scripts are discarded.
|
|
247
|
+
Also accepts a bare URL for the src. Returns null if no safe
|
|
248
|
+
src can be extracted.
|
|
249
|
+
================================================== */
|
|
250
|
+
export function buildIframe(html: string): HTMLIFrameElement | null {
|
|
251
|
+
const pasted = parseInert(html).querySelector("iframe");
|
|
252
|
+
let src: string | null = null;
|
|
253
|
+
|
|
254
|
+
if (pasted) {
|
|
255
|
+
src = validateWebURL(pasted.getAttribute("src"));
|
|
256
|
+
} else if (/^https?:\/\/\S+$/i.test(html.trim())) {
|
|
257
|
+
// The field held a bare URL rather than an embed snippet
|
|
258
|
+
src = validateWebURL(html.trim());
|
|
259
|
+
}
|
|
260
|
+
if (!src) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const iframe = document.createElement("iframe");
|
|
265
|
+
iframe.setAttribute("src", src);
|
|
266
|
+
if (pasted) {
|
|
267
|
+
for (let i = 0; i < IFRAME_ATTRIBUTES.length; i++) {
|
|
268
|
+
const value = pasted.getAttribute(IFRAME_ATTRIBUTES[i]);
|
|
269
|
+
if (value !== null) {
|
|
270
|
+
iframe.setAttribute(IFRAME_ATTRIBUTES[i], value);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
iframe.setAttribute("width", "100%");
|
|
275
|
+
iframe.setAttribute("height", "100%");
|
|
276
|
+
iframe.setAttribute("frameborder", "0");
|
|
277
|
+
iframe.setAttribute("allowfullscreen", "");
|
|
278
|
+
}
|
|
279
|
+
return iframe;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Sanitizers
|
|
283
|
+
Two entry points, one walker: both rebuild clean DOM from an allowlist
|
|
284
|
+
so markup stored in a storymap's JSON can never execute code in a
|
|
285
|
+
viewer's browser. They differ only in what they allow.
|
|
286
|
+
================================================== */
|
|
287
|
+
|
|
288
|
+
/** What a sanitizer pass is permitted to keep. */
|
|
289
|
+
interface SanitizeRules {
|
|
290
|
+
/** Tags rebuilt as-is (with the filtered attributes). */
|
|
291
|
+
tags: readonly string[];
|
|
292
|
+
/** Tags removed together with their contents. */
|
|
293
|
+
dropTags: readonly string[];
|
|
294
|
+
/** Attributes copied verbatim (the rest are dropped). */
|
|
295
|
+
attributes: readonly string[];
|
|
296
|
+
/** Rebuild a pasted <iframe> instead of dropping it. */
|
|
297
|
+
rebuildIframes: boolean;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* Sanitize pasted blockquote markup into a DocumentFragment.
|
|
301
|
+
Allowlisted formatting tags are kept (with all attributes stripped,
|
|
302
|
+
except a validated href on links), unknown tags are unwrapped, and
|
|
303
|
+
executable/embedding tags are dropped with their contents.
|
|
304
|
+
================================================== */
|
|
305
|
+
export function sanitizeBlockquote(html: string): DocumentFragment {
|
|
306
|
+
const fragment = document.createDocumentFragment();
|
|
307
|
+
appendSanitized(parseInert(html).body, fragment, {
|
|
308
|
+
tags: BLOCKQUOTE_TAGS,
|
|
309
|
+
dropTags: DROP_TAGS,
|
|
310
|
+
attributes: [],
|
|
311
|
+
rebuildIframes: false,
|
|
312
|
+
});
|
|
313
|
+
return fragment;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* Sanitize slide text (issue #358) into a DocumentFragment.
|
|
317
|
+
Allowlisted prose/media tags survive with allowlisted attributes; URL
|
|
318
|
+
attributes are validated to http(s); `style`, `id` and `name` are
|
|
319
|
+
dropped; `target` is always forced to `_blank`; and <iframe> embeds are
|
|
320
|
+
rebuilt via buildIframe() so extra media can live in the text field.
|
|
321
|
+
Anything outside the allowlist is unwrapped (its text is kept) rather
|
|
322
|
+
than dropped with its contents, so a story that used a stray tag still
|
|
323
|
+
reads correctly.
|
|
324
|
+
|
|
325
|
+
This is also the sanitizer for author-supplied *strings* that were
|
|
326
|
+
previously injected raw — media credit, media caption and the slide
|
|
327
|
+
navigation headline. It is the migration path for removed media types
|
|
328
|
+
(e.g. vine): paste the provider's iframe snippet into the slide text.
|
|
329
|
+
|
|
330
|
+
The result must be appended as a live DocumentFragment and never
|
|
331
|
+
re-serialised through innerHTML: the fragment-based build is what makes
|
|
332
|
+
the classic "reparse mXSS" unreachable here.
|
|
333
|
+
================================================== */
|
|
334
|
+
export function sanitizeSlideText(html: string): DocumentFragment {
|
|
335
|
+
const fragment = document.createDocumentFragment();
|
|
336
|
+
appendSanitized(parseInert(html).body, fragment, {
|
|
337
|
+
tags: SLIDE_TEXT_TAGS,
|
|
338
|
+
dropTags: SLIDE_TEXT_DROP_TAGS,
|
|
339
|
+
attributes: SLIDE_TEXT_ATTRIBUTES,
|
|
340
|
+
rebuildIframes: true,
|
|
341
|
+
});
|
|
342
|
+
return fragment;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** True when `url` may be used as an href/src. */
|
|
346
|
+
function isSafeURL(url: string | null): url is string {
|
|
347
|
+
return validateWebURL(url) !== null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Validate a srcset-style attribute: every candidate URL must be http(s).
|
|
352
|
+
* `srcset` is a comma-separated list of "<url> <descriptor>" pairs, so the
|
|
353
|
+
* whole attribute is dropped unless *every* candidate passes.
|
|
354
|
+
*/
|
|
355
|
+
function sanitizeSrcset(value: string): string | null {
|
|
356
|
+
const candidates = value
|
|
357
|
+
.split(",")
|
|
358
|
+
.map((part) => part.trim())
|
|
359
|
+
.filter(Boolean);
|
|
360
|
+
if (candidates.length === 0) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
const kept: string[] = [];
|
|
364
|
+
for (const candidate of candidates) {
|
|
365
|
+
const url = candidate.split(/\s+/)[0];
|
|
366
|
+
if (!isSafeURL(url)) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
kept.push(candidate);
|
|
370
|
+
}
|
|
371
|
+
return kept.join(", ");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function appendSanitized(node: Node, parent: Node, rules: SanitizeRules): void {
|
|
375
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
376
|
+
const child = node.childNodes[i];
|
|
377
|
+
if (child.nodeType === 3) {
|
|
378
|
+
parent.appendChild(document.createTextNode(child.nodeValue ?? ""));
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (child.nodeType !== 1) {
|
|
382
|
+
// Comments and other node types are dropped
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const el = child as Element;
|
|
386
|
+
const tag = el.tagName.toUpperCase();
|
|
387
|
+
|
|
388
|
+
if (rules.dropTags.includes(tag)) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (tag === "IFRAME" && rules.rebuildIframes) {
|
|
392
|
+
const clean = buildIframe(el.outerHTML);
|
|
393
|
+
if (clean) {
|
|
394
|
+
clean.setAttribute("loading", "lazy");
|
|
395
|
+
// A rebuilt embed still runs with full privileges unless it is
|
|
396
|
+
// sandboxed. This is the allowlist for what third-party embed
|
|
397
|
+
// pages can do; presentation and popups stay enabled because
|
|
398
|
+
// several legacy providers need them to work at all.
|
|
399
|
+
clean.setAttribute("sandbox", ALLOWED_IFRAME_SANDBOX);
|
|
400
|
+
clean.setAttribute("referrerpolicy", "no-referrer");
|
|
401
|
+
parent.appendChild(clean);
|
|
402
|
+
}
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (!rules.tags.includes(tag)) {
|
|
406
|
+
// Not on the allowlist: unwrap, keeping its children and text
|
|
407
|
+
appendSanitized(child, parent, rules);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const cleanEl = document.createElement(tag);
|
|
412
|
+
for (let j = 0; j < el.attributes.length; j++) {
|
|
413
|
+
const attr = el.attributes[j];
|
|
414
|
+
const name = attr.name.toLowerCase();
|
|
415
|
+
// Belt-and-braces: `on*` and `srcdoc` are not on any allowlist,
|
|
416
|
+
// but never let one through if a list is edited carelessly.
|
|
417
|
+
if (name.startsWith("on") || name === "srcdoc") {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (name === "srcset") {
|
|
421
|
+
const safe = sanitizeSrcset(attr.value);
|
|
422
|
+
if (safe) {
|
|
423
|
+
cleanEl.setAttribute("srcset", safe);
|
|
424
|
+
}
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
if (URL_ATTRIBUTES.includes(name)) {
|
|
428
|
+
const safe = validateWebURL(attr.value);
|
|
429
|
+
if (safe) {
|
|
430
|
+
cleanEl.setAttribute(attr.name, safe);
|
|
431
|
+
}
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
if (rules.attributes.includes(name)) {
|
|
435
|
+
cleanEl.setAttribute(attr.name, attr.value);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (tag === "A") {
|
|
439
|
+
// Always overwritten, never inherited from the pasted markup: a
|
|
440
|
+
// `target="_top"` would navigate the host page out of the viewer.
|
|
441
|
+
if (cleanEl.hasAttribute("href")) {
|
|
442
|
+
cleanEl.setAttribute("target", "_blank");
|
|
443
|
+
cleanEl.setAttribute("rel", "noopener noreferrer");
|
|
444
|
+
} else {
|
|
445
|
+
// a link with no safe href is not a link
|
|
446
|
+
cleanEl.removeAttribute("target");
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
appendSanitized(child, cleanEl, rules);
|
|
450
|
+
parent.appendChild(cleanEl);
|
|
451
|
+
}
|
|
452
|
+
}
|