@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.
Files changed (587) hide show
  1. package/CHANGELOG +431 -19
  2. package/README.md +168 -17
  3. package/dist/assets/demo-bWnOyfUw.js +1 -0
  4. package/dist/assets/harness-C3JUv5Ii.js +1 -0
  5. package/dist/assets/harness-multi-XZNex3tb.js +1 -0
  6. package/dist/assets/harness-support-CjfZIVeb.js +1 -0
  7. package/dist/assets/index-wHPqGrBS.js +1 -0
  8. package/dist/assets/main-DQ32hWBM.js +17 -0
  9. package/dist/context.json +23 -9
  10. package/dist/css/fonts/files/amatic-sc-cyrillic-400-normal.woff2 +0 -0
  11. package/dist/css/fonts/files/amatic-sc-cyrillic-700-normal.woff2 +0 -0
  12. package/dist/css/fonts/files/amatic-sc-hebrew-400-normal.woff2 +0 -0
  13. package/dist/css/fonts/files/amatic-sc-hebrew-700-normal.woff2 +0 -0
  14. package/dist/css/fonts/files/amatic-sc-vietnamese-400-normal.woff2 +0 -0
  15. package/dist/css/fonts/files/amatic-sc-vietnamese-700-normal.woff2 +0 -0
  16. package/dist/css/fonts/files/bitter-cyrillic-100-italic.woff2 +0 -0
  17. package/dist/css/fonts/files/bitter-cyrillic-100-normal.woff2 +0 -0
  18. package/dist/css/fonts/files/bitter-cyrillic-200-italic.woff2 +0 -0
  19. package/dist/css/fonts/files/bitter-cyrillic-200-normal.woff2 +0 -0
  20. package/dist/css/fonts/files/bitter-cyrillic-300-italic.woff2 +0 -0
  21. package/dist/css/fonts/files/bitter-cyrillic-300-normal.woff2 +0 -0
  22. package/dist/css/fonts/files/bitter-cyrillic-400-italic.woff2 +0 -0
  23. package/dist/css/fonts/files/bitter-cyrillic-400-normal.woff2 +0 -0
  24. package/dist/css/fonts/files/bitter-cyrillic-500-italic.woff2 +0 -0
  25. package/dist/css/fonts/files/bitter-cyrillic-500-normal.woff2 +0 -0
  26. package/dist/css/fonts/files/bitter-cyrillic-600-italic.woff2 +0 -0
  27. package/dist/css/fonts/files/bitter-cyrillic-600-normal.woff2 +0 -0
  28. package/dist/css/fonts/files/bitter-cyrillic-700-italic.woff2 +0 -0
  29. package/dist/css/fonts/files/bitter-cyrillic-700-normal.woff2 +0 -0
  30. package/dist/css/fonts/files/bitter-cyrillic-800-italic.woff2 +0 -0
  31. package/dist/css/fonts/files/bitter-cyrillic-800-normal.woff2 +0 -0
  32. package/dist/css/fonts/files/bitter-cyrillic-900-italic.woff2 +0 -0
  33. package/dist/css/fonts/files/bitter-cyrillic-900-normal.woff2 +0 -0
  34. package/dist/css/fonts/files/bitter-cyrillic-ext-100-italic.woff2 +0 -0
  35. package/dist/css/fonts/files/bitter-cyrillic-ext-100-normal.woff2 +0 -0
  36. package/dist/css/fonts/files/bitter-cyrillic-ext-200-italic.woff2 +0 -0
  37. package/dist/css/fonts/files/bitter-cyrillic-ext-200-normal.woff2 +0 -0
  38. package/dist/css/fonts/files/bitter-cyrillic-ext-300-italic.woff2 +0 -0
  39. package/dist/css/fonts/files/bitter-cyrillic-ext-300-normal.woff2 +0 -0
  40. package/dist/css/fonts/files/bitter-cyrillic-ext-400-italic.woff2 +0 -0
  41. package/dist/css/fonts/files/bitter-cyrillic-ext-400-normal.woff2 +0 -0
  42. package/dist/css/fonts/files/bitter-cyrillic-ext-500-italic.woff2 +0 -0
  43. package/dist/css/fonts/files/bitter-cyrillic-ext-500-normal.woff2 +0 -0
  44. package/dist/css/fonts/files/bitter-cyrillic-ext-600-italic.woff2 +0 -0
  45. package/dist/css/fonts/files/bitter-cyrillic-ext-600-normal.woff2 +0 -0
  46. package/dist/css/fonts/files/bitter-cyrillic-ext-700-italic.woff2 +0 -0
  47. package/dist/css/fonts/files/bitter-cyrillic-ext-700-normal.woff2 +0 -0
  48. package/dist/css/fonts/files/bitter-cyrillic-ext-800-italic.woff2 +0 -0
  49. package/dist/css/fonts/files/bitter-cyrillic-ext-800-normal.woff2 +0 -0
  50. package/dist/css/fonts/files/bitter-cyrillic-ext-900-italic.woff2 +0 -0
  51. package/dist/css/fonts/files/bitter-cyrillic-ext-900-normal.woff2 +0 -0
  52. package/dist/css/fonts/files/bitter-cyrillic-ext-wght-italic.woff2 +0 -0
  53. package/dist/css/fonts/files/bitter-cyrillic-ext-wght-normal.woff2 +0 -0
  54. package/dist/css/fonts/files/bitter-cyrillic-wght-italic.woff2 +0 -0
  55. package/dist/css/fonts/files/bitter-cyrillic-wght-normal.woff2 +0 -0
  56. package/dist/css/fonts/files/bitter-vietnamese-100-italic.woff2 +0 -0
  57. package/dist/css/fonts/files/bitter-vietnamese-100-normal.woff2 +0 -0
  58. package/dist/css/fonts/files/bitter-vietnamese-200-italic.woff2 +0 -0
  59. package/dist/css/fonts/files/bitter-vietnamese-200-normal.woff2 +0 -0
  60. package/dist/css/fonts/files/bitter-vietnamese-300-italic.woff2 +0 -0
  61. package/dist/css/fonts/files/bitter-vietnamese-300-normal.woff2 +0 -0
  62. package/dist/css/fonts/files/bitter-vietnamese-400-italic.woff2 +0 -0
  63. package/dist/css/fonts/files/bitter-vietnamese-400-normal.woff2 +0 -0
  64. package/dist/css/fonts/files/bitter-vietnamese-500-italic.woff2 +0 -0
  65. package/dist/css/fonts/files/bitter-vietnamese-500-normal.woff2 +0 -0
  66. package/dist/css/fonts/files/bitter-vietnamese-600-italic.woff2 +0 -0
  67. package/dist/css/fonts/files/bitter-vietnamese-600-normal.woff2 +0 -0
  68. package/dist/css/fonts/files/bitter-vietnamese-700-italic.woff2 +0 -0
  69. package/dist/css/fonts/files/bitter-vietnamese-700-normal.woff2 +0 -0
  70. package/dist/css/fonts/files/bitter-vietnamese-800-italic.woff2 +0 -0
  71. package/dist/css/fonts/files/bitter-vietnamese-800-normal.woff2 +0 -0
  72. package/dist/css/fonts/files/bitter-vietnamese-900-italic.woff2 +0 -0
  73. package/dist/css/fonts/files/bitter-vietnamese-900-normal.woff2 +0 -0
  74. package/dist/css/fonts/files/bitter-vietnamese-wght-italic.woff2 +0 -0
  75. package/dist/css/fonts/files/bitter-vietnamese-wght-normal.woff2 +0 -0
  76. package/dist/css/fonts/files/cairo-arabic-200-normal.woff2 +0 -0
  77. package/dist/css/fonts/files/cairo-arabic-300-normal.woff2 +0 -0
  78. package/dist/css/fonts/files/cairo-arabic-400-normal.woff2 +0 -0
  79. package/dist/css/fonts/files/cairo-arabic-500-normal.woff2 +0 -0
  80. package/dist/css/fonts/files/cairo-arabic-600-normal.woff2 +0 -0
  81. package/dist/css/fonts/files/cairo-arabic-700-normal.woff2 +0 -0
  82. package/dist/css/fonts/files/cairo-arabic-800-normal.woff2 +0 -0
  83. package/dist/css/fonts/files/cairo-arabic-900-normal.woff2 +0 -0
  84. package/dist/css/fonts/files/cairo-latin-200-normal.woff2 +0 -0
  85. package/dist/css/fonts/files/cairo-latin-300-normal.woff2 +0 -0
  86. package/dist/css/fonts/files/cairo-latin-400-normal.woff2 +0 -0
  87. package/dist/css/fonts/files/cairo-latin-500-normal.woff2 +0 -0
  88. package/dist/css/fonts/files/cairo-latin-600-normal.woff2 +0 -0
  89. package/dist/css/fonts/files/cairo-latin-700-normal.woff2 +0 -0
  90. package/dist/css/fonts/files/cairo-latin-800-normal.woff2 +0 -0
  91. package/dist/css/fonts/files/cairo-latin-900-normal.woff2 +0 -0
  92. package/dist/css/fonts/files/cairo-latin-ext-200-normal.woff2 +0 -0
  93. package/dist/css/fonts/files/cairo-latin-ext-300-normal.woff2 +0 -0
  94. package/dist/css/fonts/files/cairo-latin-ext-400-normal.woff2 +0 -0
  95. package/dist/css/fonts/files/cairo-latin-ext-500-normal.woff2 +0 -0
  96. package/dist/css/fonts/files/cairo-latin-ext-600-normal.woff2 +0 -0
  97. package/dist/css/fonts/files/cairo-latin-ext-700-normal.woff2 +0 -0
  98. package/dist/css/fonts/files/cairo-latin-ext-800-normal.woff2 +0 -0
  99. package/dist/css/fonts/files/cairo-latin-ext-900-normal.woff2 +0 -0
  100. package/dist/css/fonts/files/dancing-script-vietnamese-wght-normal.woff2 +0 -0
  101. package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-italic.woff2 +0 -0
  102. package/dist/css/fonts/files/eb-garamond-cyrillic-ext-wght-normal.woff2 +0 -0
  103. package/dist/css/fonts/files/eb-garamond-cyrillic-wght-italic.woff2 +0 -0
  104. package/dist/css/fonts/files/eb-garamond-cyrillic-wght-normal.woff2 +0 -0
  105. package/dist/css/fonts/files/eb-garamond-greek-ext-wght-italic.woff2 +0 -0
  106. package/dist/css/fonts/files/eb-garamond-greek-ext-wght-normal.woff2 +0 -0
  107. package/dist/css/fonts/files/eb-garamond-greek-wght-italic.woff2 +0 -0
  108. package/dist/css/fonts/files/eb-garamond-greek-wght-normal.woff2 +0 -0
  109. package/dist/css/fonts/files/eb-garamond-vietnamese-wght-italic.woff2 +0 -0
  110. package/dist/css/fonts/files/eb-garamond-vietnamese-wght-normal.woff2 +0 -0
  111. package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-italic.woff2 +0 -0
  112. package/dist/css/fonts/files/gentium-book-plus-cyrillic-400-normal.woff2 +0 -0
  113. package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-italic.woff2 +0 -0
  114. package/dist/css/fonts/files/gentium-book-plus-cyrillic-700-normal.woff2 +0 -0
  115. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-italic.woff2 +0 -0
  116. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-400-normal.woff2 +0 -0
  117. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-italic.woff2 +0 -0
  118. package/dist/css/fonts/files/gentium-book-plus-cyrillic-ext-700-normal.woff2 +0 -0
  119. package/dist/css/fonts/files/gentium-book-plus-greek-400-italic.woff2 +0 -0
  120. package/dist/css/fonts/files/gentium-book-plus-greek-400-normal.woff2 +0 -0
  121. package/dist/css/fonts/files/gentium-book-plus-greek-700-italic.woff2 +0 -0
  122. package/dist/css/fonts/files/gentium-book-plus-greek-700-normal.woff2 +0 -0
  123. package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-italic.woff2 +0 -0
  124. package/dist/css/fonts/files/gentium-book-plus-greek-ext-400-normal.woff2 +0 -0
  125. package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-italic.woff2 +0 -0
  126. package/dist/css/fonts/files/gentium-book-plus-greek-ext-700-normal.woff2 +0 -0
  127. package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-italic.woff2 +0 -0
  128. package/dist/css/fonts/files/gentium-book-plus-vietnamese-400-normal.woff2 +0 -0
  129. package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-italic.woff2 +0 -0
  130. package/dist/css/fonts/files/gentium-book-plus-vietnamese-700-normal.woff2 +0 -0
  131. package/dist/css/fonts/files/old-standard-tt-cyrillic-400-italic.woff2 +0 -0
  132. package/dist/css/fonts/files/old-standard-tt-cyrillic-400-normal.woff2 +0 -0
  133. package/dist/css/fonts/files/old-standard-tt-cyrillic-700-normal.woff2 +0 -0
  134. package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-italic.woff2 +0 -0
  135. package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-400-normal.woff2 +0 -0
  136. package/dist/css/fonts/files/old-standard-tt-cyrillic-ext-700-normal.woff2 +0 -0
  137. package/dist/css/fonts/files/old-standard-tt-vietnamese-400-italic.woff2 +0 -0
  138. package/dist/css/fonts/files/old-standard-tt-vietnamese-400-normal.woff2 +0 -0
  139. package/dist/css/fonts/files/old-standard-tt-vietnamese-700-normal.woff2 +0 -0
  140. package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-italic.woff2 +0 -0
  141. package/dist/css/fonts/files/open-sans-cyrillic-ext-wght-normal.woff2 +0 -0
  142. package/dist/css/fonts/files/open-sans-cyrillic-wght-italic.woff2 +0 -0
  143. package/dist/css/fonts/files/open-sans-cyrillic-wght-normal.woff2 +0 -0
  144. package/dist/css/fonts/files/open-sans-greek-ext-wght-italic.woff2 +0 -0
  145. package/dist/css/fonts/files/open-sans-greek-ext-wght-normal.woff2 +0 -0
  146. package/dist/css/fonts/files/open-sans-greek-wght-italic.woff2 +0 -0
  147. package/dist/css/fonts/files/open-sans-greek-wght-normal.woff2 +0 -0
  148. package/dist/css/fonts/files/open-sans-hebrew-wght-italic.woff2 +0 -0
  149. package/dist/css/fonts/files/open-sans-hebrew-wght-normal.woff2 +0 -0
  150. package/dist/css/fonts/files/open-sans-vietnamese-wght-italic.woff2 +0 -0
  151. package/dist/css/fonts/files/open-sans-vietnamese-wght-normal.woff2 +0 -0
  152. package/dist/css/fonts/files/playfair-display-cyrillic-wght-italic.woff2 +0 -0
  153. package/dist/css/fonts/files/playfair-display-cyrillic-wght-normal.woff2 +0 -0
  154. package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-italic.woff2 +0 -0
  155. package/dist/css/fonts/files/playfair-display-sc-cyrillic-400-normal.woff2 +0 -0
  156. package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-italic.woff2 +0 -0
  157. package/dist/css/fonts/files/playfair-display-sc-cyrillic-700-normal.woff2 +0 -0
  158. package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-italic.woff2 +0 -0
  159. package/dist/css/fonts/files/playfair-display-sc-cyrillic-900-normal.woff2 +0 -0
  160. package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-italic.woff2 +0 -0
  161. package/dist/css/fonts/files/playfair-display-sc-vietnamese-400-normal.woff2 +0 -0
  162. package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-italic.woff2 +0 -0
  163. package/dist/css/fonts/files/playfair-display-sc-vietnamese-700-normal.woff2 +0 -0
  164. package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-italic.woff2 +0 -0
  165. package/dist/css/fonts/files/playfair-display-sc-vietnamese-900-normal.woff2 +0 -0
  166. package/dist/css/fonts/files/playfair-display-vietnamese-wght-italic.woff2 +0 -0
  167. package/dist/css/fonts/files/playfair-display-vietnamese-wght-normal.woff2 +0 -0
  168. package/dist/css/fonts/files/pt-sans-cyrillic-400-italic.woff2 +0 -0
  169. package/dist/css/fonts/files/pt-sans-cyrillic-400-normal.woff2 +0 -0
  170. package/dist/css/fonts/files/pt-sans-cyrillic-700-italic.woff2 +0 -0
  171. package/dist/css/fonts/files/pt-sans-cyrillic-700-normal.woff2 +0 -0
  172. package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-italic.woff2 +0 -0
  173. package/dist/css/fonts/files/pt-sans-cyrillic-ext-400-normal.woff2 +0 -0
  174. package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-italic.woff2 +0 -0
  175. package/dist/css/fonts/files/pt-sans-cyrillic-ext-700-normal.woff2 +0 -0
  176. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-400-normal.woff2 +0 -0
  177. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-700-normal.woff2 +0 -0
  178. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-400-normal.woff2 +0 -0
  179. package/dist/css/fonts/files/pt-sans-narrow-cyrillic-ext-700-normal.woff2 +0 -0
  180. package/dist/css/fonts/files/pt-serif-cyrillic-400-italic.woff2 +0 -0
  181. package/dist/css/fonts/files/pt-serif-cyrillic-400-normal.woff2 +0 -0
  182. package/dist/css/fonts/files/pt-serif-cyrillic-700-italic.woff2 +0 -0
  183. package/dist/css/fonts/files/pt-serif-cyrillic-700-normal.woff2 +0 -0
  184. package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-italic.woff2 +0 -0
  185. package/dist/css/fonts/files/pt-serif-cyrillic-ext-400-normal.woff2 +0 -0
  186. package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-italic.woff2 +0 -0
  187. package/dist/css/fonts/files/pt-serif-cyrillic-ext-700-normal.woff2 +0 -0
  188. package/dist/css/fonts/files/raleway-cyrillic-ext-wght-italic.woff2 +0 -0
  189. package/dist/css/fonts/files/raleway-cyrillic-ext-wght-normal.woff2 +0 -0
  190. package/dist/css/fonts/files/raleway-cyrillic-wght-italic.woff2 +0 -0
  191. package/dist/css/fonts/files/raleway-cyrillic-wght-normal.woff2 +0 -0
  192. package/dist/css/fonts/files/raleway-vietnamese-wght-italic.woff2 +0 -0
  193. package/dist/css/fonts/files/raleway-vietnamese-wght-normal.woff2 +0 -0
  194. package/dist/css/fonts/files/roboto-slab-cyrillic-ext-wght-normal.woff2 +0 -0
  195. package/dist/css/fonts/files/roboto-slab-cyrillic-wght-normal.woff2 +0 -0
  196. package/dist/css/fonts/files/roboto-slab-greek-ext-wght-normal.woff2 +0 -0
  197. package/dist/css/fonts/files/roboto-slab-greek-wght-normal.woff2 +0 -0
  198. package/dist/css/fonts/files/roboto-slab-vietnamese-wght-normal.woff2 +0 -0
  199. package/dist/css/fonts/files/ubuntu-cyrillic-300-italic.woff2 +0 -0
  200. package/dist/css/fonts/files/ubuntu-cyrillic-300-normal.woff2 +0 -0
  201. package/dist/css/fonts/files/ubuntu-cyrillic-400-italic.woff2 +0 -0
  202. package/dist/css/fonts/files/ubuntu-cyrillic-400-normal.woff2 +0 -0
  203. package/dist/css/fonts/files/ubuntu-cyrillic-500-italic.woff2 +0 -0
  204. package/dist/css/fonts/files/ubuntu-cyrillic-500-normal.woff2 +0 -0
  205. package/dist/css/fonts/files/ubuntu-cyrillic-700-italic.woff2 +0 -0
  206. package/dist/css/fonts/files/ubuntu-cyrillic-700-normal.woff2 +0 -0
  207. package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-italic.woff2 +0 -0
  208. package/dist/css/fonts/files/ubuntu-cyrillic-ext-300-normal.woff2 +0 -0
  209. package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-italic.woff2 +0 -0
  210. package/dist/css/fonts/files/ubuntu-cyrillic-ext-400-normal.woff2 +0 -0
  211. package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-italic.woff2 +0 -0
  212. package/dist/css/fonts/files/ubuntu-cyrillic-ext-500-normal.woff2 +0 -0
  213. package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-italic.woff2 +0 -0
  214. package/dist/css/fonts/files/ubuntu-cyrillic-ext-700-normal.woff2 +0 -0
  215. package/dist/css/fonts/files/ubuntu-greek-300-italic.woff2 +0 -0
  216. package/dist/css/fonts/files/ubuntu-greek-300-normal.woff2 +0 -0
  217. package/dist/css/fonts/files/ubuntu-greek-400-italic.woff2 +0 -0
  218. package/dist/css/fonts/files/ubuntu-greek-400-normal.woff2 +0 -0
  219. package/dist/css/fonts/files/ubuntu-greek-500-italic.woff2 +0 -0
  220. package/dist/css/fonts/files/ubuntu-greek-500-normal.woff2 +0 -0
  221. package/dist/css/fonts/files/ubuntu-greek-700-italic.woff2 +0 -0
  222. package/dist/css/fonts/files/ubuntu-greek-700-normal.woff2 +0 -0
  223. package/dist/css/fonts/files/ubuntu-greek-ext-300-italic.woff2 +0 -0
  224. package/dist/css/fonts/files/ubuntu-greek-ext-300-normal.woff2 +0 -0
  225. package/dist/css/fonts/files/ubuntu-greek-ext-400-italic.woff2 +0 -0
  226. package/dist/css/fonts/files/ubuntu-greek-ext-400-normal.woff2 +0 -0
  227. package/dist/css/fonts/files/ubuntu-greek-ext-500-italic.woff2 +0 -0
  228. package/dist/css/fonts/files/ubuntu-greek-ext-500-normal.woff2 +0 -0
  229. package/dist/css/fonts/files/ubuntu-greek-ext-700-italic.woff2 +0 -0
  230. package/dist/css/fonts/files/ubuntu-greek-ext-700-normal.woff2 +0 -0
  231. package/dist/css/fonts/files/unica-one-vietnamese-400-normal.woff2 +0 -0
  232. package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-italic.woff2 +0 -0
  233. package/dist/css/fonts/files/vollkorn-cyrillic-ext-wght-normal.woff2 +0 -0
  234. package/dist/css/fonts/files/vollkorn-cyrillic-wght-italic.woff2 +0 -0
  235. package/dist/css/fonts/files/vollkorn-cyrillic-wght-normal.woff2 +0 -0
  236. package/dist/css/fonts/files/vollkorn-greek-wght-italic.woff2 +0 -0
  237. package/dist/css/fonts/files/vollkorn-greek-wght-normal.woff2 +0 -0
  238. package/dist/css/fonts/files/vollkorn-vietnamese-wght-italic.woff2 +0 -0
  239. package/dist/css/fonts/files/vollkorn-vietnamese-wght-normal.woff2 +0 -0
  240. package/dist/css/fonts/font.abril-droidsans.css +3 -0
  241. package/dist/css/fonts/font.amatic-andika.css +57 -0
  242. package/dist/css/fonts/font.bitter-raleway.css +111 -0
  243. package/dist/css/fonts/font.cairo.css +312 -0
  244. package/dist/css/fonts/font.clicker-garamond.css +93 -0
  245. package/dist/css/fonts/font.dancing-ledger.css +12 -0
  246. package/dist/css/fonts/font.default.css +183 -0
  247. package/dist/css/fonts/font.fjalla-average.css +3 -0
  248. package/dist/css/fonts/font.georgia-helvetica.css +3 -0
  249. package/dist/css/fonts/font.knightlab.css +642 -0
  250. package/dist/css/fonts/font.lustria-lato.css +3 -0
  251. package/dist/css/fonts/font.medula-lato.css +3 -0
  252. package/dist/css/fonts/font.oldstandard.css +84 -0
  253. package/dist/css/fonts/font.opensans-gentiumbook.css +183 -0
  254. package/dist/css/fonts/font.playfair-faunaone.css +39 -0
  255. package/dist/css/fonts/font.playfair.css +147 -0
  256. package/dist/css/fonts/font.pt.css +183 -0
  257. package/dist/css/fonts/font.roboto-megrim.css +3 -0
  258. package/dist/css/fonts/font.rufina-sintony.css +3 -0
  259. package/dist/css/fonts/font.ubuntu.css +291 -0
  260. package/dist/css/fonts/font.unicaone-vollkorn.css +84 -0
  261. package/dist/css/storymap.css +1 -1
  262. package/dist/demo.html +3 -2
  263. package/dist/docs/api/.nojekyll +1 -0
  264. package/dist/docs/api/assets/custom.css +47 -0
  265. package/dist/docs/api/assets/hierarchy.js +1 -0
  266. package/dist/docs/api/assets/highlight.css +57 -0
  267. package/dist/docs/api/assets/icons.js +18 -0
  268. package/dist/docs/api/assets/icons.svg +1 -0
  269. package/dist/docs/api/assets/main.js +60 -0
  270. package/dist/docs/api/assets/navigation.js +1 -0
  271. package/dist/docs/api/assets/search.js +1 -0
  272. package/dist/docs/api/assets/style.css +1648 -0
  273. package/dist/docs/api/classes/StoryMap.html +2112 -0
  274. package/dist/docs/api/functions/MediaType.html +51 -0
  275. package/dist/docs/api/functions/isPresentation3Collection.html +47 -0
  276. package/dist/docs/api/functions/isPresentation3Manifest.html +53 -0
  277. package/dist/docs/api/functions/isSlideshowCollection.html +51 -0
  278. package/dist/docs/api/functions/loadCSS.html +63 -0
  279. package/dist/docs/api/functions/manifestToStorymapData.html +49 -0
  280. package/dist/docs/api/functions/setLanguage.html +54 -0
  281. package/dist/docs/api/functions/slideshowToStorymapData.html +51 -0
  282. package/dist/docs/api/functions/slideshowVersion.html +48 -0
  283. package/dist/docs/api/functions/storymapToManifest.html +57 -0
  284. package/dist/docs/api/functions/validateStorymap.html +53 -0
  285. package/dist/docs/api/functions/validateStorymapAndReport.html +54 -0
  286. package/dist/docs/api/hierarchy.html +28 -0
  287. package/dist/docs/api/index.html +300 -0
  288. package/dist/docs/api/interfaces/AnimationHandle.html +60 -0
  289. package/dist/docs/api/interfaces/ImagereadyPayload.html +71 -0
  290. package/dist/docs/api/interfaces/LanguageEntry.html +102 -0
  291. package/dist/docs/api/interfaces/LatLngLiteral.html +73 -0
  292. package/dist/docs/api/interfaces/LoadOptions.html +59 -0
  293. package/dist/docs/api/interfaces/MapEvents.html +116 -0
  294. package/dist/docs/api/interfaces/MapMarkerEvents.html +66 -0
  295. package/dist/docs/api/interfaces/MarkerEventPayload.html +57 -0
  296. package/dist/docs/api/interfaces/MediaEvents.html +78 -0
  297. package/dist/docs/api/interfaces/MenuBarEvents.html +114 -0
  298. package/dist/docs/api/interfaces/MessageEvents.html +72 -0
  299. package/dist/docs/api/interfaces/OlLayer.html +1400 -0
  300. package/dist/docs/api/interfaces/OlMap.html +1656 -0
  301. package/dist/docs/api/interfaces/OlProjection.html +332 -0
  302. package/dist/docs/api/interfaces/OlSource.html +784 -0
  303. package/dist/docs/api/interfaces/OlTileLayer.html +1497 -0
  304. package/dist/docs/api/interfaces/OlVectorLayer.html +1559 -0
  305. package/dist/docs/api/interfaces/OlView.html +1958 -0
  306. package/dist/docs/api/interfaces/SlideBackgroundState.html +66 -0
  307. package/dist/docs/api/interfaces/SlideEvents.html +78 -0
  308. package/dist/docs/api/interfaces/SlideNavEvents.html +72 -0
  309. package/dist/docs/api/interfaces/SlideshowPlayerSettings.html +182 -0
  310. package/dist/docs/api/interfaces/SlideshowToStorymapResult.html +60 -0
  311. package/dist/docs/api/interfaces/SlideshowTranslatorOptions.html +65 -0
  312. package/dist/docs/api/interfaces/SlideshowWarning.html +72 -0
  313. package/dist/docs/api/interfaces/StoryMapEvents.html +146 -0
  314. package/dist/docs/api/interfaces/StoryMapMarker.html +763 -0
  315. package/dist/docs/api/interfaces/StorySliderEvents.html +102 -0
  316. package/dist/docs/api/interfaces/StorymapBasemap.html +69 -0
  317. package/dist/docs/api/interfaces/StorymapData.html +77 -0
  318. package/dist/docs/api/interfaces/StorymapDataWrapper.html +60 -0
  319. package/dist/docs/api/interfaces/StorymapDocument.html +68 -0
  320. package/dist/docs/api/interfaces/StorymapError.html +63 -0
  321. package/dist/docs/api/interfaces/StorymapGeoreference.html +93 -0
  322. package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +74 -0
  323. package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +69 -0
  324. package/dist/docs/api/interfaces/StorymapLanguageMap.html +57 -0
  325. package/dist/docs/api/interfaces/StorymapManifest.html +118 -0
  326. package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +137 -0
  327. package/dist/docs/api/interfaces/StorymapManifestBackground.html +81 -0
  328. package/dist/docs/api/interfaces/StorymapManifestCanvas.html +188 -0
  329. package/dist/docs/api/interfaces/StorymapManifestContentResource.html +97 -0
  330. package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +82 -0
  331. package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +87 -0
  332. package/dist/docs/api/interfaces/StorymapManifestImageService.html +69 -0
  333. package/dist/docs/api/interfaces/StorymapManifestRange.html +75 -0
  334. package/dist/docs/api/interfaces/StorymapManifestService.html +77 -0
  335. package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +69 -0
  336. package/dist/docs/api/interfaces/StorymapManifestStatement.html +63 -0
  337. package/dist/docs/api/interfaces/StorymapMapOptions.html +92 -0
  338. package/dist/docs/api/interfaces/StorymapOptions.html +734 -0
  339. package/dist/docs/api/interfaces/StorymapOverlayLayer.html +157 -0
  340. package/dist/docs/api/interfaces/StorymapSlide.html +186 -0
  341. package/dist/docs/api/interfaces/StorymapSlideBackground.html +72 -0
  342. package/dist/docs/api/interfaces/StorymapSlideLocation.html +161 -0
  343. package/dist/docs/api/interfaces/StorymapSlideMarker.html +103 -0
  344. package/dist/docs/api/interfaces/StorymapSlideMedia.html +149 -0
  345. package/dist/docs/api/interfaces/StorymapSlideNarration.html +117 -0
  346. package/dist/docs/api/interfaces/StorymapSlideText.html +72 -0
  347. package/dist/docs/api/interfaces/StorymapTilejson.html +105 -0
  348. package/dist/docs/api/interfaces/SwipableEvents.html +102 -0
  349. package/dist/docs/api/interfaces/TextEvents.html +66 -0
  350. package/dist/docs/api/media/es.json +31 -0
  351. package/dist/docs/api/media/events.md +66 -0
  352. package/dist/docs/api/media/migration-from-knightlab.md +399 -0
  353. package/dist/docs/api/media/slideshow.md +109 -0
  354. package/dist/docs/api/media/storymap-as-iiif-manifest.md +1007 -0
  355. package/dist/docs/api/modules.html +50 -0
  356. package/dist/docs/api/types/ContentState.html +70 -0
  357. package/dist/docs/api/types/FiredEvent.html +43 -0
  358. package/dist/docs/api/types/ImagereadyKind.html +34 -0
  359. package/dist/docs/api/types/MediaTypeMatch.html +78 -0
  360. package/dist/docs/api/types/SwipeDirection.html +36 -0
  361. package/dist/docs/api/types/TileSourceFactory.html +53 -0
  362. package/dist/docs/authoring.html +306 -0
  363. package/dist/docs/events.html +263 -0
  364. package/dist/docs/iiif.html +738 -69
  365. package/dist/docs/migration.html +360 -11
  366. package/dist/docs/readme.html +149 -17
  367. package/dist/embed/index.html +8 -1
  368. package/dist/examples/font-css-false.json +33 -0
  369. package/dist/examples/issue-242-nonlatin.json +55 -0
  370. package/dist/examples/issue-305-start-at-slide-data.json +96 -0
  371. package/dist/examples/issue-358-iframe.json +57 -0
  372. package/dist/examples/issue-iiif-geo.json +32 -0
  373. package/dist/examples/issue-image-alt.json +23 -0
  374. package/dist/examples/issue-image-region.json +42 -0
  375. package/dist/examples/issue-image-srcset.json +24 -0
  376. package/dist/examples/layers-control.json +60 -0
  377. package/dist/examples/map-area-overlays.json +68 -0
  378. package/dist/examples/map-template-provider.json +36 -0
  379. package/dist/examples/multi-media.json +71 -0
  380. package/dist/examples/no-map.json +44 -0
  381. package/dist/examples-iiif/annotated-image.json +204 -0
  382. package/dist/examples-iiif/bob-boilen.json +11 -5
  383. package/dist/examples-iiif/courbet.json +9 -6
  384. package/dist/examples-iiif/empty.json +8 -4
  385. package/dist/examples-iiif/flickr-drewvigal.json +248 -24
  386. package/dist/examples-iiif/flickr-zach.wise.json +8 -4
  387. package/dist/examples-iiif/font-css-false.json +114 -0
  388. package/dist/examples-iiif/georeferenced-layer-unsupported.json +153 -0
  389. package/dist/examples-iiif/georeferenced-layer.json +318 -0
  390. package/dist/examples-iiif/iiif-wellcome.json +9 -6
  391. package/dist/examples-iiif/instagram-chenpamela.json +381 -36
  392. package/dist/examples-iiif/instagram_brentfoster.json +429 -40
  393. package/dist/examples-iiif/instagram_couch.json +261 -26
  394. package/dist/examples-iiif/instagram_joegermuska.json +441 -41
  395. package/dist/examples-iiif/instagram_matteich.json +261 -26
  396. package/dist/examples-iiif/instagram_mirandamulligan.json +261 -26
  397. package/dist/examples-iiif/instagram_raymondmccrea.json +261 -26
  398. package/dist/examples-iiif/instagram_test.json +261 -26
  399. package/dist/examples-iiif/issue-134-no-lines.json +9 -5
  400. package/dist/examples-iiif/issue-177-color-vars.json +9 -5
  401. package/dist/examples-iiif/issue-211-rtl.json +9 -5
  402. package/dist/examples-iiif/issue-242-nonlatin.json +239 -0
  403. package/dist/examples-iiif/issue-272-facebook.json +9 -5
  404. package/dist/examples-iiif/issue-305-start-at-slide-data.json +305 -0
  405. package/dist/examples-iiif/issue-305-start-at-slide.json +9 -5
  406. package/dist/examples-iiif/issue-341-distance.json +9 -5
  407. package/dist/examples-iiif/issue-358-iframe.json +190 -0
  408. package/dist/examples-iiif/issue-360-juxtapose.json +22 -7
  409. package/dist/examples-iiif/issue-368-null-fields.json +9 -5
  410. package/dist/examples-iiif/issue-375-code-lists.json +9 -5
  411. package/dist/examples-iiif/issue-381-dateline.json +9 -5
  412. package/dist/examples-iiif/issue-405-custom-icon.json +203 -0
  413. package/dist/examples-iiif/issue-425-many-slides.json +9 -5
  414. package/dist/examples-iiif/issue-428-background.json +20 -8
  415. package/dist/examples-iiif/issue-435-googlemaps.json +9 -5
  416. package/dist/examples-iiif/issue-437-documentcloud.json +22 -7
  417. package/dist/examples-iiif/issue-451-webp.json +9 -5
  418. package/dist/examples-iiif/issue-455-audio.json +9 -5
  419. package/dist/examples-iiif/issue-480-shorts.json +9 -5
  420. package/dist/examples-iiif/issue-506-marker-sync.json +9 -5
  421. package/dist/examples-iiif/issue-iiif-geo.json +200 -0
  422. package/dist/examples-iiif/issue-image-alt.json +90 -0
  423. package/dist/examples-iiif/issue-image-region.json +203 -0
  424. package/dist/examples-iiif/issue-image-srcset.json +87 -0
  425. package/dist/examples-iiif/jansteen.json +9 -6
  426. package/dist/examples-iiif/katrina.json +197 -41
  427. package/dist/examples-iiif/layers-control.json +226 -0
  428. package/dist/examples-iiif/map-area-overlays.json +289 -0
  429. package/dist/examples-iiif/map-template-provider.json +133 -0
  430. package/dist/examples-iiif/marktwain.json +255 -58
  431. package/dist/examples-iiif/multi-media.json +237 -0
  432. package/dist/examples-iiif/no-map.json +148 -0
  433. package/dist/examples-iiif/population.json +440 -76
  434. package/dist/examples-iiif/president.json +456 -83
  435. package/dist/examples-iiif/scroll-hint.json +190 -0
  436. package/dist/examples-iiif/seurat.json +113 -22
  437. package/dist/examples-iiif/zoomify-clamp.json +153 -0
  438. package/dist/examples-slideshow/single.json +79 -0
  439. package/dist/examples-slideshow/static/pixel.png +0 -0
  440. package/dist/examples-slideshow/static.json +44 -0
  441. package/dist/harness-multi.html +17 -0
  442. package/dist/harness.html +4 -2
  443. package/dist/index.html +19 -12
  444. package/dist/js/storymap.d.ts +2669 -307
  445. package/dist/js/storymap.js +10820 -6196
  446. package/dist/js/storymap.js.map +1 -1
  447. package/dist/navplace-properties.json +54 -0
  448. package/dist/site.css +54 -36
  449. package/docs/migration-from-knightlab.md +279 -19
  450. package/docs/storymap-as-iiif-manifest.md +633 -136
  451. package/package.json +12 -7
  452. package/schema/storymap.schema.json +733 -80
  453. package/src/animation/easings.ts +8 -1
  454. package/src/animation/tween.ts +186 -0
  455. package/src/core/Browser.ts +6 -5
  456. package/src/core/Load.ts +54 -2
  457. package/src/core/Util.ts +257 -193
  458. package/src/core/mixins.ts +66 -35
  459. package/src/core/viewers.ts +94 -0
  460. package/src/dom/DomEvent.ts +27 -8
  461. package/src/globals.d.ts +8 -0
  462. package/src/language/Language.ts +206 -25
  463. package/src/language/locale/.expected-gaps.json +346 -0
  464. package/src/language/locale/be.json +15 -2
  465. package/src/language/locale/bg.json +15 -2
  466. package/src/language/locale/cs.json +15 -2
  467. package/src/language/locale/de.json +23 -2
  468. package/src/language/locale/el.json +15 -2
  469. package/src/language/locale/en.json +17 -3
  470. package/src/language/locale/es.json +15 -2
  471. package/src/language/locale/et.json +5 -1
  472. package/src/language/locale/fr.json +15 -2
  473. package/src/language/locale/he.json +16 -3
  474. package/src/language/locale/hu.json +15 -2
  475. package/src/language/locale/is.json +5 -1
  476. package/src/language/locale/it.json +15 -2
  477. package/src/language/locale/jp.json +15 -2
  478. package/src/language/locale/ko.json +15 -2
  479. package/src/language/locale/nl.json +15 -2
  480. package/src/language/locale/nn.json +5 -1
  481. package/src/language/locale/no.json +15 -2
  482. package/src/language/locale/pl.json +15 -2
  483. package/src/language/locale/pt.json +15 -2
  484. package/src/language/locale/ru.json +15 -2
  485. package/src/language/locale/sk.json +15 -2
  486. package/src/language/locale/sr.json +5 -1
  487. package/src/language/locale/sv.json +15 -2
  488. package/src/language/locale/tr.json +15 -2
  489. package/src/language/locale/uk.json +15 -2
  490. package/src/language/locale/ur.json +5 -1
  491. package/src/language/locale/zh-cn.json +15 -2
  492. package/src/language/locale/zh-tw.json +15 -2
  493. package/src/main.ts +143 -0
  494. package/src/map/Map.ts +227 -112
  495. package/src/map/MapMarker.ts +44 -8
  496. package/src/map/georeference.ts +325 -0
  497. package/src/map/openlayers/Map.OpenLayers.ts +1601 -263
  498. package/src/map/openlayers/MapMarker.OpenLayers.ts +348 -24
  499. package/src/map/openlayers/zoomifyTiles.ts +1 -4
  500. package/src/map/slideView.ts +149 -0
  501. package/src/map/types.ts +2 -0
  502. package/src/media/EmbedUtil.ts +333 -24
  503. package/src/media/Media.ts +270 -59
  504. package/src/media/embedId.ts +110 -0
  505. package/src/media/types/Audio.ts +9 -82
  506. package/src/media/types/Blockquote.ts +2 -3
  507. package/src/media/types/DailyMotion.ts +5 -10
  508. package/src/media/types/DocumentCloud.ts +6 -35
  509. package/src/media/types/Facebook.ts +3 -4
  510. package/src/media/types/Flickr.ts +23 -12
  511. package/src/media/types/GoogleDoc.ts +3 -4
  512. package/src/media/types/HtmlMedia.ts +233 -0
  513. package/src/media/types/IFrame.ts +3 -4
  514. package/src/media/types/Image.ts +87 -9
  515. package/src/media/types/Juxtapose.ts +14 -5
  516. package/src/media/types/SoundCloud.ts +28 -6
  517. package/src/media/types/Text.ts +46 -21
  518. package/src/media/types/Twitter.ts +35 -20
  519. package/src/media/types/Video.ts +9 -79
  520. package/src/media/types/Vimeo.ts +11 -11
  521. package/src/media/types/Website.ts +23 -13
  522. package/src/media/types/Wikipedia.ts +18 -8
  523. package/src/media/types/YouTube.ts +72 -40
  524. package/src/scss/Typography.scss +16 -18
  525. package/src/scss/VCO.StoryMap.scss +208 -12
  526. package/src/scss/Variables.scss +3 -2
  527. package/src/scss/core/Mixins.scss +5 -63
  528. package/src/scss/core/Reset.scss +5 -18
  529. package/src/scss/fonts/font.amatic-andika.scss +3 -0
  530. package/src/scss/fonts/font.bitter-raleway.scss +6 -0
  531. package/src/scss/fonts/font.cairo.scss +79 -0
  532. package/src/scss/fonts/font.clicker-garamond.scss +5 -0
  533. package/src/scss/fonts/font.dancing-ledger.scss +1 -0
  534. package/src/scss/fonts/font.knightlab.scss +14 -0
  535. package/src/scss/fonts/font.oldstandard.scss +6 -0
  536. package/src/scss/fonts/font.opensans-gentiumbook.scss +5 -0
  537. package/src/scss/fonts/font.playfair-faunaone.scss +2 -0
  538. package/src/scss/fonts/font.playfair.scss +4 -0
  539. package/src/scss/fonts/font.pt.scss +6 -0
  540. package/src/scss/fonts/font.ubuntu.scss +4 -0
  541. package/src/scss/fonts/font.unicaone-vollkorn.scss +5 -0
  542. package/src/scss/map/VCO.Map.scss +1 -1
  543. package/src/scss/map/VCO.MapMarker.scss +114 -8
  544. package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +7 -4
  545. package/src/scss/media/VCO.Media.scss +14 -17
  546. package/src/scss/media/types/VCO.Media.Blockquote.scss +1 -1
  547. package/src/scss/media/types/VCO.Media.Text.scss +13 -5
  548. package/src/scss/media/types/VCO.Media.Twitter.scss +4 -4
  549. package/src/scss/media/types/VCO.Media.Wikipedia.scss +3 -19
  550. package/src/scss/site/site.scss +55 -36
  551. package/src/scss/slider/VCO.Slide.scss +61 -13
  552. package/src/scss/slider/VCO.SlideNav.scss +34 -24
  553. package/src/scss/slider/VCO.StorySlider.scss +53 -1
  554. package/src/scss/snapmap/VCO.SnapMap.scss +3 -3
  555. package/src/scss/ui/VCO.Consent.scss +63 -13
  556. package/src/scss/ui/VCO.Layers.scss +119 -0
  557. package/src/scss/ui/VCO.MenuBar.Button.scss +143 -14
  558. package/src/scss/ui/VCO.MenuBar.scss +9 -2
  559. package/src/scss/ui/VCO.Message.scss +16 -5
  560. package/src/site/site.ts +2 -1
  561. package/src/slider/Slide.ts +326 -74
  562. package/src/slider/SlideNav.ts +54 -9
  563. package/src/slider/StorySlider.ts +352 -60
  564. package/src/storymap/Consent.ts +429 -82
  565. package/src/storymap/StoryMap.ts +2163 -340
  566. package/src/storymap/content-state.ts +180 -0
  567. package/src/storymap/font-css.ts +72 -0
  568. package/src/storymap/from-slideshow.ts +785 -0
  569. package/src/storymap/iiif-shared.ts +228 -0
  570. package/src/storymap/iiif.ts +1742 -95
  571. package/src/storymap/to-iiif.ts +1008 -0
  572. package/src/storymap/validate.ts +80 -7
  573. package/src/types.ts +591 -29
  574. package/src/ui/LayersControl.ts +302 -0
  575. package/src/ui/MenuBar.ts +325 -61
  576. package/src/ui/Message.ts +44 -2
  577. package/src/ui/Swipable.ts +170 -85
  578. package/dist/assets/demo-D6cTmzn6.js +0 -1
  579. package/dist/assets/harness-BPFlzutp.js +0 -1
  580. package/dist/assets/index-DDsPBPZA.js +0 -1
  581. package/dist/assets/main-Y-MYUSJ4.js +0 -17
  582. package/src/animation/morpheus.d.ts +0 -41
  583. package/src/scss/VCO.StoryMap.Dark.scss +0 -138
  584. package/src/scss/Variables.Dark.scss +0 -56
  585. package/src/scss/media/types/VCO.Media.Instagram.scss +0 -7
  586. package/src/scss/media/types/VCO.Media.Profile.scss +0 -5
  587. package/src/ui/Draggable.ts +0 -374
