@fiduswriter/editor 0.1.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 (525) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +22 -0
  3. package/dist/bibliography/tools.js +53 -0
  4. package/dist/bibliography/tools.js.map +1 -0
  5. package/dist/citations/index.js +339 -0
  6. package/dist/citations/index.js.map +1 -0
  7. package/dist/citations/render.js +47 -0
  8. package/dist/citations/render.js.map +1 -0
  9. package/dist/clipboard/copy/index.js +2 -0
  10. package/dist/clipboard/copy/index.js.map +1 -0
  11. package/dist/clipboard/copy/schema.js +54 -0
  12. package/dist/clipboard/copy/schema.js.map +1 -0
  13. package/dist/clipboard/copy/serializers.js +132 -0
  14. package/dist/clipboard/copy/serializers.js.map +1 -0
  15. package/dist/clipboard/paste/fidus_writer.js +45 -0
  16. package/dist/clipboard/paste/fidus_writer.js.map +1 -0
  17. package/dist/clipboard/paste/general.js +76 -0
  18. package/dist/clipboard/paste/general.js.map +1 -0
  19. package/dist/clipboard/paste/google_docs.js +24 -0
  20. package/dist/clipboard/paste/google_docs.js.map +1 -0
  21. package/dist/clipboard/paste/html.js +68 -0
  22. package/dist/clipboard/paste/html.js.map +1 -0
  23. package/dist/clipboard/paste/index.js +3 -0
  24. package/dist/clipboard/paste/index.js.map +1 -0
  25. package/dist/clipboard/paste/libreoffice_writer.js +27 -0
  26. package/dist/clipboard/paste/libreoffice_writer.js.map +1 -0
  27. package/dist/clipboard/paste/microsoft_word.js +79 -0
  28. package/dist/clipboard/paste/microsoft_word.js.map +1 -0
  29. package/dist/clipboard/paste/text.js +41 -0
  30. package/dist/clipboard/paste/text.js.map +1 -0
  31. package/dist/collab/chat.js +154 -0
  32. package/dist/collab/chat.js.map +1 -0
  33. package/dist/collab/colors.js +62 -0
  34. package/dist/collab/colors.js.map +1 -0
  35. package/dist/collab/doc.js +1090 -0
  36. package/dist/collab/doc.js.map +1 -0
  37. package/dist/collab/index.js +75 -0
  38. package/dist/collab/index.js.map +1 -0
  39. package/dist/collab/merge/changeset.js +90 -0
  40. package/dist/collab/merge/changeset.js.map +1 -0
  41. package/dist/collab/merge/editor.js +708 -0
  42. package/dist/collab/merge/editor.js.map +1 -0
  43. package/dist/collab/merge/footnotes.js +149 -0
  44. package/dist/collab/merge/footnotes.js.map +1 -0
  45. package/dist/collab/merge/index.js +270 -0
  46. package/dist/collab/merge/index.js.map +1 -0
  47. package/dist/collab/merge/recreate_transform.js +259 -0
  48. package/dist/collab/merge/recreate_transform.js.map +1 -0
  49. package/dist/collab/merge/schema.js +117 -0
  50. package/dist/collab/merge/schema.js.map +1 -0
  51. package/dist/collab/merge/state_plugins/action.js +138 -0
  52. package/dist/collab/merge/state_plugins/action.js.map +1 -0
  53. package/dist/collab/merge/state_plugins/clipboard.js +32 -0
  54. package/dist/collab/merge/state_plugins/clipboard.js.map +1 -0
  55. package/dist/collab/merge/state_plugins/diff.js +541 -0
  56. package/dist/collab/merge/state_plugins/diff.js.map +1 -0
  57. package/dist/collab/merge/state_plugins/index.js +3 -0
  58. package/dist/collab/merge/state_plugins/index.js.map +1 -0
  59. package/dist/collab/merge/tools.js +175 -0
  60. package/dist/collab/merge/tools.js.map +1 -0
  61. package/dist/collab/templates.js +10 -0
  62. package/dist/collab/templates.js.map +1 -0
  63. package/dist/comments/comment.js +17 -0
  64. package/dist/comments/comment.js.map +1 -0
  65. package/dist/comments/editors/answer.js +43 -0
  66. package/dist/comments/editors/answer.js.map +1 -0
  67. package/dist/comments/editors/comment.js +278 -0
  68. package/dist/comments/editors/comment.js.map +1 -0
  69. package/dist/comments/editors/index.js +4 -0
  70. package/dist/comments/editors/index.js.map +1 -0
  71. package/dist/comments/editors/notify.js +13 -0
  72. package/dist/comments/editors/notify.js.map +1 -0
  73. package/dist/comments/editors/schema.js +60 -0
  74. package/dist/comments/editors/schema.js.map +1 -0
  75. package/dist/comments/index.js +11 -0
  76. package/dist/comments/index.js.map +1 -0
  77. package/dist/comments/interactions.js +379 -0
  78. package/dist/comments/interactions.js.map +1 -0
  79. package/dist/comments/store.js +438 -0
  80. package/dist/comments/store.js.map +1 -0
  81. package/dist/contacts/add_dialog.js +88 -0
  82. package/dist/contacts/add_dialog.js.map +1 -0
  83. package/dist/contacts/templates.js +23 -0
  84. package/dist/contacts/templates.js.map +1 -0
  85. package/dist/copyright_dialog/index.js +148 -0
  86. package/dist/copyright_dialog/index.js.map +1 -0
  87. package/dist/copyright_dialog/templates.js +48 -0
  88. package/dist/copyright_dialog/templates.js.map +1 -0
  89. package/dist/databases/bibliography.js +162 -0
  90. package/dist/databases/bibliography.js.map +1 -0
  91. package/dist/databases/images.js +260 -0
  92. package/dist/databases/images.js.map +1 -0
  93. package/dist/databases/index.js +55 -0
  94. package/dist/databases/index.js.map +1 -0
  95. package/dist/dialogs/citation.js +321 -0
  96. package/dist/dialogs/citation.js.map +1 -0
  97. package/dist/dialogs/code_block.js +192 -0
  98. package/dist/dialogs/code_block.js.map +1 -0
  99. package/dist/dialogs/contributor.js +132 -0
  100. package/dist/dialogs/contributor.js.map +1 -0
  101. package/dist/dialogs/figure.js +378 -0
  102. package/dist/dialogs/figure.js.map +1 -0
  103. package/dist/dialogs/index.js +11 -0
  104. package/dist/dialogs/index.js.map +1 -0
  105. package/dist/dialogs/language.js +47 -0
  106. package/dist/dialogs/language.js.map +1 -0
  107. package/dist/dialogs/link.js +243 -0
  108. package/dist/dialogs/link.js.map +1 -0
  109. package/dist/dialogs/math.js +121 -0
  110. package/dist/dialogs/math.js.map +1 -0
  111. package/dist/dialogs/ordered_list.js +67 -0
  112. package/dist/dialogs/ordered_list.js.map +1 -0
  113. package/dist/dialogs/revision.js +36 -0
  114. package/dist/dialogs/revision.js.map +1 -0
  115. package/dist/dialogs/subsup.js +109 -0
  116. package/dist/dialogs/subsup.js.map +1 -0
  117. package/dist/dialogs/table.js +217 -0
  118. package/dist/dialogs/table.js.map +1 -0
  119. package/dist/dialogs/templates.js +366 -0
  120. package/dist/dialogs/templates.js.map +1 -0
  121. package/dist/document_template/exporter.js +83 -0
  122. package/dist/document_template/exporter.js.map +1 -0
  123. package/dist/document_template/index.js +327 -0
  124. package/dist/document_template/index.js.map +1 -0
  125. package/dist/documents/access_rights/index.js +532 -0
  126. package/dist/documents/access_rights/index.js.map +1 -0
  127. package/dist/documents/access_rights/templates.js +150 -0
  128. package/dist/documents/access_rights/templates.js.map +1 -0
  129. package/dist/e2ee/encryptor.js +201 -0
  130. package/dist/e2ee/encryptor.js.map +1 -0
  131. package/dist/e2ee/key-manager.js +171 -0
  132. package/dist/e2ee/key-manager.js.map +1 -0
  133. package/dist/e2ee/passphrase-crypto.js +365 -0
  134. package/dist/e2ee/passphrase-crypto.js.map +1 -0
  135. package/dist/e2ee/passphrase-dialog.js +548 -0
  136. package/dist/e2ee/passphrase-dialog.js.map +1 -0
  137. package/dist/e2ee/passphrase-manager.js +350 -0
  138. package/dist/e2ee/passphrase-manager.js.map +1 -0
  139. package/dist/e2ee/password-dialog.js +552 -0
  140. package/dist/e2ee/password-dialog.js.map +1 -0
  141. package/dist/e2ee/snapshot-manager.js +238 -0
  142. package/dist/e2ee/snapshot-manager.js.map +1 -0
  143. package/dist/exporter/native/copy.js +29 -0
  144. package/dist/exporter/native/copy.js.map +1 -0
  145. package/dist/exporter/native/file.js +19 -0
  146. package/dist/exporter/native/file.js.map +1 -0
  147. package/dist/exporter/native/index.js +4 -0
  148. package/dist/exporter/native/index.js.map +1 -0
  149. package/dist/exporter/native/revision.js +54 -0
  150. package/dist/exporter/native/revision.js.map +1 -0
  151. package/dist/exporter/native/zip.js +2 -0
  152. package/dist/exporter/native/zip.js.map +1 -0
  153. package/dist/footnotes/editor.js +180 -0
  154. package/dist/footnotes/editor.js.map +1 -0
  155. package/dist/footnotes/index.js +15 -0
  156. package/dist/footnotes/index.js.map +1 -0
  157. package/dist/footnotes/layout.js +125 -0
  158. package/dist/footnotes/layout.js.map +1 -0
  159. package/dist/footnotes/state_plugins/access_rights.js +25 -0
  160. package/dist/footnotes/state_plugins/access_rights.js.map +1 -0
  161. package/dist/footnotes/state_plugins/index.js +2 -0
  162. package/dist/footnotes/state_plugins/index.js.map +1 -0
  163. package/dist/images/edit_dialog/edit_dialog/index.js +186 -0
  164. package/dist/images/edit_dialog/edit_dialog/index.js.map +1 -0
  165. package/dist/images/edit_dialog/edit_dialog/model.js +152 -0
  166. package/dist/images/edit_dialog/edit_dialog/model.js.map +1 -0
  167. package/dist/images/edit_dialog/edit_dialog/templates.js +33 -0
  168. package/dist/images/edit_dialog/edit_dialog/templates.js.map +1 -0
  169. package/dist/images/edit_dialog/model.js +6 -0
  170. package/dist/images/edit_dialog/model.js.map +1 -0
  171. package/dist/images/selection_dialog/index.js +149 -0
  172. package/dist/images/selection_dialog/index.js.map +1 -0
  173. package/dist/index.js +1002 -0
  174. package/dist/index.js.map +1 -0
  175. package/dist/keymap.js +73 -0
  176. package/dist/keymap.js.map +1 -0
  177. package/dist/marginboxes/index.js +674 -0
  178. package/dist/marginboxes/index.js.map +1 -0
  179. package/dist/marginboxes/templates.js +447 -0
  180. package/dist/marginboxes/templates.js.map +1 -0
  181. package/dist/menus/code_block/index.js +2 -0
  182. package/dist/menus/code_block/index.js.map +1 -0
  183. package/dist/menus/code_block/model.js +49 -0
  184. package/dist/menus/code_block/model.js.map +1 -0
  185. package/dist/menus/figure/index.js +3 -0
  186. package/dist/menus/figure/index.js.map +1 -0
  187. package/dist/menus/figure/model.js +80 -0
  188. package/dist/menus/figure/model.js.map +1 -0
  189. package/dist/menus/figure/utils.js +6 -0
  190. package/dist/menus/figure/utils.js.map +1 -0
  191. package/dist/menus/headerbar/index.js +3 -0
  192. package/dist/menus/headerbar/index.js.map +1 -0
  193. package/dist/menus/headerbar/model.js +743 -0
  194. package/dist/menus/headerbar/model.js.map +1 -0
  195. package/dist/menus/headerbar/view.js +579 -0
  196. package/dist/menus/headerbar/view.js.map +1 -0
  197. package/dist/menus/image/index.js +2 -0
  198. package/dist/menus/image/index.js.map +1 -0
  199. package/dist/menus/image/model.js +32 -0
  200. package/dist/menus/image/model.js.map +1 -0
  201. package/dist/menus/index.js +10 -0
  202. package/dist/menus/index.js.map +1 -0
  203. package/dist/menus/navigator/index.js +2 -0
  204. package/dist/menus/navigator/index.js.map +1 -0
  205. package/dist/menus/navigator/model.js +29 -0
  206. package/dist/menus/navigator/model.js.map +1 -0
  207. package/dist/menus/ordered_list/index.js +2 -0
  208. package/dist/menus/ordered_list/index.js.map +1 -0
  209. package/dist/menus/ordered_list/model.js +17 -0
  210. package/dist/menus/ordered_list/model.js.map +1 -0
  211. package/dist/menus/selection/index.js +3 -0
  212. package/dist/menus/selection/index.js.map +1 -0
  213. package/dist/menus/selection/model.js +108 -0
  214. package/dist/menus/selection/model.js.map +1 -0
  215. package/dist/menus/selection/view.js +125 -0
  216. package/dist/menus/selection/view.js.map +1 -0
  217. package/dist/menus/table/index.js +2 -0
  218. package/dist/menus/table/index.js.map +1 -0
  219. package/dist/menus/table/model.js +319 -0
  220. package/dist/menus/table/model.js.map +1 -0
  221. package/dist/menus/toolbar/index.js +3 -0
  222. package/dist/menus/toolbar/index.js.map +1 -0
  223. package/dist/menus/toolbar/model.js +747 -0
  224. package/dist/menus/toolbar/model.js.map +1 -0
  225. package/dist/menus/toolbar/view.js +314 -0
  226. package/dist/menus/toolbar/view.js.map +1 -0
  227. package/dist/navigator/index.js +435 -0
  228. package/dist/navigator/index.js.map +1 -0
  229. package/dist/no_collab_save/index.js +169 -0
  230. package/dist/no_collab_save/index.js.map +1 -0
  231. package/dist/plugins/citation_dialog/index.js +2 -0
  232. package/dist/plugins/citation_dialog/index.js.map +1 -0
  233. package/dist/plugins/editor/index.js +2 -0
  234. package/dist/plugins/editor/index.js.map +1 -0
  235. package/dist/state_plugins/access_rights.js +30 -0
  236. package/dist/state_plugins/access_rights.js.map +1 -0
  237. package/dist/state_plugins/citation_render.js +78 -0
  238. package/dist/state_plugins/citation_render.js.map +1 -0
  239. package/dist/state_plugins/clipboard.js +217 -0
  240. package/dist/state_plugins/clipboard.js.map +1 -0
  241. package/dist/state_plugins/code_block.js +165 -0
  242. package/dist/state_plugins/code_block.js.map +1 -0
  243. package/dist/state_plugins/collab_carets.js +115 -0
  244. package/dist/state_plugins/collab_carets.js.map +1 -0
  245. package/dist/state_plugins/comments.js +197 -0
  246. package/dist/state_plugins/comments.js.map +1 -0
  247. package/dist/state_plugins/contributor_input/add_button.js +101 -0
  248. package/dist/state_plugins/contributor_input/add_button.js.map +1 -0
  249. package/dist/state_plugins/contributor_input/dropup.js +273 -0
  250. package/dist/state_plugins/contributor_input/dropup.js.map +1 -0
  251. package/dist/state_plugins/contributor_input/helpers.js +23 -0
  252. package/dist/state_plugins/contributor_input/helpers.js.map +1 -0
  253. package/dist/state_plugins/contributor_input/index.js +3 -0
  254. package/dist/state_plugins/contributor_input/index.js.map +1 -0
  255. package/dist/state_plugins/contributor_input/node_view.js +76 -0
  256. package/dist/state_plugins/contributor_input/node_view.js.map +1 -0
  257. package/dist/state_plugins/contributor_input/plugin.js +236 -0
  258. package/dist/state_plugins/contributor_input/plugin.js.map +1 -0
  259. package/dist/state_plugins/document_template.js +213 -0
  260. package/dist/state_plugins/document_template.js.map +1 -0
  261. package/dist/state_plugins/figure.js +90 -0
  262. package/dist/state_plugins/figure.js.map +1 -0
  263. package/dist/state_plugins/footnote_markers.js +187 -0
  264. package/dist/state_plugins/footnote_markers.js.map +1 -0
  265. package/dist/state_plugins/headerbar.js +10 -0
  266. package/dist/state_plugins/headerbar.js.map +1 -0
  267. package/dist/state_plugins/index.js +27 -0
  268. package/dist/state_plugins/index.js.map +1 -0
  269. package/dist/state_plugins/inline_math.js +719 -0
  270. package/dist/state_plugins/inline_math.js.map +1 -0
  271. package/dist/state_plugins/inline_reference/dropup.js +182 -0
  272. package/dist/state_plugins/inline_reference/dropup.js.map +1 -0
  273. package/dist/state_plugins/inline_reference/index.js +2 -0
  274. package/dist/state_plugins/inline_reference/index.js.map +1 -0
  275. package/dist/state_plugins/inline_reference/plugin.js +1134 -0
  276. package/dist/state_plugins/inline_reference/plugin.js.map +1 -0
  277. package/dist/state_plugins/jump_hidden_nodes.js +47 -0
  278. package/dist/state_plugins/jump_hidden_nodes.js.map +1 -0
  279. package/dist/state_plugins/links.js +622 -0
  280. package/dist/state_plugins/links.js.map +1 -0
  281. package/dist/state_plugins/marginboxes.js +13 -0
  282. package/dist/state_plugins/marginboxes.js.map +1 -0
  283. package/dist/state_plugins/ordered_list_menu.js +72 -0
  284. package/dist/state_plugins/ordered_list_menu.js.map +1 -0
  285. package/dist/state_plugins/placeholders.js +98 -0
  286. package/dist/state_plugins/placeholders.js.map +1 -0
  287. package/dist/state_plugins/search.js +212 -0
  288. package/dist/state_plugins/search.js.map +1 -0
  289. package/dist/state_plugins/selection_menu.js +10 -0
  290. package/dist/state_plugins/selection_menu.js.map +1 -0
  291. package/dist/state_plugins/settings.js +191 -0
  292. package/dist/state_plugins/settings.js.map +1 -0
  293. package/dist/state_plugins/table.js +104 -0
  294. package/dist/state_plugins/table.js.map +1 -0
  295. package/dist/state_plugins/tag_input/helpers.js +55 -0
  296. package/dist/state_plugins/tag_input/helpers.js.map +1 -0
  297. package/dist/state_plugins/tag_input/index.js +3 -0
  298. package/dist/state_plugins/tag_input/index.js.map +1 -0
  299. package/dist/state_plugins/tag_input/node_view.js +77 -0
  300. package/dist/state_plugins/tag_input/node_view.js.map +1 -0
  301. package/dist/state_plugins/tag_input/plugin.js +199 -0
  302. package/dist/state_plugins/tag_input/plugin.js.map +1 -0
  303. package/dist/state_plugins/tag_input/tag_editor.js +159 -0
  304. package/dist/state_plugins/tag_input/tag_editor.js.map +1 -0
  305. package/dist/state_plugins/tag_input/tag_editor_plugins.js +61 -0
  306. package/dist/state_plugins/tag_input/tag_editor_plugins.js.map +1 -0
  307. package/dist/state_plugins/toc_render.js +142 -0
  308. package/dist/state_plugins/toc_render.js.map +1 -0
  309. package/dist/state_plugins/toolbar.js +10 -0
  310. package/dist/state_plugins/toolbar.js.map +1 -0
  311. package/dist/state_plugins/track/find_selected_changes.js +82 -0
  312. package/dist/state_plugins/track/find_selected_changes.js.map +1 -0
  313. package/dist/state_plugins/track/helpers.js +67 -0
  314. package/dist/state_plugins/track/helpers.js.map +1 -0
  315. package/dist/state_plugins/track/index.js +3 -0
  316. package/dist/state_plugins/track/index.js.map +1 -0
  317. package/dist/state_plugins/track/plugin.js +114 -0
  318. package/dist/state_plugins/track/plugin.js.map +1 -0
  319. package/dist/tools/index.js +4 -0
  320. package/dist/tools/index.js.map +1 -0
  321. package/dist/tools/key_bindings/index.js +20 -0
  322. package/dist/tools/key_bindings/index.js.map +1 -0
  323. package/dist/tools/key_bindings/templates.js +68 -0
  324. package/dist/tools/key_bindings/templates.js.map +1 -0
  325. package/dist/tools/search_replace/index.js +275 -0
  326. package/dist/tools/search_replace/index.js.map +1 -0
  327. package/dist/tools/search_replace/templates.js +18 -0
  328. package/dist/tools/search_replace/templates.js.map +1 -0
  329. package/dist/tools/word_count/index.js +40 -0
  330. package/dist/tools/word_count/index.js.map +1 -0
  331. package/dist/tools/word_count/templates.js +27 -0
  332. package/dist/tools/word_count/templates.js.map +1 -0
  333. package/dist/track/accept.js +66 -0
  334. package/dist/track/accept.js.map +1 -0
  335. package/dist/track/accept_all.js +51 -0
  336. package/dist/track/accept_all.js.map +1 -0
  337. package/dist/track/accept_all_no_insertions.js +63 -0
  338. package/dist/track/accept_all_no_insertions.js.map +1 -0
  339. package/dist/track/amend_transaction.js +390 -0
  340. package/dist/track/amend_transaction.js.map +1 -0
  341. package/dist/track/delete.js +62 -0
  342. package/dist/track/delete.js.map +1 -0
  343. package/dist/track/index.js +6 -0
  344. package/dist/track/index.js.map +1 -0
  345. package/dist/track/mod.js +86 -0
  346. package/dist/track/mod.js.map +1 -0
  347. package/dist/track/reject.js +67 -0
  348. package/dist/track/reject.js.map +1 -0
  349. package/dist/track/reject_all.js +56 -0
  350. package/dist/track/reject_all.js.map +1 -0
  351. package/package.json +80 -0
  352. package/src/bibliography/tools.js +58 -0
  353. package/src/citations/index.js +443 -0
  354. package/src/citations/render.js +68 -0
  355. package/src/clipboard/copy/index.js +1 -0
  356. package/src/clipboard/copy/schema.js +62 -0
  357. package/src/clipboard/copy/serializers.js +179 -0
  358. package/src/clipboard/paste/fidus_writer.js +55 -0
  359. package/src/clipboard/paste/general.js +80 -0
  360. package/src/clipboard/paste/google_docs.js +26 -0
  361. package/src/clipboard/paste/html.js +76 -0
  362. package/src/clipboard/paste/index.js +2 -0
  363. package/src/clipboard/paste/libreoffice_writer.js +32 -0
  364. package/src/clipboard/paste/microsoft_word.js +87 -0
  365. package/src/clipboard/paste/text.js +58 -0
  366. package/src/collab/chat.js +195 -0
  367. package/src/collab/colors.js +67 -0
  368. package/src/collab/doc.js +1436 -0
  369. package/src/collab/index.js +81 -0
  370. package/src/collab/merge/changeset.js +103 -0
  371. package/src/collab/merge/editor.js +1065 -0
  372. package/src/collab/merge/footnotes.js +175 -0
  373. package/src/collab/merge/index.js +401 -0
  374. package/src/collab/merge/recreate_transform.js +326 -0
  375. package/src/collab/merge/schema.js +135 -0
  376. package/src/collab/merge/state_plugins/action.js +171 -0
  377. package/src/collab/merge/state_plugins/clipboard.js +32 -0
  378. package/src/collab/merge/state_plugins/diff.js +780 -0
  379. package/src/collab/merge/state_plugins/index.js +2 -0
  380. package/src/collab/merge/tools.js +217 -0
  381. package/src/collab/templates.js +10 -0
  382. package/src/comments/comment.js +29 -0
  383. package/src/comments/editors/answer.js +55 -0
  384. package/src/comments/editors/comment.js +318 -0
  385. package/src/comments/editors/index.js +4 -0
  386. package/src/comments/editors/notify.js +13 -0
  387. package/src/comments/editors/schema.js +65 -0
  388. package/src/comments/index.js +11 -0
  389. package/src/comments/interactions.js +465 -0
  390. package/src/comments/store.js +513 -0
  391. package/src/contacts/add_dialog.js +110 -0
  392. package/src/contacts/templates.js +28 -0
  393. package/src/copyright_dialog/index.js +179 -0
  394. package/src/copyright_dialog/templates.js +56 -0
  395. package/src/databases/bibliography.js +179 -0
  396. package/src/databases/images.js +320 -0
  397. package/src/databases/index.js +69 -0
  398. package/src/dialogs/citation.js +428 -0
  399. package/src/dialogs/code_block.js +242 -0
  400. package/src/dialogs/contributor.js +173 -0
  401. package/src/dialogs/figure.js +479 -0
  402. package/src/dialogs/index.js +10 -0
  403. package/src/dialogs/language.js +58 -0
  404. package/src/dialogs/link.js +358 -0
  405. package/src/dialogs/math.js +148 -0
  406. package/src/dialogs/ordered_list.js +84 -0
  407. package/src/dialogs/revision.js +43 -0
  408. package/src/dialogs/subsup.js +116 -0
  409. package/src/dialogs/table.js +258 -0
  410. package/src/dialogs/templates.js +426 -0
  411. package/src/document_template/exporter.js +97 -0
  412. package/src/document_template/index.js +483 -0
  413. package/src/documents/access_rights/index.js +693 -0
  414. package/src/documents/access_rights/templates.js +178 -0
  415. package/src/e2ee/encryptor.js +228 -0
  416. package/src/e2ee/key-manager.js +202 -0
  417. package/src/e2ee/passphrase-crypto.js +606 -0
  418. package/src/e2ee/passphrase-dialog.js +655 -0
  419. package/src/e2ee/passphrase-manager.js +502 -0
  420. package/src/e2ee/password-dialog.js +652 -0
  421. package/src/e2ee/snapshot-manager.js +305 -0
  422. package/src/exporter/native/copy.js +54 -0
  423. package/src/exporter/native/file.js +37 -0
  424. package/src/exporter/native/index.js +3 -0
  425. package/src/exporter/native/revision.js +86 -0
  426. package/src/exporter/native/zip.js +1 -0
  427. package/src/footnotes/editor.js +227 -0
  428. package/src/footnotes/index.js +16 -0
  429. package/src/footnotes/layout.js +190 -0
  430. package/src/footnotes/state_plugins/access_rights.js +39 -0
  431. package/src/footnotes/state_plugins/index.js +1 -0
  432. package/src/images/edit_dialog/edit_dialog/index.js +222 -0
  433. package/src/images/edit_dialog/edit_dialog/model.js +183 -0
  434. package/src/images/edit_dialog/edit_dialog/templates.js +41 -0
  435. package/src/images/edit_dialog/model.js +5 -0
  436. package/src/images/selection_dialog/index.js +176 -0
  437. package/src/index.js +1252 -0
  438. package/src/keymap.js +102 -0
  439. package/src/marginboxes/index.js +946 -0
  440. package/src/marginboxes/templates.js +573 -0
  441. package/src/menus/code_block/index.js +1 -0
  442. package/src/menus/code_block/model.js +52 -0
  443. package/src/menus/figure/index.js +2 -0
  444. package/src/menus/figure/model.js +91 -0
  445. package/src/menus/figure/utils.js +5 -0
  446. package/src/menus/headerbar/index.js +2 -0
  447. package/src/menus/headerbar/model.js +1077 -0
  448. package/src/menus/headerbar/view.js +675 -0
  449. package/src/menus/image/index.js +1 -0
  450. package/src/menus/image/model.js +32 -0
  451. package/src/menus/index.js +9 -0
  452. package/src/menus/navigator/index.js +1 -0
  453. package/src/menus/navigator/model.js +28 -0
  454. package/src/menus/ordered_list/index.js +1 -0
  455. package/src/menus/ordered_list/model.js +19 -0
  456. package/src/menus/selection/index.js +2 -0
  457. package/src/menus/selection/model.js +134 -0
  458. package/src/menus/selection/view.js +154 -0
  459. package/src/menus/table/index.js +1 -0
  460. package/src/menus/table/model.js +414 -0
  461. package/src/menus/toolbar/index.js +2 -0
  462. package/src/menus/toolbar/model.js +920 -0
  463. package/src/menus/toolbar/view.js +354 -0
  464. package/src/navigator/index.js +515 -0
  465. package/src/no_collab_save/index.js +209 -0
  466. package/src/plugins/citation_dialog/index.js +1 -0
  467. package/src/plugins/editor/index.js +1 -0
  468. package/src/state_plugins/access_rights.js +47 -0
  469. package/src/state_plugins/citation_render.js +88 -0
  470. package/src/state_plugins/clipboard.js +289 -0
  471. package/src/state_plugins/code_block.js +201 -0
  472. package/src/state_plugins/collab_carets.js +152 -0
  473. package/src/state_plugins/comments.js +259 -0
  474. package/src/state_plugins/contributor_input/add_button.js +134 -0
  475. package/src/state_plugins/contributor_input/dropup.js +318 -0
  476. package/src/state_plugins/contributor_input/helpers.js +24 -0
  477. package/src/state_plugins/contributor_input/index.js +2 -0
  478. package/src/state_plugins/contributor_input/node_view.js +86 -0
  479. package/src/state_plugins/contributor_input/plugin.js +318 -0
  480. package/src/state_plugins/document_template.js +315 -0
  481. package/src/state_plugins/figure.js +108 -0
  482. package/src/state_plugins/footnote_markers.js +238 -0
  483. package/src/state_plugins/headerbar.js +12 -0
  484. package/src/state_plugins/index.js +73 -0
  485. package/src/state_plugins/inline_math.js +918 -0
  486. package/src/state_plugins/inline_reference/dropup.js +208 -0
  487. package/src/state_plugins/inline_reference/index.js +5 -0
  488. package/src/state_plugins/inline_reference/plugin.js +1429 -0
  489. package/src/state_plugins/jump_hidden_nodes.js +58 -0
  490. package/src/state_plugins/links.js +830 -0
  491. package/src/state_plugins/marginboxes.js +14 -0
  492. package/src/state_plugins/ordered_list_menu.js +84 -0
  493. package/src/state_plugins/placeholders.js +123 -0
  494. package/src/state_plugins/search.js +251 -0
  495. package/src/state_plugins/selection_menu.js +12 -0
  496. package/src/state_plugins/settings.js +223 -0
  497. package/src/state_plugins/table.js +127 -0
  498. package/src/state_plugins/tag_input/helpers.js +69 -0
  499. package/src/state_plugins/tag_input/index.js +2 -0
  500. package/src/state_plugins/tag_input/node_view.js +85 -0
  501. package/src/state_plugins/tag_input/plugin.js +278 -0
  502. package/src/state_plugins/tag_input/tag_editor.js +202 -0
  503. package/src/state_plugins/tag_input/tag_editor_plugins.js +74 -0
  504. package/src/state_plugins/toc_render.js +160 -0
  505. package/src/state_plugins/toolbar.js +12 -0
  506. package/src/state_plugins/track/find_selected_changes.js +107 -0
  507. package/src/state_plugins/track/helpers.js +108 -0
  508. package/src/state_plugins/track/index.js +6 -0
  509. package/src/state_plugins/track/plugin.js +140 -0
  510. package/src/tools/index.js +3 -0
  511. package/src/tools/key_bindings/index.js +21 -0
  512. package/src/tools/key_bindings/templates.js +68 -0
  513. package/src/tools/search_replace/index.js +421 -0
  514. package/src/tools/search_replace/templates.js +19 -0
  515. package/src/tools/word_count/index.js +59 -0
  516. package/src/tools/word_count/templates.js +34 -0
  517. package/src/track/accept.js +102 -0
  518. package/src/track/accept_all.js +103 -0
  519. package/src/track/accept_all_no_insertions.js +102 -0
  520. package/src/track/amend_transaction.js +562 -0
  521. package/src/track/delete.js +92 -0
  522. package/src/track/index.js +8 -0
  523. package/src/track/mod.js +116 -0
  524. package/src/track/reject.js +116 -0
  525. package/src/track/reject_all.js +121 -0
