@shelamkoff/rector 1.0.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 (668) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +17 -0
  3. package/README.md +23 -0
  4. package/THIRD_PARTY_LICENSES.txt +298 -0
  5. package/dist/I18n.d.ts +1 -0
  6. package/dist/core/Block.d.ts +110 -0
  7. package/dist/core/Block.js +390 -0
  8. package/dist/core/BlockAnimator.d.ts +39 -0
  9. package/dist/core/BlockAnimator.js +106 -0
  10. package/dist/core/BlockManager.d.ts +163 -0
  11. package/dist/core/BlockManager.js +640 -0
  12. package/dist/core/BlockOperations.d.ts +67 -0
  13. package/dist/core/BlockOperations.js +238 -0
  14. package/dist/core/ChangeNotifier.d.ts +15 -0
  15. package/dist/core/ChangeNotifier.js +55 -0
  16. package/dist/core/CommandDispatcher.d.ts +52 -0
  17. package/dist/core/CommandDispatcher.js +208 -0
  18. package/dist/core/CrossBlockSelection.d.ts +30 -0
  19. package/dist/core/CrossBlockSelection.js +74 -0
  20. package/dist/core/Diagnostics.d.ts +23 -0
  21. package/dist/core/Diagnostics.js +62 -0
  22. package/dist/core/DocumentSchema.d.ts +29 -0
  23. package/dist/core/DocumentSchema.js +147 -0
  24. package/dist/core/DocumentSnapshotStore.d.ts +34 -0
  25. package/dist/core/DocumentSnapshotStore.js +153 -0
  26. package/dist/core/DragManager.d.ts +17 -0
  27. package/dist/core/DragManager.js +223 -0
  28. package/dist/core/EditorFacade.d.ts +154 -0
  29. package/dist/core/EditorFacade.js +361 -0
  30. package/dist/core/EditorHolderOwnership.d.ts +12 -0
  31. package/dist/core/EditorHolderOwnership.js +28 -0
  32. package/dist/core/I18n.d.ts +147 -0
  33. package/dist/core/I18n.js +296 -0
  34. package/dist/core/InlinePatternMatcher.d.ts +26 -0
  35. package/dist/core/InlinePatternMatcher.js +267 -0
  36. package/dist/core/InlinePluginRegistry.d.ts +55 -0
  37. package/dist/core/InlinePluginRegistry.js +128 -0
  38. package/dist/core/KeyboardManager.d.ts +17 -0
  39. package/dist/core/KeyboardManager.js +231 -0
  40. package/dist/core/LifecycleScope.d.ts +19 -0
  41. package/dist/core/LifecycleScope.js +41 -0
  42. package/dist/core/MouseSelectionManager.d.ts +30 -0
  43. package/dist/core/MouseSelectionManager.js +307 -0
  44. package/dist/core/PluginOwnership.d.ts +9 -0
  45. package/dist/core/PluginOwnership.js +40 -0
  46. package/dist/core/PopupManager.d.ts +50 -0
  47. package/dist/core/PopupManager.js +183 -0
  48. package/dist/core/PreservedBlockPlugin.d.ts +11 -0
  49. package/dist/core/PreservedBlockPlugin.js +42 -0
  50. package/dist/core/PublicEditorApi.d.ts +82 -0
  51. package/dist/core/PublicEditorApi.js +158 -0
  52. package/dist/core/SelectionManager.d.ts +50 -0
  53. package/dist/core/SelectionManager.js +205 -0
  54. package/dist/core/ShortcutRegistry.d.ts +29 -0
  55. package/dist/core/ShortcutRegistry.js +106 -0
  56. package/dist/core/SlashCommands.d.ts +34 -0
  57. package/dist/core/SlashCommands.js +483 -0
  58. package/dist/core/StyleInjector.d.ts +1 -0
  59. package/dist/core/StyleInjector.js +1 -0
  60. package/dist/core/Tooltip.d.ts +17 -0
  61. package/dist/core/Tooltip.js +60 -0
  62. package/dist/core/TriggerManager.d.ts +17 -0
  63. package/dist/core/TriggerManager.js +159 -0
  64. package/dist/core/TypeSelector.d.ts +31 -0
  65. package/dist/core/TypeSelector.js +464 -0
  66. package/dist/core/UndoManager.d.ts +72 -0
  67. package/dist/core/UndoManager.js +383 -0
  68. package/dist/core/block-settings-menu/BlockActions.d.ts +81 -0
  69. package/dist/core/block-settings-menu/BlockActions.js +233 -0
  70. package/dist/core/block-settings-menu/BlockSettingsMenu.d.ts +46 -0
  71. package/dist/core/block-settings-menu/BlockSettingsMenu.js +205 -0
  72. package/dist/core/block-settings-menu/MenuBuilder.d.ts +43 -0
  73. package/dist/core/block-settings-menu/MenuBuilder.js +203 -0
  74. package/dist/core/block-settings-menu/MenuPositioner.d.ts +22 -0
  75. package/dist/core/block-settings-menu/MenuPositioner.js +79 -0
  76. package/dist/core/clipboard/Clipboard.d.ts +47 -0
  77. package/dist/core/clipboard/Clipboard.js +653 -0
  78. package/dist/core/clipboard/CrossBlockEditor.d.ts +43 -0
  79. package/dist/core/clipboard/CrossBlockEditor.js +198 -0
  80. package/dist/core/clipboard/PasteRouter.d.ts +27 -0
  81. package/dist/core/clipboard/PasteRouter.js +86 -0
  82. package/dist/core/clipboard/pasteInsert.d.ts +35 -0
  83. package/dist/core/clipboard/pasteInsert.js +215 -0
  84. package/dist/core/clipboard/pasteUtils.d.ts +25 -0
  85. package/dist/core/clipboard/pasteUtils.js +98 -0
  86. package/dist/core/config.d.ts +77 -0
  87. package/dist/core/config.js +100 -0
  88. package/dist/core/constants.d.ts +23 -0
  89. package/dist/core/constants.js +30 -0
  90. package/dist/core/crossBlockConvert.d.ts +38 -0
  91. package/dist/core/crossBlockConvert.js +253 -0
  92. package/dist/core/dom.d.ts +35 -0
  93. package/dist/core/dom.js +65 -0
  94. package/dist/core/editorEvents.d.ts +89 -0
  95. package/dist/core/editorEvents.js +60 -0
  96. package/dist/core/hydrateInlinePlugins.d.ts +9 -0
  97. package/dist/core/hydrateInlinePlugins.js +36 -0
  98. package/dist/core/icons.d.ts +10 -0
  99. package/dist/core/icons.js +21 -0
  100. package/dist/core/index.d.ts +59 -0
  101. package/dist/core/index.js +703 -0
  102. package/dist/core/inline-toolbar/ActionsPanel.d.ts +61 -0
  103. package/dist/core/inline-toolbar/ActionsPanel.js +132 -0
  104. package/dist/core/inline-toolbar/InlinePositioner.d.ts +20 -0
  105. package/dist/core/inline-toolbar/InlinePositioner.js +63 -0
  106. package/dist/core/inline-toolbar/InlineToolbar.d.ts +45 -0
  107. package/dist/core/inline-toolbar/InlineToolbar.js +456 -0
  108. package/dist/core/inline-toolbar/PluginControlsSlot.d.ts +52 -0
  109. package/dist/core/inline-toolbar/PluginControlsSlot.js +118 -0
  110. package/dist/core/inline-toolbar/SelectionTracker.d.ts +63 -0
  111. package/dist/core/inline-toolbar/SelectionTracker.js +173 -0
  112. package/dist/core/inlinePluginInsert.d.ts +13 -0
  113. package/dist/core/inlinePluginInsert.js +56 -0
  114. package/dist/core/locale/en.d.ts +35 -0
  115. package/dist/core/locale/en.js +37 -0
  116. package/dist/core/locale/ru.d.ts +35 -0
  117. package/dist/core/locale/ru.js +37 -0
  118. package/dist/core/menuKeyboardNav.d.ts +15 -0
  119. package/dist/core/menuKeyboardNav.js +52 -0
  120. package/dist/core/sanitize.d.ts +2 -0
  121. package/dist/core/sanitize.js +6 -0
  122. package/dist/core/splitConvert.d.ts +46 -0
  123. package/dist/core/splitConvert.js +190 -0
  124. package/dist/core/textOffset.d.ts +46 -0
  125. package/dist/core/textOffset.js +180 -0
  126. package/dist/core/themes/dark.css +30 -0
  127. package/dist/core/themes/light.css +33 -0
  128. package/dist/core/themes/variables.css +1170 -0
  129. package/dist/core/toolbar/OffcanvasRoot.d.ts +37 -0
  130. package/dist/core/toolbar/OffcanvasRoot.js +127 -0
  131. package/dist/core/toolbar/Toolbar.d.ts +70 -0
  132. package/dist/core/toolbar/Toolbar.js +432 -0
  133. package/dist/core/toolbar/ToolbarPositioner.d.ts +60 -0
  134. package/dist/core/toolbar/ToolbarPositioner.js +188 -0
  135. package/dist/core/toolbar/ToolboxBuilder.d.ts +44 -0
  136. package/dist/core/toolbar/ToolboxBuilder.js +260 -0
  137. package/dist/core/types.d.ts +747 -0
  138. package/dist/core/uid.d.ts +6 -0
  139. package/dist/core/uid.js +29 -0
  140. package/dist/index.d.ts +2 -0
  141. package/dist/index.js +1 -0
  142. package/dist/inline-plugins/README.md +35 -0
  143. package/dist/inline-plugins/README.ru.md +35 -0
  144. package/dist/inline-plugins/color/README.md +61 -0
  145. package/dist/inline-plugins/color/README.ru.md +61 -0
  146. package/dist/inline-plugins/color.d.ts +8 -0
  147. package/dist/inline-plugins/color.js +184 -0
  148. package/dist/inline-plugins/locale/en.d.ts +7 -0
  149. package/dist/inline-plugins/locale/en.js +6 -0
  150. package/dist/inline-plugins/locale/ru.d.ts +7 -0
  151. package/dist/inline-plugins/locale/ru.js +6 -0
  152. package/dist/inline-plugins/mention/README.md +97 -0
  153. package/dist/inline-plugins/mention/README.ru.md +97 -0
  154. package/dist/inline-plugins/mention/index.d.ts +110 -0
  155. package/dist/inline-plugins/mention/index.js +1897 -0
  156. package/dist/inline-plugins/mention/styles.css +183 -0
  157. package/dist/inline-plugins/mention/widget.d.ts +16 -0
  158. package/dist/inline-plugins/mention/widget.js +75 -0
  159. package/dist/inline-tools/align.d.ts +14 -0
  160. package/dist/inline-tools/align.js +120 -0
  161. package/dist/inline-tools/bold.d.ts +8 -0
  162. package/dist/inline-tools/bold.js +12 -0
  163. package/dist/inline-tools/caseTransform.d.ts +8 -0
  164. package/dist/inline-tools/caseTransform.js +87 -0
  165. package/dist/inline-tools/clearFormatting.d.ts +8 -0
  166. package/dist/inline-tools/clearFormatting.js +74 -0
  167. package/dist/inline-tools/code.d.ts +8 -0
  168. package/dist/inline-tools/code.js +12 -0
  169. package/dist/inline-tools/colorPicker.d.ts +7 -0
  170. package/dist/inline-tools/colorPicker.js +271 -0
  171. package/dist/inline-tools/defaults.d.ts +10 -0
  172. package/dist/inline-tools/defaults.js +57 -0
  173. package/dist/inline-tools/fontSize.d.ts +7 -0
  174. package/dist/inline-tools/fontSize.js +524 -0
  175. package/dist/inline-tools/italic.d.ts +8 -0
  176. package/dist/inline-tools/italic.js +12 -0
  177. package/dist/inline-tools/link.d.ts +12 -0
  178. package/dist/inline-tools/link.js +251 -0
  179. package/dist/inline-tools/marker.d.ts +8 -0
  180. package/dist/inline-tools/marker.js +12 -0
  181. package/dist/inline-tools/scriptTool.d.ts +11 -0
  182. package/dist/inline-tools/scriptTool.js +149 -0
  183. package/dist/inline-tools/strikethrough.d.ts +8 -0
  184. package/dist/inline-tools/strikethrough.js +12 -0
  185. package/dist/inline-tools/utils.d.ts +220 -0
  186. package/dist/inline-tools/utils.js +992 -0
  187. package/dist/locale/en.d.ts +311 -0
  188. package/dist/locale/en.js +52 -0
  189. package/dist/locale/ru.d.ts +315 -0
  190. package/dist/locale/ru.js +52 -0
  191. package/dist/plugins/BlockPluginAbstract.d.ts +82 -0
  192. package/dist/plugins/BlockPluginAbstract.js +111 -0
  193. package/dist/plugins/README.md +44 -0
  194. package/dist/plugins/README.ru.md +40 -0
  195. package/dist/plugins/async.d.ts +35 -0
  196. package/dist/plugins/async.js +79 -0
  197. package/dist/plugins/attaches/README.md +86 -0
  198. package/dist/plugins/attaches/README.ru.md +87 -0
  199. package/dist/plugins/attaches/attaches.css +374 -0
  200. package/dist/plugins/attaches/index.d.ts +133 -0
  201. package/dist/plugins/attaches/index.js +921 -0
  202. package/dist/plugins/attaches/locale/en.d.ts +23 -0
  203. package/dist/plugins/attaches/locale/en.js +19 -0
  204. package/dist/plugins/attaches/locale/keys.d.ts +5 -0
  205. package/dist/plugins/attaches/locale/ru.d.ts +25 -0
  206. package/dist/plugins/attaches/locale/ru.js +19 -0
  207. package/dist/plugins/carousel/README.md +108 -0
  208. package/dist/plugins/carousel/README.ru.md +109 -0
  209. package/dist/plugins/carousel/carousel.css +198 -0
  210. package/dist/plugins/carousel/icons.d.ts +12 -0
  211. package/dist/plugins/carousel/icons.js +13 -0
  212. package/dist/plugins/carousel/index.d.ts +137 -0
  213. package/dist/plugins/carousel/index.js +859 -0
  214. package/dist/plugins/carousel/locale/en.d.ts +41 -0
  215. package/dist/plugins/carousel/locale/en.js +40 -0
  216. package/dist/plugins/carousel/locale/keys.d.ts +2 -0
  217. package/dist/plugins/carousel/locale/ru.d.ts +41 -0
  218. package/dist/plugins/carousel/locale/ru.js +40 -0
  219. package/dist/plugins/carousel/state.d.ts +29 -0
  220. package/dist/plugins/carousel/state.js +42 -0
  221. package/dist/plugins/checklist/README.md +54 -0
  222. package/dist/plugins/checklist/README.ru.md +55 -0
  223. package/dist/plugins/checklist/checklist.css +80 -0
  224. package/dist/plugins/checklist/index.d.ts +75 -0
  225. package/dist/plugins/checklist/index.js +407 -0
  226. package/dist/plugins/checklist/locale/en.d.ts +5 -0
  227. package/dist/plugins/checklist/locale/en.js +4 -0
  228. package/dist/plugins/checklist/locale/keys.d.ts +5 -0
  229. package/dist/plugins/checklist/locale/ru.d.ts +5 -0
  230. package/dist/plugins/checklist/locale/ru.js +4 -0
  231. package/dist/plugins/checklist/mapTextFields.d.ts +1 -0
  232. package/dist/plugins/checklist/mapTextFields.js +1 -0
  233. package/dist/plugins/code/README.md +59 -0
  234. package/dist/plugins/code/README.ru.md +60 -0
  235. package/dist/plugins/code/code.css +360 -0
  236. package/dist/plugins/code/index.d.ts +109 -0
  237. package/dist/plugins/code/index.js +1012 -0
  238. package/dist/plugins/code/locale/en.d.ts +11 -0
  239. package/dist/plugins/code/locale/en.js +10 -0
  240. package/dist/plugins/code/locale/keys.d.ts +5 -0
  241. package/dist/plugins/code/locale/ru.d.ts +11 -0
  242. package/dist/plugins/code/locale/ru.js +10 -0
  243. package/dist/plugins/columns/README.md +55 -0
  244. package/dist/plugins/columns/README.ru.md +56 -0
  245. package/dist/plugins/columns/columns.css +103 -0
  246. package/dist/plugins/columns/index.d.ts +58 -0
  247. package/dist/plugins/columns/index.js +236 -0
  248. package/dist/plugins/columns/locale/en.d.ts +6 -0
  249. package/dist/plugins/columns/locale/en.js +5 -0
  250. package/dist/plugins/columns/locale/keys.d.ts +5 -0
  251. package/dist/plugins/columns/locale/ru.d.ts +6 -0
  252. package/dist/plugins/columns/locale/ru.js +5 -0
  253. package/dist/plugins/delimiter/README.md +48 -0
  254. package/dist/plugins/delimiter/README.ru.md +49 -0
  255. package/dist/plugins/delimiter/delimiter.css +22 -0
  256. package/dist/plugins/delimiter/index.d.ts +38 -0
  257. package/dist/plugins/delimiter/index.js +69 -0
  258. package/dist/plugins/delimiter/locale/en.d.ts +4 -0
  259. package/dist/plugins/delimiter/locale/en.js +3 -0
  260. package/dist/plugins/delimiter/locale/keys.d.ts +5 -0
  261. package/dist/plugins/delimiter/locale/ru.d.ts +4 -0
  262. package/dist/plugins/delimiter/locale/ru.js +3 -0
  263. package/dist/plugins/embed/README.md +81 -0
  264. package/dist/plugins/embed/README.ru.md +82 -0
  265. package/dist/plugins/embed/embed.css +558 -0
  266. package/dist/plugins/embed/index.d.ts +271 -0
  267. package/dist/plugins/embed/index.js +967 -0
  268. package/dist/plugins/embed/locale/en.d.ts +20 -0
  269. package/dist/plugins/embed/locale/en.js +19 -0
  270. package/dist/plugins/embed/locale/keys.d.ts +5 -0
  271. package/dist/plugins/embed/locale/ru.d.ts +20 -0
  272. package/dist/plugins/embed/locale/ru.js +19 -0
  273. package/dist/plugins/embed/player.d.ts +1 -0
  274. package/dist/plugins/embed/player.js +1 -0
  275. package/dist/plugins/gallery/README.md +92 -0
  276. package/dist/plugins/gallery/README.ru.md +93 -0
  277. package/dist/plugins/gallery/css.d.ts +52 -0
  278. package/dist/plugins/gallery/css.js +67 -0
  279. package/dist/plugins/gallery/gallery.css +860 -0
  280. package/dist/plugins/gallery/icons.d.ts +13 -0
  281. package/dist/plugins/gallery/icons.js +45 -0
  282. package/dist/plugins/gallery/index.d.ts +126 -0
  283. package/dist/plugins/gallery/index.js +355 -0
  284. package/dist/plugins/gallery/layout.d.ts +35 -0
  285. package/dist/plugins/gallery/layout.js +79 -0
  286. package/dist/plugins/gallery/locale/en.d.ts +36 -0
  287. package/dist/plugins/gallery/locale/en.js +35 -0
  288. package/dist/plugins/gallery/locale/keys.d.ts +5 -0
  289. package/dist/plugins/gallery/locale/ru.d.ts +36 -0
  290. package/dist/plugins/gallery/locale/ru.js +35 -0
  291. package/dist/plugins/gallery/settings.d.ts +25 -0
  292. package/dist/plugins/gallery/settings.js +199 -0
  293. package/dist/plugins/gallery/slot.d.ts +73 -0
  294. package/dist/plugins/gallery/slot.js +260 -0
  295. package/dist/plugins/gallery/state.d.ts +67 -0
  296. package/dist/plugins/gallery/state.js +133 -0
  297. package/dist/plugins/gallery/styles.d.ts +10 -0
  298. package/dist/plugins/gallery/styles.js +24 -0
  299. package/dist/plugins/gallery/uploader.d.ts +31 -0
  300. package/dist/plugins/gallery/uploader.js +111 -0
  301. package/dist/plugins/gallery/view-empty.d.ts +41 -0
  302. package/dist/plugins/gallery/view-empty.js +56 -0
  303. package/dist/plugins/gallery/view-filled.d.ts +55 -0
  304. package/dist/plugins/gallery/view-filled.js +353 -0
  305. package/dist/plugins/heading/HeadingLevelSelect.d.ts +16 -0
  306. package/dist/plugins/heading/HeadingLevelSelect.js +183 -0
  307. package/dist/plugins/heading/README.md +58 -0
  308. package/dist/plugins/heading/README.ru.md +59 -0
  309. package/dist/plugins/heading/heading.css +76 -0
  310. package/dist/plugins/heading/index.d.ts +124 -0
  311. package/dist/plugins/heading/index.js +273 -0
  312. package/dist/plugins/heading/locale/en.d.ts +11 -0
  313. package/dist/plugins/heading/locale/en.js +10 -0
  314. package/dist/plugins/heading/locale/keys.d.ts +5 -0
  315. package/dist/plugins/heading/locale/ru.d.ts +11 -0
  316. package/dist/plugins/heading/locale/ru.js +10 -0
  317. package/dist/plugins/heading/mapTextFields.d.ts +1 -0
  318. package/dist/plugins/heading/mapTextFields.js +1 -0
  319. package/dist/plugins/image/README.md +93 -0
  320. package/dist/plugins/image/README.ru.md +94 -0
  321. package/dist/plugins/image/css.d.ts +47 -0
  322. package/dist/plugins/image/css.js +47 -0
  323. package/dist/plugins/image/icons.d.ts +13 -0
  324. package/dist/plugins/image/icons.js +26 -0
  325. package/dist/plugins/image/image.css +559 -0
  326. package/dist/plugins/image/index.d.ts +129 -0
  327. package/dist/plugins/image/index.js +346 -0
  328. package/dist/plugins/image/locale/en.d.ts +39 -0
  329. package/dist/plugins/image/locale/en.js +38 -0
  330. package/dist/plugins/image/locale/keys.d.ts +5 -0
  331. package/dist/plugins/image/locale/ru.d.ts +39 -0
  332. package/dist/plugins/image/locale/ru.js +38 -0
  333. package/dist/plugins/image/settings.d.ts +23 -0
  334. package/dist/plugins/image/settings.js +347 -0
  335. package/dist/plugins/image/state.d.ts +86 -0
  336. package/dist/plugins/image/state.js +151 -0
  337. package/dist/plugins/image/styles.d.ts +21 -0
  338. package/dist/plugins/image/styles.js +58 -0
  339. package/dist/plugins/image/uploader.d.ts +31 -0
  340. package/dist/plugins/image/uploader.js +92 -0
  341. package/dist/plugins/image/view-empty.d.ts +44 -0
  342. package/dist/plugins/image/view-empty.js +61 -0
  343. package/dist/plugins/image/view-filled.d.ts +49 -0
  344. package/dist/plugins/image/view-filled.js +282 -0
  345. package/dist/plugins/index.d.ts +21 -0
  346. package/dist/plugins/index.js +22 -0
  347. package/dist/plugins/link-preview/README.md +69 -0
  348. package/dist/plugins/link-preview/README.ru.md +70 -0
  349. package/dist/plugins/link-preview/index.d.ts +169 -0
  350. package/dist/plugins/link-preview/index.js +698 -0
  351. package/dist/plugins/link-preview/link-preview.css +254 -0
  352. package/dist/plugins/link-preview/locale/en.d.ts +14 -0
  353. package/dist/plugins/link-preview/locale/en.js +13 -0
  354. package/dist/plugins/link-preview/locale/keys.d.ts +5 -0
  355. package/dist/plugins/link-preview/locale/ru.d.ts +14 -0
  356. package/dist/plugins/link-preview/locale/ru.js +13 -0
  357. package/dist/plugins/list/README.md +59 -0
  358. package/dist/plugins/list/README.ru.md +60 -0
  359. package/dist/plugins/list/index.d.ts +134 -0
  360. package/dist/plugins/list/index.js +566 -0
  361. package/dist/plugins/list/list.css +57 -0
  362. package/dist/plugins/list/locale/en.d.ts +5 -0
  363. package/dist/plugins/list/locale/en.js +4 -0
  364. package/dist/plugins/list/locale/keys.d.ts +5 -0
  365. package/dist/plugins/list/locale/ru.d.ts +5 -0
  366. package/dist/plugins/list/locale/ru.js +4 -0
  367. package/dist/plugins/list/mapTextFields.d.ts +1 -0
  368. package/dist/plugins/list/mapTextFields.js +1 -0
  369. package/dist/plugins/paragraph/README.md +57 -0
  370. package/dist/plugins/paragraph/README.ru.md +58 -0
  371. package/dist/plugins/paragraph/index.d.ts +112 -0
  372. package/dist/plugins/paragraph/index.js +158 -0
  373. package/dist/plugins/paragraph/locale/en.d.ts +5 -0
  374. package/dist/plugins/paragraph/locale/en.js +4 -0
  375. package/dist/plugins/paragraph/locale/keys.d.ts +5 -0
  376. package/dist/plugins/paragraph/locale/ru.d.ts +5 -0
  377. package/dist/plugins/paragraph/locale/ru.js +4 -0
  378. package/dist/plugins/paragraph/mapTextFields.d.ts +1 -0
  379. package/dist/plugins/paragraph/mapTextFields.js +1 -0
  380. package/dist/plugins/paragraph/paragraph.css +56 -0
  381. package/dist/plugins/person/README.md +72 -0
  382. package/dist/plugins/person/README.ru.md +73 -0
  383. package/dist/plugins/person/index.d.ts +189 -0
  384. package/dist/plugins/person/index.js +777 -0
  385. package/dist/plugins/person/locale/en.d.ts +18 -0
  386. package/dist/plugins/person/locale/en.js +17 -0
  387. package/dist/plugins/person/locale/keys.d.ts +5 -0
  388. package/dist/plugins/person/locale/ru.d.ts +18 -0
  389. package/dist/plugins/person/locale/ru.js +17 -0
  390. package/dist/plugins/person/person.css +431 -0
  391. package/dist/plugins/person/socialResolver.d.ts +18 -0
  392. package/dist/plugins/person/socialResolver.js +69 -0
  393. package/dist/plugins/poll/README.md +96 -0
  394. package/dist/plugins/poll/README.ru.md +97 -0
  395. package/dist/plugins/poll/index.d.ts +134 -0
  396. package/dist/plugins/poll/index.js +825 -0
  397. package/dist/plugins/poll/locale/en.d.ts +23 -0
  398. package/dist/plugins/poll/locale/en.js +22 -0
  399. package/dist/plugins/poll/locale/keys.d.ts +5 -0
  400. package/dist/plugins/poll/locale/ru.d.ts +23 -0
  401. package/dist/plugins/poll/locale/ru.js +22 -0
  402. package/dist/plugins/poll/poll.css +400 -0
  403. package/dist/plugins/quote/README.md +55 -0
  404. package/dist/plugins/quote/README.ru.md +56 -0
  405. package/dist/plugins/quote/index.d.ts +81 -0
  406. package/dist/plugins/quote/index.js +165 -0
  407. package/dist/plugins/quote/locale/en.d.ts +6 -0
  408. package/dist/plugins/quote/locale/en.js +5 -0
  409. package/dist/plugins/quote/locale/keys.d.ts +5 -0
  410. package/dist/plugins/quote/locale/ru.d.ts +6 -0
  411. package/dist/plugins/quote/locale/ru.js +5 -0
  412. package/dist/plugins/quote/mapTextFields.d.ts +1 -0
  413. package/dist/plugins/quote/mapTextFields.js +1 -0
  414. package/dist/plugins/quote/quote.css +72 -0
  415. package/dist/plugins/raw/README.md +54 -0
  416. package/dist/plugins/raw/README.ru.md +55 -0
  417. package/dist/plugins/raw/index.d.ts +62 -0
  418. package/dist/plugins/raw/index.js +227 -0
  419. package/dist/plugins/raw/locale/en.d.ts +7 -0
  420. package/dist/plugins/raw/locale/en.js +6 -0
  421. package/dist/plugins/raw/locale/keys.d.ts +5 -0
  422. package/dist/plugins/raw/locale/ru.d.ts +7 -0
  423. package/dist/plugins/raw/locale/ru.js +6 -0
  424. package/dist/plugins/raw/raw.css +127 -0
  425. package/dist/plugins/shared/actionBar.d.ts +19 -0
  426. package/dist/plugins/shared/actionBar.js +35 -0
  427. package/dist/plugins/shared/dropzone.d.ts +106 -0
  428. package/dist/plugins/shared/dropzone.js +107 -0
  429. package/dist/plugins/shared/fileInput.d.ts +44 -0
  430. package/dist/plugins/shared/fileInput.js +62 -0
  431. package/dist/plugins/spoiler/README.md +55 -0
  432. package/dist/plugins/spoiler/README.ru.md +56 -0
  433. package/dist/plugins/spoiler/index.d.ts +61 -0
  434. package/dist/plugins/spoiler/index.js +169 -0
  435. package/dist/plugins/spoiler/locale/en.d.ts +7 -0
  436. package/dist/plugins/spoiler/locale/en.js +6 -0
  437. package/dist/plugins/spoiler/locale/keys.d.ts +5 -0
  438. package/dist/plugins/spoiler/locale/ru.d.ts +7 -0
  439. package/dist/plugins/spoiler/locale/ru.js +6 -0
  440. package/dist/plugins/spoiler/spoiler.css +101 -0
  441. package/dist/plugins/table/README.md +55 -0
  442. package/dist/plugins/table/README.ru.md +56 -0
  443. package/dist/plugins/table/index.d.ts +85 -0
  444. package/dist/plugins/table/index.js +399 -0
  445. package/dist/plugins/table/locale/en.d.ts +9 -0
  446. package/dist/plugins/table/locale/en.js +8 -0
  447. package/dist/plugins/table/locale/keys.d.ts +5 -0
  448. package/dist/plugins/table/locale/ru.d.ts +9 -0
  449. package/dist/plugins/table/locale/ru.js +8 -0
  450. package/dist/plugins/table/table.css +58 -0
  451. package/dist/plugins/toggle/README.md +56 -0
  452. package/dist/plugins/toggle/README.ru.md +57 -0
  453. package/dist/plugins/toggle/index.d.ts +69 -0
  454. package/dist/plugins/toggle/index.js +191 -0
  455. package/dist/plugins/toggle/locale/en.d.ts +7 -0
  456. package/dist/plugins/toggle/locale/en.js +6 -0
  457. package/dist/plugins/toggle/locale/keys.d.ts +5 -0
  458. package/dist/plugins/toggle/locale/ru.d.ts +7 -0
  459. package/dist/plugins/toggle/locale/ru.js +6 -0
  460. package/dist/plugins/toggle/toggle.css +101 -0
  461. package/dist/plugins/warning/README.md +55 -0
  462. package/dist/plugins/warning/README.ru.md +56 -0
  463. package/dist/plugins/warning/index.d.ts +66 -0
  464. package/dist/plugins/warning/index.js +167 -0
  465. package/dist/plugins/warning/locale/en.d.ts +6 -0
  466. package/dist/plugins/warning/locale/en.js +5 -0
  467. package/dist/plugins/warning/locale/keys.d.ts +5 -0
  468. package/dist/plugins/warning/locale/ru.d.ts +6 -0
  469. package/dist/plugins/warning/locale/ru.js +5 -0
  470. package/dist/plugins/warning/warning.css +63 -0
  471. package/dist/renderer/async.d.ts +1 -0
  472. package/dist/renderer/async.js +7 -0
  473. package/dist/renderer/errors.d.ts +27 -0
  474. package/dist/renderer/errors.js +48 -0
  475. package/dist/renderer/index.d.ts +82 -0
  476. package/dist/renderer/index.js +413 -0
  477. package/dist/renderer/inline.d.ts +5 -0
  478. package/dist/renderer/inline.js +61 -0
  479. package/dist/renderer/locale/en.d.ts +35 -0
  480. package/dist/renderer/locale/en.js +29 -0
  481. package/dist/renderer/locale/ru.d.ts +37 -0
  482. package/dist/renderer/locale/ru.js +29 -0
  483. package/dist/renderer/renderers/README.md +7 -0
  484. package/dist/renderer/renderers/README.ru.md +5 -0
  485. package/dist/renderer/renderers/async.d.ts +51 -0
  486. package/dist/renderer/renderers/async.js +99 -0
  487. package/dist/renderer/renderers/attaches/README.md +48 -0
  488. package/dist/renderer/renderers/attaches/README.ru.md +48 -0
  489. package/dist/renderer/renderers/attaches/index.d.ts +37 -0
  490. package/dist/renderer/renderers/attaches/index.js +451 -0
  491. package/dist/renderer/renderers/attaches/locale/en.d.ts +11 -0
  492. package/dist/renderer/renderers/attaches/locale/en.js +7 -0
  493. package/dist/renderer/renderers/attaches/locale/ru.d.ts +13 -0
  494. package/dist/renderer/renderers/attaches/locale/ru.js +7 -0
  495. package/dist/renderer/renderers/attaches/styles.css +196 -0
  496. package/dist/renderer/renderers/carousel/README.md +43 -0
  497. package/dist/renderer/renderers/carousel/README.ru.md +43 -0
  498. package/dist/renderer/renderers/carousel/index.d.ts +7 -0
  499. package/dist/renderer/renderers/carousel/index.js +110 -0
  500. package/dist/renderer/renderers/carousel/styles.css +7 -0
  501. package/dist/renderer/renderers/checklist/README.md +33 -0
  502. package/dist/renderer/renderers/checklist/README.ru.md +33 -0
  503. package/dist/renderer/renderers/checklist/index.d.ts +7 -0
  504. package/dist/renderer/renderers/checklist/index.js +55 -0
  505. package/dist/renderer/renderers/checklist/styles.css +54 -0
  506. package/dist/renderer/renderers/code/README.md +33 -0
  507. package/dist/renderer/renderers/code/README.ru.md +33 -0
  508. package/dist/renderer/renderers/code/index.d.ts +9 -0
  509. package/dist/renderer/renderers/code/index.js +137 -0
  510. package/dist/renderer/renderers/code/locale/en.d.ts +5 -0
  511. package/dist/renderer/renderers/code/locale/en.js +4 -0
  512. package/dist/renderer/renderers/code/locale/ru.d.ts +5 -0
  513. package/dist/renderer/renderers/code/locale/ru.js +4 -0
  514. package/dist/renderer/renderers/code/styles.css +330 -0
  515. package/dist/renderer/renderers/columns/README.md +33 -0
  516. package/dist/renderer/renderers/columns/README.ru.md +33 -0
  517. package/dist/renderer/renderers/columns/index.d.ts +7 -0
  518. package/dist/renderer/renderers/columns/index.js +53 -0
  519. package/dist/renderer/renderers/columns/styles.css +5 -0
  520. package/dist/renderer/renderers/delimiter/README.md +33 -0
  521. package/dist/renderer/renderers/delimiter/README.ru.md +33 -0
  522. package/dist/renderer/renderers/delimiter/index.d.ts +7 -0
  523. package/dist/renderer/renderers/delimiter/index.js +28 -0
  524. package/dist/renderer/renderers/delimiter/styles.css +12 -0
  525. package/dist/renderer/renderers/embed/README.md +35 -0
  526. package/dist/renderer/renderers/embed/README.ru.md +35 -0
  527. package/dist/renderer/renderers/embed/index.d.ts +8 -0
  528. package/dist/renderer/renderers/embed/index.js +66 -0
  529. package/dist/renderer/renderers/embed/styles.css +217 -0
  530. package/dist/renderer/renderers/gallery/README.md +41 -0
  531. package/dist/renderer/renderers/gallery/README.ru.md +41 -0
  532. package/dist/renderer/renderers/gallery/index.d.ts +8 -0
  533. package/dist/renderer/renderers/gallery/index.js +329 -0
  534. package/dist/renderer/renderers/gallery/styles.css +419 -0
  535. package/dist/renderer/renderers/heading/README.md +33 -0
  536. package/dist/renderer/renderers/heading/README.ru.md +33 -0
  537. package/dist/renderer/renderers/heading/index.d.ts +8 -0
  538. package/dist/renderer/renderers/heading/index.js +38 -0
  539. package/dist/renderer/renderers/heading/styles.css +26 -0
  540. package/dist/renderer/renderers/image/README.md +42 -0
  541. package/dist/renderer/renderers/image/README.ru.md +42 -0
  542. package/dist/renderer/renderers/image/index.d.ts +7 -0
  543. package/dist/renderer/renderers/image/index.js +93 -0
  544. package/dist/renderer/renderers/image/styles.css +40 -0
  545. package/dist/renderer/renderers/index.d.ts +47 -0
  546. package/dist/renderer/renderers/index.js +125 -0
  547. package/dist/renderer/renderers/link-preview/README.md +43 -0
  548. package/dist/renderer/renderers/link-preview/README.ru.md +43 -0
  549. package/dist/renderer/renderers/link-preview/index.d.ts +9 -0
  550. package/dist/renderer/renderers/link-preview/index.js +118 -0
  551. package/dist/renderer/renderers/link-preview/styles.css +246 -0
  552. package/dist/renderer/renderers/list/README.md +33 -0
  553. package/dist/renderer/renderers/list/README.ru.md +33 -0
  554. package/dist/renderer/renderers/list/index.d.ts +8 -0
  555. package/dist/renderer/renderers/list/index.js +42 -0
  556. package/dist/renderer/renderers/list/styles.css +20 -0
  557. package/dist/renderer/renderers/paragraph/README.md +33 -0
  558. package/dist/renderer/renderers/paragraph/README.ru.md +33 -0
  559. package/dist/renderer/renderers/paragraph/index.d.ts +7 -0
  560. package/dist/renderer/renderers/paragraph/index.js +35 -0
  561. package/dist/renderer/renderers/paragraph/styles.css +3 -0
  562. package/dist/renderer/renderers/person/README.md +44 -0
  563. package/dist/renderer/renderers/person/README.ru.md +44 -0
  564. package/dist/renderer/renderers/person/index.d.ts +7 -0
  565. package/dist/renderer/renderers/person/index.js +213 -0
  566. package/dist/renderer/renderers/person/locale/en.d.ts +6 -0
  567. package/dist/renderer/renderers/person/locale/en.js +5 -0
  568. package/dist/renderer/renderers/person/locale/ru.d.ts +6 -0
  569. package/dist/renderer/renderers/person/locale/ru.js +5 -0
  570. package/dist/renderer/renderers/person/styles.css +47 -0
  571. package/dist/renderer/renderers/poll/README.md +68 -0
  572. package/dist/renderer/renderers/poll/README.ru.md +68 -0
  573. package/dist/renderer/renderers/poll/index.d.ts +9 -0
  574. package/dist/renderer/renderers/poll/index.js +339 -0
  575. package/dist/renderer/renderers/poll/styles.css +148 -0
  576. package/dist/renderer/renderers/quote/README.md +33 -0
  577. package/dist/renderer/renderers/quote/README.ru.md +33 -0
  578. package/dist/renderer/renderers/quote/index.d.ts +7 -0
  579. package/dist/renderer/renderers/quote/index.js +59 -0
  580. package/dist/renderer/renderers/quote/styles.css +43 -0
  581. package/dist/renderer/renderers/raw/README.md +33 -0
  582. package/dist/renderer/renderers/raw/README.ru.md +33 -0
  583. package/dist/renderer/renderers/raw/index.d.ts +7 -0
  584. package/dist/renderer/renderers/raw/index.js +27 -0
  585. package/dist/renderer/renderers/spoiler/README.md +33 -0
  586. package/dist/renderer/renderers/spoiler/README.ru.md +33 -0
  587. package/dist/renderer/renderers/spoiler/index.d.ts +9 -0
  588. package/dist/renderer/renderers/spoiler/index.js +84 -0
  589. package/dist/renderer/renderers/spoiler/locale/en.d.ts +4 -0
  590. package/dist/renderer/renderers/spoiler/locale/en.js +3 -0
  591. package/dist/renderer/renderers/spoiler/locale/ru.d.ts +4 -0
  592. package/dist/renderer/renderers/spoiler/locale/ru.js +3 -0
  593. package/dist/renderer/renderers/spoiler/styles.css +61 -0
  594. package/dist/renderer/renderers/table/README.md +33 -0
  595. package/dist/renderer/renderers/table/README.ru.md +33 -0
  596. package/dist/renderer/renderers/table/index.d.ts +7 -0
  597. package/dist/renderer/renderers/table/index.js +83 -0
  598. package/dist/renderer/renderers/table/styles.css +34 -0
  599. package/dist/renderer/renderers/toggle/README.md +33 -0
  600. package/dist/renderer/renderers/toggle/README.ru.md +33 -0
  601. package/dist/renderer/renderers/toggle/index.d.ts +7 -0
  602. package/dist/renderer/renderers/toggle/index.js +59 -0
  603. package/dist/renderer/renderers/toggle/styles.css +49 -0
  604. package/dist/renderer/renderers/warning/README.md +33 -0
  605. package/dist/renderer/renderers/warning/README.ru.md +33 -0
  606. package/dist/renderer/renderers/warning/index.d.ts +7 -0
  607. package/dist/renderer/renderers/warning/index.js +62 -0
  608. package/dist/renderer/renderers/warning/styles.css +41 -0
  609. package/dist/renderer/styles/base.css +168 -0
  610. package/dist/renderer/types.d.ts +464 -0
  611. package/dist/shared/blockDataNormalizers.d.ts +14 -0
  612. package/dist/shared/blockDataNormalizers.js +235 -0
  613. package/dist/shared/blockDataValidators.d.ts +81 -0
  614. package/dist/shared/blockDataValidators.js +313 -0
  615. package/dist/shared/blockTypes.d.ts +2 -0
  616. package/dist/shared/blockTypes.js +26 -0
  617. package/dist/shared/carouselData.d.ts +34 -0
  618. package/dist/shared/carouselData.js +111 -0
  619. package/dist/shared/cloneEditorData.d.ts +11 -0
  620. package/dist/shared/cloneEditorData.js +20 -0
  621. package/dist/shared/documentTypes.d.ts +35 -0
  622. package/dist/shared/embedPlayer.d.ts +42 -0
  623. package/dist/shared/embedPlayer.js +141 -0
  624. package/dist/shared/fileUtils.d.ts +33 -0
  625. package/dist/shared/fileUtils.js +109 -0
  626. package/dist/shared/highlightRuntime.d.ts +38 -0
  627. package/dist/shared/highlightRuntime.js +75 -0
  628. package/dist/shared/inlineMarshal.d.ts +82 -0
  629. package/dist/shared/inlineMarshal.js +215 -0
  630. package/dist/shared/jsonData.d.ts +11 -0
  631. package/dist/shared/jsonData.js +53 -0
  632. package/dist/shared/localeTypes.d.ts +11 -0
  633. package/dist/shared/mapTextFields.d.ts +89 -0
  634. package/dist/shared/mapTextFields.js +119 -0
  635. package/dist/shared/pollData.d.ts +90 -0
  636. package/dist/shared/pollData.js +231 -0
  637. package/dist/shared/resolvePath.d.ts +8 -0
  638. package/dist/shared/resolvePath.js +10 -0
  639. package/dist/shared/runtime/dompurify.js +2424 -0
  640. package/dist/shared/runtime/highlightBundle.js +10 -0
  641. package/dist/shared/runtime/jszip.js +13 -0
  642. package/dist/shared/sanitize/allowlist.d.ts +21 -0
  643. package/dist/shared/sanitize/allowlist.js +40 -0
  644. package/dist/shared/sanitize/escapeHtml.d.ts +6 -0
  645. package/dist/shared/sanitize/escapeHtml.js +11 -0
  646. package/dist/shared/sanitize/index.d.ts +8 -0
  647. package/dist/shared/sanitize/index.js +8 -0
  648. package/dist/shared/sanitize/parseInline.d.ts +11 -0
  649. package/dist/shared/sanitize/parseInline.js +25 -0
  650. package/dist/shared/sanitize/sanitizeHtml.d.ts +8 -0
  651. package/dist/shared/sanitize/sanitizeHtml.js +19 -0
  652. package/dist/shared/sanitize/sanitizeRawHtml.d.ts +15 -0
  653. package/dist/shared/sanitize/sanitizeRawHtml.js +162 -0
  654. package/dist/shared/sanitize/sanitizeStyle.d.ts +9 -0
  655. package/dist/shared/sanitize/sanitizeStyle.js +39 -0
  656. package/dist/shared/sanitize/sanitizeUrl.d.ts +28 -0
  657. package/dist/shared/sanitize/sanitizeUrl.js +86 -0
  658. package/dist/shared/sanitize/walker.d.ts +15 -0
  659. package/dist/shared/sanitize/walker.js +98 -0
  660. package/dist/shared/styleRegistry.d.ts +4 -0
  661. package/dist/shared/styleRegistry.js +38 -0
  662. package/dist/shared/textFormat.d.ts +32 -0
  663. package/dist/shared/textFormat.js +48 -0
  664. package/dist/shared/zipRuntime.d.ts +19 -0
  665. package/dist/shared/zipRuntime.js +54 -0
  666. package/dist/styles/editor.css +3 -0
  667. package/dist/types.d.ts +1 -0
  668. package/package.json +149 -0