@@ -1,16 +1,65 @@
1
- import { mergeData } from "../core/Util";
1
+ import { mergeData, ratio, clearTimer } from "../core/Util";
2
2
  import { Evented, type EventedInstance } from "../core/mixins";
3
3
  import Dom from "../dom/Dom";
4
4
  import Message from "../ui/Message";
5
5
  import { Browser } from "../core/Browser";
6
6
  import { MediaState, StorymapSlideMedia } from "../types";
7
- import { consentManagerOf, consentMessage } from "../storymap/Consent";
7
+ import { Language } from "../language/Language";
8
+ import { consentManagerOf, consentMessage, mediaService } from "../storymap/Consent";
9
+ import { validateWebURL, sanitizeSlideText } from "./EmbedUtil";
8
10
  import { loadJS } from "../core/Load";
9
11
  /* VCO.Media
10
12
  Main media template for media assets.
11
13
  Takes a data object and populates a dom object
12
14
  ================================================== */
13
15
 
16
+ /**
17
+ * The icon glyph each media type shows in its error state.
18
+ *
19
+ * The icon font does not carry a glyph for every registered type, and the
20
+ * class used to be built straight from `media_type`, so dailymotion, audio,
21
+ * googledocs, iframe, documentcloud, juxtapose and website rendered an empty
22
+ * box next to the error text. The mapping is explicit rather than derived, so
23
+ * a type added later falls back to a real glyph instead of a blank one —
24
+ * `tests/embed-util-media.test.ts` checks the whole table against the font.
25
+ */
26
+ const LOAD_ERROR_ICONS: Record<string, string> = {
27
+ youtube: "youtube",
28
+ vimeo: "vimeo",
29
+ dailymotion: "video",
30
+ soundcloud: "soundcloud",
31
+ twitter: "twitter",
32
+ flickr: "flickr",
33
+ image: "image",
34
+ video: "video",
35
+ audio: "music",
36
+ googledocs: "doc",
37
+ wikipedia: "wikipedia",
38
+ iframe: "web",
39
+ facebook: "facebook",
40
+ documentcloud: "doc",
41
+ juxtapose: "image",
42
+ blockquote: "blockquote",
43
+ website: "web",
44
+ };
45
+
46
+ const GENERIC_LOAD_ERROR_ICON = "web";
47
+
48
+ export function loadErrorIcon(media_type: unknown): string {
49
+ const type = typeof media_type === "string" ? media_type : "";
50
+ return LOAD_ERROR_ICONS[type] ?? GENERIC_LOAD_ERROR_ICON;
51
+ }
52
+
53
+ /**
54
+ * Whether media captions/credits render: `show_info: false` hides them, but
55
+ * only for slideshow tours (`slideshow_source`) — internal documents always
56
+ * show their captions. Pure for testability.
57
+ */
58
+ export function shouldShowInfo(options: MediaOptions): boolean {
59
+ if (options.slideshow_source !== true) return true;
60
+ return options.show_info !== false;
61
+ }
62
+
14
63
  /* Options for Media and its subclasses: the fields Media itself sets
15
64
  or reads. Everything else merged in via mergeData is absorbed by the
16
65
  index signature. */
