@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.
- package/LICENSE +661 -0
- package/README.md +22 -0
- package/dist/bibliography/tools.js +53 -0
- package/dist/bibliography/tools.js.map +1 -0
- package/dist/citations/index.js +339 -0
- package/dist/citations/index.js.map +1 -0
- package/dist/citations/render.js +47 -0
- package/dist/citations/render.js.map +1 -0
- package/dist/clipboard/copy/index.js +2 -0
- package/dist/clipboard/copy/index.js.map +1 -0
- package/dist/clipboard/copy/schema.js +54 -0
- package/dist/clipboard/copy/schema.js.map +1 -0
- package/dist/clipboard/copy/serializers.js +132 -0
- package/dist/clipboard/copy/serializers.js.map +1 -0
- package/dist/clipboard/paste/fidus_writer.js +45 -0
- package/dist/clipboard/paste/fidus_writer.js.map +1 -0
- package/dist/clipboard/paste/general.js +76 -0
- package/dist/clipboard/paste/general.js.map +1 -0
- package/dist/clipboard/paste/google_docs.js +24 -0
- package/dist/clipboard/paste/google_docs.js.map +1 -0
- package/dist/clipboard/paste/html.js +68 -0
- package/dist/clipboard/paste/html.js.map +1 -0
- package/dist/clipboard/paste/index.js +3 -0
- package/dist/clipboard/paste/index.js.map +1 -0
- package/dist/clipboard/paste/libreoffice_writer.js +27 -0
- package/dist/clipboard/paste/libreoffice_writer.js.map +1 -0
- package/dist/clipboard/paste/microsoft_word.js +79 -0
- package/dist/clipboard/paste/microsoft_word.js.map +1 -0
- package/dist/clipboard/paste/text.js +41 -0
- package/dist/clipboard/paste/text.js.map +1 -0
- package/dist/collab/chat.js +154 -0
- package/dist/collab/chat.js.map +1 -0
- package/dist/collab/colors.js +62 -0
- package/dist/collab/colors.js.map +1 -0
- package/dist/collab/doc.js +1090 -0
- package/dist/collab/doc.js.map +1 -0
- package/dist/collab/index.js +75 -0
- package/dist/collab/index.js.map +1 -0
- package/dist/collab/merge/changeset.js +90 -0
- package/dist/collab/merge/changeset.js.map +1 -0
- package/dist/collab/merge/editor.js +708 -0
- package/dist/collab/merge/editor.js.map +1 -0
- package/dist/collab/merge/footnotes.js +149 -0
- package/dist/collab/merge/footnotes.js.map +1 -0
- package/dist/collab/merge/index.js +270 -0
- package/dist/collab/merge/index.js.map +1 -0
- package/dist/collab/merge/recreate_transform.js +259 -0
- package/dist/collab/merge/recreate_transform.js.map +1 -0
- package/dist/collab/merge/schema.js +117 -0
- package/dist/collab/merge/schema.js.map +1 -0
- package/dist/collab/merge/state_plugins/action.js +138 -0
- package/dist/collab/merge/state_plugins/action.js.map +1 -0
- package/dist/collab/merge/state_plugins/clipboard.js +32 -0
- package/dist/collab/merge/state_plugins/clipboard.js.map +1 -0
- package/dist/collab/merge/state_plugins/diff.js +541 -0
- package/dist/collab/merge/state_plugins/diff.js.map +1 -0
- package/dist/collab/merge/state_plugins/index.js +3 -0
- package/dist/collab/merge/state_plugins/index.js.map +1 -0
- package/dist/collab/merge/tools.js +175 -0
- package/dist/collab/merge/tools.js.map +1 -0
- package/dist/collab/templates.js +10 -0
- package/dist/collab/templates.js.map +1 -0
- package/dist/comments/comment.js +17 -0
- package/dist/comments/comment.js.map +1 -0
- package/dist/comments/editors/answer.js +43 -0
- package/dist/comments/editors/answer.js.map +1 -0
- package/dist/comments/editors/comment.js +278 -0
- package/dist/comments/editors/comment.js.map +1 -0
- package/dist/comments/editors/index.js +4 -0
- package/dist/comments/editors/index.js.map +1 -0
- package/dist/comments/editors/notify.js +13 -0
- package/dist/comments/editors/notify.js.map +1 -0
- package/dist/comments/editors/schema.js +60 -0
- package/dist/comments/editors/schema.js.map +1 -0
- package/dist/comments/index.js +11 -0
- package/dist/comments/index.js.map +1 -0
- package/dist/comments/interactions.js +379 -0
- package/dist/comments/interactions.js.map +1 -0
- package/dist/comments/store.js +438 -0
- package/dist/comments/store.js.map +1 -0
- package/dist/contacts/add_dialog.js +88 -0
- package/dist/contacts/add_dialog.js.map +1 -0
- package/dist/contacts/templates.js +23 -0
- package/dist/contacts/templates.js.map +1 -0
- package/dist/copyright_dialog/index.js +148 -0
- package/dist/copyright_dialog/index.js.map +1 -0
- package/dist/copyright_dialog/templates.js +48 -0
- package/dist/copyright_dialog/templates.js.map +1 -0
- package/dist/databases/bibliography.js +162 -0
- package/dist/databases/bibliography.js.map +1 -0
- package/dist/databases/images.js +260 -0
- package/dist/databases/images.js.map +1 -0
- package/dist/databases/index.js +55 -0
- package/dist/databases/index.js.map +1 -0
- package/dist/dialogs/citation.js +321 -0
- package/dist/dialogs/citation.js.map +1 -0
- package/dist/dialogs/code_block.js +192 -0
- package/dist/dialogs/code_block.js.map +1 -0
- package/dist/dialogs/contributor.js +132 -0
- package/dist/dialogs/contributor.js.map +1 -0
- package/dist/dialogs/figure.js +378 -0
- package/dist/dialogs/figure.js.map +1 -0
- package/dist/dialogs/index.js +11 -0
- package/dist/dialogs/index.js.map +1 -0
- package/dist/dialogs/language.js +47 -0
- package/dist/dialogs/language.js.map +1 -0
- package/dist/dialogs/link.js +243 -0
- package/dist/dialogs/link.js.map +1 -0
- package/dist/dialogs/math.js +121 -0
- package/dist/dialogs/math.js.map +1 -0
- package/dist/dialogs/ordered_list.js +67 -0
- package/dist/dialogs/ordered_list.js.map +1 -0
- package/dist/dialogs/revision.js +36 -0
- package/dist/dialogs/revision.js.map +1 -0
- package/dist/dialogs/subsup.js +109 -0
- package/dist/dialogs/subsup.js.map +1 -0
- package/dist/dialogs/table.js +217 -0
- package/dist/dialogs/table.js.map +1 -0
- package/dist/dialogs/templates.js +366 -0
- package/dist/dialogs/templates.js.map +1 -0
- package/dist/document_template/exporter.js +83 -0
- package/dist/document_template/exporter.js.map +1 -0
- package/dist/document_template/index.js +327 -0
- package/dist/document_template/index.js.map +1 -0
- package/dist/documents/access_rights/index.js +532 -0
- package/dist/documents/access_rights/index.js.map +1 -0
- package/dist/documents/access_rights/templates.js +150 -0
- package/dist/documents/access_rights/templates.js.map +1 -0
- package/dist/e2ee/encryptor.js +201 -0
- package/dist/e2ee/encryptor.js.map +1 -0
- package/dist/e2ee/key-manager.js +171 -0
- package/dist/e2ee/key-manager.js.map +1 -0
- package/dist/e2ee/passphrase-crypto.js +365 -0
- package/dist/e2ee/passphrase-crypto.js.map +1 -0
- package/dist/e2ee/passphrase-dialog.js +548 -0
- package/dist/e2ee/passphrase-dialog.js.map +1 -0
- package/dist/e2ee/passphrase-manager.js +350 -0
- package/dist/e2ee/passphrase-manager.js.map +1 -0
- package/dist/e2ee/password-dialog.js +552 -0
- package/dist/e2ee/password-dialog.js.map +1 -0
- package/dist/e2ee/snapshot-manager.js +238 -0
- package/dist/e2ee/snapshot-manager.js.map +1 -0
- package/dist/exporter/native/copy.js +29 -0
- package/dist/exporter/native/copy.js.map +1 -0
- package/dist/exporter/native/file.js +19 -0
- package/dist/exporter/native/file.js.map +1 -0
- package/dist/exporter/native/index.js +4 -0
- package/dist/exporter/native/index.js.map +1 -0
- package/dist/exporter/native/revision.js +54 -0
- package/dist/exporter/native/revision.js.map +1 -0
- package/dist/exporter/native/zip.js +2 -0
- package/dist/exporter/native/zip.js.map +1 -0
- package/dist/footnotes/editor.js +180 -0
- package/dist/footnotes/editor.js.map +1 -0
- package/dist/footnotes/index.js +15 -0
- package/dist/footnotes/index.js.map +1 -0
- package/dist/footnotes/layout.js +125 -0
- package/dist/footnotes/layout.js.map +1 -0
- package/dist/footnotes/state_plugins/access_rights.js +25 -0
- package/dist/footnotes/state_plugins/access_rights.js.map +1 -0
- package/dist/footnotes/state_plugins/index.js +2 -0
- package/dist/footnotes/state_plugins/index.js.map +1 -0
- package/dist/images/edit_dialog/edit_dialog/index.js +186 -0
- package/dist/images/edit_dialog/edit_dialog/index.js.map +1 -0
- package/dist/images/edit_dialog/edit_dialog/model.js +152 -0
- package/dist/images/edit_dialog/edit_dialog/model.js.map +1 -0
- package/dist/images/edit_dialog/edit_dialog/templates.js +33 -0
- package/dist/images/edit_dialog/edit_dialog/templates.js.map +1 -0
- package/dist/images/edit_dialog/model.js +6 -0
- package/dist/images/edit_dialog/model.js.map +1 -0
- package/dist/images/selection_dialog/index.js +149 -0
- package/dist/images/selection_dialog/index.js.map +1 -0
- package/dist/index.js +1002 -0
- package/dist/index.js.map +1 -0
- package/dist/keymap.js +73 -0
- package/dist/keymap.js.map +1 -0
- package/dist/marginboxes/index.js +674 -0
- package/dist/marginboxes/index.js.map +1 -0
- package/dist/marginboxes/templates.js +447 -0
- package/dist/marginboxes/templates.js.map +1 -0
- package/dist/menus/code_block/index.js +2 -0
- package/dist/menus/code_block/index.js.map +1 -0
- package/dist/menus/code_block/model.js +49 -0
- package/dist/menus/code_block/model.js.map +1 -0
- package/dist/menus/figure/index.js +3 -0
- package/dist/menus/figure/index.js.map +1 -0
- package/dist/menus/figure/model.js +80 -0
- package/dist/menus/figure/model.js.map +1 -0
- package/dist/menus/figure/utils.js +6 -0
- package/dist/menus/figure/utils.js.map +1 -0
- package/dist/menus/headerbar/index.js +3 -0
- package/dist/menus/headerbar/index.js.map +1 -0
- package/dist/menus/headerbar/model.js +743 -0
- package/dist/menus/headerbar/model.js.map +1 -0
- package/dist/menus/headerbar/view.js +579 -0
- package/dist/menus/headerbar/view.js.map +1 -0
- package/dist/menus/image/index.js +2 -0
- package/dist/menus/image/index.js.map +1 -0
- package/dist/menus/image/model.js +32 -0
- package/dist/menus/image/model.js.map +1 -0
- package/dist/menus/index.js +10 -0
- package/dist/menus/index.js.map +1 -0
- package/dist/menus/navigator/index.js +2 -0
- package/dist/menus/navigator/index.js.map +1 -0
- package/dist/menus/navigator/model.js +29 -0
- package/dist/menus/navigator/model.js.map +1 -0
- package/dist/menus/ordered_list/index.js +2 -0
- package/dist/menus/ordered_list/index.js.map +1 -0
- package/dist/menus/ordered_list/model.js +17 -0
- package/dist/menus/ordered_list/model.js.map +1 -0
- package/dist/menus/selection/index.js +3 -0
- package/dist/menus/selection/index.js.map +1 -0
- package/dist/menus/selection/model.js +108 -0
- package/dist/menus/selection/model.js.map +1 -0
- package/dist/menus/selection/view.js +125 -0
- package/dist/menus/selection/view.js.map +1 -0
- package/dist/menus/table/index.js +2 -0
- package/dist/menus/table/index.js.map +1 -0
- package/dist/menus/table/model.js +319 -0
- package/dist/menus/table/model.js.map +1 -0
- package/dist/menus/toolbar/index.js +3 -0
- package/dist/menus/toolbar/index.js.map +1 -0
- package/dist/menus/toolbar/model.js +747 -0
- package/dist/menus/toolbar/model.js.map +1 -0
- package/dist/menus/toolbar/view.js +314 -0
- package/dist/menus/toolbar/view.js.map +1 -0
- package/dist/navigator/index.js +435 -0
- package/dist/navigator/index.js.map +1 -0
- package/dist/no_collab_save/index.js +169 -0
- package/dist/no_collab_save/index.js.map +1 -0
- package/dist/plugins/citation_dialog/index.js +2 -0
- package/dist/plugins/citation_dialog/index.js.map +1 -0
- package/dist/plugins/editor/index.js +2 -0
- package/dist/plugins/editor/index.js.map +1 -0
- package/dist/state_plugins/access_rights.js +30 -0
- package/dist/state_plugins/access_rights.js.map +1 -0
- package/dist/state_plugins/citation_render.js +78 -0
- package/dist/state_plugins/citation_render.js.map +1 -0
- package/dist/state_plugins/clipboard.js +217 -0
- package/dist/state_plugins/clipboard.js.map +1 -0
- package/dist/state_plugins/code_block.js +165 -0
- package/dist/state_plugins/code_block.js.map +1 -0
- package/dist/state_plugins/collab_carets.js +115 -0
- package/dist/state_plugins/collab_carets.js.map +1 -0
- package/dist/state_plugins/comments.js +197 -0
- package/dist/state_plugins/comments.js.map +1 -0
- package/dist/state_plugins/contributor_input/add_button.js +101 -0
- package/dist/state_plugins/contributor_input/add_button.js.map +1 -0
- package/dist/state_plugins/contributor_input/dropup.js +273 -0
- package/dist/state_plugins/contributor_input/dropup.js.map +1 -0
- package/dist/state_plugins/contributor_input/helpers.js +23 -0
- package/dist/state_plugins/contributor_input/helpers.js.map +1 -0
- package/dist/state_plugins/contributor_input/index.js +3 -0
- package/dist/state_plugins/contributor_input/index.js.map +1 -0
- package/dist/state_plugins/contributor_input/node_view.js +76 -0
- package/dist/state_plugins/contributor_input/node_view.js.map +1 -0
- package/dist/state_plugins/contributor_input/plugin.js +236 -0
- package/dist/state_plugins/contributor_input/plugin.js.map +1 -0
- package/dist/state_plugins/document_template.js +213 -0
- package/dist/state_plugins/document_template.js.map +1 -0
- package/dist/state_plugins/figure.js +90 -0
- package/dist/state_plugins/figure.js.map +1 -0
- package/dist/state_plugins/footnote_markers.js +187 -0
- package/dist/state_plugins/footnote_markers.js.map +1 -0
- package/dist/state_plugins/headerbar.js +10 -0
- package/dist/state_plugins/headerbar.js.map +1 -0
- package/dist/state_plugins/index.js +27 -0
- package/dist/state_plugins/index.js.map +1 -0
- package/dist/state_plugins/inline_math.js +719 -0
- package/dist/state_plugins/inline_math.js.map +1 -0
- package/dist/state_plugins/inline_reference/dropup.js +182 -0
- package/dist/state_plugins/inline_reference/dropup.js.map +1 -0
- package/dist/state_plugins/inline_reference/index.js +2 -0
- package/dist/state_plugins/inline_reference/index.js.map +1 -0
- package/dist/state_plugins/inline_reference/plugin.js +1134 -0
- package/dist/state_plugins/inline_reference/plugin.js.map +1 -0
- package/dist/state_plugins/jump_hidden_nodes.js +47 -0
- package/dist/state_plugins/jump_hidden_nodes.js.map +1 -0
- package/dist/state_plugins/links.js +622 -0
- package/dist/state_plugins/links.js.map +1 -0
- package/dist/state_plugins/marginboxes.js +13 -0
- package/dist/state_plugins/marginboxes.js.map +1 -0
- package/dist/state_plugins/ordered_list_menu.js +72 -0
- package/dist/state_plugins/ordered_list_menu.js.map +1 -0
- package/dist/state_plugins/placeholders.js +98 -0
- package/dist/state_plugins/placeholders.js.map +1 -0
- package/dist/state_plugins/search.js +212 -0
- package/dist/state_plugins/search.js.map +1 -0
- package/dist/state_plugins/selection_menu.js +10 -0
- package/dist/state_plugins/selection_menu.js.map +1 -0
- package/dist/state_plugins/settings.js +191 -0
- package/dist/state_plugins/settings.js.map +1 -0
- package/dist/state_plugins/table.js +104 -0
- package/dist/state_plugins/table.js.map +1 -0
- package/dist/state_plugins/tag_input/helpers.js +55 -0
- package/dist/state_plugins/tag_input/helpers.js.map +1 -0
- package/dist/state_plugins/tag_input/index.js +3 -0
- package/dist/state_plugins/tag_input/index.js.map +1 -0
- package/dist/state_plugins/tag_input/node_view.js +77 -0
- package/dist/state_plugins/tag_input/node_view.js.map +1 -0
- package/dist/state_plugins/tag_input/plugin.js +199 -0
- package/dist/state_plugins/tag_input/plugin.js.map +1 -0
- package/dist/state_plugins/tag_input/tag_editor.js +159 -0
- package/dist/state_plugins/tag_input/tag_editor.js.map +1 -0
- package/dist/state_plugins/tag_input/tag_editor_plugins.js +61 -0
- package/dist/state_plugins/tag_input/tag_editor_plugins.js.map +1 -0
- package/dist/state_plugins/toc_render.js +142 -0
- package/dist/state_plugins/toc_render.js.map +1 -0
- package/dist/state_plugins/toolbar.js +10 -0
- package/dist/state_plugins/toolbar.js.map +1 -0
- package/dist/state_plugins/track/find_selected_changes.js +82 -0
- package/dist/state_plugins/track/find_selected_changes.js.map +1 -0
- package/dist/state_plugins/track/helpers.js +67 -0
- package/dist/state_plugins/track/helpers.js.map +1 -0
- package/dist/state_plugins/track/index.js +3 -0
- package/dist/state_plugins/track/index.js.map +1 -0
- package/dist/state_plugins/track/plugin.js +114 -0
- package/dist/state_plugins/track/plugin.js.map +1 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/key_bindings/index.js +20 -0
- package/dist/tools/key_bindings/index.js.map +1 -0
- package/dist/tools/key_bindings/templates.js +68 -0
- package/dist/tools/key_bindings/templates.js.map +1 -0
- package/dist/tools/search_replace/index.js +275 -0
- package/dist/tools/search_replace/index.js.map +1 -0
- package/dist/tools/search_replace/templates.js +18 -0
- package/dist/tools/search_replace/templates.js.map +1 -0
- package/dist/tools/word_count/index.js +40 -0
- package/dist/tools/word_count/index.js.map +1 -0
- package/dist/tools/word_count/templates.js +27 -0
- package/dist/tools/word_count/templates.js.map +1 -0
- package/dist/track/accept.js +66 -0
- package/dist/track/accept.js.map +1 -0
- package/dist/track/accept_all.js +51 -0
- package/dist/track/accept_all.js.map +1 -0
- package/dist/track/accept_all_no_insertions.js +63 -0
- package/dist/track/accept_all_no_insertions.js.map +1 -0
- package/dist/track/amend_transaction.js +390 -0
- package/dist/track/amend_transaction.js.map +1 -0
- package/dist/track/delete.js +62 -0
- package/dist/track/delete.js.map +1 -0
- package/dist/track/index.js +6 -0
- package/dist/track/index.js.map +1 -0
- package/dist/track/mod.js +86 -0
- package/dist/track/mod.js.map +1 -0
- package/dist/track/reject.js +67 -0
- package/dist/track/reject.js.map +1 -0
- package/dist/track/reject_all.js +56 -0
- package/dist/track/reject_all.js.map +1 -0
- package/package.json +80 -0
- package/src/bibliography/tools.js +58 -0
- package/src/citations/index.js +443 -0
- package/src/citations/render.js +68 -0
- package/src/clipboard/copy/index.js +1 -0
- package/src/clipboard/copy/schema.js +62 -0
- package/src/clipboard/copy/serializers.js +179 -0
- package/src/clipboard/paste/fidus_writer.js +55 -0
- package/src/clipboard/paste/general.js +80 -0
- package/src/clipboard/paste/google_docs.js +26 -0
- package/src/clipboard/paste/html.js +76 -0
- package/src/clipboard/paste/index.js +2 -0
- package/src/clipboard/paste/libreoffice_writer.js +32 -0
- package/src/clipboard/paste/microsoft_word.js +87 -0
- package/src/clipboard/paste/text.js +58 -0
- package/src/collab/chat.js +195 -0
- package/src/collab/colors.js +67 -0
- package/src/collab/doc.js +1436 -0
- package/src/collab/index.js +81 -0
- package/src/collab/merge/changeset.js +103 -0
- package/src/collab/merge/editor.js +1065 -0
- package/src/collab/merge/footnotes.js +175 -0
- package/src/collab/merge/index.js +401 -0
- package/src/collab/merge/recreate_transform.js +326 -0
- package/src/collab/merge/schema.js +135 -0
- package/src/collab/merge/state_plugins/action.js +171 -0
- package/src/collab/merge/state_plugins/clipboard.js +32 -0
- package/src/collab/merge/state_plugins/diff.js +780 -0
- package/src/collab/merge/state_plugins/index.js +2 -0
- package/src/collab/merge/tools.js +217 -0
- package/src/collab/templates.js +10 -0
- package/src/comments/comment.js +29 -0
- package/src/comments/editors/answer.js +55 -0
- package/src/comments/editors/comment.js +318 -0
- package/src/comments/editors/index.js +4 -0
- package/src/comments/editors/notify.js +13 -0
- package/src/comments/editors/schema.js +65 -0
- package/src/comments/index.js +11 -0
- package/src/comments/interactions.js +465 -0
- package/src/comments/store.js +513 -0
- package/src/contacts/add_dialog.js +110 -0
- package/src/contacts/templates.js +28 -0
- package/src/copyright_dialog/index.js +179 -0
- package/src/copyright_dialog/templates.js +56 -0
- package/src/databases/bibliography.js +179 -0
- package/src/databases/images.js +320 -0
- package/src/databases/index.js +69 -0
- package/src/dialogs/citation.js +428 -0
- package/src/dialogs/code_block.js +242 -0
- package/src/dialogs/contributor.js +173 -0
- package/src/dialogs/figure.js +479 -0
- package/src/dialogs/index.js +10 -0
- package/src/dialogs/language.js +58 -0
- package/src/dialogs/link.js +358 -0
- package/src/dialogs/math.js +148 -0
- package/src/dialogs/ordered_list.js +84 -0
- package/src/dialogs/revision.js +43 -0
- package/src/dialogs/subsup.js +116 -0
- package/src/dialogs/table.js +258 -0
- package/src/dialogs/templates.js +426 -0
- package/src/document_template/exporter.js +97 -0
- package/src/document_template/index.js +483 -0
- package/src/documents/access_rights/index.js +693 -0
- package/src/documents/access_rights/templates.js +178 -0
- package/src/e2ee/encryptor.js +228 -0
- package/src/e2ee/key-manager.js +202 -0
- package/src/e2ee/passphrase-crypto.js +606 -0
- package/src/e2ee/passphrase-dialog.js +655 -0
- package/src/e2ee/passphrase-manager.js +502 -0
- package/src/e2ee/password-dialog.js +652 -0
- package/src/e2ee/snapshot-manager.js +305 -0
- package/src/exporter/native/copy.js +54 -0
- package/src/exporter/native/file.js +37 -0
- package/src/exporter/native/index.js +3 -0
- package/src/exporter/native/revision.js +86 -0
- package/src/exporter/native/zip.js +1 -0
- package/src/footnotes/editor.js +227 -0
- package/src/footnotes/index.js +16 -0
- package/src/footnotes/layout.js +190 -0
- package/src/footnotes/state_plugins/access_rights.js +39 -0
- package/src/footnotes/state_plugins/index.js +1 -0
- package/src/images/edit_dialog/edit_dialog/index.js +222 -0
- package/src/images/edit_dialog/edit_dialog/model.js +183 -0
- package/src/images/edit_dialog/edit_dialog/templates.js +41 -0
- package/src/images/edit_dialog/model.js +5 -0
- package/src/images/selection_dialog/index.js +176 -0
- package/src/index.js +1252 -0
- package/src/keymap.js +102 -0
- package/src/marginboxes/index.js +946 -0
- package/src/marginboxes/templates.js +573 -0
- package/src/menus/code_block/index.js +1 -0
- package/src/menus/code_block/model.js +52 -0
- package/src/menus/figure/index.js +2 -0
- package/src/menus/figure/model.js +91 -0
- package/src/menus/figure/utils.js +5 -0
- package/src/menus/headerbar/index.js +2 -0
- package/src/menus/headerbar/model.js +1077 -0
- package/src/menus/headerbar/view.js +675 -0
- package/src/menus/image/index.js +1 -0
- package/src/menus/image/model.js +32 -0
- package/src/menus/index.js +9 -0
- package/src/menus/navigator/index.js +1 -0
- package/src/menus/navigator/model.js +28 -0
- package/src/menus/ordered_list/index.js +1 -0
- package/src/menus/ordered_list/model.js +19 -0
- package/src/menus/selection/index.js +2 -0
- package/src/menus/selection/model.js +134 -0
- package/src/menus/selection/view.js +154 -0
- package/src/menus/table/index.js +1 -0
- package/src/menus/table/model.js +414 -0
- package/src/menus/toolbar/index.js +2 -0
- package/src/menus/toolbar/model.js +920 -0
- package/src/menus/toolbar/view.js +354 -0
- package/src/navigator/index.js +515 -0
- package/src/no_collab_save/index.js +209 -0
- package/src/plugins/citation_dialog/index.js +1 -0
- package/src/plugins/editor/index.js +1 -0
- package/src/state_plugins/access_rights.js +47 -0
- package/src/state_plugins/citation_render.js +88 -0
- package/src/state_plugins/clipboard.js +289 -0
- package/src/state_plugins/code_block.js +201 -0
- package/src/state_plugins/collab_carets.js +152 -0
- package/src/state_plugins/comments.js +259 -0
- package/src/state_plugins/contributor_input/add_button.js +134 -0
- package/src/state_plugins/contributor_input/dropup.js +318 -0
- package/src/state_plugins/contributor_input/helpers.js +24 -0
- package/src/state_plugins/contributor_input/index.js +2 -0
- package/src/state_plugins/contributor_input/node_view.js +86 -0
- package/src/state_plugins/contributor_input/plugin.js +318 -0
- package/src/state_plugins/document_template.js +315 -0
- package/src/state_plugins/figure.js +108 -0
- package/src/state_plugins/footnote_markers.js +238 -0
- package/src/state_plugins/headerbar.js +12 -0
- package/src/state_plugins/index.js +73 -0
- package/src/state_plugins/inline_math.js +918 -0
- package/src/state_plugins/inline_reference/dropup.js +208 -0
- package/src/state_plugins/inline_reference/index.js +5 -0
- package/src/state_plugins/inline_reference/plugin.js +1429 -0
- package/src/state_plugins/jump_hidden_nodes.js +58 -0
- package/src/state_plugins/links.js +830 -0
- package/src/state_plugins/marginboxes.js +14 -0
- package/src/state_plugins/ordered_list_menu.js +84 -0
- package/src/state_plugins/placeholders.js +123 -0
- package/src/state_plugins/search.js +251 -0
- package/src/state_plugins/selection_menu.js +12 -0
- package/src/state_plugins/settings.js +223 -0
- package/src/state_plugins/table.js +127 -0
- package/src/state_plugins/tag_input/helpers.js +69 -0
- package/src/state_plugins/tag_input/index.js +2 -0
- package/src/state_plugins/tag_input/node_view.js +85 -0
- package/src/state_plugins/tag_input/plugin.js +278 -0
- package/src/state_plugins/tag_input/tag_editor.js +202 -0
- package/src/state_plugins/tag_input/tag_editor_plugins.js +74 -0
- package/src/state_plugins/toc_render.js +160 -0
- package/src/state_plugins/toolbar.js +12 -0
- package/src/state_plugins/track/find_selected_changes.js +107 -0
- package/src/state_plugins/track/helpers.js +108 -0
- package/src/state_plugins/track/index.js +6 -0
- package/src/state_plugins/track/plugin.js +140 -0
- package/src/tools/index.js +3 -0
- package/src/tools/key_bindings/index.js +21 -0
- package/src/tools/key_bindings/templates.js +68 -0
- package/src/tools/search_replace/index.js +421 -0
- package/src/tools/search_replace/templates.js +19 -0
- package/src/tools/word_count/index.js +59 -0
- package/src/tools/word_count/templates.js +34 -0
- package/src/track/accept.js +102 -0
- package/src/track/accept_all.js +103 -0
- package/src/track/accept_all_no_insertions.js +102 -0
- package/src/track/amend_transaction.js +562 -0
- package/src/track/delete.js +92 -0
- package/src/track/index.js +8 -0
- package/src/track/mod.js +116 -0
- package/src/track/reject.js +116 -0
- package/src/track/reject_all.js +121 -0
|
@@ -0,0 +1,1134 @@
|
|
|
1
|
+
import { NodeSelection, Plugin, PluginKey, TextSelection } from "prosemirror-state";
|
|
2
|
+
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
3
|
+
import { COMMENT_ONLY_ROLES, READ_ONLY_ROLES } from "../..";
|
|
4
|
+
import { elementDisabled } from "../../menus/toolbar/model";
|
|
5
|
+
import { buildBibliographyList, buildCrossRefList, createInlineReferenceDropUp, filterBibliography, filterCrossRefs } from "./dropup";
|
|
6
|
+
const key = new PluginKey("inlineReference");
|
|
7
|
+
export const getInlineReferenceState = state => key.getState(state);
|
|
8
|
+
export const setInlineReferenceState = (tr, state) => tr.setMeta(key, state);
|
|
9
|
+
/**
|
|
10
|
+
* Check if citations can be inserted at the given position.
|
|
11
|
+
* Checks both the ProseMirror schema and document-template restrictions
|
|
12
|
+
* (allowed elements per doc part, protected sections) — the same conditions
|
|
13
|
+
* that disable the toolbar citation button.
|
|
14
|
+
*/
|
|
15
|
+
function canActivateInlineReference(editor) {
|
|
16
|
+
// Mirror the template-based restriction check used by the toolbar button.
|
|
17
|
+
if (editor &&
|
|
18
|
+
elementDisabled(editor, "citation") &&
|
|
19
|
+
elementDisabled(editor, "cross_reference")) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse inline citation text into references array.
|
|
26
|
+
* Format: @key[prefix][locator];key2[prefix2][locator2]
|
|
27
|
+
* Returns {references, format} or null if any key cannot be resolved.
|
|
28
|
+
*/
|
|
29
|
+
function parseCitationText(text, bibEntries, bibDB) {
|
|
30
|
+
let format = "autocite";
|
|
31
|
+
let body = text;
|
|
32
|
+
if (body.startsWith("@@")) {
|
|
33
|
+
format = "textcite";
|
|
34
|
+
body = body.slice(2);
|
|
35
|
+
}
|
|
36
|
+
else if (body.startsWith("@")) {
|
|
37
|
+
body = body.slice(1);
|
|
38
|
+
}
|
|
39
|
+
if (!body) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const references = [];
|
|
43
|
+
const parts = body.split(";");
|
|
44
|
+
for (const part of parts) {
|
|
45
|
+
const match = part.match(/^([^\[]+)(?:\[(.*?)\])?(?:\[(.*?)\])?$/);
|
|
46
|
+
if (!match) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const entryKey = match[1].trim();
|
|
50
|
+
if (!entryKey) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const bibEntry = bibEntries.find(entry => entry.entry_key === entryKey);
|
|
54
|
+
if (!bibEntry) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
let id = bibEntry.id;
|
|
58
|
+
if (bibEntry.source === "user") {
|
|
59
|
+
// bibEntry.entry is the raw entry object from the user's bibDB
|
|
60
|
+
// (stored by buildBibliographyList). We must NOT look it up via
|
|
61
|
+
// bibDB.db[id] because bibDB is the *document* bibDB and the user's
|
|
62
|
+
// id doesn't exist there yet — that lookup returns undefined, which
|
|
63
|
+
// addReference then writes into the document DB, corrupting it.
|
|
64
|
+
id = bibDB.addReference(bibEntry.entry, id);
|
|
65
|
+
}
|
|
66
|
+
const ref = { id };
|
|
67
|
+
if (match[2]) {
|
|
68
|
+
ref.prefix = match[2];
|
|
69
|
+
}
|
|
70
|
+
if (match[3]) {
|
|
71
|
+
ref.locator = match[3];
|
|
72
|
+
}
|
|
73
|
+
references.push(ref);
|
|
74
|
+
}
|
|
75
|
+
if (!references.length) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return { references, format };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Extract the active reference index based on cursor offset.
|
|
82
|
+
*/
|
|
83
|
+
function getActiveRefIndex(text, cursorOffset) {
|
|
84
|
+
let pos = 0;
|
|
85
|
+
const parts = text.split(";");
|
|
86
|
+
for (let i = 0; i < parts.length; i++) {
|
|
87
|
+
const partLen = parts[i].length;
|
|
88
|
+
if (cursorOffset <= pos + partLen) {
|
|
89
|
+
return i;
|
|
90
|
+
}
|
|
91
|
+
pos += partLen + 1;
|
|
92
|
+
}
|
|
93
|
+
return Math.max(0, parts.length - 1);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get the query (key being typed) for the active reference.
|
|
97
|
+
*/
|
|
98
|
+
function getActiveQuery(text, activeIndex) {
|
|
99
|
+
const parts = text.split(";");
|
|
100
|
+
let part = parts[activeIndex] || "";
|
|
101
|
+
if (part.startsWith("@@")) {
|
|
102
|
+
part = part.slice(2);
|
|
103
|
+
}
|
|
104
|
+
else if (part.startsWith("@")) {
|
|
105
|
+
part = part.slice(1);
|
|
106
|
+
}
|
|
107
|
+
const match = part.match(/^([^\[]*)/);
|
|
108
|
+
return match ? match[1] : "";
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Replace the key of the active reference while preserving prefix/locator.
|
|
112
|
+
*/
|
|
113
|
+
function replaceActiveKey(text, activeIndex, newKey) {
|
|
114
|
+
const parts = text.split(";");
|
|
115
|
+
let part = parts[activeIndex] || "";
|
|
116
|
+
let trigger = "";
|
|
117
|
+
if (part.startsWith("@@")) {
|
|
118
|
+
trigger = "@@";
|
|
119
|
+
part = part.slice(2);
|
|
120
|
+
}
|
|
121
|
+
else if (part.startsWith("@")) {
|
|
122
|
+
trigger = "@";
|
|
123
|
+
part = part.slice(1);
|
|
124
|
+
}
|
|
125
|
+
const suffixMatch = part.match(/^[^\[]*(\[.*)$/);
|
|
126
|
+
const suffix = suffixMatch ? suffixMatch[1] : "";
|
|
127
|
+
parts[activeIndex] = trigger + newKey + suffix;
|
|
128
|
+
return parts.join(";");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Convert a citation node back to its inline text representation.
|
|
132
|
+
*/
|
|
133
|
+
function citationToText(node, bibEntries) {
|
|
134
|
+
const format = node.attrs.format;
|
|
135
|
+
const references = node.attrs.references || [];
|
|
136
|
+
const parts = references.map(ref => {
|
|
137
|
+
const entry = bibEntries.find(e => e.id === ref.id);
|
|
138
|
+
const key = entry ? entry.entry_key : "";
|
|
139
|
+
let part = key;
|
|
140
|
+
if (ref.prefix) {
|
|
141
|
+
part += `[${ref.prefix}]`;
|
|
142
|
+
}
|
|
143
|
+
if (ref.locator) {
|
|
144
|
+
part += `[${ref.locator}]`;
|
|
145
|
+
}
|
|
146
|
+
return part;
|
|
147
|
+
});
|
|
148
|
+
const body = parts.join(";");
|
|
149
|
+
if (format === "textcite") {
|
|
150
|
+
return "@@" + body;
|
|
151
|
+
}
|
|
152
|
+
return "@" + body;
|
|
153
|
+
}
|
|
154
|
+
function getInputCursorPos(el) {
|
|
155
|
+
const sel = window.getSelection();
|
|
156
|
+
if (!sel || !sel.rangeCount) {
|
|
157
|
+
return (el.textContent || "").length;
|
|
158
|
+
}
|
|
159
|
+
const range = sel.getRangeAt(0);
|
|
160
|
+
if (!el.contains(range.startContainer)) {
|
|
161
|
+
return (el.textContent || "").length;
|
|
162
|
+
}
|
|
163
|
+
return range.startOffset;
|
|
164
|
+
}
|
|
165
|
+
function setInputCursorPos(el, pos) {
|
|
166
|
+
const textNode = el.firstChild;
|
|
167
|
+
if (!textNode) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const range = document.createRange();
|
|
171
|
+
const safePos = Math.max(0, Math.min(pos, textNode.length));
|
|
172
|
+
range.setStart(textNode, safePos);
|
|
173
|
+
range.collapse(true);
|
|
174
|
+
const sel = window.getSelection();
|
|
175
|
+
if (sel) {
|
|
176
|
+
sel.removeAllRanges();
|
|
177
|
+
sel.addRange(range);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Create the inline citation widget DOM element.
|
|
182
|
+
*/
|
|
183
|
+
function createInlineReferenceWidget(editor, pluginState, key) {
|
|
184
|
+
const view = editor.currentView || editor.view;
|
|
185
|
+
const container = document.createElement("span");
|
|
186
|
+
container.className = "inline-reference-widget";
|
|
187
|
+
// Build the cross-reference target list once at widget creation time.
|
|
188
|
+
const crossRefList = buildCrossRefList(editor);
|
|
189
|
+
const input = document.createElement("span");
|
|
190
|
+
input.contentEditable = "plaintext-only";
|
|
191
|
+
input.spellcheck = false;
|
|
192
|
+
input.className = "inline-reference-input";
|
|
193
|
+
input.textContent = pluginState.query;
|
|
194
|
+
const dropUpWrapper = document.createElement("span");
|
|
195
|
+
dropUpWrapper.className = "drop-up-outer inline-reference-drop-up";
|
|
196
|
+
function renderDropUp() {
|
|
197
|
+
const currentState = key.getState(view.state);
|
|
198
|
+
if (!currentState?.active) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const rawText = input.textContent || "";
|
|
202
|
+
const citDisabled = elementDisabled(editor, "citation");
|
|
203
|
+
const xrefDisabled = elementDisabled(editor, "cross_reference");
|
|
204
|
+
const isXrefMode = !xrefDisabled && rawText.startsWith("@#");
|
|
205
|
+
let citationMatches, xrefMatches, activeCitIndex;
|
|
206
|
+
if (isXrefMode) {
|
|
207
|
+
// Cross-reference mode: only show cross-refs, filter by id/text
|
|
208
|
+
citationMatches = [];
|
|
209
|
+
xrefMatches = filterCrossRefs(crossRefList, rawText.slice(2));
|
|
210
|
+
activeCitIndex = -1;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
const cursorPos = getInputCursorPos(input);
|
|
214
|
+
activeCitIndex = getActiveRefIndex(rawText, cursorPos);
|
|
215
|
+
const query = getActiveQuery(rawText, activeCitIndex);
|
|
216
|
+
citationMatches = citDisabled
|
|
217
|
+
? []
|
|
218
|
+
: filterBibliography(currentState.bibList, query);
|
|
219
|
+
xrefMatches = xrefDisabled
|
|
220
|
+
? []
|
|
221
|
+
: filterCrossRefs(crossRefList, query);
|
|
222
|
+
}
|
|
223
|
+
const totalMatches = citationMatches.length + xrefMatches.length;
|
|
224
|
+
const selectedIndex = currentState.listActive
|
|
225
|
+
? Math.max(0, Math.min(currentState.selectedIndex, totalMatches - 1))
|
|
226
|
+
: -1;
|
|
227
|
+
dropUpWrapper.innerHTML = "";
|
|
228
|
+
const dropUp = createInlineReferenceDropUp(citationMatches, selectedIndex, idx => {
|
|
229
|
+
if (idx < citationMatches.length) {
|
|
230
|
+
const entry = citationMatches[idx];
|
|
231
|
+
if (!entry) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const newText = replaceActiveKey(rawText, activeCitIndex, entry.entry_key);
|
|
235
|
+
input.textContent = newText;
|
|
236
|
+
// Move cursor to end of replaced key
|
|
237
|
+
const newCursor = newText.indexOf(entry.entry_key, newText.indexOf("@") + 1);
|
|
238
|
+
setInputCursorPos(input, newCursor + entry.entry_key.length);
|
|
239
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
240
|
+
action: "updateQuery",
|
|
241
|
+
query: input.textContent
|
|
242
|
+
}));
|
|
243
|
+
renderDropUp();
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
// Cross-reference selected: fill input with @#id, stay open
|
|
247
|
+
const target = xrefMatches[idx - citationMatches.length];
|
|
248
|
+
if (!target) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
input.textContent = `@#${target.id}`;
|
|
252
|
+
setInputCursorPos(input, input.textContent.length);
|
|
253
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
254
|
+
action: "updateQuery",
|
|
255
|
+
query: input.textContent
|
|
256
|
+
}));
|
|
257
|
+
renderDropUp();
|
|
258
|
+
}
|
|
259
|
+
}, xrefMatches);
|
|
260
|
+
dropUpWrapper.appendChild(dropUp);
|
|
261
|
+
// Scroll selected item into view
|
|
262
|
+
const selectedItem = dropUp.querySelector(".inline-reference-drop-up-item.fw-selected");
|
|
263
|
+
if (selectedItem) {
|
|
264
|
+
selectedItem.scrollIntoView({ block: "nearest" });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
input.addEventListener("input", event => {
|
|
268
|
+
event.stopPropagation();
|
|
269
|
+
const text = input.textContent || "";
|
|
270
|
+
if (!text) {
|
|
271
|
+
// Everything including `@` was deleted — remove the node.
|
|
272
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "cancelDelete" }));
|
|
273
|
+
view.focus();
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (!text.startsWith("@")) {
|
|
277
|
+
// `@` was removed but content remains — restore it.
|
|
278
|
+
const cursorPos = getInputCursorPos(input);
|
|
279
|
+
input.textContent = "@" + text;
|
|
280
|
+
setInputCursorPos(input, cursorPos + 1);
|
|
281
|
+
}
|
|
282
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
283
|
+
action: "updateQuery",
|
|
284
|
+
query: input.textContent
|
|
285
|
+
}));
|
|
286
|
+
renderDropUp();
|
|
287
|
+
});
|
|
288
|
+
input.addEventListener("keypress", event => {
|
|
289
|
+
event.stopPropagation();
|
|
290
|
+
});
|
|
291
|
+
input.addEventListener("keydown", event => {
|
|
292
|
+
event.stopPropagation();
|
|
293
|
+
const currentState = key.getState(view.state);
|
|
294
|
+
if (!currentState?.active) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
switch (event.key) {
|
|
298
|
+
case "ArrowLeft":
|
|
299
|
+
if (getInputCursorPos(input) === 0) {
|
|
300
|
+
event.preventDefault();
|
|
301
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "cancelLeft" }));
|
|
302
|
+
view.focus();
|
|
303
|
+
}
|
|
304
|
+
break;
|
|
305
|
+
case "ArrowRight":
|
|
306
|
+
if (getInputCursorPos(input) ===
|
|
307
|
+
(input.textContent || "").length) {
|
|
308
|
+
event.preventDefault();
|
|
309
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "commitAndRight" }));
|
|
310
|
+
view.focus();
|
|
311
|
+
}
|
|
312
|
+
break;
|
|
313
|
+
case "ArrowDown":
|
|
314
|
+
event.preventDefault();
|
|
315
|
+
{
|
|
316
|
+
const currentState = key.getState(view.state);
|
|
317
|
+
if (!currentState.listActive) {
|
|
318
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
319
|
+
action: "select",
|
|
320
|
+
index: 0,
|
|
321
|
+
listActive: true
|
|
322
|
+
}));
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
326
|
+
action: "select",
|
|
327
|
+
index: currentState.selectedIndex + 1,
|
|
328
|
+
listActive: true
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
renderDropUp();
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
case "ArrowUp":
|
|
335
|
+
event.preventDefault();
|
|
336
|
+
{
|
|
337
|
+
const currentState = key.getState(view.state);
|
|
338
|
+
if (currentState.listActive &&
|
|
339
|
+
currentState.selectedIndex > 0) {
|
|
340
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
341
|
+
action: "select",
|
|
342
|
+
index: currentState.selectedIndex - 1,
|
|
343
|
+
listActive: true
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
348
|
+
action: "select",
|
|
349
|
+
index: -1,
|
|
350
|
+
listActive: false
|
|
351
|
+
}));
|
|
352
|
+
}
|
|
353
|
+
renderDropUp();
|
|
354
|
+
}
|
|
355
|
+
break;
|
|
356
|
+
case "Enter":
|
|
357
|
+
event.preventDefault();
|
|
358
|
+
{
|
|
359
|
+
const currentState = key.getState(view.state);
|
|
360
|
+
const rawText = input.textContent || "";
|
|
361
|
+
const citDisabledEnter = elementDisabled(editor, "citation");
|
|
362
|
+
const xrefDisabledEnter = elementDisabled(editor, "cross_reference");
|
|
363
|
+
const isXrefMode = !xrefDisabledEnter && rawText.startsWith("@#");
|
|
364
|
+
let citMatches, xrefMatchesEnter, activeIndexEnter;
|
|
365
|
+
if (isXrefMode) {
|
|
366
|
+
citMatches = [];
|
|
367
|
+
xrefMatchesEnter = filterCrossRefs(crossRefList, rawText.slice(2));
|
|
368
|
+
activeIndexEnter = -1;
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
const cursorPos = getInputCursorPos(input);
|
|
372
|
+
activeIndexEnter = getActiveRefIndex(rawText, cursorPos);
|
|
373
|
+
const query = getActiveQuery(rawText, activeIndexEnter);
|
|
374
|
+
citMatches = citDisabledEnter
|
|
375
|
+
? []
|
|
376
|
+
: filterBibliography(currentState.bibList, query);
|
|
377
|
+
xrefMatchesEnter = xrefDisabledEnter
|
|
378
|
+
? []
|
|
379
|
+
: filterCrossRefs(crossRefList, query);
|
|
380
|
+
}
|
|
381
|
+
const totalEnter = citMatches.length + xrefMatchesEnter.length;
|
|
382
|
+
const selectedIndex = Math.max(0, Math.min(currentState.selectedIndex, totalEnter - 1));
|
|
383
|
+
if (currentState.listActive &&
|
|
384
|
+
totalEnter > 0 &&
|
|
385
|
+
currentState.selectedIndex >= 0) {
|
|
386
|
+
if (selectedIndex < citMatches.length) {
|
|
387
|
+
// Insert selected citation key into input
|
|
388
|
+
const entry = citMatches[selectedIndex];
|
|
389
|
+
const newText = replaceActiveKey(rawText, activeIndexEnter, entry.entry_key);
|
|
390
|
+
input.textContent = newText;
|
|
391
|
+
const newCursor = newText.indexOf(entry.entry_key, newText.indexOf("@") + 1) + entry.entry_key.length;
|
|
392
|
+
setInputCursorPos(input, newCursor);
|
|
393
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
394
|
+
action: "updateQuery",
|
|
395
|
+
query: input.textContent
|
|
396
|
+
}));
|
|
397
|
+
renderDropUp();
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
// Cross-reference selected: fill input with @#id, stay open
|
|
401
|
+
const target = xrefMatchesEnter[selectedIndex - citMatches.length];
|
|
402
|
+
input.textContent = `@#${target.id}`;
|
|
403
|
+
setInputCursorPos(input, input.textContent.length);
|
|
404
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
405
|
+
action: "updateQuery",
|
|
406
|
+
query: input.textContent
|
|
407
|
+
}));
|
|
408
|
+
renderDropUp();
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
// Not in list mode or no matches: commit what we have
|
|
413
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "commit" }));
|
|
414
|
+
view.focus();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
break;
|
|
418
|
+
case "Escape":
|
|
419
|
+
event.preventDefault();
|
|
420
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "cancel" }));
|
|
421
|
+
view.focus();
|
|
422
|
+
break;
|
|
423
|
+
case "Home":
|
|
424
|
+
event.preventDefault();
|
|
425
|
+
setInputCursorPos(input, 0);
|
|
426
|
+
break;
|
|
427
|
+
case "End":
|
|
428
|
+
event.preventDefault();
|
|
429
|
+
setInputCursorPos(input, (input.textContent || "").length);
|
|
430
|
+
break;
|
|
431
|
+
case "Backspace":
|
|
432
|
+
// When only `@` remains, delete the whole node.
|
|
433
|
+
if ((input.textContent || "").length <= 1) {
|
|
434
|
+
event.preventDefault();
|
|
435
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "cancelDelete" }));
|
|
436
|
+
view.focus();
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
case "Delete":
|
|
440
|
+
// Same as Backspace when only `@` is left.
|
|
441
|
+
if ((input.textContent || "").length <= 1) {
|
|
442
|
+
event.preventDefault();
|
|
443
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "cancelDelete" }));
|
|
444
|
+
view.focus();
|
|
445
|
+
}
|
|
446
|
+
break;
|
|
447
|
+
case "Tab":
|
|
448
|
+
event.preventDefault();
|
|
449
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "commit" }));
|
|
450
|
+
break;
|
|
451
|
+
default:
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
input.addEventListener("focusout", event => {
|
|
456
|
+
const related = event.relatedTarget;
|
|
457
|
+
if (container.contains(related)) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
const myWidgetId = pluginState.widgetId;
|
|
461
|
+
setTimeout(() => {
|
|
462
|
+
const currentState = key.getState(view.state);
|
|
463
|
+
if (currentState?.active && currentState.widgetId === myWidgetId) {
|
|
464
|
+
view.dispatch(view.state.tr.setMeta(key, { action: "commit" }));
|
|
465
|
+
}
|
|
466
|
+
}, 1);
|
|
467
|
+
});
|
|
468
|
+
container.addEventListener("mousedown", event => {
|
|
469
|
+
event.stopPropagation();
|
|
470
|
+
});
|
|
471
|
+
container.appendChild(input);
|
|
472
|
+
container.appendChild(dropUpWrapper);
|
|
473
|
+
// Focus after mounting
|
|
474
|
+
setTimeout(() => {
|
|
475
|
+
input.focus();
|
|
476
|
+
// Place cursor based on entry direction
|
|
477
|
+
if (pluginState.cursorAtStart === true) {
|
|
478
|
+
setInputCursorPos(input, 0);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
setInputCursorPos(input, (input.textContent || "").length);
|
|
482
|
+
}
|
|
483
|
+
renderDropUp();
|
|
484
|
+
}, 0);
|
|
485
|
+
return container;
|
|
486
|
+
}
|
|
487
|
+
export const inlineReferencePlugin = options => {
|
|
488
|
+
const editor = options.editor;
|
|
489
|
+
const bibDB = editor.mod.db.bibDB;
|
|
490
|
+
const enabled = editor.app.config.user?.preferences?.inline_references === true &&
|
|
491
|
+
!READ_ONLY_ROLES.includes(editor.docInfo.access_rights) &&
|
|
492
|
+
!COMMENT_ONLY_ROLES.includes(editor.docInfo.access_rights);
|
|
493
|
+
if (!enabled) {
|
|
494
|
+
return new Plugin({
|
|
495
|
+
key,
|
|
496
|
+
state: {
|
|
497
|
+
init() {
|
|
498
|
+
return { active: false };
|
|
499
|
+
},
|
|
500
|
+
apply() {
|
|
501
|
+
return { active: false };
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
return new Plugin({
|
|
507
|
+
key,
|
|
508
|
+
state: {
|
|
509
|
+
init() {
|
|
510
|
+
return {
|
|
511
|
+
active: false,
|
|
512
|
+
from: 0,
|
|
513
|
+
query: "",
|
|
514
|
+
selectedIndex: -1,
|
|
515
|
+
listActive: false,
|
|
516
|
+
isEdit: false,
|
|
517
|
+
referenceNodePos: 0,
|
|
518
|
+
bibList: [],
|
|
519
|
+
widgetId: undefined,
|
|
520
|
+
cursorAtStart: undefined,
|
|
521
|
+
decos: DecorationSet.empty
|
|
522
|
+
};
|
|
523
|
+
},
|
|
524
|
+
apply(tr, prev, _oldState, _state) {
|
|
525
|
+
let next = { ...prev };
|
|
526
|
+
const meta = tr.getMeta(key);
|
|
527
|
+
if (meta?.action === "activate") {
|
|
528
|
+
next = {
|
|
529
|
+
active: true,
|
|
530
|
+
from: meta.from,
|
|
531
|
+
query: meta.query || "",
|
|
532
|
+
selectedIndex: -1,
|
|
533
|
+
listActive: false,
|
|
534
|
+
isEdit: meta.isEdit || false,
|
|
535
|
+
referenceNodePos: meta.referenceNodePos || 0,
|
|
536
|
+
bibList: meta.bibList || [],
|
|
537
|
+
widgetId: Math.random().toString(36).slice(2),
|
|
538
|
+
cursorAtStart: meta.cursorAtStart,
|
|
539
|
+
decos: DecorationSet.empty
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
else if (meta?.action === "deactivate") {
|
|
543
|
+
next = {
|
|
544
|
+
active: false,
|
|
545
|
+
from: 0,
|
|
546
|
+
query: "",
|
|
547
|
+
selectedIndex: -1,
|
|
548
|
+
listActive: false,
|
|
549
|
+
isEdit: false,
|
|
550
|
+
referenceNodePos: 0,
|
|
551
|
+
bibList: [],
|
|
552
|
+
widgetId: undefined,
|
|
553
|
+
cursorAtStart: undefined,
|
|
554
|
+
decos: DecorationSet.empty
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
else if (meta?.action === "select") {
|
|
558
|
+
next.selectedIndex = meta.index;
|
|
559
|
+
if (meta.listActive !== undefined) {
|
|
560
|
+
next.listActive = meta.listActive;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
else if (meta?.action === "updateQuery") {
|
|
564
|
+
next.query = meta.query;
|
|
565
|
+
next.selectedIndex = -1;
|
|
566
|
+
next.listActive = false;
|
|
567
|
+
}
|
|
568
|
+
if (next.active) {
|
|
569
|
+
if (!prev.active || prev.from !== next.from) {
|
|
570
|
+
// Position changed or just activated: create new widget
|
|
571
|
+
const deco = Decoration.widget(next.from, () => {
|
|
572
|
+
return createInlineReferenceWidget(editor, next, key);
|
|
573
|
+
}, {
|
|
574
|
+
key: "inline-reference-widget",
|
|
575
|
+
side: -1
|
|
576
|
+
});
|
|
577
|
+
const referenceNodeDeco = Decoration.node(next.from, next.from + 1, {
|
|
578
|
+
class: "hide"
|
|
579
|
+
});
|
|
580
|
+
next.decos = DecorationSet.create(_state.doc, [
|
|
581
|
+
deco,
|
|
582
|
+
referenceNodeDeco
|
|
583
|
+
]);
|
|
584
|
+
}
|
|
585
|
+
else if (tr.docChanged) {
|
|
586
|
+
// Document changed while active: map old decorations
|
|
587
|
+
next.decos = prev.decos.map(tr.mapping, _state.doc);
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
// Same position, doc unchanged: keep existing widget
|
|
591
|
+
next.decos = prev.decos;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
next.decos = DecorationSet.empty;
|
|
596
|
+
}
|
|
597
|
+
return next;
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
appendTransaction: (trs, oldState, newState) => {
|
|
601
|
+
const oldPluginState = key.getState(oldState);
|
|
602
|
+
const meta = trs.find(tr => tr.getMeta(key))?.getMeta(key);
|
|
603
|
+
if (meta?.action === "commit" ||
|
|
604
|
+
meta?.action === "commitAndRight") {
|
|
605
|
+
if (!oldPluginState.active) {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
const query = oldPluginState.query;
|
|
609
|
+
// Cross-reference mode: query starts with '@#'
|
|
610
|
+
if (query.startsWith("@#") &&
|
|
611
|
+
!elementDisabled(editor, "cross_reference")) {
|
|
612
|
+
const xrefId = query.slice(2);
|
|
613
|
+
const crossRefList = buildCrossRefList(editor);
|
|
614
|
+
const target = crossRefList.find(t => t.id === xrefId);
|
|
615
|
+
const crossRefNode = newState.schema.nodes.cross_reference.create({
|
|
616
|
+
id: xrefId || false,
|
|
617
|
+
title: target ? target.text : null
|
|
618
|
+
});
|
|
619
|
+
if (oldPluginState.isEdit) {
|
|
620
|
+
const existingNode = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
621
|
+
const tr = newState.tr.replaceWith(oldPluginState.referenceNodePos, oldPluginState.referenceNodePos +
|
|
622
|
+
(existingNode?.nodeSize || 1), crossRefNode);
|
|
623
|
+
tr.setSelection(TextSelection.create(tr.doc, oldPluginState.referenceNodePos +
|
|
624
|
+
crossRefNode.nodeSize));
|
|
625
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
const tr = newState.tr.insert(oldPluginState.from, crossRefNode);
|
|
629
|
+
const newPos = oldPluginState.from + crossRefNode.nodeSize;
|
|
630
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
631
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
const parsed = !elementDisabled(editor, "citation")
|
|
635
|
+
? parseCitationText(query, oldPluginState.bibList, bibDB)
|
|
636
|
+
: null;
|
|
637
|
+
if (!parsed) {
|
|
638
|
+
if (oldPluginState.isEdit) {
|
|
639
|
+
const node = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
640
|
+
const newPos = oldPluginState.referenceNodePos +
|
|
641
|
+
(node?.nodeSize || 1);
|
|
642
|
+
const tr = newState.tr.setSelection(TextSelection.create(newState.doc, newPos));
|
|
643
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
644
|
+
}
|
|
645
|
+
// Invalid reference text: insert as plain text with caret after
|
|
646
|
+
const tr = newState.tr.insertText(query, oldPluginState.from);
|
|
647
|
+
const newPos = oldPluginState.from + query.length;
|
|
648
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
649
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
650
|
+
}
|
|
651
|
+
const citationNode = newState.schema.nodes.citation.create({
|
|
652
|
+
format: parsed.format,
|
|
653
|
+
references: parsed.references
|
|
654
|
+
});
|
|
655
|
+
if (oldPluginState.isEdit) {
|
|
656
|
+
const existingNode = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
657
|
+
const tr = newState.tr.replaceWith(oldPluginState.referenceNodePos, oldPluginState.referenceNodePos +
|
|
658
|
+
(existingNode?.nodeSize || 1), citationNode);
|
|
659
|
+
const newPos = oldPluginState.referenceNodePos + citationNode.nodeSize;
|
|
660
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
661
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
662
|
+
}
|
|
663
|
+
else {
|
|
664
|
+
const tr = newState.tr.insert(oldPluginState.from, citationNode);
|
|
665
|
+
const newPos = oldPluginState.from + citationNode.nodeSize;
|
|
666
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
667
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (meta?.action === "cancel") {
|
|
671
|
+
if (oldPluginState.isEdit) {
|
|
672
|
+
// Editing: just deactivate, leave reference unchanged
|
|
673
|
+
const node = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
674
|
+
const newPos = oldPluginState.referenceNodePos + (node?.nodeSize || 1);
|
|
675
|
+
const tr = newState.tr.setSelection(TextSelection.create(newState.doc, newPos));
|
|
676
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
// New reference: insert query as plain text with caret after
|
|
680
|
+
const tr = newState.tr.insertText(oldPluginState.query, oldPluginState.from);
|
|
681
|
+
const newPos = oldPluginState.from + oldPluginState.query.length;
|
|
682
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
683
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (meta?.action === "cancelDelete") {
|
|
687
|
+
if (oldPluginState.isEdit) {
|
|
688
|
+
// Delete the reference node entirely.
|
|
689
|
+
const existingNode = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
690
|
+
const tr = newState.tr.delete(oldPluginState.referenceNodePos, oldPluginState.referenceNodePos +
|
|
691
|
+
(existingNode?.nodeSize || 1));
|
|
692
|
+
tr.setSelection(TextSelection.create(tr.doc, oldPluginState.referenceNodePos));
|
|
693
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
// New node: just deactivate — don't insert anything.
|
|
697
|
+
return newState.tr.setMeta(key, { action: "deactivate" });
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
if (meta?.action === "cancelLeft") {
|
|
701
|
+
if (oldPluginState.isEdit) {
|
|
702
|
+
const tr = newState.tr.setSelection(TextSelection.create(newState.doc, oldPluginState.referenceNodePos));
|
|
703
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
const tr = newState.tr.insertText(oldPluginState.query, oldPluginState.from);
|
|
707
|
+
tr.setSelection(TextSelection.create(tr.doc, oldPluginState.from));
|
|
708
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (meta?.action === "openDialog") {
|
|
712
|
+
if (oldPluginState.active && oldPluginState.isEdit) {
|
|
713
|
+
// Deactivate the inline editor and leave a NodeSelection on
|
|
714
|
+
// the citation so CitationDialog opens with its content.
|
|
715
|
+
const node = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
716
|
+
if (node?.type.name === "citation") {
|
|
717
|
+
return newState.tr
|
|
718
|
+
.setSelection(NodeSelection.create(newState.doc, oldPluginState.referenceNodePos))
|
|
719
|
+
.setMeta(key, { action: "deactivate" });
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
if (meta?.action === "insertCrossRef") {
|
|
725
|
+
if (!oldPluginState.active) {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
const crossRefNode = newState.schema.nodes.cross_reference.create({
|
|
729
|
+
id: meta.id,
|
|
730
|
+
title: meta.title
|
|
731
|
+
});
|
|
732
|
+
if (oldPluginState.isEdit) {
|
|
733
|
+
// Replace the existing citation node with a cross_reference.
|
|
734
|
+
const existingNode = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
735
|
+
const tr = newState.tr.replaceWith(oldPluginState.referenceNodePos, oldPluginState.referenceNodePos +
|
|
736
|
+
(existingNode?.nodeSize || 1), crossRefNode);
|
|
737
|
+
tr.setSelection(TextSelection.create(tr.doc, oldPluginState.referenceNodePos +
|
|
738
|
+
crossRefNode.nodeSize));
|
|
739
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
const tr = newState.tr.insert(oldPluginState.from, crossRefNode);
|
|
743
|
+
tr.setSelection(TextSelection.create(tr.doc, oldPluginState.from + crossRefNode.nodeSize));
|
|
744
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
if (oldPluginState.active) {
|
|
748
|
+
// If selection moved away from the widget, commit
|
|
749
|
+
if (trs.some(tr => tr.selectionSet) &&
|
|
750
|
+
(newState.selection.from !== oldPluginState.from ||
|
|
751
|
+
newState.selection.to !== oldPluginState.from)) {
|
|
752
|
+
const query = oldPluginState.query;
|
|
753
|
+
// Cross-reference mode
|
|
754
|
+
if (query.startsWith("@#") &&
|
|
755
|
+
!elementDisabled(editor, "cross_reference")) {
|
|
756
|
+
const xrefId = query.slice(2);
|
|
757
|
+
if (xrefId && oldPluginState.isEdit) {
|
|
758
|
+
const crossRefList = buildCrossRefList(editor);
|
|
759
|
+
const target = crossRefList.find(t => t.id === xrefId);
|
|
760
|
+
const crossRefNode = newState.schema.nodes.cross_reference.create({
|
|
761
|
+
id: xrefId,
|
|
762
|
+
title: target ? target.text : null
|
|
763
|
+
});
|
|
764
|
+
const existingNode = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
765
|
+
return newState.tr
|
|
766
|
+
.replaceWith(oldPluginState.referenceNodePos, oldPluginState.referenceNodePos +
|
|
767
|
+
(existingNode?.nodeSize || 1), crossRefNode)
|
|
768
|
+
.setMeta(key, { action: "deactivate" });
|
|
769
|
+
}
|
|
770
|
+
else if (xrefId && !oldPluginState.isEdit) {
|
|
771
|
+
const crossRefList = buildCrossRefList(editor);
|
|
772
|
+
const target = crossRefList.find(t => t.id === xrefId);
|
|
773
|
+
const crossRefNode = newState.schema.nodes.cross_reference.create({
|
|
774
|
+
id: xrefId,
|
|
775
|
+
title: target ? target.text : null
|
|
776
|
+
});
|
|
777
|
+
return newState.tr
|
|
778
|
+
.insert(oldPluginState.from, crossRefNode)
|
|
779
|
+
.setMeta(key, { action: "deactivate" });
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
return newState.tr.setMeta(key, {
|
|
783
|
+
action: "deactivate"
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
const parsed = !elementDisabled(editor, "citation")
|
|
788
|
+
? parseCitationText(query, oldPluginState.bibList, bibDB)
|
|
789
|
+
: null;
|
|
790
|
+
if (parsed) {
|
|
791
|
+
const citationNode = newState.schema.nodes.citation.create({
|
|
792
|
+
format: parsed.format,
|
|
793
|
+
references: parsed.references
|
|
794
|
+
});
|
|
795
|
+
if (oldPluginState.isEdit) {
|
|
796
|
+
const existingNode = newState.doc.nodeAt(oldPluginState.referenceNodePos);
|
|
797
|
+
return newState.tr
|
|
798
|
+
.replaceWith(oldPluginState.referenceNodePos, oldPluginState.referenceNodePos +
|
|
799
|
+
(existingNode?.nodeSize || 1), citationNode)
|
|
800
|
+
.setMeta(key, { action: "deactivate" });
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
return newState.tr
|
|
804
|
+
.insert(oldPluginState.from, citationNode)
|
|
805
|
+
.setMeta(key, { action: "deactivate" });
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
else if (!oldPluginState.isEdit) {
|
|
809
|
+
// Invalid reference text on blur/selection-move: insert as plain text
|
|
810
|
+
const tr = newState.tr.insertText(query, oldPluginState.from);
|
|
811
|
+
const newPos = oldPluginState.from + query.length;
|
|
812
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
813
|
+
return tr.setMeta(key, { action: "deactivate" });
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
return newState.tr.setMeta(key, {
|
|
817
|
+
action: "deactivate"
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
// Check if a citation node is selected for re-editing (keyboard)
|
|
824
|
+
const selection = newState.selection;
|
|
825
|
+
if (selection instanceof NodeSelection &&
|
|
826
|
+
selection.node.type.name === "citation") {
|
|
827
|
+
const citationNode = selection.node;
|
|
828
|
+
const from = selection.from;
|
|
829
|
+
const bibList = buildBibliographyList(editor);
|
|
830
|
+
const text = citationToText(citationNode, bibList);
|
|
831
|
+
return newState.tr.setMeta(key, {
|
|
832
|
+
action: "activate",
|
|
833
|
+
from: from,
|
|
834
|
+
query: text,
|
|
835
|
+
isEdit: true,
|
|
836
|
+
referenceNodePos: from,
|
|
837
|
+
bibList: bibList
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
// Check if a cross_reference node is selected for re-editing (keyboard)
|
|
841
|
+
if (selection instanceof NodeSelection &&
|
|
842
|
+
selection.node.type.name === "cross_reference") {
|
|
843
|
+
const crossNode = selection.node;
|
|
844
|
+
const from = selection.from;
|
|
845
|
+
return newState.tr.setMeta(key, {
|
|
846
|
+
action: "activate",
|
|
847
|
+
from: from,
|
|
848
|
+
query: `@#${crossNode.attrs.id || ""}`,
|
|
849
|
+
isEdit: true,
|
|
850
|
+
referenceNodePos: from,
|
|
851
|
+
bibList: buildBibliographyList(editor)
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
// Check for @ keypress activation via doc change
|
|
855
|
+
// (handles paste/mobile where handleKeyDown may not fire)
|
|
856
|
+
const tr = trs.find(tr => tr.docChanged);
|
|
857
|
+
if (tr) {
|
|
858
|
+
const $pos = newState.selection.$head;
|
|
859
|
+
if (canActivateInlineReference(editor)) {
|
|
860
|
+
const beforeText = newState.doc.textBetween(Math.max(0, $pos.pos - 3), $pos.pos, "");
|
|
861
|
+
if (beforeText.endsWith("@")) {
|
|
862
|
+
const lastChar = beforeText.slice(-2, -1);
|
|
863
|
+
if (!lastChar || !/[a-zA-Z0-9]/.test(lastChar)) {
|
|
864
|
+
const tr = newState.tr
|
|
865
|
+
.delete($pos.pos - 1, $pos.pos)
|
|
866
|
+
.setMeta(key, {
|
|
867
|
+
action: "activate",
|
|
868
|
+
from: $pos.pos - 1,
|
|
869
|
+
query: "@",
|
|
870
|
+
isEdit: false,
|
|
871
|
+
bibList: buildBibliographyList(editor)
|
|
872
|
+
});
|
|
873
|
+
return tr;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return null;
|
|
880
|
+
},
|
|
881
|
+
props: {
|
|
882
|
+
decorations(state) {
|
|
883
|
+
const pluginState = key.getState(state);
|
|
884
|
+
return pluginState?.decos || DecorationSet.empty;
|
|
885
|
+
},
|
|
886
|
+
handleClickOn(_view, _pos, node, nodePos, _event, _direct) {
|
|
887
|
+
if (node.type.name === "citation") {
|
|
888
|
+
const bibList = buildBibliographyList(editor);
|
|
889
|
+
const text = citationToText(node, bibList);
|
|
890
|
+
const tr = _view.state.tr.setSelection(TextSelection.create(_view.state.doc, nodePos + node.nodeSize));
|
|
891
|
+
tr.setMeta(key, {
|
|
892
|
+
action: "activate",
|
|
893
|
+
from: nodePos,
|
|
894
|
+
query: text,
|
|
895
|
+
isEdit: true,
|
|
896
|
+
referenceNodePos: nodePos,
|
|
897
|
+
bibList: bibList
|
|
898
|
+
});
|
|
899
|
+
_view.dispatch(tr);
|
|
900
|
+
return true;
|
|
901
|
+
}
|
|
902
|
+
if (node.type.name === "cross_reference") {
|
|
903
|
+
const tr = _view.state.tr.setSelection(TextSelection.create(_view.state.doc, nodePos + node.nodeSize));
|
|
904
|
+
tr.setMeta(key, {
|
|
905
|
+
action: "activate",
|
|
906
|
+
from: nodePos,
|
|
907
|
+
query: `@#${node.attrs.id || ""}`,
|
|
908
|
+
isEdit: true,
|
|
909
|
+
referenceNodePos: nodePos,
|
|
910
|
+
bibList: buildBibliographyList(editor)
|
|
911
|
+
});
|
|
912
|
+
_view.dispatch(tr);
|
|
913
|
+
return true;
|
|
914
|
+
}
|
|
915
|
+
return false;
|
|
916
|
+
},
|
|
917
|
+
handleDOMEvents: {
|
|
918
|
+
mousedown(view, event) {
|
|
919
|
+
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
|
920
|
+
return false;
|
|
921
|
+
}
|
|
922
|
+
if (event.button !== 0) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
const citTarget = event.target.closest(".citation");
|
|
926
|
+
const xrefTarget = !citTarget && event.target.closest(".cross-reference");
|
|
927
|
+
const target = citTarget || xrefTarget;
|
|
928
|
+
if (!target) {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
let pos = view.posAtDOM(target, 0);
|
|
932
|
+
let node = view.state.doc.nodeAt(pos);
|
|
933
|
+
if (!node ||
|
|
934
|
+
(node.type.name !== "citation" &&
|
|
935
|
+
node.type.name !== "cross_reference")) {
|
|
936
|
+
return false;
|
|
937
|
+
}
|
|
938
|
+
const pluginState = key.getState(view.state);
|
|
939
|
+
if (pluginState?.active) {
|
|
940
|
+
// Commit current widget first
|
|
941
|
+
const commitTr = view.state.tr.setMeta(key, {
|
|
942
|
+
action: "commit"
|
|
943
|
+
});
|
|
944
|
+
view.dispatch(commitTr);
|
|
945
|
+
pos = commitTr.mapping.map(pos);
|
|
946
|
+
node = view.state.doc.nodeAt(pos);
|
|
947
|
+
if (!node ||
|
|
948
|
+
(node.type.name !== "citation" &&
|
|
949
|
+
node.type.name !== "cross_reference")) {
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
let query, bibList;
|
|
954
|
+
if (node.type.name === "citation") {
|
|
955
|
+
bibList = buildBibliographyList(editor);
|
|
956
|
+
query = citationToText(node, bibList);
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
bibList = buildBibliographyList(editor);
|
|
960
|
+
query = `@#${node.attrs.id || ""}`;
|
|
961
|
+
}
|
|
962
|
+
const tr = view.state.tr.setSelection(TextSelection.create(view.state.doc, pos + node.nodeSize));
|
|
963
|
+
tr.setMeta(key, {
|
|
964
|
+
action: "activate",
|
|
965
|
+
from: pos,
|
|
966
|
+
query,
|
|
967
|
+
isEdit: true,
|
|
968
|
+
referenceNodePos: pos,
|
|
969
|
+
bibList
|
|
970
|
+
});
|
|
971
|
+
view.dispatch(tr);
|
|
972
|
+
event.stopPropagation();
|
|
973
|
+
event.preventDefault();
|
|
974
|
+
return true;
|
|
975
|
+
},
|
|
976
|
+
click(view, event) {
|
|
977
|
+
// Fallback click handler for touch devices and cases where
|
|
978
|
+
// mousedown/handleClickOn did not fire.
|
|
979
|
+
const pluginState = key.getState(view.state);
|
|
980
|
+
if (pluginState?.active) {
|
|
981
|
+
const target = event.target.closest(".inline-reference-widget");
|
|
982
|
+
if (target) {
|
|
983
|
+
// Click inside widget: let widget handle it
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
// When widget is active, ignore all other clicks.
|
|
987
|
+
// mousedown already handled citation clicks.
|
|
988
|
+
// focusout handles clicks outside the editor.
|
|
989
|
+
// We must prevent default because the browser may
|
|
990
|
+
// retarget click to a parent element after mousedown
|
|
991
|
+
// prevented the default.
|
|
992
|
+
event.preventDefault();
|
|
993
|
+
event.stopPropagation();
|
|
994
|
+
return true;
|
|
995
|
+
}
|
|
996
|
+
// Widget inactive: try to activate a clicked citation
|
|
997
|
+
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
|
998
|
+
return false;
|
|
999
|
+
}
|
|
1000
|
+
const target = event.target.closest(".citation");
|
|
1001
|
+
if (!target) {
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
const pos = view.posAtDOM(target, 0);
|
|
1005
|
+
const node = view.state.doc.nodeAt(pos);
|
|
1006
|
+
if (!node || node.type.name !== "citation") {
|
|
1007
|
+
return false;
|
|
1008
|
+
}
|
|
1009
|
+
const bibList = buildBibliographyList(editor);
|
|
1010
|
+
const text = citationToText(node, bibList);
|
|
1011
|
+
const tr = view.state.tr.setSelection(TextSelection.create(view.state.doc, pos + node.nodeSize));
|
|
1012
|
+
tr.setMeta(key, {
|
|
1013
|
+
action: "activate",
|
|
1014
|
+
from: pos,
|
|
1015
|
+
query: text,
|
|
1016
|
+
isEdit: true,
|
|
1017
|
+
referenceNodePos: pos,
|
|
1018
|
+
bibList: bibList
|
|
1019
|
+
});
|
|
1020
|
+
view.dispatch(tr);
|
|
1021
|
+
return true;
|
|
1022
|
+
}
|
|
1023
|
+
},
|
|
1024
|
+
handleKeyDown(view, event) {
|
|
1025
|
+
const pluginState = key.getState(view.state);
|
|
1026
|
+
if (!pluginState?.active) {
|
|
1027
|
+
if (event.key === "@") {
|
|
1028
|
+
const $pos = view.state.selection.$head;
|
|
1029
|
+
if (canActivateInlineReference(editor)) {
|
|
1030
|
+
const beforeText = view.state.doc.textBetween(Math.max(0, $pos.pos - 1), $pos.pos, "");
|
|
1031
|
+
const lastChar = beforeText.slice(-1);
|
|
1032
|
+
if (!lastChar || !/[a-zA-Z0-9]/.test(lastChar)) {
|
|
1033
|
+
event.preventDefault();
|
|
1034
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
1035
|
+
action: "activate",
|
|
1036
|
+
from: $pos.pos,
|
|
1037
|
+
query: "@",
|
|
1038
|
+
isEdit: false,
|
|
1039
|
+
bibList: buildBibliographyList(editor)
|
|
1040
|
+
}));
|
|
1041
|
+
return true;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
// ArrowRight into citation or cross_reference from the left
|
|
1046
|
+
if (event.key === "ArrowRight") {
|
|
1047
|
+
const sel = view.state.selection;
|
|
1048
|
+
if (sel.empty) {
|
|
1049
|
+
const $pos = sel.$head;
|
|
1050
|
+
const nodeAfter = $pos.nodeAfter;
|
|
1051
|
+
if (nodeAfter &&
|
|
1052
|
+
nodeAfter.type.name === "citation") {
|
|
1053
|
+
event.preventDefault();
|
|
1054
|
+
const from = $pos.pos;
|
|
1055
|
+
const bibList = buildBibliographyList(editor);
|
|
1056
|
+
const text = citationToText(nodeAfter, bibList);
|
|
1057
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
1058
|
+
action: "activate",
|
|
1059
|
+
from: from,
|
|
1060
|
+
query: text,
|
|
1061
|
+
isEdit: true,
|
|
1062
|
+
referenceNodePos: from,
|
|
1063
|
+
bibList: bibList,
|
|
1064
|
+
cursorAtStart: true
|
|
1065
|
+
}));
|
|
1066
|
+
return true;
|
|
1067
|
+
}
|
|
1068
|
+
if (nodeAfter &&
|
|
1069
|
+
nodeAfter.type.name === "cross_reference") {
|
|
1070
|
+
event.preventDefault();
|
|
1071
|
+
const from = $pos.pos;
|
|
1072
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
1073
|
+
action: "activate",
|
|
1074
|
+
from: from,
|
|
1075
|
+
query: `@#${nodeAfter.attrs.id || ""}`,
|
|
1076
|
+
isEdit: true,
|
|
1077
|
+
referenceNodePos: from,
|
|
1078
|
+
bibList: buildBibliographyList(editor),
|
|
1079
|
+
cursorAtStart: true
|
|
1080
|
+
}));
|
|
1081
|
+
return true;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
// ArrowLeft into citation or cross_reference from the right
|
|
1086
|
+
if (event.key === "ArrowLeft") {
|
|
1087
|
+
const sel = view.state.selection;
|
|
1088
|
+
if (sel.empty) {
|
|
1089
|
+
const $pos = sel.$head;
|
|
1090
|
+
const nodeBefore = $pos.nodeBefore;
|
|
1091
|
+
if (nodeBefore &&
|
|
1092
|
+
nodeBefore.type.name === "citation") {
|
|
1093
|
+
event.preventDefault();
|
|
1094
|
+
const from = $pos.pos - nodeBefore.nodeSize;
|
|
1095
|
+
const bibList = buildBibliographyList(editor);
|
|
1096
|
+
const text = citationToText(nodeBefore, bibList);
|
|
1097
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
1098
|
+
action: "activate",
|
|
1099
|
+
from: from,
|
|
1100
|
+
query: text,
|
|
1101
|
+
isEdit: true,
|
|
1102
|
+
referenceNodePos: from,
|
|
1103
|
+
bibList: bibList,
|
|
1104
|
+
cursorAtStart: false
|
|
1105
|
+
}));
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
if (nodeBefore &&
|
|
1109
|
+
nodeBefore.type.name === "cross_reference") {
|
|
1110
|
+
event.preventDefault();
|
|
1111
|
+
const from = $pos.pos - nodeBefore.nodeSize;
|
|
1112
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
1113
|
+
action: "activate",
|
|
1114
|
+
from: from,
|
|
1115
|
+
query: `@#${nodeBefore.attrs.id || ""}`,
|
|
1116
|
+
isEdit: true,
|
|
1117
|
+
referenceNodePos: from,
|
|
1118
|
+
bibList: buildBibliographyList(editor),
|
|
1119
|
+
cursorAtStart: false
|
|
1120
|
+
}));
|
|
1121
|
+
return true;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
return false;
|
|
1126
|
+
}
|
|
1127
|
+
// When active, the widget traps its own key events.
|
|
1128
|
+
// Only handle navigation keys that should move the main cursor.
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
});
|
|
1133
|
+
};
|
|
1134
|
+
//# sourceMappingURL=plugin.js.map
|