@@ -0,0 +1,825 @@
1
+ import { sanitizeHtml } from '../../core/sanitize.js'
2
+ import { resolvePath } from '../../shared/resolvePath.js'
3
+ import { BlockPluginAbstract } from '../BlockPluginAbstract.js'
4
+ import { uid } from '../../core/uid.js'
5
+ import {
6
+ applyLocalPollVote,
7
+ normalizePollData,
8
+ normalizePollResults,
9
+ shouldAcceptPollRevision,
10
+ validatePollData,
11
+ } from '../../shared/pollData.js'
12
+ import { setSafeUrlAttribute } from '../../shared/sanitize/sanitizeUrl.js'
13
+
14
+ const editorStyles = resolvePath('./poll.css', import.meta.url)
15
+
16
+ // Tabler icon: chart-bar
17
+ const ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v6a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"/><path d="M9 8m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"/><path d="M15 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"/><path d="M4 20h14"/></svg>'
18
+
19
+ // Action bar icons
20
+ const ICON_SINGLE = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>'
21
+ const ICON_MULTI = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M9 12l2 2l4 -4"/></svg>'
22
+ const ICON_RESULTS = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4"/><path d="M3 8h10"/><path d="M3 16h7"/><path d="M3 20h14"/></svg>'
23
+ const ICON_TRASH = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4 7h16"/><path stroke-linecap="round" stroke-linejoin="round" d="M10 11v6"/><path stroke-linecap="round" stroke-linejoin="round" d="M14 11v6"/><path stroke-linecap="round" stroke-linejoin="round" d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12"/><path stroke-linecap="round" stroke-linejoin="round" d="M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3"/></svg>'
24
+ const ICON_PLUS = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>'
25
+ const ICON_REMOVE = '<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M18 6L6 18"/><path stroke-linecap="round" stroke-linejoin="round" d="M6 6l12 12"/></svg>'
26
+ const ICON_SORT = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M6 12h12M10 18h4"/></svg>'
27
+
28
+ /**
29
+ * @typedef {import('../../shared/pollData').PollData} PollData
30
+ * @typedef {import('../../shared/pollData').PollResults} PollResults
31
+ * @typedef {Object} PollDataSource
32
+ * @property {(context: { pollId: string, signal: AbortSignal }) => Promise<PollResults>} load Loads the current counts and optional voter summaries for a persisted poll ID.
33
+ * @property {(context: { pollId: string, optionIds: string[], revision?: string, signal: AbortSignal }) => Promise<PollResults>} vote Submits the selected option IDs and returns the authoritative results.
34
+ * @property {(context: { pollId: string, signal: AbortSignal, onUpdate(results: PollResults): void, onError(error: unknown): void }) => void | (() => void)} [subscribe] Starts live result delivery and optionally returns an idempotent unsubscribe function.
35
+ * @typedef {Object} PollConfig
36
+ * @property {PollDataSource} [dataSource] Backend adapter. Without it votes update the serialized `initialResults` snapshot locally; no remote load, submission, or live subscription occurs.
37
+ * @property {(error: unknown) => void} [onError] Receives rejected load, vote, and subscription errors after the plugin updates its error state.
38
+ * @property {number} [maxVoters=50] Maximum number of voter summaries retained and rendered. Finite values are rounded down and clamped to zero; omitted or non-finite values use 50.
39
+ * @property {(next: string, current: string) => number} [compareRevisions] Orders opaque backend revisions. Return a positive number when `next` is newer, zero when equal, and a negative number when stale.
40
+ * @property {boolean} [injectStyles=true] Whether the editor should load the built-in poll stylesheet.
41
+ * @property {string} [css] Additional stylesheet URL, or the replacement URL when `injectStyles` is `false`.
42
+ * @typedef {{
43
+ * data: PollData,
44
+ * runtime: PollResults,
45
+ * selected: Set<string>,
46
+ * hasVoted: boolean,
47
+ * loading: boolean,
48
+ * submitting: boolean,
49
+ * error: boolean,
50
+ * connectionVersion: number,
51
+ * loadVersion: number,
52
+ * voteVersion: number,
53
+ * abortController: AbortController | null,
54
+ * unsubscribe: (() => void) | null,
55
+ * context: import('../../core/types').BlockMutationContext,
56
+ * }} PollState
57
+ */
58
+ /** @type {WeakMap<HTMLElement, PollState>} */
59
+ const stateMap = new WeakMap()
60
+
61
+
62
+ /**
63
+ * Interactive single- or multiple-choice poll with optional remote result
64
+ * loading, vote submission, and live result subscriptions.
65
+ * @extends {BlockPluginAbstract<PollConfig>}
66
+ */
67
+ export class Poll extends BlockPluginAbstract {
68
+ static isTextBlock = false
69
+ static styles = [editorStyles]
70
+ type = 'poll'
71
+ icon = ICON
72
+ inlineTools = false
73
+
74
+ /**
75
+ * Return the localized toolbox label for this block.
76
+ * @returns {string}
77
+ */
78
+ get title() {
79
+ return this._t('title', 'Poll')
80
+ }
81
+
82
+ /**
83
+ * Create a Poll instance with the supplied consumer configuration.
84
+ * @param {PollConfig} [config]
85
+ */
86
+ constructor(config) {
87
+ super(config)
88
+ }
89
+
90
+ /** Create a stable identifier for a new answer option. @returns {string} */
91
+ #createOptionId() {
92
+ return `option-${uid()}`
93
+ }
94
+
95
+ /** @returns {PollData} */
96
+ #defaultData() {
97
+ return /** @type {PollData} */ ({
98
+ question: '',
99
+ type: 'single',
100
+ options: [
101
+ { id: this.#createOptionId(), text: '' },
102
+ { id: this.#createOptionId(), text: '' },
103
+ ],
104
+ resultsMode: 'always',
105
+ })
106
+ }
107
+ /**
108
+ * Create the editable DOM owned by this block instance.
109
+ * @param {Record<string, unknown>} data
110
+ * @param {import('../../core/types').BlockMutationContext} context
111
+ * @returns {HTMLElement}
112
+ */
113
+ render(data, context) {
114
+ const d = normalizePollData(data, () => this.#createOptionId())
115
+ const runtime = normalizePollResults(d.initialResults, d.options.map(option => option.id), this._config.maxVoters, d.type)
116
+
117
+ const wrapper = document.createElement('div')
118
+ wrapper.classList.add('oe-poll')
119
+ wrapper.contentEditable = 'false'
120
+ wrapper.tabIndex = -1
121
+
122
+ stateMap.set(wrapper, {
123
+ data: d,
124
+ runtime,
125
+ selected: new Set(runtime.currentUserVote || []),
126
+ hasVoted: (runtime.currentUserVote?.length || 0) > 0,
127
+ loading: false,
128
+ submitting: false,
129
+ error: false,
130
+ connectionVersion: 0,
131
+ loadVersion: 0,
132
+ voteVersion: 0,
133
+ abortController: null,
134
+ unsubscribe: null,
135
+ context,
136
+ })
137
+
138
+ this.#build(wrapper)
139
+ this.#connectDataSource(wrapper)
140
+ return wrapper
141
+ }
142
+
143
+ /**
144
+ * Serialize the current block DOM into document data.
145
+ * @param {HTMLElement} element
146
+ * @returns {PollData}
147
+ */
148
+ save(element) {
149
+ this.#syncFromDom(element)
150
+ const s = stateMap.get(element)
151
+ if (!s) return { question: '', type: 'single', options: [], resultsMode: 'always' }
152
+ return /** @type {PollData} */ ({
153
+ ...(s.data.pollId ? { pollId: s.data.pollId } : {}),
154
+ question: s.data.question,
155
+ type: s.data.type,
156
+ options: s.data.options.map((o) => ({ ...o })),
157
+ resultsMode: s.data.resultsMode,
158
+ ...(s.data.initialResults ? { initialResults: structuredClone(s.data.initialResults) } : {}),
159
+ })
160
+ }
161
+
162
+ /**
163
+ * Check whether serialized data satisfies this block's schema.
164
+ * @param {Record<string, unknown>} data
165
+ * @returns {boolean}
166
+ */
167
+ validate(data) {
168
+ return validatePollData(data)
169
+ }
170
+
171
+ /**
172
+ * Check whether the block has no meaningful user content.
173
+ * @param {HTMLElement} element
174
+ * @returns {boolean}
175
+ */
176
+ isEmpty(element) {
177
+ this.#syncFromDom(element)
178
+ const s = stateMap.get(element)
179
+ if (!s) return true
180
+ return !s.data.question.trim() && s.data.options.every((o) => !o.text.trim())
181
+ }
182
+
183
+ /**
184
+ * Extract neutral text that can initialize another block type.
185
+ * @param {HTMLElement} element
186
+ * @returns {{ text: string }}
187
+ */
188
+ exportData(element) {
189
+ const s = stateMap.get(element)
190
+ return { text: s?.data.question || '' }
191
+ }
192
+
193
+ /**
194
+ * Release listeners and resources owned by this block element.
195
+ * @param {HTMLElement} element
196
+ * @returns {void}
197
+ */
198
+ destroy(element) {
199
+ const s = stateMap.get(element)
200
+ if (s) {
201
+ s.connectionVersion++
202
+ s.loadVersion++
203
+ s.voteVersion++
204
+ s.abortController?.abort()
205
+ try { s.unsubscribe?.() } catch (error) {
206
+ try { this._config.onError?.(error) } catch {}
207
+ }
208
+ s.abortController = null
209
+ s.unsubscribe = null
210
+ }
211
+ stateMap.delete(element)
212
+ }
213
+
214
+ // ── Private ─────────────────────────────────────────────────────────────────
215
+
216
+ /** @param {HTMLElement} wrapper @returns {void} */
217
+ #syncFromDom(wrapper) {
218
+ const s = stateMap.get(wrapper)
219
+ if (!s) return
220
+ const questionEl = wrapper.querySelector('.oe-poll__question')
221
+ s.data.question = sanitizeHtml(questionEl?.innerHTML?.trim() || '')
222
+
223
+ const optionEls = wrapper.querySelectorAll('.oe-poll__option-text')
224
+ optionEls.forEach((el, i) => {
225
+ const opt = s.data.options[i]
226
+ if (opt) {
227
+ opt.text = sanitizeHtml(el.innerHTML?.trim() || '')
228
+ }
229
+ })
230
+ }
231
+
232
+ /** @param {HTMLElement} wrapper @returns {void} */
233
+ #build(wrapper) {
234
+ const s = stateMap.get(wrapper)
235
+ if (!s) return
236
+ const w = wrapper
237
+ w.innerHTML = ''
238
+
239
+ // Question
240
+ const question = document.createElement('div')
241
+ question.className = 'oe-poll__question'
242
+ question.contentEditable = s.context.readOnly ? 'false' : 'true'
243
+ question.dataset.placeholder = this._t('questionPlaceholder', 'Question...')
244
+ if (s.data.question) question.innerHTML = sanitizeHtml(s.data.question)
245
+ if (!s.context.readOnly) question.addEventListener('keydown', (e) => {
246
+ if (e.key === 'Enter' && !e.shiftKey) {
247
+ e.preventDefault()
248
+ e.stopPropagation()
249
+ // Focus first option
250
+ const first = w.querySelector('.oe-poll__option-text')
251
+ if (first) /** @type {HTMLElement} */ (first).focus()
252
+ return
253
+ }
254
+ // Let modifier combos (Ctrl+Z, Ctrl+A, etc.) bubble to ShortcutRegistry
255
+ if (!e.ctrlKey && !e.metaKey) e.stopPropagation()
256
+ })
257
+ w.appendChild(question)
258
+
259
+ // Options container
260
+ const optionsWrap = document.createElement('div')
261
+ optionsWrap.className = 'oe-poll__options'
262
+
263
+ s.data.options.forEach((opt, i) => {
264
+ optionsWrap.appendChild(this.#createOption(wrapper, s, opt, i))
265
+ })
266
+
267
+ // Add option button
268
+ if (!s.context.readOnly) {
269
+ const addBtn = document.createElement('button')
270
+ addBtn.type = 'button'
271
+ addBtn.className = 'oe-poll__option-add'
272
+ addBtn.innerHTML = `${ICON_PLUS} ${this._t('addOption', 'Add option')}`
273
+ addBtn.addEventListener('mousedown', (e) => e.preventDefault())
274
+ addBtn.addEventListener('click', () => {
275
+ s.context.mutate(() => {
276
+ this.#syncFromDom(wrapper)
277
+ s.data.options.push({ id: this.#createOptionId(), text: '' })
278
+ this.#reconcileRuntime(s)
279
+ this.#build(wrapper)
280
+ const texts = wrapper.querySelectorAll('.oe-poll__option-text')
281
+ if (texts.length) /** @type {HTMLElement} */ (texts[texts.length - 1]).focus()
282
+ })
283
+ })
284
+ optionsWrap.appendChild(addBtn)
285
+ }
286
+
287
+ w.appendChild(optionsWrap)
288
+
289
+ w.appendChild(this.#buildRuntime(wrapper, s))
290
+
291
+ // Action bar
292
+ if (!s.context.readOnly) w.appendChild(this.#buildActions(wrapper, s))
293
+ }
294
+
295
+ /**
296
+ * @param {HTMLElement} wrapper
297
+ * @param {PollState} s
298
+ * @param {{ id: string, text: string }} opt
299
+ * @param {number} index
300
+ * @returns {HTMLDivElement}
301
+ */
302
+ #createOption(wrapper, s, opt, index) {
303
+ const option = document.createElement('div')
304
+ option.className = 'oe-poll__option'
305
+
306
+ // Marker
307
+ const marker = document.createElement('button')
308
+ marker.type = 'button'
309
+ marker.className = `oe-poll__option-marker oe-poll__option-marker--${s.data.type}`
310
+ marker.dataset.optionId = opt.id
311
+ marker.disabled = s.context.readOnly
312
+ marker.setAttribute('aria-label', this._t('selectOption', 'Select option'))
313
+ marker.setAttribute('aria-pressed', String(s.selected.has(opt.id)))
314
+ if (s.selected.has(opt.id)) marker.classList.add('oe-poll__option-marker--selected')
315
+ if (!s.context.readOnly) marker.addEventListener('click', () => {
316
+ if (s.submitting) return
317
+ if (s.data.type === 'single') {
318
+ s.selected = new Set([opt.id])
319
+ } else if (s.selected.has(opt.id)) {
320
+ s.selected.delete(opt.id)
321
+ } else {
322
+ s.selected.add(opt.id)
323
+ }
324
+ this.#syncSelectionUi(wrapper, s)
325
+ this.#replaceRuntime(wrapper, s)
326
+ })
327
+ option.appendChild(marker)
328
+
329
+ // Text
330
+ const text = document.createElement('div')
331
+ text.className = 'oe-poll__option-text'
332
+ text.contentEditable = s.context.readOnly ? 'false' : 'true'
333
+ const placeholder = this._t('optionPlaceholder', 'Option')
334
+ text.dataset.placeholder = `${placeholder} ${index + 1}`
335
+ if (opt.text) text.innerHTML = sanitizeHtml(opt.text)
336
+
337
+ if (!s.context.readOnly) text.addEventListener('keydown', (e) => {
338
+ if (e.key === 'Enter' && !e.shiftKey) {
339
+ e.preventDefault()
340
+ e.stopPropagation()
341
+ s.context.mutate(() => {
342
+ this.#syncFromDom(wrapper)
343
+ s.data.options.splice(index + 1, 0, { id: this.#createOptionId(), text: '' })
344
+ this.#reconcileRuntime(s)
345
+ this.#build(wrapper)
346
+ const texts = wrapper.querySelectorAll('.oe-poll__option-text')
347
+ if (texts[index + 1]) /** @type {HTMLElement} */ (texts[index + 1]).focus()
348
+ })
349
+ }
350
+ if (e.key === 'Backspace' && !text.textContent?.trim() && s.data.options.length > 2) {
351
+ e.preventDefault()
352
+ e.stopPropagation()
353
+ s.context.mutate(() => {
354
+ this.#syncFromDom(wrapper)
355
+ s.data.options.splice(index, 1)
356
+ this.#reconcileRuntime(s)
357
+ this.#build(wrapper)
358
+ const focusIdx = Math.max(0, index - 1)
359
+ const texts = wrapper.querySelectorAll('.oe-poll__option-text')
360
+ if (texts[focusIdx]) {
361
+ /** @type {HTMLElement} */ (texts[focusIdx]).focus()
362
+ const sel = window.getSelection()
363
+ if (sel) {
364
+ const range = document.createRange()
365
+ range.selectNodeContents(texts[focusIdx])
366
+ range.collapse(false)
367
+ sel.removeAllRanges()
368
+ sel.addRange(range)
369
+ }
370
+ }
371
+ })
372
+ return
373
+ }
374
+ if (!e.ctrlKey && !e.metaKey) e.stopPropagation()
375
+ })
376
+ option.appendChild(text)
377
+
378
+ // Remove button
379
+ if (!s.context.readOnly && s.data.options.length > 2) {
380
+ const removeBtn = document.createElement('button')
381
+ removeBtn.type = 'button'
382
+ removeBtn.className = 'oe-poll__option-remove'
383
+ removeBtn.innerHTML = ICON_REMOVE
384
+ removeBtn.addEventListener('mousedown', (e) => e.preventDefault())
385
+ removeBtn.addEventListener('click', () => {
386
+ s.context.mutate(() => {
387
+ this.#syncFromDom(wrapper)
388
+ s.data.options.splice(index, 1)
389
+ this.#reconcileRuntime(s)
390
+ this.#build(wrapper)
391
+ })
392
+ })
393
+ option.appendChild(removeBtn)
394
+ }
395
+
396
+ return option
397
+ }
398
+
399
+ /**
400
+ * @param {PollState} s
401
+ * @returns {HTMLDivElement}
402
+ */
403
+ #buildResults(s) {
404
+ const results = document.createElement('div')
405
+ results.className = 'oe-poll__results'
406
+
407
+ const totalVotes = s.runtime.total
408
+ const votesById = new Map(s.runtime.options.map(option => [option.id, option.votes]))
409
+
410
+ for (const opt of s.data.options) {
411
+ const row = document.createElement('div')
412
+ row.className = 'oe-poll__result-row'
413
+
414
+ const label = document.createElement('span')
415
+ label.className = 'oe-poll__result-label'
416
+ if (opt.text) label.innerHTML = sanitizeHtml(opt.text)
417
+ else label.textContent = '—'
418
+
419
+ const bar = document.createElement('div')
420
+ bar.className = 'oe-poll__result-bar'
421
+
422
+ const fill = document.createElement('div')
423
+ fill.className = 'oe-poll__result-fill'
424
+ const votes = votesById.get(opt.id) || 0
425
+ const pct = totalVotes > 0 ? Math.round((votes / totalVotes) * 100) : 0
426
+ fill.style.width = `${pct}%`
427
+ bar.appendChild(fill)
428
+
429
+ const pctLabel = document.createElement('span')
430
+ pctLabel.className = 'oe-poll__result-pct'
431
+ pctLabel.textContent = `${pct}%`
432
+
433
+ row.append(label, bar, pctLabel)
434
+ results.appendChild(row)
435
+ }
436
+
437
+ return results
438
+ }
439
+
440
+ /** @param {'always' | 'afterVote' | 'hidden'} mode @returns {string} */
441
+ #resultsModeLabel(mode) {
442
+ if (mode === 'afterVote') return this._t('resultsAfterVote', 'Results after vote')
443
+ if (mode === 'hidden') return this._t('resultsHidden', 'Results hidden')
444
+ return this._t('resultsAlways', 'Results always visible')
445
+ }
446
+
447
+ /** @param {PollState} s @returns {void} */
448
+ #reconcileRuntime(s) {
449
+ const ids = s.data.options.map(option => option.id)
450
+ s.runtime = normalizePollResults(s.runtime, ids, this._config.maxVoters, s.data.type)
451
+ s.selected = new Set([...s.selected].filter(id => ids.includes(id)))
452
+ if (s.data.type === 'single' && s.selected.size > 1) {
453
+ s.selected = new Set([[...s.selected][0]])
454
+ }
455
+ if (!this._config.dataSource && s.data.initialResults) {
456
+ s.data.initialResults = normalizePollResults(s.data.initialResults, ids, this._config.maxVoters, s.data.type)
457
+ }
458
+ }
459
+
460
+ /** @param {HTMLElement} wrapper @param {PollState} s @returns {void} */
461
+ #syncSelectionUi(wrapper, s) {
462
+ wrapper.querySelectorAll('.oe-poll__option-marker').forEach(element => {
463
+ const button = /** @type {HTMLButtonElement} */ (element)
464
+ const selected = !!button.dataset.optionId && s.selected.has(button.dataset.optionId)
465
+ button.classList.toggle('oe-poll__option-marker--selected', selected)
466
+ button.setAttribute('aria-pressed', String(selected))
467
+ })
468
+ }
469
+
470
+ /** @param {HTMLElement} wrapper @param {PollState} s @returns {void} */
471
+ #replaceRuntime(wrapper, s) {
472
+ wrapper.querySelector('.oe-poll__runtime')?.replaceWith(this.#buildRuntime(wrapper, s))
473
+ }
474
+
475
+ /** @param {HTMLElement} wrapper @param {PollState} s @returns {HTMLDivElement} */
476
+ #buildRuntime(wrapper, s) {
477
+ const runtime = document.createElement('div')
478
+ runtime.className = 'oe-poll__runtime'
479
+
480
+ if (s.loading) {
481
+ const status = document.createElement('div')
482
+ status.className = 'oe-poll__status'
483
+ status.setAttribute('role', 'status')
484
+ status.textContent = this._t('loading', 'Loading results…')
485
+ runtime.appendChild(status)
486
+ } else if (s.error) {
487
+ const status = document.createElement('div')
488
+ status.className = 'oe-poll__status oe-poll__status--error'
489
+ status.setAttribute('role', 'alert')
490
+ status.textContent = this._t('loadError', 'Could not load poll results')
491
+ runtime.appendChild(status)
492
+ }
493
+
494
+ const showResults = s.data.resultsMode === 'always'
495
+ || (s.data.resultsMode === 'afterVote' && s.hasVoted)
496
+ if (!s.loading && showResults) {
497
+ runtime.appendChild(this.#buildResults(s))
498
+ if (s.runtime.total === 0) {
499
+ const empty = document.createElement('div')
500
+ empty.className = 'oe-poll__status'
501
+ empty.textContent = this._t('emptyResults', 'No votes yet')
502
+ runtime.appendChild(empty)
503
+ }
504
+ if (s.runtime.voters?.length) runtime.appendChild(this.#buildVoters(s))
505
+ }
506
+
507
+ const submit = document.createElement('button')
508
+ submit.type = 'button'
509
+ submit.className = 'oe-poll__submit'
510
+ submit.disabled = s.context.readOnly || s.submitting || s.loading || s.selected.size === 0
511
+ submit.textContent = s.submitting ? this._t('submitting', 'Submitting…') : this._t('vote', 'Vote')
512
+ submit.addEventListener('click', () => this.#submitVote(wrapper, s))
513
+ runtime.appendChild(submit)
514
+ return runtime
515
+ }
516
+
517
+ /** @param {PollState} s @returns {HTMLDivElement} */
518
+ #buildVoters(s) {
519
+ const section = document.createElement('div')
520
+ section.className = 'oe-poll__voters'
521
+ const heading = document.createElement('div')
522
+ heading.className = 'oe-poll__voters-title'
523
+ const total = s.runtime.votersTotal ?? s.runtime.voters?.length ?? 0
524
+ heading.textContent = `${this._t('voters', 'Voters')}: ${total}`
525
+ section.appendChild(heading)
526
+ const list = document.createElement('ul')
527
+ for (const voter of s.runtime.voters || []) {
528
+ const item = document.createElement('li')
529
+ if (voter.avatar) {
530
+ const image = document.createElement('img')
531
+ setSafeUrlAttribute(image, 'src', voter.avatar, 'media')
532
+ image.alt = ''
533
+ image.width = 24
534
+ image.height = 24
535
+ item.appendChild(image)
536
+ }
537
+ const name = document.createElement('span')
538
+ name.textContent = voter.name || this._t('anonymousVoter', 'Anonymous voter')
539
+ item.appendChild(name)
540
+ list.appendChild(item)
541
+ }
542
+ section.appendChild(list)
543
+ return section
544
+ }
545
+
546
+ /** @param {HTMLElement} wrapper @param {PollState} s @returns {void} */
547
+ #submitVote(wrapper, s) {
548
+ if (s.context.readOnly || s.submitting || s.selected.size === 0) return
549
+ const optionIds = [...s.selected]
550
+ if (!this._config.dataSource) {
551
+ s.context.mutate(() => {
552
+ this.#syncFromDom(wrapper)
553
+ const previous = s.runtime.currentUserVote || []
554
+ s.runtime = applyLocalPollVote(s.runtime, previous, optionIds, s.data.options.map(option => option.id))
555
+ s.hasVoted = true
556
+ s.data.initialResults = structuredClone(s.runtime)
557
+ this.#replaceRuntime(wrapper, s)
558
+ })
559
+ return
560
+ }
561
+ if (!s.data.pollId) {
562
+ this.#reportDataSourceError(wrapper, s, new Error('Poll dataSource requires pollId'))
563
+ return
564
+ }
565
+
566
+ const dataSource = this._config.dataSource
567
+ const controller = s.abortController
568
+ if (!controller || controller.signal.aborted) return
569
+ const connectionVersion = s.connectionVersion
570
+ const voteVersion = ++s.voteVersion
571
+ s.submitting = true
572
+ s.error = false
573
+ this.#replaceRuntime(wrapper, s)
574
+
575
+ // Invoke the consumer callback synchronously with the user action. The
576
+ // pending flag is already set, so subscription-driven re-renders cannot
577
+ // admit a second submission. Wrap only the returned value as a promise;
578
+ // deferring the callback itself would make observable submission timing
579
+ // depend on an unrelated microtask.
580
+ let voteRequest
581
+ try {
582
+ voteRequest = dataSource.vote({
583
+ pollId: /** @type {string} */ (s.data.pollId),
584
+ optionIds,
585
+ revision: s.runtime.revision,
586
+ signal: controller.signal,
587
+ })
588
+ } catch (error) {
589
+ if (stateMap.get(wrapper) === s && !controller.signal.aborted
590
+ && connectionVersion === s.connectionVersion && voteVersion === s.voteVersion) {
591
+ s.submitting = false
592
+ this.#reportDataSourceError(wrapper, s, error)
593
+ }
594
+ return
595
+ }
596
+
597
+ void Promise.resolve(voteRequest).then(results => {
598
+ if (stateMap.get(wrapper) !== s || controller.signal.aborted
599
+ || connectionVersion !== s.connectionVersion || voteVersion !== s.voteVersion) return
600
+ this.#acceptRuntimeResults(wrapper, s, results, true)
601
+ }).catch(error => {
602
+ if (controller.signal.aborted || stateMap.get(wrapper) !== s
603
+ || connectionVersion !== s.connectionVersion || voteVersion !== s.voteVersion) return
604
+ this.#reportDataSourceError(wrapper, s, error)
605
+ }).finally(() => {
606
+ if (stateMap.get(wrapper) !== s || controller.signal.aborted
607
+ || connectionVersion !== s.connectionVersion || voteVersion !== s.voteVersion) return
608
+ s.submitting = false
609
+ this.#replaceRuntime(wrapper, s)
610
+ })
611
+ }
612
+
613
+ /** @param {HTMLElement} wrapper @param {PollState} s @param {PollResults} results @param {boolean} [confirmedVote] @returns {void} */
614
+ #acceptRuntimeResults(wrapper, s, results, confirmedVote = false) {
615
+ const normalized = normalizePollResults(results, s.data.options.map(option => option.id), this._config.maxVoters, s.data.type)
616
+ let accepted
617
+ try {
618
+ accepted = shouldAcceptPollRevision(normalized.revision, s.runtime.revision, this._config.compareRevisions)
619
+ } catch (error) {
620
+ this.#reportDataSourceError(wrapper, s, error)
621
+ return
622
+ }
623
+ if (confirmedVote) s.hasVoted = true
624
+ if (!accepted) {
625
+ s.error = false
626
+ this.#replaceRuntime(wrapper, s)
627
+ return
628
+ }
629
+ s.runtime = normalized
630
+ s.selected = new Set(normalized.currentUserVote || s.selected)
631
+ s.hasVoted ||= (normalized.currentUserVote?.length || 0) > 0
632
+ s.error = false
633
+ this.#syncSelectionUi(wrapper, s)
634
+ this.#replaceRuntime(wrapper, s)
635
+ }
636
+
637
+ /** @param {HTMLElement} wrapper @param {PollState} s @param {unknown} error @returns {void} */
638
+ #reportDataSourceError(wrapper, s, error) {
639
+ s.error = true
640
+ try { this._config.onError?.(error) } catch {}
641
+ this.#replaceRuntime(wrapper, s)
642
+ }
643
+
644
+ /** @param {HTMLElement} wrapper @returns {void} */
645
+ #connectDataSource(wrapper) {
646
+ const s = stateMap.get(wrapper)
647
+ const dataSource = this._config.dataSource
648
+ if (!s || !dataSource || !s.data.pollId) return
649
+
650
+ s.abortController?.abort()
651
+ try { s.unsubscribe?.() } catch (error) {
652
+ try { this._config.onError?.(error) } catch {}
653
+ }
654
+ const controller = new AbortController()
655
+ s.abortController = controller
656
+ const connectionVersion = ++s.connectionVersion
657
+ const loadVersion = ++s.loadVersion
658
+ s.voteVersion++
659
+ s.loading = true
660
+ s.error = false
661
+ this.#replaceRuntime(wrapper, s)
662
+
663
+ if (dataSource.subscribe) {
664
+ try {
665
+ const unsubscribe = dataSource.subscribe({
666
+ pollId: s.data.pollId,
667
+ signal: controller.signal,
668
+ onUpdate: results => {
669
+ if (stateMap.get(wrapper) === s && !controller.signal.aborted) {
670
+ s.loadVersion++
671
+ s.loading = false
672
+ this.#acceptRuntimeResults(wrapper, s, results)
673
+ }
674
+ },
675
+ onError: error => {
676
+ if (stateMap.get(wrapper) === s && !controller.signal.aborted) {
677
+ this.#reportDataSourceError(wrapper, s, error)
678
+ }
679
+ },
680
+ })
681
+ if (typeof unsubscribe === 'function') s.unsubscribe = unsubscribe
682
+ } catch (error) {
683
+ this.#reportDataSourceError(wrapper, s, error)
684
+ }
685
+ }
686
+
687
+ void Promise.resolve().then(() => dataSource.load({
688
+ pollId: /** @type {string} */ (s.data.pollId),
689
+ signal: controller.signal,
690
+ })).then(results => {
691
+ if (stateMap.get(wrapper) !== s || controller.signal.aborted
692
+ || connectionVersion !== s.connectionVersion || loadVersion !== s.loadVersion) return
693
+ this.#acceptRuntimeResults(wrapper, s, results)
694
+ }).catch(error => {
695
+ if (stateMap.get(wrapper) !== s || controller.signal.aborted
696
+ || connectionVersion !== s.connectionVersion || loadVersion !== s.loadVersion) return
697
+ this.#reportDataSourceError(wrapper, s, error)
698
+ }).finally(() => {
699
+ if (stateMap.get(wrapper) !== s || controller.signal.aborted
700
+ || connectionVersion !== s.connectionVersion || loadVersion !== s.loadVersion) return
701
+ s.loading = false
702
+ this.#replaceRuntime(wrapper, s)
703
+ })
704
+ }
705
+
706
+ /**
707
+ * @param {HTMLElement} wrapper
708
+ * @param {PollState} s
709
+ * @returns {HTMLDivElement}
710
+ */
711
+ #buildActions(wrapper, s) {
712
+ const actions = document.createElement('div')
713
+ actions.className = 'oe-poll__actions'
714
+
715
+ // Type toggle
716
+ const isSingle = s.data.type === 'single'
717
+ const typeBtn = document.createElement('button')
718
+ typeBtn.type = 'button'
719
+ typeBtn.className = 'oe-poll__action-btn'
720
+ const typeIcon = isSingle ? ICON_SINGLE : ICON_MULTI
721
+ const typeLabel = isSingle
722
+ ? this._t('single', 'Single choice')
723
+ : this._t('multiple', 'Multiple choice')
724
+ typeBtn.innerHTML = `${typeIcon} ${typeLabel}`
725
+ typeBtn.addEventListener('mousedown', (e) => e.preventDefault())
726
+ typeBtn.addEventListener('click', () => {
727
+ s.context.mutate(() => {
728
+ this.#syncFromDom(wrapper)
729
+ const previousVote = s.runtime.currentUserVote || []
730
+ s.data.type = s.data.type === 'single' ? 'multiple' : 'single'
731
+ if (s.data.type === 'single' && s.selected.size > 1) {
732
+ s.selected = new Set([[...s.selected][0]])
733
+ }
734
+ if (!this._config.dataSource && s.data.type === 'single' && previousVote.length > 1) {
735
+ s.runtime = applyLocalPollVote(
736
+ s.runtime,
737
+ previousVote,
738
+ previousVote.slice(0, 1),
739
+ s.data.options.map(option => option.id),
740
+ )
741
+ s.data.initialResults = structuredClone(s.runtime)
742
+ }
743
+ this.#reconcileRuntime(s)
744
+ this.#build(wrapper)
745
+ })
746
+ })
747
+ actions.appendChild(typeBtn)
748
+
749
+ actions.appendChild(this.#makeSep())
750
+
751
+ // Results toggle
752
+ const resultsBtn = document.createElement('button')
753
+ resultsBtn.type = 'button'
754
+ resultsBtn.className = 'oe-poll__action-btn'
755
+ resultsBtn.innerHTML = `${ICON_RESULTS} ${this.#resultsModeLabel(s.data.resultsMode)}`
756
+ resultsBtn.addEventListener('mousedown', (e) => e.preventDefault())
757
+ resultsBtn.addEventListener('click', () => {
758
+ s.context.mutate(() => {
759
+ this.#syncFromDom(wrapper)
760
+ const modes = /** @type {const} */ (['always', 'afterVote', 'hidden'])
761
+ const index = modes.indexOf(s.data.resultsMode)
762
+ s.data.resultsMode = modes[(index + 1) % modes.length]
763
+ this.#build(wrapper)
764
+ })
765
+ })
766
+ actions.appendChild(resultsBtn)
767
+
768
+ actions.appendChild(this.#makeSep())
769
+
770
+ const sortBtn = document.createElement('button')
771
+ sortBtn.type = 'button'
772
+ sortBtn.className = 'oe-poll__action-btn'
773
+ sortBtn.innerHTML = `${ICON_SORT} ${this._t('sort', 'Sort')}`
774
+ sortBtn.addEventListener('mousedown', (e) => e.preventDefault())
775
+ sortBtn.addEventListener('click', () => {
776
+ s.context.mutate(() => {
777
+ this.#syncFromDom(wrapper)
778
+ s.data.options = s.data.options
779
+ .map((option, index) => ({ option, index }))
780
+ .sort((a, b) => a.option.text.localeCompare(b.option.text) || a.index - b.index)
781
+ .map(entry => entry.option)
782
+ this.#build(wrapper)
783
+ })
784
+ })
785
+ actions.appendChild(sortBtn)
786
+
787
+ actions.appendChild(this.#makeSep())
788
+
789
+ // Delete
790
+ const deleteBtn = document.createElement('button')
791
+ deleteBtn.type = 'button'
792
+ deleteBtn.className = 'oe-poll__action-btn oe-poll__action-btn--danger'
793
+ deleteBtn.innerHTML = ICON_TRASH
794
+ deleteBtn.title = this._t('delete', 'Delete')
795
+ deleteBtn.addEventListener('mousedown', (e) => e.preventDefault())
796
+ deleteBtn.addEventListener('click', () => {
797
+ s.context.mutate(() => {
798
+ s.connectionVersion++
799
+ s.loadVersion++
800
+ s.voteVersion++
801
+ s.abortController?.abort()
802
+ try { s.unsubscribe?.() } catch (error) {
803
+ try { this._config.onError?.(error) } catch {}
804
+ }
805
+ s.abortController = null
806
+ s.unsubscribe = null
807
+ s.data = this.#defaultData()
808
+ s.runtime = normalizePollResults(undefined, s.data.options.map(option => option.id), this._config.maxVoters, s.data.type)
809
+ s.selected.clear()
810
+ s.hasVoted = false
811
+ this.#build(wrapper)
812
+ })
813
+ })
814
+ actions.appendChild(deleteBtn)
815
+
816
+ return actions
817
+ }
818
+
819
+ /** @returns {HTMLDivElement} */
820
+ #makeSep() {
821
+ const sep = document.createElement('div')
822
+ sep.className = 'oe-poll__actions-sep'
823
+ return sep
824
+ }
825
+ }