@@ -29,29 +78,57 @@ export interface MediaOptions {
29
78
  /* Data for media assets: the shared exchange format plus the link
30
79
  fields the base layout renders. */
31
80
  export interface MediaData extends StorymapSlideMedia {
32
- uniqueid?: string;
33
- link?: string;
34
- link_target?: string;
81
+ uniqueid?: string | null;
82
+ link?: string | null;
83
+ link_target?: string | null;
35
84
  [key: string]: unknown;
36
85
  }
37
86
 
87
+ export interface MediaEvents {
88
+ loaded: MediaData;
89
+ media_loaded: MediaData;
90
+ media_ended: MediaData;
91
+ added: MediaData;
92
+ removed: MediaData;
93
+ }
94
+
95
+ /**
96
+ * The media element cache.
97
+ *
98
+ * `content_item`, `content_link`, `caption` and `credit` are only created
99
+ * once `_loadMedia()` / `showMeta()` have run, so they start out null rather
100
+ * than as an empty element — that is what the "did the load happen?" check is
101
+ * for, and pretending otherwise with `{} as HTMLElement` is what let the
102
+ * consent-denied path dereference `undefined.style`.
103
+ */
104
+ type MediaElements = {
105
+ container: HTMLElement;
106
+ content_container: HTMLElement;
107
+ content: HTMLElement;
108
+ content_item: HTMLElement | null;
109
+ content_link: HTMLElement | null;
110
+ source_item: HTMLSourceElement | null;
111
+ caption: HTMLElement | null;
112
+ credit: HTMLElement | null;
113
+ parent: HTMLElement;
114
+ link: HTMLElement | null;
115
+ };
116
+
38
117
  export class MediaBase {
39
- declare "_el": Record<string, HTMLElement>;
118
+ declare "_el": MediaElements;
40
119
  declare "player": unknown;
41
- declare "timer": ReturnType<typeof setTimeout>;
42
- declare "load_timer": ReturnType<typeof setTimeout>;
120
+ declare "timer": ReturnType<typeof setTimeout> | null;
121
+ declare "load_timer": ReturnType<typeof setTimeout> | null;
43
122
  declare "load_controller": AbortController | null;
44
- declare "message": Message;
123
+ declare "message": Message | null;
45
124
  declare "media_id": unknown;
46
125
  declare "_state": MediaState;
126
+ declare "_disposed": boolean;
47
127
  declare "data": MediaData;
48
128
  declare "options": MediaOptions;
49
129
  declare "animator": unknown;
50
130
  declare "_media": unknown;
51
- declare "_": (key: string) => string;
52
- declare "fire": EventedInstance["fire"];
53
-
54
- //_el: {},
131
+ declare "fire": EventedInstance<MediaEvents>["fire"];
55
132
 
56
133
  /* Constructor
57
134
  ================================================== */
@@ -61,8 +138,9 @@ export class MediaBase {
61
138
  container: {} as HTMLElement,
62
139
  content_container: {} as HTMLElement,
63
140
  content: {} as HTMLElement,
64
- content_item: {} as HTMLElement,
65
- content_link: {} as HTMLElement,
141
+ content_item: null,
142
+ content_link: null,
143
+ source_item: null,
66
144
  caption: null,
67
145
  credit: null,
68
146
  parent: {} as HTMLElement,
@@ -89,6 +167,7 @@ export class MediaBase {
89
167
  show_meta: false,
90
168
  media_loaded: false,
91
169
  };
170
+ this._disposed = false;
92
171
 
93
172
  // Data
94
173
  this.data = {
@@ -132,8 +211,14 @@ export class MediaBase {
132
211
  const manager = consentManagerOf(this.options);
133
212
  if (this.options.consent_required && manager && this.options.media_type) {
134
213
  // GDPR consent mode: ask before loading anything from this
135
- // external service
136
- const service = this.options.media_type as string;
214
+ // external service. media_type is the stable identity (the
215
+ // MediaType slug) and media_name is the display name — using
216
+ // the slug as the label made this panel ask "Load content from
217
+ // youtube?" where the start-of-story dialog said "YouTube".
218
+ const service = mediaService(
219
+ this.options.media_type,
220
+ (this.options.media_name as string | undefined) ?? "",
221
+ );
137
222
  let host = "";
138
223
  try {
139
224
  host = new URL((this.data as { url?: string })?.url ?? "").host;
@@ -163,8 +248,7 @@ export class MediaBase {
163
248
  this._state.loaded = true;
164
249
  this._updateDisplay();
165
250
  } catch (e) {
166
- console.log("Error loading media for ", this._media);
167
- console.log(e);
251
+ console.warn("StoryMapJS: error loading media.", e);
168
252
  this.loadErrorDisplay("Error loading media.");
169
253
  }
170
254
  }, 1200);
@@ -175,49 +259,65 @@ export class MediaBase {
175
259
  const target = (this._el.content_container ?? this._el.container) as HTMLElement;
176
260
  const blocked = document.createElement("div");
177
261
  blocked.className = "vco-consent-blocked";
262
+ // the display name, not the slug — see loadMedia()
263
+ const service_name =
264
+ (this.options.media_name as string | undefined) ||
265
+ (this.options.media_type as string | undefined) ||
266
+ "";
178
267
  blocked.textContent = (
179
268
  consentMessage("consent_blocked", "Content from {service} is blocked.") as string
180
- ).replace("{service}", (this.options.media_type as string) ?? "");
269
+ ).replace("{service}", service_name);
181
270
  target.append(blocked);
182
271
  this.onLoaded(true);
183
272
  }
184
273
 
185
- loadingMessage() {
186
- this.message.updateMessage(this._("loading") + " " + this.options.media_name);
274
+ /**
275
+ * Look up a UI string for the active language, falling back to the
276
+ * English default (which `setLanguage` already merges in) and finally to
277
+ * the key itself, so a missing translation degrades to something visible
278
+ * rather than "undefined".
279
+ */
280
+ _(key: string): string {
281
+ return Language.messages[key] ?? key;
282
+ }
283
+
284
+ /** Show the loading overlay for this media item. */
285
+ loadingMessage(): void {
286
+ this.message?.updateMessage(this._("loading") + " " + this.options.media_name);
187
287
  }
188
288
 
189
289
  updateMediaDisplay(layout?: string) {
190
- if (this._state.loaded) {
191
- this._updateMediaDisplay(layout);
290
+ // `content_item` only exists once a media type's `_loadMedia()` has
291
+ // run. It stays null when a consent decision blocked the load, so the
292
+ // sizing below has to be skipped rather than dereference a
293
+ // placeholder — that was the crash on the denied path.
294
+ const content_item = this._el.content_item;
295
+ if (!this._state.loaded || !content_item) {
296
+ return;
297
+ }
192
298
 
193
- if (!Browser.mobile && layout !== "portrait") {
194
- this._el.content_item.style.maxHeight = this.options.height / 2 + "px";
195
- }
299
+ this._updateMediaDisplay(layout);
196
300
 
197
- if (this._state.media_loaded) {
198
- if (this._el.credit) {
199
- this._el.credit.style.width = "auto";
200
- }
201
- if (this._el.caption) {
202
- this._el.caption.style.width = "auto";
203
- }
204
- }
301
+ if (!Browser.mobile && layout !== "portrait") {
302
+ content_item.style.maxHeight = Number(this.options.height ?? 0) / 2 + "px";
303
+ }
205
304
 
206
- if (layout === "portrait") {
207
- this._el.content_item.style.maxHeight = "none";
305
+ if (layout === "portrait") {
306
+ content_item.style.maxHeight = "none";
307
+ }
308
+ if (this._state.media_loaded) {
309
+ const width = content_item.offsetWidth + "px";
310
+ if (this._el.credit) {
311
+ this._el.credit.style.width = width;
208
312
  }
209
- if (this._state.media_loaded) {
210
- if (this._el.credit) {
211
- this._el.credit.style.width = this._el.content_item.offsetWidth + "px";
212
- }
213
- if (this._el.caption) {
214
- this._el.caption.style.width = this._el.content_item.offsetWidth + "px";
215
- }
313
+ if (this._el.caption) {
314
+ this._el.caption.style.width = width;
216
315
  }
217
316
  }
218
317
  }
219
318
 
220
- /* Media Specific
319
+ /**
320
+ * Media Specific
221
321
  ================================================== */
222
322
  _loadMedia() {}
223
323
 
@@ -225,6 +325,24 @@ export class MediaBase {
225
325
  //this._el.content_item.style.maxHeight = (this.options.height - this.options.credit_height - this.options.caption_height - 16) + "px";
226
326
  }
227
327
 
328
+ /** Size the media box to the `height` option, in pixels. */
329
+ _sizeContentItemToOptionHeight(): void {
330
+ if (this._el.content_item) {
331
+ this._el.content_item.style.height = Number(this.options.height ?? 0) + "px";
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Size the media box to a 16:9 box matching its current width — the
337
+ * aspect ratio every video provider embeds at.
338
+ */
339
+ _sizeContentItemTo16x9(): void {
340
+ const item = this._el.content_item;
341
+ if (item) {
342
+ item.style.height = ratio.r16_9({ w: item.offsetWidth }) + "px";
343
+ }
344
+ }
345
+
228
346
  /* Public
229
347
  ================================================== */
230
348
  show() {}
@@ -241,6 +359,45 @@ export class MediaBase {
241
359
  this.onRemove();
242
360
  }
243
361
 
362
+ /**
363
+ * Terminal teardown: cancel pending work, stop playback, release the
364
+ * media-specific player and drop the DOM. Called by `Slide.dispose()`;
365
+ * the media must not be used afterwards.
366
+ */
367
+ dispose() {
368
+ if (this._disposed) {
369
+ return;
370
+ }
371
+ this._disposed = true;
372
+
373
+ // a load queued by loadMedia() that never started
374
+ if (this.load_timer) {
375
+ clearTimer(this.load_timer);
376
+ this.load_timer = null;
377
+ }
378
+ if (this.timer) {
379
+ clearTimer(this.timer);
380
+ this.timer = null;
381
+ }
382
+ // an external script still in flight (YouTube, Vimeo, Twitter, ...)
383
+ this.load_controller?.abort();
384
+ this.load_controller = null;
385
+
386
+ // let the concrete type tear down its player before the DOM goes away
387
+ this._disposeMedia();
388
+
389
+ this._el.container?.getAnimations?.().forEach((a) => a.cancel());
390
+ this.message?.dispose?.();
391
+ this.message = null;
392
+ this._el.container?.remove();
393
+ }
394
+
395
+ /**
396
+ * Media-specific teardown. Overridden by types that own a player, an
397
+ * embedded document or a listening widget.
398
+ */
399
+ _disposeMedia() {}
400
+
244
401
  // Update Display
245
402
  updateDisplay(w?: number, h?: number, l?: string) {
246
403
  this._updateDisplay(w, h, l);
@@ -251,7 +408,8 @@ export class MediaBase {
251
408
  // load delay): avoids building iframes and injecting scripts for a
252
409
  // slide the visitor already skipped past
253
410
  if (!this._state.loaded && this.load_timer) {
254
- clearTimeout(this.load_timer);
411
+ clearTimer(this.load_timer);
412
+ this.load_timer = null;
255
413
  this.load_timer = null;
256
414
  }
257
415
  // Abort an in-flight external script load, if any
@@ -288,8 +446,21 @@ export class MediaBase {
288
446
  "vco-media-item vco-media-loaderror",
289
447
  this._el.content,
290
448
  );
291
- this._el.content_item.innerHTML =
292
- "<div class='vco-icon-" + this.options.media_type + "'></div><p>" + message + "</p>";
449
+ // The icon font has no glyph for every media type (dailymotion, audio,
450
+ // googledocs, iframe, documentcloud, juxtapose and website had none),
451
+ // and the class was built by string concatenation, so those error
452
+ // states rendered an empty box. Map the missing ones to a glyph that
453
+ // exists, and fall back to a generic "web" icon for anything added
454
+ // later.
455
+ this._el.content_item.appendChild(
456
+ Dom.create("div", `vco-icon-${loadErrorIcon(this.options.media_type)}`),
457
+ );
458
+ const text = Dom.create("p", "");
459
+ text.appendChild(document.createTextNode(message));
460
+ this._el.content_item.appendChild(text);
461
+ // announced, not just shown: load failures otherwise pass silently
462
+ // for screen-reader visitors
463
+ this._el.content_item.setAttribute("role", "alert");
293
464
 
294
465
  // After Loaded
295
466
  this.onLoaded(true);
@@ -312,27 +483,38 @@ export class MediaBase {
312
483
  onMediaLoaded(e?: unknown) {
313
484
  this._state.media_loaded = true;
314
485
  this.fire("media_loaded", this.data);
486
+ const width = (this._el.content_item?.offsetWidth ?? 0) + "px";
315
487
  if (this._el.credit) {
316
- this._el.credit.style.width = this._el.content_item.offsetWidth + "px";
488
+ this._el.credit.style.width = width;
317
489
  }
318
490
  if (this._el.caption) {
319
- this._el.caption.style.width = this._el.content_item.offsetWidth + "px";
491
+ this._el.caption.style.width = width;
320
492
  }
321
493
  }
322
494
 
323
- showMeta(credit?: unknown, caption?: unknown) {
495
+ /** Render the media credit and caption, if the slide has them. */
496
+ showMeta(): void {
497
+ // slideshow tours may hide the info block (show_info: false);
498
+ // internal documents always render it
499
+ if (!shouldShowInfo(this.options)) return;
324
500
  this._state.show_meta = true;
325
- // Credit
326
- if (this.data.credit && this.data.credit !== "" && !this._el.credit) {
501
+ // Credit and caption are author-supplied strings that may legitimately
502
+ // contain formatting (they are documented as HTML), so they go through
503
+ // the same sanitizer as the slide text rather than straight to
504
+ // innerHTML — the JSON is untrusted input, and these were the two
505
+ // easiest stored-XSS sinks in the viewer.
506
+ const credit = this._credit();
507
+ if (credit && credit !== "" && !this._el.credit) {
327
508
  this._el.credit = Dom.create("div", "vco-credit", this._el.content_container);
328
- this._el.credit.innerHTML = this.data.credit;
509
+ this._el.credit.appendChild(sanitizeSlideText(credit));
329
510
  this.options.credit_height = this._el.credit.offsetHeight;
330
511
  }
331
512
 
332
513
  // Caption
333
- if (this.data.caption && this.data.caption !== "" && !this._el.caption) {
514
+ const caption = this._caption();
515
+ if (caption && caption !== "" && !this._el.caption) {
334
516
  this._el.caption = Dom.create("div", "vco-caption", this._el.content_container);
335
- this._el.caption.innerHTML = this.data.caption;
517
+ this._el.caption.appendChild(sanitizeSlideText(caption));
336
518
  this.options.caption_height = this._el.caption.offsetHeight;
337
519
  }
338
520
  }
@@ -347,6 +529,21 @@ export class MediaBase {
347
529
 
348
530
  /* Private Methods
349
531
  ================================================== */
532
+ /** The media URL, normalised to a string. */
533
+ _url(): string {
534
+ return typeof this.data.url === "string" ? this.data.url : "";
535
+ }
536
+
537
+ /** The media caption, or null when the slide has none. */
538
+ _caption(): string | null {
539
+ return typeof this.data.caption === "string" ? this.data.caption : null;
540
+ }
541
+
542
+ /** The media credit, or null when the slide has none. */
543
+ _credit(): string | null {
544
+ return typeof this.data.credit === "string" ? this.data.credit : null;
545
+ }
546
+
350
547
  _initLayout() {
351
548
  // Message
352
549
  this.message = new Message({}, this.options);
@@ -360,15 +557,29 @@ export class MediaBase {
360
557
  );
361
558
 
362
559
  // Link
363
- if (this.data.link && this.data.link !== "") {
560
+ // The link target comes from the storymap JSON, so it has to pass the
561
+ // same protocol check as every other author-supplied URL — otherwise a
562
+ // `javascript:` href is a click-through XSS. A rejected link falls
563
+ // through to the unlinked layout below rather than rendering a
564
+ // dead anchor.
565
+ // (`_el.content` starts as a truthy `{}` placeholder, so the branch is
566
+ // tracked with a local flag rather than a truthiness test.)
567
+ const raw_link = this.data.link;
568
+ const href = typeof raw_link === "string" ? validateWebURL(raw_link) : null;
569
+ if (href) {
364
570
  this._el.link = Dom.create("a", "vco-media-link", this._el.content_container);
365
571
  const link = this._el.link as HTMLAnchorElement;
366
- link.href = this.data.link;
572
+ link.href = href;
367
573
  if (this.data.link_target && this.data.link_target !== "") {
368
574
  link.target = this.data.link_target;
369
575
  } else {
370
576
  link.target = "_blank";
371
577
  }
578
+ if (link.target === "_blank") {
579
+ // rel=noopener so the opened page cannot reach back through
580
+ // window.opener
581
+ link.rel = "noopener noreferrer";
582
+ }
372
583
 
373
584
  this._el.content = Dom.create("div", "vco-media-content", this._el.link);
374
585
  } else {
@@ -402,7 +613,7 @@ export class MediaBase {
402
613
  _stopMedia() {}
403
614
  }
404
615
 
405
- export class Media extends Evented(MediaBase) {
616
+ export class Media extends Evented<MediaEvents, typeof MediaBase>(MediaBase) {
406
617
  constructor(...args: ConstructorParameters<typeof MediaBase>) {
407
618
  super(...args);
408
619
  }
@@ -0,0 +1,110 @@
1
+ /* embedId
2
+ Provider id extraction.
3
+
4
+ Each media type used to roll its own: six different ways of stripping the
5
+ query string, three different failure modes (throw an Error, throw a bare
6
+ string, or log a warning and carry on with `undefined`), and a fourth
7
+ divergence between the URL shapes the code accepted and the ones
8
+ `MediaType`'s routing regex actually matched.
9
+
10
+ These helpers are the single implementation. Each returns null when the
11
+ url does not carry that provider's id, and the caller decides how to
12
+ report it.
13
+ ================================================== */
14
+
15
+ /** Strip the query string and fragment. */
16
+ function withoutQuery(url: string): string {
17
+ return url.split(/[?#]/)[0];
18
+ }
19
+
20
+ /**
21
+ * The first path segment after any of `markers`, with the query string
22
+ * removed. Returns null when none of the markers is present.
23
+ */
24
+ export function segmentAfter(url: string, ...markers: RegExp[]): string | null {
25
+ for (const marker of markers) {
26
+ const match = url.match(marker);
27
+ if (match) {
28
+ const rest = url.slice((match.index ?? 0) + match[0].length);
29
+ const segment = withoutQuery(rest).split("/")[0];
30
+ if (segment) {
31
+ return segment;
32
+ }
33
+ }
34
+ }
35
+ return null;
36
+ }
37
+
38
+ /** A query parameter, via the platform parser rather than a hand-rolled split. */
39
+ export function queryParam(url: string, name: string): string | null {
40
+ try {
41
+ return new URL(url).searchParams.get(name);
42
+ } catch {
43
+ // not an absolute URL; fall back to the raw query string
44
+ const query = url.split("?")[1];
45
+ if (!query) return null;
46
+ for (const pair of query.split("&")) {
47
+ const [key, value] = pair.split("=");
48
+ if (key === name) {
49
+ return value ?? "";
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ }
55
+
56
+ /** YouTube video id: watch, embed, short, shorts, live and youtu.be links. */
57
+ export function youtubeId(url: string): string | null {
58
+ const fromQuery = queryParam(url, "v");
59
+ if (fromQuery) {
60
+ return fromQuery;
61
+ }
62
+ return segmentAfter(
63
+ url,
64
+ /youtu\.be\//i,
65
+ /\/embed\//i,
66
+ /\/shorts\//i,
67
+ /\/live\//i,
68
+ /\/v\//i,
69
+ /[?&]v=/i,
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Vimeo video id. Watch URLs are the bare `vimeo.com/<id>` form, so the
75
+ * explicit `/video/` path alone is not enough — the previous implementation
76
+ * split on `video\/|\/\/vimeo\.com\//` and relied on the second alternative.
77
+ * Non-numeric pages (channels, albums, showcases) are rejected.
78
+ */
79
+ export function vimeoId(url: string): string | null {
80
+ const explicit = segmentAfter(url, /vimeo\.com\/video\//i, /player\.vimeo\.com\/video\//i);
81
+ if (explicit) {
82
+ return explicit;
83
+ }
84
+ return url.match(/vimeo\.com\/(\d+)(?:$|[/?#])/i)?.[1] ?? null;
85
+ }
86
+
87
+ /** Dailymotion video id from a watch or embed link. */
88
+ export function dailymotionId(url: string): string | null {
89
+ return segmentAfter(url, /dailymotion\.com\/video\//i, /dai\.ly\//i, /\/embed\/video\//i);
90
+ }
91
+
92
+ /** Flickr photo id from a photo page URL. */
93
+ export function flickrId(url: string): string | null {
94
+ const id = segmentAfter(url, /flickr\.com\/photos\/[^/]+\//i);
95
+ if (id && /^\d+$/.test(id)) {
96
+ return id;
97
+ }
98
+ return null;
99
+ }
100
+
101
+ /** Tweet id from a twitter.com or x.com status URL. */
102
+ export function tweetId(url: string): string | null {
103
+ return segmentAfter(url, /\/status(?:es)?\//i);
104
+ }
105
+
106
+ /** Tweet author (the profile segment before `/status/<id>`), or null. */
107
+ export function tweetAuthor(url: string): string | null {
108
+ const match = /(?:twitter\.com|x\.com)\/([^\s/?#]+)\/status(?:es)?\//i.exec(url);
109
+ return match ? match[1] : null;
110
+ }