@@ -0,0 +1,652 @@
1
+ /**
2
+ * E2EE Password Dialog - UI for entering, creating, and changing
3
+ * document passwords for end-to-end encrypted documents.
4
+ *
5
+ * Provides three dialog types:
6
+ * 1. Enter password - when opening an encrypted document
7
+ * 2. Create password - when creating a new encrypted document
8
+ * 3. Change password - when changing the password of an existing encrypted document
9
+ *
10
+ * Password requirements:
11
+ * - Minimum 5 characters
12
+ * While the requirements are not satisfactory for security,
13
+ * the user is shown a degree of weakness and is therefore encouraged to use a stronger password.
14
+ */
15
+
16
+ import {Dialog, escapeText} from "fwtoolkit"
17
+
18
+ /**
19
+ * Validate a password against the minimum requirements.
20
+ *
21
+ * @param {string} password - The password to validate
22
+ * @returns {{valid: boolean, message: string}} Validation result
23
+ */
24
+ export function validatePassword(password) {
25
+ if (!password || password.length < 5) {
26
+ return {
27
+ valid: false,
28
+ message: gettext("Password must be at least 5 characters long.")
29
+ }
30
+ }
31
+ return {valid: true, message: ""}
32
+ }
33
+
34
+ /**
35
+ * Calculate a rough password strength score (0-4).
36
+ *
37
+ * Based on length, character variety, and common patterns.
38
+ * This is a simple heuristic — not a substitute for a proper
39
+ * password strength estimator like zxcvbn, but sufficient for
40
+ * a basic strength meter.
41
+ *
42
+ * @param {string} password - The password to evaluate
43
+ * @returns {number} Strength score from 0 (very weak) to 4 (very strong)
44
+ */
45
+ export function passwordStrength(password) {
46
+ if (!password) {
47
+ return 0
48
+ }
49
+
50
+ let score = 0
51
+
52
+ // Length contributions
53
+ if (password.length >= 12) {
54
+ score++
55
+ }
56
+ if (password.length >= 16) {
57
+ score++
58
+ }
59
+ if (password.length >= 20) {
60
+ score++
61
+ }
62
+
63
+ // Character variety contributions
64
+ const hasLower = /[a-z]/.test(password)
65
+ const hasUpper = /[A-Z]/.test(password)
66
+ const hasDigit = /[0-9]/.test(password)
67
+ const hasSpecial = /[^a-zA-Z0-9]/.test(password)
68
+
69
+ const varietyCount = [hasLower, hasUpper, hasDigit, hasSpecial].filter(
70
+ Boolean
71
+ ).length
72
+ if (varietyCount >= 3) {
73
+ score++
74
+ }
75
+
76
+ // Penalize very common patterns
77
+ const commonPatterns = [
78
+ /^123456/,
79
+ /^123123/,
80
+ /^password/i,
81
+ /^qwerty/i,
82
+ /^abc123/i,
83
+ /(.)\1{3,}/ // Repeated characters (4+ in a row)
84
+ ]
85
+ for (const pattern of commonPatterns) {
86
+ if (pattern.test(password)) {
87
+ score = Math.max(0, score - 2)
88
+ break
89
+ }
90
+ }
91
+
92
+ return Math.min(4, Math.max(0, score))
93
+ }
94
+
95
+ /**
96
+ * Get a CSS class and label for a password strength score.
97
+ *
98
+ * @param {number} score - Strength score from passwordStrength()
99
+ * @returns {{cssClass: string, label: string}}
100
+ */
101
+ export function strengthInfo(score) {
102
+ const levels = [
103
+ {cssClass: "very-weak", label: gettext("Very weak")},
104
+ {cssClass: "weak", label: gettext("Weak")},
105
+ {cssClass: "fair", label: gettext("Fair")},
106
+ {cssClass: "strong", label: gettext("Strong")},
107
+ {cssClass: "very-strong", label: gettext("Very strong")}
108
+ ]
109
+ return levels[score] || levels[0]
110
+ }
111
+
112
+ /**
113
+ * Show a dialog for entering the password to decrypt an E2EE document.
114
+ *
115
+ * This dialog is shown when a user opens an encrypted document.
116
+ * The user must enter the password to derive the decryption key.
117
+ *
118
+ * If the URL contains a fragment (e.g., #PASSWORD from a share link),
119
+ * the password field is pre-filled and the dialog can be auto-submitted.
120
+ *
121
+ * @param {Function} onPassword - Callback called with the entered password string
122
+ * @param {string} [urlFragment] - Password from URL fragment (share link), if available
123
+ * @returns {Promise<void>}
124
+ */
125
+ export function enterPasswordDialog(
126
+ onPassword,
127
+ urlFragment = "",
128
+ onCancel = null
129
+ ) {
130
+ return new Promise(resolve => {
131
+ const dialogId = "e2ee-enter-password"
132
+
133
+ // If password was provided via URL fragment, use it directly
134
+ if (urlFragment && urlFragment.length > 0) {
135
+ onPassword(urlFragment)
136
+ resolve()
137
+ return
138
+ }
139
+
140
+ const body = `
141
+ <div class="e2ee-password-dialog">
142
+ <p>${gettext("This document is end-to-end encrypted. Enter the password to decrypt it.")}</p>
143
+ <div class="e2ee-password-field">
144
+ <label for="e2ee-password-input">${gettext("Password")}</label>
145
+ <input type="password" id="e2ee-password-input" class="e2ee-password-input"
146
+ autocomplete="off" data-1p-ignore data-lp-ignore data-lpignore="true" data-bwignore data-form-type="other" autofocus />
147
+ <button type="button" class="e2ee-toggle-visibility" title="${gettext("Show password")}">
148
+ <i class="fa-solid fa-eye"></i>
149
+ </button>
150
+ </div>
151
+ <div class="e2ee-password-error" id="e2ee-password-error"></div>
152
+ </div>
153
+ `
154
+
155
+ // Declare dialogInstance before buttons so the click handler
156
+ // can call dialogInstance.close().
157
+ let dialogInstance
158
+
159
+ const buttons = [
160
+ {
161
+ text: gettext("Decrypt"),
162
+ classes: "fw-button fw-dark",
163
+ click: () => {
164
+ const input = document.getElementById("e2ee-password-input")
165
+ const password = input ? input.value : ""
166
+ if (password.length === 0) {
167
+ const errorEl = document.getElementById(
168
+ "e2ee-password-error"
169
+ )
170
+ if (errorEl) {
171
+ errorEl.textContent = gettext(
172
+ "Please enter the password."
173
+ )
174
+ }
175
+ return
176
+ }
177
+ dialogInstance.close()
178
+ onPassword(password)
179
+ resolve()
180
+ }
181
+ },
182
+ {
183
+ text: gettext("Cancel"),
184
+ classes: "fw-button fw-light",
185
+ click: () => {
186
+ dialogInstance.close()
187
+ if (typeof onCancel === "function") {
188
+ onCancel()
189
+ }
190
+ resolve()
191
+ }
192
+ }
193
+ ]
194
+
195
+ const dialog = {
196
+ title: gettext("Encrypted Document"),
197
+ id: dialogId,
198
+ body: body,
199
+ buttons: buttons,
200
+ canClose: true
201
+ }
202
+
203
+ // Use the Fidus Writer dialog system
204
+ dialogInstance = new Dialog(dialog)
205
+ dialogInstance.open()
206
+
207
+ // Set up toggle visibility button
208
+ setTimeout(() => {
209
+ const toggleBtn = document.querySelector(
210
+ `#${dialogId} .e2ee-toggle-visibility`
211
+ )
212
+ const input = document.getElementById("e2ee-password-input")
213
+ if (toggleBtn && input) {
214
+ toggleBtn.addEventListener("click", () => {
215
+ if (input.type === "password") {
216
+ input.type = "text"
217
+ toggleBtn.innerHTML =
218
+ '<i class="fa-solid fa-eye-slash"></i>'
219
+ toggleBtn.title = gettext("Hide password")
220
+ } else {
221
+ input.type = "password"
222
+ toggleBtn.innerHTML = '<i class="fa-solid fa-eye"></i>'
223
+ toggleBtn.title = gettext("Show password")
224
+ }
225
+ })
226
+ }
227
+
228
+ // Submit on Enter key
229
+ if (input) {
230
+ input.addEventListener("keypress", event => {
231
+ if (event.key === "Enter") {
232
+ event.preventDefault()
233
+ buttons[0].click()
234
+ }
235
+ })
236
+ input.focus()
237
+ }
238
+ }, 100)
239
+ })
240
+ }
241
+
242
+ /**
243
+ * Show a dialog for creating a password for a new E2EE document.
244
+ *
245
+ * This dialog is shown when a user creates a new encrypted document.
246
+ * The user must enter and confirm a password. The password must meet
247
+ * the minimum requirements (12+ characters, at least one letter and
248
+ * one number).
249
+ *
250
+ * @param {Function} onPassword - Callback called with the entered password string
251
+ * @returns {Promise<void>}
252
+ */
253
+ export function createPasswordDialog(onPassword) {
254
+ return new Promise(resolve => {
255
+ const dialogId = "e2ee-create-password"
256
+
257
+ const body = `
258
+ <div class="e2ee-password-dialog">
259
+ <p>${gettext("Set a password to encrypt this document. You will need this password to open the document in the future.")}</p>
260
+ <p class="e2ee-password-hint">${gettext('Tip: Use a passphrase with multiple words, e.g. "correct-horse-battery-staple". This is both secure and easy to remember.')}</p>
261
+ <div class="e2ee-password-field">
262
+ <label for="e2ee-new-password-input">${gettext("Password")}</label>
263
+ <input type="password" id="e2ee-new-password-input" class="e2ee-password-input"
264
+ autocomplete="off" data-1p-ignore data-lp-ignore data-lpignore="true" data-bwignore data-form-type="other" autofocus />
265
+ <button type="button" class="e2ee-toggle-visibility" title="${gettext("Show password")}">
266
+ <i class="fa-solid fa-eye"></i>
267
+ </button>
268
+ </div>
269
+ <div class="e2ee-strength-meter">
270
+ <div class="e2ee-strength-bar" id="e2ee-strength-bar"></div>
271
+ <span class="e2ee-strength-label" id="e2ee-strength-label"></span>
272
+ </div>
273
+ <div class="e2ee-password-field">
274
+ <label for="e2ee-confirm-password-input">${gettext("Confirm password")}</label>
275
+ <input type="password" id="e2ee-confirm-password-input" class="e2ee-password-input"
276
+ autocomplete="off" data-1p-ignore data-lp-ignore data-lpignore="true" data-bwignore data-form-type="other" />
277
+ </div>
278
+ <div class="e2ee-password-error" id="e2ee-password-error"></div>
279
+ </div>
280
+ `
281
+
282
+ const buttons = [
283
+ {
284
+ text: gettext("Create Encrypted Document"),
285
+ classes: "fw-button fw-dark",
286
+ click: () => {
287
+ const input = document.getElementById(
288
+ "e2ee-new-password-input"
289
+ )
290
+ const confirmInput = document.getElementById(
291
+ "e2ee-confirm-password-input"
292
+ )
293
+ const errorEl = document.getElementById(
294
+ "e2ee-password-error"
295
+ )
296
+ const password = input ? input.value : ""
297
+ const confirmPassword = confirmInput
298
+ ? confirmInput.value
299
+ : ""
300
+
301
+ // Validate password
302
+ const validation = validatePassword(password)
303
+ if (!validation.valid) {
304
+ if (errorEl) {
305
+ errorEl.textContent = validation.message
306
+ }
307
+ return
308
+ }
309
+
310
+ // Check confirmation
311
+ if (password !== confirmPassword) {
312
+ if (errorEl) {
313
+ errorEl.textContent = gettext(
314
+ "Passwords do not match."
315
+ )
316
+ }
317
+ return
318
+ }
319
+
320
+ dialogInstance.close()
321
+ onPassword(password)
322
+ resolve()
323
+ }
324
+ }
325
+ ]
326
+
327
+ const dialog = {
328
+ title: gettext("Set Document Password"),
329
+ id: dialogId,
330
+ body: body,
331
+ buttons: buttons,
332
+ canClose: true
333
+ }
334
+
335
+ const dialogInstance = new Dialog(dialog)
336
+ dialogInstance.open()
337
+
338
+ setTimeout(() => {
339
+ // Set up toggle visibility buttons
340
+ const toggleBtns = document.querySelectorAll(
341
+ `#${dialogId} .e2ee-toggle-visibility`
342
+ )
343
+ toggleBtns.forEach(btn => {
344
+ btn.addEventListener("click", () => {
345
+ const input = btn.parentElement.querySelector("input")
346
+ if (input) {
347
+ if (input.type === "password") {
348
+ input.type = "text"
349
+ btn.innerHTML =
350
+ '<i class="fa-solid fa-eye-slash"></i>'
351
+ } else {
352
+ input.type = "password"
353
+ btn.innerHTML = '<i class="fa-solid fa-eye"></i>'
354
+ }
355
+ }
356
+ })
357
+ })
358
+
359
+ // Set up strength meter
360
+ const passwordInput = document.getElementById(
361
+ "e2ee-new-password-input"
362
+ )
363
+ if (passwordInput) {
364
+ passwordInput.addEventListener("input", () => {
365
+ const score = passwordStrength(passwordInput.value)
366
+ const info = strengthInfo(score)
367
+ const bar = document.getElementById("e2ee-strength-bar")
368
+ const label = document.getElementById("e2ee-strength-label")
369
+ if (bar) {
370
+ bar.className = `e2ee-strength-bar ${info.cssClass}`
371
+ bar.style.width = `${(score + 1) * 25}%`
372
+ }
373
+ if (label) {
374
+ label.textContent = info.label
375
+ label.className = `e2ee-strength-label ${info.cssClass}`
376
+ }
377
+ })
378
+ // Initialize strength meter
379
+ passwordInput.dispatchEvent(new Event("input"))
380
+ passwordInput.focus()
381
+ }
382
+
383
+ // Submit on Enter key in confirm field
384
+ const confirmInput = document.getElementById(
385
+ "e2ee-confirm-password-input"
386
+ )
387
+ if (confirmInput) {
388
+ confirmInput.addEventListener("keypress", event => {
389
+ if (event.key === "Enter") {
390
+ event.preventDefault()
391
+ buttons[0].click()
392
+ }
393
+ })
394
+ }
395
+ }, 100)
396
+ })
397
+ }
398
+
399
+ /**
400
+ * Show a dialog for changing the password of an existing E2EE document.
401
+ *
402
+ * The user must enter their current password (to verify identity),
403
+ * then enter and confirm a new password.
404
+ *
405
+ * @param {Function} onPasswordChange - Callback called with
406
+ * {currentPassword: string, newPassword: string}
407
+ * @param {Object} [options] - Optional settings
408
+ * @param {string} [options.currentPassword] - Prefill current password field
409
+ * @param {string} [options.suggestedNewPassword] - Prefill new password field
410
+ * @param {boolean} [options.hideCurrentPassword] - Hide the current password field
411
+ * @param {boolean} [options.showNewPasswordPlaintext] - Show new password as plain text
412
+ * @param {string} [options.infoText] - Additional explanatory HTML paragraph
413
+ * @returns {Promise<void>}
414
+ */
415
+ export function changePasswordDialog(onPasswordChange, options = {}) {
416
+ return new Promise(resolve => {
417
+ const dialogId = "e2ee-change-password"
418
+ const currentPassword = options.currentPassword || ""
419
+ const suggestedNewPassword = options.suggestedNewPassword || ""
420
+ const hasPrefilledNew = suggestedNewPassword.length > 0
421
+ const hideCurrentPassword = options.hideCurrentPassword || false
422
+ const showNewPasswordPlaintext =
423
+ options.showNewPasswordPlaintext || false
424
+ const infoText = options.infoText || ""
425
+
426
+ const currentPasswordField = hideCurrentPassword
427
+ ? `<input type="hidden" id="e2ee-current-password-input" value="${escapeText(currentPassword)}" />`
428
+ : `<div class="e2ee-password-field">
429
+ <label for="e2ee-current-password-input">${gettext("Current password")}</label>
430
+ <input type="password" id="e2ee-current-password-input" class="e2ee-password-input"
431
+ value="${escapeText(currentPassword)}"
432
+ autocomplete="off" data-1p-ignore data-lp-ignore data-lpignore="true" data-bwignore data-form-type="other" autofocus />
433
+ </div>
434
+ <hr />`
435
+
436
+ const newPasswordInputType = showNewPasswordPlaintext
437
+ ? "text"
438
+ : "password"
439
+
440
+ const body = `
441
+ <div class="e2ee-password-dialog">
442
+ <p>${gettext("Change the document password. After changing, you must share the new password with all collaborators.")}</p>
443
+ ${infoText ? `<p class="e2ee-password-hint">${infoText}</p>` : ""}
444
+ ${currentPasswordField}
445
+ <div class="e2ee-password-field">
446
+ <label for="e2ee-new-password-input">${gettext("New password")}</label>
447
+ <input type="${newPasswordInputType}" id="e2ee-new-password-input" class="e2ee-password-input"
448
+ value="${escapeText(suggestedNewPassword)}"
449
+ autocomplete="off" data-1p-ignore data-lp-ignore data-lpignore="true" data-bwignore data-form-type="other" ${hideCurrentPassword ? "autofocus" : ""} />
450
+ ${
451
+ showNewPasswordPlaintext
452
+ ? ""
453
+ : `<button type="button" class="e2ee-toggle-visibility" title="${gettext("Show password")}">
454
+ <i class="fa-solid fa-eye"></i>
455
+ </button>`
456
+ }
457
+ </div>
458
+ <div class="e2ee-strength-meter" style="display: ${showNewPasswordPlaintext && hasPrefilledNew ? "none" : ""}">
459
+ <div class="e2ee-strength-bar" id="e2ee-strength-bar"></div>
460
+ <span class="e2ee-strength-label" id="e2ee-strength-label"></span>
461
+ </div>
462
+ <div class="e2ee-password-field" id="e2ee-confirm-field" style="display: ${hasPrefilledNew ? "none" : ""}">
463
+ <label for="e2ee-confirm-password-input">${gettext("Confirm new password")}</label>
464
+ <input type="password" id="e2ee-confirm-password-input" class="e2ee-password-input"
465
+ autocomplete="off" data-1p-ignore data-lp-ignore data-lpignore="true" data-bwignore data-form-type="other" />
466
+ </div>
467
+ <div class="e2ee-password-error" id="e2ee-password-error"></div>
468
+ </div>
469
+ `
470
+
471
+ let newPasswordChanged = !hasPrefilledNew
472
+
473
+ const buttons = [
474
+ {
475
+ text: gettext("Change Password"),
476
+ classes: "fw-button fw-dark",
477
+ click: () => {
478
+ const currentInput = document.getElementById(
479
+ "e2ee-current-password-input"
480
+ )
481
+ const newInput = document.getElementById(
482
+ "e2ee-new-password-input"
483
+ )
484
+ const confirmInput = document.getElementById(
485
+ "e2ee-confirm-password-input"
486
+ )
487
+ const errorEl = document.getElementById(
488
+ "e2ee-password-error"
489
+ )
490
+
491
+ const currentPasswordValue = currentInput
492
+ ? currentInput.value
493
+ : ""
494
+ const newPassword = newInput ? newInput.value : ""
495
+ const confirmPassword = confirmInput
496
+ ? confirmInput.value
497
+ : ""
498
+
499
+ // Validate current password
500
+ if (currentPasswordValue.length === 0) {
501
+ if (errorEl) {
502
+ errorEl.textContent = gettext(
503
+ "Please enter the current password."
504
+ )
505
+ }
506
+ return
507
+ }
508
+
509
+ // Validate new password
510
+ const validation = validatePassword(newPassword)
511
+ if (!validation.valid) {
512
+ if (errorEl) {
513
+ errorEl.textContent = validation.message
514
+ }
515
+ return
516
+ }
517
+
518
+ // Check confirmation only if user changed the prefilled value
519
+ if (newPasswordChanged && newPassword !== confirmPassword) {
520
+ if (errorEl) {
521
+ errorEl.textContent = gettext(
522
+ "Passwords do not match."
523
+ )
524
+ }
525
+ return
526
+ }
527
+
528
+ // Check that new password is different
529
+ if (currentPasswordValue === newPassword) {
530
+ if (errorEl) {
531
+ errorEl.textContent = gettext(
532
+ "New password must be different from the current password."
533
+ )
534
+ }
535
+ return
536
+ }
537
+
538
+ dialogInstance.close()
539
+ onPasswordChange({
540
+ currentPassword: currentPasswordValue,
541
+ newPassword
542
+ })
543
+ resolve()
544
+ }
545
+ }
546
+ ]
547
+
548
+ const dialog = {
549
+ title: gettext("Change Document Password"),
550
+ id: dialogId,
551
+ body: body,
552
+ buttons: buttons,
553
+ canClose: true
554
+ }
555
+
556
+ const dialogInstance = new Dialog(dialog)
557
+ dialogInstance.open()
558
+
559
+ setTimeout(() => {
560
+ // Set up toggle visibility buttons (only if new password is not plaintext)
561
+ if (!showNewPasswordPlaintext) {
562
+ const toggleBtns = document.querySelectorAll(
563
+ `#${dialogId} .e2ee-toggle-visibility`
564
+ )
565
+ toggleBtns.forEach(btn => {
566
+ btn.addEventListener("click", () => {
567
+ const input = btn.parentElement.querySelector("input")
568
+ if (input) {
569
+ if (input.type === "password") {
570
+ input.type = "text"
571
+ btn.innerHTML =
572
+ '<i class="fa-solid fa-eye-slash"></i>'
573
+ } else {
574
+ input.type = "password"
575
+ btn.innerHTML =
576
+ '<i class="fa-solid fa-eye"></i>'
577
+ }
578
+ }
579
+ })
580
+ })
581
+ }
582
+
583
+ // Set up strength meter
584
+ const passwordInput = document.getElementById(
585
+ "e2ee-new-password-input"
586
+ )
587
+ if (
588
+ passwordInput &&
589
+ !(showNewPasswordPlaintext && hasPrefilledNew)
590
+ ) {
591
+ passwordInput.addEventListener("input", () => {
592
+ const score = passwordStrength(passwordInput.value)
593
+ const info = strengthInfo(score)
594
+ const bar = document.getElementById("e2ee-strength-bar")
595
+ const label = document.getElementById("e2ee-strength-label")
596
+ if (bar) {
597
+ bar.className = `e2ee-strength-bar ${info.cssClass}`
598
+ bar.style.width = `${(score + 1) * 25}%`
599
+ }
600
+ if (label) {
601
+ label.textContent = info.label
602
+ label.className = `e2ee-strength-label ${info.cssClass}`
603
+ }
604
+ })
605
+ passwordInput.dispatchEvent(new Event("input"))
606
+ }
607
+
608
+ // Track changes to new password field
609
+ if (passwordInput && hasPrefilledNew) {
610
+ passwordInput.addEventListener("input", () => {
611
+ if (passwordInput.value !== suggestedNewPassword) {
612
+ newPasswordChanged = true
613
+ const confirmField =
614
+ document.getElementById("e2ee-confirm-field")
615
+ if (confirmField) {
616
+ confirmField.style.display = ""
617
+ }
618
+ // Show strength meter again if user edits the prefilled value
619
+ const strengthMeter = document.querySelector(
620
+ `#${dialogId} .e2ee-strength-meter`
621
+ )
622
+ if (strengthMeter) {
623
+ strengthMeter.style.display = ""
624
+ }
625
+ }
626
+ })
627
+ }
628
+
629
+ // Submit on Enter key
630
+ const confirmInput = document.getElementById(
631
+ "e2ee-confirm-password-input"
632
+ )
633
+ if (confirmInput) {
634
+ confirmInput.addEventListener("keypress", event => {
635
+ if (event.key === "Enter") {
636
+ event.preventDefault()
637
+ buttons[0].click()
638
+ }
639
+ })
640
+ }
641
+
642
+ const currentInput = document.getElementById(
643
+ "e2ee-current-password-input"
644
+ )
645
+ if (currentInput && !hideCurrentPassword) {
646
+ currentInput.focus()
647
+ } else if (passwordInput) {
648
+ passwordInput.focus()
649
+ }
650
+ }, 100)
651
+ })
652
+ }